The Testing Academy · Class Notes Monday, 12 October (IST)
Live class · study guide

The ternary operator and nested ternaries, typeof once more, pre and post increment with the divide-and-conquer method, and nullish coalescing

The ternary operator, four ways it shows up in automation code, and template literals. Then nested ternaries, including an interview question from Bingify, typeof once more, and pre and post increment and decrement, worked out with the divide-and-conquer method on an interview question from Zeta. It ends with nullish coalescing (??) and a look at the bitwise operators automation never uses. Files 26 to 45, pushed to the batch repo.

By Pramod Dutta, The Testing Academy. Study notes from the seventh class of Playwright 4x, built from the session recording, the batch repository, which received files 26 to 45 and the README cheat-sheet images as the class ended (commit "feat: add ch04 ternary, ch05 and README images"), and the Eraser notes deck. Every file was run with Node 22, and the output shown is what it prints.

01

What this class covered

  • != versus !==, and the !=== that does not exist
  • Strings: += joins, commas in console.log only print
  • The ternary operator: syntax, and the Goa example
  • Ternaries in automation code: pass or fail, base URL, headless on CI, an SLA check
  • Template literals: backticks and ${}
  • Nested ternaries: Goa and drink, the status-code question from Bingify, the temperature trap
  • typeof once more, and the data types diagram
  • Increment and decrement: pre and post
  • Divide and conquer: three interview questions, including Zeta's
  • Nullish coalescing (??)
  • Bitwise operators, which automation never uses
  • Recap: the ten groups of operators
  • Tasks: 45 exercises on GitHub, three QA battles, attendance
02

!= versus !==, and the operator that does not exist

The warm-up picked up where the last class stopped. The class's file:

JavaScript
console.log(5 != "5");
console.log(5 !== "5");
// console.log(5 !=== "5");
Text
false
true

!= is the loose not-equal: it converts "5" to the number 5 first, finds the two sides equal, and answers false. !== is the strict not-equal: a number and a string are different types, so it answers true.

The commented-out third line is the point: there is no !===. Strict not-equal is !==, two equals signs after the !. Uncomment the line and the file does not even start:

Text
console.log(5 !=== "5");
                 ^

SyntaxError: Unexpected token '='
03

Strings: += joins, commas only print

JavaScript
let s = "Hi, ";
console.log(typeof s);
s += "Dev";
console.log(s);

console.log("HELLO", "Prrammod");
console.log("Hello" + "World");

console.log(1, 2, 3, 4, "Hello", true);
Text
string
Hi, Dev
HELLO Prrammod
HelloWorld
1 2 3 4 Hello true
  • typeof s is "string". The interview version of the question is just "what is the type of s?"
  • s += "Dev" is short for s = s + "Dev". With strings, + concatenates, so s becomes "Hi, Dev".
  • "Hello" + "World" makes one new string, "HelloWorld", with no space, because none was in either string.
  • Commas do not join anything. console.log("HELLO", "Prrammod") hands console.log two separate values, and it prints them with a space between. That is why the last line can mix numbers, a string and a boolean: it is printing, not concatenation.
04

The ternary operator

A ternary operator is a condition with two possible answers: either this or that. The syntax, from the class notes:

Text
condition ? value1 (if true) : value2 (if false)

The class's example: can I go to Goa? Only if my age is over 18. With an age of 20 the answer was "Yes". Change it to 17, as the file now has it:

JavaScript
let age = 17;
let can_I_go = age > 18 ? "Yes" : "No";
console.log(can_I_go);
Text
No

age > 18 is checked first. It is false, so the value after the colon, "No", is the one stored in can_I_go. It comes up in interviews, so know the order: condition, question mark, value if true, colon, value if false.

A flowchart titled Ternary Operator. A yellow diamond holds the condition status === 200 ?. A true arrow leads to a green PASS box and a false arrow to a red FAIL box. Below it, the code: let result = status === 200 ? "PASS" : "FAIL";
From the batch repo's README: the ternary as a flowchart, the same pass or fail check as file 29.
05

Ternaries in automation code

"Where is this used?" Four examples, each a pattern you will meet in real test code.

Pass or fail from a status code, in API testing, where the actual and expected status codes are both 200:

JavaScript
let actualStatusCode = 200;
let expectedStatusCode = 200;
let testResult = actualStatusCode === expectedStatusCode ? "✅ PASS" : "❌ FAIL";
console.log(testResult);
Text
✅ PASS

