Skip to contentPlayForge
Act IChapter 2
chapter 2

2. Decisions and Loops

Make code choose with if and repeat with loops, the way a test checks and retries.

12m read4m practice · 1 exercise16m in total

Chapter film (about 7m) is coming.

Checkpoint 1 of 3

Comparisons and Truthiness

In plain English. A comparison asks JavaScript a yes/no question about two values: is this price bigger than that one, is this heading the same text as the one I expected? The answer is always true or false. Every check a test makes comes down to a comparison. JavaScript also has a rule for values that are not yes/no answers: when one is used as a yes/no check, it counts as true or false anyway. A value that counts as true is truthy, and one that counts as false is falsy. The falsy ones are a short list, so you can learn them all.

Comparing two values. The comparisons you will use are === (exactly equal), !== (not equal), >, <, >= and <=. JavaScript has two equality operators: loose equality (==) and strict equality (===). Loose equality performs type coercion before comparing (1 == '1' is true). That often leads to unexpected bugs. Always use strict equality (=== and !==), which checks both value and type.

Text compares letter by letter. '10' < '9' is true, because the text '1' sorts before '9'. A price read off a page is text, so convert it with Number() before you compare it (the Numbers & Type Coercion lesson showed how). Case matters too: 'Total' === 'total' is false.

Combining checks. && means "and": both sides must be true. || means "or": either side is enough. ! flips true to false and back. So loggedIn && isAdmin is true only when both are.

Truthy and falsy. The falsy values are false, 0, -0, 0n (the BigInt zero), "", null, undefined and NaN. Everything else is truthy, including "0", "false", the empty list [] and the empty record {} (the Arrays and Objects lessons come later in this course). That last pair catches people out: a check that tests whether [] is truthy passes. Ask JavaScript directly with Boolean(value).

Why a tester cares. A price of 0 is falsy, so a check that only asks "is there a price?" treats a free item as a missing one. When zero is a valid answer, compare against undefined or null instead. The next lesson, Decisions: if, else and switch, uses these answers to choose what the code does next.

Practise this. Read each line of the code box and predict what it prints before you press Run.

javascript
// Comparisons answer true or false console.log('3 > 2:', 3 > 2); console.log("'Total' === 'total':", 'Total' === 'total'); // false: case matters // Strict (===) vs loose (==) console.log("1 === '1':", 1 === '1'); // false: different types console.log("1 == '1':", 1 == '1'); // true: coercion, the trap // Text compares letter by letter. Convert before comparing prices. console.log("'10' < '9':", '10' < '9'); // true (!) console.log("Number('10') < Number('9'):", Number('10') < Number('9')); // false // Combining checks const loggedIn = true; const isAdmin = false; console.log('loggedIn && isAdmin:', loggedIn && isAdmin); // false: both needed console.log('loggedIn || isAdmin:', loggedIn || isAdmin); // true: either is enough console.log('!loggedIn:', !loggedIn); // false // Truthy or falsy? Boolean() tells you. console.log('Boolean(0):', Boolean(0)); // false console.log("Boolean(''):", Boolean('')); // false console.log('Boolean(null):', Boolean(null)); // false console.log('Boolean(undefined):', Boolean(undefined)); // false console.log('Boolean(NaN):', Boolean(NaN)); // false console.log("Boolean('0'):", Boolean('0')); // true: text, not the number console.log("Boolean('false'):", Boolean('false')); // true console.log('Boolean([]):', Boolean([])); // true: an empty list is truthy console.log('Boolean({}):', Boolean({})); // true
Finished reading? Tick it off.

Sign in to track your progress

Checkpoint 2 of 3

Decisions: if, else and switch

In plain English. Control flow is how a program decides what to do next. Tests do this constantly: if the status code is 200, carry on; if it is 404, report a missing page. if and else choose between paths, and switch picks one path out of several for a single value. Each choice rests on a comparison, which the last lesson (Comparisons and Truthiness) covered. A block is the group of lines inside curly braces { } that belong to one path. This lesson is about choosing; repeating a step is the next lesson, Loops.

