JavaScript Cheat Sheet for Testers
The JavaScript a tester actually uses in Playwright, Cypress and Postman — on one page. Every result shown in the comments was checked by running the code in Node.js. For explanations and exercises, see The Complete JavaScript for Testers Guide.
Variables ⭐
const apiUrl = 'https://api.example.com'; // ⭐ default — can't be reassigned
let counter = 0; // reassignable, block-scoped
var old = 'avoid'; // function-scoped, hoisted — don't use
var |
let |
const |
|
|---|---|---|---|
| Scope | Function | Block | Block |
| Reassign | ✅ | ✅ | ❌ |
| Use before declaration | undefined |
ReferenceError | ReferenceError |
const isn't immutable — the variable can't be reassigned, but an object's properties can change (user.name = 'Alex' works; user = {} throws).
Types and Equality
'5' == 5 // true — == converts types
'5' === 5 // false — ⭐ always use ===
typeof null // 'object' (a long-standing quirk)
typeof [] // 'object' → use Array.isArray([]) → true
Number('12px') // NaN
parseInt('12px') // 12
undefined = declared but not assigned; null = deliberately empty.
Falsy values: false, 0, '', null, undefined, NaN — everything else, including [] and {}, is truthy.
Strings
const email = ' Asha@Example.com ';
email.trim().toLowerCase() // 'asha@example.com'
email.includes('@') // true
'Order #1043'.match(/\d+/)[0] // '1043' — pull an ID out of text
'a,b,c'.split(',') // ['a', 'b', 'c']
'abc'.padStart(5, '0') // '00abc'
const id = 7;
`User ${id} has ${id * 2} points` // 'User 7 has 14 points' — template literal
Trimming and normalizing case before comparing UI text avoids many false failures.
Functions
function login(user, pass) { return true; } // declaration — hoisted
const double = n => n * 2; // arrow, implicit return
const getUser = () => ({ id: 1 }); // returning an object needs ( )
function search(term, limit = 10, ...filters) {} // default + rest parameters
Arrow functions don't have their own this — which is why they're the norm in test callbacks.
Arrays ⭐
const users = [{ name: 'Asha', age: 30, active: true },
{ name: 'Ravi', age: 25, active: false }];
users.map(u => u.name) // ['Asha', 'Ravi'] — transform every item
users.filter(u => u.active) // [Asha] — keep matches
users.find(u => u.name === 'Ravi') // Ravi's object — first match or undefined
users.some(u => u.active) // true — any?
users.every(u => u.active) // false — all?
users.reduce((sum, u) => sum + u.age, 0) // 55 — combine into one value
users.forEach(u => console.log(u.name)) // just loops, returns nothing
[3, 1, 10].sort() // [1, 10, 3] ⚠️ sorts as strings!
[3, 1, 10].sort((a, b) => a - b) // [1, 3, 10]
Also: push/pop, includes, indexOf, slice, join, and spread [...users, extra]. The sort() trap bites when checking that prices are sorted.
Objects, Destructuring and Spread
const user = { id: 1, name: 'Nav', address: { city: 'Bangalore' } };
user.address.city // nested
user?.address?.zip // undefined, no error — optional chaining
Object.keys(user) // ['id', 'name', 'address']
const { name, role = 'tester', address: { city } } = { name: 'Asha', address: { city: 'Pune' } };
// name = 'Asha', role = 'tester' (default), city = 'Pune'
const [first, ...rest] = [10, 20, 30]; // first = 10, rest = [20, 30]
const base = { env: 'qa', retries: 1 };
{ ...base, retries: 2 } // { env: 'qa', retries: 2 } — copy and override
Playwright fixtures use destructuring constantly: async ({ page, request }) => { … }.
JSON — the Tester's Daily Bread
JSON.parse(responseText); // string → object
JSON.stringify(payload); // object → string
JSON.stringify(obj, null, 2); // pretty-printed
try { JSON.parse('{bad json}'); } catch (e) { e.name; } // 'SyntaxError'
Null-Safe Operators
const city = user?.address?.city; // optional chaining
0 || 'default' // 'default' — || replaces ANY falsy value
0 ?? 'default' // 0 — ?? replaces only null/undefined
const msg = status === 200 ? 'OK' : 'Failed'; // ternary
Use ?? for defaults when 0 or '' are valid values (a quantity of 0, an empty search).
Loops
for (let i = 0; i < 5; i++) {}
for (const u of users) {} // ⭐ values of an array
for (const k in obj) {} // keys of an object — not for arrays
Classes (Page Objects)
class LoginPage {
constructor(page) { this.page = page; }
async open() { await this.page.goto('/login'); }
}
Async JavaScript ⭐⭐
The most important section for automation: browser actions and API calls are asynchronous and return Promises. Forget await and the next line runs before the action finishes.
// Promise states: pending → fulfilled | rejected
async function getUser(id) {
try {
const res = await fetch(`/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (err) {
console.error('Request failed:', err.message);
throw err;
}
}
// Run independent calls in parallel
const [a, b] = await Promise.all([getUser(1), getUser(2)]); // two 100 ms waits → ~100 ms total
// ❌ Flaky — missing await
page.click('#submit');
expect(page.locator('#msg')).toBeVisible();
// ✅ Correct
await page.locator('#submit').click();
await expect(page.locator('#msg')).toBeVisible();
Rules: await every Playwright action and web-first assertion; only use await inside async functions (or ES modules); don't use forEach with async callbacks — use for…of or Promise.all.
More: Playwright Auto-Wait.
Modules
export class LoginPage { … } // pages/LoginPage.js
import { LoginPage } from '../pages/LoginPage'; // tests/login.spec.js
Where You'll Use It
| Tool | Where JavaScript appears | Example |
|---|---|---|
| Playwright | The whole test — async/await everywhere | await expect(page).toHaveURL(/dashboard/) |
| Cypress | Test code and chained commands | cy.get('#msg').should('be.visible') |
| Postman | Pre-request and Tests tabs | pm.expect(pm.response.json().id).to.be.a('number') |
| Selenium | JavaScriptExecutor snippets | arguments[0].scrollIntoView({block: 'center'}) |
| Browser DevTools | Console checks and quick scripts | $$('a').length |
See Postman, Playwright and JavaScriptExecutor for more.
Testing yourself before an interview? JavaScript questions come up in the Playwright Interview Simulator, and JavaScriptExecutor questions in the Selenium Interview Simulator.
From Real Projects
My automation background is Java with Selenium and TestNG. JavaScript comes up more and more for testers because tools like Playwright and Cypress are built on it — and most concepts on this page have a direct Java equivalent. Learning it alongside Java makes switching between frameworks much easier. Focus on async/await first — it's behind most JavaScript test issues. Further reading: JavaScript Variables.
📚 Official documentation: MDN: JavaScript Guide · dev.java: Learn Java (Oracle)
FAQs
How much JavaScript does a tester need?
Variables, strings, arrays, objects, JSON and — above all — Promises and async/await. That covers Playwright, Cypress and Postman.
Why do my Playwright tests fail randomly?
Often a missing await, or a one-shot value check instead of a web-first assertion. Await every action and use expect(locator) assertions.
== or ===?
Always ===. == converts types first, so '5' == 5 is true.
Why does [3, 1, 10].sort() give [1, 10, 3]?
Without a comparator, sort() compares values as strings. Use sort((a, b) => a - b) for numbers.
|| or ?? for defaults?
?? when 0 or '' are valid values; || replaces any falsy value.