Base URL by environment:

JavaScript
let environment = "staging";
let baseUrl = environment === "prod"
    ? "https://api.example.com"
    : "https://staging-api.example.com";
console.log(baseUrl);
Text
https://staging-api.example.com

environment === "prod" is false for "staging", so the second URL is the one stored.

Headless on CI: CI is continuous integration, the server that runs your tests on every change.

JavaScript
let isCI = true;
let browserMode = isCI ? "headless" : "headed";
console.log("Launching browser in:", browserMode, "mode");
Text
Launching browser in: headless mode

One question from the room: does isCI ? ... set isCI? No. The condition is only read; the chosen value is assigned to browserMode, the variable on the left of the =.

An SLA check, where an SLA (service level agreement) says a response must arrive within 1000 ms:

JavaScript
let responseTime = 850;  // ms
let sla = 1000;          // ms
let slaStatus = responseTime <= sla ? "Within SLA ✅" : "SLA breached ❌";
console.log(`Response: ${responseTime}ms - ${slaStatus}`);


// Template Literal
console.log(`What is the SLA time ? - ${sla}`);
Text
Response: 850ms - Within SLA ✅
What is the SLA time ? - 1000

850 is less than or equal to 1000, so slaStatus is "Within SLA ✅".

06

Template literals

The strings in that last file use backticks, not quotes. That makes them template literals: each ${...} is replaced by the value of what is inside it. In the first line, ${responseTime} becomes 850 and ${slaStatus} becomes "Within SLA ✅"; in the second, ${sla} becomes 1000.

JavaScript
let condition = true;
let isSKMale = condition ? true : false;
console.log(isSKMale);
console.log(`Value is , ${isSKMale}`);
Text
true
Value is , true

The condition is true, so isSKMale is true, and the template literal prints it inside a sentence.

Can you use double quotes instead? Only when nothing needs replacing. Inside double quotes, ${isSKMale} is just text and prints exactly as typed. Backticks are for strings with values in them.

07

Nested ternaries

A nested ternary is a ternary inside a ternary, for when there is more than one condition. Over 18, you can go to Goa. In the class's example, over 25 as well and you can also drink, the age limit in Maharashtra. Two conditions, so the true branch of the first ternary holds a second one:

JavaScript
// Nested Ternary
// Multiple Conditions
// age = 26
// age > 18 -> Go Goa, age > 25 -> Drink

let age = 26;

let is_pramod_enjoy = ( age > 18) ? (age > 25 ? "Goa & Drink" : "No Drink,ONly Goa") : "No Goa";
console.log(`Pramod can Enjoy ${is_pramod_enjoy}`);
Text
Pramod can Enjoy Goa & Drink

26 is greater than 18, so the inner ternary runs. 26 is greater than 25 as well, so the value is "Goa & Drink".

The interview question, asked at Bingify: a ternary within a ternary within a ternary.

JavaScript
let statusCode = 404;
let category =
    statusCode < 300 ? "Success" :
        statusCode < 400 ? "Redirect" :
            statusCode < 500 ? "Client Error" : "Server Error";



console.log(`Status ${statusCode}: ${category}`);
Text
Status 404: Client Error

It looks crazy, and it is simple once you take it one condition at a time:

READ THE CHAIN TOP TO BOTTOM: THE FIRST TRUE CONDITION WINS let statusCode = 404; CONDITION 1 statusCode < 300 404 < 300 is false IF TRUE "Success" skipped true CONDITION 2 statusCode < 400 404 < 400 is false IF TRUE "Redirect" skipped true CONDITION 3 statusCode < 500 404 < 500 is true IF TRUE "Client Error" assigned to category true false false false OTHERWISE "Server Error" never reached
The status-code chain from file 35, run with 404. Each ? : pair asks one question. The first two say false, so their values are skipped; the third says true, so "Client Error" is assigned and the last branch never runs.

One more, to confuse you on purpose:

JavaScript
let temp = 35;
let feel = (temp >= 40) ? "Very Hot" :
    (temp >= 30) ? "Hot" :
        (temp >= 20) ? "Warm" :
            (temp >= 10) ? "Cool" : "Cold";
console.log("7. Temperature:", temp, "| Feel:", feel);
Text
7. Temperature: 35 | Feel: Hot

35 is not 40 or more, so "Very Hot" is skipped. 35 is 30 or more, so the value is "Hot", and the chain stops there. temp >= 20 and temp >= 10 are also true for 35, but they are never checked: the first true condition wins.

