chore(react): improve react e2e tests speed (#15997)
This commit is contained in:
parent
d54f848810
commit
5f86929f34
15
.github/workflows/e2e-matrix.yml
vendored
15
.github/workflows/e2e-matrix.yml
vendored
@ -118,7 +118,8 @@ jobs:
|
|||||||
- e2e-nx-misc
|
- e2e-nx-misc
|
||||||
- e2e-nx-plugin
|
- e2e-nx-plugin
|
||||||
- e2e-nx-run
|
- e2e-nx-run
|
||||||
- e2e-react
|
- e2e-react-core
|
||||||
|
- e2e-react-extensions
|
||||||
- e2e-react-native
|
- e2e-react-native
|
||||||
- e2e-web
|
- e2e-web
|
||||||
- e2e-rollup
|
- e2e-rollup
|
||||||
@ -172,7 +173,9 @@ jobs:
|
|||||||
codeowners: 'S04SYHYKGNP'
|
codeowners: 'S04SYHYKGNP'
|
||||||
- project: e2e-nx-run
|
- project: e2e-nx-run
|
||||||
codeowners: 'S04SYHYKGNP'
|
codeowners: 'S04SYHYKGNP'
|
||||||
- project: e2e-react
|
- project: e2e-react-core
|
||||||
|
codeowners: 'S04TNCNJG5N'
|
||||||
|
- project: e2e-react-extensions
|
||||||
codeowners: 'S04TNCNJG5N'
|
codeowners: 'S04TNCNJG5N'
|
||||||
- project: e2e-react-native
|
- project: e2e-react-native
|
||||||
codeowners: 'S04TNCNJG5N'
|
codeowners: 'S04TNCNJG5N'
|
||||||
@ -232,7 +235,9 @@ jobs:
|
|||||||
- node_version: 16
|
- node_version: 16
|
||||||
project: e2e-lerna-smoke-tests
|
project: e2e-lerna-smoke-tests
|
||||||
- node_version: 16
|
- node_version: 16
|
||||||
project: e2e-react
|
project: e2e-react-core
|
||||||
|
- node_version: 16
|
||||||
|
project: e2e-react-extensions
|
||||||
- node_version: 16
|
- node_version: 16
|
||||||
project: e2e-react-native
|
project: e2e-react-native
|
||||||
- node_version: 16
|
- node_version: 16
|
||||||
@ -278,7 +283,9 @@ jobs:
|
|||||||
- node_version: 19
|
- node_version: 19
|
||||||
project: e2e-lerna-smoke-tests
|
project: e2e-lerna-smoke-tests
|
||||||
- node_version: 19
|
- node_version: 19
|
||||||
project: e2e-react
|
project: e2e-react-core
|
||||||
|
- node_version: 19
|
||||||
|
project: e2e-react-extensions
|
||||||
- node_version: 19
|
- node_version: 19
|
||||||
project: e2e-react-native
|
project: e2e-react-native
|
||||||
- node_version: 19
|
- node_version: 19
|
||||||
|
|||||||
15
.github/workflows/e2e-windows.yml
vendored
15
.github/workflows/e2e-windows.yml
vendored
@ -87,7 +87,8 @@ jobs:
|
|||||||
- e2e-nx-misc
|
- e2e-nx-misc
|
||||||
- e2e-nx-plugin
|
- e2e-nx-plugin
|
||||||
- e2e-nx-run
|
- e2e-nx-run
|
||||||
- e2e-react
|
- e2e-react-core
|
||||||
|
- e2e-react-extensions
|
||||||
- e2e-web
|
- e2e-web
|
||||||
- e2e-rollup
|
- e2e-rollup
|
||||||
- e2e-storybook
|
- e2e-storybook
|
||||||
@ -126,7 +127,9 @@ jobs:
|
|||||||
codeowners: 'S04SYHYKGNP'
|
codeowners: 'S04SYHYKGNP'
|
||||||
- project: e2e-nx-run
|
- project: e2e-nx-run
|
||||||
codeowners: 'S04SYHYKGNP'
|
codeowners: 'S04SYHYKGNP'
|
||||||
- project: e2e-react
|
- project: e2e-react-core
|
||||||
|
codeowners: 'S04TNCNJG5N'
|
||||||
|
- project: e2e-react-extensions
|
||||||
codeowners: 'S04TNCNJG5N'
|
codeowners: 'S04TNCNJG5N'
|
||||||
- project: e2e-web
|
- project: e2e-web
|
||||||
codeowners: 'S04SJ6PL98X'
|
codeowners: 'S04SJ6PL98X'
|
||||||
@ -173,7 +176,9 @@ jobs:
|
|||||||
- node_version: 16
|
- node_version: 16
|
||||||
project: e2e-lerna-smoke-tests
|
project: e2e-lerna-smoke-tests
|
||||||
- node_version: 16
|
- node_version: 16
|
||||||
project: e2e-react
|
project: e2e-react-core
|
||||||
|
- node_version: 16
|
||||||
|
project: e2e-react-extensions
|
||||||
- node_version: 16
|
- node_version: 16
|
||||||
project: e2e-web
|
project: e2e-web
|
||||||
- node_version: 16
|
- node_version: 16
|
||||||
@ -213,7 +218,9 @@ jobs:
|
|||||||
- node_version: 19
|
- node_version: 19
|
||||||
project: e2e-lerna-smoke-tests
|
project: e2e-lerna-smoke-tests
|
||||||
- node_version: 19
|
- node_version: 19
|
||||||
project: e2e-react
|
project: e2e-react-core
|
||||||
|
- node_version: 19
|
||||||
|
project: e2e-react-extensions
|
||||||
- node_version: 19
|
- node_version: 19
|
||||||
project: e2e-web
|
project: e2e-web
|
||||||
- node_version: 19
|
- node_version: 19
|
||||||
|
|||||||
@ -33,7 +33,8 @@ yarn.lock @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
|
|||||||
/docs/shared/packages/react/** @jaysoo @ndcunningham @mandarini @xiongemi
|
/docs/shared/packages/react/** @jaysoo @ndcunningham @mandarini @xiongemi
|
||||||
/docs/shared/packages/next/** @jaysoo @ndcunningham @xiongemi
|
/docs/shared/packages/next/** @jaysoo @ndcunningham @xiongemi
|
||||||
/packages/react/** @jaysoo @ndcunningham @mandarini @xiongemi
|
/packages/react/** @jaysoo @ndcunningham @mandarini @xiongemi
|
||||||
/e2e/react/** @jaysoo @mandarini @xiongemi @ndcunningham
|
/e2e/react-core/** @jaysoo @mandarini @xiongemi @ndcunningham
|
||||||
|
/e2e/react-extensions/** @jaysoo @mandarini @xiongemi @ndcunningham
|
||||||
/packages/next/** @ndcunningham @jaysoo @xiongemi
|
/packages/next/** @ndcunningham @jaysoo @xiongemi
|
||||||
/e2e/next/** @ndcunningham @jaysoo @xiongemi
|
/e2e/next/** @ndcunningham @jaysoo @xiongemi
|
||||||
/packages/react/plugins/component-testing/** @jaysoo @ndcunningham @barbados-clemens
|
/packages/react/plugins/component-testing/** @jaysoo @ndcunningham @barbados-clemens
|
||||||
|
|||||||
@ -6,6 +6,6 @@ export default {
|
|||||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||||
maxWorkers: 1,
|
maxWorkers: 1,
|
||||||
globals: {},
|
globals: {},
|
||||||
displayName: 'e2e-react',
|
displayName: 'e2e-react-core',
|
||||||
preset: '../../jest.preset.js',
|
preset: '../../jest.preset.js',
|
||||||
};
|
};
|
||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "e2e-react",
|
"name": "e2e-react-core",
|
||||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||||
"sourceRoot": "e2e/react",
|
"sourceRoot": "e2e/react-core",
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"targets": {
|
"targets": {
|
||||||
"e2e": {},
|
"e2e": {},
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@ -15,9 +15,9 @@ import {
|
|||||||
describe('React Module Federation', () => {
|
describe('React Module Federation', () => {
|
||||||
let proj: string;
|
let proj: string;
|
||||||
|
|
||||||
beforeEach(() => (proj = newProject()));
|
beforeAll(() => (proj = newProject()));
|
||||||
|
|
||||||
afterEach(() => cleanupProject());
|
afterAll(() => cleanupProject());
|
||||||
|
|
||||||
it('should generate host and remote apps', async () => {
|
it('should generate host and remote apps', async () => {
|
||||||
const shell = uniq('shell');
|
const shell = uniq('shell');
|
||||||
@ -264,130 +264,3 @@ export async function h() { return 'c'; }
|
|||||||
}, 250000);
|
}, 250000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Build React applications and libraries with Vite', () => {
|
|
||||||
let proj: string;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
proj = newProject();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should test and lint app with bundler=vite', async () => {
|
|
||||||
const viteApp = uniq('viteapp');
|
|
||||||
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/react:app ${viteApp} --bundler=vite --unitTestRunner=vitest --no-interactive`
|
|
||||||
);
|
|
||||||
|
|
||||||
const appTestResults = await runCLIAsync(`test ${viteApp}`);
|
|
||||||
expect(appTestResults.combinedOutput).toContain(
|
|
||||||
'Successfully ran target test'
|
|
||||||
);
|
|
||||||
|
|
||||||
const appLintResults = await runCLIAsync(`lint ${viteApp}`);
|
|
||||||
expect(appLintResults.combinedOutput).toContain(
|
|
||||||
'Successfully ran target lint'
|
|
||||||
);
|
|
||||||
|
|
||||||
await runCLIAsync(`build ${viteApp}`);
|
|
||||||
checkFilesExist(`dist/apps/${viteApp}/index.html`);
|
|
||||||
}, 300_000);
|
|
||||||
|
|
||||||
it('should test and lint app with bundler=vite and inSourceTests', async () => {
|
|
||||||
const viteApp = uniq('viteapp');
|
|
||||||
const viteLib = uniq('vitelib');
|
|
||||||
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/react:app ${viteApp} --bundler=vite --unitTestRunner=vitest --inSourceTests --no-interactive`
|
|
||||||
);
|
|
||||||
expect(() => {
|
|
||||||
checkFilesExist(`apps/${viteApp}/src/app/app.spec.tsx`);
|
|
||||||
}).toThrow();
|
|
||||||
|
|
||||||
const appTestResults = await runCLIAsync(`test ${viteApp}`);
|
|
||||||
expect(appTestResults.combinedOutput).toContain(
|
|
||||||
'Successfully ran target test'
|
|
||||||
);
|
|
||||||
|
|
||||||
const appLintResults = await runCLIAsync(`lint ${viteApp}`);
|
|
||||||
expect(appLintResults.combinedOutput).toContain(
|
|
||||||
'Successfully ran target lint'
|
|
||||||
);
|
|
||||||
|
|
||||||
await runCLIAsync(`build ${viteApp}`);
|
|
||||||
checkFilesExist(`dist/apps/${viteApp}/index.html`);
|
|
||||||
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/react:lib ${viteLib} --bundler=vite --inSourceTests --unitTestRunner=vitest --no-interactive`
|
|
||||||
);
|
|
||||||
expect(() => {
|
|
||||||
checkFilesExist(`libs/${viteLib}/src/lib/${viteLib}.spec.tsx`);
|
|
||||||
}).toThrow();
|
|
||||||
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/react:component comp1 --inSourceTests --export --project=${viteLib} --no-interactive`
|
|
||||||
);
|
|
||||||
expect(() => {
|
|
||||||
checkFilesExist(`libs/${viteLib}/src/lib/comp1/comp1.spec.tsx`);
|
|
||||||
}).toThrow();
|
|
||||||
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/react:component comp2 --export --project=${viteLib} --no-interactive`
|
|
||||||
);
|
|
||||||
checkFilesExist(`libs/${viteLib}/src/lib/comp2/comp2.spec.tsx`);
|
|
||||||
|
|
||||||
const libTestResults = await runCLIAsync(`test ${viteLib}`);
|
|
||||||
expect(libTestResults.combinedOutput).toContain(
|
|
||||||
'Successfully ran target test'
|
|
||||||
);
|
|
||||||
|
|
||||||
const libLintResults = await runCLIAsync(`lint ${viteLib}`);
|
|
||||||
expect(libLintResults.combinedOutput).toContain(
|
|
||||||
'Successfully ran target lint'
|
|
||||||
);
|
|
||||||
|
|
||||||
await runCLIAsync(`build ${viteLib}`);
|
|
||||||
checkFilesExist(
|
|
||||||
`dist/libs/${viteLib}/index.d.ts`,
|
|
||||||
`dist/libs/${viteLib}/index.js`,
|
|
||||||
`dist/libs/${viteLib}/index.mjs`
|
|
||||||
);
|
|
||||||
}, 300_000);
|
|
||||||
|
|
||||||
it('should support bundling with Vite', async () => {
|
|
||||||
const viteLib = uniq('vitelib');
|
|
||||||
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/react:lib ${viteLib} --bundler=vite --no-interactive --unit-test-runner=none`
|
|
||||||
);
|
|
||||||
|
|
||||||
const packageJson = readJson('package.json');
|
|
||||||
// Vite does not need these libraries to work.
|
|
||||||
expect(packageJson.dependencies['core-js']).toBeUndefined();
|
|
||||||
expect(packageJson.dependencies['tslib']).toBeUndefined();
|
|
||||||
|
|
||||||
await runCLIAsync(`build ${viteLib}`);
|
|
||||||
|
|
||||||
checkFilesExist(
|
|
||||||
`dist/libs/${viteLib}/package.json`,
|
|
||||||
`dist/libs/${viteLib}/index.d.ts`,
|
|
||||||
`dist/libs/${viteLib}/index.js`,
|
|
||||||
`dist/libs/${viteLib}/index.mjs`
|
|
||||||
);
|
|
||||||
|
|
||||||
// Convert non-buildable lib to buildable one
|
|
||||||
const nonBuildableLib = uniq('nonbuildablelib');
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/react:lib ${nonBuildableLib} --no-interactive --unitTestRunner=jest`
|
|
||||||
);
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/vite:configuration ${nonBuildableLib} --uiFramework=react --no-interactive`
|
|
||||||
);
|
|
||||||
await runCLIAsync(`build ${nonBuildableLib}`);
|
|
||||||
checkFilesExist(
|
|
||||||
`dist/libs/${nonBuildableLib}/index.d.ts`,
|
|
||||||
`dist/libs/${nonBuildableLib}/index.js`,
|
|
||||||
`dist/libs/${nonBuildableLib}/index.mjs`
|
|
||||||
);
|
|
||||||
}, 300_000);
|
|
||||||
});
|
|
||||||
@ -21,12 +21,12 @@ import { join } from 'path';
|
|||||||
describe('React Applications', () => {
|
describe('React Applications', () => {
|
||||||
let proj: string;
|
let proj: string;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeAll(() => {
|
||||||
proj = newProject();
|
proj = newProject();
|
||||||
ensureCypressInstallation();
|
ensureCypressInstallation();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => cleanupProject());
|
afterAll(() => cleanupProject());
|
||||||
|
|
||||||
it('should be able to generate a react app + lib (with CSR and SSR)', async () => {
|
it('should be able to generate a react app + lib (with CSR and SSR)', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
@ -187,152 +187,183 @@ describe('React Applications', () => {
|
|||||||
expect(await killPorts()).toBeTruthy();
|
expect(await killPorts()).toBeTruthy();
|
||||||
}, 250_000);
|
}, 250_000);
|
||||||
|
|
||||||
async function testGeneratedApp(
|
it('should generate app with routing', async () => {
|
||||||
appName,
|
|
||||||
opts: {
|
|
||||||
checkStyles: boolean;
|
|
||||||
checkLinter: boolean;
|
|
||||||
checkE2E: boolean;
|
|
||||||
checkSourceMap?: boolean;
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
if (opts.checkLinter) {
|
|
||||||
const lintResults = runCLI(`lint ${appName}`);
|
|
||||||
expect(lintResults).toContain('All files pass linting.');
|
|
||||||
}
|
|
||||||
|
|
||||||
runCLI(
|
|
||||||
`build ${appName} --outputHashing none ${
|
|
||||||
opts.checkSourceMap ? '--sourceMap' : ''
|
|
||||||
}`
|
|
||||||
);
|
|
||||||
const filesToCheck = [
|
|
||||||
`dist/apps/${appName}/index.html`,
|
|
||||||
`dist/apps/${appName}/runtime.js`,
|
|
||||||
`dist/apps/${appName}/main.js`,
|
|
||||||
];
|
|
||||||
|
|
||||||
if (opts.checkSourceMap) {
|
|
||||||
filesToCheck.push(`dist/apps/${appName}/main.js.map`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.checkStyles) {
|
|
||||||
filesToCheck.push(`dist/apps/${appName}/styles.css`);
|
|
||||||
}
|
|
||||||
checkFilesExist(...filesToCheck);
|
|
||||||
|
|
||||||
if (opts.checkStyles) {
|
|
||||||
expect(readFile(`dist/apps/${appName}/index.html`)).toContain(
|
|
||||||
'<link rel="stylesheet" href="styles.css">'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const testResults = await runCLIAsync(`test ${appName}`);
|
|
||||||
expect(testResults.combinedOutput).toContain(
|
|
||||||
'Test Suites: 1 passed, 1 total'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (opts.checkE2E && runCypressTests()) {
|
|
||||||
const e2eResults = runCLI(`e2e ${appName}-e2e --no-watch`);
|
|
||||||
expect(e2eResults).toContain('All specs passed!');
|
|
||||||
expect(await killPorts()).toBeTruthy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('React Applications: --style option', () => {
|
|
||||||
// Only create workspace once
|
|
||||||
beforeAll(() => newProject());
|
|
||||||
|
|
||||||
it.each`
|
|
||||||
style
|
|
||||||
${'css'}
|
|
||||||
${'scss'}
|
|
||||||
${'less'}
|
|
||||||
${'styl'}
|
|
||||||
`('should support global and css modules', ({ style }) => {
|
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/react:app ${appName} --style=${style} --bundler=webpack --no-interactive`
|
|
||||||
);
|
|
||||||
|
|
||||||
// make sure stylePreprocessorOptions works
|
runCLI(
|
||||||
updateProjectConfig(appName, (config) => {
|
`generate @nrwl/react:app ${appName} --routing --bundler=webpack --no-interactive`
|
||||||
config.targets.build.options.stylePreprocessorOptions = {
|
|
||||||
includePaths: ['libs/shared/lib'],
|
|
||||||
};
|
|
||||||
return config;
|
|
||||||
});
|
|
||||||
updateFile(
|
|
||||||
`apps/${appName}/src/styles.${style}`,
|
|
||||||
`@import 'base.${style}';`
|
|
||||||
);
|
|
||||||
updateFile(
|
|
||||||
`apps/${appName}/src/app/app.module.${style}`,
|
|
||||||
(s) => `@import 'base.${style}';\n${s}`
|
|
||||||
);
|
|
||||||
updateFile(
|
|
||||||
`libs/shared/lib/base.${style}`,
|
|
||||||
`body { font-family: "Comic Sans MS"; }`
|
|
||||||
);
|
);
|
||||||
|
|
||||||
runCLI(`build ${appName} --outputHashing none`);
|
runCLI(`build ${appName} --outputHashing none`);
|
||||||
|
|
||||||
expect(readFile(`dist/apps/${appName}/styles.css`)).toMatch(
|
checkFilesExist(
|
||||||
/Comic Sans MS/
|
`dist/apps/${appName}/index.html`,
|
||||||
|
`dist/apps/${appName}/runtime.js`,
|
||||||
|
`dist/apps/${appName}/main.js`
|
||||||
);
|
);
|
||||||
});
|
}, 250_000);
|
||||||
});
|
|
||||||
|
|
||||||
describe('React Applications and Libs with PostCSS', () => {
|
it('should be able to add a redux slice', async () => {
|
||||||
let proj: string;
|
|
||||||
|
|
||||||
beforeAll(() => (proj = newProject()));
|
|
||||||
|
|
||||||
it('should support single path or auto-loading of PostCSS config files', async () => {
|
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
const libName = uniq('lib');
|
const libName = uniq('lib');
|
||||||
|
|
||||||
runCLI(`g @nrwl/react:app ${appName} --bundler=webpack --no-interactive`);
|
runCLI(`g @nrwl/react:app ${appName} --bundler=webpack --no-interactive`);
|
||||||
|
runCLI(`g @nrwl/react:redux lemon --project=${appName}`);
|
||||||
runCLI(
|
runCLI(
|
||||||
`g @nrwl/react:lib ${libName} --no-interactive --unit-test-runner=none`
|
`g @nrwl/react:lib ${libName} --unit-test-runner=jest --no-interactive`
|
||||||
|
);
|
||||||
|
runCLI(`g @nrwl/react:redux orange --project=${libName}`);
|
||||||
|
|
||||||
|
const appTestResults = await runCLIAsync(`test ${appName}`);
|
||||||
|
expect(appTestResults.combinedOutput).toContain(
|
||||||
|
'Test Suites: 2 passed, 2 total'
|
||||||
);
|
);
|
||||||
|
|
||||||
const mainPath = `apps/${appName}/src/main.tsx`;
|
const libTestResults = await runCLIAsync(`test ${libName}`);
|
||||||
updateFile(
|
expect(libTestResults.combinedOutput).toContain(
|
||||||
mainPath,
|
'Test Suites: 2 passed, 2 total'
|
||||||
`import '@${proj}/${libName}';\n${readFile(mainPath)}`
|
|
||||||
);
|
);
|
||||||
|
}, 250_000);
|
||||||
|
|
||||||
createFile(
|
describe('React Applications: --style option', () => {
|
||||||
`apps/${appName}/postcss.config.js`,
|
it.each`
|
||||||
`
|
style
|
||||||
|
${'css'}
|
||||||
|
${'scss'}
|
||||||
|
${'less'}
|
||||||
|
${'styl'}
|
||||||
|
`('should support global and css modules', ({ style }) => {
|
||||||
|
const appName = uniq('app');
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/react:app ${appName} --style=${style} --bundler=webpack --no-interactive`
|
||||||
|
);
|
||||||
|
|
||||||
|
// make sure stylePreprocessorOptions works
|
||||||
|
updateProjectConfig(appName, (config) => {
|
||||||
|
config.targets.build.options.stylePreprocessorOptions = {
|
||||||
|
includePaths: ['libs/shared/lib'],
|
||||||
|
};
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
updateFile(
|
||||||
|
`apps/${appName}/src/styles.${style}`,
|
||||||
|
`@import 'base.${style}';`
|
||||||
|
);
|
||||||
|
updateFile(
|
||||||
|
`apps/${appName}/src/app/app.module.${style}`,
|
||||||
|
(s) => `@import 'base.${style}';\n${s}`
|
||||||
|
);
|
||||||
|
updateFile(
|
||||||
|
`libs/shared/lib/base.${style}`,
|
||||||
|
`body { font-family: "Comic Sans MS"; }`
|
||||||
|
);
|
||||||
|
|
||||||
|
runCLI(`build ${appName} --outputHashing none`);
|
||||||
|
|
||||||
|
expect(readFile(`dist/apps/${appName}/styles.css`)).toMatch(
|
||||||
|
/Comic Sans MS/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('React Applications and Libs with PostCSS', () => {
|
||||||
|
it('should support single path or auto-loading of PostCSS config files', async () => {
|
||||||
|
const appName = uniq('app');
|
||||||
|
const libName = uniq('lib');
|
||||||
|
|
||||||
|
runCLI(`g @nrwl/react:app ${appName} --bundler=webpack --no-interactive`);
|
||||||
|
runCLI(
|
||||||
|
`g @nrwl/react:lib ${libName} --no-interactive --unit-test-runner=none`
|
||||||
|
);
|
||||||
|
|
||||||
|
const mainPath = `apps/${appName}/src/main.tsx`;
|
||||||
|
updateFile(
|
||||||
|
mainPath,
|
||||||
|
`import '@${proj}/${libName}';\n${readFile(mainPath)}`
|
||||||
|
);
|
||||||
|
|
||||||
|
createFile(
|
||||||
|
`apps/${appName}/postcss.config.js`,
|
||||||
|
`
|
||||||
console.log('HELLO FROM APP'); // need this output for e2e test
|
console.log('HELLO FROM APP'); // need this output for e2e test
|
||||||
module.exports = {};
|
module.exports = {};
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
createFile(
|
createFile(
|
||||||
`libs/${libName}/postcss.config.js`,
|
`libs/${libName}/postcss.config.js`,
|
||||||
`
|
`
|
||||||
console.log('HELLO FROM LIB'); // need this output for e2e test
|
console.log('HELLO FROM LIB'); // need this output for e2e test
|
||||||
module.exports = {};
|
module.exports = {};
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
let buildResults = await runCLIAsync(`build ${appName}`);
|
let buildResults = await runCLIAsync(`build ${appName}`);
|
||||||
|
|
||||||
expect(buildResults.combinedOutput).toMatch(/HELLO FROM APP/);
|
expect(buildResults.combinedOutput).toMatch(/HELLO FROM APP/);
|
||||||
expect(buildResults.combinedOutput).toMatch(/HELLO FROM LIB/);
|
expect(buildResults.combinedOutput).toMatch(/HELLO FROM LIB/);
|
||||||
|
|
||||||
// Only load app PostCSS config
|
// Only load app PostCSS config
|
||||||
updateJson(`apps/${appName}/project.json`, (json) => {
|
updateJson(`apps/${appName}/project.json`, (json) => {
|
||||||
json.targets.build.options.postcssConfig = `apps/${appName}/postcss.config.js`;
|
json.targets.build.options.postcssConfig = `apps/${appName}/postcss.config.js`;
|
||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
|
|
||||||
buildResults = await runCLIAsync(`build ${appName}`);
|
buildResults = await runCLIAsync(`build ${appName}`);
|
||||||
|
|
||||||
expect(buildResults.combinedOutput).toMatch(/HELLO FROM APP/);
|
expect(buildResults.combinedOutput).toMatch(/HELLO FROM APP/);
|
||||||
expect(buildResults.combinedOutput).not.toMatch(/HELLO FROM LIB/);
|
expect(buildResults.combinedOutput).not.toMatch(/HELLO FROM LIB/);
|
||||||
}, 250_000);
|
}, 250_000);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function testGeneratedApp(
|
||||||
|
appName,
|
||||||
|
opts: {
|
||||||
|
checkStyles: boolean;
|
||||||
|
checkLinter: boolean;
|
||||||
|
checkE2E: boolean;
|
||||||
|
checkSourceMap?: boolean;
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
if (opts.checkLinter) {
|
||||||
|
const lintResults = runCLI(`lint ${appName}`);
|
||||||
|
expect(lintResults).toContain('All files pass linting.');
|
||||||
|
}
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`build ${appName} --outputHashing none ${
|
||||||
|
opts.checkSourceMap ? '--sourceMap' : ''
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
const filesToCheck = [
|
||||||
|
`dist/apps/${appName}/index.html`,
|
||||||
|
`dist/apps/${appName}/runtime.js`,
|
||||||
|
`dist/apps/${appName}/main.js`,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (opts.checkSourceMap) {
|
||||||
|
filesToCheck.push(`dist/apps/${appName}/main.js.map`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.checkStyles) {
|
||||||
|
filesToCheck.push(`dist/apps/${appName}/styles.css`);
|
||||||
|
}
|
||||||
|
checkFilesExist(...filesToCheck);
|
||||||
|
|
||||||
|
if (opts.checkStyles) {
|
||||||
|
expect(readFile(`dist/apps/${appName}/index.html`)).toContain(
|
||||||
|
'<link rel="stylesheet" href="styles.css">'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const testResults = await runCLIAsync(`test ${appName}`);
|
||||||
|
expect(testResults.combinedOutput).toContain(
|
||||||
|
'Test Suites: 1 passed, 1 total'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (opts.checkE2E && runCypressTests()) {
|
||||||
|
const e2eResults = runCLI(`e2e ${appName}-e2e --no-watch`);
|
||||||
|
expect(e2eResults).toContain('All specs passed!');
|
||||||
|
expect(await killPorts()).toBeTruthy();
|
||||||
|
}
|
||||||
|
}
|
||||||
11
e2e/react-extensions/jest.config.ts
Normal file
11
e2e/react-extensions/jest.config.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
export default {
|
||||||
|
transform: {
|
||||||
|
'^.+\\.[tj]sx?$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
|
||||||
|
},
|
||||||
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||||
|
maxWorkers: 1,
|
||||||
|
globals: {},
|
||||||
|
displayName: 'e2e-react-extensions',
|
||||||
|
preset: '../../jest.preset.js',
|
||||||
|
};
|
||||||
11
e2e/react-extensions/project.json
Normal file
11
e2e/react-extensions/project.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "e2e-react-extensions",
|
||||||
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||||
|
"sourceRoot": "e2e/react-extensions",
|
||||||
|
"projectType": "application",
|
||||||
|
"targets": {
|
||||||
|
"e2e": {},
|
||||||
|
"run-e2e-tests": {}
|
||||||
|
},
|
||||||
|
"implicitDependencies": ["react"]
|
||||||
|
}
|
||||||
140
e2e/react-extensions/src/react-vite.test.ts
Normal file
140
e2e/react-extensions/src/react-vite.test.ts
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
import {
|
||||||
|
checkFilesExist,
|
||||||
|
cleanupProject,
|
||||||
|
newProject,
|
||||||
|
readJson,
|
||||||
|
runCLI,
|
||||||
|
runCLIAsync,
|
||||||
|
uniq,
|
||||||
|
} from '@nrwl/e2e/utils';
|
||||||
|
|
||||||
|
describe('Build React applications and libraries with Vite', () => {
|
||||||
|
let proj: string;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
proj = newProject();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
cleanupProject();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should test and lint app with bundler=vite', async () => {
|
||||||
|
const viteApp = uniq('viteapp');
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/react:app ${viteApp} --bundler=vite --unitTestRunner=vitest --no-interactive`
|
||||||
|
);
|
||||||
|
|
||||||
|
const appTestResults = await runCLIAsync(`test ${viteApp}`);
|
||||||
|
expect(appTestResults.combinedOutput).toContain(
|
||||||
|
'Successfully ran target test'
|
||||||
|
);
|
||||||
|
|
||||||
|
const appLintResults = await runCLIAsync(`lint ${viteApp}`);
|
||||||
|
expect(appLintResults.combinedOutput).toContain(
|
||||||
|
'Successfully ran target lint'
|
||||||
|
);
|
||||||
|
|
||||||
|
await runCLIAsync(`build ${viteApp}`);
|
||||||
|
checkFilesExist(`dist/apps/${viteApp}/index.html`);
|
||||||
|
}, 300_000);
|
||||||
|
|
||||||
|
it('should test and lint app with bundler=vite and inSourceTests', async () => {
|
||||||
|
const viteApp = uniq('viteapp');
|
||||||
|
const viteLib = uniq('vitelib');
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/react:app ${viteApp} --bundler=vite --unitTestRunner=vitest --inSourceTests --no-interactive`
|
||||||
|
);
|
||||||
|
expect(() => {
|
||||||
|
checkFilesExist(`apps/${viteApp}/src/app/app.spec.tsx`);
|
||||||
|
}).toThrow();
|
||||||
|
|
||||||
|
const appTestResults = await runCLIAsync(`test ${viteApp}`);
|
||||||
|
expect(appTestResults.combinedOutput).toContain(
|
||||||
|
'Successfully ran target test'
|
||||||
|
);
|
||||||
|
|
||||||
|
const appLintResults = await runCLIAsync(`lint ${viteApp}`);
|
||||||
|
expect(appLintResults.combinedOutput).toContain(
|
||||||
|
'Successfully ran target lint'
|
||||||
|
);
|
||||||
|
|
||||||
|
await runCLIAsync(`build ${viteApp}`);
|
||||||
|
checkFilesExist(`dist/apps/${viteApp}/index.html`);
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/react:lib ${viteLib} --bundler=vite --inSourceTests --unitTestRunner=vitest --no-interactive`
|
||||||
|
);
|
||||||
|
expect(() => {
|
||||||
|
checkFilesExist(`libs/${viteLib}/src/lib/${viteLib}.spec.tsx`);
|
||||||
|
}).toThrow();
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/react:component comp1 --inSourceTests --export --project=${viteLib} --no-interactive`
|
||||||
|
);
|
||||||
|
expect(() => {
|
||||||
|
checkFilesExist(`libs/${viteLib}/src/lib/comp1/comp1.spec.tsx`);
|
||||||
|
}).toThrow();
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/react:component comp2 --export --project=${viteLib} --no-interactive`
|
||||||
|
);
|
||||||
|
checkFilesExist(`libs/${viteLib}/src/lib/comp2/comp2.spec.tsx`);
|
||||||
|
|
||||||
|
const libTestResults = await runCLIAsync(`test ${viteLib}`);
|
||||||
|
expect(libTestResults.combinedOutput).toContain(
|
||||||
|
'Successfully ran target test'
|
||||||
|
);
|
||||||
|
|
||||||
|
const libLintResults = await runCLIAsync(`lint ${viteLib}`);
|
||||||
|
expect(libLintResults.combinedOutput).toContain(
|
||||||
|
'Successfully ran target lint'
|
||||||
|
);
|
||||||
|
|
||||||
|
await runCLIAsync(`build ${viteLib}`);
|
||||||
|
checkFilesExist(
|
||||||
|
`dist/libs/${viteLib}/index.d.ts`,
|
||||||
|
`dist/libs/${viteLib}/index.js`,
|
||||||
|
`dist/libs/${viteLib}/index.mjs`
|
||||||
|
);
|
||||||
|
}, 300_000);
|
||||||
|
|
||||||
|
it('should support bundling with Vite', async () => {
|
||||||
|
const viteLib = uniq('vitelib');
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/react:lib ${viteLib} --bundler=vite --no-interactive --unit-test-runner=none`
|
||||||
|
);
|
||||||
|
|
||||||
|
const packageJson = readJson('package.json');
|
||||||
|
// Vite does not need these libraries to work.
|
||||||
|
expect(packageJson.dependencies['core-js']).toBeUndefined();
|
||||||
|
expect(packageJson.dependencies['tslib']).toBeUndefined();
|
||||||
|
|
||||||
|
await runCLIAsync(`build ${viteLib}`);
|
||||||
|
|
||||||
|
checkFilesExist(
|
||||||
|
`dist/libs/${viteLib}/package.json`,
|
||||||
|
`dist/libs/${viteLib}/index.d.ts`,
|
||||||
|
`dist/libs/${viteLib}/index.js`,
|
||||||
|
`dist/libs/${viteLib}/index.mjs`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Convert non-buildable lib to buildable one
|
||||||
|
const nonBuildableLib = uniq('nonbuildablelib');
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/react:lib ${nonBuildableLib} --no-interactive --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/vite:configuration ${nonBuildableLib} --uiFramework=react --no-interactive`
|
||||||
|
);
|
||||||
|
await runCLIAsync(`build ${nonBuildableLib}`);
|
||||||
|
checkFilesExist(
|
||||||
|
`dist/libs/${nonBuildableLib}/index.d.ts`,
|
||||||
|
`dist/libs/${nonBuildableLib}/index.js`,
|
||||||
|
`dist/libs/${nonBuildableLib}/index.mjs`
|
||||||
|
);
|
||||||
|
}, 300_000);
|
||||||
|
});
|
||||||
13
e2e/react-extensions/tsconfig.json
Normal file
13
e2e/react-extensions/tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"types": ["node", "jest"]
|
||||||
|
},
|
||||||
|
"include": [],
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
20
e2e/react-extensions/tsconfig.spec.json
Normal file
20
e2e/react-extensions/tsconfig.spec.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"module": "commonjs",
|
||||||
|
"types": ["jest", "node"]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"**/*.test.ts",
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.spec.tsx",
|
||||||
|
"**/*.test.tsx",
|
||||||
|
"**/*.spec.js",
|
||||||
|
"**/*.test.js",
|
||||||
|
"**/*.spec.jsx",
|
||||||
|
"**/*.test.jsx",
|
||||||
|
"**/*.d.ts",
|
||||||
|
"jest.config.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -1,49 +0,0 @@
|
|||||||
import {
|
|
||||||
checkFilesExist,
|
|
||||||
newProject,
|
|
||||||
runCLI,
|
|
||||||
runCLIAsync,
|
|
||||||
uniq,
|
|
||||||
} from '@nrwl/e2e/utils';
|
|
||||||
|
|
||||||
describe('React Applications: additional packages', () => {
|
|
||||||
beforeAll(() => newProject());
|
|
||||||
|
|
||||||
it('should generate app with routing', async () => {
|
|
||||||
const appName = uniq('app');
|
|
||||||
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/react:app ${appName} --routing --bundler=webpack --no-interactive`
|
|
||||||
);
|
|
||||||
|
|
||||||
runCLI(`build ${appName} --outputHashing none`);
|
|
||||||
|
|
||||||
checkFilesExist(
|
|
||||||
`dist/apps/${appName}/index.html`,
|
|
||||||
`dist/apps/${appName}/runtime.js`,
|
|
||||||
`dist/apps/${appName}/main.js`
|
|
||||||
);
|
|
||||||
}, 250_000);
|
|
||||||
|
|
||||||
it('should be able to add a redux slice', async () => {
|
|
||||||
const appName = uniq('app');
|
|
||||||
const libName = uniq('lib');
|
|
||||||
|
|
||||||
runCLI(`g @nrwl/react:app ${appName} --bundler=webpack --no-interactive`);
|
|
||||||
runCLI(`g @nrwl/react:redux lemon --project=${appName}`);
|
|
||||||
runCLI(
|
|
||||||
`g @nrwl/react:lib ${libName} --unit-test-runner=jest --no-interactive`
|
|
||||||
);
|
|
||||||
runCLI(`g @nrwl/react:redux orange --project=${libName}`);
|
|
||||||
|
|
||||||
const appTestResults = await runCLIAsync(`test ${appName}`);
|
|
||||||
expect(appTestResults.combinedOutput).toContain(
|
|
||||||
'Test Suites: 2 passed, 2 total'
|
|
||||||
);
|
|
||||||
|
|
||||||
const libTestResults = await runCLIAsync(`test ${libName}`);
|
|
||||||
expect(libTestResults.combinedOutput).toContain(
|
|
||||||
'Test Suites: 2 passed, 2 total'
|
|
||||||
);
|
|
||||||
}, 250_000);
|
|
||||||
});
|
|
||||||
Loading…
x
Reference in New Issue
Block a user