feat(testing): add vitest generators (#13301)
This commit is contained in:
parent
17514d2366
commit
02e22de7ed
@ -162,10 +162,15 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "vitest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "jest"
|
||||||
},
|
},
|
||||||
|
"inSourceTests": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "When using Vitest, separate spec files will not be generated and instead will be included within the source files. Read more on the Vitest docs site: https://vitest.dev/guide/in-source.html"
|
||||||
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["cypress", "none"],
|
"enum": ["cypress", "none"],
|
||||||
@ -332,10 +337,15 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "vitest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "jest"
|
||||||
},
|
},
|
||||||
|
"inSourceTests": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "When using Vitest, separate spec files will not be generated and instead will be included within the source files."
|
||||||
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Add tags to the library (used for linting).",
|
"description": "Add tags to the library (used for linting).",
|
||||||
|
|||||||
@ -81,6 +81,48 @@
|
|||||||
"hidden": false,
|
"hidden": false,
|
||||||
"implementation": "/packages/vite/src/generators/configuration/configuration.ts",
|
"implementation": "/packages/vite/src/generators/configuration/configuration.ts",
|
||||||
"path": "/packages/vite/src/generators/configuration/schema.json"
|
"path": "/packages/vite/src/generators/configuration/schema.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vitest",
|
||||||
|
"factory": "./src/generators/vitest/vitest-generator",
|
||||||
|
"schema": {
|
||||||
|
"$schema": "http://json-schema.org/schema",
|
||||||
|
"cli": "nx",
|
||||||
|
"$id": "Vitest",
|
||||||
|
"title": "",
|
||||||
|
"type": "object",
|
||||||
|
"description": "Generate a vitest setup for a project.",
|
||||||
|
"properties": {
|
||||||
|
"project": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the project to test.",
|
||||||
|
"$default": { "$source": "projectName" }
|
||||||
|
},
|
||||||
|
"uiFramework": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["react", "none"],
|
||||||
|
"default": "none",
|
||||||
|
"description": "UI framework to use with vitest"
|
||||||
|
},
|
||||||
|
"inSourceTests": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Do not generate separate spec files and set up in-source testing"
|
||||||
|
},
|
||||||
|
"skipViteConfig": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Skip generating a vite config file"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["project"],
|
||||||
|
"presets": []
|
||||||
|
},
|
||||||
|
"description": "Generate a vitest configuration",
|
||||||
|
"implementation": "/packages/vite/src/generators/vitest/vitest-generator.ts",
|
||||||
|
"aliases": [],
|
||||||
|
"hidden": false,
|
||||||
|
"path": "/packages/vite/src/generators/vitest/schema.json"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"executors": [
|
"executors": [
|
||||||
|
|||||||
@ -136,10 +136,15 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "vitest", "none"],
|
||||||
"description": "Test runner to use for unit tests",
|
"description": "Test runner to use for unit tests",
|
||||||
"default": "jest"
|
"default": "jest"
|
||||||
},
|
},
|
||||||
|
"inSourceTests": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "When using Vitest, separate spec files will not be generated and instead will be included within the source files."
|
||||||
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["cypress", "none"],
|
"enum": ["cypress", "none"],
|
||||||
|
|||||||
@ -372,7 +372,7 @@
|
|||||||
"path": "generated/packages/vite.json",
|
"path": "generated/packages/vite.json",
|
||||||
"schemas": {
|
"schemas": {
|
||||||
"executors": ["dev-server", "build", "test"],
|
"executors": ["dev-server", "build", "test"],
|
||||||
"generators": ["init", "configuration"]
|
"generators": ["init", "configuration", "vitest"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
cleanupProject,
|
cleanupProject,
|
||||||
createFile,
|
createFile,
|
||||||
|
exists,
|
||||||
killPorts,
|
killPorts,
|
||||||
listFiles,
|
listFiles,
|
||||||
newProject,
|
newProject,
|
||||||
@ -10,6 +11,7 @@ import {
|
|||||||
runCLI,
|
runCLI,
|
||||||
runCLIAsync,
|
runCLIAsync,
|
||||||
runCommandUntil,
|
runCommandUntil,
|
||||||
|
tmpProjPath,
|
||||||
uniq,
|
uniq,
|
||||||
updateFile,
|
updateFile,
|
||||||
updateProjectConfig,
|
updateProjectConfig,
|
||||||
@ -391,4 +393,45 @@ describe('Vite Plugin', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('should be able to create libs that use vitest', () => {
|
||||||
|
const lib = uniq('my-lib');
|
||||||
|
beforeEach(() => {
|
||||||
|
proj = newProject();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to run tests', async () => {
|
||||||
|
runCLI(`generate @nrwl/react:lib ${lib} --unitTestRunner=vitest`);
|
||||||
|
expect(exists(tmpProjPath(`libs/${lib}/vite.config.ts`))).toBeTruthy();
|
||||||
|
|
||||||
|
const result = await runCLIAsync(`test ${lib}`);
|
||||||
|
expect(result.combinedOutput).toContain(
|
||||||
|
`Successfully ran target test for project ${lib}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to run tests with inSourceTests set to true', async () => {
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/react:lib ${lib} --unitTestRunner=vitest --inSourceTests`
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
exists(tmpProjPath(`libs/${lib}/src/lib/${lib}.spec.tsx`))
|
||||||
|
).toBeFalsy();
|
||||||
|
|
||||||
|
updateFile(`libs/${lib}/src/lib/${lib}.tsx`, (content) => {
|
||||||
|
content += `
|
||||||
|
if (import.meta.vitest) {
|
||||||
|
const { expect, it } = import.meta.vitest;
|
||||||
|
it('should be successful', () => {
|
||||||
|
expect(1 + 1).toBe(2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
return content;
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await runCLIAsync(`test ${lib}`);
|
||||||
|
expect(result.combinedOutput).toContain(`1 passed`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -29,9 +29,7 @@ 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(
|
expect(testResults.combinedOutput).toContain('Tests 2 passed (2)');
|
||||||
'Test Suites: 1 passed, 1 total'
|
|
||||||
);
|
|
||||||
|
|
||||||
const lintE2eResults = runCLI(`lint ${appName}-e2e`);
|
const lintE2eResults = runCLI(`lint ${appName}-e2e`);
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import {
|
|||||||
} from '../../utils/lint';
|
} from '../../utils/lint';
|
||||||
import { NormalizedSchema, Schema } from './schema';
|
import { NormalizedSchema, Schema } from './schema';
|
||||||
import { createApplicationFiles } from './lib/create-application-files';
|
import { createApplicationFiles } from './lib/create-application-files';
|
||||||
import { updateJestConfig } from './lib/update-jest-config';
|
import { updateSpecConfig } from './lib/update-jest-config';
|
||||||
import { normalizeOptions } from './lib/normalize-options';
|
import { normalizeOptions } from './lib/normalize-options';
|
||||||
import { addProject } from './lib/add-project';
|
import { addProject } from './lib/add-project';
|
||||||
import { addCypress } from './lib/add-cypress';
|
import { addCypress } from './lib/add-cypress';
|
||||||
@ -26,7 +26,7 @@ import reactInitGenerator from '../init/init';
|
|||||||
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
||||||
import { swcCoreVersion } from '@nrwl/js/src/utils/versions';
|
import { swcCoreVersion } from '@nrwl/js/src/utils/versions';
|
||||||
import { swcLoaderVersion } from '@nrwl/webpack/src/utils/versions';
|
import { swcLoaderVersion } from '@nrwl/webpack/src/utils/versions';
|
||||||
import { viteConfigurationGenerator } from '@nrwl/vite';
|
import { viteConfigurationGenerator, vitestGenerator } from '@nrwl/vite';
|
||||||
|
|
||||||
async function addLinting(host: Tree, options: NormalizedSchema) {
|
async function addLinting(host: Tree, options: NormalizedSchema) {
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
@ -89,10 +89,20 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
|
|||||||
uiFramework: 'react',
|
uiFramework: 'react',
|
||||||
project: options.projectName,
|
project: options.projectName,
|
||||||
newProject: true,
|
newProject: true,
|
||||||
|
includeVitest: true,
|
||||||
});
|
});
|
||||||
tasks.push(viteTask);
|
tasks.push(viteTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') {
|
||||||
|
const vitestTask = await vitestGenerator(host, {
|
||||||
|
uiFramework: 'react',
|
||||||
|
project: options.projectName,
|
||||||
|
inSourceTests: options.inSourceTests,
|
||||||
|
});
|
||||||
|
tasks.push(vitestTask);
|
||||||
|
}
|
||||||
|
|
||||||
const lintTask = await addLinting(host, options);
|
const lintTask = await addLinting(host, options);
|
||||||
tasks.push(lintTask);
|
tasks.push(lintTask);
|
||||||
|
|
||||||
@ -100,7 +110,7 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
|
|||||||
tasks.push(cypressTask);
|
tasks.push(cypressTask);
|
||||||
const jestTask = await addJest(host, options);
|
const jestTask = await addJest(host, options);
|
||||||
tasks.push(jestTask);
|
tasks.push(jestTask);
|
||||||
updateJestConfig(host, options);
|
updateSpecConfig(host, options);
|
||||||
const styledTask = addStyledModuleDependencies(host, options.styledModule);
|
const styledTask = addStyledModuleDependencies(host, options.styledModule);
|
||||||
tasks.push(styledTask);
|
tasks.push(styledTask);
|
||||||
const routingTask = addRouting(host, options);
|
const routingTask = addRouting(host, options);
|
||||||
|
|||||||
@ -68,7 +68,10 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
|||||||
templateVariables
|
templateVariables
|
||||||
);
|
);
|
||||||
|
|
||||||
if (options.unitTestRunner === 'none') {
|
if (
|
||||||
|
options.unitTestRunner === 'none' ||
|
||||||
|
(options.unitTestRunner === 'vitest' && options.inSourceTests == true)
|
||||||
|
) {
|
||||||
host.delete(
|
host.delete(
|
||||||
`${options.appProjectRoot}/src/app/${options.fileName}.spec.tsx`
|
`${options.appProjectRoot}/src/app/${options.fileName}.spec.tsx`
|
||||||
);
|
);
|
||||||
@ -80,6 +83,18 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
|||||||
templateVariables
|
templateVariables
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (options.unitTestRunner === 'vitest' && options.inSourceTests == true) {
|
||||||
|
let originalAppContents = host
|
||||||
|
.read(`${options.appProjectRoot}/src/app/${options.fileName}.tsx`)
|
||||||
|
.toString();
|
||||||
|
originalAppContents += `
|
||||||
|
if (import.meta.vitest) {
|
||||||
|
// add tests related to your file here
|
||||||
|
// For more information please visit the Vitest docs site here: https://vitest.dev/guide/in-source.html
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
if (options.js) {
|
if (options.js) {
|
||||||
toJS(host);
|
toJS(host);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,6 +40,10 @@ export function normalizeOptions(
|
|||||||
|
|
||||||
assertValidStyle(options.style);
|
assertValidStyle(options.style);
|
||||||
|
|
||||||
|
if (options.bundler === 'vite') {
|
||||||
|
options.unitTestRunner = 'vitest';
|
||||||
|
}
|
||||||
|
|
||||||
options.routing = options.routing ?? false;
|
options.routing = options.routing ?? false;
|
||||||
options.strict = options.strict ?? true;
|
options.strict = options.strict ?? true;
|
||||||
options.classComponent = options.classComponent ?? false;
|
options.classComponent = options.classComponent ?? false;
|
||||||
|
|||||||
@ -2,8 +2,8 @@ import { updateJestConfigContent } from '../../../utils/jest-utils';
|
|||||||
import { NormalizedSchema } from '../schema';
|
import { NormalizedSchema } from '../schema';
|
||||||
import { offsetFromRoot, Tree, updateJson } from '@nrwl/devkit';
|
import { offsetFromRoot, Tree, updateJson } from '@nrwl/devkit';
|
||||||
|
|
||||||
export function updateJestConfig(host: Tree, options: NormalizedSchema) {
|
export function updateSpecConfig(host: Tree, options: NormalizedSchema) {
|
||||||
if (options.unitTestRunner !== 'jest') {
|
if (options.unitTestRunner === 'none') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,6 +21,10 @@ export function updateJestConfig(host: Tree, options: NormalizedSchema) {
|
|||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (options.unitTestRunner !== 'jest') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const configPath = `${options.appProjectRoot}/jest.config.${
|
const configPath = `${options.appProjectRoot}/jest.config.${
|
||||||
options.js ? 'js' : 'ts'
|
options.js ? 'js' : 'ts'
|
||||||
}`;
|
}`;
|
||||||
|
|||||||
@ -7,7 +7,8 @@ export interface Schema {
|
|||||||
skipFormat: boolean;
|
skipFormat: boolean;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
tags?: string;
|
tags?: string;
|
||||||
unitTestRunner: 'jest' | 'none';
|
unitTestRunner: 'jest' | 'vitest' | 'none';
|
||||||
|
inSourceTests?: boolean;
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -103,10 +103,15 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "vitest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "jest"
|
||||||
},
|
},
|
||||||
|
"inSourceTests": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "When using Vitest, separate spec files will not be generated and instead will be included within the source files. Read more on the Vitest docs site: https://vitest.dev/guide/in-source.html"
|
||||||
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["cypress", "none"],
|
"enum": ["cypress", "none"],
|
||||||
|
|||||||
@ -7,7 +7,7 @@ export interface Schema {
|
|||||||
skipFormat: boolean;
|
skipFormat: boolean;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
tags?: string;
|
tags?: string;
|
||||||
unitTestRunner: 'jest' | 'none';
|
unitTestRunner: 'jest' | 'vitest' | 'none';
|
||||||
e2eTestRunner: 'cypress' | 'none';
|
e2eTestRunner: 'cypress' | 'none';
|
||||||
linter: Linter;
|
linter: Linter;
|
||||||
pascalCaseFiles?: boolean;
|
pascalCaseFiles?: boolean;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export interface InitSchema {
|
export interface InitSchema {
|
||||||
unitTestRunner?: 'jest' | 'none';
|
unitTestRunner?: 'jest' | 'vitest' | 'none';
|
||||||
e2eTestRunner?: 'cypress' | 'none';
|
e2eTestRunner?: 'cypress' | 'none';
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
|
|||||||
@ -47,6 +47,7 @@ import componentGenerator from '../component/component';
|
|||||||
import init from '../init/init';
|
import init from '../init/init';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { updateJestConfigContent } from '../../utils/jest-utils';
|
import { updateJestConfigContent } from '../../utils/jest-utils';
|
||||||
|
import { vitestGenerator } from '@nrwl/vite';
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
name: string;
|
name: string;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
@ -109,6 +110,13 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
|||||||
);
|
);
|
||||||
host.write(jestConfigPath, updatedContent);
|
host.write(jestConfigPath, updatedContent);
|
||||||
}
|
}
|
||||||
|
} else if (options.unitTestRunner === 'vitest') {
|
||||||
|
const vitestTask = await vitestGenerator(host, {
|
||||||
|
uiFramework: 'react',
|
||||||
|
project: options.name,
|
||||||
|
inSourceTests: options.inSourceTests,
|
||||||
|
});
|
||||||
|
tasks.push(vitestTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.component) {
|
if (options.component) {
|
||||||
@ -117,7 +125,9 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
|||||||
project: options.name,
|
project: options.name,
|
||||||
flat: true,
|
flat: true,
|
||||||
style: options.style,
|
style: options.style,
|
||||||
skipTests: options.unitTestRunner === 'none',
|
skipTests:
|
||||||
|
options.unitTestRunner === 'none' ||
|
||||||
|
(options.unitTestRunner === 'vitest' && options.inSourceTests == true),
|
||||||
export: true,
|
export: true,
|
||||||
routing: options.routing,
|
routing: options.routing,
|
||||||
js: options.js,
|
js: options.js,
|
||||||
|
|||||||
@ -11,7 +11,8 @@ export interface Schema {
|
|||||||
pascalCaseFiles?: boolean;
|
pascalCaseFiles?: boolean;
|
||||||
routing?: boolean;
|
routing?: boolean;
|
||||||
appProject?: string;
|
appProject?: string;
|
||||||
unitTestRunner: 'jest' | 'none';
|
unitTestRunner: 'jest' | 'vitest' | 'none';
|
||||||
|
inSourceTests?: boolean;
|
||||||
linter: Linter;
|
linter: Linter;
|
||||||
component?: boolean;
|
component?: boolean;
|
||||||
publishable?: boolean;
|
publishable?: boolean;
|
||||||
|
|||||||
@ -80,10 +80,15 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "vitest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "jest"
|
||||||
},
|
},
|
||||||
|
"inSourceTests": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "When using Vitest, separate spec files will not be generated and instead will be included within the source files."
|
||||||
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Add tags to the library (used for linting).",
|
"description": "Add tags to the library (used for linting).",
|
||||||
|
|||||||
@ -8,7 +8,7 @@ export interface Schema {
|
|||||||
skipFormat: boolean;
|
skipFormat: boolean;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
tags?: string;
|
tags?: string;
|
||||||
unitTestRunner: 'jest' | 'none';
|
unitTestRunner: 'jest' | 'vitest' | 'none';
|
||||||
e2eTestRunner: 'cypress' | 'none';
|
e2eTestRunner: 'cypress' | 'none';
|
||||||
linter: Linter;
|
linter: Linter;
|
||||||
pascalCaseFiles?: boolean;
|
pascalCaseFiles?: boolean;
|
||||||
|
|||||||
@ -15,6 +15,11 @@
|
|||||||
"description": "Add Vite configuration to an application.",
|
"description": "Add Vite configuration to an application.",
|
||||||
"aliases": ["ng-add"],
|
"aliases": ["ng-add"],
|
||||||
"hidden": false
|
"hidden": false
|
||||||
|
},
|
||||||
|
"vitest": {
|
||||||
|
"factory": "./src/generators/vitest/vitest-generator#vitestSchematic",
|
||||||
|
"schema": "./src/generators/vitest/schema.json",
|
||||||
|
"description": "Generate a vitest configuration"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"generators": {
|
"generators": {
|
||||||
@ -31,6 +36,11 @@
|
|||||||
"description": "Add Vite configuration to an application.",
|
"description": "Add Vite configuration to an application.",
|
||||||
"aliases": ["ng-add"],
|
"aliases": ["ng-add"],
|
||||||
"hidden": false
|
"hidden": false
|
||||||
|
},
|
||||||
|
"vitest": {
|
||||||
|
"factory": "./src/generators/vitest/vitest-generator",
|
||||||
|
"schema": "./src/generators/vitest/schema.json",
|
||||||
|
"description": "Generate a vitest configuration"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
export * from './src/utils/versions';
|
export * from './src/utils/versions';
|
||||||
export { viteConfigurationGenerator } from './src/generators/configuration/configuration';
|
export { viteConfigurationGenerator } from './src/generators/configuration/configuration';
|
||||||
|
export { vitestGenerator } from './src/generators/vitest/vitest-generator';
|
||||||
|
|||||||
12
packages/vite/src/executors/test/schema.d.ts
vendored
12
packages/vite/src/executors/test/schema.d.ts
vendored
@ -1,9 +1,9 @@
|
|||||||
export interface VitestExecutorSchema {
|
export interface VitestExecutorOptions {
|
||||||
config: string;
|
config?: string;
|
||||||
passWithNoTests: boolean;
|
passWithNoTests?: boolean;
|
||||||
testNamePattern?: string;
|
testNamePattern?: string;
|
||||||
mode: 'test' | 'benchmark' | 'typecheck';
|
mode?: 'test' | 'benchmark' | 'typecheck';
|
||||||
reporters?: string[];
|
reporters?: string[];
|
||||||
watch: boolean;
|
watch?: boolean;
|
||||||
update: boolean;
|
update?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { ExecutorContext } from '@nrwl/devkit';
|
import { ExecutorContext } from '@nrwl/devkit';
|
||||||
import { File, Reporter } from 'vitest';
|
import { File, Reporter } from 'vitest';
|
||||||
import { VitestExecutorSchema } from './schema';
|
import { VitestExecutorOptions } from './schema';
|
||||||
|
|
||||||
class NxReporter implements Reporter {
|
class NxReporter implements Reporter {
|
||||||
deferred: {
|
deferred: {
|
||||||
@ -38,7 +38,7 @@ class NxReporter implements Reporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function* runExecutor(
|
export default async function* runExecutor(
|
||||||
options: VitestExecutorSchema,
|
options: VitestExecutorOptions,
|
||||||
context: ExecutorContext
|
context: ExecutorContext
|
||||||
) {
|
) {
|
||||||
const { startVitest } = await (Function(
|
const { startVitest } = await (Function(
|
||||||
|
|||||||
@ -91,4 +91,29 @@ describe('@nrwl/vite:configuration', () => {
|
|||||||
expect(tree.exists('apps/my-test-web-app/vite.config.ts')).toBe(true);
|
expect(tree.exists('apps/my-test-web-app/vite.config.ts')).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('vitest', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
tree = createTreeWithEmptyV1Workspace();
|
||||||
|
await mockReactAppGenerator(tree);
|
||||||
|
const existing = 'existing';
|
||||||
|
const existingVersion = '1.0.0';
|
||||||
|
addDependenciesToPackageJson(
|
||||||
|
tree,
|
||||||
|
{ '@nrwl/vite': nxVersion, [existing]: existingVersion },
|
||||||
|
{ [existing]: existingVersion }
|
||||||
|
);
|
||||||
|
await viteConfigurationGenerator(tree, {
|
||||||
|
uiFramework: 'react',
|
||||||
|
project: 'my-test-react-app',
|
||||||
|
includeVitest: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should create a vitest configuration if "includeVitest" is true', () => {
|
||||||
|
const viteConfig = tree
|
||||||
|
.read('apps/my-test-react-app/vite.config.ts')
|
||||||
|
.toString();
|
||||||
|
expect(viteConfig).toContain('test');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import {
|
|||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||||
import {
|
import {
|
||||||
findServeAndBuildTargets,
|
findExistingTargets,
|
||||||
addOrChangeBuildTarget,
|
addOrChangeBuildTarget,
|
||||||
addOrChangeServeTarget,
|
addOrChangeServeTarget,
|
||||||
editTsConfig,
|
editTsConfig,
|
||||||
@ -16,6 +16,7 @@ import {
|
|||||||
} from '../../utils/generator-utils';
|
} from '../../utils/generator-utils';
|
||||||
|
|
||||||
import initGenerator from '../init/init';
|
import initGenerator from '../init/init';
|
||||||
|
import vitestGenerator from '../vitest/vitest-generator';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
|
||||||
export async function viteConfigurationGenerator(tree: Tree, schema: Schema) {
|
export async function viteConfigurationGenerator(tree: Tree, schema: Schema) {
|
||||||
@ -26,8 +27,8 @@ export async function viteConfigurationGenerator(tree: Tree, schema: Schema) {
|
|||||||
let serveTarget = 'serve';
|
let serveTarget = 'serve';
|
||||||
|
|
||||||
if (!schema.newProject) {
|
if (!schema.newProject) {
|
||||||
buildTarget = findServeAndBuildTargets(targets).buildTarget;
|
buildTarget = findExistingTargets(targets).buildTarget;
|
||||||
serveTarget = findServeAndBuildTargets(targets).serveTarget;
|
serveTarget = findExistingTargets(targets).serveTarget;
|
||||||
moveAndEditIndexHtml(tree, schema, buildTarget);
|
moveAndEditIndexHtml(tree, schema, buildTarget);
|
||||||
editTsConfig(tree, schema);
|
editTsConfig(tree, schema);
|
||||||
}
|
}
|
||||||
@ -39,8 +40,19 @@ export async function viteConfigurationGenerator(tree: Tree, schema: Schema) {
|
|||||||
|
|
||||||
addOrChangeBuildTarget(tree, schema, buildTarget);
|
addOrChangeBuildTarget(tree, schema, buildTarget);
|
||||||
addOrChangeServeTarget(tree, schema, serveTarget);
|
addOrChangeServeTarget(tree, schema, serveTarget);
|
||||||
|
|
||||||
writeViteConfig(tree, schema);
|
writeViteConfig(tree, schema);
|
||||||
|
|
||||||
|
if (schema.includeVitest) {
|
||||||
|
const vitestTask = await vitestGenerator(tree, {
|
||||||
|
project: schema.project,
|
||||||
|
uiFramework: schema.uiFramework,
|
||||||
|
inSourceTests: schema.inSourceTests,
|
||||||
|
skipViteConfig: true,
|
||||||
|
});
|
||||||
|
tasks.push(vitestTask);
|
||||||
|
}
|
||||||
|
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
|
|
||||||
return runTasksInSerial(...tasks);
|
return runTasksInSerial(...tasks);
|
||||||
|
|||||||
@ -2,4 +2,6 @@ export interface Schema {
|
|||||||
uiFramework: 'react' | 'none';
|
uiFramework: 'react' | 'none';
|
||||||
project: string;
|
project: string;
|
||||||
newProject?: boolean;
|
newProject?: boolean;
|
||||||
|
includeVitest?: boolean;
|
||||||
|
inSourceTests?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ Object {
|
|||||||
"@vitejs/plugin-react": "^2.2.0",
|
"@vitejs/plugin-react": "^2.2.0",
|
||||||
"@vitest/ui": "^0.9.3",
|
"@vitest/ui": "^0.9.3",
|
||||||
"existing": "1.0.0",
|
"existing": "1.0.0",
|
||||||
|
"jsdom": "~20.0.3",
|
||||||
"vite": "^3.0.5",
|
"vite": "^3.0.5",
|
||||||
"vite-plugin-eslint": "^1.6.0",
|
"vite-plugin-eslint": "^1.6.0",
|
||||||
"vite-tsconfig-paths": "^3.5.2",
|
"vite-tsconfig-paths": "^3.5.2",
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {
|
|||||||
vitestUiVersion,
|
vitestUiVersion,
|
||||||
vitestVersion,
|
vitestVersion,
|
||||||
viteTsConfigPathsVersion,
|
viteTsConfigPathsVersion,
|
||||||
|
jsdomVersion,
|
||||||
} from '../../utils/versions';
|
} from '../../utils/versions';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ function checkDependenciesInstalled(host: Tree, schema: Schema) {
|
|||||||
const devDependencies = {};
|
const devDependencies = {};
|
||||||
const dependencies = {};
|
const dependencies = {};
|
||||||
packageJson.dependencies = packageJson.dependencies || {};
|
packageJson.dependencies = packageJson.dependencies || {};
|
||||||
packageJson.devDependencices = packageJson.devDependencices || {};
|
packageJson.devDependencies = packageJson.devDependencies || {};
|
||||||
|
|
||||||
// base deps
|
// base deps
|
||||||
devDependencies['@nrwl/vite'] = nxVersion;
|
devDependencies['@nrwl/vite'] = nxVersion;
|
||||||
@ -32,6 +33,7 @@ function checkDependenciesInstalled(host: Tree, schema: Schema) {
|
|||||||
devDependencies['vite-tsconfig-paths'] = viteTsConfigPathsVersion;
|
devDependencies['vite-tsconfig-paths'] = viteTsConfigPathsVersion;
|
||||||
devDependencies['vitest'] = vitestVersion;
|
devDependencies['vitest'] = vitestVersion;
|
||||||
devDependencies['@vitest/ui'] = vitestUiVersion;
|
devDependencies['@vitest/ui'] = vitestUiVersion;
|
||||||
|
devDependencies['jsdom'] = jsdomVersion;
|
||||||
|
|
||||||
if (schema.uiFramework === 'react') {
|
if (schema.uiFramework === 'react') {
|
||||||
devDependencies['@vitejs/plugin-react'] = vitePluginReactVersion;
|
devDependencies['@vitejs/plugin-react'] = vitePluginReactVersion;
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"types": ["vitest/globals", "node"]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"vite.config.ts",
|
||||||
|
"**/*.test.ts",
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.test.tsx",
|
||||||
|
"**/*.spec.tsx",
|
||||||
|
"**/*.test.js",
|
||||||
|
"**/*.spec.js",
|
||||||
|
"**/*.test.jsx",
|
||||||
|
"**/*.spec.jsx",
|
||||||
|
"**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
6
packages/vite/src/generators/vitest/schema.d.ts
vendored
Normal file
6
packages/vite/src/generators/vitest/schema.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export interface VitestGeneratorSchema {
|
||||||
|
project: string;
|
||||||
|
uiFramework: 'react' | 'none';
|
||||||
|
inSourceTests?: boolean;
|
||||||
|
skipViteConfig?: boolean;
|
||||||
|
}
|
||||||
32
packages/vite/src/generators/vitest/schema.json
Normal file
32
packages/vite/src/generators/vitest/schema.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/schema",
|
||||||
|
"cli": "nx",
|
||||||
|
"$id": "Vitest",
|
||||||
|
"title": "",
|
||||||
|
"type": "object",
|
||||||
|
"description": "Generate a vitest setup for a project.",
|
||||||
|
"properties": {
|
||||||
|
"project": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the project to test.",
|
||||||
|
"$default": { "$source": "projectName" }
|
||||||
|
},
|
||||||
|
"uiFramework": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["react", "none"],
|
||||||
|
"default": "none",
|
||||||
|
"description": "UI framework to use with vitest"
|
||||||
|
},
|
||||||
|
"inSourceTests": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Do not generate separate spec files and set up in-source testing"
|
||||||
|
},
|
||||||
|
"skipViteConfig": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Skip generating a vite config file"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["project"]
|
||||||
|
}
|
||||||
109
packages/vite/src/generators/vitest/vitest-generator.ts
Normal file
109
packages/vite/src/generators/vitest/vitest-generator.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import {
|
||||||
|
convertNxGenerator,
|
||||||
|
formatFiles,
|
||||||
|
generateFiles,
|
||||||
|
GeneratorCallback,
|
||||||
|
joinPathFragments,
|
||||||
|
offsetFromRoot,
|
||||||
|
readProjectConfiguration,
|
||||||
|
Tree,
|
||||||
|
updateJson,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
|
import {
|
||||||
|
addOrChangeTestTarget,
|
||||||
|
findExistingTargets,
|
||||||
|
writeViteConfig,
|
||||||
|
} from '../../utils/generator-utils';
|
||||||
|
import { VitestGeneratorSchema } from './schema';
|
||||||
|
|
||||||
|
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||||
|
import initGenerator from '../init/init';
|
||||||
|
|
||||||
|
export async function vitestGenerator(
|
||||||
|
tree: Tree,
|
||||||
|
schema: VitestGeneratorSchema
|
||||||
|
) {
|
||||||
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
|
const { targets, root } = readProjectConfiguration(tree, schema.project);
|
||||||
|
let testTarget = findExistingTargets(targets).testTarget;
|
||||||
|
|
||||||
|
addOrChangeTestTarget(tree, schema, testTarget);
|
||||||
|
|
||||||
|
const initTask = await initGenerator(tree, {
|
||||||
|
uiFramework: schema.uiFramework,
|
||||||
|
});
|
||||||
|
tasks.push(initTask);
|
||||||
|
|
||||||
|
if (!schema.skipViteConfig) {
|
||||||
|
writeViteConfig(tree, {
|
||||||
|
...schema,
|
||||||
|
includeVitest: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createFiles(tree, schema, root);
|
||||||
|
updateTsConfig(tree, schema, root);
|
||||||
|
|
||||||
|
await formatFiles(tree);
|
||||||
|
|
||||||
|
return runTasksInSerial(...tasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTsConfig(
|
||||||
|
tree: Tree,
|
||||||
|
options: VitestGeneratorSchema,
|
||||||
|
projectRoot: string
|
||||||
|
) {
|
||||||
|
updateJson(tree, joinPathFragments(projectRoot, 'tsconfig.json'), (json) => {
|
||||||
|
if (
|
||||||
|
json.references &&
|
||||||
|
!json.references.some((r) => r.path === './tsconfig.spec.json')
|
||||||
|
) {
|
||||||
|
json.references.push({
|
||||||
|
path: './tsconfig.spec.json',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.inSourceTests) {
|
||||||
|
const tsconfigLibPath = joinPathFragments(projectRoot, 'tsconfig.lib.json');
|
||||||
|
const tsconfigAppPath = joinPathFragments(projectRoot, 'tsconfig.app.json');
|
||||||
|
if (tree.exists(tsconfigLibPath)) {
|
||||||
|
updateJson(
|
||||||
|
tree,
|
||||||
|
joinPathFragments(projectRoot, 'tsconfig.lib.json'),
|
||||||
|
(json) => {
|
||||||
|
(json.compilerOptions.types ??= []).push('vitest/importMeta');
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else if (tree.exists(tsconfigAppPath)) {
|
||||||
|
updateJson(
|
||||||
|
tree,
|
||||||
|
joinPathFragments(projectRoot, 'tsconfig.app.json'),
|
||||||
|
(json) => {
|
||||||
|
(json.compilerOptions.types ??= []).push('vitest/importMeta');
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFiles(
|
||||||
|
tree: Tree,
|
||||||
|
options: VitestGeneratorSchema,
|
||||||
|
projectRoot: string
|
||||||
|
) {
|
||||||
|
generateFiles(tree, joinPathFragments(__dirname, 'files'), projectRoot, {
|
||||||
|
tmpl: '',
|
||||||
|
...options,
|
||||||
|
projectRoot,
|
||||||
|
offsetFromRoot: offsetFromRoot(projectRoot),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default vitestGenerator;
|
||||||
|
export const vitestSchematic = convertNxGenerator(vitestGenerator);
|
||||||
162
packages/vite/src/generators/vitest/vitest.spec.ts
Normal file
162
packages/vite/src/generators/vitest/vitest.spec.ts
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
|
import { Tree, readProjectConfiguration } from '@nrwl/devkit';
|
||||||
|
|
||||||
|
import generator from './vitest-generator';
|
||||||
|
import { VitestGeneratorSchema } from './schema';
|
||||||
|
import { mockReactAppGenerator } from '../../utils/test-utils';
|
||||||
|
|
||||||
|
describe('vitest generator', () => {
|
||||||
|
let appTree: Tree;
|
||||||
|
const options: VitestGeneratorSchema = {
|
||||||
|
project: 'my-test-react-app',
|
||||||
|
uiFramework: 'react',
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
appTree = createTreeWithEmptyWorkspace();
|
||||||
|
await mockReactAppGenerator(appTree);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should add the test target', async () => {
|
||||||
|
await generator(appTree, options);
|
||||||
|
const config = readProjectConfiguration(appTree, 'my-test-react-app');
|
||||||
|
expect(config.targets['test']).toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"executor": "@nrwl/vite:test",
|
||||||
|
"options": Object {
|
||||||
|
"passWithNoTests": true,
|
||||||
|
},
|
||||||
|
"outputs": Array [
|
||||||
|
"{workspaceRoot}/coverage/{projectRoot}",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('tsconfig', () => {
|
||||||
|
it('should add a tsconfig.spec.json file', async () => {
|
||||||
|
await generator(appTree, options);
|
||||||
|
const tsconfig = JSON.parse(
|
||||||
|
appTree.read('apps/my-test-react-app/tsconfig.json')?.toString() ?? '{}'
|
||||||
|
);
|
||||||
|
expect(tsconfig.references).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
|
||||||
|
const tsconfigSpec = JSON.parse(
|
||||||
|
appTree.read('apps/my-test-react-app/tsconfig.spec.json')?.toString() ??
|
||||||
|
'{}'
|
||||||
|
);
|
||||||
|
expect(tsconfigSpec).toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"compilerOptions": Object {
|
||||||
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"types": Array [
|
||||||
|
"vitest/globals",
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"include": Array [
|
||||||
|
"vite.config.ts",
|
||||||
|
"**/*.test.ts",
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.test.tsx",
|
||||||
|
"**/*.spec.tsx",
|
||||||
|
"**/*.test.js",
|
||||||
|
"**/*.spec.js",
|
||||||
|
"**/*.test.jsx",
|
||||||
|
"**/*.spec.jsx",
|
||||||
|
"**/*.d.ts",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add vitest/importMeta when inSourceTests is true', async () => {
|
||||||
|
await generator(appTree, { ...options, inSourceTests: true });
|
||||||
|
const tsconfig = JSON.parse(
|
||||||
|
appTree.read('apps/my-test-react-app/tsconfig.app.json')?.toString() ??
|
||||||
|
'{}'
|
||||||
|
);
|
||||||
|
expect(tsconfig.compilerOptions.types).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
"vitest/importMeta",
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('vite.config', () => {
|
||||||
|
it('should modify the vite.config.js file to include the test options', async () => {
|
||||||
|
await generator(appTree, options);
|
||||||
|
const viteConfig = appTree
|
||||||
|
.read('apps/my-test-react-app/vite.config.ts')
|
||||||
|
.toString();
|
||||||
|
expect(viteConfig).toMatchInlineSnapshot(`
|
||||||
|
"
|
||||||
|
/// <reference types=\\"vitest\\" />
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import ViteTsConfigPathsPlugin from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
react(),
|
||||||
|
ViteTsConfigPathsPlugin({
|
||||||
|
root: '../../',
|
||||||
|
projects: ['tsconfig.base.json'],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
|
||||||
|
},
|
||||||
|
});"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('insourceTests', () => {
|
||||||
|
it('should add the insourceSource option in the vite config', async () => {
|
||||||
|
await generator(appTree, { ...options, inSourceTests: true });
|
||||||
|
const viteConfig = appTree
|
||||||
|
.read('apps/my-test-react-app/vite.config.ts')
|
||||||
|
.toString();
|
||||||
|
expect(viteConfig).toMatchInlineSnapshot(`
|
||||||
|
"
|
||||||
|
/// <reference types=\\"vitest\\" />
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import ViteTsConfigPathsPlugin from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
react(),
|
||||||
|
ViteTsConfigPathsPlugin({
|
||||||
|
root: '../../',
|
||||||
|
projects: ['tsconfig.base.json'],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
define: {
|
||||||
|
'import.meta.vitest': undefined
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
includeSource: ['src/**/*.{js,ts,jsx,tsx}']
|
||||||
|
},
|
||||||
|
});"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -11,6 +11,7 @@ import {
|
|||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { ViteBuildExecutorOptions } from '../executors/build/schema';
|
import { ViteBuildExecutorOptions } from '../executors/build/schema';
|
||||||
import { ViteDevServerExecutorOptions } from '../executors/dev-server/schema';
|
import { ViteDevServerExecutorOptions } from '../executors/dev-server/schema';
|
||||||
|
import { VitestExecutorOptions } from '../executors/test/schema';
|
||||||
import { Schema } from '../generators/configuration/schema';
|
import { Schema } from '../generators/configuration/schema';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,18 +28,21 @@ import { Schema } from '../generators/configuration/schema';
|
|||||||
* they are using, and infer from the executor that the target
|
* they are using, and infer from the executor that the target
|
||||||
* is a build target.
|
* is a build target.
|
||||||
*/
|
*/
|
||||||
export function findServeAndBuildTargets(targets: {
|
export function findExistingTargets(targets: {
|
||||||
[targetName: string]: TargetConfiguration;
|
[targetName: string]: TargetConfiguration;
|
||||||
}): {
|
}): {
|
||||||
buildTarget: string;
|
buildTarget: string;
|
||||||
serveTarget: string;
|
serveTarget: string;
|
||||||
|
testTarget: string;
|
||||||
} {
|
} {
|
||||||
const returnObject: {
|
const returnObject: {
|
||||||
buildTarget: string;
|
buildTarget: string;
|
||||||
serveTarget: string;
|
serveTarget: string;
|
||||||
|
testTarget: string;
|
||||||
} = {
|
} = {
|
||||||
buildTarget: 'build',
|
buildTarget: 'build',
|
||||||
serveTarget: 'serve',
|
serveTarget: 'serve',
|
||||||
|
testTarget: 'test',
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.entries(targets).forEach(([target, targetConfig]) => {
|
Object.entries(targets).forEach(([target, targetConfig]) => {
|
||||||
@ -68,9 +72,13 @@ export function findServeAndBuildTargets(targets: {
|
|||||||
case '@nxext/vite:build':
|
case '@nxext/vite:build':
|
||||||
returnObject.buildTarget = target;
|
returnObject.buildTarget = target;
|
||||||
break;
|
break;
|
||||||
|
case '@nrwl/jest:jest':
|
||||||
|
case 'nxext/vitest:vitest':
|
||||||
|
returnObject.testTarget = target;
|
||||||
default:
|
default:
|
||||||
returnObject.buildTarget = 'build';
|
returnObject.buildTarget = 'build';
|
||||||
returnObject.serveTarget = 'serve';
|
returnObject.serveTarget = 'serve';
|
||||||
|
returnObject.testTarget = 'test';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -78,6 +86,39 @@ export function findServeAndBuildTargets(targets: {
|
|||||||
return returnObject;
|
return returnObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function addOrChangeTestTarget(
|
||||||
|
tree: Tree,
|
||||||
|
options: Schema,
|
||||||
|
target: string
|
||||||
|
) {
|
||||||
|
const project = readProjectConfiguration(tree, options.project);
|
||||||
|
const targets = {
|
||||||
|
...project.targets,
|
||||||
|
};
|
||||||
|
|
||||||
|
const testOptions: VitestExecutorOptions = {
|
||||||
|
passWithNoTests: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (targets[target]) {
|
||||||
|
targets[target].executor = '@nrwl/vite:test';
|
||||||
|
delete targets[target].options.jestConfig;
|
||||||
|
} else {
|
||||||
|
targets[target] = {
|
||||||
|
executor: '@nrwl/vite:test',
|
||||||
|
outputs: ['{projectRoot}/coverage'],
|
||||||
|
options: testOptions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProjectConfiguration(tree, options.project, {
|
||||||
|
...project,
|
||||||
|
targets: {
|
||||||
|
...targets,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function addOrChangeBuildTarget(
|
export function addOrChangeBuildTarget(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: Schema,
|
options: Schema,
|
||||||
@ -315,9 +356,22 @@ export function writeViteConfig(tree: Tree, options: Schema) {
|
|||||||
|
|
||||||
let viteConfigContent = '';
|
let viteConfigContent = '';
|
||||||
|
|
||||||
|
const testOption = `test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
${
|
||||||
|
options.inSourceTests ? `includeSource: ['src/**/*.{js,ts,jsx,tsx}']` : ''
|
||||||
|
}
|
||||||
|
},`;
|
||||||
|
|
||||||
|
const defineOption = `define: {
|
||||||
|
'import.meta.vitest': undefined
|
||||||
|
},`;
|
||||||
|
|
||||||
switch (options.uiFramework) {
|
switch (options.uiFramework) {
|
||||||
case 'react':
|
case 'react':
|
||||||
viteConfigContent = `
|
viteConfigContent = `
|
||||||
|
${options.includeVitest ? '/// <reference types="vitest" />' : ''}
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import ViteTsConfigPathsPlugin from 'vite-tsconfig-paths';
|
import ViteTsConfigPathsPlugin from 'vite-tsconfig-paths';
|
||||||
@ -330,10 +384,13 @@ export function writeViteConfig(tree: Tree, options: Schema) {
|
|||||||
projects: ['tsconfig.base.json'],
|
projects: ['tsconfig.base.json'],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
${options.inSourceTests ? defineOption : ''}
|
||||||
|
${options.includeVitest ? testOption : ''}
|
||||||
});`;
|
});`;
|
||||||
break;
|
break;
|
||||||
case 'none':
|
case 'none':
|
||||||
viteConfigContent = `
|
viteConfigContent = `
|
||||||
|
${options.includeVitest ? '/// <reference types="vitest" />' : ''}
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import ViteTsConfigPathsPlugin from 'vite-tsconfig-paths';
|
import ViteTsConfigPathsPlugin from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
@ -344,6 +401,8 @@ export function writeViteConfig(tree: Tree, options: Schema) {
|
|||||||
projects: ['tsconfig.base.json'],
|
projects: ['tsconfig.base.json'],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
${options.inSourceTests ? defineOption : ''}
|
||||||
|
${options.includeVitest ? testOption : ''}
|
||||||
});`;
|
});`;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -39,6 +39,32 @@ export function mockReactAppGenerator(tree: Tree): Tree {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
tree.write(
|
||||||
|
`apps/${appName}/tsconfig.app.json`,
|
||||||
|
`{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../dist/out-tsc"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
|
||||||
|
"../../node_modules/@nrwl/react/typings/image.d.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.test.ts",
|
||||||
|
"**/*.spec.tsx",
|
||||||
|
"**/*.test.tsx",
|
||||||
|
"**/*.spec.js",
|
||||||
|
"**/*.test.js",
|
||||||
|
"**/*.spec.jsx",
|
||||||
|
"**/*.test.jsx"
|
||||||
|
],
|
||||||
|
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
tree.write(
|
tree.write(
|
||||||
`apps/${appName}/src/index.html`,
|
`apps/${appName}/src/index.html`,
|
||||||
|
|||||||
@ -7,3 +7,4 @@ export const vitePluginReactVersion = '^2.2.0';
|
|||||||
export const vitePluginVueVersion = '^3.2.0';
|
export const vitePluginVueVersion = '^3.2.0';
|
||||||
export const vitePluginVueJsxVersion = '^2.1.1';
|
export const vitePluginVueJsxVersion = '^2.1.1';
|
||||||
export const viteTsConfigPathsVersion = '^3.5.2';
|
export const viteTsConfigPathsVersion = '^3.5.2';
|
||||||
|
export const jsdomVersion = '~20.0.3';
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import { swcCoreVersion } from '@nrwl/js/src/utils/versions';
|
|||||||
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
||||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||||
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
||||||
import { viteConfigurationGenerator } from '@nrwl/vite';
|
import { viteConfigurationGenerator, vitestGenerator } from '@nrwl/vite';
|
||||||
|
|
||||||
import { swcLoaderVersion } from '../../utils/versions';
|
import { swcLoaderVersion } from '../../utils/versions';
|
||||||
import { webInitGenerator } from '../init/init';
|
import { webInitGenerator } from '../init/init';
|
||||||
@ -203,10 +203,20 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
|
|||||||
uiFramework: 'react',
|
uiFramework: 'react',
|
||||||
project: options.projectName,
|
project: options.projectName,
|
||||||
newProject: true,
|
newProject: true,
|
||||||
|
includeVitest: true,
|
||||||
});
|
});
|
||||||
tasks.push(viteTask);
|
tasks.push(viteTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') {
|
||||||
|
const vitestTask = await vitestGenerator(host, {
|
||||||
|
uiFramework: 'none',
|
||||||
|
project: options.projectName,
|
||||||
|
inSourceTests: options.inSourceTests,
|
||||||
|
});
|
||||||
|
tasks.push(vitestTask);
|
||||||
|
}
|
||||||
|
|
||||||
const lintTask = await lintProjectGenerator(host, {
|
const lintTask = await lintProjectGenerator(host, {
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
project: options.projectName,
|
project: options.projectName,
|
||||||
@ -273,6 +283,10 @@ function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
|||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
if (options.bundler === 'vite') {
|
||||||
|
options.unitTestRunner = 'vitest';
|
||||||
|
}
|
||||||
|
|
||||||
options.style = options.style || 'css';
|
options.style = options.style || 'css';
|
||||||
options.linter = options.linter || Linter.EsLint;
|
options.linter = options.linter || Linter.EsLint;
|
||||||
options.unitTestRunner = options.unitTestRunner || 'jest';
|
options.unitTestRunner = options.unitTestRunner || 'jest';
|
||||||
|
|||||||
@ -9,7 +9,8 @@ export interface Schema {
|
|||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
tags?: string;
|
tags?: string;
|
||||||
unitTestRunner?: 'jest' | 'none';
|
unitTestRunner?: 'jest' | 'vitest' | 'none';
|
||||||
|
inSourceTests?: boolean;
|
||||||
e2eTestRunner?: 'cypress' | 'none';
|
e2eTestRunner?: 'cypress' | 'none';
|
||||||
linter?: Linter;
|
linter?: Linter;
|
||||||
standaloneConfig?: boolean;
|
standaloneConfig?: boolean;
|
||||||
|
|||||||
@ -73,10 +73,15 @@
|
|||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "vitest", "none"],
|
||||||
"description": "Test runner to use for unit tests",
|
"description": "Test runner to use for unit tests",
|
||||||
"default": "jest"
|
"default": "jest"
|
||||||
},
|
},
|
||||||
|
"inSourceTests": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "When using Vitest, separate spec files will not be generated and instead will be included within the source files."
|
||||||
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["cypress", "none"],
|
"enum": ["cypress", "none"],
|
||||||
|
|||||||
2
packages/web/src/generators/init/schema.d.ts
vendored
2
packages/web/src/generators/init/schema.d.ts
vendored
@ -1,6 +1,6 @@
|
|||||||
export interface Schema {
|
export interface Schema {
|
||||||
bundler?: 'webpack' | 'none' | 'vite';
|
bundler?: 'webpack' | 'none' | 'vite';
|
||||||
unitTestRunner?: 'jest' | 'none';
|
unitTestRunner?: 'jest' | 'vitest' | 'none';
|
||||||
e2eTestRunner?: 'cypress' | 'none';
|
e2eTestRunner?: 'cypress' | 'none';
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user