08

typeof, once more

JavaScript
console.log(typeof "hello");
console.log(typeof 123); // number
console.log(typeof 31.4); // number

// typeof true
//typeof undefined
// typeof null -> object
Text
string
number
number

There is no float type in JavaScript: 123 and 31.4 are both number. The commented lines were answered aloud, and the class notes add arrays. They print:

Expression typeof says
typeof true "boolean"
typeof undefined "undefined"
typeof null "object", the exception to remember
typeof [] "object", an array is an object

The data types diagram went up next. The primitive types: number, BigInt, string, boolean, null, undefined and symbol, and symbol is not used in automation. The non-primitive types: objects, arrays, functions, dates and regular expressions. The full operator notes, with an example for every operator, are linked at the top of the SDET Club.

09

Increment and decrement: pre and post

++ adds 1 to a variable and -- subtracts 1. Each comes in two forms, and the difference is the whole topic:

  • Pre (++a): first increase the value by 1, then use it.
  • Post (a++): first use the value, then increase it by 1.

Pre-increment, the first file of a new chapter:

JavaScript
// Pre Increment
let a = 10;
let b = ++a;
console.log(b);
console.log(a);
Text
11
11

++a makes a 11 first, then assigns 11 to b. Post-increment:

JavaScript
// Post Increment
let a = 10;
let b = a++;
console.log(b);
console.log(a);
Text
10
11

a++ assigns the current value, 10, to b first, then makes a 11.

A comparison titled Pre vs Post Increment, starting from a = 10. Left, Pre: ++a, for let b = ++a;: step 1, a becomes 11; step 2, b gets 11. Right, Post: a++, for let b = a++;: step 1, b gets 10; step 2, a becomes 11. A banner at the bottom reads: Pre changes first. Post uses first.
From the batch repo's README: files 38 and 39 side by side. Pre changes first; post uses first.

Decrement works the same way. Pre-decrement:

JavaScript
let a = 10;
let b = --a;
console.log(b);
console.log(a);
Text
9
9

Post-decrement:

JavaScript
let a = 10;
let b = a--;
console.log(b);
console.log(a);
Text
10
9

The class also opened the batch's coding-exercise platform here: 150 interview questions for SDETs and automation testers, worth points for every program you solve. The first one, printing Hello World, was solved live with a plain console.log.

10

Divide and conquer: the interview questions

The easy cases are easy. Questions mix pre and post increment in one expression, and that is where people get confused. The method borrows its name from the British in India, divide and rule:

  1. Split the expression at every + into parts: A, B, C.
  2. Work out the parts left to right, writing down the value of the variable after each one.
  3. Add the parts.

First question:

JavaScript
let a= 10;
console.log(++a + a);
console.log(a);
Text
22
11
Part Code Value of the part a afterwards
A ++a 11 11
B a 11 11
Total A + B 22 11

The real one, asked at Zeta. Answers in the chat ranged over 33, 32 and 12, and plenty of people get it wrong in interviews:

JavaScript
let a = 10;
console.log(++a + a + a++);
console.log(a);
Text
33
12
SPLIT AT EVERY +, THEN WALK LEFT TO RIGHT let a = 10; ++a part A a part B a++ part C + + PART A A = 11 add 1 to a first, so a is now 11 PART B B = 11 just reads a, which is still 11 PART C C = 11 uses a first (11), then a becomes 12 RESULT A + B + C = 11 + 11 + 11 = 33 console.log(a) then prints 12, the value left after part C
File 41, the Zeta question, by divide and conquer: split at every +, work out each part in order, and keep track of a after each one. Pre-increment changes a before it is used; post-increment uses it first.

"Why is a 12 at the end?" Because part C is a post-increment: it hands over 11 first, and only then increases a to 12.

One more, with i:

JavaScript
let i = 1;
let result = i++ + ++i;
console.log(result,i );
Text
4 3
Part Code Value of the part i afterwards
A i++ 1 2
B ++i 3 3
Total A + B 4 3

console.log(result, i) prints two values separated by a comma, which console.log shows with a space: 4, then 3.

11

Nullish coalescing (??)

The last operator of the day, and a difficult one to pronounce: nullish coalescing, written ??. The class notes put it simply: if the value on the left is null, the value on the right is assigned.

The class's analogy: you want Amul milk, but there is none, so Nandini milk it is.

