PROJECTS / LESSON 03

Find and fix a bug one step at a time

Compare what you expected with what happened, investigate a cause, and test one small change.

Content updated

By the end, you can…

  • Describe a bug using expected and actual behavior.
  • Use HTML, styles, and runtime messages to investigate a cause.
  • Test a small repair without losing behavior that already works.
Before you begin

Describe the difference before editing

A bug is a difference between what you expected and what actually happened. Start with one action you can repeat, not the whole page at once.

Spot the difference

A quick visual example

Action: click Save

Expected
Saved

A confirmation appears.

Actual
Not saved

The old message stays.

A useful bug report: “After Save, I still see Not saved.”

  1. 1Observe
  2. 2Investigate
  3. 3Change one thing
  4. 4Test again

Predict what one small change should do, then test it. If you change several things together, you will not know which one helped. Keep a copy or use undo when an experiment makes things worse.

When a style seems to do nothing

A valid CSS rule can match nothing. Compare the class in this HTML with the CSS selector, then try the repair button.

Which element does this rule match?

Interactive illustration · try it

HTML + CSS
<p class="note">
  Remember to save
</p>

.notes {
  background: #fef3c7;
  padding: 16px;
}
What the page shows

Remember to save

No match: the text keeps its default appearance.

Compare note in the HTML with notes in the CSS. One extra letter matters.

On your own page, use Inspect on the element. Styles or Rules shows matching declarations; Computed shows the resulting value. A crossed-out declaration usually lost to another rule. If the whole page has no styling, check that the stylesheet loaded before changing selectors.

Before you try: running, pausing, and stepping

A statement is an instruction in your code, such as changing a paragraph’s text. Running (or executing) code means carrying out those instructions. A runtime error happens while the code is running and can stop it before later instructions are reached.

Pausing gives you time to inspect the current values without running the next instruction. In the example below, the highlighted statement has not run yet when the script is paused. Stepping means running that statement, then pausing again so you can see what changed.

Use Run automatically to start fresh and watch the script run. Use Start step-by-step to start fresh and pause before the first instruction.

Once paused, Run next statement advances one instruction. Resume automatically lets the remaining code run without clicking through each step. These two controls are disabled when there is no paused code to resume.

Try one debugging control at a time

Interactive illustration · try it

Start from the beginning. Watch all three instructions run without another click.

Here, output is the paragraph shown as “On the page” below.

let count = 1;count = count + 1;output.textContent = count;
Stored countNot assigned yet
On the pageWaiting

Ready. No instructions have run yet.

A simplified simulation of these three instructions. Each numbered example resets its own starting point.

A callback is a function that runs later in response to something, such as a click. Registering a click listener does not run its callback immediately: the example waits for you to click Save in the live page.

When the script stops

An early error can prevent later statements from running. Predict where this script stops, then trace it.

Follow the script until it stops

Live code · run or step through

The goal: show Ready after setup, then Saved when you click Save. This HTML is loaded before the script runs.

HTML · the elements that actually exist
<button id="save">Save</button>
<p id="message">Not ready</p>

Broken: #save-now does not match any element in this HTML.

const button = document.querySelector("#save-now");const message = document.querySelector("#message"); button.addEventListener("click", () => {  message.textContent = "Saved";}); message.textContent = "Ready";

Try Start step-by-step to watch what changes after each instruction.

Variables · values after executed statements
button
Not assigned yet
message
Not assigned yet
Live page · the script changes these real elements

Run a version to open its page here.

What each statement does

Follow the execution order: find the elements, prepare the click, then update the page.

  1. Line 1

    Find the Save button

    #save looks for id="save". The broken selector, #save-now, finds nothing.

    Result: button holds the element or null (no match). No error yet.

  2. Line 2

    Find the message paragraph

    #message matches the paragraph in both versions.

    Result: message holds that paragraph. Its text is still Not ready.

  3. Line 4

    Prepare a response to a click

    addEventListener registers the callback. It does not run the callback yet.

    Broken · stops herenull has no addEventListener method. An error stops this run; line 8 is never reached.

    Corrected · continuesThe real button gets a listener. The callback waits for a click while setup continues to line 8.

  4. Line 8

    Show that setup is complete

    In the corrected version, the paragraph changes from Not ready → Ready.

    Next: the script waits for you to click Save. Line 5 has not run.

  5. Line 5

    After a click: run the callback

    Click Save in the corrected live page. The callback changes the paragraph from Ready → Saved.

    In step mode: it pauses before this update. Choose Run next statement to execute it.

This teaching debugger executes the shown example with pause instructions in an isolated page. It is not the browser’s DevTools and cannot debug arbitrary code. Each run or version change starts fresh. Saved changes the demo text; it does not save a file.

In a local project, open the developer tools Console and reproduce the problem. Start with the first relevant error and follow its file-and-line link. A null error is a clue to trace a missing value, not proof of one particular cause. The practice has a runtime message panel rather than a full console.

When the code runs but the page stays the same

Click Add a star twice. Watch the stored number and the displayed number separately. Then include the display update and try again.

A stored value is not the page

Interactive illustration · try it

Stored in memory0stars
Shown on the page0Visible stars
stars = stars + 1;
// No statement updates the page here.

Stored: 0. Shown: 0. Only the value in memory changes.

Switching modes starts both numbers at zero. This example uses a star counter, separate from the practice.

A variable and the page are separate. Trace which statements change each one, and whether they run on every click. After a repair, test repeated actions and reset behavior too. Fixing an early error can reveal another bug that was previously hidden.

Your turn: fix a broken counter

Fix this page is a separate interactive practice. You will repair a counter with broken styling and button behavior. The HTML is provided; you edit its CSS and JavaScript and test your changes in a live preview.

Open Fix this page practice →

  • Run the supplied code and try the counter. Describe what you expected and what actually happened.
  • Investigate one symptom. If you get stuck, open a hint for a question that points you toward what to inspect.
  • Make one small change, then use Check solution to see which checks pass. Repeat until the counter works, including repeated clicks and reset.

The practice uses different names from the lesson examples, so compare its HTML and code rather than copying a selector from here. Hints guide your investigation; the explained solution shows the complete repair when you are ready to review it.

Go to the source

Examples are authored for Tuklas and checked with code and reference documentation. This is not a claim of independent human review. Suggest a correction.