chore(repo): split e2e-workspace to two applications (#7240)

This commit is contained in:
Miroslav Jonaš 2021-10-05 18:59:03 +02:00 committed by GitHub
parent 508ff79296
commit a01a5c9d34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 869 additions and 660 deletions

View File

@ -390,7 +390,7 @@ workflows:
run-unit-tests: 'false' run-unit-tests: 'false'
run-linting: 'false' run-linting: 'false'
e2e-test-filter: 'MACOS-Tests' e2e-test-filter: 'MACOS-Tests'
exclude-projects: 'e2e-next,e2e-gatsby,e2e-workspace,e2e-react,e2e-web,e2e-angular-extensions,e2e-angular-core,e2e-cli,e2e-nx-plugin,e2e-storybook,e2e-cypress,e2e-node,e2e-linter,e2e-jest' exclude-projects: 'e2e-next,e2e-gatsby,e2e-workspace-create,e2e-workspace-integrations,e2e-workspace-core,e2e-react,e2e-web,e2e-angular-extensions,e2e-angular-core,e2e-cli,e2e-nx-plugin,e2e-storybook,e2e-cypress,e2e-node,e2e-linter,e2e-jest'
filters: filters:
branches: branches:
ignore: master ignore: master
@ -426,7 +426,7 @@ workflows:
run-linting: 'false' run-linting: 'false'
e2e-test-filter: 'MACOS-Tests' e2e-test-filter: 'MACOS-Tests'
run-cypress-tests: 'true' run-cypress-tests: 'true'
exclude-projects: 'e2e-next,e2e-gatsby,e2e-workspace,e2e-react,e2e-web,e2e-angular-extensions,e2e-angular-core,e2e-cli,e2e-nx-plugin,e2e-storybook,e2e-cypress,e2e-node,e2e-linter,e2e-jest' exclude-projects: 'e2e-next,e2e-gatsby,e2e-workspace-create,e2e-workspace-integrations,e2e-workspace-core,e2e-react,e2e-web,e2e-angular-extensions,e2e-angular-core,e2e-cli,e2e-nx-plugin,e2e-storybook,e2e-cypress,e2e-node,e2e-linter,e2e-jest'
filters: filters:
branches: branches:
only: master only: master

View File

@ -45,7 +45,7 @@ jobs:
- e2e-node - e2e-node
- e2e-web - e2e-web
- e2e-storybook - e2e-storybook
- e2e-workspace - e2e-workspace-integrations,e2e-workspace-core,e2e-workspace-create
- e2e-react-native,e2e-detox - e2e-react-native,e2e-detox
exclude: exclude:
- os: ubuntu-latest - os: ubuntu-latest
@ -64,7 +64,11 @@ jobs:
- os: macos-latest - os: macos-latest
package_manager: pnpm package_manager: pnpm
- os: macos-latest - os: macos-latest
packages: e2e-workspace packages: e2e-workspace-core
- os: macos-latest
packages: e2e-workspace-integrations
- os: macos-latest
packages: e2e-workspace-create
- os: windows-latest - os: windows-latest
node_version: '14' node_version: '14'
- os: windows-latest - os: windows-latest

View File

@ -188,9 +188,19 @@
"data": { "tags": [], "root": "e2e/storybook", "files": [] } "data": { "tags": [], "root": "e2e/storybook", "files": [] }
}, },
{ {
"name": "e2e-workspace", "name": "e2e-workspace-integrations",
"type": "app", "type": "app",
"data": { "tags": [], "root": "e2e/workspace", "files": [] } "data": { "tags": [], "root": "e2e/workspace-integrations", "files": [] }
},
{
"name": "e2e-workspace-core",
"type": "app",
"data": { "tags": [], "root": "e2e/workspace-core", "files": [] }
},
{
"name": "e2e-workspace-create",
"type": "app",
"data": { "tags": [], "root": "e2e/workspace-create", "files": [] }
}, },
{ {
"name": "jest", "name": "jest",
@ -510,17 +520,61 @@
{ "source": "e2e-storybook", "target": "storybook", "type": "implicit" }, { "source": "e2e-storybook", "target": "storybook", "type": "implicit" },
{ "source": "e2e-storybook", "target": "e2e-utils", "type": "static" } { "source": "e2e-storybook", "target": "e2e-utils", "type": "static" }
], ],
"e2e-workspace": [ "e2e-workspace-integrations": [
{ {
"source": "e2e-workspace", "source": "e2e-workspace-integrations",
"target": "angular",
"type": "implicit"
},
{
"source": "e2e-workspace-integrations",
"target": "react",
"type": "implicit"
},
{
"source": "e2e-workspace-integrations",
"target": "e2e-utils",
"type": "static"
},
{
"source": "e2e-workspace-integrations",
"target": "devkit",
"type": "static"
},
{
"source": "e2e-workspace-integrations",
"target": "workspace",
"type": "static"
}
],
"e2e-workspace-create": [
{
"source": "e2e-workspace-create",
"target": "create-nx-workspace", "target": "create-nx-workspace",
"type": "implicit" "type": "implicit"
}, },
{ "source": "e2e-workspace", "target": "angular", "type": "implicit" }, {
{ "source": "e2e-workspace", "target": "react", "type": "implicit" }, "source": "e2e-workspace-create",
{ "source": "e2e-workspace", "target": "e2e-utils", "type": "static" }, "target": "e2e-utils",
{ "source": "e2e-workspace", "target": "devkit", "type": "static" }, "type": "static"
{ "source": "e2e-workspace", "target": "workspace", "type": "static" } },
{
"source": "e2e-workspace-create",
"target": "workspace",
"type": "static"
}
],
"e2e-workspace-core": [
{
"source": "e2e-workspace-core",
"target": "e2e-utils",
"type": "static"
},
{
"source": "e2e-workspace-core",
"target": "workspace",
"type": "static"
}
], ],
"jest": [ "jest": [
{ "source": "jest", "target": "devkit", "type": "static" }, { "source": "jest", "target": "devkit", "type": "static" },

View File

@ -230,6 +230,72 @@ describe('Linter', () => {
expect(lintOutput).toContain(knownLintErrorMessage); expect(lintOutput).toContain(knownLintErrorMessage);
}, 1000000); }, 1000000);
}); });
it('lint plugin should ensure module boundaries', () => {
const proj = newProject();
const myapp = uniq('myapp');
const myapp2 = uniq('myapp2');
const mylib = uniq('mylib');
const lazylib = uniq('lazylib');
const invalidtaglib = uniq('invalidtaglib');
const validtaglib = uniq('validtaglib');
runCLI(`generate @nrwl/angular:app ${myapp} --tags=validtag`);
runCLI(`generate @nrwl/angular:app ${myapp2}`);
runCLI(`generate @nrwl/angular:lib ${mylib}`);
runCLI(`generate @nrwl/angular:lib ${lazylib}`);
runCLI(`generate @nrwl/angular:lib ${invalidtaglib} --tags=invalidtag`);
runCLI(`generate @nrwl/angular:lib ${validtaglib} --tags=validtag`);
const eslint = readJson('.eslintrc.json');
eslint.overrides[0].rules[
'@nrwl/nx/enforce-module-boundaries'
][1].depConstraints = [
{ sourceTag: 'validtag', onlyDependOnLibsWithTags: ['validtag'] },
...eslint.overrides[0].rules['@nrwl/nx/enforce-module-boundaries'][1]
.depConstraints,
];
updateFile('.eslintrc.json', JSON.stringify(eslint, null, 2));
const tsConfig = readJson('tsconfig.base.json');
/**
* apps do not add themselves to the tsconfig file.
*
* Let's add it so that we can trigger the lint failure
*/
tsConfig.compilerOptions.paths[`@${proj}/${myapp2}`] = [
`apps/${myapp2}/src/main.ts`,
];
tsConfig.compilerOptions.paths[`@secondScope/${lazylib}`] =
tsConfig.compilerOptions.paths[`@${proj}/${lazylib}`];
delete tsConfig.compilerOptions.paths[`@${proj}/${lazylib}`];
updateFile('tsconfig.base.json', JSON.stringify(tsConfig, null, 2));
updateFile(
`apps/${myapp}/src/main.ts`,
`
import '../../../libs/${mylib}';
import '@secondScope/${lazylib}';
import '@${proj}/${myapp2}';
import '@${proj}/${invalidtaglib}';
import '@${proj}/${validtaglib}';
const s = {loadChildren: '@${proj}/${lazylib}'};
`
);
const out = runCLI(`lint ${myapp}`, { silenceError: true });
expect(out).toContain(
'Libraries cannot be imported by a relative or absolute path, and must begin with a npm scope'
);
// expect(out).toContain('Imports of lazy-loaded libraries are forbidden');
expect(out).toContain('Imports of apps are forbidden');
expect(out).toContain(
'A project tagged with "validtag" can only depend on libs tagged with "validtag"'
);
}, 1000000);
}); });
/** /**

View File

@ -6,5 +6,5 @@ module.exports = {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
maxWorkers: 1, maxWorkers: 1,
globals: { 'ts-jest': { tsconfig: '<rootDir>/tsconfig.spec.json' } }, globals: { 'ts-jest': { tsconfig: '<rootDir>/tsconfig.spec.json' } },
displayName: 'e2e-workspace', displayName: 'e2e-workspace-core',
}; };

View File

@ -1,6 +1,6 @@
{ {
"root": "e2e/workspace", "root": "e2e/workspace-core",
"sourceRoot": "e2e/workspace", "sourceRoot": "e2e/workspace-core",
"projectType": "application", "projectType": "application",
"targets": { "targets": {
"e2e": { "e2e": {
@ -14,7 +14,7 @@
"command": "yarn e2e-build-package-publish" "command": "yarn e2e-build-package-publish"
}, },
{ {
"command": "nx run-e2e-tests e2e-workspace" "command": "nx run-e2e-tests e2e-workspace-core"
} }
], ],
"parallel": false "parallel": false
@ -23,12 +23,12 @@
"run-e2e-tests": { "run-e2e-tests": {
"executor": "@nrwl/jest:jest", "executor": "@nrwl/jest:jest",
"options": { "options": {
"jestConfig": "e2e/workspace/jest.config.js", "jestConfig": "e2e/workspace-core/jest.config.js",
"passWithNoTests": true, "passWithNoTests": true,
"runInBand": true "runInBand": true
}, },
"outputs": ["coverage/e2e/workspace"] "outputs": ["coverage/e2e/workspace-core"]
} }
}, },
"implicitDependencies": ["create-nx-workspace", "angular", "react"] "implicitDependencies": []
} }

View File

@ -1,251 +1,23 @@
import * as path from 'path'; import { NxJsonConfiguration } from '@nrwl/devkit';
import { import {
checkFilesExist, checkFilesExist,
exists, exists,
isNotWindows,
newProject, newProject,
readFile, readFile,
readJson, readJson,
removeProject,
renameFile, renameFile,
runCLI, runCLI,
runCLIAsync,
tmpProjPath, tmpProjPath,
uniq, uniq,
updateFile, updateFile,
workspaceConfigName, workspaceConfigName,
} from '@nrwl/e2e/utils'; } from '@nrwl/e2e/utils';
import type { NxJsonConfiguration } from '@nrwl/devkit';
import { classify } from '@nrwl/workspace/src/utils/strings';
let proj: string; let proj;
beforeAll(() => { beforeAll(() => {
proj = newProject(); proj = newProject();
}); });
describe('lint', () => {
it('lint should ensure module boundaries', () => {
const myapp = uniq('myapp');
const myapp2 = uniq('myapp2');
const mylib = uniq('mylib');
const lazylib = uniq('lazylib');
const invalidtaglib = uniq('invalidtaglib');
const validtaglib = uniq('validtaglib');
runCLI(`generate @nrwl/angular:app ${myapp} --tags=validtag`);
runCLI(`generate @nrwl/angular:app ${myapp2}`);
runCLI(`generate @nrwl/angular:lib ${mylib}`);
runCLI(`generate @nrwl/angular:lib ${lazylib}`);
runCLI(`generate @nrwl/angular:lib ${invalidtaglib} --tags=invalidtag`);
runCLI(`generate @nrwl/angular:lib ${validtaglib} --tags=validtag`);
const eslint = readJson('.eslintrc.json');
eslint.overrides[0].rules[
'@nrwl/nx/enforce-module-boundaries'
][1].depConstraints = [
{ sourceTag: 'validtag', onlyDependOnLibsWithTags: ['validtag'] },
...eslint.overrides[0].rules['@nrwl/nx/enforce-module-boundaries'][1]
.depConstraints,
];
updateFile('.eslintrc.json', JSON.stringify(eslint, null, 2));
const tsConfig = readJson('tsconfig.base.json');
/**
* apps do not add themselves to the tsconfig file.
*
* Let's add it so that we can trigger the lint failure
*/
tsConfig.compilerOptions.paths[`@${proj}/${myapp2}`] = [
`apps/${myapp2}/src/main.ts`,
];
tsConfig.compilerOptions.paths[`@secondScope/${lazylib}`] =
tsConfig.compilerOptions.paths[`@${proj}/${lazylib}`];
delete tsConfig.compilerOptions.paths[`@${proj}/${lazylib}`];
updateFile('tsconfig.base.json', JSON.stringify(tsConfig, null, 2));
updateFile(
`apps/${myapp}/src/main.ts`,
`
import '../../../libs/${mylib}';
import '@secondScope/${lazylib}';
import '@${proj}/${myapp2}';
import '@${proj}/${invalidtaglib}';
import '@${proj}/${validtaglib}';
const s = {loadChildren: '@${proj}/${lazylib}'};
`
);
const out = runCLI(`lint ${myapp}`, { silenceError: true });
expect(out).toContain(
'Libraries cannot be imported by a relative or absolute path, and must begin with a npm scope'
);
// expect(out).toContain('Imports of lazy-loaded libraries are forbidden');
expect(out).toContain('Imports of apps are forbidden');
expect(out).toContain(
'A project tagged with "validtag" can only depend on libs tagged with "validtag"'
);
}, 1000000);
describe('nx workspace-lint', () => {
it('should identify issues with the workspace', () => {
const appBefore = uniq('before');
const appAfter = uniq('after');
runCLI(`generate @nrwl/angular:app ${appBefore}`);
renameFile(`apps/${appBefore}`, `apps/${appAfter}`);
const stdout = runCLI('workspace-lint', { silenceError: true });
expect(stdout).toContain(
`- Cannot find project '${appBefore}' in 'apps/${appBefore}'`
);
expect(stdout).toContain(
'The following file(s) do not belong to any projects:'
);
expect(stdout).toContain(`- apps/${appAfter}/jest.config.js`);
expect(stdout).toContain(`- apps/${appAfter}/src/app/app.component.css`);
expect(stdout).toContain(`- apps/${appAfter}/src/app/app.component.html`);
expect(stdout).toContain(
`- apps/${appAfter}/src/app/app.component.spec.ts`
);
});
});
});
describe('format', () => {
it('should check and reformat the code', async () => {
if (isNotWindows()) {
const myapp = uniq('myapp');
const mylib = uniq('mylib');
runCLI(`generate @nrwl/angular:app ${myapp}`);
runCLI(`generate @nrwl/angular:lib ${mylib}`);
updateFile(
`apps/${myapp}/src/main.ts`,
`
const x = 1111;
`
);
updateFile(
`apps/${myapp}/src/app/app.module.ts`,
`
const y = 1111;
`
);
updateFile(
`apps/${myapp}/src/app/app.component.ts`,
`
const z = 1111;
`
);
updateFile(
`libs/${mylib}/index.ts`,
`
const x = 1111;
`
);
updateFile(
`libs/${mylib}/src/${mylib}.module.ts`,
`
const y = 1111;
`
);
updateFile(
`README.md`,
`
my new readme;
`
);
let stdout = runCLI(
`format:check --files="libs/${mylib}/index.ts,package.json" --libs-and-apps`,
{ silenceError: true }
);
expect(stdout).toContain(path.normalize(`libs/${mylib}/index.ts`));
expect(stdout).toContain(
path.normalize(`libs/${mylib}/src/${mylib}.module.ts`)
);
expect(stdout).not.toContain(path.normalize(`README.md`)); // It will be contained only in case of exception, that we fallback to all
stdout = runCLI(`format:check --all`, { silenceError: true });
expect(stdout).toContain(path.normalize(`apps/${myapp}/src/main.ts`));
expect(stdout).toContain(
path.normalize(`apps/${myapp}/src/app/app.module.ts`)
);
expect(stdout).toContain(
path.normalize(`apps/${myapp}/src/app/app.component.ts`)
);
stdout = runCLI(`format:check --projects=${myapp}`, {
silenceError: true,
});
expect(stdout).toContain(path.normalize(`apps/${myapp}/src/main.ts`));
expect(stdout).toContain(
path.normalize(`apps/${myapp}/src/app/app.module.ts`)
);
expect(stdout).toContain(
path.normalize(`apps/${myapp}/src/app/app.component.ts`)
);
expect(stdout).not.toContain(path.normalize(`libs/${mylib}/index.ts`));
expect(stdout).not.toContain(
path.normalize(`libs/${mylib}/src/${mylib}.module.ts`)
);
expect(stdout).not.toContain(path.normalize(`README.md`));
stdout = runCLI(`format:check --projects=${myapp},${mylib}`, {
silenceError: true,
});
expect(stdout).toContain(path.normalize(`apps/${myapp}/src/main.ts`));
expect(stdout).toContain(
path.normalize(`apps/${myapp}/src/app/app.module.ts`)
);
expect(stdout).toContain(
path.normalize(`apps/${myapp}/src/app/app.component.ts`)
);
expect(stdout).toContain(path.normalize(`libs/${mylib}/index.ts`));
expect(stdout).toContain(
path.normalize(`libs/${mylib}/src/${mylib}.module.ts`)
);
expect(stdout).not.toContain(path.normalize(`README.md`));
const { stderr } = await runCLIAsync(
`format:check --projects=${myapp},${mylib} --all`,
{
silenceError: true,
}
);
expect(stderr).toContain(
'Arguments all and projects are mutually exclusive'
);
runCLI(
`format:write --files="apps/${myapp}/src/app/app.module.ts,apps/${myapp}/src/app/app.component.ts"`
);
stdout = runCLI('format:check --all', { silenceError: true });
expect(stdout).toContain(path.normalize(`apps/${myapp}/src/main.ts`));
expect(stdout).not.toContain(
path.normalize(`apps/${myapp}/src/app/app.module.ts`)
);
expect(stdout).not.toContain(
path.normalize(`apps/${myapp}/src/app/app.component.ts`)
);
runCLI('format:write --all');
expect(runCLI('format:check --all')).not.toContain(
path.normalize(`apps/${myapp}/src/main.ts`)
);
}
}, 90000);
});
describe('workspace-generator', () => { describe('workspace-generator', () => {
let custom: string; let custom: string;
let failing: string; let failing: string;
@ -399,329 +171,31 @@ describe('workspace-generator', () => {
}); });
}); });
describe('dep-graph', () => { describe('workspace-lint', () => {
let proj: string; it('should identify issues with the workspace', () => {
let myapp: string; const appBefore = uniq('before');
let myapp2: string; const appAfter = uniq('after');
let myapp3: string;
let myappE2e: string;
let myapp2E2e: string;
let myapp3E2e: string;
let mylib: string;
let mylib2: string;
beforeAll(() => {
proj = newProject();
myapp = uniq('myapp');
myapp2 = uniq('myapp2');
myapp3 = uniq('myapp3');
myappE2e = `${myapp}-e2e`;
myapp2E2e = `${myapp2}-e2e`;
myapp3E2e = `${myapp3}-e2e`;
mylib = uniq('mylib');
mylib2 = uniq('mylib2');
runCLI(`generate @nrwl/angular:app ${myapp}`); runCLI(`generate @nrwl/angular:app ${appBefore}`);
runCLI(`generate @nrwl/angular:app ${myapp2}`); renameFile(`apps/${appBefore}`, `apps/${appAfter}`);
runCLI(`generate @nrwl/angular:app ${myapp3}`);
runCLI(`generate @nrwl/angular:lib ${mylib}`);
runCLI(`generate @nrwl/angular:lib ${mylib2}`);
updateFile( const stdout = runCLI('workspace-lint', { silenceError: true });
`apps/${myapp}/src/main.ts`, expect(stdout).toContain(
` `- Cannot find project '${appBefore}' in 'apps/${appBefore}'`
import '@${proj}/${mylib}';
const s = {loadChildren: '@${proj}/${mylib2}'};
`
); );
expect(stdout).toContain(
updateFile( 'The following file(s) do not belong to any projects:'
`apps/${myapp2}/src/app/app.component.spec.ts`,
`import '@${proj}/${mylib}';`
); );
expect(stdout).toContain(`- apps/${appAfter}/jest.config.js`);
updateFile( expect(stdout).toContain(`- apps/${appAfter}/src/app/app.component.css`);
`libs/${mylib}/src/mylib.module.spec.ts`, expect(stdout).toContain(`- apps/${appAfter}/src/app/app.component.html`);
`import '@${proj}/${mylib2}';` expect(stdout).toContain(
`- apps/${appAfter}/src/app/app.component.spec.ts`
); );
}); });
it('dep-graph should output json to file', () => {
runCLI(`dep-graph --file=project-graph.json`);
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
const jsonFileContents = readJson('project-graph.json');
expect(jsonFileContents.graph.dependencies).toEqual(
expect.objectContaining({
[myapp3E2e]: [
{
source: myapp3E2e,
target: myapp3,
type: 'implicit',
},
],
[myapp2]: [
{
source: myapp2,
target: mylib,
type: 'static',
},
],
[myapp2E2e]: [
{
source: myapp2E2e,
target: myapp2,
type: 'implicit',
},
],
[mylib]: [
{
source: mylib,
target: mylib2,
type: 'static',
},
],
[mylib2]: [],
[myapp]: [
{
source: myapp,
target: mylib,
type: 'static',
},
{ source: myapp, target: mylib2, type: 'static' },
],
[myappE2e]: [
{
source: myappE2e,
target: myapp,
type: 'implicit',
},
],
[myapp3]: [],
})
);
runCLI(
`affected:dep-graph --files="libs/${mylib}/src/index.ts" --file="project-graph.json"`
);
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
const jsonFileContents2 = readJson('project-graph.json');
expect(jsonFileContents2.criticalPath).toContain(myapp);
expect(jsonFileContents2.criticalPath).toContain(myapp2);
expect(jsonFileContents2.criticalPath).toContain(mylib);
expect(jsonFileContents2.criticalPath).not.toContain(mylib2);
}, 1000000);
it('dep-graph should focus requested project', () => {
runCLI(`dep-graph --focus=${myapp} --file=project-graph.json`);
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
const jsonFileContents = readJson('project-graph.json');
const projectNames = Object.keys(jsonFileContents.graph.nodes);
expect(projectNames).toContain(myapp);
expect(projectNames).toContain(mylib);
expect(projectNames).toContain(mylib2);
expect(projectNames).toContain(myappE2e);
expect(projectNames).not.toContain(myapp2);
expect(projectNames).not.toContain(myapp3);
expect(projectNames).not.toContain(myapp2E2e);
expect(projectNames).not.toContain(myapp3E2e);
}, 1000000);
it('dep-graph should exclude requested projects', () => {
runCLI(
`dep-graph --exclude=${myappE2e},${myapp2E2e},${myapp3E2e} --file=project-graph.json`
);
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
const jsonFileContents = readJson('project-graph.json');
const projectNames = Object.keys(jsonFileContents.graph.nodes);
expect(projectNames).toContain(myapp);
expect(projectNames).toContain(mylib);
expect(projectNames).toContain(mylib2);
expect(projectNames).toContain(myapp2);
expect(projectNames).toContain(myapp3);
expect(projectNames).not.toContain(myappE2e);
expect(projectNames).not.toContain(myapp2E2e);
expect(projectNames).not.toContain(myapp3E2e);
}, 1000000);
it('dep-graph should exclude requested projects that were included by a focus', () => {
runCLI(
`dep-graph --focus=${myapp} --exclude=${myappE2e} --file=project-graph.json`
);
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
const jsonFileContents = readJson('project-graph.json');
const projectNames = Object.keys(jsonFileContents.graph.nodes);
expect(projectNames).toContain(myapp);
expect(projectNames).toContain(mylib);
expect(projectNames).toContain(mylib2);
expect(projectNames).not.toContain(myappE2e);
expect(projectNames).not.toContain(myapp2);
expect(projectNames).not.toContain(myapp3);
expect(projectNames).not.toContain(myapp2E2e);
expect(projectNames).not.toContain(myapp3E2e);
}, 1000000);
it('dep-graph should output a deployable static website in an html file accompanied by a folder with static assets', () => {
runCLI(`dep-graph --file=project-graph.html`);
expect(() => checkFilesExist('project-graph.html')).not.toThrow();
expect(() => checkFilesExist('static/styles.css')).not.toThrow();
expect(() => checkFilesExist('static/runtime.esm.js')).not.toThrow();
expect(() => checkFilesExist('static/polyfills.esm.js')).not.toThrow();
expect(() => checkFilesExist('static/main.esm.js')).not.toThrow();
});
}); });
describe('Move Angular Project', () => { describe('move project', () => {
let proj: string;
let app1: string;
let app2: string;
let newPath: string;
beforeEach(() => {
proj = newProject();
app1 = uniq('app1');
app2 = uniq('app2');
newPath = `subfolder/${app2}`;
runCLI(`generate @nrwl/angular:app ${app1}`);
});
afterEach(() => removeProject({ onlyOnCI: true }));
/**
* Tries moving an app from ${app1} -> subfolder/${app2}
*/
it('should work for apps', () => {
const moveOutput = runCLI(
`generate @nrwl/angular:move --project ${app1} ${newPath}`
);
// just check the output
expect(moveOutput).toContain(`DELETE apps/${app1}`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/.browserslistrc`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/jest.config.js`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.app.json`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.json`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.spec.json`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/.eslintrc.json`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/favicon.ico`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/index.html`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/main.ts`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/polyfills.ts`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/styles.css`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/test-setup.ts`);
expect(moveOutput).toContain(
`CREATE apps/${newPath}/src/app/app.component.html`
);
expect(moveOutput).toContain(
`CREATE apps/${newPath}/src/app/app.module.ts`
);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/assets/.gitkeep`);
expect(moveOutput).toContain(
`CREATE apps/${newPath}/src/environments/environment.prod.ts`
);
expect(moveOutput).toContain(
`CREATE apps/${newPath}/src/environments/environment.ts`
);
expect(moveOutput).toContain(`UPDATE nx.json`);
expect(moveOutput).toContain(`UPDATE workspace.json`);
});
/**
* Tries moving an e2e project from ${app1} -> ${newPath}
*/
it('should work for e2e projects', () => {
const moveOutput = runCLI(
`generate @nrwl/angular:move --projectName=${app1}-e2e --destination=${newPath}-e2e`
);
// just check that the cypress.json is updated correctly
const cypressJsonPath = `apps/${newPath}-e2e/cypress.json`;
expect(moveOutput).toContain(`CREATE ${cypressJsonPath}`);
checkFilesExist(cypressJsonPath);
const cypressJson = readJson(cypressJsonPath);
expect(cypressJson.videosFolder).toEqual(
`../../../dist/cypress/apps/${newPath}-e2e/videos`
);
expect(cypressJson.screenshotsFolder).toEqual(
`../../../dist/cypress/apps/${newPath}-e2e/screenshots`
);
});
/**
* Tries moving a library from ${lib} -> shared/${lib}
*/
it('should work for libraries', () => {
const lib1 = uniq('mylib');
const lib2 = uniq('mylib');
runCLI(`generate @nrwl/angular:lib ${lib1}`);
/**
* Create a library which imports the module from the other lib
*/
runCLI(`generate @nrwl/angular:lib ${lib2}`);
updateFile(
`libs/${lib2}/src/lib/${lib2}.module.ts`,
`import { ${classify(lib1)}Module } from '@${proj}/${lib1}';
export class ExtendedModule extends ${classify(lib1)}Module { }`
);
const moveOutput = runCLI(
`generate @nrwl/angular:move --projectName=${lib1} --destination=shared/${lib1}`
);
const newPath = `libs/shared/${lib1}`;
const newModule = `Shared${classify(lib1)}Module`;
const testSetupPath = `${newPath}/src/test-setup.ts`;
expect(moveOutput).toContain(`CREATE ${testSetupPath}`);
checkFilesExist(testSetupPath);
const modulePath = `${newPath}/src/lib/shared-${lib1}.module.ts`;
expect(moveOutput).toContain(`CREATE ${modulePath}`);
checkFilesExist(modulePath);
const moduleFile = readFile(modulePath);
expect(moduleFile).toContain(`export class ${newModule}`);
const indexPath = `${newPath}/src/index.ts`;
expect(moveOutput).toContain(`CREATE ${indexPath}`);
checkFilesExist(indexPath);
const index = readFile(indexPath);
expect(index).toContain(`export * from './lib/shared-${lib1}.module'`);
/**
* Check that the import in lib2 has been updated
*/
const lib2FilePath = `libs/${lib2}/src/lib/${lib2}.module.ts`;
const lib2File = readFile(lib2FilePath);
expect(lib2File).toContain(
`import { ${newModule} } from '@${proj}/shared-${lib1}';`
);
expect(lib2File).toContain(`extends ${newModule}`);
});
});
describe('Move Project', () => {
/** /**
* Tries moving a library from ${lib}/data-access -> shared/${lib}/data-access * Tries moving a library from ${lib}/data-access -> shared/${lib}/data-access
*/ */
@ -1138,7 +612,7 @@ describe('Move Project', () => {
}); });
}); });
describe('Remove Project', () => { describe('remove project', () => {
/** /**
* Tries creating then deleting a lib * Tries creating then deleting a lib
*/ */

View File

@ -13,20 +13,20 @@ describe('Run Commands', () => {
afterAll(() => removeProject({ onlyOnCI: true })); afterAll(() => removeProject({ onlyOnCI: true }));
it('should not override environment variables already set when setting a custom env file path', async () => { it('should not override environment variables already set when setting a custom env file path', async () => {
const nodeapp = uniq('nodeapp'); const mylib = uniq('lib');
updateFile( updateFile(
`.env`, `.env`,
'SHARED_VAR=shared-root-value\nROOT_ONLY=root-only-value' 'SHARED_VAR=shared-root-value\nROOT_ONLY=root-only-value'
); );
runCLI(`generate @nrwl/express:app ${nodeapp}`); runCLI(`generate @nrwl/workspace:lib ${mylib}`);
updateFile( updateFile(
`apps/${nodeapp}/.custom.env`, `apps/${mylib}/.custom.env`,
'SHARED_VAR=shared-nested-value\nNESTED_ONLY=nested-only-value' 'SHARED_VAR=shared-nested-value\nNESTED_ONLY=nested-only-value'
); );
const envFile = `apps/${nodeapp}/.custom.env`; const envFile = `apps/${mylib}/.custom.env`;
runCLI( runCLI(
`generate @nrwl/workspace:run-commands echoEnvVariables --command=echo --envFile=${envFile} --project=${nodeapp}` `generate @nrwl/workspace:run-commands echoEnvVariables --command=echo --envFile=${envFile} --project=${mylib}`
); );
const command = const command =
@ -35,11 +35,11 @@ describe('Run Commands', () => {
: `$SHARED_VAR $ROOT_ONLY $NESTED_ONLY`; : `$SHARED_VAR $ROOT_ONLY $NESTED_ONLY`;
const config = readJson(workspaceConfigName()); const config = readJson(workspaceConfigName());
config.projects[ config.projects[
nodeapp mylib
].targets.echoEnvVariables.options.command += ` ${command}`; ].targets.echoEnvVariables.options.command += ` ${command}`;
updateFile(workspaceConfigName(), JSON.stringify(config, null, 2)); updateFile(workspaceConfigName(), JSON.stringify(config, null, 2));
const result = runCLI('echoEnvVariables'); const result = runCLI(`run ${mylib}:echoEnvVariables`);
expect(result).toContain('shared-root-value'); expect(result).toContain('shared-root-value');
expect(result).not.toContain('shared-nested-value'); expect(result).not.toContain('shared-nested-value');
expect(result).toContain('root-only-value'); expect(result).toContain('root-only-value');
@ -47,12 +47,12 @@ describe('Run Commands', () => {
}, 120000); }, 120000);
it('should pass options', async () => { it('should pass options', async () => {
const myapp = uniq('myapp1'); const mylib = uniq('lib');
runCLI(`generate @nrwl/web:app ${myapp}`); runCLI(`generate @nrwl/workspace:lib ${mylib}`);
const config = readJson(workspaceConfigName()); const config = readJson(workspaceConfigName());
config.projects[myapp].targets.echo = { config.projects[mylib].targets.echo = {
executor: '@nrwl/workspace:run-commands', executor: '@nrwl/workspace:run-commands',
options: { options: {
command: 'echo', command: 'echo',
@ -64,19 +64,19 @@ describe('Run Commands', () => {
}; };
updateFile(workspaceConfigName(), JSON.stringify(config)); updateFile(workspaceConfigName(), JSON.stringify(config));
const result = runCLI(`run ${myapp}:echo`, { silent: true }); const result = runCLI(`run ${mylib}:echo`, { silent: true });
expect(result).toContain( expect(result).toContain(
'--var1=a --var2=b --var-hyphen=c --varCamelCase=d' '--var1=a --var2=b --var-hyphen=c --varCamelCase=d'
); );
}, 120000); }, 120000);
it('should interpolate provided arguments', async () => { it('should interpolate provided arguments', async () => {
const myapp = uniq('myapp1'); const mylib = uniq('lib');
runCLI(`generate @nrwl/web:app ${myapp}`); runCLI(`generate @nrwl/workspace:lib ${mylib}`);
const config = readJson(workspaceConfigName()); const config = readJson(workspaceConfigName());
config.projects[myapp].targets.echo = { config.projects[mylib].targets.echo = {
executor: '@nrwl/workspace:run-commands', executor: '@nrwl/workspace:run-commands',
options: { options: {
commands: [ commands: [
@ -92,7 +92,7 @@ describe('Run Commands', () => {
updateFile(workspaceConfigName(), JSON.stringify(config)); updateFile(workspaceConfigName(), JSON.stringify(config));
const result = runCLI( const result = runCLI(
`run ${myapp}:echo --var1=a --var2=b --var-hyphen=c --varCamelCase=d` `run ${mylib}:echo --var1=a --var2=b --var-hyphen=c --varCamelCase=d`
); );
expect(result).toContain('var1: a'); expect(result).toContain('var1: a');
expect(result).toContain('var2: b'); expect(result).toContain('var2: b');
@ -100,7 +100,7 @@ describe('Run Commands', () => {
expect(result).toContain('camel: d'); expect(result).toContain('camel: d');
const resultArgs = runCLI( const resultArgs = runCLI(
`run ${myapp}:echo --args="--var1=a --var2=b --var-hyphen=c --varCamelCase=d"` `run ${mylib}:echo --args="--var1=a --var2=b --var-hyphen=c --varCamelCase=d"`
); );
expect(resultArgs).toContain('var1: a'); expect(resultArgs).toContain('var1: a');
expect(resultArgs).toContain('var2: b'); expect(resultArgs).toContain('var2: b');
@ -109,12 +109,12 @@ describe('Run Commands', () => {
}, 120000); }, 120000);
it('should fail when a process exits non-zero', () => { it('should fail when a process exits non-zero', () => {
const myapp = uniq('myapp1'); const mylib = uniq('lib');
runCLI(`generate @nrwl/web:app ${myapp}`); runCLI(`generate @nrwl/workspace:lib ${mylib}`);
const config = readJson(workspaceConfigName()); const config = readJson(workspaceConfigName());
config.projects[myapp].targets.error = { config.projects[mylib].targets.error = {
executor: '@nrwl/workspace:run-commands', executor: '@nrwl/workspace:run-commands',
options: { options: {
command: `exit 1`, command: `exit 1`,
@ -123,7 +123,7 @@ describe('Run Commands', () => {
updateFile(workspaceConfigName(), JSON.stringify(config)); updateFile(workspaceConfigName(), JSON.stringify(config));
try { try {
runCLI(`run ${myapp}:error`); runCLI(`run ${mylib}:error`);
fail('Should error if process errors'); fail('Should error if process errors');
} catch (e) { } catch (e) {
expect(e.stderr.toString()).toContain( expect(e.stderr.toString()).toContain(
@ -133,17 +133,17 @@ describe('Run Commands', () => {
}); });
it('run command should not break if output property is missing in options and arguments', () => { it('run command should not break if output property is missing in options and arguments', () => {
const myapp = uniq('myapp'); const mylib = uniq('mylib');
runCLI(`generate @nrwl/web:app ${myapp}`); runCLI(`generate @nrwl/workspace:lib ${mylib}`);
const workspaceJson = readJson(`workspace.json`); const workspaceJson = readJson(`workspace.json`);
workspaceJson.projects[myapp].targets.lint.outputs = [ workspaceJson.projects[mylib].targets.lint.outputs = [
'{options.outputFile}', '{options.outputFile}',
]; ];
updateFile('workspace.json', JSON.stringify(workspaceJson, null, 2)); updateFile('workspace.json', JSON.stringify(workspaceJson, null, 2));
expect(() => expect(() =>
runCLI(`run ${myapp}:lint --format=json`, { runCLI(`run ${mylib}:lint --format=json`, {
silenceError: true, silenceError: true,
}) })
).not.toThrow(); ).not.toThrow();

View File

@ -0,0 +1,10 @@
module.exports = {
preset: '../../jest.preset.js',
transform: {
'^.+\\.[tj]sx?$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
maxWorkers: 1,
globals: { 'ts-jest': { tsconfig: '<rootDir>/tsconfig.spec.json' } },
displayName: 'e2e-workspace-create',
};

View File

@ -0,0 +1,34 @@
{
"root": "e2e/workspace-create",
"sourceRoot": "e2e/workspace-create",
"projectType": "application",
"targets": {
"e2e": {
"executor": "@nrwl/workspace:run-commands",
"options": {
"commands": [
{
"command": "yarn e2e-start-local-registry"
},
{
"command": "yarn e2e-build-package-publish"
},
{
"command": "nx run-e2e-tests e2e-workspace-create"
}
],
"parallel": false
}
},
"run-e2e-tests": {
"executor": "@nrwl/jest:jest",
"options": {
"jestConfig": "e2e/workspace-create/jest.config.js",
"passWithNoTests": true,
"runInBand": true
},
"outputs": ["coverage/e2e/workspace-create"]
}
},
"implicitDependencies": ["create-nx-workspace"]
}

View File

@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"types": ["node", "jest"]
},
"include": [],
"files": [],
"references": [
{
"path": "./tsconfig.spec.json"
}
]
}

View File

@ -0,0 +1,16 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"**/*.test.ts",
"**/*.spec.ts",
"**/*.spec.tsx",
"**/*.spec.js",
"**/*.spec.jsx",
"**/*.d.ts"
]
}

View File

@ -0,0 +1,10 @@
module.exports = {
preset: '../../jest.preset.js',
transform: {
'^.+\\.[tj]sx?$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
maxWorkers: 1,
globals: { 'ts-jest': { tsconfig: '<rootDir>/tsconfig.spec.json' } },
displayName: 'e2e-workspace-integrations',
};

View File

@ -0,0 +1,34 @@
{
"root": "e2e/workspace-integrations",
"sourceRoot": "e2e/workspace-integrations",
"projectType": "application",
"targets": {
"e2e": {
"executor": "@nrwl/workspace:run-commands",
"options": {
"commands": [
{
"command": "yarn e2e-start-local-registry"
},
{
"command": "yarn e2e-build-package-publish"
},
{
"command": "nx run-e2e-tests e2e-workspace-integrations"
}
],
"parallel": false
}
},
"run-e2e-tests": {
"executor": "@nrwl/jest:jest",
"options": {
"jestConfig": "e2e/workspace-integrations/jest.config.js",
"passWithNoTests": true,
"runInBand": true
},
"outputs": ["coverage/e2e/workspace-integrations"]
}
},
"implicitDependencies": ["angular", "react"]
}

View File

@ -0,0 +1,56 @@
import {
checkFilesExist,
readFile,
readJson,
runCLI,
runCLIAsync,
runCreateWorkspace,
uniq,
packageInstall,
removeProject,
getSelectedPackageManager,
} from '@nrwl/e2e/utils';
describe('custom workspace layout', () => {
afterAll(() => removeProject({ onlyOnCI: true }));
it('should work', async () => {
// TODO (meeroslav): what is the purpose of this test?
// const proj = uniq('custom-layout-proj');
// const packageManager = getSelectedPackageManager();
// runCreateWorkspace(proj, { preset: 'npm', packageManager });
// packageInstall('@nrwl/react @nrwl/angular @nrwl/express');
// const nxJson = readJson('nx.json');
// expect(nxJson.extends).toEqual('@nrwl/workspace/presets/npm.json');
// const reactApp = uniq('reactapp');
// const reactLib = uniq('reactlib');
// const ngApp = uniq('ngapp');
// const ngLib = uniq('nglib');
// const expressApp = uniq('expessapp');
// const expressLib = uniq('expresslib');
// runCLI(`generate @nrwl/react:app ${reactApp} --no-interactive`);
// runCLI(`generate @nrwl/react:lib ${reactLib} --no-interactive`);
// runCLI(`generate @nrwl/angular:app ${ngApp} --no-interactive`);
// runCLI(`generate @nrwl/angular:lib ${ngLib} --no-interactive`);
// runCLI(`generate @nrwl/express:app ${expressApp} --no-interactive`);
// runCLI(`generate @nrwl/express:lib ${expressLib} --no-interactive`);
// checkFilesExist(
// `packages/${reactLib}/src/index.ts`,
// `packages/${reactApp}/src/main.tsx`,
// `packages/${reactApp}-e2e/cypress.json`,
// `packages/${ngLib}/src/index.ts`,
// `packages/${ngApp}/src/main.ts`,
// `packages/${ngApp}-e2e/cypress.json`,
// `packages/${expressLib}/src/index.ts`,
// `packages/${expressApp}/src/main.ts`
// );
// const workspaceJson = readFile('workspace.json');
// expect(workspaceJson).not.toContain('apps/');
// expect(workspaceJson).not.toContain('libs/');
// const libTestResults = await runCLIAsync(`test ${expressLib}`);
// expect(libTestResults.stdout).toContain(`nx run ${expressLib}:test`);
// const appBuildResults = await runCLIAsync(`build ${expressApp}`);
// expect(appBuildResults.stdout).toContain(`nx run ${expressApp}:build`);
// checkFilesExist(`dist/packages/${expressApp}/main.js`);
}, 1000000);
});

View File

@ -0,0 +1,476 @@
import * as path from 'path';
import {
checkFilesExist,
exists,
isNotWindows,
newProject,
readFile,
readJson,
removeProject,
runCLI,
runCLIAsync,
tmpProjPath,
uniq,
updateFile,
} from '@nrwl/e2e/utils';
import type { NxJsonConfiguration } from '@nrwl/devkit';
import { classify } from '@nrwl/workspace/src/utils/strings';
let proj: string;
beforeAll(() => {
proj = newProject();
});
describe('format', () => {
it('should check and reformat the code', async () => {
if (isNotWindows()) {
const myapp = uniq('myapp');
const mylib = uniq('mylib');
runCLI(`generate @nrwl/angular:app ${myapp}`);
runCLI(`generate @nrwl/angular:lib ${mylib}`);
updateFile(
`apps/${myapp}/src/main.ts`,
`
const x = 1111;
`
);
updateFile(
`apps/${myapp}/src/app/app.module.ts`,
`
const y = 1111;
`
);
updateFile(
`apps/${myapp}/src/app/app.component.ts`,
`
const z = 1111;
`
);
updateFile(
`libs/${mylib}/index.ts`,
`
const x = 1111;
`
);
updateFile(
`libs/${mylib}/src/${mylib}.module.ts`,
`
const y = 1111;
`
);
updateFile(
`README.md`,
`
my new readme;
`
);
let stdout = runCLI(
`format:check --files="libs/${mylib}/index.ts,package.json" --libs-and-apps`,
{ silenceError: true }
);
expect(stdout).toContain(path.normalize(`libs/${mylib}/index.ts`));
expect(stdout).toContain(
path.normalize(`libs/${mylib}/src/${mylib}.module.ts`)
);
expect(stdout).not.toContain(path.normalize(`README.md`)); // It will be contained only in case of exception, that we fallback to all
stdout = runCLI(`format:check --all`, { silenceError: true });
expect(stdout).toContain(path.normalize(`apps/${myapp}/src/main.ts`));
expect(stdout).toContain(
path.normalize(`apps/${myapp}/src/app/app.module.ts`)
);
expect(stdout).toContain(
path.normalize(`apps/${myapp}/src/app/app.component.ts`)
);
stdout = runCLI(`format:check --projects=${myapp}`, {
silenceError: true,
});
expect(stdout).toContain(path.normalize(`apps/${myapp}/src/main.ts`));
expect(stdout).toContain(
path.normalize(`apps/${myapp}/src/app/app.module.ts`)
);
expect(stdout).toContain(
path.normalize(`apps/${myapp}/src/app/app.component.ts`)
);
expect(stdout).not.toContain(path.normalize(`libs/${mylib}/index.ts`));
expect(stdout).not.toContain(
path.normalize(`libs/${mylib}/src/${mylib}.module.ts`)
);
expect(stdout).not.toContain(path.normalize(`README.md`));
stdout = runCLI(`format:check --projects=${myapp},${mylib}`, {
silenceError: true,
});
expect(stdout).toContain(path.normalize(`apps/${myapp}/src/main.ts`));
expect(stdout).toContain(
path.normalize(`apps/${myapp}/src/app/app.module.ts`)
);
expect(stdout).toContain(
path.normalize(`apps/${myapp}/src/app/app.component.ts`)
);
expect(stdout).toContain(path.normalize(`libs/${mylib}/index.ts`));
expect(stdout).toContain(
path.normalize(`libs/${mylib}/src/${mylib}.module.ts`)
);
expect(stdout).not.toContain(path.normalize(`README.md`));
const { stderr } = await runCLIAsync(
`format:check --projects=${myapp},${mylib} --all`,
{
silenceError: true,
}
);
expect(stderr).toContain(
'Arguments all and projects are mutually exclusive'
);
runCLI(
`format:write --files="apps/${myapp}/src/app/app.module.ts,apps/${myapp}/src/app/app.component.ts"`
);
stdout = runCLI('format:check --all', { silenceError: true });
expect(stdout).toContain(path.normalize(`apps/${myapp}/src/main.ts`));
expect(stdout).not.toContain(
path.normalize(`apps/${myapp}/src/app/app.module.ts`)
);
expect(stdout).not.toContain(
path.normalize(`apps/${myapp}/src/app/app.component.ts`)
);
runCLI('format:write --all');
expect(runCLI('format:check --all')).not.toContain(
path.normalize(`apps/${myapp}/src/main.ts`)
);
}
}, 90000);
});
describe('dep-graph', () => {
let proj: string;
let myapp: string;
let myapp2: string;
let myapp3: string;
let myappE2e: string;
let myapp2E2e: string;
let myapp3E2e: string;
let mylib: string;
let mylib2: string;
beforeAll(() => {
proj = newProject();
myapp = uniq('myapp');
myapp2 = uniq('myapp2');
myapp3 = uniq('myapp3');
myappE2e = `${myapp}-e2e`;
myapp2E2e = `${myapp2}-e2e`;
myapp3E2e = `${myapp3}-e2e`;
mylib = uniq('mylib');
mylib2 = uniq('mylib2');
runCLI(`generate @nrwl/angular:app ${myapp}`);
runCLI(`generate @nrwl/angular:app ${myapp2}`);
runCLI(`generate @nrwl/angular:app ${myapp3}`);
runCLI(`generate @nrwl/angular:lib ${mylib}`);
runCLI(`generate @nrwl/angular:lib ${mylib2}`);
updateFile(
`apps/${myapp}/src/main.ts`,
`
import '@${proj}/${mylib}';
const s = {loadChildren: '@${proj}/${mylib2}'};
`
);
updateFile(
`apps/${myapp2}/src/app/app.component.spec.ts`,
`import '@${proj}/${mylib}';`
);
updateFile(
`libs/${mylib}/src/mylib.module.spec.ts`,
`import '@${proj}/${mylib2}';`
);
});
it('dep-graph should output json to file', () => {
runCLI(`dep-graph --file=project-graph.json`);
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
const jsonFileContents = readJson('project-graph.json');
expect(jsonFileContents.graph.dependencies).toEqual(
expect.objectContaining({
[myapp3E2e]: [
{
source: myapp3E2e,
target: myapp3,
type: 'implicit',
},
],
[myapp2]: [
{
source: myapp2,
target: mylib,
type: 'static',
},
],
[myapp2E2e]: [
{
source: myapp2E2e,
target: myapp2,
type: 'implicit',
},
],
[mylib]: [
{
source: mylib,
target: mylib2,
type: 'static',
},
],
[mylib2]: [],
[myapp]: [
{
source: myapp,
target: mylib,
type: 'static',
},
{ source: myapp, target: mylib2, type: 'static' },
],
[myappE2e]: [
{
source: myappE2e,
target: myapp,
type: 'implicit',
},
],
[myapp3]: [],
})
);
runCLI(
`affected:dep-graph --files="libs/${mylib}/src/index.ts" --file="project-graph.json"`
);
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
const jsonFileContents2 = readJson('project-graph.json');
expect(jsonFileContents2.criticalPath).toContain(myapp);
expect(jsonFileContents2.criticalPath).toContain(myapp2);
expect(jsonFileContents2.criticalPath).toContain(mylib);
expect(jsonFileContents2.criticalPath).not.toContain(mylib2);
}, 1000000);
it('dep-graph should focus requested project', () => {
runCLI(`dep-graph --focus=${myapp} --file=project-graph.json`);
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
const jsonFileContents = readJson('project-graph.json');
const projectNames = Object.keys(jsonFileContents.graph.nodes);
expect(projectNames).toContain(myapp);
expect(projectNames).toContain(mylib);
expect(projectNames).toContain(mylib2);
expect(projectNames).toContain(myappE2e);
expect(projectNames).not.toContain(myapp2);
expect(projectNames).not.toContain(myapp3);
expect(projectNames).not.toContain(myapp2E2e);
expect(projectNames).not.toContain(myapp3E2e);
}, 1000000);
it('dep-graph should exclude requested projects', () => {
runCLI(
`dep-graph --exclude=${myappE2e},${myapp2E2e},${myapp3E2e} --file=project-graph.json`
);
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
const jsonFileContents = readJson('project-graph.json');
const projectNames = Object.keys(jsonFileContents.graph.nodes);
expect(projectNames).toContain(myapp);
expect(projectNames).toContain(mylib);
expect(projectNames).toContain(mylib2);
expect(projectNames).toContain(myapp2);
expect(projectNames).toContain(myapp3);
expect(projectNames).not.toContain(myappE2e);
expect(projectNames).not.toContain(myapp2E2e);
expect(projectNames).not.toContain(myapp3E2e);
}, 1000000);
it('dep-graph should exclude requested projects that were included by a focus', () => {
runCLI(
`dep-graph --focus=${myapp} --exclude=${myappE2e} --file=project-graph.json`
);
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
const jsonFileContents = readJson('project-graph.json');
const projectNames = Object.keys(jsonFileContents.graph.nodes);
expect(projectNames).toContain(myapp);
expect(projectNames).toContain(mylib);
expect(projectNames).toContain(mylib2);
expect(projectNames).not.toContain(myappE2e);
expect(projectNames).not.toContain(myapp2);
expect(projectNames).not.toContain(myapp3);
expect(projectNames).not.toContain(myapp2E2e);
expect(projectNames).not.toContain(myapp3E2e);
}, 1000000);
it('dep-graph should output a deployable static website in an html file accompanied by a folder with static assets', () => {
runCLI(`dep-graph --file=project-graph.html`);
expect(() => checkFilesExist('project-graph.html')).not.toThrow();
expect(() => checkFilesExist('static/styles.css')).not.toThrow();
expect(() => checkFilesExist('static/runtime.esm.js')).not.toThrow();
expect(() => checkFilesExist('static/polyfills.esm.js')).not.toThrow();
expect(() => checkFilesExist('static/main.esm.js')).not.toThrow();
});
});
describe('Move Angular Project', () => {
let proj: string;
let app1: string;
let app2: string;
let newPath: string;
beforeEach(() => {
proj = newProject();
app1 = uniq('app1');
app2 = uniq('app2');
newPath = `subfolder/${app2}`;
runCLI(`generate @nrwl/angular:app ${app1}`);
});
afterEach(() => removeProject({ onlyOnCI: true }));
/**
* Tries moving an app from ${app1} -> subfolder/${app2}
*/
it('should work for apps', () => {
const moveOutput = runCLI(
`generate @nrwl/angular:move --project ${app1} ${newPath}`
);
// just check the output
expect(moveOutput).toContain(`DELETE apps/${app1}`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/.browserslistrc`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/jest.config.js`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.app.json`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.json`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.spec.json`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/.eslintrc.json`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/favicon.ico`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/index.html`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/main.ts`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/polyfills.ts`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/styles.css`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/test-setup.ts`);
expect(moveOutput).toContain(
`CREATE apps/${newPath}/src/app/app.component.html`
);
expect(moveOutput).toContain(
`CREATE apps/${newPath}/src/app/app.module.ts`
);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/assets/.gitkeep`);
expect(moveOutput).toContain(
`CREATE apps/${newPath}/src/environments/environment.prod.ts`
);
expect(moveOutput).toContain(
`CREATE apps/${newPath}/src/environments/environment.ts`
);
expect(moveOutput).toContain(`UPDATE nx.json`);
expect(moveOutput).toContain(`UPDATE workspace.json`);
});
/**
* Tries moving an e2e project from ${app1} -> ${newPath}
*/
it('should work for e2e projects', () => {
const moveOutput = runCLI(
`generate @nrwl/angular:move --projectName=${app1}-e2e --destination=${newPath}-e2e`
);
// just check that the cypress.json is updated correctly
const cypressJsonPath = `apps/${newPath}-e2e/cypress.json`;
expect(moveOutput).toContain(`CREATE ${cypressJsonPath}`);
checkFilesExist(cypressJsonPath);
const cypressJson = readJson(cypressJsonPath);
expect(cypressJson.videosFolder).toEqual(
`../../../dist/cypress/apps/${newPath}-e2e/videos`
);
expect(cypressJson.screenshotsFolder).toEqual(
`../../../dist/cypress/apps/${newPath}-e2e/screenshots`
);
});
/**
* Tries moving a library from ${lib} -> shared/${lib}
*/
it('should work for libraries', () => {
const lib1 = uniq('mylib');
const lib2 = uniq('mylib');
runCLI(`generate @nrwl/angular:lib ${lib1}`);
/**
* Create a library which imports the module from the other lib
*/
runCLI(`generate @nrwl/angular:lib ${lib2}`);
updateFile(
`libs/${lib2}/src/lib/${lib2}.module.ts`,
`import { ${classify(lib1)}Module } from '@${proj}/${lib1}';
export class ExtendedModule extends ${classify(lib1)}Module { }`
);
const moveOutput = runCLI(
`generate @nrwl/angular:move --projectName=${lib1} --destination=shared/${lib1}`
);
const newPath = `libs/shared/${lib1}`;
const newModule = `Shared${classify(lib1)}Module`;
const testSetupPath = `${newPath}/src/test-setup.ts`;
expect(moveOutput).toContain(`CREATE ${testSetupPath}`);
checkFilesExist(testSetupPath);
const modulePath = `${newPath}/src/lib/shared-${lib1}.module.ts`;
expect(moveOutput).toContain(`CREATE ${modulePath}`);
checkFilesExist(modulePath);
const moduleFile = readFile(modulePath);
expect(moduleFile).toContain(`export class ${newModule}`);
const indexPath = `${newPath}/src/index.ts`;
expect(moveOutput).toContain(`CREATE ${indexPath}`);
checkFilesExist(indexPath);
const index = readFile(indexPath);
expect(index).toContain(`export * from './lib/shared-${lib1}.module'`);
/**
* Check that the import in lib2 has been updated
*/
const lib2FilePath = `libs/${lib2}/src/lib/${lib2}.module.ts`;
const lib2File = readFile(lib2FilePath);
expect(lib2File).toContain(
`import { ${newModule} } from '@${proj}/shared-${lib1}';`
);
expect(lib2File).toContain(`extends ${newModule}`);
});
});

View File

@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"types": ["node", "jest"]
},
"include": [],
"files": [],
"references": [
{
"path": "./tsconfig.spec.json"
}
]
}