Two panels showing the same small wooden shelf with one slot. Left, titled null, with the sublabel Use the fallback: the slot is an empty dashed outline of a milk carton, and a pale pink carton slides in from the right along a curved terracotta arrow. Right, titled Has a value, with the sublabel Keep the value: a terracotta carton already stands in the slot, and the pale pink carton waits unused on the floor beside the shelf.
The milk analogy as code sees it: ?? reaches for the fallback only when the left side is missing.

The file, with the first two examples still commented out:

JavaScript
// let amul = null;
// let val = amul ?? "NANDANI Milk";
// console.log(val);


// let api_response = null;
// let responsedata = api_response ?? "{}";
// console.log(responsedata);

let api_response1 = "Pramod";
let responsedata1 = api_response1 ?? "{}";
console.log(responsedata1);
Text
Pramod

api_response1 holds "Pramod", which is not null, so ?? changes nothing. Uncomment the first two examples and the file prints their fallbacks first:

Text
NANDANI Milk
{}
Pramod
?? ASKS ONE QUESTION: IS THE LEFT SIDE NULL OR UNDEFINED? left side the question the value you get LEFT SIDE amul let amul = null; NULL OR UNDEFINED? yes use the right side VALUE "NANDANI Milk" the right side LEFT SIDE api_response let api_response = null; NULL OR UNDEFINED? yes use the right side VALUE "{}" the right side, a string LEFT SIDE api_response1 let api_response1 = "Pramod"; NULL OR UNDEFINED? no keep the left side VALUE "Pramod" the left side, kept
The three examples in file 45. The right side only gets through when the left side is missing. "{}" is in quotes, so here it is a two-character string, not an empty object.

Null or undefined. In class, ?? was described as a check for null. It also catches undefined: ?? uses the right side when the left side is null or undefined, so let u; console.log(u ?? "fallback"); prints fallback. Any other value is kept as it is, even 0 or "". The repo's README gives the full rule, with a comparison against ||.

12

Bitwise operators: know they exist

Bitwise operators work on the binary bits of a number: AND, OR, XOR, NOT, left shift and right shift, the gates from electronics. They are never used in automation, and the class did not cover them. The examples from the class notes, if you are curious:

JavaScript
5 & 1    // 1  (AND)
5 | 1    // 5  (OR)
5 ^ 1    // 4  (XOR)
~5       // -6 (NOT)
5 << 1   // 10 (Left shift)
5 >> 1   // 2  (Right shift)

All six results check out when run. To learn more, RapidTables covers them.

What you do need is the difference in the symbols. A single & is bitwise AND. A double && is logical AND, the one you will actually use. Do not mix them up.

13

The ten groups of operators

The recap, as the class notes list them:

  1. Assignment
  2. Logical (&&, ||)
  3. Arithmetic
  4. Comparison
  5. String concatenation
  6. Type (typeof)
  7. Bitwise (&, |)
  8. Ternary
  9. Increment and decrement
  10. Nullish coalescing

The class also showed cheat-sheet diagrams for revision, a style the instructor calls handwritten notes, made with ChatGPT. The batch repo's README now carries one cheat-sheet image per chapter, including the two on this page.

14

Tasks and announcements

  • 45 exercises on GitHub. The class's own push was done by AI with one prompt: "Please update the parent README file with images also. Also commit the changes and push the code to repo." Push yours, 45 or more, to your Playwright repository. The instructor runs a GitHub agent over every learner's repository today and reads the report.
  • QA battles. Sign-in is LinkedIn only, no Gmail, to keep spam out, and the instructor can see who is winning. There are battles just for the Playwright batch. Use your real name on your profile.
  • Coding exercises. Work through the 150 questions over the next 90 to 100 days, in JavaScript.
  • Audio conversations in class start slowly this week.
  • Questions from the end of class. console is not a keyword. A warning in VS Code that name is deprecated can be ignored. Backticks are only needed when a value is substituted in. And a broken GitHub token is fixed by deleting it and creating a new one.
  • Next class: conditions, the if statement and for loops.

Task 1, attendance. Mark today's attendance, with what you learned.

Task 2, the exercises. Push files 01 to 45, or more, to your GitHub repository.

Task 3, three QA battles. Complete three battles this week.

Task 4, the hard increment questions. Meeti posts today's task: long chains that mix ++ and --, pre and post. Solve them with the divide-and-conquer method. Doubts go in today's doubt thread.