if, else if and else. The line if (status === 200) asks a yes/no question. If the answer is yes, the block after it runs. else if adds another question to try when the first was no, and else catches everything left over. The check inside the parentheses does not have to be a comparison: any value works, and a truthy one counts as yes.

The ternary operator. For a choice between two values, the ternary operator (condition ? trueValue : falseValue) fits on one line. It is shorthand, so keep it for short choices and use if when a path needs several lines.

switch. JavaScript has a switch statement for picking one path out of several for a single value. switch uses strict equality (===) for its comparisons under the hood. Each path ends with break; leave it out and the code carries on into the next path as well. default runs when no case matches.

javascript
const status = 200; if (status === 200) { console.log('Success!'); } else if (status === 404) { console.log('Not Found'); } else { console.log('Unknown error'); } // The ternary operator: one value or the other, on one line const label = status === 200 ? 'passed' : 'failed'; console.log('Result:', label); const action = 'START'; switch (action) { case 'START': console.log('Starting...'); break; default: console.log('Idle'); } // Leave out break and the code falls through into the next case switch (404) { case 404: console.log('Not Found'); case 500: console.log('...and this line runs too'); break; default: console.log('Unknown'); }
Finished reading? Tick it off.

Sign in to track your progress

Checkpoint 3 of 3

Loops: for, while, for...of and for...in

In plain English. A loop repeats a step. Tests need this whenever there is a list: check every row of a table, try every user in a list, read every price on a page. To iterate means to go through a collection one item at a time. Two kinds of collection matter here. An array is an ordered list of values in square brackets, such as ['apple', 'banana']; the Arrays: The Complete Guide lesson covers them properly. An object is a set of named values, like a user record with a name and a role; each name is called a key. You will meet one loop for lists and a different one for an object's keys.

The classic loops. The classic for loop (for (let i = 0; i < 10; i++): start at 0, keep going while i < 10, and add 1 to i after each round with i++), while loop, and do...while loop are all available, as are the break keyword (leave the loop now) and continue (skip to the next round). Be mindful of scope: declaring loop variables with var leaks them outside the loop block, which is why let is strongly preferred for loop counters.

for...of walks a list. While the classic for loop is useful, JavaScript has a simpler way to go through a list or a string: the for...of loop, which hands you each value directly with no index to manage.

for...in walks an object's keys. JavaScript also has a for...in loop. It goes through the keys of an object, one per round. Inside it, user[key] reads the property whose name is held in key; the Objects & Destructuring lesson covers that bracket form. Do not use for...in on an array: it hands you the positions as text ('0', '1') instead of the values. Stick to for...of for arrays, and for...in for inspecting object keys.

Practise this. Change the lists in the code box and predict how many times each loop runs before you press Run.

javascript
// The classic for loop: start, stop condition, step for (let i = 1; i <= 3; i++) { console.log('Attempt', i); } // while: keep going as long as the check is true let retries = 0; while (retries < 2) { retries++; console.log('Retry', retries); } // break leaves the loop; continue skips to the next round for (let n = 1; n <= 5; n++) { if (n === 2) continue; if (n === 4) break; console.log('n =', n); } // for...of (iterates values directly) const fruits = ['apple', 'banana', 'cherry']; for (const fruit of fruits) { console.log('Fruit:', fruit); } // for...in (for object properties) const user = { name: 'Jatin', role: 'Developer' }; for (const key in user) { console.log(`Key: ${key}, Value: ${user[key]}`); }
Finished reading? Tick it off.

Sign in to track your progress

Practice set

Practice and interview questions: JavaScript Basics

This is your first set of practice exercises. They use only what the last two chapters taught: values and variables, strings, numbers, comparisons, decisions and loops. Each one is a small script, themed on a job a tester does by hand: reading a value off a page, deciding what it means, and reporting it.

Write the code in a file or in the Run box, run it, and change the input to see whether it still behaves. Try the awkward inputs on purpose, such as an empty string, a missing @, or a value that is null. Remember that === checks exactly, while == converts types first, so === is almost always what you want.