View File

@ -0,0 +1,16 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"**/*.test.ts",
"**/*.spec.ts",
"**/*.spec.tsx",
"**/*.spec.js",
"**/*.spec.jsx",
"**/*.d.ts"
]
}

View File

@ -1,69 +0,0 @@
import {
checkFilesExist,
readFile,
readJson,
runCLI,
runCLIAsync,
runCreateWorkspace,
uniq,
packageInstall,
removeProject,
getSelectedPackageManager,
} from '@nrwl/e2e/utils';
describe('custom workspace layout', () => {
afterAll(() => removeProject({ onlyOnCI: true }));
it('should work', async () => {
const proj = uniq('custom-layout-proj');
const packageManager = getSelectedPackageManager();
runCreateWorkspace(proj, { preset: 'npm', packageManager });
packageInstall('@nrwl/react @nrwl/angular @nrwl/express');
const nxJson = readJson('nx.json');
expect(nxJson.extends).toEqual('@nrwl/workspace/presets/npm.json');
const reactApp = uniq('reactapp');
const reactLib = uniq('reactlib');
const ngApp = uniq('ngapp');
const ngLib = uniq('nglib');
const expressApp = uniq('expessapp');
const expressLib = uniq('expresslib');
runCLI(`generate @nrwl/react:app ${reactApp} --no-interactive`);
runCLI(`generate @nrwl/react:lib ${reactLib} --no-interactive`);
runCLI(`generate @nrwl/angular:app ${ngApp} --no-interactive`);
runCLI(`generate @nrwl/angular:lib ${ngLib} --no-interactive`);
runCLI(`generate @nrwl/express:app ${expressApp} --no-interactive`);
runCLI(`generate @nrwl/express:lib ${expressLib} --no-interactive`);
checkFilesExist(
`packages/${reactLib}/src/index.ts`,
`packages/${reactApp}/src/main.tsx`,
`packages/${reactApp}-e2e/cypress.json`,
`packages/${ngLib}/src/index.ts`,
`packages/${ngApp}/src/main.ts`,
`packages/${ngApp}-e2e/cypress.json`,
`packages/${expressLib}/src/index.ts`,
`packages/${expressApp}/src/main.ts`
);
const workspaceJson = readFile('workspace.json');
expect(workspaceJson).not.toContain('apps/');
expect(workspaceJson).not.toContain('libs/');
const libTestResults = await runCLIAsync(`test ${expressLib}`);
expect(libTestResults.stdout).toContain(`nx run ${expressLib}:test`);
const appBuildResults = await runCLIAsync(`build ${expressApp}`);
expect(appBuildResults.stdout).toContain(`nx run ${expressApp}:build`);
checkFilesExist(`dist/packages/${expressApp}/main.js`);
}, 1000000);
});

View File

@ -37,7 +37,9 @@
"e2e-storybook": "e2e/storybook", "e2e-storybook": "e2e/storybook",
"e2e-utils": "e2e/utils", "e2e-utils": "e2e/utils",
"e2e-web": "e2e/web", "e2e-web": "e2e/web",
"e2e-workspace": "e2e/workspace", "e2e-workspace-core": "e2e/workspace-core",
"e2e-workspace-create": "e2e/workspace-create",
"e2e-workspace-integrations": "e2e/workspace-integrations",
"eslint-plugin-nx": "packages/eslint-plugin-nx", "eslint-plugin-nx": "packages/eslint-plugin-nx",
"express": "packages/express", "express": "packages/express",
"gatsby": "packages/gatsby", "gatsby": "packages/gatsby",