From e43ca993e94099c313f28af2652193b48a63e726 Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Wed, 8 Jun 2022 09:58:57 +1000 Subject: [PATCH 01/70] jest-circus runs children in shuffled order --- packages/jest-circus/package.json | 2 ++ packages/jest-circus/src/run.ts | 3 +++ yarn.lock | 25 +++++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/packages/jest-circus/package.json b/packages/jest-circus/package.json index 4dca4e39727a..d5da2aebfc19 100644 --- a/packages/jest-circus/package.json +++ b/packages/jest-circus/package.json @@ -22,6 +22,7 @@ "@jest/expect": "^28.1.1", "@jest/test-result": "^28.1.1", "@jest/types": "^28.1.1", + "@types/lodash.shuffle": "^4.2.7", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", @@ -33,6 +34,7 @@ "jest-runtime": "^28.1.1", "jest-snapshot": "^28.1.1", "jest-util": "^28.1.1", + "lodash.shuffle": "^4.2.0", "pretty-format": "^28.1.1", "slash": "^3.0.0", "stack-utils": "^2.0.3", diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index 8d8242b6c203..c9241845c7c4 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -17,6 +17,7 @@ import { invariant, makeRunResult, } from './utils'; +import shuffle = require('lodash.shuffle'); const run = async (): Promise => { const {rootDescribeBlock} = getState(); @@ -68,6 +69,8 @@ const _runTestsForDescribeBlock = async ( const retryTimes = parseInt(global[RETRY_TIMES], 10) || 0; const deferredRetryTests = []; + // jhwang I did this :) + describeBlock.children = shuffle(describeBlock.children); for (const child of describeBlock.children) { switch (child.type) { case 'describeBlock': { diff --git a/yarn.lock b/yarn.lock index 700249a07e8e..1e33195dd903 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5138,6 +5138,22 @@ __metadata: languageName: node linkType: hard +"@types/lodash.shuffle@npm:^4.2.7": + version: 4.2.7 + resolution: "@types/lodash.shuffle@npm:4.2.7" + dependencies: + "@types/lodash": "*" + checksum: b6417a358159982a93273a96ade01801923628bf4f288f686200501cae664d8d04deb492ec072b435a0837e6a2b671e1ae868aeaeb047242ff447fabec53d4a5 + languageName: node + linkType: hard + +"@types/lodash@npm:*": + version: 4.14.182 + resolution: "@types/lodash@npm:4.14.182" + checksum: 7dd137aa9dbabd632408bd37009d984655164fa1ecc3f2b6eb94afe35bf0a5852cbab6183148d883e9c73a958b7fec9a9bcf7c8e45d41195add6a18c34958209 + languageName: node + linkType: hard + "@types/mdast@npm:^3.0.0": version: 3.0.10 resolution: "@types/mdast@npm:3.0.10" @@ -13070,6 +13086,7 @@ __metadata: "@types/co": ^4.6.2 "@types/dedent": ^0.7.0 "@types/graceful-fs": ^4.1.3 + "@types/lodash.shuffle": ^4.2.7 "@types/node": "*" "@types/stack-utils": ^2.0.0 chalk: ^4.0.0 @@ -13084,6 +13101,7 @@ __metadata: jest-runtime: ^28.1.1 jest-snapshot: ^28.1.1 jest-util: ^28.1.1 + lodash.shuffle: ^4.2.0 pretty-format: ^28.1.1 slash: ^3.0.0 stack-utils: ^2.0.3 @@ -14581,6 +14599,13 @@ __metadata: languageName: node linkType: hard +"lodash.shuffle@npm:^4.2.0": + version: 4.2.0 + resolution: "lodash.shuffle@npm:4.2.0" + checksum: 3d451e16c18cd7e7c4c265199c87f0a1fff2976b8bf14d94de20a445e76f61a5c39b62181e5660e8f3a1602518b15a3d7d54732067cdef9d446e47d1e8f48938 + languageName: node + linkType: hard + "lodash.some@npm:^4.4.0": version: 4.6.0 resolution: "lodash.some@npm:4.6.0" From bbb1cf3d83dc72f23a598840a379bdda8e856354 Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Wed, 8 Jun 2022 20:56:41 +1000 Subject: [PATCH 02/70] added shuffle and pseudorandom number generator --- packages/jest-circus/package.json | 2 -- packages/jest-circus/src/run.ts | 5 ++-- packages/jest-core/src/runJest.ts | 1 + packages/jest-util/package.json | 3 +- packages/jest-util/src/index.ts | 1 + packages/jest-util/src/shuffleArray.ts | 38 ++++++++++++++++++++++++++ yarn.lock | 33 ++++++---------------- 7 files changed, 53 insertions(+), 30 deletions(-) create mode 100644 packages/jest-util/src/shuffleArray.ts diff --git a/packages/jest-circus/package.json b/packages/jest-circus/package.json index d5da2aebfc19..4dca4e39727a 100644 --- a/packages/jest-circus/package.json +++ b/packages/jest-circus/package.json @@ -22,7 +22,6 @@ "@jest/expect": "^28.1.1", "@jest/test-result": "^28.1.1", "@jest/types": "^28.1.1", - "@types/lodash.shuffle": "^4.2.7", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", @@ -34,7 +33,6 @@ "jest-runtime": "^28.1.1", "jest-snapshot": "^28.1.1", "jest-util": "^28.1.1", - "lodash.shuffle": "^4.2.0", "pretty-format": "^28.1.1", "slash": "^3.0.0", "stack-utils": "^2.0.3", diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index c9241845c7c4..76295eba468d 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -7,6 +7,7 @@ import throat from 'throat'; import type {Circus} from '@jest/types'; +import {rng, shuffleArray} from 'jest-util'; import {dispatch, getState} from './state'; import {RETRY_TIMES} from './types'; import { @@ -17,7 +18,6 @@ import { invariant, makeRunResult, } from './utils'; -import shuffle = require('lodash.shuffle'); const run = async (): Promise => { const {rootDescribeBlock} = getState(); @@ -70,7 +70,8 @@ const _runTestsForDescribeBlock = async ( const deferredRetryTests = []; // jhwang I did this :) - describeBlock.children = shuffle(describeBlock.children); + const r = rng(3); + describeBlock.children = shuffleArray(describeBlock.children, r.next); for (const child of describeBlock.children) { switch (child.type) { case 'describeBlock': { diff --git a/packages/jest-core/src/runJest.ts b/packages/jest-core/src/runJest.ts index 7061d3d282e7..85199ced0457 100644 --- a/packages/jest-core/src/runJest.ts +++ b/packages/jest-core/src/runJest.ts @@ -200,6 +200,7 @@ export default async function runJest({ allTests = await sequencer.shard(allTests, globalConfig.shard); } + // jhwang allTests actually means all test suites allTests = await sequencer.sort(allTests); if (globalConfig.listTests) { diff --git a/packages/jest-util/package.json b/packages/jest-util/package.json index d520c66ad9c3..522de4be2566 100644 --- a/packages/jest-util/package.json +++ b/packages/jest-util/package.json @@ -22,7 +22,8 @@ "chalk": "^4.0.0", "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" + "picomatch": "^2.2.3", + "seedrandom": "^3.0.5" }, "devDependencies": { "@types/graceful-fs": "^4.1.3", diff --git a/packages/jest-util/src/index.ts b/packages/jest-util/src/index.ts index da313207feb8..efd5364ffb16 100644 --- a/packages/jest-util/src/index.ts +++ b/packages/jest-util/src/index.ts @@ -28,3 +28,4 @@ export {default as pluralize} from './pluralize'; export {default as formatTime} from './formatTime'; export {default as tryRealpath} from './tryRealpath'; export {default as requireOrImportModule} from './requireOrImportModule'; +export {default as shuffleArray, rng} from './shuffleArray'; diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts new file mode 100644 index 000000000000..9753f3d68a1d --- /dev/null +++ b/packages/jest-util/src/shuffleArray.ts @@ -0,0 +1,38 @@ +// Mulberry 32 taken from +// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript +export function mulberry32(seed: number): {next: () => number} { + let state = seed; + + function next(): number { + state |= 0; + state = (state + 0x6d2b79f5) | 0; + let t = Math.imul(state ^ (state >>> 15), state | 1); + t ^= t + Math.imul(t ^ (t >>> 7), t | 61); + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + } + + return {next}; +} + +export const rng = mulberry32; + +// Fisher-Yates shuffle +// This is performed in-place +export default function shuffleArray( + array: Array, + random: () => number = Math.random, +): Array { + const length = array == null ? 0 : array.length; + if (!length) { + return []; + } + let index = -1; + const lastIndex = length - 1; + while (++index < length) { + const rand = index + Math.floor(random() * (lastIndex - index + 1)); + const value = array[index]; + array[index] = array[rand]; + array[rand] = value; + } + return array; +} diff --git a/yarn.lock b/yarn.lock index 1e33195dd903..80067a2a086f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5138,22 +5138,6 @@ __metadata: languageName: node linkType: hard -"@types/lodash.shuffle@npm:^4.2.7": - version: 4.2.7 - resolution: "@types/lodash.shuffle@npm:4.2.7" - dependencies: - "@types/lodash": "*" - checksum: b6417a358159982a93273a96ade01801923628bf4f288f686200501cae664d8d04deb492ec072b435a0837e6a2b671e1ae868aeaeb047242ff447fabec53d4a5 - languageName: node - linkType: hard - -"@types/lodash@npm:*": - version: 4.14.182 - resolution: "@types/lodash@npm:4.14.182" - checksum: 7dd137aa9dbabd632408bd37009d984655164fa1ecc3f2b6eb94afe35bf0a5852cbab6183148d883e9c73a958b7fec9a9bcf7c8e45d41195add6a18c34958209 - languageName: node - linkType: hard - "@types/mdast@npm:^3.0.0": version: 3.0.10 resolution: "@types/mdast@npm:3.0.10" @@ -13086,7 +13070,6 @@ __metadata: "@types/co": ^4.6.2 "@types/dedent": ^0.7.0 "@types/graceful-fs": ^4.1.3 - "@types/lodash.shuffle": ^4.2.7 "@types/node": "*" "@types/stack-utils": ^2.0.0 chalk: ^4.0.0 @@ -13101,7 +13084,6 @@ __metadata: jest-runtime: ^28.1.1 jest-snapshot: ^28.1.1 jest-util: ^28.1.1 - lodash.shuffle: ^4.2.0 pretty-format: ^28.1.1 slash: ^3.0.0 stack-utils: ^2.0.3 @@ -13679,6 +13661,7 @@ __metadata: ci-info: ^3.2.0 graceful-fs: ^4.2.9 picomatch: ^2.2.3 + seedrandom: ^3.0.5 languageName: unknown linkType: soft @@ -14599,13 +14582,6 @@ __metadata: languageName: node linkType: hard -"lodash.shuffle@npm:^4.2.0": - version: 4.2.0 - resolution: "lodash.shuffle@npm:4.2.0" - checksum: 3d451e16c18cd7e7c4c265199c87f0a1fff2976b8bf14d94de20a445e76f61a5c39b62181e5660e8f3a1602518b15a3d7d54732067cdef9d446e47d1e8f48938 - languageName: node - linkType: hard - "lodash.some@npm:^4.4.0": version: 4.6.0 resolution: "lodash.some@npm:4.6.0" @@ -19832,6 +19808,13 @@ __metadata: languageName: node linkType: hard +"seedrandom@npm:^3.0.5": + version: 3.0.5 + resolution: "seedrandom@npm:3.0.5" + checksum: 728b56bc3bc1b9ddeabd381e449b51cb31bdc0aa86e27fcd0190cea8c44613d5bcb2f6bb63ed79f78180cbe791c20b8ec31a9627f7b7fc7f476fd2bdb7e2da9f + languageName: node + linkType: hard + "select-hose@npm:^2.0.0": version: 2.0.0 resolution: "select-hose@npm:2.0.0" From 99ac4cd3c60af4817f89ce7375d27f81b5bb79a1 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 3 Sep 2022 13:05:40 +1000 Subject: [PATCH 03/70] added cli argv --- .../jestAdapterInit.ts | 3 +++ packages/jest-circus/src/run.ts | 18 ++++++++++++------ packages/jest-circus/src/state.ts | 1 + packages/jest-cli/src/cli/args.ts | 13 +++++++++++++ packages/jest-config/src/index.ts | 2 ++ packages/jest-config/src/normalize.ts | 5 +++++ .../logDebugMessages.test.ts.snap | 1 + packages/jest-types/src/Circus.ts | 1 + packages/jest-types/src/Config.ts | 4 ++++ packages/jest-util/src/index.ts | 2 +- packages/jest-util/src/shuffleArray.ts | 2 +- packages/test-utils/src/config.ts | 2 ++ 12 files changed, 46 insertions(+), 8 deletions(-) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 4556c55185ae..cae752a18f36 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -62,6 +62,9 @@ export const initialize = async ({ getRunnerState().testTimeout = globalConfig.testTimeout; } getRunnerState().maxConcurrency = globalConfig.maxConcurrency; + if (globalConfig.randomize && globalConfig.seed) { + getRunnerState().seed = globalConfig.seed; + } // @ts-expect-error: missing `concurrent` which is added later const globalsObject: Global.TestFrameworkGlobals = { diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index 30336c1b6460..6f6e27bd6632 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -7,7 +7,7 @@ import pLimit = require('p-limit'); import type {Circus} from '@jest/types'; -import {rng, shuffleArray} from 'jest-util'; +import {rngBuilder, shuffleArray} from 'jest-util'; import {dispatch, getState} from './state'; import {RETRY_TIMES} from './types'; import { @@ -20,9 +20,13 @@ import { } from './utils'; const run = async (): Promise => { - const {rootDescribeBlock} = getState(); + const {rootDescribeBlock, seed} = getState(); await dispatch({name: 'run_start'}); - await _runTestsForDescribeBlock(rootDescribeBlock, true); + let rng = undefined; + if (seed) { + rng = rngBuilder(seed).next; + } + await _runTestsForDescribeBlock(rootDescribeBlock, rng, true); await dispatch({name: 'run_finish'}); return makeRunResult( getState().rootDescribeBlock, @@ -32,6 +36,7 @@ const run = async (): Promise => { const _runTestsForDescribeBlock = async ( describeBlock: Circus.DescribeBlock, + rng: (() => number) | undefined, isRootBlock = false, ) => { await dispatch({describeBlock, name: 'run_describe_start'}); @@ -70,12 +75,13 @@ const _runTestsForDescribeBlock = async ( const deferredRetryTests = []; // jhwang I did this :) - const r = rng(3); - describeBlock.children = shuffleArray(describeBlock.children, r.next); + if (rng) { + describeBlock.children = shuffleArray(describeBlock.children, rng); + } for (const child of describeBlock.children) { switch (child.type) { case 'describeBlock': { - await _runTestsForDescribeBlock(child); + await _runTestsForDescribeBlock(child, rng); break; } case 'test': { diff --git a/packages/jest-circus/src/state.ts b/packages/jest-circus/src/state.ts index e9f0321e979f..62d413605ac6 100644 --- a/packages/jest-circus/src/state.ts +++ b/packages/jest-circus/src/state.ts @@ -33,6 +33,7 @@ const createState = (): Circus.State => { testNamePattern: null, testTimeout: 5000, unhandledErrors: [], + seed: undefined, }; }; diff --git a/packages/jest-cli/src/cli/args.ts b/packages/jest-cli/src/cli/args.ts index f58194047977..e2281bbcde3e 100644 --- a/packages/jest-cli/src/cli/args.ts +++ b/packages/jest-cli/src/cli/args.ts @@ -10,6 +10,10 @@ import type {Config} from '@jest/types'; import {constants, isJSONString} from 'jest-config'; export function check(argv: Config.Argv): true { + if (argv.seed && !argv.randomize) { + throw new Error('--seed requires --randomize to be specified.'); + } + if ( argv.runInBand && Object.prototype.hasOwnProperty.call(argv, 'maxWorkers') @@ -449,6 +453,10 @@ export const options: {[key: string]: Options} = { string: true, type: 'array', }, + randomize: { + description: 'Randomise the order of the tests in each describe block', + type: 'boolean', + }, reporters: { description: 'A list of custom reporters for the test suite.', string: true, @@ -510,6 +518,11 @@ export const options: {[key: string]: Options} = { "Allows to use a custom runner instead of Jest's default test runner.", type: 'string', }, + seed: { + description: + 'Must be used with the randomize flag. Specify the seed to randomize with.', + type: 'number', + }, selectProjects: { description: 'Run the tests of the specified projects. ' + diff --git a/packages/jest-config/src/index.ts b/packages/jest-config/src/index.ts index de947b1d5de2..64c430a25658 100644 --- a/packages/jest-config/src/index.ts +++ b/packages/jest-config/src/index.ts @@ -149,10 +149,12 @@ const groupOptions = ( outputFile: options.outputFile, passWithNoTests: options.passWithNoTests, projects: options.projects, + randomize: options.randomize, replname: options.replname, reporters: options.reporters, rootDir: options.rootDir, runTestsByPath: options.runTestsByPath, + seed: options.seed, shard: options.shard, silent: options.silent, skipFilter: options.skipFilter, diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index da4bb5977e16..2856e87a0f13 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -1152,6 +1152,11 @@ export default async function normalize( newOptions.shard = parseShardPair(argv.shard); } + if (argv.randomize) { + // at time of writing we use mulberry32 pseudorandom number generator so 32 bits + newOptions.seed = argv.seed ?? Math.floor(Math.random() * 4294967296); + } + return { hasDeprecationWarnings, options: newOptions, diff --git a/packages/jest-core/src/lib/__tests__/__snapshots__/logDebugMessages.test.ts.snap b/packages/jest-core/src/lib/__tests__/__snapshots__/logDebugMessages.test.ts.snap index b27bc6754017..54275543954c 100644 --- a/packages/jest-core/src/lib/__tests__/__snapshots__/logDebugMessages.test.ts.snap +++ b/packages/jest-core/src/lib/__tests__/__snapshots__/logDebugMessages.test.ts.snap @@ -92,6 +92,7 @@ exports[`prints the config object 1`] = ` "onlyFailures": false, "passWithNoTests": false, "projects": [], + "randomize": false, "reporters": [], "rootDir": "/test_root_dir/", "runTestsByPath": false, diff --git a/packages/jest-types/src/Circus.ts b/packages/jest-types/src/Circus.ts index 7ed5023d6caf..fb4e611bf0cf 100644 --- a/packages/jest-types/src/Circus.ts +++ b/packages/jest-types/src/Circus.ts @@ -215,6 +215,7 @@ export type State = { originalGlobalErrorHandlers?: GlobalErrorHandlers; parentProcess: Process | null; // process object from the outer scope rootDescribeBlock: DescribeBlock; + seed?: number; testNamePattern?: RegExp | null; testTimeout: number; unhandledErrors: Array; diff --git a/packages/jest-types/src/Config.ts b/packages/jest-types/src/Config.ts index cc23cbbdd21d..a1f0a1736f09 100644 --- a/packages/jest-types/src/Config.ts +++ b/packages/jest-types/src/Config.ts @@ -390,10 +390,12 @@ export type GlobalConfig = { onlyFailures: boolean; passWithNoTests: boolean; projects: Array; + randomize: boolean; replname?: string; reporters?: Array; runTestsByPath: boolean; rootDir: string; + seed?: number; shard?: ShardConfig; silent?: boolean; skipFilter: boolean; @@ -529,6 +531,7 @@ export type Argv = Arguments< preset: string | null | undefined; prettierPath: string | null | undefined; projects: Array; + randomize: boolean; reporters: Array; resetMocks: boolean; resetModules: boolean; @@ -537,6 +540,7 @@ export type Argv = Arguments< rootDir: string; roots: Array; runInBand: boolean; + seed: number; selectProjects: Array; setupFiles: Array; setupFilesAfterEnv: Array; diff --git a/packages/jest-util/src/index.ts b/packages/jest-util/src/index.ts index efd5364ffb16..0128c65e1185 100644 --- a/packages/jest-util/src/index.ts +++ b/packages/jest-util/src/index.ts @@ -28,4 +28,4 @@ export {default as pluralize} from './pluralize'; export {default as formatTime} from './formatTime'; export {default as tryRealpath} from './tryRealpath'; export {default as requireOrImportModule} from './requireOrImportModule'; -export {default as shuffleArray, rng} from './shuffleArray'; +export {default as shuffleArray, rngBuilder} from './shuffleArray'; diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts index 9753f3d68a1d..466e4747377a 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-util/src/shuffleArray.ts @@ -14,7 +14,7 @@ export function mulberry32(seed: number): {next: () => number} { return {next}; } -export const rng = mulberry32; +export const rngBuilder = mulberry32; // Fisher-Yates shuffle // This is performed in-place diff --git a/packages/test-utils/src/config.ts b/packages/test-utils/src/config.ts index 92e65d53e91b..d0d36e589cbd 100644 --- a/packages/test-utils/src/config.ts +++ b/packages/test-utils/src/config.ts @@ -43,10 +43,12 @@ const DEFAULT_GLOBAL_CONFIG: Config.GlobalConfig = { outputFile: undefined, passWithNoTests: false, projects: [], + randomize: false, replname: undefined, reporters: [], rootDir: '/test_root_dir/', runTestsByPath: false, + seed: undefined, silent: false, skipFilter: false, snapshotFormat: {}, From 882f92018de0e3f4fc3c314344ac17a427161124 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 3 Sep 2022 13:38:22 +1000 Subject: [PATCH 04/70] removed unnecessary dependencies --- packages/jest-util/package.json | 3 +-- yarn.lock | 23 ----------------------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/packages/jest-util/package.json b/packages/jest-util/package.json index 7a2ac1cee62a..fe1c36eb5ce1 100644 --- a/packages/jest-util/package.json +++ b/packages/jest-util/package.json @@ -22,8 +22,7 @@ "chalk": "^4.0.0", "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3", - "seedrandom": "^3.0.5" + "picomatch": "^2.2.3" }, "devDependencies": { "@types/graceful-fs": "^4.1.3", diff --git a/yarn.lock b/yarn.lock index 8c011cfe6439..e1f1f1375383 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12871,22 +12871,6 @@ __metadata: languageName: unknown linkType: soft -"jest-util@^28.1.1, jest-util@workspace:packages/jest-util": - version: 0.0.0-use.local - resolution: "jest-util@workspace:packages/jest-util" - dependencies: - "@jest/types": ^28.1.1 - "@types/graceful-fs": ^4.1.3 - "@types/node": "*" - "@types/picomatch": ^2.2.2 - chalk: ^4.0.0 - ci-info: ^3.2.0 - graceful-fs: ^4.2.9 - picomatch: ^2.2.3 - seedrandom: ^3.0.5 - languageName: unknown - linkType: soft - "jest-util@npm:^26.0.0": version: 26.6.2 resolution: "jest-util@npm:26.6.2" @@ -18612,13 +18596,6 @@ __metadata: languageName: node linkType: hard -"seedrandom@npm:^3.0.5": - version: 3.0.5 - resolution: "seedrandom@npm:3.0.5" - checksum: 728b56bc3bc1b9ddeabd381e449b51cb31bdc0aa86e27fcd0190cea8c44613d5bcb2f6bb63ed79f78180cbe791c20b8ec31a9627f7b7fc7f476fd2bdb7e2da9f - languageName: node - linkType: hard - "select-hose@npm:^2.0.0": version: 2.0.0 resolution: "select-hose@npm:2.0.0" From 4df23a98bf67874492e77b8ff6d57d031c8a66fc Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 3 Sep 2022 18:06:03 +1000 Subject: [PATCH 05/70] add console logs about the seed --- .../src/legacy-code-todo-rewrite/jestAdapterInit.ts | 2 +- packages/jest-config/src/index.ts | 1 - packages/jest-core/src/cli/index.ts | 5 +++++ packages/jest-core/src/watch.ts | 3 +++ packages/jest-types/src/Config.ts | 1 - 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index cae752a18f36..332f468fe45d 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -62,7 +62,7 @@ export const initialize = async ({ getRunnerState().testTimeout = globalConfig.testTimeout; } getRunnerState().maxConcurrency = globalConfig.maxConcurrency; - if (globalConfig.randomize && globalConfig.seed) { + if (globalConfig.seed) { getRunnerState().seed = globalConfig.seed; } diff --git a/packages/jest-config/src/index.ts b/packages/jest-config/src/index.ts index 64c430a25658..4a72a51dd282 100644 --- a/packages/jest-config/src/index.ts +++ b/packages/jest-config/src/index.ts @@ -149,7 +149,6 @@ const groupOptions = ( outputFile: options.outputFile, passWithNoTests: options.passWithNoTests, projects: options.projects, - randomize: options.randomize, replname: options.replname, reporters: options.reporters, rootDir: options.rootDir, diff --git a/packages/jest-core/src/cli/index.ts b/packages/jest-core/src/cli/index.ts index 6556a919ebb9..39b027a5662c 100644 --- a/packages/jest-core/src/cli/index.ts +++ b/packages/jest-core/src/cli/index.ts @@ -279,6 +279,11 @@ const runWithoutWatch = async ( if (!globalConfig.listTests) { preRunMessagePrint(outputStream); } + + if (globalConfig.seed) { + console.log("Seed is", globalConfig.seed); + } + return runJest({ changedFilesPromise, contexts, diff --git a/packages/jest-core/src/watch.ts b/packages/jest-core/src/watch.ts index d1b84c7635bc..156bcce996fb 100644 --- a/packages/jest-core/src/watch.ts +++ b/packages/jest-core/src/watch.ts @@ -287,6 +287,9 @@ export default async function watch( testWatcher = new TestWatcher({isWatchMode: true}); isInteractive && outputStream.write(specialChars.CLEAR); + if (globalConfig.seed) { + console.log("Seed is", globalConfig.seed); + } preRunMessagePrint(outputStream); isRunning = true; const configs = contexts.map(context => context.config); diff --git a/packages/jest-types/src/Config.ts b/packages/jest-types/src/Config.ts index a1f0a1736f09..5817e94a4b78 100644 --- a/packages/jest-types/src/Config.ts +++ b/packages/jest-types/src/Config.ts @@ -390,7 +390,6 @@ export type GlobalConfig = { onlyFailures: boolean; passWithNoTests: boolean; projects: Array; - randomize: boolean; replname?: string; reporters?: Array; runTestsByPath: boolean; From dc6e64fad550378018afa0e82b7097e8660e36b6 Mon Sep 17 00:00:00 2001 From: Joshua <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 3 Sep 2022 23:44:57 +1000 Subject: [PATCH 06/70] More readable Math.pow() Co-authored-by: Simen Bekkhus --- packages/jest-config/src/normalize.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index 2856e87a0f13..468339d42d7d 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -1154,7 +1154,7 @@ export default async function normalize( if (argv.randomize) { // at time of writing we use mulberry32 pseudorandom number generator so 32 bits - newOptions.seed = argv.seed ?? Math.floor(Math.random() * 4294967296); + newOptions.seed = argv.seed ?? Math.floor(Math.random() * Math.pow(2, 32)); } return { From 3d09cfb45b16a0b2289d90ca2bc04600d45395af Mon Sep 17 00:00:00 2001 From: Joshua <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 3 Sep 2022 23:45:19 +1000 Subject: [PATCH 07/70] Used recommended logging approach Co-authored-by: Simen Bekkhus --- packages/jest-core/src/cli/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-core/src/cli/index.ts b/packages/jest-core/src/cli/index.ts index 39b027a5662c..9bce8e999564 100644 --- a/packages/jest-core/src/cli/index.ts +++ b/packages/jest-core/src/cli/index.ts @@ -281,7 +281,7 @@ const runWithoutWatch = async ( } if (globalConfig.seed) { - console.log("Seed is", globalConfig.seed); + outputStream.write(`Seed is ${globalConfig.seed}\n`); } return runJest({ From f8860e2ef1e786edf9c63b3fdaa2ace71ce9aeac Mon Sep 17 00:00:00 2001 From: Joshua <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 3 Sep 2022 23:45:32 +1000 Subject: [PATCH 08/70] Used recommended logging approach Co-authored-by: Simen Bekkhus --- packages/jest-core/src/watch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-core/src/watch.ts b/packages/jest-core/src/watch.ts index 156bcce996fb..2ea405cc0ca9 100644 --- a/packages/jest-core/src/watch.ts +++ b/packages/jest-core/src/watch.ts @@ -288,7 +288,7 @@ export default async function watch( testWatcher = new TestWatcher({isWatchMode: true}); isInteractive && outputStream.write(specialChars.CLEAR); if (globalConfig.seed) { - console.log("Seed is", globalConfig.seed); + outputStream.write(`Seed is ${globalConfig.seed}\n`); } preRunMessagePrint(outputStream); isRunning = true; From 0bec19fe602f6367f9ed0ff2e7b3dc255101ee8c Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sun, 4 Sep 2022 00:43:05 +1000 Subject: [PATCH 09/70] added prando rng --- packages/jest-circus/src/run.ts | 4 ++-- packages/jest-core/src/runJest.ts | 1 - packages/jest-util/package.json | 3 ++- packages/jest-util/src/shuffleArray.ts | 18 ++---------------- packages/test-utils/src/config.ts | 1 - yarn.lock | 8 ++++++++ 6 files changed, 14 insertions(+), 21 deletions(-) diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index 6f6e27bd6632..236a57cfcd41 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -22,9 +22,9 @@ import { const run = async (): Promise => { const {rootDescribeBlock, seed} = getState(); await dispatch({name: 'run_start'}); - let rng = undefined; + let rng: undefined | (() => number) = undefined; if (seed) { - rng = rngBuilder(seed).next; + rng = () => rngBuilder(seed).next(); } await _runTestsForDescribeBlock(rootDescribeBlock, rng, true); await dispatch({name: 'run_finish'}); diff --git a/packages/jest-core/src/runJest.ts b/packages/jest-core/src/runJest.ts index 85199ced0457..7061d3d282e7 100644 --- a/packages/jest-core/src/runJest.ts +++ b/packages/jest-core/src/runJest.ts @@ -200,7 +200,6 @@ export default async function runJest({ allTests = await sequencer.shard(allTests, globalConfig.shard); } - // jhwang allTests actually means all test suites allTests = await sequencer.sort(allTests); if (globalConfig.listTests) { diff --git a/packages/jest-util/package.json b/packages/jest-util/package.json index fe1c36eb5ce1..97d955b8bf71 100644 --- a/packages/jest-util/package.json +++ b/packages/jest-util/package.json @@ -22,7 +22,8 @@ "chalk": "^4.0.0", "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" + "picomatch": "^2.2.3", + "prando": "^6.0.1" }, "devDependencies": { "@types/graceful-fs": "^4.1.3", diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts index 466e4747377a..ff6267cbd6c0 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-util/src/shuffleArray.ts @@ -1,20 +1,6 @@ -// Mulberry 32 taken from -// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript -export function mulberry32(seed: number): {next: () => number} { - let state = seed; +import Prando from 'prando'; - function next(): number { - state |= 0; - state = (state + 0x6d2b79f5) | 0; - let t = Math.imul(state ^ (state >>> 15), state | 1); - t ^= t + Math.imul(t ^ (t >>> 7), t | 61); - return ((t ^ (t >>> 14)) >>> 0) / 4294967296; - } - - return {next}; -} - -export const rngBuilder = mulberry32; +export const rngBuilder = (seed: number) => new Prando(seed); // Fisher-Yates shuffle // This is performed in-place diff --git a/packages/test-utils/src/config.ts b/packages/test-utils/src/config.ts index d0d36e589cbd..65e787e469aa 100644 --- a/packages/test-utils/src/config.ts +++ b/packages/test-utils/src/config.ts @@ -43,7 +43,6 @@ const DEFAULT_GLOBAL_CONFIG: Config.GlobalConfig = { outputFile: undefined, passWithNoTests: false, projects: [], - randomize: false, replname: undefined, reporters: [], rootDir: '/test_root_dir/', diff --git a/yarn.lock b/yarn.lock index e1f1f1375383..d7f34b9257c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12925,6 +12925,7 @@ __metadata: ci-info: ^3.2.0 graceful-fs: ^4.2.9 picomatch: ^2.2.3 + prando: ^6.0.1 languageName: unknown linkType: soft @@ -16807,6 +16808,13 @@ __metadata: languageName: node linkType: hard +"prando@npm:^6.0.1": + version: 6.0.1 + resolution: "prando@npm:6.0.1" + checksum: c0c25dbb2cb92dff4b0f44781f0e2132886c34ab6a12f7f0839d6073c783d86589d4c632727819d8fb0a5a675a7e27223285c6907261d3b6a49167b4cbdc162a + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" From 3a1d7126a4939e3adac91407d22e99c81b5848a8 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sun, 4 Sep 2022 00:58:26 +1000 Subject: [PATCH 10/70] bug where rng was recreated every run --- packages/jest-circus/src/run.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index 236a57cfcd41..1e5feffefb1a 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -22,11 +22,12 @@ import { const run = async (): Promise => { const {rootDescribeBlock, seed} = getState(); await dispatch({name: 'run_start'}); - let rng: undefined | (() => number) = undefined; + let nextRng: undefined | (() => number) = undefined; if (seed) { - rng = () => rngBuilder(seed).next(); + const rng = rngBuilder(seed); + nextRng = () => rng.next(); } - await _runTestsForDescribeBlock(rootDescribeBlock, rng, true); + await _runTestsForDescribeBlock(rootDescribeBlock, nextRng, true); await dispatch({name: 'run_finish'}); return makeRunResult( getState().rootDescribeBlock, @@ -74,7 +75,6 @@ const _runTestsForDescribeBlock = async ( const retryTimes = parseInt(global[RETRY_TIMES], 10) || 0; const deferredRetryTests = []; - // jhwang I did this :) if (rng) { describeBlock.children = shuffleArray(describeBlock.children, rng); } From 95590dc07de0053978dae470af2404baf19894ce Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sun, 4 Sep 2022 01:33:39 +1000 Subject: [PATCH 11/70] swapped order of logs --- packages/jest-core/src/cli/index.ts | 8 ++++---- .../__tests__/__snapshots__/logDebugMessages.test.ts.snap | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/jest-core/src/cli/index.ts b/packages/jest-core/src/cli/index.ts index 9bce8e999564..4c7ff8718640 100644 --- a/packages/jest-core/src/cli/index.ts +++ b/packages/jest-core/src/cli/index.ts @@ -276,14 +276,14 @@ const runWithoutWatch = async ( filter?: Filter, ) => { const startRun = async (): Promise => { - if (!globalConfig.listTests) { - preRunMessagePrint(outputStream); - } - if (globalConfig.seed) { outputStream.write(`Seed is ${globalConfig.seed}\n`); } + if (!globalConfig.listTests) { + preRunMessagePrint(outputStream); + } + return runJest({ changedFilesPromise, contexts, diff --git a/packages/jest-core/src/lib/__tests__/__snapshots__/logDebugMessages.test.ts.snap b/packages/jest-core/src/lib/__tests__/__snapshots__/logDebugMessages.test.ts.snap index 54275543954c..b27bc6754017 100644 --- a/packages/jest-core/src/lib/__tests__/__snapshots__/logDebugMessages.test.ts.snap +++ b/packages/jest-core/src/lib/__tests__/__snapshots__/logDebugMessages.test.ts.snap @@ -92,7 +92,6 @@ exports[`prints the config object 1`] = ` "onlyFailures": false, "passWithNoTests": false, "projects": [], - "randomize": false, "reporters": [], "rootDir": "/test_root_dir/", "runTestsByPath": false, From 14349bd35d7efad482d50b38b08606c406f92a5f Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Mon, 5 Sep 2022 13:28:20 +1000 Subject: [PATCH 12/70] added typing for the rng --- packages/jest-util/src/shuffleArray.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts index ff6267cbd6c0..48b231265d98 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-util/src/shuffleArray.ts @@ -1,6 +1,6 @@ import Prando from 'prando'; -export const rngBuilder = (seed: number) => new Prando(seed); +export const rngBuilder: (seed: number) => { next: () => number } = (seed: number) => new Prando(seed); // Fisher-Yates shuffle // This is performed in-place From 4ae8ff29dec13c82ab40e16976701dd315e45068 Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Thu, 29 Sep 2022 11:05:32 +1000 Subject: [PATCH 13/70] linting issues fixed --- packages/jest-circus/src/state.ts | 2 +- packages/jest-util/src/shuffleArray.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/jest-circus/src/state.ts b/packages/jest-circus/src/state.ts index 62d413605ac6..4e1f3335868a 100644 --- a/packages/jest-circus/src/state.ts +++ b/packages/jest-circus/src/state.ts @@ -30,10 +30,10 @@ const createState = (): Circus.State => { maxConcurrency: 5, parentProcess: null, rootDescribeBlock: ROOT_DESCRIBE_BLOCK, + seed: undefined, testNamePattern: null, testTimeout: 5000, unhandledErrors: [], - seed: undefined, }; }; diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts index 48b231265d98..aa2da91d02c5 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-util/src/shuffleArray.ts @@ -1,6 +1,8 @@ import Prando from 'prando'; -export const rngBuilder: (seed: number) => { next: () => number } = (seed: number) => new Prando(seed); +export const rngBuilder: (seed: number) => {next: () => number} = ( + seed: number, +) => new Prando(seed); // Fisher-Yates shuffle // This is performed in-place From 967b32e424a9df494cda63f262c49e447b9c5d21 Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Fri, 30 Sep 2022 07:56:48 +1000 Subject: [PATCH 14/70] unit tests are green --- .../src/__tests__/shuffleArray.test.ts | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 packages/jest-util/src/__tests__/shuffleArray.test.ts diff --git a/packages/jest-util/src/__tests__/shuffleArray.test.ts b/packages/jest-util/src/__tests__/shuffleArray.test.ts new file mode 100644 index 000000000000..d81cba1990f9 --- /dev/null +++ b/packages/jest-util/src/__tests__/shuffleArray.test.ts @@ -0,0 +1,46 @@ +import shuffleArray, {rngBuilder} from '../shuffleArray'; + +describe(rngBuilder, () => { + // Breaking these orders would be a breaking change + // Some people will be using seeds relying on a particular order + test.each([ + [1, ['0.50', '0.52', '0.92', '0.32']], // 0 is not a valid seed + [2, ['0.50', '0.53', '0.66', '0.89']], + [4, ['0.50', '0.56', '0.82', '0.28']], + [8, ['0.50', '0.63', '0.15', '0.06']], + [16, ['0.50', '0.75', '0.29', '0.39']], + ])('creates a randomiser given seed %s', (seed, expectations) => { + const newRng = rngBuilder(seed); + for (const expectedNext of expectations) { + expect(newRng.next().toFixed(2)).toEqual(expectedNext); + } + }); +}); + +describe(shuffleArray, () => { + it('empty array is shuffled', () => { + const shuffled = shuffleArray([]); + expect(shuffled).toEqual([]); + }); + + // Breaking these orders would be a breaking change + // Some people will be using seeds relying on a particular order + const seed = 123; + test.each([ + [ + ['a', 'b'], + ['b', 'a'], + ], + [ + ['a', 'b', 'c'], + ['b', 'a', 'c'], + ], + [ + ['a', 'b', 'c', 'd'], + ['c', 'a', 'd', 'b'], + ], + ])('shuffles list %p', (l, expectation) => { + const rng = rngBuilder(seed); + expect(shuffleArray(l, () => rng.next())).toEqual(expectation); + }); +}); From 561146cd588edfeedd8541af3f7dd790eb7e9d7c Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Fri, 30 Sep 2022 11:34:38 +1000 Subject: [PATCH 15/70] used snapshots instead --- .../__snapshots__/shuffleArray.test.ts.snap | 106 ++++++++++++++++++ .../src/__tests__/shuffleArray.test.ts | 41 +++---- 2 files changed, 119 insertions(+), 28 deletions(-) create mode 100644 packages/jest-util/src/__tests__/__snapshots__/shuffleArray.test.ts.snap diff --git a/packages/jest-util/src/__tests__/__snapshots__/shuffleArray.test.ts.snap b/packages/jest-util/src/__tests__/__snapshots__/shuffleArray.test.ts.snap new file mode 100644 index 000000000000..4288d1d48e02 --- /dev/null +++ b/packages/jest-util/src/__tests__/__snapshots__/shuffleArray.test.ts.snap @@ -0,0 +1,106 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`rngBuilder creates a randomiser given seed 1 1`] = ` +Array [ + 0.500062950304724, + 0.5157397988987481, + 0.9226656041393675, + 0.3155057489209589, + 0.1551597700815554, + 0.9486529105223372, + 0.3748853226133821, + 0.3723766031610725, + 0.48958173894546503, + 0.6052440010489067, +] +`; + +exports[`rngBuilder creates a randomiser given seed 2 1`] = ` +Array [ + 0.5001259004930327, + 0.5312583452396231, + 0.6624884909630028, + 0.8890491144007652, + 0.38940668720505356, + 0.6909172021995571, + 0.6007535305341597, + 0.06686430426008634, + 0.881952763041936, + 0.5476082643837688, +] +`; + +exports[`rngBuilder creates a randomiser given seed 4 1`] = ` +Array [ + 0.5002518008696502, + 0.5625166903628308, + 0.8249769818095902, + 0.27809822845228443, + 0.2790498855242156, + 0.0634860098509784, + 0.4434312750686499, + 0.05855132221676207, + 0.5894388301739094, + 0.24544880754441228, +] +`; + +exports[`rngBuilder creates a randomiser given seed 8 1`] = ` +Array [ + 0.500503601622885, + 0.6250333806092463, + 0.14995397095334576, + 0.058307676123992465, + 0.47901072620391166, + 0.9113757456446475, + 0.5750688020081886, + 0.8338097936552507, + 0.8361590078184752, + 0.8376564038539437, +] +`; + +exports[`rngBuilder creates a randomiser given seed 16 1`] = ` +Array [ + 0.5010072108127659, + 0.7520182327721311, + 0.2882353561670136, + 0.3866406226033905, + 0.8962605120372634, + 0.19173304927342874, + 0.08497578978654365, + 0.3369975006992457, + 0.9351766044123043, + 0.10703910470638403, +] +`; + +exports[`shuffleArray shuffles list ["a", "b", "c", "d"] 1`] = ` +Array [ + "c", + "a", + "d", + "b", +] +`; + +exports[`shuffleArray shuffles list ["a", "b", "c"] 1`] = ` +Array [ + "b", + "a", + "c", +] +`; + +exports[`shuffleArray shuffles list ["a", "b"] 1`] = ` +Array [ + "b", + "a", +] +`; + +exports[`shuffleArray shuffles list ["a"] 1`] = ` +Array [ + "a", +] +`; diff --git a/packages/jest-util/src/__tests__/shuffleArray.test.ts b/packages/jest-util/src/__tests__/shuffleArray.test.ts index d81cba1990f9..b0ae1f5d4361 100644 --- a/packages/jest-util/src/__tests__/shuffleArray.test.ts +++ b/packages/jest-util/src/__tests__/shuffleArray.test.ts @@ -3,17 +3,12 @@ import shuffleArray, {rngBuilder} from '../shuffleArray'; describe(rngBuilder, () => { // Breaking these orders would be a breaking change // Some people will be using seeds relying on a particular order - test.each([ - [1, ['0.50', '0.52', '0.92', '0.32']], // 0 is not a valid seed - [2, ['0.50', '0.53', '0.66', '0.89']], - [4, ['0.50', '0.56', '0.82', '0.28']], - [8, ['0.50', '0.63', '0.15', '0.06']], - [16, ['0.50', '0.75', '0.29', '0.39']], - ])('creates a randomiser given seed %s', (seed, expectations) => { - const newRng = rngBuilder(seed); - for (const expectedNext of expectations) { - expect(newRng.next().toFixed(2)).toEqual(expectedNext); - } + test.each([1, 2, 4, 8, 16])('creates a randomiser given seed %s', seed => { + const rng = rngBuilder(seed); + const results = Array(10) + .fill(0) + .map(() => rng.next()); + expect(results).toMatchSnapshot(); }); }); @@ -26,21 +21,11 @@ describe(shuffleArray, () => { // Breaking these orders would be a breaking change // Some people will be using seeds relying on a particular order const seed = 123; - test.each([ - [ - ['a', 'b'], - ['b', 'a'], - ], - [ - ['a', 'b', 'c'], - ['b', 'a', 'c'], - ], - [ - ['a', 'b', 'c', 'd'], - ['c', 'a', 'd', 'b'], - ], - ])('shuffles list %p', (l, expectation) => { - const rng = rngBuilder(seed); - expect(shuffleArray(l, () => rng.next())).toEqual(expectation); - }); + test.each([[['a']], [['a', 'b']], [['a', 'b', 'c']], [['a', 'b', 'c', 'd']]])( + 'shuffles list %p', + l => { + const rng = rngBuilder(seed); + expect(shuffleArray(l, () => rng.next())).toMatchSnapshot(); + }, + ); }); From 2f95b65bcdf6a5edc8c2392abeaf0be1dea1b18b Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Fri, 30 Sep 2022 12:10:16 +1000 Subject: [PATCH 16/70] added e2e tests --- .../__snapshots__/randomize.test.ts.snap | 344 ++++++++++++++++++ e2e/__tests__/randomize.test.ts | 44 +++ .../__snapshots__/snapshots.test.js.snap | 31 ++ e2e/randomize/__tests__/each.test.js | 21 ++ e2e/randomize/__tests__/hooks.test.js | 91 +++++ e2e/randomize/__tests__/snapshots.test.js | 21 ++ e2e/randomize/__tests__/success.test.js | 67 ++++ e2e/randomize/package.json | 5 + 8 files changed, 624 insertions(+) create mode 100644 e2e/__tests__/__snapshots__/randomize.test.ts.snap create mode 100644 e2e/__tests__/randomize.test.ts create mode 100644 e2e/randomize/__tests__/__snapshots__/snapshots.test.js.snap create mode 100644 e2e/randomize/__tests__/each.test.js create mode 100644 e2e/randomize/__tests__/hooks.test.js create mode 100644 e2e/randomize/__tests__/snapshots.test.js create mode 100644 e2e/randomize/__tests__/success.test.js create mode 100644 e2e/randomize/package.json diff --git a/e2e/__tests__/__snapshots__/randomize.test.ts.snap b/e2e/__tests__/__snapshots__/randomize.test.ts.snap new file mode 100644 index 000000000000..9773194e2042 --- /dev/null +++ b/e2e/__tests__/__snapshots__/randomize.test.ts.snap @@ -0,0 +1,344 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`works with each 1`] = ` +"PASS __tests__/each.test.js + ✓ test1 + ✓ test2 + ✓ test3 + describe1 + ✓ test4 + ✓ test6 + ✓ test5 + describe3 + ✓ test11 + ✓ test12 + ✓ test10 + describe4 + ✓ test14 + ✓ test13 + ✓ test15 + describe2 + ✓ test4 + ✓ test5 + ✓ test6" +`; + +exports[`works with hooks 1`] = ` +"Seed is 123 + console.log + This is before all + + at Object.log (__tests__/hooks.test.js:2:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + test4 + + at Object.log (__tests__/hooks.test.js:31:13) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + test6 + + at Object.log (__tests__/hooks.test.js:39:13) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + test5 + + at Object.log (__tests__/hooks.test.js:35:13) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + test1 + + at Object.log (__tests__/hooks.test.js:18:11) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + This is before each describe3 + + at Object.log (__tests__/hooks.test.js:63:13) + + console.log + test11 + + at Object.log (__tests__/hooks.test.js:71:13) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + This is before each describe3 + + at Object.log (__tests__/hooks.test.js:63:13) + + console.log + test12 + + at Object.log (__tests__/hooks.test.js:75:13) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + This is before each describe3 + + at Object.log (__tests__/hooks.test.js:63:13) + + console.log + test14 + + at Object.log (__tests__/hooks.test.js:84:15) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + This is before each describe3 + + at Object.log (__tests__/hooks.test.js:63:13) + + console.log + test13 + + at Object.log (__tests__/hooks.test.js:80:15) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + This is before each describe3 + + at Object.log (__tests__/hooks.test.js:63:13) + + console.log + test15 + + at Object.log (__tests__/hooks.test.js:88:15) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + This is before each describe3 + + at Object.log (__tests__/hooks.test.js:63:13) + + console.log + test10 + + at Object.log (__tests__/hooks.test.js:67:13) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + test7 + + at Object.log (__tests__/hooks.test.js:49:13) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + test8 + + at Object.log (__tests__/hooks.test.js:53:13) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + test9 + + at Object.log (__tests__/hooks.test.js:57:13) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is after all describe2 + + at Object.log (__tests__/hooks.test.js:45:13) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + test2 + + at Object.log (__tests__/hooks.test.js:22:11) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is before each + + at Object.log (__tests__/hooks.test.js:6:11) + + console.log + test3 + + at Object.log (__tests__/hooks.test.js:26:11) + + console.log + This is after each + + at Object.log (__tests__/hooks.test.js:10:11) + + console.log + This is after all + + at Object.log (__tests__/hooks.test.js:14:11) +" +`; + +exports[`works with passing tests 1`] = ` +"PASS __tests__/success.test.js + ✓ test1 + ✓ test2 + ✓ test3 + describe1 + ✓ test4 + ✓ test6 + ✓ test5 + describe3 + ✓ test11 + ✓ test12 + ✓ test10 + describe4 + ✓ test14 + ✓ test13 + ✓ test15 + describe2 + ✓ test7 + ✓ test8 + ✓ test9" +`; + +exports[`works with snapshots 1`] = ` +"PASS __tests__/snapshots.test.js + ✓ test1 + ✓ test2 + ✓ test3 + describe1 + ✓ test4 + ✓ test6 + ✓ test5 + describe3 + ✓ test11 + ✓ test12 + ✓ test10 + describe4 + ✓ test14 + ✓ test13 + ✓ test15 + describe2 + ✓ test4 + ✓ test5 + ✓ test6" +`; diff --git a/e2e/__tests__/randomize.test.ts b/e2e/__tests__/randomize.test.ts new file mode 100644 index 000000000000..40385825da62 --- /dev/null +++ b/e2e/__tests__/randomize.test.ts @@ -0,0 +1,44 @@ +import * as path from 'path'; +import {extractSummary} from '../Utils'; +import runJest from '../runJest'; + +const dir = path.resolve(__dirname, '../randomize'); + +test('works with passing tests', () => { + const result = runJest(dir, [ + 'success.test.js', + '--randomize', + '--seed', + '123', + ]); + const {rest} = extractSummary(result.stderr); + expect(rest).toMatchSnapshot(); +}); + +test('works with each', () => { + const result = runJest(dir, ['each.test.js', '--randomize', '--seed', '123']); + const {rest} = extractSummary(result.stderr); + expect(rest).toMatchSnapshot(); +}); + +test('works with hooks', () => { + const result = runJest(dir, [ + 'hooks.test.js', + '--randomize', + '--seed', + '123', + ]); + // Change in formatting could change this one + expect(result.stdout).toMatchSnapshot(); +}); + +test('works with snapshots', () => { + const result = runJest(dir, [ + 'snapshots.test.js', + '--randomize', + '--seed', + '123', + ]); + const {rest} = extractSummary(result.stderr); + expect(rest).toMatchSnapshot(); +}); diff --git a/e2e/randomize/__tests__/__snapshots__/snapshots.test.js.snap b/e2e/randomize/__tests__/__snapshots__/snapshots.test.js.snap new file mode 100644 index 000000000000..8fb29cd59a98 --- /dev/null +++ b/e2e/randomize/__tests__/__snapshots__/snapshots.test.js.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`describe1 test4 1`] = `4`; + +exports[`describe1 test5 1`] = `5`; + +exports[`describe1 test6 1`] = `6`; + +exports[`describe2 test4 1`] = `4`; + +exports[`describe2 test5 1`] = `5`; + +exports[`describe2 test6 1`] = `6`; + +exports[`describe3 describe4 test13 1`] = `13`; + +exports[`describe3 describe4 test14 1`] = `14`; + +exports[`describe3 describe4 test15 1`] = `15`; + +exports[`describe3 test10 1`] = `10`; + +exports[`describe3 test11 1`] = `11`; + +exports[`describe3 test12 1`] = `12`; + +exports[`test1 1`] = `1`; + +exports[`test2 1`] = `2`; + +exports[`test3 1`] = `3`; diff --git a/e2e/randomize/__tests__/each.test.js b/e2e/randomize/__tests__/each.test.js new file mode 100644 index 000000000000..4d2ff2006eb3 --- /dev/null +++ b/e2e/randomize/__tests__/each.test.js @@ -0,0 +1,21 @@ +it.each([1, 2, 3])('test%d', () => { + expect(true).toBe(true); +}); + +describe.each([1, 2])('describe%d', () => { + it.each([4, 5, 6])('test%d', () => { + expect(true).toBe(true); + }); +}); + +describe('describe3', () => { + it.each([10, 11, 12])('test%d', () => { + expect(true).toBe(true); + }); + + describe('describe4', () => { + it.each([13, 14, 15])('test%d', () => { + expect(true).toBe(true); + }); + }); +}); diff --git a/e2e/randomize/__tests__/hooks.test.js b/e2e/randomize/__tests__/hooks.test.js new file mode 100644 index 000000000000..c5c98b3f4ffa --- /dev/null +++ b/e2e/randomize/__tests__/hooks.test.js @@ -0,0 +1,91 @@ +beforeAll(() => { + console.log('This is before all'); +}); + +beforeEach(() => { + console.log('This is before each'); +}); + +afterEach(() => { + console.log('This is after each'); +}); + +afterAll(() => { + console.log('This is after all'); +}); + +it('test1', () => { + console.log('test1'); +}); + +it('test2', () => { + console.log('test2'); +}); + +it('test3', () => { + console.log('test3'); +}); + +describe('describe1', () => { + it('test4', () => { + console.log('test4'); + }); + + it('test5', () => { + console.log('test5'); + }); + + it('test6', () => { + console.log('test6'); + }); +}); + +describe('describe2', () => { + afterAll(() => { + console.log('This is after all describe2'); + }); + + it('test7', () => { + console.log('test7'); + }); + + it('test8', () => { + console.log('test8'); + }); + + it('test9', () => { + console.log('test9'); + }); +}); + +describe('describe3', () => { + beforeEach(() => { + console.log('This is before each describe3'); + }); + + it('test10', () => { + console.log('test10'); + }); + + it('test11', () => { + console.log('test11'); + }); + + it('test12', () => { + console.log('test12'); + }); + + describe('describe4', () => { + it('test13', () => { + console.log('test13'); + }); + + it('test14', () => { + console.log('test14'); + }); + + it('test15', () => { + console.log('test15'); + }); + }); +}); diff --git a/e2e/randomize/__tests__/snapshots.test.js b/e2e/randomize/__tests__/snapshots.test.js new file mode 100644 index 000000000000..6431d7d36160 --- /dev/null +++ b/e2e/randomize/__tests__/snapshots.test.js @@ -0,0 +1,21 @@ +it.each([1, 2, 3])('test%d', n => { + expect(n).toMatchSnapshot(); +}); + +describe.each([1, 2])('describe%d', () => { + it.each([4, 5, 6])('test%d', n => { + expect(n).toMatchSnapshot(); + }); +}); + +describe('describe3', () => { + it.each([10, 11, 12])('test%d', n => { + expect(n).toMatchSnapshot(); + }); + + describe('describe4', () => { + it.each([13, 14, 15])('test%d', n => { + expect(n).toMatchSnapshot(); + }); + }); +}); diff --git a/e2e/randomize/__tests__/success.test.js b/e2e/randomize/__tests__/success.test.js new file mode 100644 index 000000000000..817b17c21046 --- /dev/null +++ b/e2e/randomize/__tests__/success.test.js @@ -0,0 +1,67 @@ +it('test1', () => { + expect(true).toBe(true); +}); + +it('test2', () => { + expect(true).toBe(true); +}); + +it('test3', () => { + expect(true).toBe(true); +}); + +describe('describe1', () => { + it('test4', () => { + expect(true).toBe(true); + }); + + it('test5', () => { + expect(true).toBe(true); + }); + + it('test6', () => { + expect(true).toBe(true); + }); +}); + +describe('describe2', () => { + it('test7', () => { + expect(true).toBe(true); + }); + + it('test8', () => { + expect(true).toBe(true); + }); + + it('test9', () => { + expect(true).toBe(true); + }); +}); + +describe('describe3', () => { + it('test10', () => { + expect(true).toBe(true); + }); + + it('test11', () => { + expect(true).toBe(true); + }); + + it('test12', () => { + expect(true).toBe(true); + }); + + describe('describe4', () => { + it('test13', () => { + expect(true).toBe(true); + }); + + it('test14', () => { + expect(true).toBe(true); + }); + + it('test15', () => { + expect(true).toBe(true); + }); + }); +}); diff --git a/e2e/randomize/package.json b/e2e/randomize/package.json new file mode 100644 index 000000000000..148788b25446 --- /dev/null +++ b/e2e/randomize/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "testEnvironment": "node" + } +} From 50bada019fe73119c9fff21d0404fbaa5d3fabd5 Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Fri, 30 Sep 2022 12:19:13 +1000 Subject: [PATCH 17/70] changed valid seeds --- packages/jest-config/src/normalize.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index 06d47e0bbb48..43b785ca7195 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -1140,8 +1140,10 @@ export default async function normalize( } if (argv.randomize) { - // at time of writing we use mulberry32 pseudorandom number generator so 32 bits - newOptions.seed = argv.seed ?? Math.floor(Math.random() * Math.pow(2, 32)); + // at time of writing we use Prando which starts repeating after 2^29 - 1 + // 0 is not a valid input seed + newOptions.seed = + argv.seed ?? Math.floor((1 - Math.random()) * (Math.pow(2, 29) - 1)); } return { From b78fdc27fcac63e61523de57155dd4bb2fe48b69 Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Fri, 30 Sep 2022 12:23:29 +1000 Subject: [PATCH 18/70] added changelog message --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a99c2fb23f35..cf5d9f3c7d1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features - `[@jest/environment, jest-runtime]` Allow passing a generic type argument to `jest.createMockFromModule()` method ([#13202](https://github.com/facebook/jest/pull/13202)) +- `[jest-circus, jest-cli, jest-config, @jest/core, @jest/types, @jest-util]` Add cli feature to randomize order or tests ([#12922](https://github.com/facebook/jest/pull/12922)) ### Fixes From 3f33508679de0afe3df8f93684f618c631a0f677 Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Fri, 30 Sep 2022 12:41:11 +1000 Subject: [PATCH 19/70] improved cli help and added documentation --- docs/CLI.md | 21 +++++++++++++++++++++ packages/jest-cli/src/cli/args.ts | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/CLI.md b/docs/CLI.md index bca78b1ca5b3..a9bb8c99c63b 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -28,6 +28,18 @@ Run tests related to changed files based on hg/git (uncommitted files): jest -o ``` +Run tests in a file in a random order (this will print the seed used for random number generation): + +```bash +jest --randomize +``` + +Run tests in a file in an order determined by a seed: + +```bash +jest --randomize --seed 1234 +``` + Run tests related to `path/to/fileA.js` and `path/to/fileB.js`: ```bash @@ -311,6 +323,11 @@ Allows the test suite to pass when no files are found. Run tests from one or more projects, found in the specified paths; also takes path globs. This option is the CLI equivalent of the [`projects`](configuration#projects-arraystring--projectconfig) configuration option. Note that if configuration files are found in the specified paths, _all_ projects specified within those configuration files will be run. +### `--randomize` + +Shuffle the order of the tests within a file. The seed used to generate the new order will be printed to stdout. +In order to determine the seed refer to the `--seed` CLI option. + ### `--reporters` Run tests with specified reporters. [Reporter options](configuration#reporters-arraymodulename--modulename-options) are not available via CLI. Example with multiple reporters: @@ -343,6 +360,10 @@ The default regex matching works fine on small runs, but becomes slow if provide ::: +### `--seed` + +Run the tests in the order specified by the seed value. Must be used with the `--randomize` flag. + ### `--selectProjects ... ` Run the tests of the specified projects. Jest uses the attribute `displayName` in the configuration to identify each project. If you use this option, you should provide a `displayName` to all your projects. diff --git a/packages/jest-cli/src/cli/args.ts b/packages/jest-cli/src/cli/args.ts index e2281bbcde3e..8b081869fb64 100644 --- a/packages/jest-cli/src/cli/args.ts +++ b/packages/jest-cli/src/cli/args.ts @@ -454,7 +454,7 @@ export const options: {[key: string]: Options} = { type: 'array', }, randomize: { - description: 'Randomise the order of the tests in each describe block', + description: 'Randomize the order of the tests within a file', type: 'boolean', }, reporters: { From b5c34fe280fdd2f12cdcdb19800da65936337a70 Mon Sep 17 00:00:00 2001 From: Josh <81541956+jhwang98@users.noreply.github.com> Date: Fri, 30 Sep 2022 14:19:43 +1000 Subject: [PATCH 20/70] Update docs/CLI.md Co-authored-by: Tom Mrazauskas --- docs/CLI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CLI.md b/docs/CLI.md index b323a9d7b723..1469252a4c0f 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -333,7 +333,7 @@ If configuration files are found in the specified paths, _all_ projects specifie ### `--randomize` Shuffle the order of the tests within a file. The seed used to generate the new order will be printed to stdout. -In order to determine the seed refer to the `--seed` CLI option. +In order to determine the seed refer to the [`--seed`](#seed) CLI option. ### `--reporters` From b9c51398c3f2576b6806e8865483474f8d10f2cc Mon Sep 17 00:00:00 2001 From: Josh <81541956+jhwang98@users.noreply.github.com> Date: Fri, 30 Sep 2022 14:19:50 +1000 Subject: [PATCH 21/70] Update docs/CLI.md Co-authored-by: Tom Mrazauskas --- docs/CLI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CLI.md b/docs/CLI.md index 1469252a4c0f..71c9d905c14c 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -369,7 +369,7 @@ The default regex matching works fine on small runs, but becomes slow if provide ### `--seed` -Run the tests in the order specified by the seed value. Must be used with the `--randomize` flag. +Run the tests in the order specified by the seed value. Must be used with the [`--randomize`](#randomize) flag. ### `--selectProjects ... ` From 1b412b4aef08e81ea31e77c63b1ff5716678227e Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Fri, 30 Sep 2022 14:27:45 +1000 Subject: [PATCH 22/70] skipped jasmine --- e2e/__tests__/randomize.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/e2e/__tests__/randomize.test.ts b/e2e/__tests__/randomize.test.ts index 40385825da62..5ed2dfafc1c2 100644 --- a/e2e/__tests__/randomize.test.ts +++ b/e2e/__tests__/randomize.test.ts @@ -1,7 +1,10 @@ import * as path from 'path'; +import {skipSuiteOnJasmine} from '@jest/test-utils'; import {extractSummary} from '../Utils'; import runJest from '../runJest'; +skipSuiteOnJasmine(); + const dir = path.resolve(__dirname, '../randomize'); test('works with passing tests', () => { From c45244caf1cc3c083981f25807bf046e83d35ae0 Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Fri, 30 Sep 2022 14:39:06 +1000 Subject: [PATCH 23/70] updated cli help and docs for randomize --- docs/CLI.md | 22 ++++++++++++++++++++-- packages/jest-cli/src/cli/args.ts | 5 +++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index a9bb8c99c63b..613f93ca4a90 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -34,12 +34,18 @@ Run tests in a file in a random order (this will print the seed used for random jest --randomize ``` -Run tests in a file in an order determined by a seed: +Run tests in a file in an order with a given seed: ```bash jest --randomize --seed 1234 ``` +:::note + +The `randomize` option is only supported using the default `jest-circus` test runner. + +::: + Run tests related to `path/to/fileA.js` and `path/to/fileB.js`: ```bash @@ -326,7 +332,13 @@ Run tests from one or more projects, found in the specified paths; also takes pa ### `--randomize` Shuffle the order of the tests within a file. The seed used to generate the new order will be printed to stdout. -In order to determine the seed refer to the `--seed` CLI option. +In order to choose the seed refer to the `--seed` CLI option. + +:::note + +This option is only supported using the default `jest-circus` test runner. + +::: ### `--reporters` @@ -364,6 +376,12 @@ The default regex matching works fine on small runs, but becomes slow if provide Run the tests in the order specified by the seed value. Must be used with the `--randomize` flag. +:::note + +This option is only supported using the default `jest-circus` test runner. + +::: + ### `--selectProjects ... ` Run the tests of the specified projects. Jest uses the attribute `displayName` in the configuration to identify each project. If you use this option, you should provide a `displayName` to all your projects. diff --git a/packages/jest-cli/src/cli/args.ts b/packages/jest-cli/src/cli/args.ts index 8b081869fb64..c4c094f1fa06 100644 --- a/packages/jest-cli/src/cli/args.ts +++ b/packages/jest-cli/src/cli/args.ts @@ -454,7 +454,8 @@ export const options: {[key: string]: Options} = { type: 'array', }, randomize: { - description: 'Randomize the order of the tests within a file', + description: + 'Shuffle the order of the tests within a file. The seed used to generate the new order will be printed to stdout. In order to choose the seed refer to the `--seed` CLI option.', type: 'boolean', }, reporters: { @@ -520,7 +521,7 @@ export const options: {[key: string]: Options} = { }, seed: { description: - 'Must be used with the randomize flag. Specify the seed to randomize with.', + 'Must be used with the `--randomize` flag. Specify the seed to randomize with.', type: 'number', }, selectProjects: { From 21520313b1ff14b3dd973fb40e74d72c492c2a5f Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Fri, 30 Sep 2022 15:31:32 +1000 Subject: [PATCH 24/70] updated documentation order --- docs/CLI.md | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index 00c52f0adf89..b158e63dc458 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -28,24 +28,6 @@ Run tests related to changed files based on hg/git (uncommitted files): jest -o ``` -Run tests in a file in a random order (this will print the seed used for random number generation): - -```bash -jest --randomize -``` - -Run tests in a file in an order with a given seed: - -```bash -jest --randomize --seed 1234 -``` - -:::note - -The `randomize` option is only supported using the default `jest-circus` test runner. - -::: - Run tests related to `path/to/fileA.js` and `path/to/fileB.js`: ```bash @@ -339,7 +321,11 @@ If configuration files are found in the specified paths, _all_ projects specifie ### `--randomize` Shuffle the order of the tests within a file. The seed used to generate the new order will be printed to stdout. -In order to determine the seed refer to the [`--seed`](#seed) CLI option. +In order to determine the seed refer to the [`--seed`](#--seed) CLI option. + +```bash +jest --randomize +``` :::note @@ -381,7 +367,11 @@ The default regex matching works fine on small runs, but becomes slow if provide ### `--seed` -Run the tests in the order specified by the seed value. Must be used with the [`--randomize`](#randomize) flag. +Run the tests in the order specified by the seed value. Must be used with the [`--randomize`](#--randomize) flag. + +```bash +jest --randomize --seed 1234 +``` :::note From 6bb94490d3bd0f6f23925d2a75f42ed4e26e4f57 Mon Sep 17 00:00:00 2001 From: Josh <81541956+jhwang98@users.noreply.github.com> Date: Fri, 30 Sep 2022 15:41:55 +1000 Subject: [PATCH 25/70] Update docs/CLI.md Co-authored-by: Tom Mrazauskas --- docs/CLI.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index b158e63dc458..32972830501f 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -321,11 +321,14 @@ If configuration files are found in the specified paths, _all_ projects specifie ### `--randomize` Shuffle the order of the tests within a file. The seed used to generate the new order will be printed to stdout. -In order to determine the seed refer to the [`--seed`](#--seed) CLI option. -```bash -jest --randomize -``` +:::tip +Additionally you can use the [`--seed`](#--seed) flag to pass the seed value: + + ```bash + jest --randomize --seed 1234 + ``` +::: :::note From 164d6fa067cac2d970197a9c1f2c44bc94d6f0a4 Mon Sep 17 00:00:00 2001 From: Josh <81541956+jhwang98@users.noreply.github.com> Date: Fri, 30 Sep 2022 15:47:15 +1000 Subject: [PATCH 26/70] Update docs/CLI.md Co-authored-by: Tom Mrazauskas --- docs/CLI.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CLI.md b/docs/CLI.md index 32972830501f..ce33dfbba800 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -323,6 +323,7 @@ If configuration files are found in the specified paths, _all_ projects specifie Shuffle the order of the tests within a file. The seed used to generate the new order will be printed to stdout. :::tip + Additionally you can use the [`--seed`](#--seed) flag to pass the seed value: ```bash From 79401d11c8cffca4d0b74942c06f264810dd5ee8 Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Fri, 30 Sep 2022 15:49:52 +1000 Subject: [PATCH 27/70] removed whitespace --- docs/CLI.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index ce33dfbba800..b3ea3a812d7f 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -326,9 +326,10 @@ Shuffle the order of the tests within a file. The seed used to generate the new Additionally you can use the [`--seed`](#--seed) flag to pass the seed value: - ```bash - jest --randomize --seed 1234 - ``` +```bash +jest --randomize --seed 1234 +``` + ::: :::note From b6c4da48bd0d09f0db9bea0de942bf2d890f901f Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Tue, 4 Oct 2022 15:44:30 +1100 Subject: [PATCH 28/70] added copyright headers --- e2e/__tests__/randomize.test.ts | 7 +++++++ e2e/randomize/__tests__/each.test.js | 7 +++++++ e2e/randomize/__tests__/hooks.test.js | 7 +++++++ e2e/randomize/__tests__/snapshots.test.js | 7 +++++++ e2e/randomize/__tests__/success.test.js | 7 +++++++ packages/jest-util/src/__tests__/shuffleArray.test.ts | 7 +++++++ packages/jest-util/src/shuffleArray.ts | 7 +++++++ 7 files changed, 49 insertions(+) diff --git a/e2e/__tests__/randomize.test.ts b/e2e/__tests__/randomize.test.ts index 5ed2dfafc1c2..3d4d1812562a 100644 --- a/e2e/__tests__/randomize.test.ts +++ b/e2e/__tests__/randomize.test.ts @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + import * as path from 'path'; import {skipSuiteOnJasmine} from '@jest/test-utils'; import {extractSummary} from '../Utils'; diff --git a/e2e/randomize/__tests__/each.test.js b/e2e/randomize/__tests__/each.test.js index 4d2ff2006eb3..4c4408a8e0e0 100644 --- a/e2e/randomize/__tests__/each.test.js +++ b/e2e/randomize/__tests__/each.test.js @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + it.each([1, 2, 3])('test%d', () => { expect(true).toBe(true); }); diff --git a/e2e/randomize/__tests__/hooks.test.js b/e2e/randomize/__tests__/hooks.test.js index c5c98b3f4ffa..653926478448 100644 --- a/e2e/randomize/__tests__/hooks.test.js +++ b/e2e/randomize/__tests__/hooks.test.js @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + beforeAll(() => { console.log('This is before all'); }); diff --git a/e2e/randomize/__tests__/snapshots.test.js b/e2e/randomize/__tests__/snapshots.test.js index 6431d7d36160..78f0baa18e39 100644 --- a/e2e/randomize/__tests__/snapshots.test.js +++ b/e2e/randomize/__tests__/snapshots.test.js @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + it.each([1, 2, 3])('test%d', n => { expect(n).toMatchSnapshot(); }); diff --git a/e2e/randomize/__tests__/success.test.js b/e2e/randomize/__tests__/success.test.js index 817b17c21046..b8c7ad786337 100644 --- a/e2e/randomize/__tests__/success.test.js +++ b/e2e/randomize/__tests__/success.test.js @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + it('test1', () => { expect(true).toBe(true); }); diff --git a/packages/jest-util/src/__tests__/shuffleArray.test.ts b/packages/jest-util/src/__tests__/shuffleArray.test.ts index b0ae1f5d4361..41e86e18ca19 100644 --- a/packages/jest-util/src/__tests__/shuffleArray.test.ts +++ b/packages/jest-util/src/__tests__/shuffleArray.test.ts @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + import shuffleArray, {rngBuilder} from '../shuffleArray'; describe(rngBuilder, () => { diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts index aa2da91d02c5..4a2d83b03d84 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-util/src/shuffleArray.ts @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + import Prando from 'prando'; export const rngBuilder: (seed: number) => {next: () => number} = ( From 19cf2b52f7a6fae4c82a1c3691b464136be613ed Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Tue, 4 Oct 2022 16:16:28 +1100 Subject: [PATCH 29/70] modifed snapshots to not rely on the actual lines --- .../__snapshots__/randomize.test.ts.snap | 324 +++--------------- e2e/randomize/__tests__/hooks.test.js | 42 +-- 2 files changed, 75 insertions(+), 291 deletions(-) diff --git a/e2e/__tests__/__snapshots__/randomize.test.ts.snap b/e2e/__tests__/__snapshots__/randomize.test.ts.snap index 9773194e2042..dfbb6e85152a 100644 --- a/e2e/__tests__/__snapshots__/randomize.test.ts.snap +++ b/e2e/__tests__/__snapshots__/randomize.test.ts.snap @@ -25,276 +25,60 @@ exports[`works with each 1`] = ` exports[`works with hooks 1`] = ` "Seed is 123 - console.log - This is before all - - at Object.log (__tests__/hooks.test.js:2:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - test4 - - at Object.log (__tests__/hooks.test.js:31:13) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - test6 - - at Object.log (__tests__/hooks.test.js:39:13) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - test5 - - at Object.log (__tests__/hooks.test.js:35:13) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - test1 - - at Object.log (__tests__/hooks.test.js:18:11) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - This is before each describe3 - - at Object.log (__tests__/hooks.test.js:63:13) - - console.log - test11 - - at Object.log (__tests__/hooks.test.js:71:13) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - This is before each describe3 - - at Object.log (__tests__/hooks.test.js:63:13) - - console.log - test12 - - at Object.log (__tests__/hooks.test.js:75:13) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - This is before each describe3 - - at Object.log (__tests__/hooks.test.js:63:13) - - console.log - test14 - - at Object.log (__tests__/hooks.test.js:84:15) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - This is before each describe3 - - at Object.log (__tests__/hooks.test.js:63:13) - - console.log - test13 - - at Object.log (__tests__/hooks.test.js:80:15) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - This is before each describe3 - - at Object.log (__tests__/hooks.test.js:63:13) - - console.log - test15 - - at Object.log (__tests__/hooks.test.js:88:15) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - This is before each describe3 - - at Object.log (__tests__/hooks.test.js:63:13) - - console.log - test10 - - at Object.log (__tests__/hooks.test.js:67:13) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - test7 - - at Object.log (__tests__/hooks.test.js:49:13) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - test8 - - at Object.log (__tests__/hooks.test.js:53:13) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - test9 - - at Object.log (__tests__/hooks.test.js:57:13) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is after all describe2 - - at Object.log (__tests__/hooks.test.js:45:13) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - test2 - - at Object.log (__tests__/hooks.test.js:22:11) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is before each - - at Object.log (__tests__/hooks.test.js:6:11) - - console.log - test3 - - at Object.log (__tests__/hooks.test.js:26:11) - - console.log - This is after each - - at Object.log (__tests__/hooks.test.js:10:11) - - console.log - This is after all - - at Object.log (__tests__/hooks.test.js:14:11) -" +This is before all +This is before each +test4 +This is after each +This is before each +test6 +This is after each +This is before each +test5 +This is after each +This is before each +test1 +This is after each +This is before each +This is before each describe3 +test11 +This is after each +This is before each +This is before each describe3 +test12 +This is after each +This is before each +This is before each describe3 +test14 +This is after each +This is before each +This is before each describe3 +test13 +This is after each +This is before each +This is before each describe3 +test15 +This is after each +This is before each +This is before each describe3 +test10 +This is after each +This is before each +test7 +This is after each +This is before each +test8 +This is after each +This is before each +test9 +This is after each +This is after all describe2 +This is before each +test2 +This is after each +This is before each +test3 +This is after each +This is after all" `; exports[`works with passing tests 1`] = ` diff --git a/e2e/randomize/__tests__/hooks.test.js b/e2e/randomize/__tests__/hooks.test.js index 653926478448..ecd8279c7920 100644 --- a/e2e/randomize/__tests__/hooks.test.js +++ b/e2e/randomize/__tests__/hooks.test.js @@ -6,93 +6,93 @@ */ beforeAll(() => { - console.log('This is before all'); + process.stdout.write('This is before all\n'); }); beforeEach(() => { - console.log('This is before each'); + process.stdout.write('This is before each\n'); }); afterEach(() => { - console.log('This is after each'); + process.stdout.write('This is after each\n'); }); afterAll(() => { - console.log('This is after all'); + process.stdout.write('This is after all\n'); }); it('test1', () => { - console.log('test1'); + process.stdout.write('test1\n'); }); it('test2', () => { - console.log('test2'); + process.stdout.write('test2\n'); }); it('test3', () => { - console.log('test3'); + process.stdout.write('test3\n'); }); describe('describe1', () => { it('test4', () => { - console.log('test4'); + process.stdout.write('test4\n'); }); it('test5', () => { - console.log('test5'); + process.stdout.write('test5\n'); }); it('test6', () => { - console.log('test6'); + process.stdout.write('test6\n'); }); }); describe('describe2', () => { afterAll(() => { - console.log('This is after all describe2'); + process.stdout.write('This is after all describe2\n'); }); it('test7', () => { - console.log('test7'); + process.stdout.write('test7\n'); }); it('test8', () => { - console.log('test8'); + process.stdout.write('test8\n'); }); it('test9', () => { - console.log('test9'); + process.stdout.write('test9\n'); }); }); describe('describe3', () => { beforeEach(() => { - console.log('This is before each describe3'); + process.stdout.write('This is before each describe3\n'); }); it('test10', () => { - console.log('test10'); + process.stdout.write('test10\n'); }); it('test11', () => { - console.log('test11'); + process.stdout.write('test11\n'); }); it('test12', () => { - console.log('test12'); + process.stdout.write('test12\n'); }); describe('describe4', () => { it('test13', () => { - console.log('test13'); + process.stdout.write('test13\n'); }); it('test14', () => { - console.log('test14'); + process.stdout.write('test14\n'); }); it('test15', () => { - console.log('test15'); + process.stdout.write('test15\n'); }); }); }); From 2007d475f225831453bebd49d9a734116d10be6b Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 4 Oct 2022 11:49:05 +0200 Subject: [PATCH 30/70] move changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d1c262157b4..de0059c2648e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- `[jest-circus, jest-cli, jest-config, @jest/core, @jest/types, @jest-util]` Add cli feature to randomize order or tests ([#12922](https://github.com/facebook/jest/pull/12922)) - `[jest-config]` Add `readInitialConfig` utility function ([#13356](https://github.com/facebook/jest/pull/13356)) - `[jest-core]` Enable testResultsProcessor to be async ([#13343](https://github.com/facebook/jest/pull/13343)) - `[expect, @jest/expect-utils]` Allow `isA` utility to take a type argument ([#13355](https://github.com/facebook/jest/pull/13355)) @@ -54,7 +55,6 @@ ### Features - `[@jest/environment, jest-runtime]` Allow passing a generic type argument to `jest.createMockFromModule()` method ([#13202](https://github.com/facebook/jest/pull/13202)) -- `[jest-circus, jest-cli, jest-config, @jest/core, @jest/types, @jest-util]` Add cli feature to randomize order or tests ([#12922](https://github.com/facebook/jest/pull/12922)) - `[expect]` Expose `ExpectationResult` type ([#13240](https://github.com/facebook/jest/pull/13240)) - `[jest-snapshot]` Expose `Context` type ([#13240](https://github.com/facebook/jest/pull/13240)) - `[@jest/globals]` Add `jest.Mock` type helper ([#13235](https://github.com/facebook/jest/pull/13235)) From a087ce63a4dbac4abdf0be25e6a47b884b0aa160 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Fri, 14 Oct 2022 22:29:00 +1000 Subject: [PATCH 31/70] added documentation for configuration --- docs/Configuration.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/Configuration.md b/docs/Configuration.md index 19cd805224d7..e43966119cd2 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -1216,6 +1216,12 @@ With the `projects` option enabled, Jest will copy the root-level configuration ::: +### `randomize` \[boolean] + +Default: `false` + +The equivalent of the [`--randomize`](CLI.md#--randomize) flag to randomize the order of the tests in a file. + ### `reporters` \[array<moduleName | \[moduleName, options]>] Default: `undefined` From b17565214a19d550473967e5ad2da67e554b20d1 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Fri, 14 Oct 2022 22:44:13 +1000 Subject: [PATCH 32/70] using pure-rand --- packages/jest-util/package.json | 2 +- packages/jest-util/src/shuffleArray.ts | 8 ++++++-- yarn.lock | 16 ++++++++-------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/jest-util/package.json b/packages/jest-util/package.json index e744019f17ab..effe3f953ce3 100644 --- a/packages/jest-util/package.json +++ b/packages/jest-util/package.json @@ -23,7 +23,7 @@ "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", "picomatch": "^2.2.3", - "prando": "^6.0.1" + "pure-rand": "^5.0.3" }, "devDependencies": { "@types/graceful-fs": "^4.1.3", diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts index 4a2d83b03d84..18d2ed885a2a 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-util/src/shuffleArray.ts @@ -5,11 +5,14 @@ * LICENSE file in the root directory of this source tree. */ -import Prando from 'prando'; +import {xoroshiro128plus} from 'pure-rand'; export const rngBuilder: (seed: number) => {next: () => number} = ( seed: number, -) => new Prando(seed); +) => { + const gen = xoroshiro128plus(seed); + return { next: () => gen.unsafeNext() }; +} // Fisher-Yates shuffle // This is performed in-place @@ -18,6 +21,7 @@ export default function shuffleArray( random: () => number = Math.random, ): Array { const length = array == null ? 0 : array.length; + if (!length) { return []; } diff --git a/yarn.lock b/yarn.lock index c91ace80b69c..6034d525e6c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12819,7 +12819,7 @@ __metadata: ci-info: ^3.2.0 graceful-fs: ^4.2.9 picomatch: ^2.2.3 - prando: ^6.0.1 + pure-rand: ^5.0.3 languageName: unknown linkType: soft @@ -16625,13 +16625,6 @@ __metadata: languageName: node linkType: hard -"prando@npm:^6.0.1": - version: 6.0.1 - resolution: "prando@npm:6.0.1" - checksum: c0c25dbb2cb92dff4b0f44781f0e2132886c34ab6a12f7f0839d6073c783d86589d4c632727819d8fb0a5a675a7e27223285c6907261d3b6a49167b4cbdc162a - languageName: node - linkType: hard - "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" @@ -16960,6 +16953,13 @@ __metadata: languageName: node linkType: hard +"pure-rand@npm:^5.0.3": + version: 5.0.3 + resolution: "pure-rand@npm:5.0.3" + checksum: a898ab8a40a8eebc641123dab19308044d8bd979efeaba1d8a45e9977593b25b00c3bd9681e2a558a7daec96c6fb8709995b8f10c55475e892b96f381bb6c6d2 + languageName: node + linkType: hard + "q@npm:^1.5.1": version: 1.5.1 resolution: "q@npm:1.5.1" From 54cc38c7b7b0165f104cfa9eeef2fdf9f50eb4e7 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Fri, 14 Oct 2022 22:51:34 +1000 Subject: [PATCH 33/70] updated cli message --- packages/jest-cli/src/args.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/jest-cli/src/args.ts b/packages/jest-cli/src/args.ts index 20cdc864d82f..39c722901518 100644 --- a/packages/jest-cli/src/args.ts +++ b/packages/jest-cli/src/args.ts @@ -10,10 +10,6 @@ import type {Config} from '@jest/types'; import {constants, isJSONString} from 'jest-config'; export function check(argv: Config.Argv): true { - if (argv.seed && !argv.randomize) { - throw new Error('--seed requires --randomize to be specified.'); - } - if ( argv.runInBand && Object.prototype.hasOwnProperty.call(argv, 'maxWorkers') @@ -455,7 +451,7 @@ export const options: {[key: string]: Options} = { }, randomize: { description: - 'Shuffle the order of the tests within a file. The seed used to generate the new order will be printed to stdout. In order to choose the seed refer to the `--seed` CLI option.', + 'Shuffle the order of the tests within a file. In order to choose the seed refer to the `--seed` CLI option.', type: 'boolean', }, reporters: { From 974bc5b33d0d6ef780533c44e4268773b02ff614 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Fri, 14 Oct 2022 22:54:21 +1000 Subject: [PATCH 34/70] added randomize to config --- packages/jest-config/src/ValidConfig.ts | 1 + packages/jest-types/src/Config.ts | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/jest-config/src/ValidConfig.ts b/packages/jest-config/src/ValidConfig.ts index 5239ffd8709d..86e244cacbb6 100644 --- a/packages/jest-config/src/ValidConfig.ts +++ b/packages/jest-config/src/ValidConfig.ts @@ -120,6 +120,7 @@ const initialOptions: Config.InitialOptions = { preset: 'react-native', prettierPath: '/node_modules/prettier', projects: ['project-a', 'project-b/'], + randomize: false, reporters: [ 'default', 'custom-reporter-1', diff --git a/packages/jest-types/src/Config.ts b/packages/jest-types/src/Config.ts index 9a0fa224fdfa..0f15d5621892 100644 --- a/packages/jest-types/src/Config.ts +++ b/packages/jest-types/src/Config.ts @@ -278,6 +278,7 @@ export type InitialOptions = Partial<{ preset: string | null | undefined; prettierPath: string | null | undefined; projects: Array; + randomize: boolean; replname: string | null | undefined; resetMocks: boolean; resetModules: boolean; @@ -391,6 +392,7 @@ export type GlobalConfig = { onlyFailures: boolean; passWithNoTests: boolean; projects: Array; + randomize?: boolean; replname?: string; reporters?: Array; runTestsByPath: boolean; @@ -542,10 +544,7 @@ export type Argv = Arguments< roots: Array; runInBand: boolean; seed: number; -<<<<<<< HEAD -======= showSeed: boolean; ->>>>>>> a49d2dee430835addadb069652af98fc5b87689b selectProjects: Array; setupFiles: Array; setupFilesAfterEnv: Array; From b4e448f86941d0ded09fe05e17f2445453b9a8b0 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Fri, 14 Oct 2022 23:02:00 +1000 Subject: [PATCH 35/70] randomize gets passed to config objects --- .../src/__tests__/normalize.test.ts | 22 +++++++++++++++++++ packages/jest-config/src/normalize.ts | 3 +++ 2 files changed, 25 insertions(+) diff --git a/packages/jest-config/src/__tests__/normalize.test.ts b/packages/jest-config/src/__tests__/normalize.test.ts index 60176360650d..35eea3a03605 100644 --- a/packages/jest-config/src/__tests__/normalize.test.ts +++ b/packages/jest-config/src/__tests__/normalize.test.ts @@ -2164,3 +2164,25 @@ describe('showSeed', () => { expect(options.showSeed).toBeFalsy(); }); }); + +describe('randomize', () => { + test('randomize is set when argv flag is set', async () => { + const {options} = await normalize({rootDir: '/root/'}, { + randomize: true, + } as Config.Argv); + expect(options.randomize).toBe(true); + }); + + test('randomize is set when the config is set', async () => { + const {options} = await normalize( + {randomize: true, rootDir: '/root/'}, + {} as Config.Argv, + ); + expect(options.randomize).toBe(true); + }); + + test('randomize is false when neither is set', async () => { + const {options} = await normalize({rootDir: '/root/'}, {} as Config.Argv); + expect(options.randomize).toBeFalsy(); + }); +}); diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index b8e07d565d52..8d9dfaeaa4b0 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -910,6 +910,7 @@ export default async function normalize( case 'onlyFailures': case 'outputFile': case 'passWithNoTests': + case 'randomize': case 'replname': case 'resetMocks': case 'resetModules': @@ -1022,6 +1023,8 @@ export default async function normalize( newOptions.onlyChanged = newOptions.watch; } + newOptions.randomize = newOptions.randomize || argv.randomize; + newOptions.showSeed = newOptions.showSeed || argv.showSeed; const upperBoundSeedValue = 2 ** 31; From 816b8e621ac30601e10a42a38b984a282cfcda40 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Fri, 14 Oct 2022 23:02:07 +1000 Subject: [PATCH 36/70] lint fix --- packages/jest-util/src/shuffleArray.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts index 18d2ed885a2a..ff19107555d6 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-util/src/shuffleArray.ts @@ -11,8 +11,8 @@ export const rngBuilder: (seed: number) => {next: () => number} = ( seed: number, ) => { const gen = xoroshiro128plus(seed); - return { next: () => gen.unsafeNext() }; -} + return {next: () => gen.unsafeNext()}; +}; // Fisher-Yates shuffle // This is performed in-place From 4ba33d4f739beae3f017bd8bc8282a7f20e4102e Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Fri, 14 Oct 2022 23:04:37 +1000 Subject: [PATCH 37/70] group options returns randomize --- packages/jest-config/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/jest-config/src/index.ts b/packages/jest-config/src/index.ts index 8a8142c502be..6cdd2969d0a6 100644 --- a/packages/jest-config/src/index.ts +++ b/packages/jest-config/src/index.ts @@ -111,6 +111,7 @@ const groupOptions = ( outputFile: options.outputFile, passWithNoTests: options.passWithNoTests, projects: options.projects, + randomize: options.randomize, replname: options.replname, reporters: options.reporters, rootDir: options.rootDir, From 7b40ca5d70bc181a82cd870dc4fd3401130e6f77 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Fri, 14 Oct 2022 23:09:26 +1000 Subject: [PATCH 38/70] removed unnecessary messages --- packages/jest-core/src/cli/index.ts | 4 ---- packages/jest-core/src/watch.ts | 3 --- 2 files changed, 7 deletions(-) diff --git a/packages/jest-core/src/cli/index.ts b/packages/jest-core/src/cli/index.ts index 7e32f7c00ca6..9eb7065cc0a3 100644 --- a/packages/jest-core/src/cli/index.ts +++ b/packages/jest-core/src/cli/index.ts @@ -276,10 +276,6 @@ const runWithoutWatch = async ( filter?: Filter, ) => { const startRun = async (): Promise => { - if (globalConfig.seed) { - outputStream.write(`Seed is ${globalConfig.seed}\n`); - } - if (!globalConfig.listTests) { preRunMessagePrint(outputStream); } diff --git a/packages/jest-core/src/watch.ts b/packages/jest-core/src/watch.ts index 3eefc774d89a..84fbd3e2a69e 100644 --- a/packages/jest-core/src/watch.ts +++ b/packages/jest-core/src/watch.ts @@ -281,9 +281,6 @@ export default async function watch( testWatcher = new TestWatcher({isWatchMode: true}); isInteractive && outputStream.write(specialChars.CLEAR); - if (globalConfig.seed) { - outputStream.write(`Seed is ${globalConfig.seed}\n`); - } preRunMessagePrint(outputStream); isRunning = true; const configs = contexts.map(context => context.config); From ebf01d585a6325284db917c6046568854ac454b0 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Fri, 14 Oct 2022 23:17:14 +1000 Subject: [PATCH 39/70] improved docs --- docs/CLI.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index 5f81a63b8b5b..2481eec9696e 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -320,18 +320,12 @@ If configuration files are found in the specified paths, _all_ projects specifie ### `--randomize` -Shuffle the order of the tests within a file. The seed used to generate the new order will be printed to stdout. - -:::tip - -Additionally you can use the [`--seed`](#--seed) flag to pass the seed value: +Shuffle the order of the tests within a file. The shuffling is based on the seed. See [`--seed`](#--seednum) for more info. ```bash jest --randomize --seed 1234 ``` -::: - :::note This option is only supported using the default `jest-circus` test runner. From 91724513318b06efc2a0d4883b601287b8afe028 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Fri, 14 Oct 2022 23:35:19 +1000 Subject: [PATCH 40/70] updated types --- .../src/legacy-code-todo-rewrite/jestAdapterInit.ts | 5 ++--- packages/jest-circus/src/run.ts | 4 ++-- packages/jest-config/src/normalize.ts | 7 ------- packages/jest-util/src/index.ts | 2 ++ packages/jest-util/src/shuffleArray.ts | 4 +++- 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 332f468fe45d..f51128769600 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -62,9 +62,8 @@ export const initialize = async ({ getRunnerState().testTimeout = globalConfig.testTimeout; } getRunnerState().maxConcurrency = globalConfig.maxConcurrency; - if (globalConfig.seed) { - getRunnerState().seed = globalConfig.seed; - } + + getRunnerState().seed = globalConfig.seed; // @ts-expect-error: missing `concurrent` which is added later const globalsObject: Global.TestFrameworkGlobals = { diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index 1e5feffefb1a..c51ac8fa7f4a 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -7,7 +7,7 @@ import pLimit = require('p-limit'); import type {Circus} from '@jest/types'; -import {rngBuilder, shuffleArray} from 'jest-util'; +import {rngBuilder, RandomNumberGenerator, shuffleArray} from 'jest-util'; import {dispatch, getState} from './state'; import {RETRY_TIMES} from './types'; import { @@ -22,7 +22,7 @@ import { const run = async (): Promise => { const {rootDescribeBlock, seed} = getState(); await dispatch({name: 'run_start'}); - let nextRng: undefined | (() => number) = undefined; + let nextRng: undefined | RandomNumberGenerator["next"] = undefined; if (seed) { const rng = rngBuilder(seed); nextRng = () => rng.next(); diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index 8d9dfaeaa4b0..95e7b78ffba1 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -1161,13 +1161,6 @@ export default async function normalize( newOptions.shard = parseShardPair(argv.shard); } - if (argv.randomize) { - // at time of writing we use Prando which starts repeating after 2^29 - 1 - // 0 is not a valid input seed - newOptions.seed = - argv.seed ?? Math.floor((1 - Math.random()) * (Math.pow(2, 29) - 1)); - } - return { hasDeprecationWarnings, options: newOptions, diff --git a/packages/jest-util/src/index.ts b/packages/jest-util/src/index.ts index 0128c65e1185..8a5ab2b591a6 100644 --- a/packages/jest-util/src/index.ts +++ b/packages/jest-util/src/index.ts @@ -29,3 +29,5 @@ export {default as formatTime} from './formatTime'; export {default as tryRealpath} from './tryRealpath'; export {default as requireOrImportModule} from './requireOrImportModule'; export {default as shuffleArray, rngBuilder} from './shuffleArray'; + +export type {RandomNumberGenerator} from './shuffleArray'; diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts index ff19107555d6..56350a6f8b89 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-util/src/shuffleArray.ts @@ -7,7 +7,9 @@ import {xoroshiro128plus} from 'pure-rand'; -export const rngBuilder: (seed: number) => {next: () => number} = ( +export type RandomNumberGenerator = {next: () => number}; + +export const rngBuilder: (seed: number) => RandomNumberGenerator = ( seed: number, ) => { const gen = xoroshiro128plus(seed); From 0797346da30319102fdf76748485b25a1ff02673 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 15 Oct 2022 00:06:20 +1000 Subject: [PATCH 41/70] changed the type of the rng --- packages/jest-circus/src/run.ts | 13 +++++-------- packages/jest-circus/src/state.ts | 2 +- packages/jest-types/src/Circus.ts | 2 +- packages/jest-util/src/shuffleArray.ts | 16 +++++++++------- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index c51ac8fa7f4a..d4cbaf233089 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -7,7 +7,7 @@ import pLimit = require('p-limit'); import type {Circus} from '@jest/types'; -import {rngBuilder, RandomNumberGenerator, shuffleArray} from 'jest-util'; +import {RandomNumberGenerator, rngBuilder, shuffleArray} from 'jest-util'; import {dispatch, getState} from './state'; import {RETRY_TIMES} from './types'; import { @@ -22,12 +22,9 @@ import { const run = async (): Promise => { const {rootDescribeBlock, seed} = getState(); await dispatch({name: 'run_start'}); - let nextRng: undefined | RandomNumberGenerator["next"] = undefined; - if (seed) { - const rng = rngBuilder(seed); - nextRng = () => rng.next(); - } - await _runTestsForDescribeBlock(rootDescribeBlock, nextRng, true); + const rng = rngBuilder(seed); + + await _runTestsForDescribeBlock(rootDescribeBlock, rng, true); await dispatch({name: 'run_finish'}); return makeRunResult( getState().rootDescribeBlock, @@ -37,7 +34,7 @@ const run = async (): Promise => { const _runTestsForDescribeBlock = async ( describeBlock: Circus.DescribeBlock, - rng: (() => number) | undefined, + rng: RandomNumberGenerator, isRootBlock = false, ) => { await dispatch({describeBlock, name: 'run_describe_start'}); diff --git a/packages/jest-circus/src/state.ts b/packages/jest-circus/src/state.ts index 4e1f3335868a..45466857f52b 100644 --- a/packages/jest-circus/src/state.ts +++ b/packages/jest-circus/src/state.ts @@ -30,7 +30,7 @@ const createState = (): Circus.State => { maxConcurrency: 5, parentProcess: null, rootDescribeBlock: ROOT_DESCRIBE_BLOCK, - seed: undefined, + seed: 0, testNamePattern: null, testTimeout: 5000, unhandledErrors: [], diff --git a/packages/jest-types/src/Circus.ts b/packages/jest-types/src/Circus.ts index fb4e611bf0cf..f94df279c0ae 100644 --- a/packages/jest-types/src/Circus.ts +++ b/packages/jest-types/src/Circus.ts @@ -215,7 +215,7 @@ export type State = { originalGlobalErrorHandlers?: GlobalErrorHandlers; parentProcess: Process | null; // process object from the outer scope rootDescribeBlock: DescribeBlock; - seed?: number; + seed: number; testNamePattern?: RegExp | null; testTimeout: number; unhandledErrors: Array; diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts index 56350a6f8b89..71b9580db236 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-util/src/shuffleArray.ts @@ -5,22 +5,24 @@ * LICENSE file in the root directory of this source tree. */ -import {xoroshiro128plus} from 'pure-rand'; +import {xoroshiro128plus, unsafeUniformIntDistribution} from 'pure-rand'; -export type RandomNumberGenerator = {next: () => number}; +// Generates [from, to] inclusive +export type RandomNumberGenerator = {next: (from: number, to: number) => number}; +// Will likely fail if there are more than 2**32 items to randomize export const rngBuilder: (seed: number) => RandomNumberGenerator = ( seed: number, ) => { const gen = xoroshiro128plus(seed); - return {next: () => gen.unsafeNext()}; + return {next: (from, to) => unsafeUniformIntDistribution(from, to, gen)}; }; // Fisher-Yates shuffle // This is performed in-place export default function shuffleArray( array: Array, - random: () => number = Math.random, + random: RandomNumberGenerator, ): Array { const length = array == null ? 0 : array.length; @@ -30,10 +32,10 @@ export default function shuffleArray( let index = -1; const lastIndex = length - 1; while (++index < length) { - const rand = index + Math.floor(random() * (lastIndex - index + 1)); + const n = random.next(index, lastIndex); const value = array[index]; - array[index] = array[rand]; - array[rand] = value; + array[index] = array[n]; + array[n] = value; } return array; } From 9c0ff4ef9fb7f76ed55d113ba1f75d11595b343b Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 15 Oct 2022 00:12:04 +1000 Subject: [PATCH 42/70] unit tests green --- .../jestAdapterInit.ts | 1 + packages/jest-circus/src/run.ts | 6 +- packages/jest-types/src/Circus.ts | 1 + .../__snapshots__/shuffleArray.test.ts.snap | 114 +++++++++--------- .../src/__tests__/shuffleArray.test.ts | 11 +- 5 files changed, 67 insertions(+), 66 deletions(-) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index f51128769600..29501be1f6cf 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -63,6 +63,7 @@ export const initialize = async ({ } getRunnerState().maxConcurrency = globalConfig.maxConcurrency; + getRunnerState().randomize = globalConfig.randomize; getRunnerState().seed = globalConfig.seed; // @ts-expect-error: missing `concurrent` which is added later diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index d4cbaf233089..4cc79a272110 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -20,9 +20,9 @@ import { } from './utils'; const run = async (): Promise => { - const {rootDescribeBlock, seed} = getState(); + const {rootDescribeBlock, seed, randomize} = getState(); await dispatch({name: 'run_start'}); - const rng = rngBuilder(seed); + const rng = randomize ? rngBuilder(seed) : undefined; await _runTestsForDescribeBlock(rootDescribeBlock, rng, true); await dispatch({name: 'run_finish'}); @@ -34,7 +34,7 @@ const run = async (): Promise => { const _runTestsForDescribeBlock = async ( describeBlock: Circus.DescribeBlock, - rng: RandomNumberGenerator, + rng?: RandomNumberGenerator, isRootBlock = false, ) => { await dispatch({describeBlock, name: 'run_describe_start'}); diff --git a/packages/jest-types/src/Circus.ts b/packages/jest-types/src/Circus.ts index f94df279c0ae..f359ae9c3e34 100644 --- a/packages/jest-types/src/Circus.ts +++ b/packages/jest-types/src/Circus.ts @@ -214,6 +214,7 @@ export type State = { // the original ones. originalGlobalErrorHandlers?: GlobalErrorHandlers; parentProcess: Process | null; // process object from the outer scope + randomize?: boolean; rootDescribeBlock: DescribeBlock; seed: number; testNamePattern?: RegExp | null; diff --git a/packages/jest-util/src/__tests__/__snapshots__/shuffleArray.test.ts.snap b/packages/jest-util/src/__tests__/__snapshots__/shuffleArray.test.ts.snap index 4288d1d48e02..fa97936e90c3 100644 --- a/packages/jest-util/src/__tests__/__snapshots__/shuffleArray.test.ts.snap +++ b/packages/jest-util/src/__tests__/__snapshots__/shuffleArray.test.ts.snap @@ -1,86 +1,86 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`rngBuilder creates a randomiser given seed 1 1`] = ` +exports[`rngBuilder creates a randomizer given seed 1 1`] = ` Array [ - 0.500062950304724, - 0.5157397988987481, - 0.9226656041393675, - 0.3155057489209589, - 0.1551597700815554, - 0.9486529105223372, - 0.3748853226133821, - 0.3723766031610725, - 0.48958173894546503, - 0.6052440010489067, + 0, + 2, + 4, + 0, + 2, + 8, + 5, + 9, + 9, + 5, ] `; -exports[`rngBuilder creates a randomiser given seed 2 1`] = ` +exports[`rngBuilder creates a randomizer given seed 2 1`] = ` Array [ - 0.5001259004930327, - 0.5312583452396231, - 0.6624884909630028, - 0.8890491144007652, - 0.38940668720505356, - 0.6909172021995571, - 0.6007535305341597, - 0.06686430426008634, - 0.881952763041936, - 0.5476082643837688, + 10, + 1, + 0, + 7, + 4, + 4, + 5, + 0, + 10, + 3, ] `; -exports[`rngBuilder creates a randomiser given seed 4 1`] = ` +exports[`rngBuilder creates a randomizer given seed 4 1`] = ` Array [ - 0.5002518008696502, - 0.5625166903628308, - 0.8249769818095902, - 0.27809822845228443, - 0.2790498855242156, - 0.0634860098509784, - 0.4434312750686499, - 0.05855132221676207, - 0.5894388301739094, - 0.24544880754441228, + 8, + 10, + 3, + 2, + 5, + 2, + 3, + 4, + 8, + 5, ] `; -exports[`rngBuilder creates a randomiser given seed 8 1`] = ` +exports[`rngBuilder creates a randomizer given seed 8 1`] = ` Array [ - 0.500503601622885, - 0.6250333806092463, - 0.14995397095334576, - 0.058307676123992465, - 0.47901072620391166, - 0.9113757456446475, - 0.5750688020081886, - 0.8338097936552507, - 0.8361590078184752, - 0.8376564038539437, + 4, + 6, + 0, + 5, + 10, + 0, + 3, + 9, + 5, + 6, ] `; -exports[`rngBuilder creates a randomiser given seed 16 1`] = ` +exports[`rngBuilder creates a randomizer given seed 16 1`] = ` Array [ - 0.5010072108127659, - 0.7520182327721311, - 0.2882353561670136, - 0.3866406226033905, - 0.8962605120372634, - 0.19173304927342874, - 0.08497578978654365, - 0.3369975006992457, - 0.9351766044123043, - 0.10703910470638403, + 7, + 9, + 3, + 2, + 8, + 1, + 6, + 1, + 10, + 1, ] `; exports[`shuffleArray shuffles list ["a", "b", "c", "d"] 1`] = ` Array [ "c", + "b", "a", "d", - "b", ] `; @@ -94,8 +94,8 @@ Array [ exports[`shuffleArray shuffles list ["a", "b"] 1`] = ` Array [ - "b", "a", + "b", ] `; diff --git a/packages/jest-util/src/__tests__/shuffleArray.test.ts b/packages/jest-util/src/__tests__/shuffleArray.test.ts index 41e86e18ca19..68378cd73465 100644 --- a/packages/jest-util/src/__tests__/shuffleArray.test.ts +++ b/packages/jest-util/src/__tests__/shuffleArray.test.ts @@ -10,29 +10,28 @@ import shuffleArray, {rngBuilder} from '../shuffleArray'; describe(rngBuilder, () => { // Breaking these orders would be a breaking change // Some people will be using seeds relying on a particular order - test.each([1, 2, 4, 8, 16])('creates a randomiser given seed %s', seed => { + test.each([1, 2, 4, 8, 16])('creates a randomizer given seed %s', seed => { const rng = rngBuilder(seed); const results = Array(10) .fill(0) - .map(() => rng.next()); + .map(() => rng.next(0, 10)); expect(results).toMatchSnapshot(); }); }); describe(shuffleArray, () => { it('empty array is shuffled', () => { - const shuffled = shuffleArray([]); + const shuffled = shuffleArray([], rngBuilder(seed)); expect(shuffled).toEqual([]); }); // Breaking these orders would be a breaking change // Some people will be using seeds relying on a particular order - const seed = 123; + const seed = 321; test.each([[['a']], [['a', 'b']], [['a', 'b', 'c']], [['a', 'b', 'c', 'd']]])( 'shuffles list %p', l => { - const rng = rngBuilder(seed); - expect(shuffleArray(l, () => rng.next())).toMatchSnapshot(); + expect(shuffleArray(l, rngBuilder(seed))).toMatchSnapshot(); }, ); }); From 604499df05a35ba9ba05933d24aa3099e2970f65 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 15 Oct 2022 00:43:27 +1000 Subject: [PATCH 43/70] added unit tests for the shuffling of tests --- .../jest-circus/src/__mocks__/testUtils.ts | 6 +- .../__snapshots__/randomizeTest.test.ts.snap | 85 +++++++++++++++++++ .../src/__tests__/randomizeTest.test.ts | 44 ++++++++++ 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 packages/jest-circus/src/__tests__/__snapshots__/randomizeTest.test.ts.snap create mode 100644 packages/jest-circus/src/__tests__/randomizeTest.test.ts diff --git a/packages/jest-circus/src/__mocks__/testUtils.ts b/packages/jest-circus/src/__mocks__/testUtils.ts index 300159fd3e71..ea9f63bf2f81 100644 --- a/packages/jest-circus/src/__mocks__/testUtils.ts +++ b/packages/jest-circus/src/__mocks__/testUtils.ts @@ -30,7 +30,7 @@ interface Result extends ExecaSyncReturnValue { error: string; } -export const runTest = (source: string) => { +export const runTest = (source: string, opts?: { seed?: number, randomize?: boolean }) => { const filename = createHash('sha256') .update(source) .digest('hex') @@ -48,7 +48,9 @@ export const runTest = (source: string) => { global.afterAll = circus.afterAll; const testEventHandler = require('${TEST_EVENT_HANDLER_PATH}').default; - const addEventHandler = require('${CIRCUS_STATE_PATH}').addEventHandler; + const {addEventHandler, getState} = require('${CIRCUS_STATE_PATH}'); + getState().randomize = ${opts?.randomize}; + getState().seed = ${opts?.seed ?? 0}; addEventHandler(testEventHandler); ${source}; diff --git a/packages/jest-circus/src/__tests__/__snapshots__/randomizeTest.test.ts.snap b/packages/jest-circus/src/__tests__/__snapshots__/randomizeTest.test.ts.snap new file mode 100644 index 000000000000..f44411f9ac58 --- /dev/null +++ b/packages/jest-circus/src/__tests__/__snapshots__/randomizeTest.test.ts.snap @@ -0,0 +1,85 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`failures 1`] = ` +"start_describe_definition: describe +add_hook: beforeEach +add_hook: afterEach +add_test: one +add_test: two +finish_describe_definition: describe +run_start +run_describe_start: ROOT_DESCRIBE_BLOCK +run_describe_start: describe +test_start: one +hook_start: beforeEach +hook_success: beforeEach +test_fn_start: one +test_fn_failure: one +hook_start: afterEach +hook_failure: afterEach +test_done: one +test_start: two +hook_start: beforeEach +hook_success: beforeEach +test_fn_start: two +test_fn_success: two +hook_start: afterEach +hook_failure: afterEach +test_done: two +run_describe_finish: describe +run_describe_finish: ROOT_DESCRIBE_BLOCK +run_finish + +unhandledErrors: 0" +`; + +exports[`function descriptors 1`] = ` +"start_describe_definition: describer +add_test: One +finish_describe_definition: describer +run_start +run_describe_start: ROOT_DESCRIBE_BLOCK +run_describe_start: describer +test_start: One +test_fn_start: One +test_fn_success: One +test_done: One +run_describe_finish: describer +run_describe_finish: ROOT_DESCRIBE_BLOCK +run_finish + +unhandledErrors: 0" +`; + +exports[`simple test 1`] = ` +"start_describe_definition: describe +add_hook: beforeEach +add_hook: afterEach +add_test: one +add_test: two +finish_describe_definition: describe +run_start +run_describe_start: ROOT_DESCRIBE_BLOCK +run_describe_start: describe +test_start: one +hook_start: beforeEach +hook_success: beforeEach +test_fn_start: one +test_fn_success: one +hook_start: afterEach +hook_success: afterEach +test_done: one +test_start: two +hook_start: beforeEach +hook_success: beforeEach +test_fn_start: two +test_fn_success: two +hook_start: afterEach +hook_success: afterEach +test_done: two +run_describe_finish: describe +run_describe_finish: ROOT_DESCRIBE_BLOCK +run_finish + +unhandledErrors: 0" +`; diff --git a/packages/jest-circus/src/__tests__/randomizeTest.test.ts b/packages/jest-circus/src/__tests__/randomizeTest.test.ts new file mode 100644 index 000000000000..791cf0429a57 --- /dev/null +++ b/packages/jest-circus/src/__tests__/randomizeTest.test.ts @@ -0,0 +1,44 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {runTest} from '../__mocks__/testUtils'; + +test('simple test', () => { + const {stdout} = runTest(` + describe('describe', () => { + beforeEach(() => {}); + afterEach(() => {}); + test('one', () => {}); + test('two', () => {}); + }) + `, { randomize: true, seed: 3 }); + + expect(stdout).toMatchSnapshot(); +}); + +test('function descriptors', () => { + const {stdout} = runTest(` + describe(function describer() {}, () => { + test(class One {}, () => {}); + }) + `, { randomize: true, seed: 3 }); + + expect(stdout).toMatchSnapshot(); +}); + +test('failures', () => { + const {stdout} = runTest(` + describe('describe', () => { + beforeEach(() => {}); + afterEach(() => { throw new Error('banana')}); + test('one', () => { throw new Error('kentucky')}); + test('two', () => {}); + }) + `, { randomize: true, seed: 3 }); + + expect(stdout).toMatchSnapshot(); +}); From 001d150cea958d1df0f4ec802816868d402a2f31 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 15 Oct 2022 00:54:23 +1000 Subject: [PATCH 44/70] e2e tests green --- .../__snapshots__/randomize.test.ts.snap | 71 +++++++++---------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/e2e/__tests__/__snapshots__/randomize.test.ts.snap b/e2e/__tests__/__snapshots__/randomize.test.ts.snap index dfbb6e85152a..282b9671dc04 100644 --- a/e2e/__tests__/__snapshots__/randomize.test.ts.snap +++ b/e2e/__tests__/__snapshots__/randomize.test.ts.snap @@ -5,6 +5,10 @@ exports[`works with each 1`] = ` ✓ test1 ✓ test2 ✓ test3 + describe2 + ✓ test4 + ✓ test6 + ✓ test5 describe1 ✓ test4 ✓ test6 @@ -15,17 +19,22 @@ exports[`works with each 1`] = ` ✓ test10 describe4 ✓ test14 - ✓ test13 ✓ test15 - describe2 - ✓ test4 - ✓ test5 - ✓ test6" + ✓ test13" `; exports[`works with hooks 1`] = ` -"Seed is 123 -This is before all +"This is before all +This is before each +test7 +This is after each +This is before each +test9 +This is after each +This is before each +test8 +This is after each +This is after all describe2 This is before each test4 This is after each @@ -39,6 +48,12 @@ This is before each test1 This is after each This is before each +test2 +This is after each +This is before each +test3 +This is after each +This is before each This is before each describe3 test11 This is after each @@ -48,11 +63,11 @@ test12 This is after each This is before each This is before each describe3 -test14 +test10 This is after each This is before each This is before each describe3 -test13 +test14 This is after each This is before each This is before each describe3 @@ -60,23 +75,7 @@ test15 This is after each This is before each This is before each describe3 -test10 -This is after each -This is before each -test7 -This is after each -This is before each -test8 -This is after each -This is before each -test9 -This is after each -This is after all describe2 -This is before each -test2 -This is after each -This is before each -test3 +test13 This is after each This is after all" `; @@ -86,6 +85,10 @@ exports[`works with passing tests 1`] = ` ✓ test1 ✓ test2 ✓ test3 + describe2 + ✓ test7 + ✓ test9 + ✓ test8 describe1 ✓ test4 ✓ test6 @@ -96,12 +99,8 @@ exports[`works with passing tests 1`] = ` ✓ test10 describe4 ✓ test14 - ✓ test13 ✓ test15 - describe2 - ✓ test7 - ✓ test8 - ✓ test9" + ✓ test13" `; exports[`works with snapshots 1`] = ` @@ -109,6 +108,10 @@ exports[`works with snapshots 1`] = ` ✓ test1 ✓ test2 ✓ test3 + describe2 + ✓ test4 + ✓ test6 + ✓ test5 describe1 ✓ test4 ✓ test6 @@ -119,10 +122,6 @@ exports[`works with snapshots 1`] = ` ✓ test10 describe4 ✓ test14 - ✓ test13 ✓ test15 - describe2 - ✓ test4 - ✓ test5 - ✓ test6" + ✓ test13" `; From 30b345250145b52530bb1579cf8f18185edb3889 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 15 Oct 2022 01:23:35 +1000 Subject: [PATCH 45/70] small change to docs --- docs/CLI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CLI.md b/docs/CLI.md index 2481eec9696e..647f174fd62a 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -320,7 +320,7 @@ If configuration files are found in the specified paths, _all_ projects specifie ### `--randomize` -Shuffle the order of the tests within a file. The shuffling is based on the seed. See [`--seed`](#--seednum) for more info. +Shuffle the order of the tests within a file. The shuffling is based on the seed. See [`--seed=`](#--seednum) for more info. ```bash jest --randomize --seed 1234 From 8661cad1dca72e11e9e79cd59f0c783b39192f52 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 15 Oct 2022 01:24:05 +1000 Subject: [PATCH 46/70] e2e test for the config --- .../__snapshots__/randomize.test.ts.snap | 82 +++++-------------- e2e/__tests__/randomize.test.ts | 50 ++++++----- e2e/randomize/different-config.json | 4 + 3 files changed, 57 insertions(+), 79 deletions(-) create mode 100644 e2e/randomize/different-config.json diff --git a/e2e/__tests__/__snapshots__/randomize.test.ts.snap b/e2e/__tests__/__snapshots__/randomize.test.ts.snap index 282b9671dc04..7b9e9f889c89 100644 --- a/e2e/__tests__/__snapshots__/randomize.test.ts.snap +++ b/e2e/__tests__/__snapshots__/randomize.test.ts.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`works with each 1`] = ` -"PASS __tests__/each.test.js - ✓ test1 +" ✓ test1 ✓ test2 ✓ test3 describe2 @@ -24,65 +23,29 @@ exports[`works with each 1`] = ` `; exports[`works with hooks 1`] = ` -"This is before all -This is before each -test7 -This is after each -This is before each -test9 -This is after each -This is before each -test8 -This is after each -This is after all describe2 -This is before each -test4 -This is after each -This is before each -test6 -This is after each -This is before each -test5 -This is after each -This is before each -test1 -This is after each -This is before each -test2 -This is after each -This is before each -test3 -This is after each -This is before each -This is before each describe3 -test11 -This is after each -This is before each -This is before each describe3 -test12 -This is after each -This is before each -This is before each describe3 -test10 -This is after each -This is before each -This is before each describe3 -test14 -This is after each -This is before each -This is before each describe3 -test15 -This is after each -This is before each -This is before each describe3 -test13 -This is after each -This is after all" +" ✓ test1 + ✓ test2 + ✓ test3 + describe2 + ✓ test7 + ✓ test9 + ✓ test8 + describe1 + ✓ test4 + ✓ test6 + ✓ test5 + describe3 + ✓ test11 + ✓ test12 + ✓ test10 + describe4 + ✓ test14 + ✓ test15 + ✓ test13" `; exports[`works with passing tests 1`] = ` -"PASS __tests__/success.test.js - ✓ test1 +" ✓ test1 ✓ test2 ✓ test3 describe2 @@ -104,8 +67,7 @@ exports[`works with passing tests 1`] = ` `; exports[`works with snapshots 1`] = ` -"PASS __tests__/snapshots.test.js - ✓ test1 +" ✓ test1 ✓ test2 ✓ test3 describe2 diff --git a/e2e/__tests__/randomize.test.ts b/e2e/__tests__/randomize.test.ts index 3d4d1812562a..265675a843e0 100644 --- a/e2e/__tests__/randomize.test.ts +++ b/e2e/__tests__/randomize.test.ts @@ -8,47 +8,59 @@ import * as path from 'path'; import {skipSuiteOnJasmine} from '@jest/test-utils'; import {extractSummary} from '../Utils'; -import runJest from '../runJest'; +import runJest, { RunJestResult } from '../runJest'; skipSuiteOnJasmine(); const dir = path.resolve(__dirname, '../randomize'); +function runJestTwice( + dir: string, + args: Array, +): [RunJestResult, RunJestResult] { + return [runJest(dir, [...args, '--randomize']), runJest(dir, [...args, '--config', 'different-config.json'])]; +} + test('works with passing tests', () => { - const result = runJest(dir, [ - 'success.test.js', - '--randomize', - '--seed', - '123', - ]); - const {rest} = extractSummary(result.stderr); - expect(rest).toMatchSnapshot(); + const [result1, result2] = runJestTwice(dir, ['success.test.js', '--seed', '123']); + + const rest1 = extractSummary(result1.stderr).rest.split('\n').slice(1).join('\n'); + const rest2 = extractSummary(result2.stderr).rest.split('\n').slice(1).join('\n'); + expect(rest1).toEqual(rest2); + expect(rest1).toMatchSnapshot(); }); test('works with each', () => { - const result = runJest(dir, ['each.test.js', '--randomize', '--seed', '123']); - const {rest} = extractSummary(result.stderr); - expect(rest).toMatchSnapshot(); + const [result1, result2] = runJestTwice(dir, ['each.test.js', '--seed', '123']); + const rest1 = extractSummary(result1.stderr).rest.split('\n').slice(1).join('\n'); + const rest2 = extractSummary(result2.stderr).rest.split('\n').slice(1).join('\n'); + expect(rest1).toEqual(rest2); + expect(rest1).toMatchSnapshot(); }); test('works with hooks', () => { - const result = runJest(dir, [ + const [result1, result2] = runJestTwice(dir, [ 'hooks.test.js', - '--randomize', '--seed', '123', ]); + // Change in formatting could change this one - expect(result.stdout).toMatchSnapshot(); + const rest1 = extractSummary(result1.stderr).rest.split('\n').slice(1).join('\n'); + const rest2 = extractSummary(result2.stderr).rest.split('\n').slice(1).join('\n'); + expect(rest1).toEqual(rest2); + expect(rest1).toMatchSnapshot(); }); test('works with snapshots', () => { - const result = runJest(dir, [ + const [result1, result2] = runJestTwice(dir, [ 'snapshots.test.js', - '--randomize', '--seed', '123', ]); - const {rest} = extractSummary(result.stderr); - expect(rest).toMatchSnapshot(); + + const rest1 = extractSummary(result1.stderr).rest.split('\n').slice(1).join('\n'); + const rest2 = extractSummary(result2.stderr).rest.split('\n').slice(1).join('\n'); + expect(rest1).toEqual(rest2); + expect(rest1).toMatchSnapshot(); }); diff --git a/e2e/randomize/different-config.json b/e2e/randomize/different-config.json new file mode 100644 index 000000000000..4f8448990517 --- /dev/null +++ b/e2e/randomize/different-config.json @@ -0,0 +1,4 @@ +{ + "displayName": "Config from different-config.json file", + "randomize": true +} From 81d526b6813e31c09610bf615d5844bff0c7703a Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 15 Oct 2022 01:38:02 +1000 Subject: [PATCH 47/70] tweaked changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a20de49bfd7..10af4ccf2a67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Features -- `[jest-circus, @jest/cli, jest-config]` Add cli feature to randomize order or tests ([#12922](https://github.com/facebook/jest/pull/12922)) +- `[jest-circus, @jest/cli, jest-config]` Add feature to randomize order of tests via CLI flag or through the config file([#12922](https://github.com/facebook/jest/pull/12922)) ### Fixes From 825fdd96d0c6cd2a94cb405336a875581ff685dc Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 15 Oct 2022 01:39:12 +1000 Subject: [PATCH 48/70] linting fix --- e2e/__tests__/randomize.test.ts | 59 +++++++++++++++---- .../jest-circus/src/__mocks__/testUtils.ts | 5 +- .../src/__tests__/randomizeTest.test.ts | 21 +++++-- packages/jest-util/src/shuffleArray.ts | 6 +- 4 files changed, 70 insertions(+), 21 deletions(-) diff --git a/e2e/__tests__/randomize.test.ts b/e2e/__tests__/randomize.test.ts index 265675a843e0..799e51f86386 100644 --- a/e2e/__tests__/randomize.test.ts +++ b/e2e/__tests__/randomize.test.ts @@ -8,7 +8,7 @@ import * as path from 'path'; import {skipSuiteOnJasmine} from '@jest/test-utils'; import {extractSummary} from '../Utils'; -import runJest, { RunJestResult } from '../runJest'; +import runJest, {RunJestResult} from '../runJest'; skipSuiteOnJasmine(); @@ -18,22 +18,45 @@ function runJestTwice( dir: string, args: Array, ): [RunJestResult, RunJestResult] { - return [runJest(dir, [...args, '--randomize']), runJest(dir, [...args, '--config', 'different-config.json'])]; + return [ + runJest(dir, [...args, '--randomize']), + runJest(dir, [...args, '--config', 'different-config.json']), + ]; } test('works with passing tests', () => { - const [result1, result2] = runJestTwice(dir, ['success.test.js', '--seed', '123']); + const [result1, result2] = runJestTwice(dir, [ + 'success.test.js', + '--seed', + '123', + ]); - const rest1 = extractSummary(result1.stderr).rest.split('\n').slice(1).join('\n'); - const rest2 = extractSummary(result2.stderr).rest.split('\n').slice(1).join('\n'); + const rest1 = extractSummary(result1.stderr) + .rest.split('\n') + .slice(1) + .join('\n'); + const rest2 = extractSummary(result2.stderr) + .rest.split('\n') + .slice(1) + .join('\n'); expect(rest1).toEqual(rest2); expect(rest1).toMatchSnapshot(); }); test('works with each', () => { - const [result1, result2] = runJestTwice(dir, ['each.test.js', '--seed', '123']); - const rest1 = extractSummary(result1.stderr).rest.split('\n').slice(1).join('\n'); - const rest2 = extractSummary(result2.stderr).rest.split('\n').slice(1).join('\n'); + const [result1, result2] = runJestTwice(dir, [ + 'each.test.js', + '--seed', + '123', + ]); + const rest1 = extractSummary(result1.stderr) + .rest.split('\n') + .slice(1) + .join('\n'); + const rest2 = extractSummary(result2.stderr) + .rest.split('\n') + .slice(1) + .join('\n'); expect(rest1).toEqual(rest2); expect(rest1).toMatchSnapshot(); }); @@ -46,8 +69,14 @@ test('works with hooks', () => { ]); // Change in formatting could change this one - const rest1 = extractSummary(result1.stderr).rest.split('\n').slice(1).join('\n'); - const rest2 = extractSummary(result2.stderr).rest.split('\n').slice(1).join('\n'); + const rest1 = extractSummary(result1.stderr) + .rest.split('\n') + .slice(1) + .join('\n'); + const rest2 = extractSummary(result2.stderr) + .rest.split('\n') + .slice(1) + .join('\n'); expect(rest1).toEqual(rest2); expect(rest1).toMatchSnapshot(); }); @@ -59,8 +88,14 @@ test('works with snapshots', () => { '123', ]); - const rest1 = extractSummary(result1.stderr).rest.split('\n').slice(1).join('\n'); - const rest2 = extractSummary(result2.stderr).rest.split('\n').slice(1).join('\n'); + const rest1 = extractSummary(result1.stderr) + .rest.split('\n') + .slice(1) + .join('\n'); + const rest2 = extractSummary(result2.stderr) + .rest.split('\n') + .slice(1) + .join('\n'); expect(rest1).toEqual(rest2); expect(rest1).toMatchSnapshot(); }); diff --git a/packages/jest-circus/src/__mocks__/testUtils.ts b/packages/jest-circus/src/__mocks__/testUtils.ts index ea9f63bf2f81..5d3e91292f90 100644 --- a/packages/jest-circus/src/__mocks__/testUtils.ts +++ b/packages/jest-circus/src/__mocks__/testUtils.ts @@ -30,7 +30,10 @@ interface Result extends ExecaSyncReturnValue { error: string; } -export const runTest = (source: string, opts?: { seed?: number, randomize?: boolean }) => { +export const runTest = ( + source: string, + opts?: {seed?: number; randomize?: boolean}, +) => { const filename = createHash('sha256') .update(source) .digest('hex') diff --git a/packages/jest-circus/src/__tests__/randomizeTest.test.ts b/packages/jest-circus/src/__tests__/randomizeTest.test.ts index 791cf0429a57..1a2cbe6204da 100644 --- a/packages/jest-circus/src/__tests__/randomizeTest.test.ts +++ b/packages/jest-circus/src/__tests__/randomizeTest.test.ts @@ -8,37 +8,46 @@ import {runTest} from '../__mocks__/testUtils'; test('simple test', () => { - const {stdout} = runTest(` + const {stdout} = runTest( + ` describe('describe', () => { beforeEach(() => {}); afterEach(() => {}); test('one', () => {}); test('two', () => {}); }) - `, { randomize: true, seed: 3 }); + `, + {randomize: true, seed: 3}, + ); expect(stdout).toMatchSnapshot(); }); test('function descriptors', () => { - const {stdout} = runTest(` + const {stdout} = runTest( + ` describe(function describer() {}, () => { test(class One {}, () => {}); }) - `, { randomize: true, seed: 3 }); + `, + {randomize: true, seed: 3}, + ); expect(stdout).toMatchSnapshot(); }); test('failures', () => { - const {stdout} = runTest(` + const {stdout} = runTest( + ` describe('describe', () => { beforeEach(() => {}); afterEach(() => { throw new Error('banana')}); test('one', () => { throw new Error('kentucky')}); test('two', () => {}); }) - `, { randomize: true, seed: 3 }); + `, + {randomize: true, seed: 3}, + ); expect(stdout).toMatchSnapshot(); }); diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts index 71b9580db236..68a7ae854f79 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-util/src/shuffleArray.ts @@ -5,10 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import {xoroshiro128plus, unsafeUniformIntDistribution} from 'pure-rand'; +import {unsafeUniformIntDistribution, xoroshiro128plus} from 'pure-rand'; // Generates [from, to] inclusive -export type RandomNumberGenerator = {next: (from: number, to: number) => number}; +export type RandomNumberGenerator = { + next: (from: number, to: number) => number; +}; // Will likely fail if there are more than 2**32 items to randomize export const rngBuilder: (seed: number) => RandomNumberGenerator = ( From 75127388d38cc444143cd9370375db3286717745 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 15 Oct 2022 01:48:07 +1000 Subject: [PATCH 49/70] factorised test --- e2e/__tests__/randomize.test.ts | 47 +++++++++++---------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/e2e/__tests__/randomize.test.ts b/e2e/__tests__/randomize.test.ts index 799e51f86386..a7d891727548 100644 --- a/e2e/__tests__/randomize.test.ts +++ b/e2e/__tests__/randomize.test.ts @@ -14,6 +14,8 @@ skipSuiteOnJasmine(); const dir = path.resolve(__dirname, '../randomize'); +const trimFirstLine = (str: string): string => str.split('\n').slice(1).join('\n'); + function runJestTwice( dir: string, args: Array, @@ -31,14 +33,9 @@ test('works with passing tests', () => { '123', ]); - const rest1 = extractSummary(result1.stderr) - .rest.split('\n') - .slice(1) - .join('\n'); - const rest2 = extractSummary(result2.stderr) - .rest.split('\n') - .slice(1) - .join('\n'); + const rest1 = trimFirstLine(extractSummary(result1.stderr).rest); + const rest2 = trimFirstLine(extractSummary(result2.stderr).rest); + expect(rest1).toEqual(rest2); expect(rest1).toMatchSnapshot(); }); @@ -49,14 +46,10 @@ test('works with each', () => { '--seed', '123', ]); - const rest1 = extractSummary(result1.stderr) - .rest.split('\n') - .slice(1) - .join('\n'); - const rest2 = extractSummary(result2.stderr) - .rest.split('\n') - .slice(1) - .join('\n'); + + const rest1 = trimFirstLine(extractSummary(result1.stderr).rest); + const rest2 = trimFirstLine(extractSummary(result2.stderr).rest); + expect(rest1).toEqual(rest2); expect(rest1).toMatchSnapshot(); }); @@ -69,14 +62,9 @@ test('works with hooks', () => { ]); // Change in formatting could change this one - const rest1 = extractSummary(result1.stderr) - .rest.split('\n') - .slice(1) - .join('\n'); - const rest2 = extractSummary(result2.stderr) - .rest.split('\n') - .slice(1) - .join('\n'); + const rest1 = trimFirstLine(extractSummary(result1.stderr).rest); + const rest2 = trimFirstLine(extractSummary(result2.stderr).rest); + expect(rest1).toEqual(rest2); expect(rest1).toMatchSnapshot(); }); @@ -88,14 +76,9 @@ test('works with snapshots', () => { '123', ]); - const rest1 = extractSummary(result1.stderr) - .rest.split('\n') - .slice(1) - .join('\n'); - const rest2 = extractSummary(result2.stderr) - .rest.split('\n') - .slice(1) - .join('\n'); + const rest1 = trimFirstLine(extractSummary(result1.stderr).rest); + const rest2 = trimFirstLine(extractSummary(result2.stderr).rest); + expect(rest1).toEqual(rest2); expect(rest1).toMatchSnapshot(); }); From 57e98360d726359cda3975a8f5b33df82aa4e34a Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 22 Oct 2022 07:20:31 +1000 Subject: [PATCH 50/70] linting fix --- e2e/__tests__/randomize.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/e2e/__tests__/randomize.test.ts b/e2e/__tests__/randomize.test.ts index a7d891727548..b433436bf73a 100644 --- a/e2e/__tests__/randomize.test.ts +++ b/e2e/__tests__/randomize.test.ts @@ -14,7 +14,8 @@ skipSuiteOnJasmine(); const dir = path.resolve(__dirname, '../randomize'); -const trimFirstLine = (str: string): string => str.split('\n').slice(1).join('\n'); +const trimFirstLine = (str: string): string => + str.split('\n').slice(1).join('\n'); function runJestTwice( dir: string, From b844e1b165a42db1a6f6c009d14054edb5a36d59 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 22 Oct 2022 07:21:14 +1000 Subject: [PATCH 51/70] yarn dedupe --- yarn.lock | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 2d87d4269dce..333aaf428ea1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16946,14 +16946,7 @@ __metadata: languageName: node linkType: hard -"pure-rand@npm:^5.0.1": - version: 5.0.1 - resolution: "pure-rand@npm:5.0.1" - checksum: 2b05a6d80163308583a013fab8d7f7f2958a6f77895680c99d8c3ea1f3e49ac273716a59cb1777cfc370540df53e6dc017e46c70a869da81fe490b2e6703d77d - languageName: node - linkType: hard - -"pure-rand@npm:^5.0.3": +"pure-rand@npm:^5.0.1, pure-rand@npm:^5.0.3": version: 5.0.3 resolution: "pure-rand@npm:5.0.3" checksum: a898ab8a40a8eebc641123dab19308044d8bd979efeaba1d8a45e9977593b25b00c3bd9681e2a558a7daec96c6fb8709995b8f10c55475e892b96f381bb6c6d2 From bbc70a132e436a881721c0c6741338eea6484d43 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 22 Oct 2022 07:44:26 +1000 Subject: [PATCH 52/70] show seed true for randomize --- .../src/__tests__/normalize.test.ts | 8 +++++++ packages/jest-config/src/normalize.ts | 5 +++-- packages/jest-util/src/invariant.ts | 8 +++++++ packages/jest-util/src/shuffleArray.ts | 21 ++++++++++++------- 4 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 packages/jest-util/src/invariant.ts diff --git a/packages/jest-config/src/__tests__/normalize.test.ts b/packages/jest-config/src/__tests__/normalize.test.ts index 4292cc82923f..121eeaba89c8 100644 --- a/packages/jest-config/src/__tests__/normalize.test.ts +++ b/packages/jest-config/src/__tests__/normalize.test.ts @@ -2165,6 +2165,14 @@ describe('showSeed', () => { const {options} = await normalize({rootDir: '/root/'}, {} as Config.Argv); expect(options.showSeed).toBeFalsy(); }); + + test('showSeed is true when randomize is set', async () => { + const {options} = await normalize( + {randomize: true, rootDir: '/root/'}, + {} as Config.Argv, + ); + expect(options.showSeed).toBe(true); + }); }); describe('randomize', () => { diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index 46131f08710c..222a5ba5d30e 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -1025,11 +1025,12 @@ export default async function normalize( newOptions.randomize = newOptions.randomize || argv.randomize; - newOptions.showSeed = newOptions.showSeed || argv.showSeed; + newOptions.showSeed = + newOptions.randomize || newOptions.showSeed || argv.showSeed; const upperBoundSeedValue = 2 ** 31; - // xoroshiro128plus is used in v8 and is used here (at time of writing) + // bounds are determined by xoroshiro128plus which is used in v8 and is used here (at time of writing) newOptions.seed = argv.seed ?? Math.floor((2 ** 32 - 1) * Math.random() - upperBoundSeedValue); diff --git a/packages/jest-util/src/invariant.ts b/packages/jest-util/src/invariant.ts new file mode 100644 index 000000000000..eee61ed9d0c3 --- /dev/null +++ b/packages/jest-util/src/invariant.ts @@ -0,0 +1,8 @@ +export function invariant( + condition: unknown, + message?: string, +): asserts condition { + if (!condition) { + throw new Error(message); + } +} diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts index 68a7ae854f79..a393bb9e3c00 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-util/src/shuffleArray.ts @@ -6,16 +6,21 @@ */ import {unsafeUniformIntDistribution, xoroshiro128plus} from 'pure-rand'; +import {invariant} from './invariant'; // Generates [from, to] inclusive export type RandomNumberGenerator = { next: (from: number, to: number) => number; }; -// Will likely fail if there are more than 2**32 items to randomize export const rngBuilder: (seed: number) => RandomNumberGenerator = ( seed: number, ) => { + const upperBoundSeedValue = 2 ** 31; + invariant( + seed < -upperBoundSeedValue || seed > upperBoundSeedValue - 1, + `seed value must be between \`-0x80000000\` and \`0x7fffffff\` inclusive - is ${seed}`, + ); const gen = xoroshiro128plus(seed); return {next: (from, to) => unsafeUniformIntDistribution(from, to, gen)}; }; @@ -28,16 +33,16 @@ export default function shuffleArray( ): Array { const length = array == null ? 0 : array.length; - if (!length) { + if (length === 0) { return []; } - let index = -1; - const lastIndex = length - 1; - while (++index < length) { - const n = random.next(index, lastIndex); - const value = array[index]; - array[index] = array[n]; + + for (let i = 0; i < length; i++) { + const n = random.next(i, length - 1); + const value = array[i]; + array[i] = array[n]; array[n] = value; } + return array; } From d4509cbacce30920212db3cc93832b224bd32c71 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 22 Oct 2022 07:56:07 +1000 Subject: [PATCH 53/70] updated docs about randomize --- docs/CLI.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CLI.md b/docs/CLI.md index 647f174fd62a..c8db3353f881 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -321,6 +321,7 @@ If configuration files are found in the specified paths, _all_ projects specifie ### `--randomize` Shuffle the order of the tests within a file. The shuffling is based on the seed. See [`--seed=`](#--seednum) for more info. +Seed value is displayed when this option is set equivalent to setting the CLI option [`--showSeed`](#--showseed). ```bash jest --randomize --seed 1234 From 6ce659deedfd802b70e412560ceb0440cb2471cc Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 22 Oct 2022 08:14:48 +1000 Subject: [PATCH 54/70] e2e tests also test randomize --- e2e/__tests__/showSeed.test.ts | 50 ++++++++++++++------------- e2e/jest-object/different-config.json | 4 --- e2e/jest-object/randomize-config.json | 4 +++ e2e/jest-object/showSeed-config.json | 4 +++ 4 files changed, 34 insertions(+), 28 deletions(-) delete mode 100644 e2e/jest-object/different-config.json create mode 100644 e2e/jest-object/randomize-config.json create mode 100644 e2e/jest-object/showSeed-config.json diff --git a/e2e/__tests__/showSeed.test.ts b/e2e/__tests__/showSeed.test.ts index d7574e166945..d75484496652 100644 --- a/e2e/__tests__/showSeed.test.ts +++ b/e2e/__tests__/showSeed.test.ts @@ -14,39 +14,41 @@ const dir = path.resolve(__dirname, '../jest-object'); const randomSeedValueRegExp = /Seed:\s+<>/; const seedValueRegExp = /Seed:\s+1234/; -test('--showSeed changes report to output seed', () => { - const {stderr} = runJest(dir, ['--showSeed', '--no-cache']); +describe.each(['showSeed', 'randomize'])('Option %s', option => { + test(`--${option} changes report to output seed`, () => { + const {stderr} = runJest(dir, [`--${option}`, '--no-cache']); - const {summary} = extractSummary(stderr); + const {summary} = extractSummary(stderr); - expect(replaceSeed(summary)).toMatch(randomSeedValueRegExp); -}); + expect(replaceSeed(summary)).toMatch(randomSeedValueRegExp); + }); -test('if --showSeed is not present the report will not show the seed', () => { - const {stderr} = runJest(dir, ['--seed', '1234']); + test(`if --${option} is not present the report will not show the seed`, () => { + const {stderr} = runJest(dir, ['--seed', '1234']); - const {summary} = extractSummary(stderr); + const {summary} = extractSummary(stderr); - expect(replaceSeed(summary)).not.toMatch(randomSeedValueRegExp); -}); + expect(replaceSeed(summary)).not.toMatch(randomSeedValueRegExp); + }); -test('if showSeed is present in the config the report will show the seed', () => { - const {stderr} = runJest(dir, [ - '--seed', - '1234', - '--config', - 'different-config.json', - ]); + test(`if ${option} is present in the config the report will show the seed`, () => { + const {stderr} = runJest(dir, [ + '--seed', + '1234', + '--config', + `${option}-config.json`, + ]); - const {summary} = extractSummary(stderr); + const {summary} = extractSummary(stderr); - expect(summary).toMatch(seedValueRegExp); -}); + expect(summary).toMatch(seedValueRegExp); + }); -test('--seed --showSeed will show the seed in the report', () => { - const {stderr} = runJest(dir, ['--showSeed', '--seed', '1234']); + test(`--seed --${option} will show the seed in the report`, () => { + const {stderr} = runJest(dir, [`--${option}`, '--seed', '1234']); - const {summary} = extractSummary(stderr); + const {summary} = extractSummary(stderr); - expect(summary).toMatch(seedValueRegExp); + expect(summary).toMatch(seedValueRegExp); + }); }); diff --git a/e2e/jest-object/different-config.json b/e2e/jest-object/different-config.json deleted file mode 100644 index ae9b2166eaff..000000000000 --- a/e2e/jest-object/different-config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "displayName": "Config from different-config.json file", - "showSeed": true -} diff --git a/e2e/jest-object/randomize-config.json b/e2e/jest-object/randomize-config.json new file mode 100644 index 000000000000..434221a0bb3d --- /dev/null +++ b/e2e/jest-object/randomize-config.json @@ -0,0 +1,4 @@ +{ + "displayName": "Config from randomize-config.json file", + "randomize": true +} diff --git a/e2e/jest-object/showSeed-config.json b/e2e/jest-object/showSeed-config.json new file mode 100644 index 000000000000..a25af4e8d2b4 --- /dev/null +++ b/e2e/jest-object/showSeed-config.json @@ -0,0 +1,4 @@ +{ + "displayName": "Config from showSeed-config.json file", + "showSeed": true +} From 7bdad9f93750a35b828f893cb7663863bb0bb279 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 22 Oct 2022 08:14:56 +1000 Subject: [PATCH 55/70] updated error message --- packages/jest-config/src/__tests__/normalize.test.ts | 4 ++-- packages/jest-config/src/normalize.ts | 2 +- packages/jest-util/src/shuffleArray.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/jest-config/src/__tests__/normalize.test.ts b/packages/jest-config/src/__tests__/normalize.test.ts index 121eeaba89c8..e92ee6a76761 100644 --- a/packages/jest-config/src/__tests__/normalize.test.ts +++ b/packages/jest-config/src/__tests__/normalize.test.ts @@ -2133,14 +2133,14 @@ describe('seed', () => { seed: 2 ** 33, } as Config.Argv), ).rejects.toThrow( - 'seed value must be between `-0x80000000` and `0x7fffffff` inclusive - is 8589934592', + 'seed value must be between `-0x80000000` and `0x7fffffff` inclusive instead it is 8589934592', ); await expect( normalize({rootDir: '/root/'}, { seed: -(2 ** 33), } as Config.Argv), ).rejects.toThrow( - 'seed value must be between `-0x80000000` and `0x7fffffff` inclusive - is -8589934592', + 'seed value must be between `-0x80000000` and `0x7fffffff` inclusive instead it is -8589934592', ); }); }); diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index 222a5ba5d30e..9319e0039b80 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -1040,7 +1040,7 @@ export default async function normalize( ) { throw new ValidationError( 'Validation Error', - `seed value must be between \`-0x80000000\` and \`0x7fffffff\` inclusive - is ${newOptions.seed}`, + `seed value must be between \`-0x80000000\` and \`0x7fffffff\` inclusive instead it is ${newOptions.seed}`, ); } diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-util/src/shuffleArray.ts index a393bb9e3c00..61445b392f2c 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-util/src/shuffleArray.ts @@ -18,8 +18,8 @@ export const rngBuilder: (seed: number) => RandomNumberGenerator = ( ) => { const upperBoundSeedValue = 2 ** 31; invariant( - seed < -upperBoundSeedValue || seed > upperBoundSeedValue - 1, - `seed value must be between \`-0x80000000\` and \`0x7fffffff\` inclusive - is ${seed}`, + seed > -upperBoundSeedValue || seed < upperBoundSeedValue - 1, + `seed value must be between \`-0x80000000\` and \`0x7fffffff\` inclusive instead it is ${seed}`, ); const gen = xoroshiro128plus(seed); return {next: (from, to) => unsafeUniformIntDistribution(from, to, gen)}; From 5fd2e2ae9d27b4166f1c374766b30b5cd77a9084 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 22 Oct 2022 15:29:03 +1000 Subject: [PATCH 56/70] move shuffleArray to jest-circus --- packages/jest-circus/package.json | 1 + .../__snapshots__/shuffleArray.test.ts.snap | 0 .../src/__tests__/shuffleArray.test.ts | 15 ++++++++++++--- packages/jest-circus/src/run.ts | 2 +- .../src/shuffleArray.ts | 11 ++++++----- packages/jest-util/package.json | 3 +-- packages/jest-util/src/index.ts | 3 --- packages/jest-util/src/invariant.ts | 8 -------- yarn.lock | 2 +- 9 files changed, 22 insertions(+), 23 deletions(-) rename packages/{jest-util => jest-circus}/src/__tests__/__snapshots__/shuffleArray.test.ts.snap (100%) rename packages/{jest-util => jest-circus}/src/__tests__/shuffleArray.test.ts (68%) rename packages/{jest-util => jest-circus}/src/shuffleArray.ts (82%) delete mode 100644 packages/jest-util/src/invariant.ts diff --git a/packages/jest-circus/package.json b/packages/jest-circus/package.json index c991d700976c..9d19f5a59813 100644 --- a/packages/jest-circus/package.json +++ b/packages/jest-circus/package.json @@ -35,6 +35,7 @@ "jest-util": "workspace:^", "p-limit": "^3.1.0", "pretty-format": "workspace:^", + "pure-rand": "^5.0.3", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, diff --git a/packages/jest-util/src/__tests__/__snapshots__/shuffleArray.test.ts.snap b/packages/jest-circus/src/__tests__/__snapshots__/shuffleArray.test.ts.snap similarity index 100% rename from packages/jest-util/src/__tests__/__snapshots__/shuffleArray.test.ts.snap rename to packages/jest-circus/src/__tests__/__snapshots__/shuffleArray.test.ts.snap diff --git a/packages/jest-util/src/__tests__/shuffleArray.test.ts b/packages/jest-circus/src/__tests__/shuffleArray.test.ts similarity index 68% rename from packages/jest-util/src/__tests__/shuffleArray.test.ts rename to packages/jest-circus/src/__tests__/shuffleArray.test.ts index 68378cd73465..bc92ba8536a4 100644 --- a/packages/jest-util/src/__tests__/shuffleArray.test.ts +++ b/packages/jest-circus/src/__tests__/shuffleArray.test.ts @@ -7,7 +7,7 @@ import shuffleArray, {rngBuilder} from '../shuffleArray'; -describe(rngBuilder, () => { +describe('rngBuilder', () => { // Breaking these orders would be a breaking change // Some people will be using seeds relying on a particular order test.each([1, 2, 4, 8, 16])('creates a randomizer given seed %s', seed => { @@ -17,10 +17,19 @@ describe(rngBuilder, () => { .map(() => rng.next(0, 10)); expect(results).toMatchSnapshot(); }); + + test('throwing is seed is too large or too small', () => { + expect(() => rngBuilder(2 ** 33)).toThrow( + 'seed value must be between `-0x80000000` and `0x7fffffff` inclusive instead it is 8589934592', + ); + expect(() => rngBuilder(-(2 ** 33))).toThrow( + 'seed value must be between `-0x80000000` and `0x7fffffff` inclusive instead it is -8589934592', + ); + }); }); -describe(shuffleArray, () => { - it('empty array is shuffled', () => { +describe('shuffleArray', () => { + test('empty array is shuffled', () => { const shuffled = shuffleArray([], rngBuilder(seed)); expect(shuffled).toEqual([]); }); diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index 4cc79a272110..f7fecae82b99 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -7,7 +7,7 @@ import pLimit = require('p-limit'); import type {Circus} from '@jest/types'; -import {RandomNumberGenerator, rngBuilder, shuffleArray} from 'jest-util'; +import shuffleArray, {RandomNumberGenerator, rngBuilder} from './shuffleArray'; import {dispatch, getState} from './state'; import {RETRY_TIMES} from './types'; import { diff --git a/packages/jest-util/src/shuffleArray.ts b/packages/jest-circus/src/shuffleArray.ts similarity index 82% rename from packages/jest-util/src/shuffleArray.ts rename to packages/jest-circus/src/shuffleArray.ts index 61445b392f2c..e8fd24832426 100644 --- a/packages/jest-util/src/shuffleArray.ts +++ b/packages/jest-circus/src/shuffleArray.ts @@ -6,7 +6,6 @@ */ import {unsafeUniformIntDistribution, xoroshiro128plus} from 'pure-rand'; -import {invariant} from './invariant'; // Generates [from, to] inclusive export type RandomNumberGenerator = { @@ -17,10 +16,12 @@ export const rngBuilder: (seed: number) => RandomNumberGenerator = ( seed: number, ) => { const upperBoundSeedValue = 2 ** 31; - invariant( - seed > -upperBoundSeedValue || seed < upperBoundSeedValue - 1, - `seed value must be between \`-0x80000000\` and \`0x7fffffff\` inclusive instead it is ${seed}`, - ); + if (seed < -upperBoundSeedValue || seed > upperBoundSeedValue - 1) { + throw new Error( + `seed value must be between \`-0x80000000\` and \`0x7fffffff\` inclusive instead it is ${seed}`, + ); + } + const gen = xoroshiro128plus(seed); return {next: (from, to) => unsafeUniformIntDistribution(from, to, gen)}; }; diff --git a/packages/jest-util/package.json b/packages/jest-util/package.json index 1e1e31c4f1ea..6427674e32cb 100644 --- a/packages/jest-util/package.json +++ b/packages/jest-util/package.json @@ -22,8 +22,7 @@ "chalk": "^4.0.0", "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3", - "pure-rand": "^5.0.3" + "picomatch": "^2.2.3" }, "devDependencies": { "@types/graceful-fs": "^4.1.3", diff --git a/packages/jest-util/src/index.ts b/packages/jest-util/src/index.ts index 8a5ab2b591a6..da313207feb8 100644 --- a/packages/jest-util/src/index.ts +++ b/packages/jest-util/src/index.ts @@ -28,6 +28,3 @@ export {default as pluralize} from './pluralize'; export {default as formatTime} from './formatTime'; export {default as tryRealpath} from './tryRealpath'; export {default as requireOrImportModule} from './requireOrImportModule'; -export {default as shuffleArray, rngBuilder} from './shuffleArray'; - -export type {RandomNumberGenerator} from './shuffleArray'; diff --git a/packages/jest-util/src/invariant.ts b/packages/jest-util/src/invariant.ts deleted file mode 100644 index eee61ed9d0c3..000000000000 --- a/packages/jest-util/src/invariant.ts +++ /dev/null @@ -1,8 +0,0 @@ -export function invariant( - condition: unknown, - message?: string, -): asserts condition { - if (!condition) { - throw new Error(message); - } -} diff --git a/yarn.lock b/yarn.lock index 333aaf428ea1..7bf20ca4ea45 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12222,6 +12222,7 @@ __metadata: jest-util: "workspace:^" p-limit: ^3.1.0 pretty-format: "workspace:^" + pure-rand: ^5.0.3 slash: ^3.0.0 stack-utils: ^2.0.3 languageName: unknown @@ -12819,7 +12820,6 @@ __metadata: ci-info: ^3.2.0 graceful-fs: ^4.2.9 picomatch: ^2.2.3 - pure-rand: ^5.0.3 languageName: unknown linkType: soft From 2bffe528218127e536da2aaab5e5f0a9eb30695e Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 22 Oct 2022 11:07:29 +0200 Subject: [PATCH 57/70] prettier --- docs/CLI.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index c8db3353f881..1fde67055416 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -320,8 +320,7 @@ If configuration files are found in the specified paths, _all_ projects specifie ### `--randomize` -Shuffle the order of the tests within a file. The shuffling is based on the seed. See [`--seed=`](#--seednum) for more info. -Seed value is displayed when this option is set equivalent to setting the CLI option [`--showSeed`](#--showseed). +Shuffle the order of the tests within a file. The shuffling is based on the seed. See [`--seed=`](#--seednum) for more info. Seed value is displayed when this option is set equivalent to setting the CLI option [`--showSeed`](#--showseed). ```bash jest --randomize --seed 1234 From f5b919cbcf9bb6c4f3fd203d0ab60bc81afcdb44 Mon Sep 17 00:00:00 2001 From: josh <41476440+Joshua-Hwang@users.noreply.github.com> Date: Sat, 22 Oct 2022 19:15:08 +1000 Subject: [PATCH 58/70] improved randomize docs --- docs/CLI.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CLI.md b/docs/CLI.md index 1fde67055416..947a9d0b4f8f 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -320,7 +320,9 @@ If configuration files are found in the specified paths, _all_ projects specifie ### `--randomize` -Shuffle the order of the tests within a file. The shuffling is based on the seed. See [`--seed=`](#--seednum) for more info. Seed value is displayed when this option is set equivalent to setting the CLI option [`--showSeed`](#--showseed). +Shuffle the order of the tests within a file. The shuffling is based on the seed. See [`--seed=`](#--seednum) for more info. + +Seed value is displayed when this option is set. Equivalent to setting the CLI option [`--showSeed`](#--showseed). ```bash jest --randomize --seed 1234 From 5946e84e809dd8b0cfa7db82111a2c01c46d117a Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Tue, 8 Nov 2022 13:25:11 +1100 Subject: [PATCH 59/70] lint fix --- docs/Webpack.md | 75 ++++++++-------- .../versioned_docs/version-25.x/Webpack.md | 90 +++++++++---------- .../versioned_docs/version-26.x/Webpack.md | 90 +++++++++---------- 3 files changed, 129 insertions(+), 126 deletions(-) diff --git a/docs/Webpack.md b/docs/Webpack.md index fcf7b36672c4..84b8944b7c4f 100644 --- a/docs/Webpack.md +++ b/docs/Webpack.md @@ -56,11 +56,12 @@ Next, let's configure Jest to gracefully handle asset files such as stylesheets ```js title="jest.config.js" module.exports = { - 'moduleNameMapper': { - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/__mocks__/fileMock.js', - '\\.(css|less)$': '/__mocks__/styleMock.js' - } -} + moduleNameMapper: { + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/__mocks__/fileMock.js', + '\\.(css|less)$': '/__mocks__/styleMock.js', + }, +}; ``` And the mock files themselves: @@ -85,11 +86,12 @@ Then all your className lookups on the styles object will be returned as-is (e.g ```js title="jest.config.js (for CSS Modules)" module.exports = { - 'moduleNameMapper': { - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/__mocks__/fileMock.js', - '\\.(css|less)$': 'identity-obj-proxy' - } -} + moduleNameMapper: { + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/__mocks__/fileMock.js', + '\\.(css|less)$': 'identity-obj-proxy', + }, +}; ``` If `moduleNameMapper` cannot fulfill your requirements, you can use Jest's [`transform`](Configuration.md#transform-objectstring-pathtotransformer--pathtotransformer-object) config option to specify how assets are transformed. For example, a transformer that returns the basename of a file (such that `require('logo.jpg');` returns `'logo'`) can be written as: @@ -108,13 +110,14 @@ module.exports = { ```js title="jest.config.js (for custom transformers and CSS Modules)" module.exports = { - 'moduleNameMapper': { - '\\.(css|less)$': 'identity-obj-proxy' + moduleNameMapper: { + '\\.(css|less)$': 'identity-obj-proxy', }, - 'transform': { - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/fileTransformer.js' - } -} + transform: { + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/fileTransformer.js', + }, +}; ``` We've told Jest to ignore files matching a stylesheet or image extension, and instead, require our mock files. You can adjust the regular expression to match the file types your webpack config handles. @@ -138,14 +141,14 @@ Now that Jest knows how to process our files, we need to tell it how to _find_ t ```js title="jest.config.js" module.exports = { - 'moduleFileExtensions': ['js', 'jsx'], - 'moduleDirectories': ['node_modules', 'bower_components', 'shared'], + moduleFileExtensions: ['js', 'jsx'], + moduleDirectories: ['node_modules', 'bower_components', 'shared'], - 'moduleNameMapper': { + moduleNameMapper: { '\\.(css|less)$': '/__mocks__/styleMock.js', - '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js' - } -} + '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js', + }, +}; ``` :::note @@ -158,32 +161,32 @@ Similarly, Jest's counterpart for Webpack's `resolve.roots` (an alternative to s ```js title="jest.config.js" module.exports = { - 'modulePaths': ['/shared/vendor/modules'], - 'moduleFileExtensions': ['js', 'jsx'], - 'moduleDirectories': ['node_modules', 'bower_components', 'shared'], - 'moduleNameMapper': { + modulePaths: ['/shared/vendor/modules'], + moduleFileExtensions: ['js', 'jsx'], + moduleDirectories: ['node_modules', 'bower_components', 'shared'], + moduleNameMapper: { '\\.(css|less)$': '/__mocks__/styleMock.js', - '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js' - } -} + '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js', + }, +}; ``` And finally, we have to handle the webpack `alias`. For that, we can make use of the `moduleNameMapper` option again. ```js title="jest.config.js" module.exports = { - 'modulePaths': ['/shared/vendor/modules'], - 'moduleFileExtensions': ['js', 'jsx'], - 'moduleDirectories': ['node_modules', 'bower_components', 'shared'], + modulePaths: ['/shared/vendor/modules'], + moduleFileExtensions: ['js', 'jsx'], + moduleDirectories: ['node_modules', 'bower_components', 'shared'], - 'moduleNameMapper': { + moduleNameMapper: { '\\.(css|less)$': '/__mocks__/styleMock.js', '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js', '^react(.*)$': '/vendor/react-master$1', - '^config$': '/configs/app-config.js' - } -} + '^config$': '/configs/app-config.js', + }, +}; ``` That's it! webpack is a complex and flexible tool, so you may have to make some adjustments to handle your specific application's needs. Luckily for most projects, Jest should be more than flexible enough to handle your webpack config. diff --git a/website/versioned_docs/version-25.x/Webpack.md b/website/versioned_docs/version-25.x/Webpack.md index 04b987003ce9..95a7e0676a32 100644 --- a/website/versioned_docs/version-25.x/Webpack.md +++ b/website/versioned_docs/version-25.x/Webpack.md @@ -16,24 +16,21 @@ module.exports = { { test: /\.jsx?$/, exclude: ['node_modules'], - use: ['babel-loader'] + use: ['babel-loader'], }, { test: /\.css$/, - use: [ - 'style-loader', - 'css-loader' - ] + use: ['style-loader', 'css-loader'], }, { test: /\.gif$/, - type: 'asset/inline' + type: 'asset/inline', }, { test: /\.(ttf|eot|svg)$/, - type: 'asset/resource' - } - ] + type: 'asset/resource', + }, + ], }, resolve: { alias: { @@ -59,11 +56,12 @@ Next, let's configure Jest to gracefully handle asset files such as stylesheets ```js title="jest.config.js" module.exports = { - 'moduleNameMapper': { - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/__mocks__/fileMock.js', - '\\.(css|less)$': '/__mocks__/styleMock.js' - } -} + moduleNameMapper: { + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/__mocks__/fileMock.js', + '\\.(css|less)$': '/__mocks__/styleMock.js', + }, +}; ``` And the mock files themselves: @@ -88,11 +86,12 @@ Then all your className lookups on the styles object will be returned as-is (e.g ```js title="jest.config.js (for CSS Modules)" module.exports = { - 'moduleNameMapper': { - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/__mocks__/fileMock.js', - '\\.(css|less)$': 'identity-obj-proxy' - } -} + moduleNameMapper: { + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/__mocks__/fileMock.js', + '\\.(css|less)$': 'identity-obj-proxy', + }, +}; ``` If `moduleNameMapper` cannot fulfill your requirements, you can use Jest's [`transform`](Configuration.md#transform-objectstring-pathtotransformer--pathtotransformer-object) config option to specify how assets are transformed. For example, a transformer that returns the basename of a file (such that `require('logo.jpg');` returns `'logo'`) can be written as: @@ -109,13 +108,14 @@ module.exports = { ```js title="jest.config.js (for custom transformers and CSS Modules)" module.exports = { - 'moduleNameMapper': { - '\\.(css|less)$': 'identity-obj-proxy' + moduleNameMapper: { + '\\.(css|less)$': 'identity-obj-proxy', }, - 'transform': { - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/fileTransformer.js' - } -} + transform: { + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/fileTransformer.js', + }, +}; ``` We've told Jest to ignore files matching a stylesheet or image extension, and instead, require our mock files. You can adjust the regular expression to match the file types your webpack config handles. @@ -140,14 +140,14 @@ Now that Jest knows how to process our files, we need to tell it how to _find_ t ```js title="jest.config.js" module.exports = { - 'moduleFileExtensions': ['js', 'jsx'], - 'moduleDirectories': ['node_modules', 'bower_components', 'shared'], + moduleFileExtensions: ['js', 'jsx'], + moduleDirectories: ['node_modules', 'bower_components', 'shared'], - 'moduleNameMapper': { + moduleNameMapper: { '\\.(css|less)$': '/__mocks__/styleMock.js', - '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js' - } -} + '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js', + }, +}; ``` :::info @@ -160,32 +160,32 @@ Similarly, webpack's `resolve.root` option functions like setting the `NODE_PATH ```js title="jest.config.js" module.exports = { - 'modulePaths': ['/shared/vendor/modules'], - 'moduleFileExtensions': ['js', 'jsx'], - 'moduleDirectories': ['node_modules', 'bower_components', 'shared'], - 'moduleNameMapper': { + modulePaths: ['/shared/vendor/modules'], + moduleFileExtensions: ['js', 'jsx'], + moduleDirectories: ['node_modules', 'bower_components', 'shared'], + moduleNameMapper: { '\\.(css|less)$': '/__mocks__/styleMock.js', - '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js' - } -} + '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js', + }, +}; ``` And finally, we have to handle the webpack `alias`. For that, we can make use of the `moduleNameMapper` option again. ```js title="jest.config.js" module.exports = { - 'modulePaths': ['/shared/vendor/modules'], - 'moduleFileExtensions': ['js', 'jsx'], - 'moduleDirectories': ['node_modules', 'bower_components', 'shared'], + modulePaths: ['/shared/vendor/modules'], + moduleFileExtensions: ['js', 'jsx'], + moduleDirectories: ['node_modules', 'bower_components', 'shared'], - 'moduleNameMapper': { + moduleNameMapper: { '\\.(css|less)$': '/__mocks__/styleMock.js', '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js', '^react(.*)$': '/vendor/react-master$1', - '^config$': '/configs/app-config.js' - } -} + '^config$': '/configs/app-config.js', + }, +}; ``` That's it! webpack is a complex and flexible tool, so you may have to make some adjustments to handle your specific application's needs. Luckily for most projects, Jest should be more than flexible enough to handle your webpack config. diff --git a/website/versioned_docs/version-26.x/Webpack.md b/website/versioned_docs/version-26.x/Webpack.md index 04b987003ce9..95a7e0676a32 100644 --- a/website/versioned_docs/version-26.x/Webpack.md +++ b/website/versioned_docs/version-26.x/Webpack.md @@ -16,24 +16,21 @@ module.exports = { { test: /\.jsx?$/, exclude: ['node_modules'], - use: ['babel-loader'] + use: ['babel-loader'], }, { test: /\.css$/, - use: [ - 'style-loader', - 'css-loader' - ] + use: ['style-loader', 'css-loader'], }, { test: /\.gif$/, - type: 'asset/inline' + type: 'asset/inline', }, { test: /\.(ttf|eot|svg)$/, - type: 'asset/resource' - } - ] + type: 'asset/resource', + }, + ], }, resolve: { alias: { @@ -59,11 +56,12 @@ Next, let's configure Jest to gracefully handle asset files such as stylesheets ```js title="jest.config.js" module.exports = { - 'moduleNameMapper': { - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/__mocks__/fileMock.js', - '\\.(css|less)$': '/__mocks__/styleMock.js' - } -} + moduleNameMapper: { + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/__mocks__/fileMock.js', + '\\.(css|less)$': '/__mocks__/styleMock.js', + }, +}; ``` And the mock files themselves: @@ -88,11 +86,12 @@ Then all your className lookups on the styles object will be returned as-is (e.g ```js title="jest.config.js (for CSS Modules)" module.exports = { - 'moduleNameMapper': { - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/__mocks__/fileMock.js', - '\\.(css|less)$': 'identity-obj-proxy' - } -} + moduleNameMapper: { + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/__mocks__/fileMock.js', + '\\.(css|less)$': 'identity-obj-proxy', + }, +}; ``` If `moduleNameMapper` cannot fulfill your requirements, you can use Jest's [`transform`](Configuration.md#transform-objectstring-pathtotransformer--pathtotransformer-object) config option to specify how assets are transformed. For example, a transformer that returns the basename of a file (such that `require('logo.jpg');` returns `'logo'`) can be written as: @@ -109,13 +108,14 @@ module.exports = { ```js title="jest.config.js (for custom transformers and CSS Modules)" module.exports = { - 'moduleNameMapper': { - '\\.(css|less)$': 'identity-obj-proxy' + moduleNameMapper: { + '\\.(css|less)$': 'identity-obj-proxy', }, - 'transform': { - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/fileTransformer.js' - } -} + transform: { + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/fileTransformer.js', + }, +}; ``` We've told Jest to ignore files matching a stylesheet or image extension, and instead, require our mock files. You can adjust the regular expression to match the file types your webpack config handles. @@ -140,14 +140,14 @@ Now that Jest knows how to process our files, we need to tell it how to _find_ t ```js title="jest.config.js" module.exports = { - 'moduleFileExtensions': ['js', 'jsx'], - 'moduleDirectories': ['node_modules', 'bower_components', 'shared'], + moduleFileExtensions: ['js', 'jsx'], + moduleDirectories: ['node_modules', 'bower_components', 'shared'], - 'moduleNameMapper': { + moduleNameMapper: { '\\.(css|less)$': '/__mocks__/styleMock.js', - '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js' - } -} + '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js', + }, +}; ``` :::info @@ -160,32 +160,32 @@ Similarly, webpack's `resolve.root` option functions like setting the `NODE_PATH ```js title="jest.config.js" module.exports = { - 'modulePaths': ['/shared/vendor/modules'], - 'moduleFileExtensions': ['js', 'jsx'], - 'moduleDirectories': ['node_modules', 'bower_components', 'shared'], - 'moduleNameMapper': { + modulePaths: ['/shared/vendor/modules'], + moduleFileExtensions: ['js', 'jsx'], + moduleDirectories: ['node_modules', 'bower_components', 'shared'], + moduleNameMapper: { '\\.(css|less)$': '/__mocks__/styleMock.js', - '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js' - } -} + '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js', + }, +}; ``` And finally, we have to handle the webpack `alias`. For that, we can make use of the `moduleNameMapper` option again. ```js title="jest.config.js" module.exports = { - 'modulePaths': ['/shared/vendor/modules'], - 'moduleFileExtensions': ['js', 'jsx'], - 'moduleDirectories': ['node_modules', 'bower_components', 'shared'], + modulePaths: ['/shared/vendor/modules'], + moduleFileExtensions: ['js', 'jsx'], + moduleDirectories: ['node_modules', 'bower_components', 'shared'], - 'moduleNameMapper': { + moduleNameMapper: { '\\.(css|less)$': '/__mocks__/styleMock.js', '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js', '^react(.*)$': '/vendor/react-master$1', - '^config$': '/configs/app-config.js' - } -} + '^config$': '/configs/app-config.js', + }, +}; ``` That's it! webpack is a complex and flexible tool, so you may have to make some adjustments to handle your specific application's needs. Luckily for most projects, Jest should be more than flexible enough to handle your webpack config. From af913e2c1869b72c4aa489d473ef27f68c146474 Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Fri, 13 Jan 2023 11:34:15 +1100 Subject: [PATCH 60/70] bumped pure-rand package --- packages/jest-circus/package.json | 2 +- yarn.lock | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/jest-circus/package.json b/packages/jest-circus/package.json index f7146b97c1b1..5f26359df6fd 100644 --- a/packages/jest-circus/package.json +++ b/packages/jest-circus/package.json @@ -35,7 +35,7 @@ "jest-util": "workspace:^", "p-limit": "^3.1.0", "pretty-format": "workspace:^", - "pure-rand": "^5.0.3", + "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, diff --git a/yarn.lock b/yarn.lock index 42f6b21c77e7..86f10ac241cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12530,7 +12530,7 @@ __metadata: jest-util: "workspace:^" p-limit: ^3.1.0 pretty-format: "workspace:^" - pure-rand: ^5.0.3 + pure-rand: ^6.0.0 slash: ^3.0.0 stack-utils: ^2.0.3 languageName: unknown @@ -17304,13 +17304,20 @@ __metadata: languageName: node linkType: hard -"pure-rand@npm:^5.0.2, pure-rand@npm:^5.0.3": +"pure-rand@npm:^5.0.2": version: 5.0.5 resolution: "pure-rand@npm:5.0.5" checksum: 824b906f7f66695c15ed9a898ff650e925723515e999de0360b0726ebad924ce41a74cc2ac60409dc6c55f5781008855f32ecd0fe0a1f40fbce293d48bd11dd1 languageName: node linkType: hard +"pure-rand@npm:^6.0.0": + version: 6.0.0 + resolution: "pure-rand@npm:6.0.0" + checksum: ad1378d0a4859482d053a5264b2b485b445ece4bbc56f8959c233ea678b81ac2d613737925d496ded134eff5f29cc5546bf7492b6bce319ee27bebbad8a0c612 + languageName: node + linkType: hard + "q@npm:^1.5.1": version: 1.5.1 resolution: "q@npm:1.5.1" From c4baaaa6f9dae2b57936bb717d2a937ca28abee1 Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Tue, 14 Feb 2023 12:55:15 +1100 Subject: [PATCH 61/70] yarn.lock updated --- yarn.lock | 7 ------- 1 file changed, 7 deletions(-) diff --git a/yarn.lock b/yarn.lock index 9e5b7859ad8f..9212d31704d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17349,13 +17349,6 @@ __metadata: languageName: node linkType: hard -"pure-rand@npm:^6.0.0": - version: 6.0.0 - resolution: "pure-rand@npm:6.0.0" - checksum: ad1378d0a4859482d053a5264b2b485b445ece4bbc56f8959c233ea678b81ac2d613737925d496ded134eff5f29cc5546bf7492b6bce319ee27bebbad8a0c612 - languageName: node - linkType: hard - "q@npm:^1.5.1": version: 1.5.1 resolution: "q@npm:1.5.1" From 87547f3fd963033528885690288aa9576ee1140b Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Tue, 14 Feb 2023 14:07:15 +1100 Subject: [PATCH 62/70] fixed copyright headers --- e2e/__tests__/randomize.test.ts | 2 +- e2e/randomize/__tests__/each.test.js | 2 +- e2e/randomize/__tests__/hooks.test.js | 2 +- e2e/randomize/__tests__/snapshots.test.js | 2 +- e2e/randomize/__tests__/success.test.js | 2 +- packages/jest-circus/src/__tests__/randomizeTest.test.ts | 2 +- packages/jest-circus/src/__tests__/shuffleArray.test.ts | 2 +- packages/jest-circus/src/shuffleArray.ts | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/e2e/__tests__/randomize.test.ts b/e2e/__tests__/randomize.test.ts index b433436bf73a..b0b83fd15c7e 100644 --- a/e2e/__tests__/randomize.test.ts +++ b/e2e/__tests__/randomize.test.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. diff --git a/e2e/randomize/__tests__/each.test.js b/e2e/randomize/__tests__/each.test.js index 4c4408a8e0e0..9a065728417f 100644 --- a/e2e/randomize/__tests__/each.test.js +++ b/e2e/randomize/__tests__/each.test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. diff --git a/e2e/randomize/__tests__/hooks.test.js b/e2e/randomize/__tests__/hooks.test.js index ecd8279c7920..96bc057110d5 100644 --- a/e2e/randomize/__tests__/hooks.test.js +++ b/e2e/randomize/__tests__/hooks.test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. diff --git a/e2e/randomize/__tests__/snapshots.test.js b/e2e/randomize/__tests__/snapshots.test.js index 78f0baa18e39..dbaf12e835aa 100644 --- a/e2e/randomize/__tests__/snapshots.test.js +++ b/e2e/randomize/__tests__/snapshots.test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. diff --git a/e2e/randomize/__tests__/success.test.js b/e2e/randomize/__tests__/success.test.js index b8c7ad786337..184b23cce28a 100644 --- a/e2e/randomize/__tests__/success.test.js +++ b/e2e/randomize/__tests__/success.test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. diff --git a/packages/jest-circus/src/__tests__/randomizeTest.test.ts b/packages/jest-circus/src/__tests__/randomizeTest.test.ts index 1a2cbe6204da..a4035972d6f8 100644 --- a/packages/jest-circus/src/__tests__/randomizeTest.test.ts +++ b/packages/jest-circus/src/__tests__/randomizeTest.test.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. diff --git a/packages/jest-circus/src/__tests__/shuffleArray.test.ts b/packages/jest-circus/src/__tests__/shuffleArray.test.ts index bc92ba8536a4..94c497c4eeef 100644 --- a/packages/jest-circus/src/__tests__/shuffleArray.test.ts +++ b/packages/jest-circus/src/__tests__/shuffleArray.test.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. diff --git a/packages/jest-circus/src/shuffleArray.ts b/packages/jest-circus/src/shuffleArray.ts index e8fd24832426..6c4bff7b0b49 100644 --- a/packages/jest-circus/src/shuffleArray.ts +++ b/packages/jest-circus/src/shuffleArray.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. From 3a0a4f14639708c7b0bda8e6f3a3db63e0865aef Mon Sep 17 00:00:00 2001 From: Josh <81541956+jhwang98@users.noreply.github.com> Date: Thu, 23 Feb 2023 20:23:27 +1100 Subject: [PATCH 63/70] Update packages/jest-config/src/normalize.ts Co-authored-by: Simen Bekkhus --- packages/jest-config/src/normalize.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index 036a82b50401..a5f94d16d95e 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -1045,7 +1045,7 @@ export default async function normalize( ) { throw new ValidationError( 'Validation Error', - `seed value must be between \`-0x80000000\` and \`0x7fffffff\` inclusive instead it is ${newOptions.seed}`, + `seed value must be between \`-0x80000000\` and \`0x7fffffff\` inclusive - instead it is ${newOptions.seed}`, ); } From 43d6f8b36ba0533b4de3d7c10a9695680e1c9f01 Mon Sep 17 00:00:00 2001 From: Josh <81541956+jhwang98@users.noreply.github.com> Date: Thu, 23 Feb 2023 20:27:12 +1100 Subject: [PATCH 64/70] Update packages/jest-core/src/cli/index.ts Co-authored-by: Simen Bekkhus --- packages/jest-core/src/cli/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/jest-core/src/cli/index.ts b/packages/jest-core/src/cli/index.ts index 27b8a5faf072..40c9f4c39c9a 100644 --- a/packages/jest-core/src/cli/index.ts +++ b/packages/jest-core/src/cli/index.ts @@ -291,7 +291,6 @@ const runWithoutWatch = async ( if (!globalConfig.listTests) { preRunMessagePrint(outputStream); } - return runJest({ changedFilesPromise, contexts, From 7bd3fe1684b728aea19c5771be47cdcfed849770 Mon Sep 17 00:00:00 2001 From: Josh <81541956+jhwang98@users.noreply.github.com> Date: Thu, 23 Feb 2023 20:27:34 +1100 Subject: [PATCH 65/70] Update packages/jest-circus/src/shuffleArray.ts Co-authored-by: Simen Bekkhus --- packages/jest-circus/src/shuffleArray.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jest-circus/src/shuffleArray.ts b/packages/jest-circus/src/shuffleArray.ts index 6c4bff7b0b49..aad379397875 100644 --- a/packages/jest-circus/src/shuffleArray.ts +++ b/packages/jest-circus/src/shuffleArray.ts @@ -12,9 +12,9 @@ export type RandomNumberGenerator = { next: (from: number, to: number) => number; }; -export const rngBuilder: (seed: number) => RandomNumberGenerator = ( +export const rngBuilder = ( seed: number, -) => { +): RandomNumberGenerator => { const upperBoundSeedValue = 2 ** 31; if (seed < -upperBoundSeedValue || seed > upperBoundSeedValue - 1) { throw new Error( From cff3995ab8d3f28539c025ab21c27fc3f7aa1ad5 Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Thu, 23 Feb 2023 21:14:42 +1100 Subject: [PATCH 66/70] remove bounds check as it's being done at the normalize level --- .../jest-circus/src/__tests__/shuffleArray.test.ts | 9 --------- packages/jest-circus/src/shuffleArray.ts | 14 ++------------ 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/packages/jest-circus/src/__tests__/shuffleArray.test.ts b/packages/jest-circus/src/__tests__/shuffleArray.test.ts index 94c497c4eeef..b16ebb148177 100644 --- a/packages/jest-circus/src/__tests__/shuffleArray.test.ts +++ b/packages/jest-circus/src/__tests__/shuffleArray.test.ts @@ -17,15 +17,6 @@ describe('rngBuilder', () => { .map(() => rng.next(0, 10)); expect(results).toMatchSnapshot(); }); - - test('throwing is seed is too large or too small', () => { - expect(() => rngBuilder(2 ** 33)).toThrow( - 'seed value must be between `-0x80000000` and `0x7fffffff` inclusive instead it is 8589934592', - ); - expect(() => rngBuilder(-(2 ** 33))).toThrow( - 'seed value must be between `-0x80000000` and `0x7fffffff` inclusive instead it is -8589934592', - ); - }); }); describe('shuffleArray', () => { diff --git a/packages/jest-circus/src/shuffleArray.ts b/packages/jest-circus/src/shuffleArray.ts index aad379397875..e2afe6cdaaec 100644 --- a/packages/jest-circus/src/shuffleArray.ts +++ b/packages/jest-circus/src/shuffleArray.ts @@ -12,16 +12,7 @@ export type RandomNumberGenerator = { next: (from: number, to: number) => number; }; -export const rngBuilder = ( - seed: number, -): RandomNumberGenerator => { - const upperBoundSeedValue = 2 ** 31; - if (seed < -upperBoundSeedValue || seed > upperBoundSeedValue - 1) { - throw new Error( - `seed value must be between \`-0x80000000\` and \`0x7fffffff\` inclusive instead it is ${seed}`, - ); - } - +export const rngBuilder = (seed: number): RandomNumberGenerator => { const gen = xoroshiro128plus(seed); return {next: (from, to) => unsafeUniformIntDistribution(from, to, gen)}; }; @@ -32,8 +23,7 @@ export default function shuffleArray( array: Array, random: RandomNumberGenerator, ): Array { - const length = array == null ? 0 : array.length; - + const length = array.length; if (length === 0) { return []; } From 7c8bfc1a45aa7a9df79ba159bac7f93ec33590cc Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Thu, 23 Feb 2023 21:15:01 +1100 Subject: [PATCH 67/70] changed error message slightly --- packages/jest-config/src/__tests__/normalize.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jest-config/src/__tests__/normalize.test.ts b/packages/jest-config/src/__tests__/normalize.test.ts index dd787d9396e6..afbfe417a222 100644 --- a/packages/jest-config/src/__tests__/normalize.test.ts +++ b/packages/jest-config/src/__tests__/normalize.test.ts @@ -2150,14 +2150,14 @@ describe('seed', () => { seed: 2 ** 33, } as Config.Argv), ).rejects.toThrow( - 'seed value must be between `-0x80000000` and `0x7fffffff` inclusive instead it is 8589934592', + 'seed value must be between `-0x80000000` and `0x7fffffff` inclusive - instead it is 8589934592', ); await expect( normalize({rootDir: '/root/'}, { seed: -(2 ** 33), } as Config.Argv), ).rejects.toThrow( - 'seed value must be between `-0x80000000` and `0x7fffffff` inclusive instead it is -8589934592', + 'seed value must be between `-0x80000000` and `0x7fffffff` inclusive - instead it is -8589934592', ); }); }); From c3c65160f60f7fb344042cda3a3433cf7ee15beb Mon Sep 17 00:00:00 2001 From: Joshua Hwang Date: Thu, 23 Feb 2023 21:16:30 +1100 Subject: [PATCH 68/70] swapped order for generating rng --- packages/jest-circus/src/run.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index de0ddfb19b6c..53b7168afac8 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -21,8 +21,8 @@ import { const run = async (): Promise => { const {rootDescribeBlock, seed, randomize} = getState(); - await dispatch({name: 'run_start'}); const rng = randomize ? rngBuilder(seed) : undefined; + await dispatch({name: 'run_start'}); await _runTestsForDescribeBlock(rootDescribeBlock, rng, true); await dispatch({name: 'run_finish'}); From d57bf1cb94126d6f389fe33b50cb4279924f35a7 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Thu, 23 Feb 2023 12:19:59 +0100 Subject: [PATCH 69/70] Update packages/jest-circus/src/run.ts --- packages/jest-circus/src/run.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index 53b7168afac8..a13ea309ad47 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -23,7 +23,6 @@ const run = async (): Promise => { const {rootDescribeBlock, seed, randomize} = getState(); const rng = randomize ? rngBuilder(seed) : undefined; await dispatch({name: 'run_start'}); - await _runTestsForDescribeBlock(rootDescribeBlock, rng, true); await dispatch({name: 'run_finish'}); return makeRunResult( From 1137ce1fe810b515d6deba8672c2ac99f9cbe91c Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Thu, 23 Feb 2023 12:21:07 +0100 Subject: [PATCH 70/70] Update packages/jest-circus/src/run.ts --- packages/jest-circus/src/run.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index a13ea309ad47..7ccaf2d2e187 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -33,7 +33,7 @@ const run = async (): Promise => { const _runTestsForDescribeBlock = async ( describeBlock: Circus.DescribeBlock, - rng?: RandomNumberGenerator, + rng: RandomNumberGenerator | undefined, isRootBlock = false, ) => { await dispatch({describeBlock, name: 'run_describe_start'});