feat(react): make vitest the default test runner since it supports ESM and different moduleResolution better (#28153)
This PR updates the default test runner for React/Web apps to be `vitest`. It aligned better with our emphasis on modern tooling, and the lack of ESM and proper TS support (using `module` other than `commonjs`) in Jest makes it hard to use in some workspaces. <!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
ac53df6c67
commit
85877e3e18
@ -70,8 +70,9 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "vitest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"description": "Test runner to use for unit tests."
|
"description": "Test runner to use for unit tests.",
|
||||||
|
"default": "vitest"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -105,9 +105,9 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "vitest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "vitest"
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -80,7 +80,8 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "vitest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
|
"default": "vitest",
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"x-prompt": "What unit test runner should be used?"
|
"x-prompt": "What unit test runner should be used?"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -49,7 +49,7 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "vitest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"description": "Test Runner to use for Unit Tests",
|
"description": "Test Runner to use for Unit Tests",
|
||||||
"x-prompt": "What test runner should be used?",
|
"x-prompt": "What test runner should be used?",
|
||||||
"default": "vitest"
|
"default": "vitest"
|
||||||
|
|||||||
@ -55,6 +55,12 @@
|
|||||||
"runtimeTsconfigFileName": {
|
"runtimeTsconfigFileName": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The name of the project's tsconfig file that includes the runtime source files. If not provided, it will default to `tsconfig.lib.json` for libraries and `tsconfig.app.json` for applications."
|
"description": "The name of the project's tsconfig file that includes the runtime source files. If not provided, it will default to `tsconfig.lib.json` for libraries and `tsconfig.app.json` for applications."
|
||||||
|
},
|
||||||
|
"compiler": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["babel", "swc"],
|
||||||
|
"default": "babel",
|
||||||
|
"description": "The compiler to use"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["project"],
|
"required": ["project"],
|
||||||
|
|||||||
@ -74,7 +74,8 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "vitest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
|
"default": "vitest",
|
||||||
"description": "Test runner to use for unit tests. Default value is 'jest' when using 'webpack' or 'none' as the bundler and 'vitest' when using 'vite' as the bundler"
|
"description": "Test runner to use for unit tests. Default value is 'jest' when using 'webpack' or 'none' as the bundler and 'vitest' when using 'vite' as the bundler"
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
|
|||||||
@ -685,7 +685,9 @@ describe('Linter', () => {
|
|||||||
const myapp = uniq('myapp');
|
const myapp = uniq('myapp');
|
||||||
const mylib = uniq('mylib');
|
const mylib = uniq('mylib');
|
||||||
|
|
||||||
runCLI(`generate @nx/react:app ${myapp} --rootProject=true`);
|
runCLI(
|
||||||
|
`generate @nx/react:app ${myapp} --unitTestRunner=jest --rootProject=true`
|
||||||
|
);
|
||||||
verifySuccessfulStandaloneSetup(myapp);
|
verifySuccessfulStandaloneSetup(myapp);
|
||||||
|
|
||||||
let appEslint = readJson('.eslintrc.json');
|
let appEslint = readJson('.eslintrc.json');
|
||||||
|
|||||||
@ -331,8 +331,6 @@ describe('Nx Running Tests', () => {
|
|||||||
.filter((r) => r);
|
.filter((r) => r);
|
||||||
withBail = withBail.slice(withBail.indexOf('Failed tasks:'));
|
withBail = withBail.slice(withBail.indexOf('Failed tasks:'));
|
||||||
|
|
||||||
expect(withBail).toHaveLength(2);
|
|
||||||
|
|
||||||
if (withBail[1] === `- ${myapp1}:error`) {
|
if (withBail[1] === `- ${myapp1}:error`) {
|
||||||
expect(withBail).not.toContain(`- ${myapp2}:error`);
|
expect(withBail).not.toContain(`- ${myapp2}:error`);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -107,7 +107,7 @@ describe('React Applications', () => {
|
|||||||
const redSvg = `<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" viewBox="0 0 30 30"><rect x="10" y="10" width="10" height="10" fill="red"/></svg>`;
|
const redSvg = `<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" viewBox="0 0 30 30"><rect x="10" y="10" width="10" height="10" fill="red"/></svg>`;
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app ${appName} --directory=apps/${appName} --style=css --bundler=webpack --no-interactive --skipFormat`
|
`generate @nx/react:app ${appName} --directory=apps/${appName} --style=css --bundler=webpack --unit-test-runner=jest --no-interactive --skipFormat`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib ${libName} --directory=libs${libName} --style=css --no-interactive --unit-test-runner=jest --skipFormat`
|
`generate @nx/react:lib ${libName} --directory=libs${libName} --style=css --no-interactive --unit-test-runner=jest --skipFormat`
|
||||||
@ -234,7 +234,7 @@ describe('React Applications', () => {
|
|||||||
);
|
);
|
||||||
const appTestResults = await runCLIAsync(`test ${appName}`);
|
const appTestResults = await runCLIAsync(`test ${appName}`);
|
||||||
expect(appTestResults.combinedOutput).toContain(
|
expect(appTestResults.combinedOutput).toContain(
|
||||||
'Test Suites: 2 passed, 2 total'
|
`Successfully ran target test for project ${appName}`
|
||||||
);
|
);
|
||||||
|
|
||||||
lintResults = runCLI(`lint ${libName}`);
|
lintResults = runCLI(`lint ${libName}`);
|
||||||
@ -243,7 +243,7 @@ describe('React Applications', () => {
|
|||||||
);
|
);
|
||||||
const libTestResults = await runCLIAsync(`test ${libName}`);
|
const libTestResults = await runCLIAsync(`test ${libName}`);
|
||||||
expect(libTestResults.combinedOutput).toContain(
|
expect(libTestResults.combinedOutput).toContain(
|
||||||
'Test Suites: 2 passed, 2 total'
|
`Successfully ran target test for project ${libName}`
|
||||||
);
|
);
|
||||||
}, 250_000);
|
}, 250_000);
|
||||||
|
|
||||||
@ -414,7 +414,7 @@ describe('React Applications', () => {
|
|||||||
const plainJsLib = uniq('jslib');
|
const plainJsLib = uniq('jslib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:app ${appName} --directory=apps/${appName} --bundler=webpack --no-interactive --js --skipFormat`
|
`generate @nx/react:app ${appName} --directory=apps/${appName} --bundler=webpack --unit-test-runner=jest --no-interactive --js --skipFormat`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib ${libName} --directory=libs/${libName} --no-interactive --js --unit-test-runner=none --skipFormat`
|
`generate @nx/react:lib ${libName} --directory=libs/${libName} --no-interactive --js --unit-test-runner=none --skipFormat`
|
||||||
|
|||||||
@ -30,7 +30,9 @@ describe('Web Components Applications with bundler set as vite', () => {
|
|||||||
|
|
||||||
const testResults = await runCLIAsync(`test ${appName}`);
|
const testResults = await runCLIAsync(`test ${appName}`);
|
||||||
|
|
||||||
expect(testResults.combinedOutput).toContain(`PASS ${appName}`);
|
expect(testResults.combinedOutput).toContain(
|
||||||
|
`Successfully ran target test for project ${appName}`
|
||||||
|
);
|
||||||
|
|
||||||
const lintE2eResults = runCLI(`lint ${appName}-e2e`);
|
const lintE2eResults = runCLI(`lint ${appName}-e2e`);
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,7 @@ describe('Web Components Applications', () => {
|
|||||||
const testResults = await runCLIAsync(`test ${appName}`);
|
const testResults = await runCLIAsync(`test ${appName}`);
|
||||||
|
|
||||||
expect(testResults.combinedOutput).toContain(
|
expect(testResults.combinedOutput).toContain(
|
||||||
'Test Suites: 1 passed, 1 total'
|
`Successfully ran target test for project ${appName}`
|
||||||
);
|
);
|
||||||
const lintE2eResults = runCLI(`lint ${appName}-e2e`);
|
const lintE2eResults = runCLI(`lint ${appName}-e2e`);
|
||||||
|
|
||||||
|
|||||||
@ -85,6 +85,13 @@ exports[`Webpack Plugin (legacy) ConvertConfigToWebpackPlugin, should convert wi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"test": {
|
||||||
|
"executor": "@nx/vite:test",
|
||||||
|
"outputs": ["{options.reportsDirectory}"],
|
||||||
|
"options": {
|
||||||
|
"reportsDirectory": "../coverage/app3224373"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"executor": "@nx/eslint:lint"
|
"executor": "@nx/eslint:lint"
|
||||||
},
|
},
|
||||||
@ -95,13 +102,6 @@ exports[`Webpack Plugin (legacy) ConvertConfigToWebpackPlugin, should convert wi
|
|||||||
"buildTarget": "app3224373:build",
|
"buildTarget": "app3224373:build",
|
||||||
"spa": true
|
"spa": true
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"test": {
|
|
||||||
"executor": "@nx/jest:jest",
|
|
||||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
|
||||||
"options": {
|
|
||||||
"jestConfig": "app3224373/jest.config.ts"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -168,6 +168,7 @@ export async function libraryGeneratorInternal(
|
|||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
testEnvironment: options.testEnvironment,
|
testEnvironment: options.testEnvironment,
|
||||||
runtimeTsconfigFileName: 'tsconfig.lib.json',
|
runtimeTsconfigFileName: 'tsconfig.lib.json',
|
||||||
|
compiler: options.compiler === 'swc' ? 'swc' : 'babel',
|
||||||
});
|
});
|
||||||
tasks.push(vitestTask);
|
tasks.push(vitestTask);
|
||||||
createOrEditViteConfig(
|
createOrEditViteConfig(
|
||||||
|
|||||||
@ -73,8 +73,9 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "vitest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"description": "Test runner to use for unit tests."
|
"description": "Test runner to use for unit tests.",
|
||||||
|
"default": "vitest"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -111,9 +111,9 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "vitest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "vitest"
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -158,6 +158,7 @@ export async function libraryGeneratorInternal(host: Tree, schema: Schema) {
|
|||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
testEnvironment: 'jsdom',
|
testEnvironment: 'jsdom',
|
||||||
addPlugin: options.addPlugin,
|
addPlugin: options.addPlugin,
|
||||||
|
compiler: options.compiler,
|
||||||
});
|
});
|
||||||
tasks.push(vitestTask);
|
tasks.push(vitestTask);
|
||||||
createOrEditViteConfig(
|
createOrEditViteConfig(
|
||||||
|
|||||||
@ -83,7 +83,8 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "vitest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
|
"default": "vitest",
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"x-prompt": "What unit test runner should be used?"
|
"x-prompt": "What unit test runner should be used?"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -49,7 +49,7 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "vitest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"description": "Test Runner to use for Unit Tests",
|
"description": "Test Runner to use for Unit Tests",
|
||||||
"x-prompt": "What test runner should be used?",
|
"x-prompt": "What test runner should be used?",
|
||||||
"default": "vitest"
|
"default": "vitest"
|
||||||
|
|||||||
@ -163,6 +163,7 @@ export async function viteConfigurationGeneratorInternal(
|
|||||||
testTarget: 'test',
|
testTarget: 'test',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
addPlugin: schema.addPlugin,
|
addPlugin: schema.addPlugin,
|
||||||
|
compiler: schema.compiler,
|
||||||
});
|
});
|
||||||
tasks.push(vitestTask);
|
tasks.push(vitestTask);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,4 +9,5 @@ export interface VitestGeneratorSchema {
|
|||||||
testEnvironment?: 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime' | string;
|
testEnvironment?: 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime' | string;
|
||||||
addPlugin?: boolean;
|
addPlugin?: boolean;
|
||||||
runtimeTsconfigFileName?: string;
|
runtimeTsconfigFileName?: string;
|
||||||
|
compiler?: 'babel' | 'swc'; // default: babel
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,6 +54,12 @@
|
|||||||
"runtimeTsconfigFileName": {
|
"runtimeTsconfigFileName": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The name of the project's tsconfig file that includes the runtime source files. If not provided, it will default to `tsconfig.lib.json` for libraries and `tsconfig.app.json` for applications."
|
"description": "The name of the project's tsconfig file that includes the runtime source files. If not provided, it will default to `tsconfig.lib.json` for libraries and `tsconfig.app.json` for applications."
|
||||||
|
},
|
||||||
|
"compiler": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["babel", "swc"],
|
||||||
|
"default": "babel",
|
||||||
|
"description": "The compiler to use"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["project"]
|
"required": ["project"]
|
||||||
|
|||||||
@ -46,6 +46,10 @@ export async function vitestGeneratorInternal(
|
|||||||
schema: VitestGeneratorSchema,
|
schema: VitestGeneratorSchema,
|
||||||
hasPlugin = false
|
hasPlugin = false
|
||||||
) {
|
) {
|
||||||
|
// Setting default to jsdom since it is the most common use case (React, Web).
|
||||||
|
// The @nx/js:lib generator specifically sets this to node to be more generic.
|
||||||
|
schema.testEnvironment ??= 'jsdom';
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
const { root, projectType } = readProjectConfiguration(tree, schema.project);
|
const { root, projectType } = readProjectConfiguration(tree, schema.project);
|
||||||
@ -85,7 +89,11 @@ export async function vitestGeneratorInternal(
|
|||||||
"'react-dom'",
|
"'react-dom'",
|
||||||
"'react/jsx-runtime'",
|
"'react/jsx-runtime'",
|
||||||
],
|
],
|
||||||
imports: [`import react from '@vitejs/plugin-react'`],
|
imports: [
|
||||||
|
schema.compiler === 'swc'
|
||||||
|
? `import react from '@vitejs/plugin-react-swc'`
|
||||||
|
: `import react from '@vitejs/plugin-react'`,
|
||||||
|
],
|
||||||
plugins: ['react()'],
|
plugins: ['react()'],
|
||||||
coverageProvider: schema.coverageProvider,
|
coverageProvider: schema.coverageProvider,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -325,6 +325,7 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
|||||||
inSourceTests: options.inSourceTests,
|
inSourceTests: options.inSourceTests,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
addPlugin: options.addPlugin,
|
addPlugin: options.addPlugin,
|
||||||
|
compiler: options.compiler,
|
||||||
});
|
});
|
||||||
tasks.push(vitestTask);
|
tasks.push(vitestTask);
|
||||||
createOrEditViteConfig(
|
createOrEditViteConfig(
|
||||||
|
|||||||
@ -77,7 +77,8 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "vitest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
|
"default": "vitest",
|
||||||
"description": "Test runner to use for unit tests. Default value is 'jest' when using 'webpack' or 'none' as the bundler and 'vitest' when using 'vite' as the bundler"
|
"description": "Test runner to use for unit tests. Default value is 'jest' when using 'webpack' or 'none' as the bundler and 'vitest' when using 'vite' as the bundler"
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user