Coding Exercises

  1. Extract the Domain (Easy) Problem: Store an email address in a const, such as 'tester@playwright.dev'. Print only the part after the @. If the email has no @, print Invalid email instead. Hint: includes('@') tells you whether the @ is there. email.split('@') cuts the text at the @ and gives back a list of the pieces; the second piece is parts[1], because positions count from zero.

  2. Status Code Labels (Easy) Problem: Store an HTTP status code in a const. Print Success for 200-299, Redirect for 300-399, Client Error for 400-499 and Server Error for 500-599. Print Unknown for anything else. Hint: An if / else if chain, with two comparisons joined by && for each range.

  3. Parse a UI Price (Medium) Problem: You read a price from a page: "Total: $1,234.56 USD". Turn it into the number 1234.56. Hint: Remove the pieces that are not part of the number with replace, one piece at a time, then convert what is left with parseFloat().

  4. First Plain Pattern (Medium) Problem: You have a list of text patterns, such as ['//button', '#save', '//a']. Print the first one that does NOT start with //. If every one starts with //, print the first one. Hint: A for...of loop with startsWith, and break once you have an answer. patterns[0] is the first item in the list.

  5. Safe Label (Medium) Problem: A label read from a page might be text, an empty string, or null (missing). Print the label with spaces trimmed off, or No label when there is no text. Hint: A label with no text is falsy, so the ternary label ? label.trim() : 'No label' covers it. Try it with ' Save ', '' and null.

Interview Questions

  1. What is the difference between var, let, and const? Answer: var is function-scoped (it exists everywhere inside the function it is declared in; Functions Deep Dive introduces functions). let and const are block-scoped, which means they exist only inside the { } where they were declared. const prevents reassignment, though objects declared with const can still be mutated.

  2. Why should you use === instead of ==? Answer: == performs type coercion (e.g., "1" == 1 is true). === checks both value and type, preventing unexpected bugs.

  3. What is the difference between null and undefined? Answer: undefined means a variable has been declared but not assigned a value. null is an explicit assignment representing "no value".

  4. What is NaN and how do you check for it? Answer: NaN stands for Not-a-Number, representing an invalid mathematical operation. Check it using Number.isNaN(value). Interestingly, typeof NaN returns "number".

  5. Which values are falsy in JavaScript? Answer: false, 0, -0, 0n, "", null, undefined and NaN. Everything else is truthy, including "0", "false", [] and {}.

  6. What does '5' + 2 give, and what does '5' * 2 give? Answer: '5' + 2 gives the text '52', because + joins text when either side is text. '5' * 2 gives the number 10, because * only does arithmetic and converts the text first.

javascript
// Exercise 1: Extract the Domain const email = 'tester@playwright.dev'; if (email.includes('@')) { const parts = email.split('@'); console.log(parts[1]); // Expected: playwright.dev } else { console.log('Invalid email'); } // Exercise 2: Status Code Labels const code = 404; if (code >= 200 && code <= 299) { console.log('Success'); } else if (code >= 300 && code <= 399) { console.log('Redirect'); } else if (code >= 400 && code <= 499) { console.log('Client Error'); // Expected for 404 } else if (code >= 500 && code <= 599) { console.log('Server Error'); } else { console.log('Unknown'); } // Exercise 3: Parse a UI Price const priceText = 'Total: $1,234.56 USD'; const cleaned = priceText.replace('Total: $', '').replace(' USD', '').replace(',', ''); console.log(parseFloat(cleaned)); // Expected: 1234.56 // Exercise 4: First Plain Pattern const patterns = ['//button', '#save', '//a']; let chosen = patterns[0]; // fall back to the first one for (const pattern of patterns) { if (!pattern.startsWith('//')) { chosen = pattern; break; } } console.log(chosen); // Expected: #save // Exercise 5: Safe Label for (const label of [' Save ', '', null]) { console.log(label ? label.trim() : 'No label'); // Expected: Save, No label, No label }
Finished reading? Tick it off.

Sign in to track your progress