JavaScript in Plain English

New JavaScript and Web Development content every day. Follow to join our 3.5M+ monthly readers.

Follow publication

Mitigate JavaScript Flaky Unit Tests

Andrey Enin
JavaScript in Plain English
8 min readMar 24, 2025

--

Mitigate JavaScript Flaky Unit Tests

1. Rewrite your flaky tests

2. Maintain maximum test independence

Avoid sharing state across tests

import { test, expect } from 'vitest';

let counter = 0;

test('should increment counter', () => {
counter += 1;
expect(counter).toBe(1);
});

test('should decrement counter', () => {
counter -= 1;
expect(counter).toBe(0); // ❌ Fails if tests run in a different order due to shared variable
});
import { test, expect } from 'vitest';

test('should increment counter', () => {
let counter = 0;
counter += 1;
expect(counter).toBe(1);
});

test('should decrement counter', () => {
let counter = 0;
counter -= 1;
expect(counter).toBe(-1);
});

Keep test data isolated

import { test, expect } from 'vitest';
import _ from 'lodash';

const original = {
player: { name: 'Messi', bib: 10 },
};

test('should not mutate the original object', () => {
const originalCopy = _.cloneDeep(original);

originalCopy.player.bib = 30;

expect(original.player.bib).toBe(10);
});

Avoid order-dependent tests

3. Use hooks for preconditions and postconditions

import { expect, test } from 'vitest';

let dataBase: Record<string, string>[] = [];

test('should initialize data', () => {
dataBase.push({ player: 'Messi' });
expect(dataBase.length).toBe(1);
});

test('should get data', () => {
expect(dataBase[0].player).toBe('Messi'); // ❌ Fails if run in isolation or in random order
});
import { beforeAll, expect, test } from 'vitest';

let dataBase: Record<string, string>[] = [];

beforeAll(() => {
dataBase.push({ player: 'Messi' });
});

test('should get data', () => {
expect(dataBase[0].player).toBe('Messi');
});

4. Be careful with the precision of checks

import { test, expect } from 'vitest';
import { calculateDistanceFunction } from './calculate-distance-function';

test('should calculate distance', () => {
const result = calculateDistanceFunction([20.4489, 44.7866], [19.8335, 45.2671]);
expect(result).toBe(72.06735); // ❌ Too precise, may cause flakiness due to floating-point precision
});
import { test, expect } from 'vitest';
import { calculateDistanceFunction } from './calculate-distance-function';

test('should calculate distance', () => {
const result = calculateDistanceFunction([20.4489, 44.7866], [19.8335, 45.2671]);
expect(result).toBeCloseTo(72, 0);
});

5. Brace yourself for time checks

import { test, expect } from 'vitest';
import { delayedFunction } from './delayed-function';

test('should call callback after 100ms', async () => {
const start = Date.now();

await new Promise((resolve) => {
delayedFunction(() => {
const end = Date.now();

expect(end - start).toBe(100); // ❌ Too strict, while execution time may vary

resolve();
});
});
});
import { test, expect } from 'vitest';
import { delayedFunction } from './delayed-function';

test('should call callback after approximately 100ms', async () => {
const start = Date.now();

await new Promise((resolve) => {
delayedFunction(() => {
const end = Date.now();

expect(end - start).toBeGreaterThanOrEqual(100);
expect(end - start).toBeLessThan(150);

resolve();
});
});
});

6. Test your tests

Thank you for being a part of the community

--

--

Published in JavaScript in Plain English

New JavaScript and Web Development content every day. Follow to join our 3.5M+ monthly readers.

Written by Andrey Enin

Quality assurance engineer: I’m testing web applications, APIs and do automation testing.

No responses yet

Write a response