blob: e35b2546714594c12bbe61ccaf36c99f1aba9e5b [file] [edit]
'use strict';
require('../common');
const assert = require('node:assert');
const { spawnSync } = require('node:child_process');
const { join } = require('node:path');
const { describe, it } = require('node:test');
const fixtures = require('../common/fixtures');
const testFixtures = fixtures.path('test-runner');
const internalOrderFixture = fixtures.path('test-runner', 'randomize', 'internal-order.cjs');
const rerunStateFile = fixtures.path('test-runner', 'rerun-state.json');
const kShardFiles = ['a.cjs', 'b.cjs', 'c.cjs', 'd.cjs', 'e.cjs', 'f.cjs', 'g.cjs', 'h.cjs', 'i.cjs', 'j.cjs'];
const kInternalTests = ['a', 'b', 'c', 'd', 'e'];
function getShardOrder(stdout) {
return Array.from(stdout.matchAll(/ok \d+ - ([a-j]\.cjs) this should pass/g), ({ 1: name }) => name);
}
function getInternalExecutionOrder(stdout) {
const match = stdout.match(/EXECUTION_ORDER:([a-e](?:,[a-e])*)/);
assert(match, `Missing EXECUTION_ORDER marker in output: ${stdout}`);
return match[1].split(',');
}
describe('test runner randomize flags via command line', () => {
it('should be deterministic with --test-random-seed', () => {
const args = [
'--test',
'--test-reporter=tap',
'--test-concurrency=1',
'--test-randomize',
'--test-random-seed=12345',
join(testFixtures, 'shards/*.cjs'),
];
const first = spawnSync(process.execPath, args);
const second = spawnSync(process.execPath, args);
assert.strictEqual(first.stderr.toString(), '');
assert.strictEqual(second.stderr.toString(), '');
assert.strictEqual(first.status, 0);
assert.strictEqual(second.status, 0);
const firstOrder = getShardOrder(first.stdout.toString());
const secondOrder = getShardOrder(second.stdout.toString());
assert.deepStrictEqual(firstOrder, secondOrder);
assert.deepStrictEqual([...firstOrder].sort(), kShardFiles);
});
it('should use different orders for different seeds', () => {
const first = spawnSync(process.execPath, [
'--test',
'--test-reporter=tap',
'--test-concurrency=1',
'--test-randomize',
'--test-random-seed=11111',
join(testFixtures, 'shards/*.cjs'),
]);
const second = spawnSync(process.execPath, [
'--test',
'--test-reporter=tap',
'--test-concurrency=1',
'--test-randomize',
'--test-random-seed=22222',
join(testFixtures, 'shards/*.cjs'),
]);
assert.strictEqual(first.stderr.toString(), '');
assert.strictEqual(second.stderr.toString(), '');
assert.strictEqual(first.status, 0);
assert.strictEqual(second.status, 0);
const firstOrder = getShardOrder(first.stdout.toString());
const secondOrder = getShardOrder(second.stdout.toString());
assert.notDeepStrictEqual(firstOrder, secondOrder);
assert.deepStrictEqual([...firstOrder].sort(), kShardFiles);
assert.deepStrictEqual([...secondOrder].sort(), kShardFiles);
});
it('should randomize deterministically with --test-random-seed alone', () => {
const args = [
'--test',
'--test-reporter=tap',
'--test-concurrency=1',
'--test-random-seed=24680',
join(testFixtures, 'shards/*.cjs'),
];
const first = spawnSync(process.execPath, args);
const second = spawnSync(process.execPath, args);
assert.strictEqual(first.stderr.toString(), '');
assert.strictEqual(second.stderr.toString(), '');
assert.strictEqual(first.status, 0);
assert.strictEqual(second.status, 0);
const firstOrder = getShardOrder(first.stdout.toString());
const secondOrder = getShardOrder(second.stdout.toString());
assert.deepStrictEqual(firstOrder, secondOrder);
assert.deepStrictEqual([...firstOrder].sort(), kShardFiles);
assert.match(first.stdout.toString(), /# Randomized test order seed: 24680/);
});
it('should print the randomization seed when --test-randomize is used', () => {
const child = spawnSync(process.execPath, [
'--test',
'--test-reporter=tap',
'--test-concurrency=1',
'--test-randomize',
join(testFixtures, 'shards/*.cjs'),
]);
assert.strictEqual(child.stderr.toString(), '');
assert.strictEqual(child.status, 0);
assert.match(child.stdout.toString(), /# Randomized test order seed: \d+/);
});
it('should randomize internal test order deterministically with --test-random-seed', () => {
const args = [
'--test',
'--test-reporter=tap',
'--test-random-seed=12345',
internalOrderFixture,
];
const first = spawnSync(process.execPath, args);
const second = spawnSync(process.execPath, args);
assert.strictEqual(first.stderr.toString(), '');
assert.strictEqual(second.stderr.toString(), '');
assert.strictEqual(first.status, 0);
assert.strictEqual(second.status, 0);
const firstOrder = getInternalExecutionOrder(first.stdout.toString());
const secondOrder = getInternalExecutionOrder(second.stdout.toString());
assert.deepStrictEqual(firstOrder, secondOrder);
assert.deepStrictEqual([...firstOrder].sort(), kInternalTests);
});
it('should randomize internal test order differently across seeds', () => {
const orders = [];
for (const seed of [11111, 22222, 33333, 44444]) {
const child = spawnSync(process.execPath, [
'--test',
'--test-reporter=tap',
`--test-random-seed=${seed}`,
internalOrderFixture,
]);
assert.strictEqual(child.stderr.toString(), '');
assert.strictEqual(child.status, 0);
const order = getInternalExecutionOrder(child.stdout.toString());
assert.deepStrictEqual([...order].sort(), kInternalTests);
orders.push(order.join(','));
}
assert.notStrictEqual(new Set(orders).size, 1);
});
it('should reject --test-randomize with --watch', () => {
const child = spawnSync(process.execPath, [
'--test',
'--watch',
'--test-randomize',
join(testFixtures, 'shards/*.cjs'),
]);
assert.strictEqual(child.stdout.toString(), '');
assert.match(child.stderr.toString(), /The property 'options\.randomize' is not supported with watch mode\./);
assert.strictEqual(child.status, 1);
assert.strictEqual(child.signal, null);
});
it('should reject --test-random-seed with --watch', () => {
const child = spawnSync(process.execPath, [
'--test',
'--watch',
'--test-random-seed=12345',
join(testFixtures, 'shards/*.cjs'),
]);
assert.strictEqual(child.stdout.toString(), '');
assert.match(child.stderr.toString(), /The property 'options\.randomSeed' is not supported with watch mode\./);
assert.strictEqual(child.status, 1);
assert.strictEqual(child.signal, null);
});
it('should reject --test-randomize with --test-rerun-failures', () => {
const child = spawnSync(process.execPath, [
'--test',
'--test-randomize',
'--test-rerun-failures',
rerunStateFile,
join(testFixtures, 'shards/*.cjs'),
]);
assert.strictEqual(child.stdout.toString(), '');
assert.match(child.stderr.toString(), /The property 'options\.randomize' is not supported with rerun failures mode\./);
assert.strictEqual(child.status, 1);
assert.strictEqual(child.signal, null);
});
it('should reject --test-random-seed with --test-rerun-failures', () => {
const child = spawnSync(process.execPath, [
'--test',
'--test-random-seed=12345',
'--test-rerun-failures',
rerunStateFile,
join(testFixtures, 'shards/*.cjs'),
]);
assert.strictEqual(child.stdout.toString(), '');
assert.match(child.stderr.toString(), /The property 'options\.randomSeed' is not supported with rerun failures mode\./);
assert.strictEqual(child.status, 1);
assert.strictEqual(child.signal, null);
});
it('should reject out of range --test-random-seed values', () => {
const child = spawnSync(process.execPath, [
'--test',
'--test-random-seed=4294967296',
join(testFixtures, 'shards/*.cjs'),
]);
assert.strictEqual(child.stdout.toString(), '');
assert.match(child.stderr.toString(), /The value of "--test-random-seed" is out of range\. It must be >= 0 && <= 4294967295\. Received 4294967296/);
assert.strictEqual(child.status, 1);
assert.strictEqual(child.signal, null);
});
});