Variables ⭐
const apiUrl = 'https://api.com'; // ⭐ default — can't reassign
let counter = 0; // reassignable, block-scoped
var old = 'avoid'; // function-scoped, hoisted — don't use
var |
let |
const |
|
|---|---|---|---|
| Scope | Function | Block | Block |
| Reassign | ✅ | ✅ | ❌ |
| Hoisted | ✅ | ❌ | ❌ |
⚠️ const ≠ immutable — you can't reassign the variable, but you can mutate the object:
const user = { name: 'Nav' };
user.name = 'Alex'; // ✅ allowed
user = {}; // ❌ TypeError
Equality: always === (value and type). == coerces: '5' == 5 is true, '5' === 5 is false.
null vs undefined: undefined = declared, not assigned. null = deliberately empty.
Functions
// Declaration — hoisted
function login(user, pass) { return true; }
// Arrow — no own `this`, concise
const login = (user, pass) => true;
const double = n => n * 2; // implicit return
const getUser = () => ({ id: 1 }); // returning an object needs ( )
// Default + rest params
function search(term, limit = 10, ...filters) {}
Arrow vs regular: arrows don't have their own this, arguments, and can't be constructors. For test code, arrows are almost always fine.
Arrays ⭐
const users = ['admin', 'user', 'guest'];
users.length // 3
users[0] // 'admin'
users.push('new') // add to end
users.pop() // remove from end
users.includes('admin') // true
users.indexOf('user') // 1
users.join(', ') // 'admin, user, guest'
users.slice(0, 2) // copy a portion
[...users, 'extra'] // spread
The four that matter most:
| Method | Returns | Use |
|---|---|---|
map() |
New array, transformed | Extract/convert every item |
filter() |
New array, subset | Keep matching items |
find() |
First match (or undefined) | Locate one item |
forEach() |
Nothing | Just iterate |
const names = users.map(u => u.name);
const admins = users.filter(u => u.role === 'admin');
const nav = users.find(u => u.name === 'Nav');
users.forEach(u => console.log(u.name));
// Also useful
users.some(u => u.active) // any match? → boolean
users.every(u => u.active) // all match? → boolean
users.reduce((sum, u) => sum + u.age, 0);
Objects & JSON ⭐
const user = { id: 1, name: 'Nav', address: { city: 'Bangalore' } };
user.name // dot notation
user['name'] // bracket notation
user.address.city // nested
user?.address?.zip // optional chaining — safe if missing
Object.keys(user) // ['id','name','address']
Object.values(user)
Object.entries(user) // [['id',1], ...]
{ ...user, name: 'Alex' } // spread + override
// Destructuring ⭐ — everywhere in API tests
const { id, name } = user;
const { address: { city } } = user;
const [first, second] = users;
JSON — the tester's daily bread:
JSON.parse(responseText); // string → object
JSON.stringify(payload); // object → string
JSON.stringify(obj, null, 2); // pretty-printed
Async JavaScript ⭐⭐
The single most important section for automation. Browser actions and API calls are asynchronous — forgetting await is a top cause of flaky tests.
// Promise states: pending → fulfilled | rejected
// .then() chain (older style)
fetch(url)
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
// ⭐ async/await — cleaner, use this
async function getUser(id) {
try {
const res = await fetch(`/users/${id}`);
const data = await res.json();
return data;
} catch (err) {
console.error('Failed:', err);
}
}
// Parallel — when calls don't depend on each other
const [users, orders] = await Promise.all([getUsers(), getOrders()]);
The rules:
awaitonly works inside anasyncfunctionawaitpauses until the promise settles- Use
try/catchfor errors - Missing
await= your assertion runs before the action finishes
// ❌ Flaky — no await
page.click('#submit');
expect(page.locator('#msg')).toBeVisible();
// ✅ Correct
await page.click('#submit');
await expect(page.locator('#msg')).toBeVisible();
Conditions & Loops
if (status === 200) {} else if (status === 404) {} else {}
const msg = status === 200 ? 'OK' : 'Failed'; // ternary
const name = user.name ?? 'Guest'; // nullish coalescing
const city = user?.address?.city; // optional chaining
for (let i = 0; i < 5; i++) {}
for (const u of users) {} // ⭐ values (arrays)
for (const k in obj) {} // keys (objects)
while (retries < 3) { retries++; }
Falsy values: false 0 '' null undefined NaN — everything else is truthy.
Where You'll Use This
| Tool | JavaScript use |
|---|---|
| Playwright | The whole test — async/await everywhere |
| Postman | Tests tab — pm.expect, JSON parsing |
| Cypress | Test code + chained commands |
| Selenium | JavaScriptExecutor snippets |
Go Deeper
- Complete JavaScript for Testers Guide — the full path
- Top 15 JavaScript Questions — interview prep
- Playwright Cheat Sheet · Postman Cheat Sheet