Skip to content

Commit

Permalink
feat(testing): add vitest generators (#13301)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cammisuli committed Nov 23, 2022
1 parent 17514d2 commit 02e22de
Show file tree
Hide file tree
Showing 39 changed files with 678 additions and 38 deletions.
14 changes: 12 additions & 2 deletions docs/generated/packages/react.json
Expand Up @@ -162,10 +162,15 @@
},
"unitTestRunner": {
"type": "string",
"enum": ["jest", "none"],
"enum": ["jest", "vitest", "none"],
"description": "Test runner to use for unit tests.",
"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": {
"type": "string",
"enum": ["cypress", "none"],
Expand Down Expand Up @@ -332,10 +337,15 @@
},
"unitTestRunner": {
"type": "string",
"enum": ["jest", "none"],
"enum": ["jest", "vitest", "none"],
"description": "Test runner to use for unit tests.",
"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": {
"type": "string",
"description": "Add tags to the library (used for linting).",
Expand Down
42 changes: 42 additions & 0 deletions docs/generated/packages/vite.json
Expand Up @@ -81,6 +81,48 @@
"hidden": false,
"implementation": "/packages/vite/src/generators/configuration/configuration.ts",
"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": [
Expand Down
7 changes: 6 additions & 1 deletion docs/generated/packages/web.json
Expand Up @@ -136,10 +136,15 @@
},
"unitTestRunner": {
"type": "string",
"enum": ["jest", "none"],
"enum": ["jest", "vitest", "none"],
"description": "Test runner to use for unit tests",
"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": {
"type": "string",
"enum": ["cypress", "none"],
Expand Down
2 changes: 1 addition & 1 deletion docs/packages.json
Expand Up @@ -372,7 +372,7 @@
"path": "generated/packages/vite.json",
"schemas": {
"executors": ["dev-server", "build", "test"],
"generators": ["init", "configuration"]
"generators": ["init", "configuration", "vitest"]
}
},
{
Expand Down
43 changes: 43 additions & 0 deletions e2e/vite/src/vite.test.ts
@@ -1,6 +1,7 @@
import {
cleanupProject,
createFile,
exists,
killPorts,
listFiles,
newProject,
Expand All @@ -10,6 +11,7 @@ import {
runCLI,
runCLIAsync,
runCommandUntil,
tmpProjPath,
uniq,
updateFile,
updateProjectConfig,
Expand Down Expand Up @@ -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`);
});
});
});
4 changes: 1 addition & 3 deletions e2e/web/src/web-vite.test.ts
Expand Up @@ -29,9 +29,7 @@ describe('Web Components Applications with bundler set as vite', () => {

const testResults = await runCLIAsync(`test ${appName}`);

expect(testResults.combinedOutput).toContain(
'Test Suites: 1 passed, 1 total'
);
expect(testResults.combinedOutput).toContain('Tests 2 passed (2)');

const lintE2eResults = runCLI(`lint ${appName}-e2e`);

Expand Down
16 changes: 13 additions & 3 deletions packages/react/src/generators/application/application.ts
Expand Up @@ -4,7 +4,7 @@ import {
} from '../../utils/lint';
import { NormalizedSchema, Schema } from './schema';
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 { addProject } from './lib/add-project';
import { addCypress } from './lib/add-cypress';
Expand All @@ -26,7 +26,7 @@ import reactInitGenerator from '../init/init';
import { Linter, lintProjectGenerator } from '@nrwl/linter';
import { swcCoreVersion } from '@nrwl/js/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) {
const tasks: GeneratorCallback[] = [];
Expand Down Expand Up @@ -89,18 +89,28 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
uiFramework: 'react',
project: options.projectName,
newProject: true,
includeVitest: true,
});
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);
tasks.push(lintTask);

const cypressTask = await addCypress(host, options);
tasks.push(cypressTask);
const jestTask = await addJest(host, options);
tasks.push(jestTask);
updateJestConfig(host, options);
updateSpecConfig(host, options);
const styledTask = addStyledModuleDependencies(host, options.styledModule);
tasks.push(styledTask);
const routingTask = addRouting(host, options);
Expand Down
Expand Up @@ -68,7 +68,10 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
templateVariables
);

if (options.unitTestRunner === 'none') {
if (
options.unitTestRunner === 'none' ||
(options.unitTestRunner === 'vitest' && options.inSourceTests == true)
) {
host.delete(
`${options.appProjectRoot}/src/app/${options.fileName}.spec.tsx`
);
Expand All @@ -80,6 +83,18 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
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) {
toJS(host);
}
Expand Down
Expand Up @@ -40,6 +40,10 @@ export function normalizeOptions(

assertValidStyle(options.style);

if (options.bundler === 'vite') {
options.unitTestRunner = 'vitest';
}

options.routing = options.routing ?? false;
options.strict = options.strict ?? true;
options.classComponent = options.classComponent ?? false;
Expand Down
Expand Up @@ -2,8 +2,8 @@ import { updateJestConfigContent } from '../../../utils/jest-utils';
import { NormalizedSchema } from '../schema';
import { offsetFromRoot, Tree, updateJson } from '@nrwl/devkit';

export function updateJestConfig(host: Tree, options: NormalizedSchema) {
if (options.unitTestRunner !== 'jest') {
export function updateSpecConfig(host: Tree, options: NormalizedSchema) {
if (options.unitTestRunner === 'none') {
return;
}

Expand All @@ -21,6 +21,10 @@ export function updateJestConfig(host: Tree, options: NormalizedSchema) {
return json;
});

if (options.unitTestRunner !== 'jest') {
return;
}

const configPath = `${options.appProjectRoot}/jest.config.${
options.js ? 'js' : 'ts'
}`;
Expand Down
3 changes: 2 additions & 1 deletion packages/react/src/generators/application/schema.d.ts
Expand Up @@ -7,7 +7,8 @@ export interface Schema {
skipFormat: boolean;
directory?: string;
tags?: string;
unitTestRunner: 'jest' | 'none';
unitTestRunner: 'jest' | 'vitest' | 'none';
inSourceTests?: boolean;
/**
* @deprecated
*/
Expand Down
7 changes: 6 additions & 1 deletion packages/react/src/generators/application/schema.json
Expand Up @@ -103,10 +103,15 @@
},
"unitTestRunner": {
"type": "string",
"enum": ["jest", "none"],
"enum": ["jest", "vitest", "none"],
"description": "Test runner to use for unit tests.",
"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": {
"type": "string",
"enum": ["cypress", "none"],
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/generators/host/schema.d.ts
Expand Up @@ -7,7 +7,7 @@ export interface Schema {
skipFormat: boolean;
directory?: string;
tags?: string;
unitTestRunner: 'jest' | 'none';
unitTestRunner: 'jest' | 'vitest' | 'none';
e2eTestRunner: 'cypress' | 'none';
linter: Linter;
pascalCaseFiles?: boolean;
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/generators/init/schema.d.ts
@@ -1,5 +1,5 @@
export interface InitSchema {
unitTestRunner?: 'jest' | 'none';
unitTestRunner?: 'jest' | 'vitest' | 'none';
e2eTestRunner?: 'cypress' | 'none';
skipFormat?: boolean;
skipPackageJson?: boolean;
Expand Down
12 changes: 11 additions & 1 deletion packages/react/src/generators/library/library.ts
Expand Up @@ -47,6 +47,7 @@ import componentGenerator from '../component/component';
import init from '../init/init';
import { Schema } from './schema';
import { updateJestConfigContent } from '../../utils/jest-utils';
import { vitestGenerator } from '@nrwl/vite';
export interface NormalizedSchema extends Schema {
name: string;
fileName: string;
Expand Down Expand Up @@ -109,6 +110,13 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
);
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) {
Expand All @@ -117,7 +125,9 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
project: options.name,
flat: true,
style: options.style,
skipTests: options.unitTestRunner === 'none',
skipTests:
options.unitTestRunner === 'none' ||
(options.unitTestRunner === 'vitest' && options.inSourceTests == true),
export: true,
routing: options.routing,
js: options.js,
Expand Down
3 changes: 2 additions & 1 deletion packages/react/src/generators/library/schema.d.ts
Expand Up @@ -11,7 +11,8 @@ export interface Schema {
pascalCaseFiles?: boolean;
routing?: boolean;
appProject?: string;
unitTestRunner: 'jest' | 'none';
unitTestRunner: 'jest' | 'vitest' | 'none';
inSourceTests?: boolean;
linter: Linter;
component?: boolean;
publishable?: boolean;
Expand Down
7 changes: 6 additions & 1 deletion packages/react/src/generators/library/schema.json
Expand Up @@ -80,10 +80,15 @@
},
"unitTestRunner": {
"type": "string",
"enum": ["jest", "none"],
"enum": ["jest", "vitest", "none"],
"description": "Test runner to use for unit tests.",
"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": {
"type": "string",
"description": "Add tags to the library (used for linting).",
Expand Down

0 comments on commit 02e22de

Please sign in to comment.