दिन 27: Testing और Interview तैयारी
✅ आज आप सीखेंगे
- Automated tests समय (और नौकरियाँ) क्यों बचाते हैं
- node:test और assert से unit tests
- Edge cases test करना और test-first से bug ठीक करना
- Units के लिए Jest/Vitest, browser के लिए Playwright
- सबसे ज़्यादा पूछे JavaScript interview सवाल और coding tasks
🏢 असली दुनिया में
Diwali की भीड़ में एक developer ने delivery-fee नियम बदला और ग़लती से ₹1,500 से ऊपर के हर order पर ₹60 अतिरिक्त लगने लगे। दो दिन तक किसी ने नहीं देखा। 10-line का test live होने से पहले एक सेकंड में पकड़ लेता। Companies अब freshers से basic tests लिखने – और क्लासिक JavaScript सवालों के आत्मविश्वासी जवाबों की उम्मीद करती हैं।
हाथ से जाँच बनाम automated tests
Manual testing
- हर बदलाव के बाद site पर click करते रहना
- धीमा, उबाऊ, छोड़ना आसान
- Edge cases भूल जाते हैं
- Bugs customers तक
Automated tests
- Code जो code जाँचता है
- सेकंडों में सैकड़ों जाँच
- Edge cases एक बार लिखे, हमेशा जाँचे
- Deploy से पहले bugs पकड़े (CI)
node:test से आपके पहले tests
const { test } = require('node:test');
const assert = require('node:assert/strict');
// --- code under test ---
const FREE_FROM = 1500, FEE = 60;
function deliveryFee(subtotal) {
if (subtotal <= 0) return 0;
return subtotal >= FREE_FROM ? 0 : FEE;
}
function orderTotal(items, coupon) {
const subtotal = items.reduce((s, i) => s + i.price * i.qty, 0);
const discounted = coupon === 'SWEET10' ? Math.round(subtotal * 0.9) : subtotal;
return discounted + deliveryFee(discounted);
}
// --- tests ---
test('delivery is free from ₹1,500', () => {
assert.equal(deliveryFee(1500), 0);
assert.equal(deliveryFee(2400), 0);
});
test('₹60 delivery below ₹1,500', () => {
assert.equal(deliveryFee(1499), 60);
});
test('empty cart has no delivery fee', () => {
assert.equal(deliveryFee(0), 0);
});
test('coupon is applied before the delivery rule', () => {
// 1600 − 10% = 1440 → below 1500 → +60
assert.equal(orderTotal([{ price: 800, qty: 2 }], 'SWEET10'), 1500);
});| Assertion | क्या जाँचता है |
|---|---|
| assert.equal(a, b) | a === b (strict module) |
| assert.deepEqual(obj1, obj2) | एक जैसा ढाँचा और values |
| assert.ok(value) | Truthy |
| assert.throws(() => fn(), /message/) | अपेक्षित error throw करता है |
| await assert.rejects(promise) | Async function अपेक्षा अनुसार fail |
पैसे, dates और नियमों वाले pure functions: totals, discounts, GST, validation। सीमाएँ test करें – ठीक 1500, 1499, 0, negative, ख़ाली, बहुत बड़ा – bugs वहीं रहते हैं।
Test-first से bug ठीक करना
const { test } = require('node:test');
const assert = require('node:assert/strict');
// Bug report: "Mobile +91 98290 12345 is rejected on the order form"
function isValidMobile(input) {
const digits = input.replace(/\D/g, '');
const ten = digits.length === 12 && digits.startsWith('91') ? digits.slice(2)
: digits.length === 11 && digits.startsWith('0') ? digits.slice(1)
: digits; // ← the fix: accept 91/0 prefixes
return /^[6-9]\d{9}$/.test(ten);
}
test('accepts common Indian formats (the bug report)', () => {
for (const ok of ['9829012345', '+91 98290 12345', '098290-12345', '91-9829012345']) {
assert.ok(isValidMobile(ok), ok);
}
});
test('still rejects invalid numbers', () => {
for (const bad of ['5829012345', '98290', '+1 202 555 0101', '']) {
assert.equal(isValidMobile(bad), false, bad);
}
});- 1Bug दोहराने वाला test लिखें – fail होता है (red)
- 2ठीक करने वाला सबसे छोटा बदलाव – test pass (green)
- 3Code साफ़ करें; tests अब भी pass (refactor)
- 4Test हमेशा रखें ताकि bug कभी न लौटे
Job पर मिलने वाले testing tools
| Tool | प्रकार | उपयोग |
|---|---|---|
| node:test | Built-in unit tests | Utilities, Node APIs |
| Vitest / Jest | Unit + component tests | Functions, React components (Testing Library के साथ) |
| Playwright / Cypress | असली browsers में end-to-end | “Add to cart → checkout → order number दिखे” |
| Lighthouse CI | Performance और accessibility budgets | LCP बिगड़े तो build fail |
| GitHub Actions | Continuous integration | हर push / pull request पर सब tests |
import { test, expect } from '@playwright/test';
test('customer can order kaju katli', async ({ page }) => {
await page.goto('http://localhost:5173/');
await page.getByRole('button', { name: /add kaju katli/i }).click();
await page.getByRole('link', { name: /cart/i }).click();
await page.getByLabel('Name').fill('Aarti Gupta');
await page.getByLabel('Mobile').fill('9829012345');
await page.getByRole('button', { name: 'Place order' }).click();
await expect(page.getByText(/order SS\d+/i)).toBeVisible();
});शीर्ष interview सवाल – छोटे जवाब
Concept सवाल (देखने के लिए tap करें)
Q1. JavaScript में data types कौन से हैं?
Primitives: string, number, bigint, boolean, undefined, null, symbol। बाक़ी सब object है (arrays, functions, dates…)।
Q2. == और === में फ़र्क?
=== value और type दोनों तुलना करता है; == पहले types बदलता है। === लें।
Q3. Hoisting क्या है?
Code चलने से पहले declarations दर्ज होते हैं: functions पूरे, var undefined, let/const temporal dead zone में।
Q4. Closure क्या है?
ऐसा function जो अपने बनने की जगह के variables याद रखे – private state, factories, debounce में।
Q5. Event loop समझाइए।
एक call stack; async callbacks queues में; stack ख़ाली होने पर microtasks (promises) tasks (timers, events) से पहले।
Q6. map बनाम forEach?
map नया बदला array लौटाता है; forEach undefined लौटाता है और side effects के लिए।
Q7. Event delegation क्या है?
Parent पर एक listener bubbling और e.target.closest() से कई (भविष्य के भी) children के events संभालता है।
Q8. this कैसे काम करता है?
Call से तय: obj.method() → obj; साधारण call → undefined (strict); new → instance; bind/call/apply → दी value; arrows बाहरी this।
Q9. Promise.all बनाम allSettled?
all पहले reject पर तुरंत fail; allSettled सबका इंतज़ार करके हर नतीजा बताता है।
Q10. localStorage बनाम cookies?
localStorage: ~5 MB, JS पढ़ सकता है, server को नहीं जाता। Cookies: छोटी, requests के साथ जाती हैं, HttpOnly हो सकती हैं – sessions के लिए।
Q11. Debounce बनाम throttle?
Debounce calls रुकने के बाद (search box); throttle हर अंतराल में अधिकतम एक बार (scroll)।
Q12. XSS कैसे रोकें?
User data को text के रूप में render, HTML escape/sanitise, URLs validate, eval से बचें, CSP और HttpOnly cookies।
क्लासिक coding सवाल
// 1. Reverse words, 2. palindrome, 3. frequency count, 4. flatten, 5. remove duplicates, 6. chunk, 7. deep equal
const reverseWords = s => s.trim().split(/\s+/).reverse().join(' ');
const isPalindrome = s => { const c = s.toLowerCase().replace(/[^a-z0-9]/g, ''); return c === [...c].reverse().join(''); };
const frequency = arr => arr.reduce((m, x) => ((m[x] = (m[x] || 0) + 1), m), {});
const flatten = arr => arr.reduce((out, x) => out.concat(Array.isArray(x) ? flatten(x) : x), []);
const unique = arr => [...new Set(arr)];
const chunk = (arr, n) => Array.from({ length: Math.ceil(arr.length / n) }, (_, i) => arr.slice(i * n, i * n + n));
const deepEqual = (a, b) => {
if (a === b) return true;
if (typeof a !== 'object' || typeof b !== 'object' || !a || !b) return false;
const ka = Object.keys(a), kb = Object.keys(b);
return ka.length === kb.length && ka.every(k => deepEqual(a[k], b[k]));
};
console.log(reverseWords(' fresh ghewar daily '));
console.log(isPalindrome('Madam, in Eden I’m Adam'), isPalindrome('Rasmalai'));
console.log(frequency(['kaju', 'ladoo', 'kaju', 'ghewar', 'kaju']));
console.log(flatten([1, [2, [3, [4]], 5]]));
console.log(unique([302001, 302003, 302001, 302012]));
console.log(chunk(['A101', 'A102', 'A103', 'A104', 'A105'], 2));
console.log(deepEqual({ id: 1, tags: ['veg'] }, { id: 1, tags: ['veg'] }), deepEqual({ a: 1 }, { a: '1' }));| तैयारी | कैसे |
|---|---|
| अपने projects समझाना | STAR format: स्थिति, काम, कार्य, मापने योग्य नतीजा |
| Live coding | बोलकर सोचें, सरल शुरू करें, edge cases test, फिर optimise |
| Machine-coding round | 60–90 मिनट में to-do / debounce वाला search / modal – ठीक वही जो इस course में अभ्यास हुआ |
| Fundamentals | Closures, this, event loop, promises, array methods, DOM, CSS layout |
| Portfolio | Live links: HTML portfolio, CSS redesign, JS to-do, quiz और shop project |
🏅 आज के Job Skills
Practice tasks
🏋️ Practice – ख़ुद करें
Solution देखें
const { test } = require('node:test');
const assert = require('node:assert/strict');
function grade(m) {
if (m < 0 || m > 100) throw new RangeError('marks must be 0–100');
if (m >= 90) return 'A+';
if (m >= 75) return 'A';
if (m >= 60) return 'B';
if (m >= 33) return 'C';
return 'Fail';
}
test('grade boundaries', () => {
assert.equal(grade(100), 'A+');
assert.equal(grade(90), 'A+');
assert.equal(grade(89), 'A');
assert.equal(grade(33), 'C');
assert.equal(grade(32), 'Fail');
assert.equal(grade(0), 'Fail');
});
test('invalid marks throw', () => {
assert.throws(() => grade(-5), RangeError);
});Solution देखें
function secondHighest(totals) {
const sorted = [...new Set(totals)].sort((a, b) => b - a);
return sorted.length > 1 ? sorted[1] : null;
}
console.log(secondHighest([1800, 650, 2400, 2400, 900]));
console.log(secondHighest([500, 500]));Quick quiz
🧠 Quick Quiz – ख़ुद को जाँचें
Interview corner
💼 Interview Corner
क्या test करना है, कैसे तय करते हैं?
पहले business-critical logic और सीमाएँ (पैसा, validation, permissions), फिर मुख्य user flows end-to-end; लक्ष्य भरोसा, 100% coverage नहीं; हर ठीक bug का regression test; tests तेज़ और स्वतंत्र।
आपने ठीक किया कोई bug बताइए।
STAR लें: लक्षण और असर, कैसे दोहराया, कारण कैसे मिला (DevTools, logs), इलाज, जोड़ा गया test और ऐसे bugs रोकने के लिए क्या बदला।
सारांश
- Automated tests सेकंडों में bugs पकड़ते और regressions से बचाते हैं।
- Units के लिए node:test + assert; सीमाएँ test; test-first से bugs ठीक।
- Units/components के लिए Vitest/Jest, असली flows के लिए Playwright, चलाने को CI।
- मुख्य सवालों और क्लासिक coding tasks में महारत; projects STAR से समझाएँ।
Day 28 – Mini project: scoring, review और high scores वाला timed quiz app।
