Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
••••••••••••••••••••
Intelligence View
⚡ tsecurity.de Intelligence

Testing JavaScript: Practical Guide to Confident Code (2026)

Testing JavaScript: Practical Guide to Confident Code (2026) Testing isn't about catching bugs — it's about having the confidence to change code without fear. H…

Beitrag
0
Seite
0
↗ Quelle (dev.to)
Social ReaktionenReagiere als Erste:r — dein Feedback zählt!




Testing JavaScript: Practical Guide to Confident Code (2026)



Testing isn't about catching bugs — it's about having the confidence to change code without fear. Here's how to write tests that actually matter.






The Testing Pyramid






                    ╱╲
╱ E2E╲ ← Few, slow, expensive
╱──────╲
╱ Integration╲ ← Some, medium speed
╱──────────────╲
╱ Unit Tests ╲ ← Many, fast, cheap
╱──────────────────╲

Rule of thumb:
- 70% Unit tests (fast, isolated)
- 20% Integration tests (test component interaction)
- 10% E2E tests (critical user flows only)

Unit test: Does this function work? (ms per test)
Integration: Do these modules work together? (seconds per test)
E2E: Can a user complete a purchase? (minutes per test)









Unit Testing with Vitest/Jest






// Setup (vitest.config.js or jest.config.js):
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'node',
globals: true,
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
include: ['src/**/*.js'],
exclude: ['src/**/*.test.js', 'src/config/**'],
thresholds: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
},
});

// Basic unit test:
import { describe, it, expect, beforeEach } from 'vitest';
import { Calculator } from '../calculator.js';

describe('Calculator', () => {
let calc;

beforeEach(() => {
calc = new Calculator();
});

describe('add()', () => {
it('should add two positive numbers', () => {
expect(calc.add(2, 3)).toBe(5);
});

it('should handle negative numbers', () => {
expect(calc.add(-1, -1)).toBe(-2);
});

it('should handle decimal numbers', () => {
expect(calc.add(0.1, 0.2)).toBeCloseTo(0.3); // Floating point!
});

it('should throw on non-number input', () => {
expect(() => calc.add('a', 2)).toThrow('Numbers only');
});
});
});

// Async testing:
describe('API Service', () => {
it('should fetch user data', async () => {
const user = await userService.findById('abc123');
expect(user).toBeDefined();
expect(user.id).toBe('abc123');
});

it('should throw on not found', async () => {
await expect(userService.findById('nonexistent'))
.rejects.toThrow('User not found');
});

// Mocking external dependencies:
it('should call API with correct params', async () => {
const mockFetch = vi.fn().mockResolvedValue({
json: async () => ({ id: '123', name: 'Test' })
});

global.fetch = mockFetch;
const result = await apiClient.getUser('123');

expect(mockFetch).toHaveBeenCalledWith('/api/users/123');
expect(result.name).toBe('Test');
});
});









Test Doubles: Mocks, Stubs & Spies






// Understanding when to use each:

// STUB: Replace real implementation with a fixed response
// Use when: You need to control dependencies' behavior deterministically
const dbStub = {
findById: vi.fn()
.mockResolvedValueOnce({ id: '1', name: 'Alice' })
.mockResolvedValueOnce({ id: '2', name: 'Bob' })
.mockRejectedValueOnce(new Error('DB error')),
};

// MOCK: Verify behavior (was it called? with what args?)
// Use when: You need to assert HOW your code uses dependencies
const emailServiceMock = {
sendWelcomeEmail: vi.fn(),
};

await registerNewUser({ email: '[email protected]' });
expect(emailServiceMock.sendWelcomeEmail).toHaveBeenCalledTimes(1);
expect(emailServiceMock.sendWelcomeEmail).toHaveBeenCalledWith(
'[email protected]',
'Welcome!'
);

// SPY: Wrap real function to track calls without replacing behavior
// Use when: You want to keep original behavior but verify usage
const realLogger = console.log;
const logSpy = vi.spyOn(console, 'log');

processData();
expect(logSpy).toHaveBeenCalledWith('Processing started');

