fix(misc): update e2e config generators to align with new TS solution setup (#29638)

This PR updates the `@nx/detox:app` generator to match the new TS
solution setup. The `@nx/cypress:configuration` and
`@nx/cypress:configuration` generators are also updated so that they can
be run on existing projects and generator the correct tsconfig files.

The Playwright/Cypress example can be seen as follows:

```shell
# Skip e2e
nx g @nx/react:app apps/demo --bundler vite --e2eTestRunner none

# now configure e2e
nx g @nx/playwright --project demo
```

Now if you add this line to `apps/demo/e2e/example.spec.ts`:
```
const x: number = 'a';
```

And run `nx typecheck demo`, it will pass. This happens because the
`e2e/**/*.ts` pattern is missing. Thus, we need to ensure that a
`tsconfig.e2e.json` project is added for the Playwright spec files. Same
thing with Cypress.

The Detox generator does not support adding configuration to existing
project, so we don't quite get the same problem. The fix for Detox is
just to make sure the tsconfig content is not following the old
(integrated) version, but the updated TS solution version.

## Current Behavior
Detox TS setup is incorrect. Running Cypress and Playwright
configuration generator on existing projects generate invalid setup,
such that spec files are not typechecked.

## Expected Behavior
E2E generators should all generate correct TS setup.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
This commit is contained in:
Jack Hsu 2025-01-16 13:10:34 -05:00 committed by GitHub
parent 8a6e44b788
commit 1e032fb9e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 464 additions and 24 deletions

View File

@ -37,14 +37,25 @@ export function addBaseCypressSetup(
} }
const opts = normalizeOptions(tree, projectConfig, options); const opts = normalizeOptions(tree, projectConfig, options);
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(tree);
const templateVars = { const templateVars = {
...opts, ...opts,
jsx: !!opts.jsx, jsx: !!opts.jsx,
offsetFromRoot: offsetFromRoot(projectConfig.root), offsetFromRoot: offsetFromRoot(projectConfig.root),
offsetFromProjectRoot: opts.hasTsConfig ? opts.offsetFromProjectRoot : '', offsetFromProjectRoot: opts.hasTsConfig ? opts.offsetFromProjectRoot : '',
tsConfigPath: opts.hasTsConfig tsConfigPath:
? `${opts.offsetFromProjectRoot}tsconfig.json` // TS solution setup should always extend from tsconfig.base.json to use shared compilerOptions, the project's tsconfig.json will not have compilerOptions.
: getRelativePathToRootTsConfig(tree, projectConfig.root), isUsingTsSolutionConfig
? getRelativePathToRootTsConfig(
tree,
opts.hasTsConfig
? joinPathFragments(projectConfig.root, options.directory)
: // If an existing tsconfig.json file does not exist, then cypress tsconfig will be moved to the project root.
projectConfig.root
)
: opts.hasTsConfig
? `${opts.offsetFromProjectRoot}tsconfig.json`
: getRelativePathToRootTsConfig(tree, projectConfig.root),
linter: isEslintInstalled(tree) ? 'eslint' : 'none', linter: isEslintInstalled(tree) ? 'eslint' : 'none',
ext: '', ext: '',
}; };
@ -58,7 +69,7 @@ export function addBaseCypressSetup(
generateFiles( generateFiles(
tree, tree,
isUsingTsSolutionSetup(tree) isUsingTsSolutionConfig
? join(__dirname, 'files/tsconfig/ts-solution') ? join(__dirname, 'files/tsconfig/ts-solution')
: join(__dirname, 'files/tsconfig/non-ts-solution'), : join(__dirname, 'files/tsconfig/non-ts-solution'),
projectConfig.root, projectConfig.root,

View File

@ -8,6 +8,7 @@ import {
Tree, Tree,
updateJson, updateJson,
updateProjectConfiguration, updateProjectConfiguration,
writeJson,
} from '@nx/devkit'; } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import cypressE2EConfigurationGenerator from './configuration'; import cypressE2EConfigurationGenerator from './configuration';
@ -555,6 +556,77 @@ export default defineConfig({
" "
`); `);
}); });
describe('TS Solution Setup', () => {
beforeEach(() => {
updateJson(tree, 'package.json', (json) => {
json.workspaces = ['packages/*', 'apps/*'];
return json;
});
writeJson(tree, 'tsconfig.base.json', {
compilerOptions: {
composite: true,
declaration: true,
},
});
writeJson(tree, 'tsconfig.json', {
extends: './tsconfig.base.json',
files: [],
references: [],
});
});
it('should handle existing tsconfig.json files', async () => {
addProject(tree, { name: 'my-lib', type: 'libs' });
writeJson(tree, 'libs/my-lib/tsconfig.json', {
include: [],
files: [],
references: [],
});
await cypressE2EConfigurationGenerator(tree, {
project: 'my-lib',
baseUrl: 'http://localhost:4200',
js: true,
});
expect(tree.read('libs/my-lib/tsconfig.json', 'utf-8'))
.toMatchInlineSnapshot(`
"{
"include": [],
"files": [],
"references": [
{
"path": "./src/tsconfig.json"
}
]
}
"
`);
expect(tree.read('libs/my-lib/src/tsconfig.json', 'utf-8'))
.toMatchInlineSnapshot(`
"{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "out-tsc/cypress",
"allowJs": true,
"types": ["cypress", "node"],
"sourceMap": false
},
"include": [
"**/*.ts",
"**/*.js",
"../cypress.config.ts",
"../**/*.cy.ts",
"../**/*.cy.js",
"../**/*.d.ts"
],
"exclude": ["out-tsc", "test-output"]
}
"
`);
});
});
}); });
}); });

View File

@ -5,6 +5,8 @@ import {
readJson, readJson,
readProjectConfiguration, readProjectConfiguration,
Tree, Tree,
updateJson,
writeJson,
} from '@nx/devkit'; } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Linter } from '@nx/eslint/src/generators/utils/linter'; import { Linter } from '@nx/eslint/src/generators/utils/linter';
@ -396,8 +398,38 @@ describe('detox application generator', () => {
addPlugin: true, addPlugin: true,
}); });
const tsConfig = readJson(tree, 'my-app-e2e/tsconfig.json'); expect(readJson(tree, 'my-app-e2e/tsconfig.json')).toMatchInlineSnapshot(`
expect(tsConfig.extends).toEqual('../tsconfig.base.json'); {
"extends": "../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.e2e.json",
},
],
}
`);
expect(readJson(tree, 'my-app-e2e/tsconfig.e2e.json'))
.toMatchInlineSnapshot(`
{
"compilerOptions": {
"allowJs": true,
"outDir": "../dist/out-tsc",
"sourceMap": false,
"types": [
"node",
"jest",
"detox",
],
},
"extends": "./tsconfig.json",
"include": [
"src/**/*.ts",
"src/**/*.js",
],
}
`);
}); });
it('should support a root tsconfig.json instead of tsconfig.base.json', async () => { it('should support a root tsconfig.json instead of tsconfig.base.json', async () => {
@ -411,8 +443,120 @@ describe('detox application generator', () => {
addPlugin: true, addPlugin: true,
}); });
const tsConfig = readJson(tree, 'my-app-e2e/tsconfig.json'); expect(readJson(tree, 'my-app-e2e/tsconfig.json')).toMatchInlineSnapshot(`
expect(tsConfig.extends).toEqual('../tsconfig.json'); {
"extends": "../tsconfig.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.e2e.json",
},
],
}
`);
expect(readJson(tree, 'my-app-e2e/tsconfig.e2e.json'))
.toMatchInlineSnapshot(`
{
"compilerOptions": {
"allowJs": true,
"outDir": "../dist/out-tsc",
"sourceMap": false,
"types": [
"node",
"jest",
"detox",
],
},
"extends": "./tsconfig.json",
"include": [
"src/**/*.ts",
"src/**/*.js",
],
}
`);
});
});
describe('TS Solution Setup', () => {
beforeEach(() => {
updateJson(tree, 'package.json', (json) => {
json.workspaces = ['packages/*', 'apps/*'];
return json;
});
writeJson(tree, 'tsconfig.base.json', {
compilerOptions: {
composite: true,
declaration: true,
},
});
writeJson(tree, 'tsconfig.json', {
extends: './tsconfig.base.json',
files: [],
references: [],
});
});
it('should create tsconfig.json and update project references', async () => {
writeJson(tree, 'apps/my-app/package.json', {
name: 'my-app',
});
await detoxApplicationGenerator(tree, {
e2eDirectory: 'apps/my-app-e2e',
appProject: 'my-app',
linter: Linter.None,
framework: 'react-native',
addPlugin: true,
});
expect(tree.read('tsconfig.json', 'utf-8')).toMatchInlineSnapshot(`
"{
"extends": "./tsconfig.base.json",
"files": [],
"references": [
{
"path": "./apps/my-app-e2e"
}
]
}
"
`);
expect(tree.read('apps/my-app-e2e/package.json', 'utf-8'))
.toMatchInlineSnapshot(`
"{
"name": "my-app-e2e",
"version": "0.0.1",
"private": true,
"nx": {
"sourceRoot": "apps/my-app-e2e/src",
"projectType": "application",
"implicitDependencies": [
"my-app"
]
}
}
"
`);
expect(tree.read('apps/my-app-e2e/tsconfig.json', 'utf-8'))
.toMatchInlineSnapshot(`
"{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"sourceMap": false,
"outDir": "out-tsc/detox",
"allowJs": true,
"types": ["node", "jest", "detox"],
"rootDir": "src",
"module": "esnext",
"moduleResolution": "bundler",
"tsBuildInfoFile": "out-tsc/detox/tsconfig.tsbuildinfo"
},
"include": ["src/**/*.ts", "src/**/*.js"],
"exclude": ["out-tsc", "dist", "test-output"]
}
"
`);
}); });
}); });
}); });

View File

@ -9,6 +9,11 @@ import { createFiles } from './lib/create-files';
import { normalizeOptions } from './lib/normalize-options'; import { normalizeOptions } from './lib/normalize-options';
import { Schema } from './schema'; import { Schema } from './schema';
import { ensureDependencies } from './lib/ensure-dependencies'; import { ensureDependencies } from './lib/ensure-dependencies';
import {
addProjectToTsSolutionWorkspace,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';
import { sortPackageJsonFields } from '@nx/js/src/utils/package-json/sort-fields';
export async function detoxApplicationGenerator(host: Tree, schema: Schema) { export async function detoxApplicationGenerator(host: Tree, schema: Schema) {
return await detoxApplicationGeneratorInternal(host, { return await detoxApplicationGeneratorInternal(host, {
@ -38,6 +43,28 @@ export async function detoxApplicationGeneratorInternal(
const lintingTask = await addLinting(host, options); const lintingTask = await addLinting(host, options);
const depsTask = ensureDependencies(host, options); const depsTask = ensureDependencies(host, options);
updateTsconfigFiles(
host,
options.e2eProjectRoot,
'tsconfig.json',
{
module: 'esnext',
moduleResolution: 'bundler',
outDir: 'out-tsc/detox',
allowJs: true,
types: ['node', 'jest', 'detox'],
},
options.linter === 'eslint'
? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
: undefined
);
if (options.isUsingTsSolutionConfig) {
addProjectToTsSolutionWorkspace(host, options.e2eProjectRoot);
}
sortPackageJsonFields(host, options.e2eProjectRoot);
if (!options.skipFormat) { if (!options.skipFormat) {
await formatFiles(host); await formatFiles(host);
} }

View File

@ -20,6 +20,7 @@ describe('Add Linting', () => {
appExpoName: 'MyApp', appExpoName: 'MyApp',
appRoot: 'apps/my-app', appRoot: 'apps/my-app',
linter: Linter.EsLint, linter: Linter.EsLint,
isUsingTsSolutionConfig: false,
framework: 'react-native', framework: 'react-native',
}); });
}); });
@ -36,6 +37,7 @@ describe('Add Linting', () => {
appExpoName: 'MyApp', appExpoName: 'MyApp',
appRoot: 'apps/my-app', appRoot: 'apps/my-app',
linter: Linter.EsLint, linter: Linter.EsLint,
isUsingTsSolutionConfig: false,
framework: 'react-native', framework: 'react-native',
}); });
@ -54,6 +56,7 @@ describe('Add Linting', () => {
appExpoName: 'MyApp', appExpoName: 'MyApp',
appRoot: 'apps/my-app', appRoot: 'apps/my-app',
linter: Linter.None, linter: Linter.None,
isUsingTsSolutionConfig: false,
framework: 'react-native', framework: 'react-native',
}); });
const project = readProjectConfiguration(tree, 'my-app-e2e'); const project = readProjectConfiguration(tree, 'my-app-e2e');

View File

@ -2,24 +2,56 @@ import {
detectPackageManager, detectPackageManager,
generateFiles, generateFiles,
getPackageManagerCommand, getPackageManagerCommand,
offsetFromRoot, offsetFromRoot as _offsetFromRoot,
toJS, toJS,
Tree, Tree,
writeJson,
joinPathFragments,
} from '@nx/devkit'; } from '@nx/devkit';
import { getRelativePathToRootTsConfig } from '@nx/js'; import { getRelativePathToRootTsConfig } from '@nx/js';
import { join } from 'path'; import { join } from 'path';
import { NormalizedSchema } from './normalize-options'; import { NormalizedSchema } from './normalize-options';
export function createFiles(host: Tree, options: NormalizedSchema) { export function createFiles(host: Tree, options: NormalizedSchema) {
const offsetFromRoot = _offsetFromRoot(options.e2eProjectRoot);
const rootTsConfigPath = getRelativePathToRootTsConfig(
host,
options.e2eProjectRoot
);
generateFiles(host, join(__dirname, '../files/app'), options.e2eProjectRoot, { generateFiles(host, join(__dirname, '../files/app'), options.e2eProjectRoot, {
...options, ...options,
exec: getPackageManagerCommand(detectPackageManager(host.root)).exec, exec: getPackageManagerCommand(detectPackageManager(host.root)).exec,
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot), offsetFromRoot,
rootTsConfigPath: getRelativePathToRootTsConfig( rootTsConfigPath,
host,
options.e2eProjectRoot
),
}); });
if (options.isUsingTsSolutionConfig) {
writeJson(
host,
joinPathFragments(options.e2eProjectRoot, 'tsconfig.json'),
{
extends: `${offsetFromRoot}tsconfig.base.json`,
compilerOptions: {
sourceMap: false,
outDir: 'out-tsc/detox',
allowJs: true,
types: ['node', 'jest', 'detox'],
},
include: ['src/**/*.ts', 'src/**/*.js'],
exclude: ['out-tsc', 'test-output'],
}
);
} else {
generateFiles(
host,
join(__dirname, '../files/non-ts-solution'),
options.e2eProjectRoot,
{
...options,
offsetFromRoot,
rootTsConfigPath,
}
);
}
if (options.js) { if (options.js) {
toJS(host); toJS(host);
} }

View File

@ -37,6 +37,7 @@ describe('Normalize Options', () => {
appDisplayName: 'MyApp', appDisplayName: 'MyApp',
appExpoName: 'MyApp', appExpoName: 'MyApp',
appRoot: 'apps/my-app', appRoot: 'apps/my-app',
isUsingTsSolutionConfig: false,
linter: Linter.EsLint, linter: Linter.EsLint,
}); });
}); });
@ -66,6 +67,7 @@ describe('Normalize Options', () => {
e2eProjectName: 'my-app-e2e', e2eProjectName: 'my-app-e2e',
e2eProjectRoot: 'apps/my-app-e2e', e2eProjectRoot: 'apps/my-app-e2e',
framework: 'react-native', framework: 'react-native',
isUsingTsSolutionConfig: false,
}); });
}); });
@ -94,6 +96,7 @@ describe('Normalize Options', () => {
e2eDirectory: 'directory', e2eDirectory: 'directory',
e2eProjectName: 'directory-my-app-e2e', e2eProjectName: 'directory-my-app-e2e',
framework: 'react-native', framework: 'react-native',
isUsingTsSolutionConfig: false,
}); });
}); });
}); });

View File

@ -4,6 +4,7 @@ import {
ensureProjectName, ensureProjectName,
} from '@nx/devkit/src/generators/project-name-and-root-utils'; } from '@nx/devkit/src/generators/project-name-and-root-utils';
import { Schema } from '../schema'; import { Schema } from '../schema';
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
export interface NormalizedSchema extends Schema { export interface NormalizedSchema extends Schema {
appFileName: string; // the file name of app to be tested in kebab case appFileName: string; // the file name of app to be tested in kebab case
@ -12,6 +13,7 @@ export interface NormalizedSchema extends Schema {
appRoot: string; // the root path of e2e project. e.g. apps/app-directory/app appRoot: string; // the root path of e2e project. e.g. apps/app-directory/app
e2eProjectName: string; // the name of e2e project e2eProjectName: string; // the name of e2e project
e2eProjectRoot: string; // the root path of e2e project. e.g. apps/e2e-directory/e2e-app e2eProjectRoot: string; // the root path of e2e project. e.g. apps/e2e-directory/e2e-app
isUsingTsSolutionConfig?: boolean;
} }
export async function normalizeOptions( export async function normalizeOptions(
@ -45,5 +47,6 @@ export async function normalizeOptions(
e2eName: e2eProjectName, e2eName: e2eProjectName,
e2eProjectName, e2eProjectName,
e2eProjectRoot, e2eProjectRoot,
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
}; };
} }

View File

@ -0,0 +1,114 @@
import 'nx/src/internal-testing-utils/mock-project-graph';
import { Tree, updateJson, writeJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import configGenerator from './configuration';
describe('Playwright e2e configuration', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});
afterAll(() => {
jest.resetAllMocks();
});
describe('TS Solution Setup', () => {
beforeEach(() => {
updateJson(tree, 'package.json', (json) => {
json.workspaces = ['packages/*', 'apps/*'];
return json;
});
writeJson(tree, 'tsconfig.base.json', {
compilerOptions: {
composite: true,
declaration: true,
},
});
writeJson(tree, 'tsconfig.json', {
extends: './tsconfig.base.json',
files: [],
references: [],
});
});
it('should create tsconfig.json if it does not exist yet (default case for app generators)', async () => {
writeJson(tree, 'apps/myapp-e2e/package.json', {
name: '@proj/myapp-e2e',
});
await configGenerator(tree, {
project: '@proj/myapp-e2e',
});
expect(tree.read('apps/myapp-e2e/tsconfig.json', 'utf-8'))
.toMatchInlineSnapshot(`
"{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"outDir": "out-tsc/playwright",
"sourceMap": false
},
"include": [
"**/*.ts",
"**/*.js",
"playwright.config.ts",
"src/**/*.spec.ts",
"src/**/*.spec.js",
"src/**/*.test.ts",
"src/**/*.test.js",
"src/**/*.d.ts"
],
"exclude": ["out-tsc", "test-output"]
}
"
`);
expect(tree.exists('apps/myapp/tsconfig.e2e.json')).toBeFalsy();
});
it('should use tsconfig.e2e.json if tsconfig.json already exists', async () => {
writeJson(tree, 'apps/myapp/package.json', {
name: '@proj/myapp',
});
writeJson(tree, 'apps/myapp/tsconfig.json', {
include: [],
files: [],
references: [],
});
await configGenerator(tree, {
project: '@proj/myapp',
});
expect(tree.read('apps/myapp/tsconfig.json', 'utf-8'))
.toMatchInlineSnapshot(`
"{
"include": [],
"files": [],
"references": [
{
"path": "./tsconfig.e2e.json"
}
]
}
"
`);
expect(tree.read('apps/myapp/tsconfig.e2e.json', 'utf-8'))
.toMatchInlineSnapshot(`
"{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"outDir": "out-tsc/playwright",
"sourceMap": false
},
"include": ["e2e/**/*.ts", "e2e/**/*.js", "playwright.config.ts"],
"exclude": ["out-tsc", "test-output"]
}
"
`);
});
});
});

View File

@ -74,7 +74,46 @@ export async function configurationGeneratorInternal(
const isTsSolutionSetup = isUsingTsSolutionSetup(tree); const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
const tsconfigPath = joinPathFragments(projectConfig.root, 'tsconfig.json'); const tsconfigPath = joinPathFragments(projectConfig.root, 'tsconfig.json');
if (!tree.exists(tsconfigPath)) { if (tree.exists(tsconfigPath)) {
if (isTsSolutionSetup) {
const tsconfig: any = {
extends: getRelativePathToRootTsConfig(tree, projectConfig.root),
compilerOptions: {
allowJs: true,
outDir: 'out-tsc/playwright',
sourceMap: false,
},
include: [
joinPathFragments(options.directory, '**/*.ts'),
joinPathFragments(options.directory, '**/*.js'),
'playwright.config.ts',
],
exclude: ['out-tsc', 'test-output'],
};
// skip eslint from typechecking since it extends from root file that is outside rootDir
if (options.linter === 'eslint') {
tsconfig.exclude.push(
'eslint.config.js',
'eslint.config.mjs',
'eslint.config.cjs'
);
}
writeJson(
tree,
joinPathFragments(projectConfig.root, 'tsconfig.e2e.json'),
tsconfig
);
updateJson(tree, tsconfigPath, (json) => {
// add the project tsconfig to the workspace root tsconfig.json references
json.references ??= [];
json.references.push({ path: './tsconfig.e2e.json' });
return json;
});
}
} else {
const tsconfig: any = { const tsconfig: any = {
extends: getRelativePathToRootTsConfig(tree, projectConfig.root), extends: getRelativePathToRootTsConfig(tree, projectConfig.root),
compilerOptions: { compilerOptions: {

View File

@ -1,7 +1,6 @@
import { defineConfig, devices } from '@playwright/test'; import { defineConfig, devices } from '@playwright/test';
import { nxE2EPreset } from '@nx/playwright/preset'; import { nxE2EPreset } from '@nx/playwright/preset';
<% if(!webServerCommand || !webServerAddress) { %>// eslint-disable-next-line @typescript-eslint/no-unused-vars <% } %> <% if (webServerCommand && webServerAddress) { %>import { workspaceRoot } from '@nx/devkit';<% } %>
import { workspaceRoot } from '@nx/devkit';
// For CI, you may want to set BASE_URL to the deployed application. // For CI, you may want to set BASE_URL to the deployed application.
const baseURL = process.env['BASE_URL'] || '<% if(webServerAddress) {%><%= webServerAddress %><% } else {%>http://localhost:3000<% } %>'; const baseURL = process.env['BASE_URL'] || '<% if(webServerAddress) {%><%= webServerAddress %><% } else {%>http://localhost:3000<% } %>';

View File

@ -134,7 +134,6 @@ describe('app', () => {
const snapshot = ` const snapshot = `
"import { defineConfig, devices } from '@playwright/test'; "import { defineConfig, devices } from '@playwright/test';
import { nxE2EPreset } from '@nx/playwright/preset'; import { nxE2EPreset } from '@nx/playwright/preset';
import { workspaceRoot } from '@nx/devkit'; import { workspaceRoot } from '@nx/devkit';
// For CI, you may want to set BASE_URL to the deployed application. // For CI, you may want to set BASE_URL to the deployed application.

View File

@ -156,7 +156,6 @@ export default defineConfig({
exports[`Remix Application Integrated Repo --e2eTestRunner should generate a playwright e2e application for the app 1`] = ` exports[`Remix Application Integrated Repo --e2eTestRunner should generate a playwright e2e application for the app 1`] = `
"import { defineConfig, devices } from '@playwright/test'; "import { defineConfig, devices } from '@playwright/test';
import { nxE2EPreset } from '@nx/playwright/preset'; import { nxE2EPreset } from '@nx/playwright/preset';
import { workspaceRoot } from '@nx/devkit'; import { workspaceRoot } from '@nx/devkit';
// For CI, you may want to set BASE_URL to the deployed application. // For CI, you may want to set BASE_URL to the deployed application.
@ -678,7 +677,6 @@ exports[`Remix Application Standalone Project Repo should create the application
exports[`Remix Application Standalone Project Repo should generate a playwright e2e application for the app 1`] = ` exports[`Remix Application Standalone Project Repo should generate a playwright e2e application for the app 1`] = `
"import { defineConfig, devices } from '@playwright/test'; "import { defineConfig, devices } from '@playwright/test';
import { nxE2EPreset } from '@nx/playwright/preset'; import { nxE2EPreset } from '@nx/playwright/preset';
import { workspaceRoot } from '@nx/devkit'; import { workspaceRoot } from '@nx/devkit';
// For CI, you may want to set BASE_URL to the deployed application. // For CI, you may want to set BASE_URL to the deployed application.

View File

@ -327,7 +327,6 @@ describe('App', () => {
exports[`application generator should set up project correctly with given options 5`] = ` exports[`application generator should set up project correctly with given options 5`] = `
"import { defineConfig, devices } from '@playwright/test'; "import { defineConfig, devices } from '@playwright/test';
import { nxE2EPreset } from '@nx/playwright/preset'; import { nxE2EPreset } from '@nx/playwright/preset';
import { workspaceRoot } from '@nx/devkit'; import { workspaceRoot } from '@nx/devkit';
// For CI, you may want to set BASE_URL to the deployed application. // For CI, you may want to set BASE_URL to the deployed application.

View File

@ -3,7 +3,6 @@
exports[`app not nested should generate files if bundler is vite 1`] = ` exports[`app not nested should generate files if bundler is vite 1`] = `
"import { defineConfig, devices } from '@playwright/test'; "import { defineConfig, devices } from '@playwright/test';
import { nxE2EPreset } from '@nx/playwright/preset'; import { nxE2EPreset } from '@nx/playwright/preset';
import { workspaceRoot } from '@nx/devkit'; import { workspaceRoot } from '@nx/devkit';
// For CI, you may want to set BASE_URL to the deployed application. // For CI, you may want to set BASE_URL to the deployed application.
@ -76,7 +75,6 @@ export default defineConfig({
exports[`app not nested should setup playwright e2e project correctly for webpack 1`] = ` exports[`app not nested should setup playwright e2e project correctly for webpack 1`] = `
"import { defineConfig, devices } from '@playwright/test'; "import { defineConfig, devices } from '@playwright/test';
import { nxE2EPreset } from '@nx/playwright/preset'; import { nxE2EPreset } from '@nx/playwright/preset';
import { workspaceRoot } from '@nx/devkit'; import { workspaceRoot } from '@nx/devkit';
// For CI, you may want to set BASE_URL to the deployed application. // For CI, you may want to set BASE_URL to the deployed application.
@ -149,7 +147,6 @@ export default defineConfig({
exports[`app not nested should use serve target and port if bundler=vite, e2eTestRunner=playwright, addPlugin=false 1`] = ` exports[`app not nested should use serve target and port if bundler=vite, e2eTestRunner=playwright, addPlugin=false 1`] = `
"import { defineConfig, devices } from '@playwright/test'; "import { defineConfig, devices } from '@playwright/test';
import { nxE2EPreset } from '@nx/playwright/preset'; import { nxE2EPreset } from '@nx/playwright/preset';
import { workspaceRoot } from '@nx/devkit'; import { workspaceRoot } from '@nx/devkit';
// For CI, you may want to set BASE_URL to the deployed application. // For CI, you may want to set BASE_URL to the deployed application.