## Current Behavior The Angular plugin currently uses Angular Rspack at `^20.7.0`. The latest release of Angular Rspack is `21.0.0` ## Expected Behavior Use the latest version of Angular Rspack
624 lines
21 KiB
TypeScript
624 lines
21 KiB
TypeScript
import { names } from '@nx/devkit';
|
|
import {
|
|
checkFilesDoNotExist,
|
|
checkFilesExist,
|
|
cleanupProject,
|
|
getSize,
|
|
killPort,
|
|
killProcessAndPorts,
|
|
newProject,
|
|
readFile,
|
|
removeFile,
|
|
rmDist,
|
|
runCLI,
|
|
runCommandUntil,
|
|
runE2ETests,
|
|
tmpProjPath,
|
|
uniq,
|
|
updateFile,
|
|
updateJson,
|
|
} from '@nx/e2e/utils';
|
|
import { join, normalize } from 'path';
|
|
|
|
describe('Angular Projects', () => {
|
|
let proj: string;
|
|
const app1 = uniq('app1');
|
|
const esbuildApp = uniq('esbuild-app');
|
|
const lib1 = uniq('lib1');
|
|
let app1DefaultModule: string;
|
|
let app1DefaultComponentTemplate: string;
|
|
let esbuildAppDefaultModule: string;
|
|
let esbuildAppDefaultComponentTemplate: string;
|
|
let esbuildAppDefaultProjectConfig: string;
|
|
|
|
beforeAll(() => {
|
|
proj = newProject({ packages: ['@nx/angular'] });
|
|
runCLI(
|
|
`generate @nx/angular:app ${app1} --no-standalone --bundler=webpack --no-interactive`
|
|
);
|
|
runCLI(
|
|
`generate @nx/angular:app ${esbuildApp} --bundler=esbuild --no-standalone --no-interactive`
|
|
);
|
|
runCLI(`generate @nx/angular:lib ${lib1} --no-interactive`);
|
|
app1DefaultModule = readFile(`${app1}/src/app/app.module.ts`);
|
|
app1DefaultComponentTemplate = readFile(
|
|
`${app1}/src/app/app.component.html`
|
|
);
|
|
esbuildAppDefaultModule = readFile(`${esbuildApp}/src/app/app.module.ts`);
|
|
esbuildAppDefaultComponentTemplate = readFile(
|
|
`${esbuildApp}/src/app/app.component.html`
|
|
);
|
|
esbuildAppDefaultProjectConfig = readFile(`${esbuildApp}/project.json`);
|
|
});
|
|
|
|
afterEach(() => {
|
|
updateFile(`${app1}/src/app/app.module.ts`, app1DefaultModule);
|
|
updateFile(
|
|
`${app1}/src/app/app.component.html`,
|
|
app1DefaultComponentTemplate
|
|
);
|
|
updateFile(`${esbuildApp}/src/app/app.module.ts`, esbuildAppDefaultModule);
|
|
updateFile(
|
|
`${esbuildApp}/src/app/app.component.html`,
|
|
esbuildAppDefaultComponentTemplate
|
|
);
|
|
updateFile(`${esbuildApp}/project.json`, esbuildAppDefaultProjectConfig);
|
|
});
|
|
|
|
afterAll(() => cleanupProject());
|
|
|
|
it('should successfully generate apps and libs and work correctly', async () => {
|
|
const standaloneApp = uniq('standalone-app');
|
|
runCLI(
|
|
`generate @nx/angular:app my-dir/${standaloneApp} --bundler=webpack --no-interactive`
|
|
);
|
|
|
|
const esbuildStandaloneApp = uniq('esbuild-app');
|
|
runCLI(
|
|
`generate @nx/angular:app my-dir/${esbuildStandaloneApp} --bundler=esbuild --no-interactive`
|
|
);
|
|
|
|
updateFile(
|
|
`${app1}/src/app/app.module.ts`,
|
|
`
|
|
import { NgModule } from '@angular/core';
|
|
import { BrowserModule } from '@angular/platform-browser';
|
|
import { RouterModule } from '@angular/router';
|
|
import { AppComponent } from './app.component';
|
|
import { appRoutes } from './app.routes';
|
|
import { NxWelcomeComponent } from './nx-welcome.component';
|
|
import { ${names(lib1).className}Component } from '@${proj}/${lib1}';
|
|
|
|
@NgModule({
|
|
imports: [
|
|
BrowserModule,
|
|
RouterModule.forRoot(appRoutes, { initialNavigation: 'enabledBlocking' }),
|
|
${names(lib1).className}Component
|
|
],
|
|
declarations: [AppComponent, NxWelcomeComponent],
|
|
bootstrap: [AppComponent]
|
|
})
|
|
export class AppModule {}
|
|
`
|
|
);
|
|
|
|
// check build
|
|
runCLI(
|
|
`run-many --target build --projects=${app1},${esbuildApp},${standaloneApp},${esbuildStandaloneApp} --parallel --prod --output-hashing none`
|
|
);
|
|
checkFilesExist(`dist/${app1}/main.js`);
|
|
checkFilesExist(`dist/${esbuildApp}/browser/main.js`);
|
|
checkFilesExist(`dist/my-dir/${standaloneApp}/main.js`);
|
|
checkFilesExist(`dist/my-dir/${esbuildStandaloneApp}/browser/main.js`);
|
|
// This is a loose requirement because there are a lot of
|
|
// influences external from this project that affect this.
|
|
const es2015BundleSize = getSize(tmpProjPath(`dist/${app1}/main.js`));
|
|
console.log(
|
|
`The current es2015 bundle size is ${es2015BundleSize / 1000} KB`
|
|
);
|
|
expect(es2015BundleSize).toBeLessThanOrEqual(221000);
|
|
|
|
// check unit tests
|
|
runCLI(
|
|
`run-many --target test --projects=${app1},${standaloneApp},${esbuildStandaloneApp},${lib1} --parallel`
|
|
);
|
|
|
|
// check e2e tests
|
|
if (runE2ETests('playwright')) {
|
|
expect(() => runCLI(`e2e ${app1}-e2e`)).not.toThrow();
|
|
expect(await killPort(4200)).toBeTruthy();
|
|
}
|
|
|
|
const appPort = 4207;
|
|
const process = await runCommandUntil(
|
|
`serve ${app1} -- --port=${appPort}`,
|
|
(output) => output.includes(`listening on localhost:${appPort}`)
|
|
);
|
|
|
|
// port and process cleanup
|
|
await killProcessAndPorts(process.pid, appPort);
|
|
|
|
const esbProcess = await runCommandUntil(
|
|
`serve ${esbuildStandaloneApp} -- --port=${appPort}`,
|
|
(output) =>
|
|
output.includes(`Application bundle generation complete`) &&
|
|
output.includes(`localhost:${appPort}`)
|
|
);
|
|
|
|
// port and process cleanup
|
|
await killProcessAndPorts(esbProcess.pid, appPort);
|
|
}, 1000000);
|
|
|
|
it('should successfully work with rspack for build', async () => {
|
|
const app = uniq('app');
|
|
runCLI(
|
|
`generate @nx/angular:app my-dir/${app} --bundler=rspack --no-interactive`
|
|
);
|
|
const rspackConfigFileContents = readFile(
|
|
join('my-dir', app, 'rspack.config.ts')
|
|
);
|
|
const updatedConfigFileContents = rspackConfigFileContents.replace(
|
|
`maximumError: '1mb'`,
|
|
`maximumError: '3mb'`
|
|
);
|
|
updateFile(
|
|
join('my-dir', app, 'rspack.config.ts'),
|
|
updatedConfigFileContents
|
|
);
|
|
runCLI(`build ${app}`);
|
|
|
|
if (runE2ETests()) {
|
|
expect(() => runCLI(`e2e ${app}-e2e`)).not.toThrow();
|
|
expect(await killPort(4200)).toBeTruthy();
|
|
}
|
|
}, 1000000);
|
|
|
|
it('should successfully work with playwright for e2e tests', async () => {
|
|
const app = uniq('app');
|
|
|
|
runCLI(
|
|
`generate @nx/angular:app ${app} --e2eTestRunner=playwright --no-interactive`
|
|
);
|
|
|
|
if (runE2ETests('playwright')) {
|
|
expect(() => runCLI(`e2e ${app}-e2e`)).not.toThrow();
|
|
expect(await killPort(4200)).toBeTruthy();
|
|
}
|
|
}, 1000000);
|
|
|
|
it('should lint correctly with eslint and handle external HTML files and inline templates', async () => {
|
|
// disable the prefer-standalone rule for app1 which is not standalone
|
|
let app1EslintConfig = readFile(`${app1}/eslint.config.mjs`);
|
|
app1EslintConfig = app1EslintConfig.replace(
|
|
`'@angular-eslint/directive-selector': [`,
|
|
`'@angular-eslint/prefer-standalone': 'off',
|
|
'@angular-eslint/directive-selector': [`
|
|
);
|
|
updateFile(`${app1}/eslint.config.mjs`, app1EslintConfig);
|
|
|
|
// check apps and lib pass linting for initial generated code
|
|
runCLI(`run-many --target lint --projects=${app1},${lib1} --parallel`);
|
|
|
|
// External HTML template file
|
|
const templateWhichFailsBananaInBoxLintCheck = `<div ([foo])="bar"></div>`;
|
|
updateFile(
|
|
`${app1}/src/app/app.component.html`,
|
|
templateWhichFailsBananaInBoxLintCheck
|
|
);
|
|
// Inline template within component.ts file
|
|
const wrappedAsInlineTemplate = `
|
|
import { Component } from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'inline-template-component',
|
|
template: \`
|
|
${templateWhichFailsBananaInBoxLintCheck}
|
|
\`,
|
|
})
|
|
export class InlineTemplateComponent {}
|
|
`;
|
|
updateFile(
|
|
`${app1}/src/app/inline-template.component.ts`,
|
|
wrappedAsInlineTemplate
|
|
);
|
|
|
|
const appLintStdOut = runCLI(`lint ${app1}`, {
|
|
silenceError: true,
|
|
});
|
|
expect(appLintStdOut).toContain(
|
|
normalize(`${app1}/src/app/app.component.html`)
|
|
);
|
|
expect(appLintStdOut).toContain(`1:6`);
|
|
expect(appLintStdOut).toContain(`Invalid binding syntax`);
|
|
expect(appLintStdOut).toContain(
|
|
normalize(`${app1}/src/app/inline-template.component.ts`)
|
|
);
|
|
expect(appLintStdOut).toContain(`5:19`);
|
|
expect(appLintStdOut).toContain(
|
|
`The selector should start with one of these prefixes`
|
|
);
|
|
expect(appLintStdOut).toContain(`7:16`);
|
|
expect(appLintStdOut).toContain(`Invalid binding syntax`);
|
|
|
|
// cleanup added component
|
|
removeFile(`${app1}/src/app/inline-template.component.ts`);
|
|
}, 1000000);
|
|
|
|
it('should build the dependent buildable lib and its child lib, as well as the app', async () => {
|
|
// ARRANGE
|
|
const buildableLib = uniq('buildlib1');
|
|
const buildableChildLib = uniq('buildlib2');
|
|
|
|
runCLI(
|
|
`generate @nx/angular:library ${buildableLib} --buildable=true --no-standalone --no-interactive`
|
|
);
|
|
runCLI(
|
|
`generate @nx/angular:library ${buildableChildLib} --buildable=true --no-standalone --no-interactive`
|
|
);
|
|
|
|
// update the app module to include a ref to the buildable lib
|
|
updateFile(
|
|
`${app1}/src/app/app.module.ts`,
|
|
`
|
|
import { NgModule } from '@angular/core';
|
|
import { BrowserModule } from '@angular/platform-browser';
|
|
import { RouterModule } from '@angular/router';
|
|
import { AppComponent } from './app.component';
|
|
import { appRoutes } from './app.routes';
|
|
import { NxWelcomeComponent } from './nx-welcome.component';
|
|
import {${
|
|
names(buildableLib).className
|
|
}Module} from '@${proj}/${buildableLib}';
|
|
|
|
@NgModule({
|
|
declarations: [AppComponent, NxWelcomeComponent],
|
|
imports: [
|
|
BrowserModule,
|
|
RouterModule.forRoot(appRoutes, { initialNavigation: 'enabledBlocking' }),
|
|
${names(buildableLib).className}Module
|
|
],
|
|
providers: [],
|
|
bootstrap: [AppComponent],
|
|
})
|
|
export class AppModule {}
|
|
`
|
|
);
|
|
updateFile(
|
|
`${esbuildApp}/src/app/app.module.ts`,
|
|
`
|
|
import { NgModule } from '@angular/core';
|
|
import { BrowserModule } from '@angular/platform-browser';
|
|
import { RouterModule } from '@angular/router';
|
|
import { AppComponent } from './app.component';
|
|
import { appRoutes } from './app.routes';
|
|
import { NxWelcomeComponent } from './nx-welcome.component';
|
|
import {${
|
|
names(buildableLib).className
|
|
}Module} from '@${proj}/${buildableLib}';
|
|
|
|
@NgModule({
|
|
declarations: [AppComponent, NxWelcomeComponent],
|
|
imports: [
|
|
BrowserModule,
|
|
RouterModule.forRoot(appRoutes, { initialNavigation: 'enabledBlocking' }),
|
|
${names(buildableLib).className}Module
|
|
],
|
|
providers: [],
|
|
bootstrap: [AppComponent],
|
|
})
|
|
export class AppModule {}
|
|
`
|
|
);
|
|
|
|
// update the buildable lib module to include a ref to the buildable child lib
|
|
updateFile(
|
|
`${buildableLib}/src/lib/${names(buildableLib).fileName}.module.ts`,
|
|
`
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { ${
|
|
names(buildableChildLib).className
|
|
}Module } from '@${proj}/${buildableChildLib}';
|
|
|
|
@NgModule({
|
|
imports: [CommonModule, ${names(buildableChildLib).className}Module],
|
|
})
|
|
export class ${names(buildableLib).className}Module {}
|
|
|
|
`
|
|
);
|
|
|
|
// update the project.json
|
|
updateJson(join(app1, 'project.json'), (config) => {
|
|
config.targets.build.executor = '@nx/angular:webpack-browser';
|
|
config.targets.build.options = {
|
|
...config.targets.build.options,
|
|
buildLibsFromSource: false,
|
|
};
|
|
return config;
|
|
});
|
|
updateJson(join(esbuildApp, 'project.json'), (config) => {
|
|
config.targets.build.executor = '@nx/angular:browser-esbuild';
|
|
config.targets.build.options = {
|
|
...config.targets.build.options,
|
|
outputPath: `dist/${esbuildApp}`,
|
|
main: config.targets.build.options.browser,
|
|
browser: undefined,
|
|
buildLibsFromSource: false,
|
|
};
|
|
return config;
|
|
});
|
|
|
|
// update the nx.json
|
|
updateJson('nx.json', (config) => {
|
|
config.targetDefaults ??= {};
|
|
config.targetDefaults['@nx/angular:webpack-browser'] ??= {
|
|
cache: true,
|
|
dependsOn: [`^build`],
|
|
inputs:
|
|
config.namedInputs && 'production' in config.namedInputs
|
|
? ['production', '^production']
|
|
: ['default', '^default'],
|
|
};
|
|
config.targetDefaults['@nx/angular:browser-esbuild'] ??= {
|
|
cache: true,
|
|
dependsOn: [`^build`],
|
|
inputs:
|
|
config.namedInputs && 'production' in config.namedInputs
|
|
? ['production', '^production']
|
|
: ['default', '^default'],
|
|
};
|
|
return config;
|
|
});
|
|
|
|
// ACT
|
|
const libOutput = runCLI(`build ${app1} --configuration=development`);
|
|
const esbuildLibOutput = runCLI(
|
|
`build ${esbuildApp} --configuration=development`
|
|
);
|
|
|
|
// ASSERT
|
|
expect(libOutput).toContain(
|
|
`Building entry point '@${proj}/${buildableLib}'`
|
|
);
|
|
expect(libOutput).toContain(`nx run ${app1}:build:development`);
|
|
|
|
// to proof it has been built from source the "main.js" should actually contain
|
|
// the path to dist
|
|
const mainBundle = readFile(`dist/${app1}/main.js`);
|
|
expect(mainBundle).toContain(`dist/${buildableLib}`);
|
|
|
|
const mainEsBuildBundle = readFile(`dist/${esbuildApp}/main.js`);
|
|
expect(mainEsBuildBundle).toContain(`dist/${buildableLib}`);
|
|
});
|
|
|
|
it('should support esbuild plugins', async () => {
|
|
updateFile(
|
|
`${esbuildApp}/replace-text.plugin.mjs`,
|
|
`const replaceTextPlugin = {
|
|
name: 'replace-text',
|
|
setup(build) {
|
|
const options = build.initialOptions;
|
|
options.define.BUILD_DEFINED = '"Value was provided at build time"';
|
|
},
|
|
};
|
|
|
|
export default replaceTextPlugin;`
|
|
);
|
|
updateFile(
|
|
`${esbuildApp}/src/app/app.component.ts`,
|
|
`import { Component } from '@angular/core';
|
|
|
|
declare const BUILD_DEFINED: string;
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
standalone: false,
|
|
templateUrl: './app.component.html',
|
|
})
|
|
export class AppComponent {
|
|
title = 'esbuild-app';
|
|
buildDefined = BUILD_DEFINED;
|
|
}`
|
|
);
|
|
|
|
// check @nx/angular:application
|
|
updateJson(join(esbuildApp, 'project.json'), (config) => {
|
|
config.targets.build.executor = '@nx/angular:application';
|
|
config.targets.build.options = {
|
|
...config.targets.build.options,
|
|
plugins: [`${esbuildApp}/replace-text.plugin.mjs`],
|
|
};
|
|
return config;
|
|
});
|
|
|
|
runCLI(`build ${esbuildApp} --configuration=development`);
|
|
|
|
let mainBundle = readFile(`dist/${esbuildApp}/browser/main.js`);
|
|
expect(mainBundle).toContain(
|
|
'buildDefined = "Value was provided at build time";'
|
|
);
|
|
|
|
// check @nx/angular:browser-esbuild
|
|
updateJson(join(esbuildApp, 'project.json'), (config) => {
|
|
config.targets.build.executor = '@nx/angular:browser-esbuild';
|
|
config.targets.build.options = {
|
|
...config.targets.build.options,
|
|
main: config.targets.build.options.browser,
|
|
browser: undefined,
|
|
};
|
|
return config;
|
|
});
|
|
|
|
runCLI(`build ${esbuildApp} --configuration=development`);
|
|
|
|
mainBundle = readFile(`dist/${esbuildApp}/main.js`);
|
|
expect(mainBundle).toContain(
|
|
'buildDefined = "Value was provided at build time";'
|
|
);
|
|
});
|
|
|
|
it('should support providing a transformer function for the "index.html" file with the application executor', async () => {
|
|
updateFile(
|
|
`${esbuildApp}/index.transformer.mjs`,
|
|
`const indexHtmlTransformer = (indexContent) => {
|
|
return indexContent.replace(
|
|
'<title>${esbuildApp}</title>',
|
|
'<title>${esbuildApp} (transformed)</title>'
|
|
);
|
|
};
|
|
|
|
export default indexHtmlTransformer;`
|
|
);
|
|
|
|
updateJson(join(esbuildApp, 'project.json'), (config) => {
|
|
config.targets.build.executor = '@nx/angular:application';
|
|
config.targets.build.options = {
|
|
...config.targets.build.options,
|
|
indexHtmlTransformer: `${esbuildApp}/index.transformer.mjs`,
|
|
};
|
|
return config;
|
|
});
|
|
|
|
runCLI(`build ${esbuildApp}`);
|
|
|
|
let indexHtmlContent = readFile(`dist/${esbuildApp}/browser/index.html`);
|
|
expect(indexHtmlContent).toContain(
|
|
`<title>${esbuildApp} (transformed)</title>`
|
|
);
|
|
});
|
|
|
|
it('should build publishable libs successfully', () => {
|
|
// ARRANGE
|
|
const lib = uniq('lib');
|
|
const childLib = uniq('child');
|
|
const entryPoint = uniq('entrypoint');
|
|
|
|
runCLI(
|
|
`generate @nx/angular:lib ${lib} --publishable --importPath=@${proj}/${lib} --no-standalone --no-interactive`
|
|
);
|
|
runCLI(
|
|
`generate @nx/angular:secondary-entry-point --name=${entryPoint} --library=${lib} --no-interactive`
|
|
);
|
|
|
|
runCLI(
|
|
`generate @nx/angular:library ${childLib} --publishable=true --importPath=@${proj}/${childLib} --no-standalone --no-interactive`
|
|
);
|
|
runCLI(
|
|
`generate @nx/angular:secondary-entry-point --name=sub --library=${childLib} --no-interactive`
|
|
);
|
|
|
|
const moduleContent = `
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { ${
|
|
names(childLib).className
|
|
}Module } from '@${proj}/${childLib}';
|
|
import { SubModule } from '@${proj}/${childLib}/sub';
|
|
@NgModule({
|
|
imports: [CommonModule, ${names(childLib).className}Module, SubModule]
|
|
})
|
|
export class ${names(lib).className}Module {}`;
|
|
|
|
updateFile(`${lib}/src/lib/${lib}.module.ts`, moduleContent);
|
|
|
|
// ACT
|
|
const buildOutput = runCLI(`build ${lib}`, { env: { CI: 'false' } });
|
|
|
|
// ASSERT
|
|
expect(buildOutput).toContain(`Building entry point '@${proj}/${lib}'`);
|
|
expect(buildOutput).toContain(
|
|
`Building entry point '@${proj}/${lib}/${entryPoint}'`
|
|
);
|
|
expect(buildOutput).toContain('Successfully ran target build');
|
|
|
|
expect(() => runCLI(`lint ${lib} --fix`)).not.toThrow();
|
|
expect(() => runCLI(`lint ${childLib} --fix`)).not.toThrow();
|
|
});
|
|
|
|
it('should support generating libraries with a scoped name when', () => {
|
|
const libName = uniq('@my-org/lib1');
|
|
|
|
runCLI(`generate @nx/angular:lib ${libName} --buildable --standalone`);
|
|
|
|
// check files are generated without the layout directory ("libs/") and
|
|
// using the project name as the directory when no directory is provided
|
|
checkFilesExist(
|
|
`${libName}/src/index.ts`,
|
|
`${libName}/src/lib/${libName.split('/')[1]}/${
|
|
libName.split('/')[1]
|
|
}.component.ts`
|
|
);
|
|
// check build works
|
|
expect(() => runCLI(`build ${libName}`)).not.toThrow();
|
|
// check tests pass
|
|
expect(() => runCLI(`test ${libName}`)).not.toThrow();
|
|
}, 500_000);
|
|
|
|
it('should support generating applications with SSR and converting targets with webpack-based executors to use the application executor', async () => {
|
|
const esbuildApp = uniq('esbuild-app');
|
|
const webpackApp = uniq('webpack-app');
|
|
|
|
runCLI(
|
|
`generate @nx/angular:app ${esbuildApp} --bundler=esbuild --ssr --no-interactive`
|
|
);
|
|
|
|
// check build produces both the browser and server bundles
|
|
runCLI(`build ${esbuildApp} --output-hashing none`);
|
|
checkFilesExist(
|
|
`dist/${esbuildApp}/browser/main.js`,
|
|
`dist/${esbuildApp}/server/server.mjs`
|
|
);
|
|
|
|
runCLI(
|
|
`generate @nx/angular:app ${webpackApp} --bundler=webpack --ssr --no-interactive`
|
|
);
|
|
|
|
// check build only produces the browser bundle
|
|
runCLI(`build ${webpackApp} --output-hashing none`);
|
|
checkFilesExist(`dist/${webpackApp}/browser/main.js`);
|
|
checkFilesDoNotExist(`dist/${webpackApp}/server/main.js`);
|
|
|
|
// check server produces the server bundle
|
|
runCLI(`server ${webpackApp} --output-hashing none`);
|
|
checkFilesExist(`dist/${webpackApp}/server/main.js`);
|
|
|
|
rmDist();
|
|
|
|
// convert target with webpack-based executors to use the application executor
|
|
runCLI(
|
|
`generate @nx/angular:convert-to-application-executor ${webpackApp}`
|
|
);
|
|
|
|
// check build now produces both the browser and server bundles
|
|
runCLI(`build ${webpackApp} --output-hashing none`);
|
|
checkFilesExist(
|
|
`dist/${webpackApp}/browser/main.js`,
|
|
`dist/${webpackApp}/server/server.mjs`
|
|
);
|
|
|
|
// check server target is no longer available
|
|
expect(() =>
|
|
runCLI(`server ${webpackApp} --output-hashing none`)
|
|
).toThrow();
|
|
}, 500_000);
|
|
|
|
// TODO: enable this test once vitest issue is resolved
|
|
it.skip('should generate apps and libs with vitest', async () => {
|
|
const app = uniq('app');
|
|
const lib = uniq('lib');
|
|
|
|
runCLI(
|
|
`generate @nx/angular:app ${app} --unit-test-runner=vitest --no-interactive`
|
|
);
|
|
runCLI(
|
|
`generate @nx/angular:lib ${lib} --unit-test-runner=vitest --no-interactive`
|
|
);
|
|
|
|
// Make sure we are using vitest
|
|
checkFilesExist(`${app}/vite.config.mts`, `${lib}/vite.config.mts`);
|
|
|
|
runCLI(`run-many --target test --projects=${app},${lib} --parallel`);
|
|
});
|
|
});
|