// Best practices for mocking:
// ✅ Mock at boundaries (database, file system, network, time)
// ✅ Keep mocks close to the code they mock (same folder or __mocks__/)
// ❌ Don't mock everything — if you mock everything, you're testing nothing
// ❌ Don't mock implementation details — test behavior, not internals

// Time mocking (essential for timers/deadlines):
vi.useFakeTimers();
const callback = vi.fn();
setTimeout(callback, 5000);

// Fast-forward 5 seconds instantly!
vi.advanceTimersByTime(5000);
expect(callback).toHaveBeenCalled();

// Or advance tick by tick:
vi.advanceTimersByTime(1000);
expect(callback).not.toHaveBeenCalled(); // Not yet!

vi.advanceTimersByTime(4000);
expect(callback).toHaveBeenCalled(); // Now!
vi.useRealTimers(); // Always restore!









Integration Testing






// Test that components work together correctly:

describe('Auth Flow Integration', () => {
// Use a test database (not production!)
beforeAll(async () => {
await testDb.migrate();
await testDb.seed(['users', 'sessions']);
});

afterAll(async () => {
await testDb.close();
});

it('should complete full login flow', async () => {
// Step 1: Register
const regRes = await request(app)
.post('/api/auth/register')
.send({ email: '[email protected]', password: 'Password123!' })
.expect(201);

expect(regRes.body.data.email).toBe('[email protected]');
expect(regRes.body.data.token).toBeDefined();

// Step 2: Login with same credentials
const loginRes = await request(app)
.post('/api/auth/login')
.send({ email: '[email protected]', password: 'Password123!' })
.expect(200);

// Step 3: Access protected endpoint with token
const profileRes = await request(app)
.get('/api/profile')
.set('Authorization', `Bearer ${loginRes.body.token}`)
.expect(200);

expect(profileRes.body.data.email).toBe('[email protected]');
});

it('should reject expired token', async () => {
const expiredToken = jwt.sign({ sub: 'user1' }, secret, { expiresIn: '-1h' });

await request(app)
.get('/api/profile')
.set('Authorization', `Bearer ${expiredToken}`)
.expect(401);
});
});

// Database integration with test containers:
// Using testcontainers-js for real DB in tests:
import { PostgreSqlContainer } from '@testcontainers/postgresql';

let container;
let pool;

beforeAll(async () => {
container = await new PostgreSqlContainer().start();
pool = new Pool({ connectionString: container.getConnectionUri() });
await pool.query(`CREATE TABLE users (id UUID PRIMARY KEY, name TEXT)`);
});

afterAll(async () => {
await pool.end();
await container.stop();
});









What to Test (and What NOT to Test)






// ✅ TEST THIS:
// - Business logic and calculations
// - Authentication and authorization rules
// - Input validation and sanitization
// - Error handling paths (what happens when things go wrong?)
// - Critical user flows (login, checkout, data export)
// - Edge cases: empty arrays, null values, boundary numbers, unicode strings
// - Performance-sensitive operations (are they within acceptable time?)

// ❌ DON'T TEST THIS:
// - Third-party libraries (they have their own tests)
// - Framework internals (Express routing works, don't test it)
// - Implementation details (private methods, internal state)
// - Trivial getters/setters (one-liners)
// - Things you can't control (external APIs without mocking)

// The "useful test" litmus test:
// If this test fails, will it tell me exactly what's wrong?
// If I refactor the code (without changing behavior), will this test still pass?
// If the answer to both is YES → good test!
// If either is NO → reconsider the test.

// Test naming convention that tells a story:
it('should deny access when token has expired'); // Clear!
it('auth-001'); // Unclear — what does this test?
it('returns 401 for expired tokens'); // Better but vague
it('POST /api/protected → 401 when JWT exp < now'); // BEST — specific + actionable









What's your testing philosophy? TDD first, or test after? How much coverage do you aim for?



Follow @armorbreak for more practical developer guides.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Testing JavaScript: Practical Guide to Confident Code (2026)

Thematisch verwandte Begriffe: Testing, JavaScript, Practical, Guide · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag