From bad24ae0f00a5ac2fef55e2f40c2d01f4f79747d Mon Sep 17 00:00:00 2001 From: Nicolas DUBIEN Date: Wed, 19 Oct 2022 21:24:03 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8(jest)=20Take=20seed=20coming=20fr?= =?UTF-8?q?om=20Jest=20whenever=20provided?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #3287 --- packages/jest/src/jest-fast-check.ts | 11 ++++- packages/jest/test/jest-fast-check.spec.ts | 55 ++++++++++++++++++---- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/packages/jest/src/jest-fast-check.ts b/packages/jest/src/jest-fast-check.ts index ae0f1595a7c..05bc25e226d 100644 --- a/packages/jest/src/jest-fast-check.ts +++ b/packages/jest/src/jest-fast-check.ts @@ -1,4 +1,4 @@ -import { it, test } from '@jest/globals'; +import { it, test, jest } from '@jest/globals'; import * as fc from 'fast-check'; type It = typeof it; @@ -29,7 +29,14 @@ function internalTestPropExecute( if (seedFromGlobals !== undefined) { customParams.seed = seedFromGlobals; } else { - customParams.seed = Date.now() ^ (Math.random() * 0x100000000); + // This option is only available since v29.2.0 of Jest + // See official release note: https://github.com/facebook/jest/releases/tag/v29.2.0 + const seedFromJest = typeof jest.getSeed === 'function' ? jest.getSeed() : undefined; + if (seedFromJest) { + customParams.seed = seedFromJest; + } else { + customParams.seed = Date.now() ^ (Math.random() * 0x100000000); + } } } diff --git a/packages/jest/test/jest-fast-check.spec.ts b/packages/jest/test/jest-fast-check.spec.ts index bd640c139fc..a838062c11f 100644 --- a/packages/jest/test/jest-fast-check.spec.ts +++ b/packages/jest/test/jest-fast-check.spec.ts @@ -105,7 +105,7 @@ describe.each<{ runner: RunnerType }>([{ runner: 'testProp' }, { runner: 'itProp // Assert expectFail(out, specFileName); - expectAlignedSeeds(out); + expectAlignedSeeds(out, { noAlignWithJest: true }); expect(out).toMatch(/[×✕] property fail with locally requested seed \(with seed=4242\)/); }); @@ -121,10 +121,25 @@ describe.each<{ runner: RunnerType }>([{ runner: 'testProp' }, { runner: 'itProp // Assert expectFail(out, specFileName); - expectAlignedSeeds(out); + expectAlignedSeeds(out, { noAlignWithJest: true }); expect(out).toMatch(/[×✕] property fail with globally requested seed \(with seed=4848\)/); }); + it.concurrent('should fail with seed requested at jest level', async () => { + // Arrange + const { specFileName, jestConfigRelativePath } = await writeToFile(runner, () => { + runnerProp('property fail with globally requested seed', [fc.constant(null)], (_unused) => false); + }); + + // Act + const out = await runSpec(jestConfigRelativePath, { jestSeed: 6969 }); + + // Assert + expectFail(out, specFileName); + expectAlignedSeeds(out); + expect(out).toMatch(/[×✕] property fail with globally requested seed \(with seed=6969\)/); + }); + describe('.skip', () => { it.concurrent('should never be executed', async () => { // Arrange @@ -271,11 +286,17 @@ async function writeToFile( return { specFileName, jestConfigRelativePath }; } -async function runSpec(jestConfigRelativePath: string): Promise { +async function runSpec(jestConfigRelativePath: string, opts: { jestSeed?: number } = {}): Promise { const { stdout: jestBinaryPathCommand } = await execFile('yarn', ['bin', 'jest'], { shell: true }); const jestBinaryPath = jestBinaryPathCommand.split('\n')[0]; try { - const { stderr: specOutput } = await execFile('node', [jestBinaryPath, '--config', jestConfigRelativePath]); + const { stderr: specOutput } = await execFile('node', [ + jestBinaryPath, + '--config', + jestConfigRelativePath, + '--show-seed', + ...(opts.jestSeed !== undefined ? ['--seed', String(opts.jestSeed)] : []), + ]); return specOutput; } catch (err) { return (err as any).stderr; @@ -290,8 +311,26 @@ function expectFail(out: string, specFileName: string): void { expect(out).toMatch(new RegExp('FAIL .*/' + specFileName)); } -function expectAlignedSeeds(out: string): void { - expect(out).toMatch(/[×✕] .* \(with seed=-?\d+\)/); - const receivedSeed = out.split('seed=')[1].split(')')[0]; - expect(out).toMatch(new RegExp('seed\\s*:\\s*' + receivedSeed + '[^\\d]')); +function expectAlignedSeeds(out: string, opts: { noAlignWithJest?: boolean } = {}): void { + // Seed printed by jest has the shape: + // > Seed: -518086725 + // > Test Suites: 1 failed, 1 total + // > Tests: 1 failed, 1 total + // > Snapshots: 0 total + // > Time: 0.952 s + // > Ran all test suites + const JestSeedMatcher = /Seed:\s+(-?\d+)/; + expect(out).toMatch(JestSeedMatcher); + const jestSeed = JestSeedMatcher.exec(out)![1]; + // Seed printed by jest-fast-check next to test name has the shape: + // > × property fail on falsy property (with seed=-518086725) + const JestFastCheckSeedMatcher = opts.noAlignWithJest + ? /[×✕] .* \(with seed=(-?\d+)\)/ + : new RegExp('[×✕] .* \\(with seed=(' + jestSeed + ')\\)'); + expect(out).toMatch(JestFastCheckSeedMatcher); + const jestFastCheckSeed = JestFastCheckSeedMatcher.exec(out)![1]; + // Seed printed by fast-check in case of failure has the shape: + // > Property failed after 1 tests + // > { seed: -518086725, path: \"0\", endOnFailure: true } + expect(out).toMatch(new RegExp('\\{[^}]*seed\\s*:\\s*' + jestFastCheckSeed + '[^\\d]')); } From ff717826d26195cb5d2d372abe6642b7d982c06d Mon Sep 17 00:00:00 2001 From: Nicolas DUBIEN Date: Wed, 19 Oct 2022 21:25:06 +0200 Subject: [PATCH 2/3] versions --- .yarn/versions/ce9dc069.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .yarn/versions/ce9dc069.yml diff --git a/.yarn/versions/ce9dc069.yml b/.yarn/versions/ce9dc069.yml new file mode 100644 index 00000000000..24da0f62700 --- /dev/null +++ b/.yarn/versions/ce9dc069.yml @@ -0,0 +1,2 @@ +releases: + "@fast-check/jest": minor From 041f675810f38e6b9e7ccc73896682217f6db96d Mon Sep 17 00:00:00 2001 From: Nicolas DUBIEN Date: Wed, 19 Oct 2022 21:37:48 +0200 Subject: [PATCH 3/3] Update packages/jest/src/jest-fast-check.ts --- packages/jest/src/jest-fast-check.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest/src/jest-fast-check.ts b/packages/jest/src/jest-fast-check.ts index 05bc25e226d..0f1d5f80807 100644 --- a/packages/jest/src/jest-fast-check.ts +++ b/packages/jest/src/jest-fast-check.ts @@ -32,7 +32,7 @@ function internalTestPropExecute( // This option is only available since v29.2.0 of Jest // See official release note: https://github.com/facebook/jest/releases/tag/v29.2.0 const seedFromJest = typeof jest.getSeed === 'function' ? jest.getSeed() : undefined; - if (seedFromJest) { + if (seedFromJest !== undefined) { customParams.seed = seedFromJest; } else { customParams.seed = Date.now() ^ (Math.random() * 0x100000000);