feat(vite): add angular option to vitest generator (#29055)
## Current Behavior `@nx/vite:vitest` generator does not provide Angular support in the `uiFramework` options. ## Expected Behavior `angular` option should generate the vitest configuration just like `@nx/angular:application` and `@nx/angular/library` do.
This commit is contained in:
parent
5068a26ed6
commit
77dc090a75
@ -16,8 +16,7 @@
|
|||||||
},
|
},
|
||||||
"uiFramework": {
|
"uiFramework": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["react", "none"],
|
"enum": ["angular", "react", "none"],
|
||||||
"default": "none",
|
|
||||||
"description": "UI framework to use with vitest."
|
"description": "UI framework to use with vitest."
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
|
|||||||
@ -1,10 +1,5 @@
|
|||||||
import {
|
import { ensurePackage, type Tree } from '@nx/devkit';
|
||||||
addDependenciesToPackageJson,
|
import { nxVersion } from '../../utils/versions';
|
||||||
ensurePackage,
|
|
||||||
joinPathFragments,
|
|
||||||
type Tree,
|
|
||||||
} from '@nx/devkit';
|
|
||||||
import { analogVitestAngular, nxVersion } from '../../utils/versions';
|
|
||||||
|
|
||||||
export type AddVitestOptions = {
|
export type AddVitestOptions = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -17,69 +12,16 @@ export async function addVitest(
|
|||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: AddVitestOptions
|
options: AddVitestOptions
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!options.skipPackageJson) {
|
const { vitestGenerator } = ensurePackage<typeof import('@nx/vite')>(
|
||||||
addDependenciesToPackageJson(
|
'@nx/vite',
|
||||||
tree,
|
nxVersion
|
||||||
{},
|
|
||||||
{
|
|
||||||
'@analogjs/vitest-angular': analogVitestAngular,
|
|
||||||
'@analogjs/vite-plugin-angular': analogVitestAngular,
|
|
||||||
},
|
|
||||||
undefined,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { createOrEditViteConfig, vitestGenerator } = ensurePackage<
|
|
||||||
typeof import('@nx/vite')
|
|
||||||
>('@nx/vite', nxVersion);
|
|
||||||
|
|
||||||
const relativeTestSetupPath = joinPathFragments('src', 'test-setup.ts');
|
|
||||||
|
|
||||||
const setupFile = joinPathFragments(
|
|
||||||
options.projectRoot,
|
|
||||||
relativeTestSetupPath
|
|
||||||
);
|
);
|
||||||
if (!tree.exists(setupFile)) {
|
|
||||||
tree.write(
|
|
||||||
setupFile,
|
|
||||||
`import '@analogjs/vitest-angular/setup-zone';
|
|
||||||
|
|
||||||
import {
|
await vitestGenerator(tree, {
|
||||||
BrowserDynamicTestingModule,
|
project: options.name,
|
||||||
platformBrowserDynamicTesting,
|
uiFramework: 'angular',
|
||||||
} from '@angular/platform-browser-dynamic/testing';
|
testEnvironment: 'jsdom',
|
||||||
import { getTestBed } from '@angular/core/testing';
|
coverageProvider: 'v8',
|
||||||
|
addPlugin: false,
|
||||||
getTestBed().initTestEnvironment(
|
});
|
||||||
BrowserDynamicTestingModule,
|
|
||||||
platformBrowserDynamicTesting()
|
|
||||||
);
|
|
||||||
`
|
|
||||||
);
|
|
||||||
|
|
||||||
await vitestGenerator(tree, {
|
|
||||||
project: options.name,
|
|
||||||
uiFramework: 'none',
|
|
||||||
skipViteConfig: true,
|
|
||||||
testEnvironment: 'jsdom',
|
|
||||||
coverageProvider: 'v8',
|
|
||||||
addPlugin: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
createOrEditViteConfig(
|
|
||||||
tree,
|
|
||||||
{
|
|
||||||
project: options.name,
|
|
||||||
includeLib: false,
|
|
||||||
includeVitest: true,
|
|
||||||
inSourceTests: false,
|
|
||||||
imports: [`import angular from '@analogjs/vite-plugin-angular'`],
|
|
||||||
plugins: ['angular()'],
|
|
||||||
setupFile: relativeTestSetupPath,
|
|
||||||
useEsmExtension: true,
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,10 +14,7 @@ export type PackageVersionNames =
|
|||||||
|
|
||||||
export type VersionMap = {
|
export type VersionMap = {
|
||||||
angularV17: Record<
|
angularV17: Record<
|
||||||
Exclude<
|
Exclude<CompatPackageVersionNames, 'typescriptEslintVersion'>,
|
||||||
CompatPackageVersionNames,
|
|
||||||
'analogVitestAngular' | 'typescriptEslintVersion'
|
|
||||||
>,
|
|
||||||
string
|
string
|
||||||
>;
|
>;
|
||||||
angularV18: Record<CompatPackageVersionNames, string>;
|
angularV18: Record<CompatPackageVersionNames, string>;
|
||||||
@ -80,7 +77,6 @@ export const backwardCompatibleVersions: VersionMap = {
|
|||||||
jestPresetAngularVersion: '~14.1.0',
|
jestPresetAngularVersion: '~14.1.0',
|
||||||
typesNodeVersion: '18.16.9',
|
typesNodeVersion: '18.16.9',
|
||||||
jasmineMarblesVersion: '^0.9.2',
|
jasmineMarblesVersion: '^0.9.2',
|
||||||
analogVitestAngular: '~1.9.1',
|
|
||||||
jsoncEslintParserVersion: '^2.1.0',
|
jsoncEslintParserVersion: '^2.1.0',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -28,6 +28,5 @@ export const tsNodeVersion = '10.9.1';
|
|||||||
export const jestPresetAngularVersion = '~14.4.0';
|
export const jestPresetAngularVersion = '~14.4.0';
|
||||||
export const typesNodeVersion = '18.16.9';
|
export const typesNodeVersion = '18.16.9';
|
||||||
export const jasmineMarblesVersion = '^0.9.2';
|
export const jasmineMarblesVersion = '^0.9.2';
|
||||||
export const analogVitestAngular = '~1.10.0';
|
|
||||||
|
|
||||||
export const jsoncEslintParserVersion = '^2.1.0';
|
export const jsoncEslintParserVersion = '^2.1.0';
|
||||||
|
|||||||
@ -1,5 +1,52 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`vitest generator angular should generate src/test-setup.ts 1`] = `
|
||||||
|
"import '@analogjs/vitest-angular/setup-zone';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting,
|
||||||
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
import { getTestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
getTestBed().initTestEnvironment(
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting()
|
||||||
|
);
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`vitest generator angular should generate vite.config.mts 1`] = `
|
||||||
|
"/// <reference types='vitest' />
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import angular from '@analogjs/vite-plugin-angular';
|
||||||
|
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||||
|
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
root: __dirname,
|
||||||
|
cacheDir: '../../node_modules/.vite/apps/my-test-angular-app',
|
||||||
|
plugins: [angular(), nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
|
||||||
|
// Uncomment this if you are using workers.
|
||||||
|
// worker: {
|
||||||
|
// plugins: [ nxViteTsPaths() ],
|
||||||
|
// },
|
||||||
|
test: {
|
||||||
|
watch: false,
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||||
|
setupFiles: ['src/test-setup.ts'],
|
||||||
|
reporters: ['default'],
|
||||||
|
coverage: {
|
||||||
|
reportsDirectory: '../../coverage/apps/my-test-angular-app',
|
||||||
|
provider: 'v8',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`vitest generator insourceTests should add the insourceSource option in the vite config 1`] = `
|
exports[`vitest generator insourceTests should add the insourceSource option in the vite config 1`] = `
|
||||||
"/// <reference types='vitest' />
|
"/// <reference types='vitest' />
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
@ -39,6 +86,36 @@ exports[`vitest generator tsconfig should add vitest.workspace.ts at the root 1`
|
|||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`vitest generator vite.config for libs should create correct vite.config.ts file for non buildable libs 1`] = `
|
||||||
|
"/// <reference types='vitest' />
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||||
|
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
root: __dirname,
|
||||||
|
cacheDir: '../../node_modules/.vite/libs/react-lib-nonb-jest',
|
||||||
|
plugins: [react(), nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
|
||||||
|
// Uncomment this if you are using workers.
|
||||||
|
// worker: {
|
||||||
|
// plugins: [ nxViteTsPaths() ],
|
||||||
|
// },
|
||||||
|
test: {
|
||||||
|
watch: false,
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||||
|
reporters: ['default'],
|
||||||
|
coverage: {
|
||||||
|
reportsDirectory: '../../coverage/libs/react-lib-nonb-jest',
|
||||||
|
provider: 'v8',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`vitest generator vite.config should create correct vite.config.ts file for apps 1`] = `
|
exports[`vitest generator vite.config should create correct vite.config.ts file for apps 1`] = `
|
||||||
"/// <reference types='vitest' />
|
"/// <reference types='vitest' />
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
@ -68,33 +145,3 @@ export default defineConfig({
|
|||||||
});
|
});
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`vitest generator vite.config should create correct vite.config.ts file for non buildable libs 1`] = `
|
|
||||||
"/// <reference types='vitest' />
|
|
||||||
import { defineConfig } from 'vite';
|
|
||||||
import react from '@vitejs/plugin-react';
|
|
||||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
|
||||||
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
root: __dirname,
|
|
||||||
cacheDir: '../../node_modules/.vite/libs/react-lib-nonb-jest',
|
|
||||||
plugins: [react(), nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
|
|
||||||
// Uncomment this if you are using workers.
|
|
||||||
// worker: {
|
|
||||||
// plugins: [ nxViteTsPaths() ],
|
|
||||||
// },
|
|
||||||
test: {
|
|
||||||
watch: false,
|
|
||||||
globals: true,
|
|
||||||
environment: 'jsdom',
|
|
||||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
|
||||||
reporters: ['default'],
|
|
||||||
coverage: {
|
|
||||||
reportsDirectory: '../../coverage/libs/react-lib-nonb-jest',
|
|
||||||
provider: 'v8',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
export interface VitestGeneratorSchema {
|
export interface VitestGeneratorSchema {
|
||||||
project: string;
|
project: string;
|
||||||
uiFramework: 'react' | 'none';
|
uiFramework?: 'angular' | 'react' | 'none';
|
||||||
coverageProvider: 'v8' | 'istanbul' | 'custom';
|
coverageProvider: 'v8' | 'istanbul' | 'custom';
|
||||||
inSourceTests?: boolean;
|
inSourceTests?: boolean;
|
||||||
skipViteConfig?: boolean;
|
skipViteConfig?: boolean;
|
||||||
|
|||||||
@ -15,8 +15,7 @@
|
|||||||
},
|
},
|
||||||
"uiFramework": {
|
"uiFramework": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["react", "none"],
|
"enum": ["angular", "react", "none"],
|
||||||
"default": "none",
|
|
||||||
"description": "UI framework to use with vitest."
|
"description": "UI framework to use with vitest."
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
|
|||||||
@ -27,7 +27,11 @@ import {
|
|||||||
} from '../../utils/versions';
|
} from '../../utils/versions';
|
||||||
import initGenerator from '../init/init';
|
import initGenerator from '../init/init';
|
||||||
import { VitestGeneratorSchema } from './schema';
|
import { VitestGeneratorSchema } from './schema';
|
||||||
|
import { detectUiFramework } from '../../utils/detect-ui-framework';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param hasPlugin some frameworks (e.g. Nuxt) provide their own plugin. Their generators handle the plugin detection.
|
||||||
|
*/
|
||||||
export function vitestGenerator(
|
export function vitestGenerator(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
schema: VitestGeneratorSchema,
|
schema: VitestGeneratorSchema,
|
||||||
@ -56,6 +60,8 @@ export async function vitestGeneratorInternal(
|
|||||||
schema.project
|
schema.project
|
||||||
);
|
);
|
||||||
const projectType = schema.projectType ?? _projectType;
|
const projectType = schema.projectType ?? _projectType;
|
||||||
|
const uiFramework =
|
||||||
|
schema.uiFramework ?? (await detectUiFramework(schema.project));
|
||||||
const isRootProject = root === '.';
|
const isRootProject = root === '.';
|
||||||
|
|
||||||
tasks.push(await jsInitGenerator(tree, { ...schema, skipFormat: true }));
|
tasks.push(await jsInitGenerator(tree, { ...schema, skipFormat: true }));
|
||||||
@ -64,22 +70,49 @@ export async function vitestGeneratorInternal(
|
|||||||
addPlugin: schema.addPlugin,
|
addPlugin: schema.addPlugin,
|
||||||
});
|
});
|
||||||
tasks.push(initTask);
|
tasks.push(initTask);
|
||||||
tasks.push(ensureDependencies(tree, schema));
|
tasks.push(ensureDependencies(tree, { ...schema, uiFramework }));
|
||||||
|
|
||||||
const nxJson = readNxJson(tree);
|
addOrChangeTestTarget(tree, schema, hasPlugin);
|
||||||
const hasPluginCheck = nxJson.plugins?.some(
|
|
||||||
(p) =>
|
|
||||||
(typeof p === 'string'
|
|
||||||
? p === '@nx/vite/plugin'
|
|
||||||
: p.plugin === '@nx/vite/plugin') || hasPlugin
|
|
||||||
);
|
|
||||||
if (!hasPluginCheck) {
|
|
||||||
const testTarget = schema.testTarget ?? 'test';
|
|
||||||
addOrChangeTestTarget(tree, schema, testTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!schema.skipViteConfig) {
|
if (!schema.skipViteConfig) {
|
||||||
if (schema.uiFramework === 'react') {
|
if (uiFramework === 'angular') {
|
||||||
|
const relativeTestSetupPath = joinPathFragments('src', 'test-setup.ts');
|
||||||
|
|
||||||
|
const setupFile = joinPathFragments(root, relativeTestSetupPath);
|
||||||
|
if (!tree.exists(setupFile)) {
|
||||||
|
tree.write(
|
||||||
|
setupFile,
|
||||||
|
`import '@analogjs/vitest-angular/setup-zone';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting,
|
||||||
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
import { getTestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
getTestBed().initTestEnvironment(
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting()
|
||||||
|
);
|
||||||
|
`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
createOrEditViteConfig(
|
||||||
|
tree,
|
||||||
|
{
|
||||||
|
project: schema.project,
|
||||||
|
includeLib: false,
|
||||||
|
includeVitest: true,
|
||||||
|
inSourceTests: false,
|
||||||
|
imports: [`import angular from '@analogjs/vite-plugin-angular'`],
|
||||||
|
plugins: ['angular()'],
|
||||||
|
setupFile: relativeTestSetupPath,
|
||||||
|
useEsmExtension: true,
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
} else if (uiFramework === 'react') {
|
||||||
createOrEditViteConfig(
|
createOrEditViteConfig(
|
||||||
tree,
|
tree,
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,29 +1,79 @@
|
|||||||
import 'nx/src/internal-testing-utils/mock-project-graph';
|
import 'nx/src/internal-testing-utils/mock-project-graph';
|
||||||
|
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
|
||||||
import { Tree } from '@nx/devkit';
|
|
||||||
|
|
||||||
import generator from './vitest-generator';
|
|
||||||
import { VitestGeneratorSchema } from './schema';
|
|
||||||
import {
|
import {
|
||||||
|
createProjectGraphAsync,
|
||||||
|
readJson,
|
||||||
|
Tree,
|
||||||
|
updateJson,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
|
|
||||||
|
import {
|
||||||
|
mockAngularAppGenerator,
|
||||||
mockReactAppGenerator,
|
mockReactAppGenerator,
|
||||||
mockReactLibNonBuildableJestTestRunnerGenerator,
|
mockReactLibNonBuildableJestTestRunnerGenerator,
|
||||||
} from '../../utils/test-utils';
|
} from '../../utils/test-utils';
|
||||||
|
import { VitestGeneratorSchema } from './schema';
|
||||||
|
import generator from './vitest-generator';
|
||||||
|
|
||||||
describe('vitest generator', () => {
|
describe('vitest generator', () => {
|
||||||
let appTree: Tree;
|
let appTree: Tree;
|
||||||
const options: VitestGeneratorSchema = {
|
const options: VitestGeneratorSchema = {
|
||||||
project: 'my-test-react-app',
|
project: 'my-test-react-app',
|
||||||
uiFramework: 'react',
|
|
||||||
coverageProvider: 'v8',
|
coverageProvider: 'v8',
|
||||||
addPlugin: true,
|
addPlugin: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
describe('test target', () => {
|
||||||
|
it('should fail if test target is already defined', async () => {
|
||||||
|
const { runGenerator } = setUpAngularWorkspace();
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
runGenerator({
|
||||||
|
addPlugin: false,
|
||||||
|
})
|
||||||
|
).rejects.toThrow('Target "test" already exists in the project.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not add test target to the project', async () => {
|
||||||
|
const { runGenerator, tree } = setUpAngularWorkspace();
|
||||||
|
|
||||||
|
updateJson(tree, 'apps/my-test-angular-app/project.json', (json) => {
|
||||||
|
delete json.targets.test;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await runGenerator();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'apps/my-test-angular-app/project.json').targets.test
|
||||||
|
).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add test target to the project if plugin is not used', async () => {
|
||||||
|
const { runGenerator, tree } = setUpAngularWorkspace();
|
||||||
|
|
||||||
|
updateJson(tree, 'apps/my-test-angular-app/project.json', (json) => {
|
||||||
|
delete json.targets.test;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await runGenerator({
|
||||||
|
addPlugin: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'apps/my-test-angular-app/project.json').targets.test
|
||||||
|
.executor
|
||||||
|
).toBe('@nx/vite:test');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('tsconfig', () => {
|
describe('tsconfig', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
appTree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
const { runGenerator, tree } = setUpReactWorkspace();
|
||||||
mockReactAppGenerator(appTree);
|
appTree = tree;
|
||||||
await generator(appTree, options);
|
await runGenerator();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add vitest.workspace.ts at the root', async () => {
|
it('should add vitest.workspace.ts at the root', async () => {
|
||||||
@ -80,18 +130,61 @@ describe('vitest generator', () => {
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('vite.config', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
const { runGenerator, tree } = setUpReactWorkspace();
|
||||||
|
appTree = tree;
|
||||||
|
await runGenerator();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add @nx/vite dependency', async () => {
|
||||||
|
const { devDependencies } = readJson(appTree, 'package.json');
|
||||||
|
expect(devDependencies['@nx/vite']).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create correct vite.config.ts file for apps', async () => {
|
||||||
|
expect(
|
||||||
|
appTree.read('apps/my-test-react-app/vite.config.ts', 'utf-8')
|
||||||
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('vite.config for libs', () => {
|
||||||
|
it('should create correct vite.config.ts file for non buildable libs', async () => {
|
||||||
|
const { runGenerator, tree } = setUpReactWorkspace();
|
||||||
|
|
||||||
|
mockReactLibNonBuildableJestTestRunnerGenerator(tree);
|
||||||
|
setProjectGraphDependencies('react-lib-nonb-jest', ['npm:react']);
|
||||||
|
|
||||||
|
await runGenerator({ project: 'react-lib-nonb-jest' });
|
||||||
|
|
||||||
|
expect(
|
||||||
|
tree.read('libs/react-lib-nonb-jest/vite.config.ts', 'utf-8')
|
||||||
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('insourceTests', () => {
|
||||||
|
it('should add the insourceSource option in the vite config', async () => {
|
||||||
|
const { runGenerator, tree } = setUpReactWorkspace();
|
||||||
|
|
||||||
|
await runGenerator({ inSourceTests: true });
|
||||||
|
|
||||||
|
expect(
|
||||||
|
tree.read('apps/my-test-react-app/vite.config.ts', 'utf-8')
|
||||||
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
it('should add vitest/importMeta when inSourceTests is true', async () => {
|
it('should add vitest/importMeta when inSourceTests is true', async () => {
|
||||||
mockReactAppGenerator(appTree, 'my-test-react-app-2');
|
const { tree, runGenerator } = setUpReactWorkspace();
|
||||||
await generator(appTree, {
|
|
||||||
...options,
|
await runGenerator({ inSourceTests: true });
|
||||||
inSourceTests: true,
|
|
||||||
project: 'my-test-react-app-2',
|
|
||||||
});
|
|
||||||
const tsconfig = JSON.parse(
|
const tsconfig = JSON.parse(
|
||||||
appTree
|
tree.read('apps/my-test-react-app/tsconfig.app.json')?.toString() ??
|
||||||
.read('apps/my-test-react-app-2/tsconfig.app.json')
|
'{}'
|
||||||
?.toString() ?? '{}'
|
|
||||||
);
|
);
|
||||||
expect(tsconfig.compilerOptions.types).toMatchInlineSnapshot(`
|
expect(tsconfig.compilerOptions.types).toMatchInlineSnapshot(`
|
||||||
[
|
[
|
||||||
@ -101,37 +194,131 @@ describe('vitest generator', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('vite.config', () => {
|
describe('angular', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
appTree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
const { tree, runGenerator } = setUpAngularWorkspace();
|
||||||
mockReactAppGenerator(appTree);
|
appTree = tree;
|
||||||
await generator(appTree, options);
|
await runGenerator();
|
||||||
});
|
});
|
||||||
it('should create correct vite.config.ts file for apps', async () => {
|
|
||||||
|
it('should generate vite.config.mts', async () => {
|
||||||
expect(
|
expect(
|
||||||
appTree.read('apps/my-test-react-app/vite.config.ts', 'utf-8')
|
appTree.read('apps/my-test-angular-app/vite.config.mts', 'utf-8')
|
||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create correct vite.config.ts file for non buildable libs', async () => {
|
it('should not generate vite.config.ts', async () => {
|
||||||
mockReactLibNonBuildableJestTestRunnerGenerator(appTree);
|
expect(appTree.exists('apps/my-test-angular-app/vite.config.ts')).toBe(
|
||||||
await generator(appTree, { ...options, project: 'react-lib-nonb-jest' });
|
false
|
||||||
expect(
|
);
|
||||||
appTree.read('libs/react-lib-nonb-jest/vite.config.ts', 'utf-8')
|
|
||||||
).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe('insourceTests', () => {
|
it('should generate src/test-setup.ts', async () => {
|
||||||
beforeAll(async () => {
|
|
||||||
appTree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
||||||
mockReactAppGenerator(appTree);
|
|
||||||
await generator(appTree, { ...options, inSourceTests: true });
|
|
||||||
});
|
|
||||||
it('should add the insourceSource option in the vite config', async () => {
|
|
||||||
expect(
|
expect(
|
||||||
appTree.read('apps/my-test-react-app/vite.config.ts', 'utf-8')
|
appTree.read('apps/my-test-angular-app/src/test-setup.ts', 'utf-8')
|
||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should exclude src/test-setup.ts in tsconfig.app.json', async () => {
|
||||||
|
const tsConfig = readJson(
|
||||||
|
appTree,
|
||||||
|
'apps/my-test-angular-app/tsconfig.app.json'
|
||||||
|
);
|
||||||
|
expect(tsConfig.exclude).toContain('src/test-setup.ts');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should include src/test-setup.ts in tsconfig.spec.json', async () => {
|
||||||
|
const tsConfig = readJson(
|
||||||
|
appTree,
|
||||||
|
'apps/my-test-angular-app/tsconfig.spec.json'
|
||||||
|
);
|
||||||
|
expect(tsConfig.files).toContain('src/test-setup.ts');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add vitest-angular', async () => {
|
||||||
|
const { devDependencies } = readJson(appTree, 'package.json');
|
||||||
|
expect(devDependencies['@analogjs/vite-plugin-angular']).toBeDefined();
|
||||||
|
expect(devDependencies['@analogjs/vitest-angular']).toBeDefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function setUpAngularWorkspace() {
|
||||||
|
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
|
const project = 'my-test-angular-app';
|
||||||
|
|
||||||
|
(
|
||||||
|
createProjectGraphAsync as jest.MockedFn<typeof createProjectGraphAsync>
|
||||||
|
).mockResolvedValue({
|
||||||
|
dependencies: {
|
||||||
|
[project]: [
|
||||||
|
{
|
||||||
|
type: 'static',
|
||||||
|
source: project,
|
||||||
|
target: 'npm:@angular/core',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
nodes: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
mockAngularAppGenerator(tree);
|
||||||
|
|
||||||
|
return {
|
||||||
|
async runGenerator({ addPlugin = true }: { addPlugin?: boolean } = {}) {
|
||||||
|
await generator(tree, {
|
||||||
|
project,
|
||||||
|
coverageProvider: 'v8',
|
||||||
|
addPlugin,
|
||||||
|
});
|
||||||
|
return tree;
|
||||||
|
},
|
||||||
|
tree,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUpReactWorkspace() {
|
||||||
|
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
|
const appName = 'my-test-react-app';
|
||||||
|
|
||||||
|
mockReactAppGenerator(tree);
|
||||||
|
|
||||||
|
setProjectGraphDependencies(appName, ['npm:react']);
|
||||||
|
|
||||||
|
return {
|
||||||
|
project: appName,
|
||||||
|
async runGenerator({
|
||||||
|
addPlugin = true,
|
||||||
|
inSourceTests,
|
||||||
|
project,
|
||||||
|
}: {
|
||||||
|
addPlugin?: boolean;
|
||||||
|
inSourceTests?: boolean;
|
||||||
|
project?: string;
|
||||||
|
} = {}) {
|
||||||
|
await generator(tree, {
|
||||||
|
project: project ?? appName,
|
||||||
|
coverageProvider: 'v8',
|
||||||
|
addPlugin,
|
||||||
|
inSourceTests,
|
||||||
|
});
|
||||||
|
return tree;
|
||||||
|
},
|
||||||
|
tree,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function setProjectGraphDependencies(project: string, dependencies: string[]) {
|
||||||
|
(
|
||||||
|
createProjectGraphAsync as jest.MockedFn<typeof createProjectGraphAsync>
|
||||||
|
).mockResolvedValue({
|
||||||
|
dependencies: {
|
||||||
|
[project]: dependencies.map((target) => ({
|
||||||
|
type: 'static',
|
||||||
|
source: project,
|
||||||
|
target,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
nodes: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
66
packages/vite/src/utils/detect-ui-framework.spec.ts
Normal file
66
packages/vite/src/utils/detect-ui-framework.spec.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { createProjectGraphAsync, ProjectGraph } from '@nx/devkit';
|
||||||
|
import { detectUiFramework } from './detect-ui-framework';
|
||||||
|
|
||||||
|
jest.mock('@nx/devkit', () => ({
|
||||||
|
...jest.requireActual('@nx/devkit'),
|
||||||
|
createProjectGraphAsync: jest.fn().mockImplementation(() => {
|
||||||
|
throw new Error('createProjectGraphAsync stub is not configured');
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe(detectUiFramework.name, () => {
|
||||||
|
it.each([
|
||||||
|
{ framework: 'angular', dependency: '@angular/core' },
|
||||||
|
{ framework: 'angular', dependency: '@nx/angular' },
|
||||||
|
{ framework: 'react', dependency: 'react' },
|
||||||
|
{ framework: 'react', dependency: '@nx/react' },
|
||||||
|
{ framework: 'none', dependency: null },
|
||||||
|
])(
|
||||||
|
`should detect $framework when dependency "$dependency" is present`,
|
||||||
|
async ({ framework, dependency }) => {
|
||||||
|
const { projectGraphFake } = setUp();
|
||||||
|
|
||||||
|
if (dependency) {
|
||||||
|
await projectGraphFake.addNpmDependency('my-project', dependency);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(await detectUiFramework('my-project')).toBe(framework);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
const projectGraphFake = new ProjectGraphFake();
|
||||||
|
(
|
||||||
|
createProjectGraphAsync as jest.MockedFn<typeof createProjectGraphAsync>
|
||||||
|
).mockImplementation(async (options) =>
|
||||||
|
projectGraphFake.createProjectGraphAsync(options)
|
||||||
|
);
|
||||||
|
|
||||||
|
return { projectGraphFake };
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProjectGraphFake {
|
||||||
|
private _graph: ProjectGraph = {
|
||||||
|
dependencies: {},
|
||||||
|
nodes: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
async createProjectGraphAsync(
|
||||||
|
opts: { exitOnError: boolean; resetDaemonClient?: boolean } = {
|
||||||
|
exitOnError: false,
|
||||||
|
resetDaemonClient: false,
|
||||||
|
}
|
||||||
|
): Promise<ProjectGraph> {
|
||||||
|
return this._graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
async addNpmDependency(project: string, dependency: string) {
|
||||||
|
this._graph.dependencies[project] ??= [];
|
||||||
|
this._graph.dependencies[project].push({
|
||||||
|
source: project,
|
||||||
|
type: 'static',
|
||||||
|
target: `npm:${dependency}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
32
packages/vite/src/utils/detect-ui-framework.ts
Normal file
32
packages/vite/src/utils/detect-ui-framework.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { createProjectGraphAsync } from '@nx/devkit';
|
||||||
|
|
||||||
|
const ANGULAR_NPM_SCOPE = 'angular';
|
||||||
|
const ANGULAR_DEPS = ['@nx/angular'];
|
||||||
|
const REACT_DEPS = ['react', '@nx/react'];
|
||||||
|
|
||||||
|
export async function detectUiFramework(
|
||||||
|
project: string
|
||||||
|
): Promise<'angular' | 'react' | 'none'> {
|
||||||
|
const graph = await createProjectGraphAsync();
|
||||||
|
|
||||||
|
for (const dep of graph.dependencies[project] ?? []) {
|
||||||
|
if (dep.source !== project || !dep.target.startsWith('npm:')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const npmDependency = dep.target.replace('npm:', '');
|
||||||
|
|
||||||
|
if (
|
||||||
|
dep.target.startsWith(`npm:@${ANGULAR_NPM_SCOPE}/`) ||
|
||||||
|
ANGULAR_DEPS.includes(npmDependency)
|
||||||
|
) {
|
||||||
|
return 'angular';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (REACT_DEPS.includes(npmDependency)) {
|
||||||
|
return 'react';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'none';
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ import {
|
|||||||
type Tree,
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import {
|
import {
|
||||||
|
analogVitestAngular,
|
||||||
edgeRuntimeVmVersion,
|
edgeRuntimeVmVersion,
|
||||||
happyDomVersion,
|
happyDomVersion,
|
||||||
jsdomVersion,
|
jsdomVersion,
|
||||||
@ -14,7 +15,7 @@ import {
|
|||||||
} from './versions';
|
} from './versions';
|
||||||
|
|
||||||
export type EnsureDependenciesOptions = {
|
export type EnsureDependenciesOptions = {
|
||||||
uiFramework: 'react' | 'none';
|
uiFramework: 'angular' | 'react' | 'none';
|
||||||
compiler?: 'babel' | 'swc';
|
compiler?: 'babel' | 'swc';
|
||||||
includeLib?: boolean;
|
includeLib?: boolean;
|
||||||
testEnvironment?: 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime' | string;
|
testEnvironment?: 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime' | string;
|
||||||
@ -38,6 +39,11 @@ export function ensureDependencies(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (schema.uiFramework === 'angular') {
|
||||||
|
devDependencies['@analogjs/vitest-angular'] = analogVitestAngular;
|
||||||
|
devDependencies['@analogjs/vite-plugin-angular'] = analogVitestAngular;
|
||||||
|
}
|
||||||
|
|
||||||
if (schema.uiFramework === 'react') {
|
if (schema.uiFramework === 'react') {
|
||||||
if (schema.compiler === 'swc') {
|
if (schema.compiler === 'swc') {
|
||||||
devDependencies['@vitejs/plugin-react-swc'] = vitePluginReactSwcVersion;
|
devDependencies['@vitejs/plugin-react-swc'] = vitePluginReactSwcVersion;
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import {
|
|||||||
logger,
|
logger,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
readJson,
|
readJson,
|
||||||
|
readNxJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
TargetConfiguration,
|
TargetConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
@ -16,6 +17,7 @@ import { VitePreviewServerExecutorOptions } from '../executors/preview-server/sc
|
|||||||
import { VitestExecutorOptions } from '../executors/test/schema';
|
import { VitestExecutorOptions } from '../executors/test/schema';
|
||||||
import { ViteConfigurationGeneratorSchema } from '../generators/configuration/schema';
|
import { ViteConfigurationGeneratorSchema } from '../generators/configuration/schema';
|
||||||
import { ensureViteConfigIsCorrect } from './vite-config-edit-utils';
|
import { ensureViteConfigIsCorrect } from './vite-config-edit-utils';
|
||||||
|
import { VitestGeneratorSchema } from '../generators/vitest/schema';
|
||||||
|
|
||||||
export type Target = 'build' | 'serve' | 'test' | 'preview';
|
export type Target = 'build' | 'serve' | 'test' | 'preview';
|
||||||
export type TargetFlags = Partial<Record<Target, boolean>>;
|
export type TargetFlags = Partial<Record<Target, boolean>>;
|
||||||
@ -81,10 +83,23 @@ export function findExistingJsBuildTargetInProject(targets: {
|
|||||||
|
|
||||||
export function addOrChangeTestTarget(
|
export function addOrChangeTestTarget(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: ViteConfigurationGeneratorSchema,
|
options: VitestGeneratorSchema,
|
||||||
target: string
|
hasPlugin: boolean
|
||||||
) {
|
) {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
|
||||||
|
hasPlugin = nxJson.plugins?.some((p) =>
|
||||||
|
typeof p === 'string'
|
||||||
|
? p === '@nx/vite/plugin'
|
||||||
|
: p.plugin === '@nx/vite/plugin' || hasPlugin
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hasPlugin) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const project = readProjectConfiguration(tree, options.project);
|
const project = readProjectConfiguration(tree, options.project);
|
||||||
|
const target = options.testTarget ?? 'test';
|
||||||
|
|
||||||
const reportsDirectory = joinPathFragments(
|
const reportsDirectory = joinPathFragments(
|
||||||
offsetFromRoot(project.root),
|
offsetFromRoot(project.root),
|
||||||
@ -98,8 +113,7 @@ export function addOrChangeTestTarget(
|
|||||||
project.targets ??= {};
|
project.targets ??= {};
|
||||||
|
|
||||||
if (project.targets[target]) {
|
if (project.targets[target]) {
|
||||||
project.targets[target].executor = '@nx/vite:test';
|
throw new Error(`Target "${target}" already exists in the project.`);
|
||||||
delete project.targets[target].options?.jestConfig;
|
|
||||||
} else {
|
} else {
|
||||||
project.targets[target] = {
|
project.targets[target] = {
|
||||||
executor: '@nx/vite:test',
|
executor: '@nx/vite:test',
|
||||||
@ -373,10 +387,7 @@ export function createOrEditViteConfig(
|
|||||||
projectAlreadyHasViteTargets?: TargetFlags,
|
projectAlreadyHasViteTargets?: TargetFlags,
|
||||||
vitestFileName?: boolean
|
vitestFileName?: boolean
|
||||||
) {
|
) {
|
||||||
const { root: projectRoot, projectType } = readProjectConfiguration(
|
const { root: projectRoot } = readProjectConfiguration(tree, options.project);
|
||||||
tree,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
|
|
||||||
const extension = options.useEsmExtension ? 'mts' : 'ts';
|
const extension = options.useEsmExtension ? 'mts' : 'ts';
|
||||||
const viteConfigPath = vitestFileName
|
const viteConfigPath = vitestFileName
|
||||||
|
|||||||
@ -407,6 +407,67 @@ export function mockAngularAppGenerator(tree: Tree): Tree {
|
|||||||
projectType: 'application',
|
projectType: 'application',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
writeJson(tree, `apps/${appName}/tsconfig.json`, {
|
||||||
|
compilerOptions: {
|
||||||
|
target: 'es2022',
|
||||||
|
esModuleInterop: true,
|
||||||
|
forceConsistentCasingInFileNames: true,
|
||||||
|
strict: true,
|
||||||
|
noImplicitOverride: true,
|
||||||
|
noPropertyAccessFromIndexSignature: true,
|
||||||
|
noImplicitReturns: true,
|
||||||
|
noFallthroughCasesInSwitch: true,
|
||||||
|
},
|
||||||
|
files: [],
|
||||||
|
include: [],
|
||||||
|
references: [
|
||||||
|
{
|
||||||
|
path: './tsconfig.editor.json',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: './tsconfig.app.json',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: './tsconfig.spec.json',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
extends: '../../tsconfig.base.json',
|
||||||
|
angularCompilerOptions: {
|
||||||
|
enableI18nLegacyMessageIdFormat: false,
|
||||||
|
strictInjectionParameters: true,
|
||||||
|
strictInputAccessModifiers: true,
|
||||||
|
strictTemplates: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
writeJson(tree, `apps/${appName}/tsconfig.app.json`, {
|
||||||
|
extends: './tsconfig.json',
|
||||||
|
compilerOptions: {
|
||||||
|
outDir: '../../dist/out-tsc',
|
||||||
|
types: [],
|
||||||
|
},
|
||||||
|
files: ['src/main.ts'],
|
||||||
|
include: ['src/**/*.d.ts'],
|
||||||
|
exclude: ['jest.config.ts', 'src/**/*.test.ts', 'src/**/*.spec.ts'],
|
||||||
|
});
|
||||||
|
|
||||||
|
writeJson(tree, `apps/${appName}/tsconfig.spec.json`, {
|
||||||
|
extends: './tsconfig.json',
|
||||||
|
compilerOptions: {
|
||||||
|
outDir: '../../dist/out-tsc',
|
||||||
|
module: 'commonjs',
|
||||||
|
target: 'es2016',
|
||||||
|
types: ['jest', 'node'],
|
||||||
|
},
|
||||||
|
files: ['src/test-setup.ts'],
|
||||||
|
include: [
|
||||||
|
'jest.config.ts',
|
||||||
|
'src/**/*.test.ts',
|
||||||
|
'src/**/*.spec.ts',
|
||||||
|
'src/**/*.d.ts',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,8 @@ export const vitePluginDtsVersion = '~3.8.1';
|
|||||||
export const happyDomVersion = '~9.20.3';
|
export const happyDomVersion = '~9.20.3';
|
||||||
export const edgeRuntimeVmVersion = '~3.0.2';
|
export const edgeRuntimeVmVersion = '~3.0.2';
|
||||||
|
|
||||||
|
export const analogVitestAngular = '~1.10.0';
|
||||||
|
|
||||||
// Coverage providers
|
// Coverage providers
|
||||||
export const vitestCoverageV8Version = '^1.0.4';
|
export const vitestCoverageV8Version = '^1.0.4';
|
||||||
export const vitestCoverageIstanbulVersion = '^1.0.4';
|
export const vitestCoverageIstanbulVersion = '^1.0.4';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user