cleanup(core): refactor e2e tests for workspace

This commit is contained in:
Victor Savkin 2020-03-12 18:25:02 -04:00 committed by Victor Savkin
parent 818727c3f0
commit 1c2eedf9cb
24 changed files with 1553 additions and 1772 deletions

View File

@ -99,6 +99,7 @@ jobs:
- run:
name: Nx CLI E2E Tests Part 1
command: yarn e2e-ci1 nx
no_output_timeout: 30m
e2e-nx-2:
executor: default
steps:
@ -106,6 +107,7 @@ jobs:
- run:
name: Nx CLI E2E Tests Part 2
command: yarn e2e-ci2 nx
no_output_timeout: 30m
e2e-nx-3:
executor: default
steps:
@ -113,6 +115,7 @@ jobs:
- run:
name: Nx CLI E2E Tests Part 3
command: yarn e2e-ci3 nx
no_output_timeout: 30m
e2e-nx-4:
executor: default
steps:
@ -120,6 +123,7 @@ jobs:
- run:
name: Nx CLI E2E Tests Part 4
command: yarn e2e-ci4 nx
no_output_timeout: 30m
e2e-ng-1:
executor: default
steps:
@ -127,6 +131,7 @@ jobs:
- run:
name: Angular CLI E2E Tests Part 1
command: yarn e2e-ci1 angular
no_output_timeout: 30m
e2e-ng-2:
executor: default
steps:
@ -134,6 +139,7 @@ jobs:
- run:
name: Angular CLI E2E Tests Part 2
command: yarn e2e-ci2 angular
no_output_timeout: 30m
e2e-ng-3:
executor: default
steps:
@ -141,6 +147,7 @@ jobs:
- run:
name: Angular CLI E2E Tests Part 3
command: yarn e2e-ci3 angular
no_output_timeout: 30m
e2e-ng-4:
executor: default
steps:
@ -148,6 +155,7 @@ jobs:
- run:
name: Angular CLI E2E Tests Part 4
command: yarn e2e-ci4 angular
no_output_timeout: 30m
workflows:
version: 2.1

View File

@ -1,85 +0,0 @@
import {
ensureProject,
readJson,
runCommand,
uniq,
updateFile,
runCLI,
forEachCli,
workspaceConfigName
} from './utils';
import { NxJson } from '@nrwl/workspace/src/core/shared-interfaces';
forEachCli(() => {
describe('Affected (with Git)', () => {
let myapp = uniq('myapp');
let myapp2 = uniq('myapp');
let mylib = uniq('mylib');
it('should not affect other projects by generating a new project', () => {
ensureProject();
const nxJson: NxJson = readJson('nx.json');
delete nxJson.implicitDependencies;
updateFile('nx.json', JSON.stringify(nxJson));
runCommand(`git init`);
runCommand(`git config user.email "test@test.com"`);
runCommand(`git config user.name "Test"`);
runCommand(
`git add . && git commit -am "initial commit" && git checkout -b master`
);
runCLI(`generate @nrwl/angular:app ${myapp}`);
expect(runCommand('yarn affected:apps')).toContain(myapp);
runCommand(`git add . && git commit -am "add ${myapp}"`);
runCLI(`generate @nrwl/angular:app ${myapp2}`);
expect(runCommand('yarn affected:apps')).not.toContain(myapp);
expect(runCommand('yarn affected:apps')).toContain(myapp2);
runCommand(`git add . && git commit -am "add ${myapp2}"`);
runCLI(`generate @nrwl/angular:lib ${mylib}`);
expect(runCommand('yarn affected:apps')).not.toContain(myapp);
expect(runCommand('yarn affected:apps')).not.toContain(myapp2);
expect(runCommand('yarn affected:libs')).toContain(mylib);
runCommand(`git add . && git commit -am "add ${mylib}"`);
}, 1000000);
it('should detect changes to projects based on the nx.json', () => {
const nxJson: NxJson = readJson('nx.json');
nxJson.projects[myapp].tags = ['tag'];
updateFile('nx.json', JSON.stringify(nxJson));
expect(runCommand('yarn affected:apps')).toContain(myapp);
expect(runCommand('yarn affected:apps')).not.toContain(myapp2);
expect(runCommand('yarn affected:libs')).not.toContain(mylib);
runCommand(`git add . && git commit -am "add tag to ${myapp}"`);
});
it('should detect changes to projects based on the workspace.json', () => {
const workspaceJson = readJson(workspaceConfigName());
workspaceJson.projects[myapp].prefix = 'my-app';
updateFile(workspaceConfigName(), JSON.stringify(workspaceJson));
expect(runCommand('yarn affected:apps')).toContain(myapp);
expect(runCommand('yarn affected:apps')).not.toContain(myapp2);
expect(runCommand('yarn affected:libs')).not.toContain(mylib);
runCommand(`git add . && git commit -am "change prefix for ${myapp}"`);
});
it('should affect all projects by removing projects', () => {
const workspaceJson = readJson(workspaceConfigName());
delete workspaceJson.projects[mylib];
updateFile(workspaceConfigName(), JSON.stringify(workspaceJson));
const nxJson = readJson('nx.json');
delete nxJson.projects[mylib];
updateFile('nx.json', JSON.stringify(nxJson));
expect(runCommand('yarn affected:apps')).toContain(myapp);
expect(runCommand('yarn affected:apps')).toContain(myapp2);
expect(runCommand('yarn affected:libs')).not.toContain(mylib);
runCommand(`git add . && git commit -am "remove ${mylib}"`);
});
});
});

View File

@ -1,293 +0,0 @@
import {
ensureProject,
readFile,
readJson,
runCommand,
uniq,
updateFile,
runCLI,
forEachCli,
supportUi
} from './utils';
let originalCIValue: any;
forEachCli(() => {
/**
* Setting CI=true makes it simpler to configure assertions around output, as there
* won't be any colors.
*/
beforeAll(() => {
originalCIValue = process.env.CI;
process.env.CI = 'true';
});
afterAll(() => {
process.env.CI = originalCIValue;
});
describe('Affected', () => {
it('should print, build, and test affected apps', () => {
ensureProject();
const myapp = uniq('myapp');
const myapp2 = uniq('myapp2');
const mylib = uniq('mylib');
const mylib2 = uniq('mylib2');
const mypublishablelib = uniq('mypublishablelib');
runCLI(`generate @nrwl/angular:app ${myapp}`);
runCLI(`generate @nrwl/angular:app ${myapp2}`);
runCLI(`generate @nrwl/angular:lib ${mylib}`);
runCLI(`generate @nrwl/angular:lib ${mylib2}`);
runCLI(`generate @nrwl/angular:lib ${mypublishablelib} --publishable`);
updateFile(
`apps/${myapp}/src/app/app.component.spec.ts`,
`
import '@proj/${mylib}';
describe('sample test', () => {
it('should test', () => {
expect(1).toEqual(1);
});
});
`
);
updateFile(
`libs/${mypublishablelib}/src/lib/${mypublishablelib}.module.spec.ts`,
`
import '@proj/${mylib}';
describe('sample test', () => {
it('should test', () => {
expect(1).toEqual(1);
});
});
`
);
expect(
runCommand(
`npm run affected:apps -- --files="libs/${mylib}/src/index.ts" --plain`
).split('\n')[4]
).toEqual(myapp);
const affectedApps = runCommand(
`npm run affected:apps -- --files="libs/${mylib}/src/index.ts"`
);
expect(affectedApps).toContain(myapp);
expect(affectedApps).not.toContain(myapp2);
expect(affectedApps).not.toContain(`${myapp}-e2e`);
const implicitlyAffectedApps = runCommand(
'npm run affected:apps -- --files="tsconfig.json"'
);
expect(implicitlyAffectedApps).toContain(myapp);
expect(implicitlyAffectedApps).toContain(myapp2);
const noAffectedApps = runCommand(
'npm run affected:apps -- --files="README.md"'
);
expect(noAffectedApps).not.toContain(myapp);
expect(noAffectedApps).not.toContain(myapp2);
expect(
runCommand(
`npm run affected:libs -- --files="libs/${mylib}/src/index.ts" --plain`
).split('\n')[4]
).toEqual(`${mylib} ${mypublishablelib}`);
const affectedLibs = runCommand(
`npm run affected:libs -- --files="libs/${mylib}/src/index.ts"`
);
expect(affectedLibs).toContain(mypublishablelib);
expect(affectedLibs).toContain(mylib);
expect(affectedLibs).not.toContain(mylib2);
const implicitlyAffectedLibs = runCommand(
'npm run affected:libs -- --files="tsconfig.json"'
);
expect(implicitlyAffectedLibs).toContain(mypublishablelib);
expect(implicitlyAffectedLibs).toContain(mylib);
expect(implicitlyAffectedLibs).toContain(mylib2);
const noAffectedLibs = runCommand(
'npm run affected:libs -- --files="README.md"'
);
expect(noAffectedLibs).not.toContain(mypublishablelib);
expect(noAffectedLibs).not.toContain(mylib);
expect(noAffectedLibs).not.toContain(mylib2);
const build = runCommand(
`npm run affected:build -- --files="libs/${mylib}/src/index.ts"`
);
expect(build).toContain(`Running target build for projects:`);
expect(build).toContain(`- ${myapp}`);
expect(build).toContain(`- ${mypublishablelib}`);
expect(build).not.toContain('is not registered with the build command');
expect(build).not.toContain('with flags:');
// Should work in parallel
const buildParallel = runCommand(
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --parallel`
);
expect(buildParallel).toContain(`Running target build for projects:`);
expect(buildParallel).toContain(`- ${myapp}`);
expect(buildParallel).toContain(`- ${mypublishablelib}`);
expect(buildParallel).toContain('Running target "build" succeeded');
const buildExcluded = runCommand(
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --exclude ${myapp}`
);
expect(buildExcluded).toContain(`Running target build for projects:`);
expect(buildExcluded).toContain(`- ${mypublishablelib}`);
// affected:build should pass non-nx flags to the CLI
const buildWithFlags = runCommand(
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" -- --stats-json`
);
expect(buildWithFlags).toContain(`Running target build for projects:`);
expect(buildWithFlags).toContain(`- ${myapp}`);
expect(buildWithFlags).toContain(`- ${mypublishablelib}`);
expect(buildWithFlags).toContain('With flags:');
expect(buildWithFlags).toContain('--stats-json=true');
if (supportUi()) {
const e2e = runCommand(
`npm run affected:e2e -- --files="libs/${mylib}/src/index.ts" --headless`
);
expect(e2e).toContain('should display welcome message');
}
const unitTests = runCommand(
`npm run affected:test -- --files="libs/${mylib}/src/index.ts"`
);
expect(unitTests).toContain(`Running target test for projects:`);
expect(unitTests).toContain(`- ${mylib}`);
expect(unitTests).toContain(`- ${myapp}`);
expect(unitTests).toContain(`- ${mypublishablelib}`);
// Fail a Unit Test
updateFile(
`apps/${myapp}/src/app/app.component.spec.ts`,
readFile(`apps/${myapp}/src/app/app.component.spec.ts`).replace(
'.toEqual(1)',
'.toEqual(2)'
)
);
const failedTests = runCommand(
`npm run affected:test -- --files="libs/${mylib}/src/index.ts"`
);
expect(failedTests).toContain(`Running target test for projects:`);
expect(failedTests).toContain(`- ${mylib}`);
expect(failedTests).toContain(`- ${myapp}`);
expect(failedTests).toContain(`- ${mypublishablelib}`);
expect(failedTests).toContain(`Failed projects:`);
expect(failedTests).toContain(
'You can isolate the above projects by passing: --only-failed'
);
expect(readJson('dist/.nx-results')).toEqual({
command: 'test',
results: {
[myapp]: false,
[mylib]: true,
[mypublishablelib]: true
}
});
// Fix failing Unit Test
updateFile(
`apps/${myapp}/src/app/app.component.spec.ts`,
readFile(`apps/${myapp}/src/app/app.component.spec.ts`).replace(
'.toEqual(2)',
'.toEqual(1)'
)
);
const isolatedTests = runCommand(
`npm run affected:test -- --files="libs/${mylib}/src/index.ts" --only-failed`
);
expect(isolatedTests).toContain(`Running target test for projects`);
expect(isolatedTests).toContain(`- ${myapp}`);
const linting = runCommand(
`npm run affected:lint -- --files="libs/${mylib}/src/index.ts"`
);
expect(linting).toContain(`Running target lint for projects:`);
expect(linting).toContain(`- ${mylib}`);
expect(linting).toContain(`- ${myapp}`);
expect(linting).toContain(`- ${myapp}-e2e`);
expect(linting).toContain(`- ${mypublishablelib}`);
const lintWithJsonFormatting = runCommand(
`npm run affected:lint -- --files="libs/${mylib}/src/index.ts" -- --format json`
);
expect(lintWithJsonFormatting).toContain('With flags:');
expect(lintWithJsonFormatting).toContain('--format=json');
const unitTestsExcluded = runCommand(
`npm run affected:test -- --files="libs/${mylib}/src/index.ts" --exclude=${myapp},${mypublishablelib}`
);
expect(unitTestsExcluded).toContain(`Running target test for projects:`);
expect(unitTestsExcluded).toContain(`- ${mylib}`);
const i18n = runCommand(
`npm run affected -- --target extract-i18n --files="libs/${mylib}/src/index.ts"`
);
expect(i18n).toContain(`Running target extract-i18n for projects:`);
expect(i18n).toContain(`- ${myapp}`);
const interpolatedTests = runCommand(
`npm run affected -- --target test --files="libs/${mylib}/src/index.ts" -- --jest-config {project.root}/jest.config.js`
);
expect(interpolatedTests).toContain(`Running target \"test\" succeeded`);
}, 1000000);
});
describe('build in the right order', () => {
let myapp, mypublishablelib;
beforeEach(() => {
ensureProject();
// create my app depending on mypublishablelib
myapp = uniq('myapp');
mypublishablelib = uniq('mypublishablelib');
runCLI(`generate @nrwl/angular:app ${myapp}`);
runCLI(`generate @nrwl/angular:lib ${mypublishablelib} --publishable`);
updateFile(
`apps/${myapp}/src/app/app.component.spec.ts`,
`
import '@proj/${mypublishablelib}';
describe('sample test', () => {
it('should test', () => {
expect(1).toEqual(1);
});
});
`
);
});
it('should wait for deps to be built before continuing', () => {
const build = runCommand(
`npm run affected:build -- --files="apps/${myapp}/src/main.ts,libs/${mypublishablelib}/src/index.ts" --parallel`
);
// make sure that the package is done building before we start building the app
expect(
build.indexOf('Built Angular Package!') <
build.indexOf(`Generating ES5 bundles for differential loading.`)
).toBeTruthy();
});
it('should not invoke build for projects who deps fail', () => {
updateFile(
`libs/${mypublishablelib}/src/index.ts`,
`
const x: number = 'string';
`
);
const build = runCommand(
`npm run affected:build -- --files="apps/${myapp}/src/main.ts,libs/${mypublishablelib}/src/index.ts" --parallel`
);
expect(build.indexOf(`"build" "${myapp}"`)).toEqual(-1);
});
});
});

View File

@ -15,7 +15,7 @@ import {
import { toClassName } from '@nrwl/workspace';
forEachCli(() => {
describe('Create New Workspace', () => {
describe('Angular Package', () => {
beforeEach(() => {
ensureProject();
});

View File

@ -1,39 +0,0 @@
import { forEachCli, newProject, runCLI, uniq, updateFile } from './utils';
forEachCli(() => {
describe('Buildable Libraries', () => {
it('should be able to run the task for the specified project and its dependencies', () => {
newProject();
const myapp = uniq('myapp');
const mylib1 = uniq('mylib1');
const mylib2 = uniq('mylib1');
runCLI(`generate @nrwl/react:app ${myapp}`);
runCLI(`generate @nrwl/react:lib ${mylib1} --publishable`);
runCLI(`generate @nrwl/react:lib ${mylib2} --publishable`);
updateFile(
`apps/${myapp}/src/main.ts`,
`
import "@proj/${mylib1}";
import "@proj/${mylib2}";
`
);
const buildWithDeps = runCLI(`build ${myapp} --with-deps --prod`);
expect(buildWithDeps).toContain(`Running target "build" succeeded`);
expect(buildWithDeps).toContain(`nx run ${myapp}:build:production`);
expect(buildWithDeps).toContain(`nx run ${mylib1}:build`);
expect(buildWithDeps).toContain(`nx run ${mylib2}:build`);
const testsWithDeps = runCLI(`test ${myapp} --with-deps`);
expect(testsWithDeps).toContain(`NX Running target test for projects:`);
expect(testsWithDeps).toContain(myapp);
expect(testsWithDeps).toContain(mylib1);
expect(testsWithDeps).toContain(mylib2);
const testsWithoutDeps = runCLI(`test ${myapp}`);
expect(testsWithoutDeps).not.toContain(mylib1);
});
});
});

View File

@ -1,157 +0,0 @@
import {
forEachCli,
listFiles,
newProject,
rmDist,
runCLI,
runCommand,
uniq,
updateFile
} from './utils';
forEachCli(() => {
describe('Cache', () => {
it('should cache command execution', async () => {
newProject();
const myapp1 = uniq('myapp1');
const myapp2 = uniq('myapp2');
runCLI(`generate @nrwl/web:app ${myapp1}`);
runCLI(`generate @nrwl/web:app ${myapp2}`);
const files = `--files="apps/${myapp1}/src/main.ts,apps/${myapp2}/src/main.ts"`;
// run without caching
// --------------------------------------------
const outputWithoutCachingEnabled1 = runCommand(
`npm run affected:build -- ${files}`
);
const filesApp1 = listFiles(`dist/apps/${myapp1}`);
const filesApp2 = listFiles(`dist/apps/${myapp2}`);
expect(outputWithoutCachingEnabled1).not.toContain(
'read the output from cache'
);
const outputWithoutCachingEnabled2 = runCommand(
`npm run affected:build -- ${files}`
);
expect(outputWithoutCachingEnabled2).not.toContain(
'read the output from cache'
);
// enable caching
// --------------------------------------------
updateFile('nx.json', c => {
const nxJson = JSON.parse(c);
nxJson.tasksRunnerOptions = {
default: {
options: {
cacheableOperations: ['build', 'test', 'lint']
}
}
};
return JSON.stringify(nxJson, null, 2);
});
// run build with caching
// --------------------------------------------
const outputThatPutsDataIntoCache = runCommand(
`npm run affected:build -- ${files}`
);
// now the data is in cache
expect(outputThatPutsDataIntoCache).not.toContain(
'read the output from cache'
);
rmDist();
const outputWithBothBuildTasksCached = runCommand(
`npm run affected:build -- ${files}`
);
expect(outputWithBothBuildTasksCached).toContain(
'read the output from cache'
);
expectCached(outputWithBothBuildTasksCached, [myapp1, myapp2]);
expect(listFiles(`dist/apps/${myapp1}`)).toEqual(filesApp1);
expect(listFiles(`dist/apps/${myapp2}`)).toEqual(filesApp2);
// run with skipping cache
const outputWithBothBuildTasksCachedButSkipped = runCommand(
`npm run affected:build -- ${files} --skip-nx-cache`
);
expect(outputWithBothBuildTasksCachedButSkipped).not.toContain(
`read the output from cache`
);
// touch myapp1
// --------------------------------------------
updateFile(`apps/${myapp1}/src/main.ts`, c => {
return `${c}\n//some comment`;
});
const outputWithBuildApp2Cached = runCommand(
`npm run affected:build -- ${files}`
);
expect(outputWithBuildApp2Cached).toContain('read the output from cache');
expectCached(outputWithBuildApp2Cached, [myapp2]);
// touch package.json
// --------------------------------------------
updateFile(`package.json`, c => {
const r = JSON.parse(c);
r.description = 'different';
return JSON.stringify(r);
});
const outputWithNoBuildCached = runCommand(
`npm run affected:build -- ${files}`
);
expect(outputWithNoBuildCached).not.toContain(
'read the output from cache'
);
// build individual project with caching
const individualBuildWithCache = runCommand(
`npm run nx -- build ${myapp1}`
);
expect(individualBuildWithCache).toContain('Cached Output');
// skip caching when building individual projects
const individualBuildWithSkippedCache = runCommand(
`npm run nx -- build ${myapp1} --skip-nx-cache`
);
expect(individualBuildWithSkippedCache).not.toContain('Cached Output');
// run lint with caching
// --------------------------------------------
const outputWithNoLintCached = runCommand(
`npm run affected:lint -- ${files}`
);
expect(outputWithNoLintCached).not.toContain(
'read the output from cache'
);
const outputWithBothLintTasksCached = runCommand(
`npm run affected:lint -- ${files}`
);
expect(outputWithBothLintTasksCached).toContain(
'read the output from cache'
);
expectCached(outputWithBothLintTasksCached, [
myapp1,
myapp2,
`${myapp1}-e2e`,
`${myapp2}-e2e`
]);
}, 120000);
});
function expectCached(actual: string, expected: string[]) {
const section = actual.split('read the output from cache')[1];
const r = section
.split('\n')
.filter(l => l.trim().startsWith('-'))
.map(l => l.split('- ')[1].trim());
r.sort((a, b) => a.localeCompare(b));
expected.sort((a, b) => a.localeCompare(b));
expect(r).toEqual(expected);
}
});

272
e2e/cli.test.ts Normal file
View File

@ -0,0 +1,272 @@
import {
ensureProject,
forEachCli,
newProject,
readFile,
readJson,
runCLI,
runCommand,
tmpProjPath,
updateFile
} from './utils';
import { packagesWeCareAbout } from '@nrwl/workspace/src/command-line/report';
import { renameSync } from 'fs';
forEachCli('nx', () => {
describe('Help', () => {
it('should show help', async () => {
ensureProject();
let mainHelp = runCLI(`--help`);
expect(mainHelp).toContain('Run a target for a project');
expect(mainHelp).toContain('Run task for affected projects');
mainHelp = runCLI(`help`);
expect(mainHelp).toContain('Run a target for a project');
expect(mainHelp).toContain('Run task for affected projects');
const genHelp = runCLI(`g @nrwl/web:app --help`);
expect(genHelp).toContain(
'The file extension to be used for style files. (default: css)'
);
const affectedHelp = runCLI(`affected --help`);
expect(affectedHelp).toContain('Run task for affected projects');
const version = runCLI(`--version`);
expect(version).toContain('*'); // stub value
}, 120000);
});
});
forEachCli('angular', () => {
describe('help', () => {
it('should show help', async () => {
ensureProject();
let mainHelp = runCLI(`--help`);
expect(mainHelp).toContain('Run a target for a project');
expect(mainHelp).toContain('Run task for affected projects');
mainHelp = runCLI(`help`);
expect(mainHelp).toContain('Run a target for a project');
expect(mainHelp).toContain('Run task for affected projects');
const genHelp = runCLI(`g @nrwl/web:app --help`);
expect(genHelp).toContain(
'The file extension to be used for style files.'
);
const affectedHelp = runCLI(`affected --help`);
expect(affectedHelp).toContain('Run task for affected projects');
const version = runCLI(`--version`);
expect(version).toContain('*'); // stub value
}, 120000);
});
});
forEachCli(() => {
describe('report', () => {
it(`should report package versions`, async () => {
ensureProject();
const reportOutput = runCommand('npm run nx report');
packagesWeCareAbout.forEach(p => {
expect(reportOutput).toContain(p);
});
}, 120000);
});
describe('list', () => {
beforeEach(() => {
newProject();
});
it(`should work`, async () => {
let listOutput = runCommand('npm run nx -- list');
expect(listOutput).toContain('NX Installed plugins');
// just check for some, not all
expect(listOutput).toContain('@nrwl/angular');
expect(listOutput).toContain('@schematics/angular');
expect(listOutput).toContain('@ngrx/store');
expect(listOutput).not.toContain('NX Also available');
// temporarily make it look like this isn't installed
renameSync(
tmpProjPath('node_modules/@nrwl/angular'),
tmpProjPath('node_modules/@nrwl/angular_tmp')
);
listOutput = runCommand('npm run nx -- list');
expect(listOutput).toContain('NX Also available');
// look for specific plugin
listOutput = runCommand('npm run nx -- list @nrwl/workspace');
expect(listOutput).toContain('Capabilities in @nrwl/workspace');
// check for schematics
expect(listOutput).toContain('workspace');
expect(listOutput).toContain('ng-add');
expect(listOutput).toContain('library');
// check for builders
expect(listOutput).toContain('run-commands');
// look for uninstalled approved plugin
listOutput = runCommand('npm run nx -- list @nrwl/angular');
expect(listOutput).toContain(
'NX NOTE @nrwl/angular is not currently installed'
);
// look for an unknown plugin
listOutput = runCommand('npm run nx -- list @wibble/fish');
expect(listOutput).toContain(
'NX ERROR Could not find plugin @wibble/fish'
);
// put back the @nrwl/angular module (or all the other e2e tests after this will fail)
renameSync(
tmpProjPath('node_modules/@nrwl/angular_tmp'),
tmpProjPath('node_modules/@nrwl/angular')
);
}, 120000);
});
describe('migrate', () => {
it('should run migrations', () => {
ensureProject();
updateFile(
`./node_modules/migrate-parent-package/package.json`,
JSON.stringify({
version: '1.0.0',
'nx-migrations': './migrations.json'
})
);
updateFile(
`./node_modules/migrate-parent-package/migrations.json`,
JSON.stringify({
schematics: {
run11: {
version: '1.1.0',
description: '1.1.0',
factory: './run11'
},
run20: {
version: '2.0.0',
description: '2.0.0',
factory: './run20'
}
}
})
);
updateFile(
`./node_modules/migrate-parent-package/run11.js`,
`
exports.default = function default_1() {
return function(host) {
host.create('file-11', 'content11')
}
}
`
);
updateFile(
`./node_modules/migrate-parent-package/run20.js`,
`
exports.default = function default_1() {
return function(host) {
host.create('file-20', 'content20')
}
}
`
);
updateFile(
`./node_modules/migrate-child-package/package.json`,
JSON.stringify({
version: '1.0.0'
})
);
updateFile(
'./node_modules/@nrwl/tao/src/commands/migrate.js',
content => {
const start = content.indexOf('// testing-fetch-start');
const end = content.indexOf('// testing-fetch-end');
const before = content.substring(0, start);
const after = content.substring(end);
const newFetch = `
function createFetcher(logger) {
return function fetch(packageName) {
if (packageName === 'migrate-parent-package') {
return Promise.resolve({
version: '2.0.0',
schematics: {
'run11': {
version: '1.1.0'
},
'run20': {
version: '2.0.0'
}
},
packageJsonUpdates: {
'run-11': {version: '1.1.0', packages: {'migrate-child-package': {version: '9.0.0', alwaysAddToPackageJson: true}}},
}
});
} else {
return Promise.resolve({version: '9.0.0'});
}
}
}
`;
return `${before}${newFetch}${after}`;
}
);
runCLI(
'migrate migrate-parent-package@2.0.0 --from="migrate-parent-package@1.0.0"'
);
// updates package.json
const packageJson = readJson(`package.json`);
expect(packageJson.dependencies['migrate-child-package']).toEqual(
'9.0.0'
);
// creates migrations.json
const migrationsJson = readJson(`migrations.json`);
expect(migrationsJson).toEqual({
migrations: [
{
package: 'migrate-parent-package',
version: '1.1.0',
name: 'run11'
},
{
package: 'migrate-parent-package',
version: '2.0.0',
name: 'run20'
}
]
});
// runs migrations
runCLI('migrate --run-migrations=migrations.json');
expect(readFile('file-11')).toEqual('content11');
expect(readFile('file-20')).toEqual('content20');
});
});
});

View File

@ -1,328 +0,0 @@
import {
checkFilesExist,
newProject,
readFile,
readJson,
runCLI,
runCommand,
updateFile,
exists,
ensureProject,
uniq,
forEachCli,
workspaceConfigName
} from './utils';
forEachCli(() => {
describe('Command line', () => {
it('lint should ensure module boundaries', () => {
ensureProject();
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 tslint = readJson('tslint.json');
tslint.rules['nx-enforce-module-boundaries'][1].depConstraints = [
{ sourceTag: 'validtag', onlyDependOnLibsWithTags: ['validtag'] },
...tslint.rules['nx-enforce-module-boundaries'][1].depConstraints
];
updateFile('tslint.json', JSON.stringify(tslint, null, 2));
updateFile(
`apps/${myapp}/src/main.ts`,
`
import '../../../libs/${mylib}';
import '@proj/${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('library imports must start with @proj/');
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 lint', () => {
afterAll(() => {
newProject();
});
it('should run nx lint', () => {
ensureProject();
const appBefore = uniq('before');
const appAfter = uniq('after');
runCLI(`generate @nrwl/angular:app ${appBefore}`);
runCommand(`mv apps/${appBefore} apps/${appAfter}`);
const stdout = runCommand('./node_modules/.bin/nx workspace-lint');
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}/browserslist`);
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`
);
});
});
it('format should check and reformat the code', () => {
ensureProject();
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;
`
);
let stdout = runCommand(
`npm run -s format:check -- --files="libs/${mylib}/index.ts" --libs-and-apps`
);
expect(stdout).toContain(`libs/${mylib}/index.ts`);
expect(stdout).toContain(`libs/${mylib}/src/${mylib}.module.ts`);
stdout = runCommand(`npm run -s format:check -- --all`);
expect(stdout).toContain(`apps/${myapp}/src/main.ts`);
expect(stdout).toContain(`apps/${myapp}/src/app/app.module.ts`);
expect(stdout).toContain(`apps/${myapp}/src/app/app.component.ts`);
runCommand(
`npm run format:write -- --files="apps/${myapp}/src/app/app.module.ts,apps/${myapp}/src/app/app.component.ts"`
);
stdout = runCommand('npm run -s format:check -- --all');
expect(stdout).toContain(`apps/${myapp}/src/main.ts`);
expect(stdout).not.toContain(`apps/${myapp}/src/app/app.module.ts`);
expect(stdout).not.toContain(`apps/${myapp}/src/app/app.component.ts`);
runCommand('npm run format:write -- --all');
expect(runCommand('npm run -s format:check -- --all')).toEqual('');
});
it('should support workspace-specific schematics', () => {
ensureProject();
const custom = uniq('custom');
runCLI(`g workspace-schematic ${custom} --no-interactive`);
checkFilesExist(
`tools/schematics/${custom}/index.ts`,
`tools/schematics/${custom}/schema.json`
);
const json = readJson(`tools/schematics/${custom}/schema.json`);
json.properties['directory'] = {
type: 'string',
description: 'lib directory'
};
json.properties['skipTsConfig'] = {
type: 'boolean',
description: 'skip changes to tsconfig'
};
updateFile(
`tools/schematics/${custom}/schema.json`,
JSON.stringify(json)
);
const indexFile = readFile(`tools/schematics/${custom}/index.ts`);
updateFile(
`tools/schematics/${custom}/index.ts`,
indexFile.replace(
'name: schema.name',
'name: schema.name, directory: schema.directory, skipTsConfig: schema.skipTsConfig'
)
);
const workspace = uniq('workspace');
const dryRunOutput = runCommand(
`npm run workspace-schematic ${custom} ${workspace} -- --no-interactive --directory=dir --skipTsConfig=true -d`
);
expect(exists(`libs/dir/${workspace}/src/index.ts`)).toEqual(false);
expect(dryRunOutput).toContain(`UPDATE ${workspaceConfigName()}`);
expect(dryRunOutput).toContain('UPDATE nx.json');
expect(dryRunOutput).not.toContain('UPDATE tsconfig.json');
const output = runCommand(
`npm run workspace-schematic ${custom} ${workspace} -- --no-interactive --directory=dir`
);
checkFilesExist(`libs/dir/${workspace}/src/index.ts`);
expect(output).toContain(`UPDATE ${workspaceConfigName()}`);
expect(output).toContain('UPDATE nx.json');
const another = uniq('another');
runCLI(`g workspace-schematic ${another} --no-interactive`);
const listSchematicsOutput = runCommand(
'npm run workspace-schematic -- --list-schematics'
);
expect(listSchematicsOutput).toContain(
'nx workspace-schematic "--list-schematics"'
);
expect(listSchematicsOutput).toContain(custom);
expect(listSchematicsOutput).toContain(another);
const promptOutput = runCommand(
`npm run workspace-schematic ${custom} mylib2 --dry-run`
);
expect(promptOutput).toContain('UPDATE nx.json');
}, 1000000);
describe('dep-graph', () => {
beforeEach(() => {
newProject();
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', () => {
runCommand(`npm run dep-graph -- --file=project-graph.json`);
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
const jsonFileContents = readJson('project-graph.json');
expect(jsonFileContents.graph.dependencies).toEqual({
'myapp3-e2e': [
{
source: 'myapp3-e2e',
target: 'myapp3',
type: 'implicit'
}
],
myapp2: [
{
source: 'myapp2',
target: 'mylib',
type: 'static'
}
],
'myapp2-e2e': [
{
source: 'myapp2-e2e',
target: 'myapp2',
type: 'implicit'
}
],
mylib: [
{
source: 'mylib',
target: 'mylib2',
type: 'static'
}
],
mylib2: [],
myapp: [
{
source: 'myapp',
target: 'mylib',
type: 'static'
},
{ source: 'myapp', target: 'mylib2', type: 'dynamic' }
],
'myapp-e2e': [
{
source: 'myapp-e2e',
target: 'myapp',
type: 'implicit'
}
],
myapp3: []
});
runCommand(
`npm run 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);
});
});
});

View File

@ -1,29 +0,0 @@
import {
ensureProject,
uniq,
runCommand,
checkFilesExist,
forEachCli
} from './utils';
forEachCli(() => {
describe('Delegate to CLI', () => {
it('should delegate to the cli all non-standard commands', async () => {
ensureProject();
const appName = uniq('app');
runCommand(`npm run nx -- g @nrwl/web:app ${appName}`);
runCommand(`npm run nx -- build ${appName} --prod --outputHashing none`);
checkFilesExist(
`dist/apps/${appName}/index.html`,
`dist/apps/${appName}/runtime.js`,
`dist/apps/${appName}/polyfills.esm.js`,
`dist/apps/${appName}/main.esm.js`,
`dist/apps/${appName}/polyfills.es5.js`,
`dist/apps/${appName}/main.es5.js`,
`dist/apps/${appName}/styles.css`
);
}, 120000);
});
});

View File

@ -1,55 +0,0 @@
import { ensureProject, forEachCli, runCLI } from './utils';
forEachCli('nx', () => {
describe('Help', () => {
it('should show help', async () => {
ensureProject();
let mainHelp = runCLI(`--help`);
expect(mainHelp).toContain('Run a target for a project');
expect(mainHelp).toContain('Run task for affected projects');
mainHelp = runCLI(`help`);
expect(mainHelp).toContain('Run a target for a project');
expect(mainHelp).toContain('Run task for affected projects');
const genHelp = runCLI(`g @nrwl/web:app --help`);
expect(genHelp).toContain(
'The file extension to be used for style files. (default: css)'
);
const affectedHelp = runCLI(`affected --help`);
expect(affectedHelp).toContain('Run task for affected projects');
const version = runCLI(`--version`);
expect(version).toContain('*'); // stub value
}, 120000);
});
});
forEachCli('angular', () => {
describe('Help', () => {
it('should show help', async () => {
ensureProject();
let mainHelp = runCLI(`--help`);
expect(mainHelp).toContain('Run a target for a project');
expect(mainHelp).toContain('Run task for affected projects');
mainHelp = runCLI(`help`);
expect(mainHelp).toContain('Run a target for a project');
expect(mainHelp).toContain('Run task for affected projects');
const genHelp = runCLI(`g @nrwl/web:app --help`);
expect(genHelp).toContain(
'The file extension to be used for style files.'
);
const affectedHelp = runCLI(`affected --help`);
expect(affectedHelp).toContain('Run task for affected projects');
const version = runCLI(`--version`);
expect(version).toContain('*'); // stub value
}, 120000);
});
});

View File

@ -1,71 +0,0 @@
import { renameSync } from 'fs';
import { forEachCli, newProject, runCommand, tmpProjPath } from './utils';
const testTimeout = 120000;
forEachCli(() => {
describe('list', () => {
beforeEach(() => {
newProject();
});
it(
`should work`,
async () => {
let listOutput = runCommand('npm run nx -- list');
expect(listOutput).toContain('NX Installed plugins');
// just check for some, not all
expect(listOutput).toContain('@nrwl/angular');
expect(listOutput).toContain('@schematics/angular');
expect(listOutput).toContain('@ngrx/store');
expect(listOutput).not.toContain('NX Also available');
// temporarily make it look like this isn't installed
renameSync(
tmpProjPath('node_modules/@nrwl/angular'),
tmpProjPath('node_modules/@nrwl/angular_tmp')
);
listOutput = runCommand('npm run nx -- list');
expect(listOutput).toContain('NX Also available');
// look for specific plugin
listOutput = runCommand('npm run nx -- list @nrwl/workspace');
expect(listOutput).toContain('Capabilities in @nrwl/workspace');
// check for schematics
expect(listOutput).toContain('workspace');
expect(listOutput).toContain('ng-add');
expect(listOutput).toContain('library');
// check for builders
expect(listOutput).toContain('run-commands');
// look for uninstalled approved plugin
listOutput = runCommand('npm run nx -- list @nrwl/angular');
expect(listOutput).toContain(
'NX NOTE @nrwl/angular is not currently installed'
);
// look for an unknown plugin
listOutput = runCommand('npm run nx -- list @wibble/fish');
expect(listOutput).toContain(
'NX ERROR Could not find plugin @wibble/fish'
);
// put back the @nrwl/angular module (or all the other e2e tests after this will fail)
renameSync(
tmpProjPath('node_modules/@nrwl/angular_tmp'),
tmpProjPath('node_modules/@nrwl/angular')
);
},
testTimeout
);
});
});

View File

@ -1,140 +0,0 @@
import {
ensureProject,
forEachCli,
readFile,
readJson,
runCLI,
updateFile
} from './utils';
forEachCli(() => {
describe('migrate', () => {
it('should run migrations', () => {
ensureProject();
updateFile(
`./node_modules/migrate-parent-package/package.json`,
JSON.stringify({
version: '1.0.0',
'nx-migrations': './migrations.json'
})
);
updateFile(
`./node_modules/migrate-parent-package/migrations.json`,
JSON.stringify({
schematics: {
run11: {
version: '1.1.0',
description: '1.1.0',
factory: './run11'
},
run20: {
version: '2.0.0',
description: '2.0.0',
factory: './run20'
}
}
})
);
updateFile(
`./node_modules/migrate-parent-package/run11.js`,
`
exports.default = function default_1() {
return function(host) {
host.create('file-11', 'content11')
}
}
`
);
updateFile(
`./node_modules/migrate-parent-package/run20.js`,
`
exports.default = function default_1() {
return function(host) {
host.create('file-20', 'content20')
}
}
`
);
updateFile(
`./node_modules/migrate-child-package/package.json`,
JSON.stringify({
version: '1.0.0'
})
);
updateFile(
'./node_modules/@nrwl/tao/src/commands/migrate.js',
content => {
const start = content.indexOf('// testing-fetch-start');
const end = content.indexOf('// testing-fetch-end');
const before = content.substring(0, start);
const after = content.substring(end);
const newFetch = `
function createFetcher(logger) {
return function fetch(packageName) {
if (packageName === 'migrate-parent-package') {
return Promise.resolve({
version: '2.0.0',
schematics: {
'run11': {
version: '1.1.0'
},
'run20': {
version: '2.0.0'
}
},
packageJsonUpdates: {
'run-11': {version: '1.1.0', packages: {'migrate-child-package': {version: '9.0.0', alwaysAddToPackageJson: true}}},
}
});
} else {
return Promise.resolve({version: '9.0.0'});
}
}
}
`;
return `${before}${newFetch}${after}`;
}
);
runCLI(
'migrate migrate-parent-package@2.0.0 --from="migrate-parent-package@1.0.0"'
);
// updates package.json
const packageJson = readJson(`package.json`);
expect(packageJson.dependencies['migrate-child-package']).toEqual(
'9.0.0'
);
// creates migrations.json
const migrationsJson = readJson(`migrations.json`);
expect(migrationsJson).toEqual({
migrations: [
{
package: 'migrate-parent-package',
version: '1.1.0',
name: 'run11'
},
{
package: 'migrate-parent-package',
version: '2.0.0',
name: 'run20'
}
]
});
// runs migrations
runCLI('migrate --run-migrations=migrations.json');
expect(readFile('file-11')).toEqual('content11');
expect(readFile('file-20')).toEqual('content20');
});
});
});

View File

@ -1,155 +0,0 @@
import { classify } from '@nrwl/workspace/src/utils/strings';
import {
checkFilesExist,
forEachCli,
newProject,
readFile,
readJson,
runCLI,
uniq,
updateFile
} from './utils';
forEachCli(cli => {
describe('Move Angular Project', () => {
const workspace: string = cli === 'angular' ? 'angular' : 'workspace';
describe('Apps', () => {
let app1: string;
let app2: string;
let newPath: string;
beforeEach(() => {
app1 = uniq('app1');
app2 = uniq('app2');
newPath = `subfolder/${app2}`;
newProject();
runCLI(`generate @nrwl/angular:app ${app1}`);
});
/**
* 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}/browserslist`);
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}/tslint.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');
newProject();
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

@ -1,142 +0,0 @@
import { NxJson } from '@nrwl/workspace';
import {
checkFilesExist,
exists,
forEachCli,
newProject,
readFile,
readJson,
runCLI,
uniq,
updateFile
} from './utils';
forEachCli(cli => {
describe('Move Project', () => {
const workspace: string = cli === 'angular' ? 'angular' : 'workspace';
/**
* Tries moving a library from ${lib}/data-access -> shared/${lib}/data-access
*/
it('should work for libraries', () => {
const lib1 = uniq('mylib');
const lib2 = uniq('mylib');
newProject();
runCLI(`generate @nrwl/workspace:lib ${lib1}/data-access`);
updateFile(
`libs/${lib1}/data-access/src/lib/${lib1}-data-access.ts`,
`export function fromLibOne() { console.log('This is completely pointless'); }`
);
updateFile(
`libs/${lib1}/data-access/src/index.ts`,
`export * from './lib/${lib1}-data-access.ts'`
);
/**
* Create a library which imports a class from the other lib
*/
runCLI(`generate @nrwl/workspace:lib ${lib2}/ui`);
updateFile(
`libs/${lib2}/ui/src/lib/${lib2}-ui.ts`,
`import { fromLibOne } from '@proj/${lib1}/data-access';
export const fromLibTwo = () => fromLibOne(); }`
);
const moveOutput = runCLI(
`generate @nrwl/workspace:move --project ${lib1}-data-access shared/${lib1}/data-access`
);
expect(moveOutput).toContain(`DELETE libs/${lib1}/data-access`);
expect(exists(`libs/${lib1}/data-access`)).toBeFalsy();
const newPath = `libs/shared/${lib1}/data-access`;
const newName = `shared-${lib1}-data-access`;
const readmePath = `${newPath}/README.md`;
expect(moveOutput).toContain(`CREATE ${readmePath}`);
checkFilesExist(readmePath);
const jestConfigPath = `${newPath}/jest.config.js`;
expect(moveOutput).toContain(`CREATE ${jestConfigPath}`);
checkFilesExist(jestConfigPath);
const jestConfig = readFile(jestConfigPath);
expect(jestConfig).toContain(`name: 'shared-${lib1}-data-access'`);
expect(jestConfig).toContain(`preset: '../../../../jest.config.js'`);
expect(jestConfig).toContain(
`coverageDirectory: '../../../../coverage/${newPath}'`
);
const tsConfigPath = `${newPath}/tsconfig.json`;
expect(moveOutput).toContain(`CREATE ${tsConfigPath}`);
checkFilesExist(tsConfigPath);
const tsConfig = readJson(tsConfigPath);
expect(tsConfig.extends).toEqual('../../../../tsconfig.json');
const tsConfigLibPath = `${newPath}/tsconfig.lib.json`;
expect(moveOutput).toContain(`CREATE ${tsConfigLibPath}`);
checkFilesExist(tsConfigLibPath);
const tsConfigLib = readJson(tsConfigLibPath);
expect(tsConfigLib.compilerOptions.outDir).toEqual(
'../../../../dist/out-tsc'
);
const tsConfigSpecPath = `${newPath}/tsconfig.spec.json`;
expect(moveOutput).toContain(`CREATE ${tsConfigSpecPath}`);
checkFilesExist(tsConfigSpecPath);
const tsConfigSpec = readJson(tsConfigSpecPath);
expect(tsConfigSpec.compilerOptions.outDir).toEqual(
'../../../../dist/out-tsc'
);
const indexPath = `${newPath}/src/index.ts`;
expect(moveOutput).toContain(`CREATE ${indexPath}`);
checkFilesExist(indexPath);
const rootClassPath = `${newPath}/src/lib/${lib1}-data-access.ts`;
expect(moveOutput).toContain(`CREATE ${rootClassPath}`);
checkFilesExist(rootClassPath);
expect(moveOutput).toContain('UPDATE nx.json');
const nxJson = JSON.parse(readFile('nx.json')) as NxJson;
expect(nxJson.projects[`${lib1}-data-access`]).toBeUndefined();
expect(nxJson.projects[newName]).toEqual({
tags: []
});
expect(moveOutput).toContain('UPDATE tsconfig.json');
const rootTsConfig = readJson('tsconfig.json');
expect(
rootTsConfig.compilerOptions.paths[`@proj/${lib1}/data-access`]
).toBeUndefined();
expect(
rootTsConfig.compilerOptions.paths[`@proj/shared/${lib1}/data-access`]
).toEqual([`libs/shared/${lib1}/data-access/src/index.ts`]);
expect(moveOutput).toContain(`UPDATE ${workspace}.json`);
const workspaceJson = readJson(`${workspace}.json`);
expect(workspaceJson.projects[`${lib1}-data-access`]).toBeUndefined();
const project = workspaceJson.projects[newName];
expect(project).toBeTruthy();
expect(project.root).toBe(newPath);
expect(project.sourceRoot).toBe(`${newPath}/src`);
expect(project.architect.lint.options.tsConfig).toEqual([
`libs/shared/${lib1}/data-access/tsconfig.lib.json`,
`libs/shared/${lib1}/data-access/tsconfig.spec.json`
]);
/**
* Check that the import in lib2 has been updated
*/
const lib2FilePath = `libs/${lib2}/ui/src/lib/${lib2}-ui.ts`;
const lib2File = readFile(lib2FilePath);
expect(lib2File).toContain(
`import { fromLibOne } from '@proj/shared/${lib1}/data-access';`
);
});
});
});

View File

@ -1,143 +0,0 @@
import {
forEachCli,
newProject,
runCLI,
uniq,
updateFile,
runCommand
} from './utils';
forEachCli(cliName => {
describe('print-affected', () => {
it('should print information about affected projects', () => {
newProject();
const myapp = uniq('myapp-a');
const myapp2 = uniq('myapp-b');
const mylib = uniq('mylib');
const mylib2 = uniq('mylib2');
const mypublishablelib = uniq('mypublishablelib');
runCLI(`generate @nrwl/react:app ${myapp}`);
runCLI(`generate @nrwl/react:app ${myapp2}`);
runCLI(`generate @nrwl/react:lib ${mylib}`);
runCLI(`generate @nrwl/react:lib ${mylib2}`);
runCLI(`generate @nrwl/react:lib ${mypublishablelib} --publishable`);
updateFile(
`apps/${myapp}/src/main.tsx`,
`
import React from 'react';
import ReactDOM from 'react-dom';
import "@proj/${mylib}";
import "@proj/${mypublishablelib}";
import App from './app/app';
ReactDOM.render(<App />, document.getElementById('root'));
`
);
updateFile(
`apps/${myapp2}/src/main.tsx`,
`
import React from 'react';
import ReactDOM from 'react-dom';
import "@proj/${mylib}";
import "@proj/${mypublishablelib}";
import App from './app/app';
ReactDOM.render(<App />, document.getElementById('root'));
`
);
const resWithoutTarget = JSON.parse(
runCommand(
`npm run nx print-affected --silent -- --files=apps/${myapp}/src/main.tsx`
)
);
expect(resWithoutTarget.tasks).toEqual([]);
compareTwoArrays(resWithoutTarget.projects, [`${myapp}-e2e`, myapp]);
const resWithTarget = JSON.parse(
runCommand(
`npm run nx print-affected --silent -- --files=apps/${myapp}/src/main.tsx --target=test`
).trim()
);
const cliCommand = cliName === 'angular' ? 'ng' : 'nx';
expect(resWithTarget.tasks).toEqual([
{
id: `${myapp}:test`,
overrides: {},
target: {
project: myapp,
target: 'test'
},
command: `npm run ${cliCommand} -- test ${myapp}`,
outputs: []
}
]);
compareTwoArrays(resWithTarget.projects, [`${myapp}-e2e`, myapp]);
const resWithDeps = JSON.parse(
runCommand(
`npm run nx print-affected --silent -- --files=apps/${myapp}/src/main.tsx --target=build --with-deps`
)
);
expect(resWithDeps.tasks).toEqual([
{
id: `${mypublishablelib}:build`,
overrides: {},
target: {
project: mypublishablelib,
target: 'build'
},
command: `npm run ${cliCommand} -- build ${mypublishablelib}`,
outputs: [`dist/libs/${mypublishablelib}`]
},
{
id: `${myapp}:build`,
overrides: {},
target: {
project: myapp,
target: 'build'
},
command: `npm run ${cliCommand} -- build ${myapp}`,
outputs: [`dist/apps/${myapp}`]
}
]);
compareTwoArrays(resWithDeps.projects, [
mylib,
mypublishablelib,
myapp,
`${myapp}-e2e`
]);
const resWithTargetWithSelect1 = runCommand(
`npm run nx print-affected --silent -- --files=apps/${myapp}/src/main.tsx --target=test --select=projects`
).trim();
compareTwoSerializedArrays(
resWithTargetWithSelect1,
`${myapp}-e2e, ${myapp}`
);
const resWithTargetWithSelect2 = runCommand(
`npm run nx print-affected --silent -- --files=apps/${myapp}/src/main.tsx --target=test --select="tasks.target.project"`
).trim();
compareTwoSerializedArrays(resWithTargetWithSelect2, `${myapp}`);
}, 120000);
});
function compareTwoSerializedArrays(a: string, b: string) {
compareTwoArrays(
a.split(',').map(_ => _.trim()),
b.split(',').map(_ => _.trim())
);
}
function compareTwoArrays(a: string[], b: string[]) {
expect(a.sort((x, y) => x.localeCompare(y))).toEqual(
b.sort((x, y) => x.localeCompare(y))
);
}
});

View File

@ -1,22 +0,0 @@
import { packagesWeCareAbout } from '../packages/workspace/src/command-line/report';
import { ensureProject, forEachCli, runCommand } from './utils';
const testTimeout = 120000;
forEachCli(() => {
describe('report', () => {
it(
`should report package versions`,
async () => {
ensureProject();
const reportOutput = runCommand('npm run nx report');
packagesWeCareAbout.forEach(p => {
expect(reportOutput).toContain(p);
});
},
testTimeout
);
});
});

View File

@ -1,94 +0,0 @@
import { updateFile, uniq, runCLI, forEachCli, newProject } from './utils';
const DEBUG = false;
const l = (str: string) => {
if (DEBUG) {
console.log(str);
}
return str;
};
forEachCli(() => {
describe('Run Many', () => {
it('should build specific and all projects', () => {
newProject();
const appA = uniq('appa-rand');
const libA = uniq('liba-rand');
const libB = uniq('libb-rand');
const libC = uniq('libc-rand');
const libD = uniq('libd-rand');
l(runCLI(`generate @nrwl/angular:app ${appA}`));
l(runCLI(`generate @nrwl/angular:lib ${libA} --publishable --defaults`));
l(runCLI(`generate @nrwl/angular:lib ${libB} --publishable --defaults`));
l(runCLI(`generate @nrwl/angular:lib ${libC} --publishable --defaults`));
l(runCLI(`generate @nrwl/angular:lib ${libD} --defaults`));
l('=======> libA depends on libC');
updateFile(
`libs/${libA}/src/lib/${libA}.module.spec.ts`,
`
import '@proj/${libC}';
describe('sample test', () => {
it('should test', () => {
expect(1).toEqual(1);
});
});
`
);
l('=======> testing run many starting');
const buildParallel = l(
runCLI(`run-many --target=build --projects="${libC},${libB}"`)
);
expect(buildParallel).toContain(`Running target build for projects:`);
expect(buildParallel).not.toContain(`- ${libA}`);
expect(buildParallel).toContain(`- ${libB}`);
expect(buildParallel).toContain(`- ${libC}`);
expect(buildParallel).not.toContain(`- ${libD}`);
expect(buildParallel).toContain('Running target "build" succeeded');
l('=======> testing run many complete');
l('=======> testing run many --all starting');
const buildAllParallel = l(runCLI(`run-many --target=build --all`));
expect(buildAllParallel).toContain(`Running target build for projects:`);
expect(buildAllParallel).toContain(`- ${libA}`);
expect(buildAllParallel).toContain(`- ${libB}`);
expect(buildAllParallel).toContain(`- ${libC}`);
expect(buildAllParallel).not.toContain(`- ${libD}`);
expect(buildAllParallel).toContain('Running target "build" succeeded');
l('=======> testing run many --all complete');
l('=======> testing run many --with-deps');
const buildWithDeps = l(
runCLI(`run-many --target=build --projects="${libA}" --with-deps`)
);
expect(buildWithDeps).toContain(`Running target build for projects:`);
expect(buildWithDeps).toContain(`- ${libA}`);
expect(buildWithDeps).toContain(`- ${libC}`);
expect(buildWithDeps).not.toContain(`- ${libB}`);
expect(buildWithDeps).not.toContain(`- ${libD}`);
expect(buildWithDeps).toContain('Running target "build" succeeded');
l('=======> testing run many --with-deps complete');
l('=======> testing run many --configuration');
const buildConfig = l(
runCLI(`run-many --target=build --projects="${appA},${libA}" --prod`)
);
expect(buildConfig).toContain(`Running target build for projects:`);
expect(buildConfig).toContain(`run ${appA}:build:production`);
expect(buildConfig).toContain(`run ${libA}:build:production`);
expect(buildConfig).toContain('Running target "build" succeeded');
l('=======> testing run many --configuration');
}, 1000000);
});
});

View File

@ -399,7 +399,7 @@ export function runCLI(
}
): string {
try {
return execSync(`node ./node_modules/@nrwl/cli/bin/nx.js ${command}`, {
const r = execSync(`node ./node_modules/@nrwl/cli/bin/nx.js ${command}`, {
cwd: tmpProjPath()
})
.toString()
@ -407,6 +407,8 @@ export function runCLI(
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
''
);
console.log(r);
return r;
} catch (e) {
if (opts.silenceError) {
return e.stdout.toString();
@ -424,10 +426,12 @@ export function expectTestsPass(v: { stdout: string; stderr: string }) {
export function runCommand(command: string): string {
try {
return execSync(command, {
const r = execSync(command, {
cwd: tmpProjPath(),
stdio: ['pipe', 'pipe', 'pipe']
}).toString();
console.log(r);
return r;
} catch (e) {
return e.stdout.toString() + e.stderr.toString();
}

View File

@ -0,0 +1,600 @@
import {
checkFilesExist,
newProject,
readFile,
readJson,
runCLI,
runCommand,
updateFile,
exists,
ensureProject,
uniq,
forEachCli,
workspaceConfigName
} from './utils';
import { classify } from '@nrwl/workspace/src/utils/strings';
import { NxJson } from '@nrwl/workspace';
forEachCli(cli => {
describe('lint', () => {
it('lint should ensure module boundaries', () => {
ensureProject();
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 tslint = readJson('tslint.json');
tslint.rules['nx-enforce-module-boundaries'][1].depConstraints = [
{ sourceTag: 'validtag', onlyDependOnLibsWithTags: ['validtag'] },
...tslint.rules['nx-enforce-module-boundaries'][1].depConstraints
];
updateFile('tslint.json', JSON.stringify(tslint, null, 2));
updateFile(
`apps/${myapp}/src/main.ts`,
`
import '../../../libs/${mylib}';
import '@proj/${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('library imports must start with @proj/');
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 lint', () => {
afterAll(() => {
newProject();
});
it('should run nx lint', () => {
ensureProject();
const appBefore = uniq('before');
const appAfter = uniq('after');
runCLI(`generate @nrwl/angular:app ${appBefore}`);
runCommand(`mv apps/${appBefore} apps/${appAfter}`);
const stdout = runCommand('./node_modules/.bin/nx workspace-lint');
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}/browserslist`);
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`
);
});
});
it('format should check and reformat the code', () => {
ensureProject();
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;
`
);
let stdout = runCommand(
`npm run -s format:check -- --files="libs/${mylib}/index.ts" --libs-and-apps`
);
expect(stdout).toContain(`libs/${mylib}/index.ts`);
expect(stdout).toContain(`libs/${mylib}/src/${mylib}.module.ts`);
stdout = runCommand(`npm run -s format:check -- --all`);
expect(stdout).toContain(`apps/${myapp}/src/main.ts`);
expect(stdout).toContain(`apps/${myapp}/src/app/app.module.ts`);
expect(stdout).toContain(`apps/${myapp}/src/app/app.component.ts`);
runCommand(
`npm run format:write -- --files="apps/${myapp}/src/app/app.module.ts,apps/${myapp}/src/app/app.component.ts"`
);
stdout = runCommand('npm run -s format:check -- --all');
expect(stdout).toContain(`apps/${myapp}/src/main.ts`);
expect(stdout).not.toContain(`apps/${myapp}/src/app/app.module.ts`);
expect(stdout).not.toContain(`apps/${myapp}/src/app/app.component.ts`);
runCommand('npm run format:write -- --all');
expect(runCommand('npm run -s format:check -- --all')).toEqual('');
});
it('should support workspace-specific schematics', () => {
ensureProject();
const custom = uniq('custom');
runCLI(`g workspace-schematic ${custom} --no-interactive`);
checkFilesExist(
`tools/schematics/${custom}/index.ts`,
`tools/schematics/${custom}/schema.json`
);
const json = readJson(`tools/schematics/${custom}/schema.json`);
json.properties['directory'] = {
type: 'string',
description: 'lib directory'
};
json.properties['skipTsConfig'] = {
type: 'boolean',
description: 'skip changes to tsconfig'
};
updateFile(
`tools/schematics/${custom}/schema.json`,
JSON.stringify(json)
);
const indexFile = readFile(`tools/schematics/${custom}/index.ts`);
updateFile(
`tools/schematics/${custom}/index.ts`,
indexFile.replace(
'name: schema.name',
'name: schema.name, directory: schema.directory, skipTsConfig: schema.skipTsConfig'
)
);
const workspace = uniq('workspace');
const dryRunOutput = runCommand(
`npm run workspace-schematic ${custom} ${workspace} -- --no-interactive --directory=dir --skipTsConfig=true -d`
);
expect(exists(`libs/dir/${workspace}/src/index.ts`)).toEqual(false);
expect(dryRunOutput).toContain(`UPDATE ${workspaceConfigName()}`);
expect(dryRunOutput).toContain('UPDATE nx.json');
expect(dryRunOutput).not.toContain('UPDATE tsconfig.json');
const output = runCommand(
`npm run workspace-schematic ${custom} ${workspace} -- --no-interactive --directory=dir`
);
checkFilesExist(`libs/dir/${workspace}/src/index.ts`);
expect(output).toContain(`UPDATE ${workspaceConfigName()}`);
expect(output).toContain('UPDATE nx.json');
const another = uniq('another');
runCLI(`g workspace-schematic ${another} --no-interactive`);
const listSchematicsOutput = runCommand(
'npm run workspace-schematic -- --list-schematics'
);
expect(listSchematicsOutput).toContain(
'nx workspace-schematic "--list-schematics"'
);
expect(listSchematicsOutput).toContain(custom);
expect(listSchematicsOutput).toContain(another);
const promptOutput = runCommand(
`npm run workspace-schematic ${custom} mylib2 --dry-run`
);
expect(promptOutput).toContain('UPDATE nx.json');
}, 1000000);
});
describe('dep-graph', () => {
beforeEach(() => {
newProject();
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', () => {
runCommand(`npm run dep-graph -- --file=project-graph.json`);
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
const jsonFileContents = readJson('project-graph.json');
expect(jsonFileContents.graph.dependencies).toEqual({
'myapp3-e2e': [
{
source: 'myapp3-e2e',
target: 'myapp3',
type: 'implicit'
}
],
myapp2: [
{
source: 'myapp2',
target: 'mylib',
type: 'static'
}
],
'myapp2-e2e': [
{
source: 'myapp2-e2e',
target: 'myapp2',
type: 'implicit'
}
],
mylib: [
{
source: 'mylib',
target: 'mylib2',
type: 'static'
}
],
mylib2: [],
myapp: [
{
source: 'myapp',
target: 'mylib',
type: 'static'
},
{ source: 'myapp', target: 'mylib2', type: 'dynamic' }
],
'myapp-e2e': [
{
source: 'myapp-e2e',
target: 'myapp',
type: 'implicit'
}
],
myapp3: []
});
runCommand(
`npm run 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);
});
describe('Move Angular Project', () => {
const workspace: string = cli === 'angular' ? 'angular' : 'workspace';
describe('Apps', () => {
let app1: string;
let app2: string;
let newPath: string;
beforeEach(() => {
app1 = uniq('app1');
app2 = uniq('app2');
newPath = `subfolder/${app2}`;
newProject();
runCLI(`generate @nrwl/angular:app ${app1}`);
});
/**
* 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}/browserslist`);
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}/tslint.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');
newProject();
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', () => {
const workspace: string = cli === 'angular' ? 'angular' : 'workspace';
/**
* Tries moving a library from ${lib}/data-access -> shared/${lib}/data-access
*/
it('should work for libraries', () => {
const lib1 = uniq('mylib');
const lib2 = uniq('mylib');
newProject();
runCLI(`generate @nrwl/workspace:lib ${lib1}/data-access`);
updateFile(
`libs/${lib1}/data-access/src/lib/${lib1}-data-access.ts`,
`export function fromLibOne() { console.log('This is completely pointless'); }`
);
updateFile(
`libs/${lib1}/data-access/src/index.ts`,
`export * from './lib/${lib1}-data-access.ts'`
);
/**
* Create a library which imports a class from the other lib
*/
runCLI(`generate @nrwl/workspace:lib ${lib2}/ui`);
updateFile(
`libs/${lib2}/ui/src/lib/${lib2}-ui.ts`,
`import { fromLibOne } from '@proj/${lib1}/data-access';
export const fromLibTwo = () => fromLibOne(); }`
);
const moveOutput = runCLI(
`generate @nrwl/workspace:move --project ${lib1}-data-access shared/${lib1}/data-access`
);
expect(moveOutput).toContain(`DELETE libs/${lib1}/data-access`);
expect(exists(`libs/${lib1}/data-access`)).toBeFalsy();
const newPath = `libs/shared/${lib1}/data-access`;
const newName = `shared-${lib1}-data-access`;
const readmePath = `${newPath}/README.md`;
expect(moveOutput).toContain(`CREATE ${readmePath}`);
checkFilesExist(readmePath);
const jestConfigPath = `${newPath}/jest.config.js`;
expect(moveOutput).toContain(`CREATE ${jestConfigPath}`);
checkFilesExist(jestConfigPath);
const jestConfig = readFile(jestConfigPath);
expect(jestConfig).toContain(`name: 'shared-${lib1}-data-access'`);
expect(jestConfig).toContain(`preset: '../../../../jest.config.js'`);
expect(jestConfig).toContain(
`coverageDirectory: '../../../../coverage/${newPath}'`
);
const tsConfigPath = `${newPath}/tsconfig.json`;
expect(moveOutput).toContain(`CREATE ${tsConfigPath}`);
checkFilesExist(tsConfigPath);
const tsConfig = readJson(tsConfigPath);
expect(tsConfig.extends).toEqual('../../../../tsconfig.json');
const tsConfigLibPath = `${newPath}/tsconfig.lib.json`;
expect(moveOutput).toContain(`CREATE ${tsConfigLibPath}`);
checkFilesExist(tsConfigLibPath);
const tsConfigLib = readJson(tsConfigLibPath);
expect(tsConfigLib.compilerOptions.outDir).toEqual(
'../../../../dist/out-tsc'
);
const tsConfigSpecPath = `${newPath}/tsconfig.spec.json`;
expect(moveOutput).toContain(`CREATE ${tsConfigSpecPath}`);
checkFilesExist(tsConfigSpecPath);
const tsConfigSpec = readJson(tsConfigSpecPath);
expect(tsConfigSpec.compilerOptions.outDir).toEqual(
'../../../../dist/out-tsc'
);
const indexPath = `${newPath}/src/index.ts`;
expect(moveOutput).toContain(`CREATE ${indexPath}`);
checkFilesExist(indexPath);
const rootClassPath = `${newPath}/src/lib/${lib1}-data-access.ts`;
expect(moveOutput).toContain(`CREATE ${rootClassPath}`);
checkFilesExist(rootClassPath);
expect(moveOutput).toContain('UPDATE nx.json');
const nxJson = JSON.parse(readFile('nx.json')) as NxJson;
expect(nxJson.projects[`${lib1}-data-access`]).toBeUndefined();
expect(nxJson.projects[newName]).toEqual({
tags: []
});
expect(moveOutput).toContain('UPDATE tsconfig.json');
const rootTsConfig = readJson('tsconfig.json');
expect(
rootTsConfig.compilerOptions.paths[`@proj/${lib1}/data-access`]
).toBeUndefined();
expect(
rootTsConfig.compilerOptions.paths[`@proj/shared/${lib1}/data-access`]
).toEqual([`libs/shared/${lib1}/data-access/src/index.ts`]);
expect(moveOutput).toContain(`UPDATE ${workspace}.json`);
const workspaceJson = readJson(`${workspace}.json`);
expect(workspaceJson.projects[`${lib1}-data-access`]).toBeUndefined();
const project = workspaceJson.projects[newName];
expect(project).toBeTruthy();
expect(project.root).toBe(newPath);
expect(project.sourceRoot).toBe(`${newPath}/src`);
expect(project.architect.lint.options.tsConfig).toEqual([
`libs/shared/${lib1}/data-access/tsconfig.lib.json`,
`libs/shared/${lib1}/data-access/tsconfig.spec.json`
]);
/**
* Check that the import in lib2 has been updated
*/
const lib2FilePath = `libs/${lib2}/ui/src/lib/${lib2}-ui.ts`;
const lib2File = readFile(lib2FilePath);
expect(lib2File).toContain(
`import { fromLibOne } from '@proj/shared/${lib1}/data-access';`
);
});
});
});

661
e2e/workspace.test.ts Normal file
View File

@ -0,0 +1,661 @@
import {
cli,
ensureProject,
forEachCli,
listFiles,
newProject,
readFile,
readJson,
rmDist,
runCLI,
runCommand,
setMaxWorkers,
uniq,
updateFile,
workspaceConfigName
} from './utils';
import { NxJson } from '@nrwl/workspace';
let originalCIValue: any;
forEachCli(cliName => {
const cliCommand = cliName === 'angular' ? 'ng' : 'nx';
/**
* Setting CI=true makes it simpler to configure assertions around output, as there
* won't be any colors.
*/
beforeAll(() => {
originalCIValue = process.env.CI;
process.env.CI = 'true';
});
afterAll(() => {
process.env.CI = originalCIValue;
});
describe('run-one', () => {
it('should build specific project', () => {
ensureProject();
const myapp = uniq('myapp');
const mylib1 = uniq('mylib1');
const mylib2 = uniq('mylib1');
runCLI(`generate @nrwl/react:app ${myapp}`);
setMaxWorkers(myapp);
runCLI(`generate @nrwl/react:lib ${mylib1} --publishable`);
runCLI(`generate @nrwl/react:lib ${mylib2} --publishable`);
updateFile(
`apps/${myapp}/src/main.ts`,
`
import "@proj/${mylib1}";
import "@proj/${mylib2}";
`
);
const buildWithDeps = runCLI(`build ${myapp} --with-deps --prod`);
expect(buildWithDeps).toContain(`Running target "build" succeeded`);
expect(buildWithDeps).toContain(
`${cliCommand} run ${myapp}:build:production`
);
expect(buildWithDeps).toContain(`${cliCommand} run ${mylib1}:build`);
expect(buildWithDeps).toContain(`${cliCommand} run ${mylib2}:build`);
const testsWithDeps = runCLI(`test ${myapp} --with-deps`);
expect(testsWithDeps).toContain(`NX Running target test for projects:`);
expect(testsWithDeps).toContain(myapp);
expect(testsWithDeps).toContain(mylib1);
expect(testsWithDeps).toContain(mylib2);
const testsWithoutDeps = runCLI(`test ${myapp}`);
expect(testsWithoutDeps).not.toContain(mylib1);
}, 1000000);
});
describe('run-many', () => {
it('should build specific and all projects', () => {
newProject();
const appA = uniq('appa-rand');
const libA = uniq('liba-rand');
const libB = uniq('libb-rand');
const libC = uniq('libc-rand');
const libD = uniq('libd-rand');
runCLI(`generate @nrwl/angular:app ${appA}`);
runCLI(`generate @nrwl/angular:lib ${libA} --publishable --defaults`);
runCLI(`generate @nrwl/angular:lib ${libB} --publishable --defaults`);
runCLI(`generate @nrwl/angular:lib ${libC} --publishable --defaults`);
runCLI(`generate @nrwl/angular:lib ${libD} --defaults`);
// libA depends on libC
updateFile(
`libs/${libA}/src/lib/${libA}.module.spec.ts`,
`
import '@proj/${libC}';
describe('sample test', () => {
it('should test', () => {
expect(1).toEqual(1);
});
});
`
);
// testing run many starting'
const buildParallel = runCLI(
`run-many --target=build --projects="${libC},${libB}"`
);
expect(buildParallel).toContain(`Running target build for projects:`);
expect(buildParallel).not.toContain(`- ${libA}`);
expect(buildParallel).toContain(`- ${libB}`);
expect(buildParallel).toContain(`- ${libC}`);
expect(buildParallel).not.toContain(`- ${libD}`);
expect(buildParallel).toContain('Running target "build" succeeded');
// testing run many --all starting
const buildAllParallel = runCLI(`run-many --target=build --all`);
expect(buildAllParallel).toContain(`Running target build for projects:`);
expect(buildAllParallel).toContain(`- ${libA}`);
expect(buildAllParallel).toContain(`- ${libB}`);
expect(buildAllParallel).toContain(`- ${libC}`);
expect(buildAllParallel).not.toContain(`- ${libD}`);
expect(buildAllParallel).toContain('Running target "build" succeeded');
// testing run many --with-deps
const buildWithDeps = runCLI(
`run-many --target=build --projects="${libA}" --with-deps`
);
expect(buildWithDeps).toContain(`Running target build for projects:`);
expect(buildWithDeps).toContain(`- ${libA}`);
expect(buildWithDeps).toContain(`- ${libC}`);
expect(buildWithDeps).not.toContain(`- ${libB}`);
expect(buildWithDeps).not.toContain(`- ${libD}`);
expect(buildWithDeps).toContain('Running target "build" succeeded');
// testing run many --configuration
const buildConfig = runCLI(
`run-many --target=build --projects="${appA},${libA}" --prod`
);
expect(buildConfig).toContain(`Running target build for projects:`);
expect(buildConfig).toContain(`run ${appA}:build:production`);
expect(buildConfig).toContain(`run ${libA}:build:production`);
expect(buildConfig).toContain('Running target "build" succeeded');
}, 1000000);
});
describe('affected:*', () => {
it('should print, build, and test affected apps', () => {
ensureProject();
const myapp = uniq('myapp');
const myapp2 = uniq('myapp2');
const mylib = uniq('mylib');
const mylib2 = uniq('mylib2');
const mypublishablelib = uniq('mypublishablelib');
runCLI(`generate @nrwl/angular:app ${myapp}`);
runCLI(`generate @nrwl/angular:app ${myapp2}`);
runCLI(`generate @nrwl/angular:lib ${mylib}`);
runCLI(`generate @nrwl/angular:lib ${mylib2}`);
runCLI(`generate @nrwl/angular:lib ${mypublishablelib} --publishable`);
updateFile(
`apps/${myapp}/src/app/app.component.spec.ts`,
`
import '@proj/${mylib}';
describe('sample test', () => {
it('should test', () => {
expect(1).toEqual(1);
});
});
`
);
updateFile(
`libs/${mypublishablelib}/src/lib/${mypublishablelib}.module.spec.ts`,
`
import '@proj/${mylib}';
describe('sample test', () => {
it('should test', () => {
expect(1).toEqual(1);
});
});
`
);
expect(
runCommand(
`npm run affected:apps -- --files="libs/${mylib}/src/index.ts" --plain`
).split('\n')[4]
).toEqual(myapp);
const affectedApps = runCommand(
`npm run affected:apps -- --files="libs/${mylib}/src/index.ts"`
);
expect(affectedApps).toContain(myapp);
expect(affectedApps).not.toContain(myapp2);
expect(affectedApps).not.toContain(`${myapp}-e2e`);
const implicitlyAffectedApps = runCommand(
'npm run affected:apps -- --files="tsconfig.json"'
);
expect(implicitlyAffectedApps).toContain(myapp);
expect(implicitlyAffectedApps).toContain(myapp2);
const noAffectedApps = runCommand(
'npm run affected:apps -- --files="README.md"'
);
expect(noAffectedApps).not.toContain(myapp);
expect(noAffectedApps).not.toContain(myapp2);
expect(
runCommand(
`npm run affected:libs -- --files="libs/${mylib}/src/index.ts" --plain`
).split('\n')[4]
).toEqual(`${mylib} ${mypublishablelib}`);
const affectedLibs = runCommand(
`npm run affected:libs -- --files="libs/${mylib}/src/index.ts"`
);
expect(affectedLibs).toContain(mypublishablelib);
expect(affectedLibs).toContain(mylib);
expect(affectedLibs).not.toContain(mylib2);
const implicitlyAffectedLibs = runCommand(
'npm run affected:libs -- --files="tsconfig.json"'
);
expect(implicitlyAffectedLibs).toContain(mypublishablelib);
expect(implicitlyAffectedLibs).toContain(mylib);
expect(implicitlyAffectedLibs).toContain(mylib2);
const noAffectedLibs = runCommand(
'npm run affected:libs -- --files="README.md"'
);
expect(noAffectedLibs).not.toContain(mypublishablelib);
expect(noAffectedLibs).not.toContain(mylib);
expect(noAffectedLibs).not.toContain(mylib2);
// build
const build = runCommand(
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --parallel`
);
expect(build).toContain(`Running target build for projects:`);
expect(build).toContain(`- ${myapp}`);
expect(build).toContain(`- ${mypublishablelib}`);
expect(build).not.toContain('is not registered with the build command');
expect(build).toContain('Running target "build" succeeded');
const buildExcluded = runCommand(
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --exclude ${myapp}`
);
expect(buildExcluded).toContain(`Running target build for projects:`);
expect(buildExcluded).toContain(`- ${mypublishablelib}`);
// test
updateFile(
`apps/${myapp}/src/app/app.component.spec.ts`,
readFile(`apps/${myapp}/src/app/app.component.spec.ts`).replace(
'.toEqual(1)',
'.toEqual(2)'
)
);
const failedTests = runCommand(
`npm run affected:test -- --files="libs/${mylib}/src/index.ts"`
);
expect(failedTests).toContain(`Running target test for projects:`);
expect(failedTests).toContain(`- ${mylib}`);
expect(failedTests).toContain(`- ${myapp}`);
expect(failedTests).toContain(`- ${mypublishablelib}`);
expect(failedTests).toContain(`Failed projects:`);
expect(failedTests).toContain(
'You can isolate the above projects by passing: --only-failed'
);
expect(readJson('dist/.nx-results')).toEqual({
command: 'test',
results: {
[myapp]: false,
[mylib]: true,
[mypublishablelib]: true
}
});
// Fix failing Unit Test
updateFile(
`apps/${myapp}/src/app/app.component.spec.ts`,
readFile(`apps/${myapp}/src/app/app.component.spec.ts`).replace(
'.toEqual(2)',
'.toEqual(1)'
)
);
const isolatedTests = runCommand(
`npm run affected:test -- --files="libs/${mylib}/src/index.ts" --only-failed`
);
expect(isolatedTests).toContain(`Running target test for projects`);
expect(isolatedTests).toContain(`- ${myapp}`);
const interpolatedTests = runCommand(
`npm run affected -- --target test --files="libs/${mylib}/src/index.ts" -- --jest-config {project.root}/jest.config.js`
);
expect(interpolatedTests).toContain(`Running target \"test\" succeeded`);
}, 1000000);
});
describe('affected (with git)', () => {
let myapp = uniq('myapp');
let myapp2 = uniq('myapp');
let mylib = uniq('mylib');
it('should not affect other projects by generating a new project', () => {
ensureProject();
const nxJson: NxJson = readJson('nx.json');
delete nxJson.implicitDependencies;
updateFile('nx.json', JSON.stringify(nxJson));
runCommand(`git init`);
runCommand(`git config user.email "test@test.com"`);
runCommand(`git config user.name "Test"`);
runCommand(
`git add . && git commit -am "initial commit" && git checkout -b master`
);
runCLI(`generate @nrwl/angular:app ${myapp}`);
expect(runCommand('yarn affected:apps')).toContain(myapp);
runCommand(`git add . && git commit -am "add ${myapp}"`);
runCLI(`generate @nrwl/angular:app ${myapp2}`);
expect(runCommand('yarn affected:apps')).not.toContain(myapp);
expect(runCommand('yarn affected:apps')).toContain(myapp2);
runCommand(`git add . && git commit -am "add ${myapp2}"`);
runCLI(`generate @nrwl/angular:lib ${mylib}`);
expect(runCommand('yarn affected:apps')).not.toContain(myapp);
expect(runCommand('yarn affected:apps')).not.toContain(myapp2);
expect(runCommand('yarn affected:libs')).toContain(mylib);
runCommand(`git add . && git commit -am "add ${mylib}"`);
}, 1000000);
it('should detect changes to projects based on the nx.json', () => {
const nxJson: NxJson = readJson('nx.json');
nxJson.projects[myapp].tags = ['tag'];
updateFile('nx.json', JSON.stringify(nxJson));
expect(runCommand('yarn affected:apps')).toContain(myapp);
expect(runCommand('yarn affected:apps')).not.toContain(myapp2);
expect(runCommand('yarn affected:libs')).not.toContain(mylib);
runCommand(`git add . && git commit -am "add tag to ${myapp}"`);
});
it('should detect changes to projects based on the workspace.json', () => {
const workspaceJson = readJson(workspaceConfigName());
workspaceJson.projects[myapp].prefix = 'my-app';
updateFile(workspaceConfigName(), JSON.stringify(workspaceJson));
expect(runCommand('yarn affected:apps')).toContain(myapp);
expect(runCommand('yarn affected:apps')).not.toContain(myapp2);
expect(runCommand('yarn affected:libs')).not.toContain(mylib);
runCommand(`git add . && git commit -am "change prefix for ${myapp}"`);
});
it('should affect all projects by removing projects', () => {
const workspaceJson = readJson(workspaceConfigName());
delete workspaceJson.projects[mylib];
updateFile(workspaceConfigName(), JSON.stringify(workspaceJson));
const nxJson = readJson('nx.json');
delete nxJson.projects[mylib];
updateFile('nx.json', JSON.stringify(nxJson));
expect(runCommand('yarn affected:apps')).toContain(myapp);
expect(runCommand('yarn affected:apps')).toContain(myapp2);
expect(runCommand('yarn affected:libs')).not.toContain(mylib);
runCommand(`git add . && git commit -am "remove ${mylib}"`);
});
});
describe('print-affected', () => {
it('should print information about affected projects', () => {
newProject();
const myapp = uniq('myapp-a');
const myapp2 = uniq('myapp-b');
const mylib = uniq('mylib');
const mylib2 = uniq('mylib2');
const mypublishablelib = uniq('mypublishablelib');
runCLI(`generate @nrwl/react:app ${myapp}`);
runCLI(`generate @nrwl/react:app ${myapp2}`);
runCLI(`generate @nrwl/react:lib ${mylib}`);
runCLI(`generate @nrwl/react:lib ${mylib2}`);
runCLI(`generate @nrwl/react:lib ${mypublishablelib} --publishable`);
updateFile(
`apps/${myapp}/src/main.tsx`,
`
import React from 'react';
import ReactDOM from 'react-dom';
import "@proj/${mylib}";
import "@proj/${mypublishablelib}";
import App from './app/app';
ReactDOM.render(<App />, document.getElementById('root'));
`
);
updateFile(
`apps/${myapp2}/src/main.tsx`,
`
import React from 'react';
import ReactDOM from 'react-dom';
import "@proj/${mylib}";
import "@proj/${mypublishablelib}";
import App from './app/app';
ReactDOM.render(<App />, document.getElementById('root'));
`
);
const resWithoutTarget = JSON.parse(
runCommand(
`npm run nx print-affected --silent -- --files=apps/${myapp}/src/main.tsx`
)
);
expect(resWithoutTarget.tasks).toEqual([]);
compareTwoArrays(resWithoutTarget.projects, [`${myapp}-e2e`, myapp]);
const resWithTarget = JSON.parse(
runCommand(
`npm run nx print-affected --silent -- --files=apps/${myapp}/src/main.tsx --target=test`
).trim()
);
expect(resWithTarget.tasks).toEqual([
{
id: `${myapp}:test`,
overrides: {},
target: {
project: myapp,
target: 'test'
},
command: `npm run ${cliCommand} -- test ${myapp}`,
outputs: []
}
]);
compareTwoArrays(resWithTarget.projects, [`${myapp}-e2e`, myapp]);
const resWithDeps = JSON.parse(
runCommand(
`npm run nx print-affected --silent -- --files=apps/${myapp}/src/main.tsx --target=build --with-deps`
)
);
expect(resWithDeps.tasks).toEqual([
{
id: `${mypublishablelib}:build`,
overrides: {},
target: {
project: mypublishablelib,
target: 'build'
},
command: `npm run ${cliCommand} -- build ${mypublishablelib}`,
outputs: [`dist/libs/${mypublishablelib}`]
},
{
id: `${myapp}:build`,
overrides: {},
target: {
project: myapp,
target: 'build'
},
command: `npm run ${cliCommand} -- build ${myapp}`,
outputs: [`dist/apps/${myapp}`]
}
]);
compareTwoArrays(resWithDeps.projects, [
mylib,
mypublishablelib,
myapp,
`${myapp}-e2e`
]);
const resWithTargetWithSelect1 = runCommand(
`npm run nx print-affected --silent -- --files=apps/${myapp}/src/main.tsx --target=test --select=projects`
).trim();
compareTwoSerializedArrays(
resWithTargetWithSelect1,
`${myapp}-e2e, ${myapp}`
);
const resWithTargetWithSelect2 = runCommand(
`npm run nx print-affected --silent -- --files=apps/${myapp}/src/main.tsx --target=test --select="tasks.target.project"`
).trim();
compareTwoSerializedArrays(resWithTargetWithSelect2, `${myapp}`);
}, 120000);
function compareTwoSerializedArrays(a: string, b: string) {
compareTwoArrays(
a.split(',').map(_ => _.trim()),
b.split(',').map(_ => _.trim())
);
}
function compareTwoArrays(a: string[], b: string[]) {
expect(a.sort((x, y) => x.localeCompare(y))).toEqual(
b.sort((x, y) => x.localeCompare(y))
);
}
});
describe('cache', () => {
afterAll(() => {
updateFile('nx.json', c => {
const nxJson = JSON.parse(c);
nxJson.tasksRunnerOptions = {
default: {
options: {
cacheableOperations: []
}
}
};
return JSON.stringify(nxJson, null, 2);
});
});
it('should cache command execution', async () => {
ensureProject();
const myapp1 = uniq('myapp1');
const myapp2 = uniq('myapp2');
runCLI(`generate @nrwl/web:app ${myapp1}`);
runCLI(`generate @nrwl/web:app ${myapp2}`);
const files = `--files="apps/${myapp1}/src/main.ts,apps/${myapp2}/src/main.ts"`;
// run without caching
// --------------------------------------------
const outputWithoutCachingEnabled1 = runCommand(
`npm run affected:build -- ${files}`
);
const filesApp1 = listFiles(`dist/apps/${myapp1}`);
const filesApp2 = listFiles(`dist/apps/${myapp2}`);
expect(outputWithoutCachingEnabled1).not.toContain(
'read the output from cache'
);
const outputWithoutCachingEnabled2 = runCommand(
`npm run affected:build -- ${files}`
);
expect(outputWithoutCachingEnabled2).not.toContain(
'read the output from cache'
);
// enable caching
// --------------------------------------------
updateFile('nx.json', c => {
const nxJson = JSON.parse(c);
nxJson.tasksRunnerOptions = {
default: {
options: {
cacheableOperations: ['build', 'test', 'lint']
}
}
};
return JSON.stringify(nxJson, null, 2);
});
// run build with caching
// --------------------------------------------
const outputThatPutsDataIntoCache = runCommand(
`npm run affected:build -- ${files}`
);
// now the data is in cache
expect(outputThatPutsDataIntoCache).not.toContain(
'read the output from cache'
);
rmDist();
const outputWithBothBuildTasksCached = runCommand(
`npm run affected:build -- ${files}`
);
expect(outputWithBothBuildTasksCached).toContain(
'read the output from cache'
);
expectCached(outputWithBothBuildTasksCached, [myapp1, myapp2]);
expect(listFiles(`dist/apps/${myapp1}`)).toEqual(filesApp1);
expect(listFiles(`dist/apps/${myapp2}`)).toEqual(filesApp2);
// run with skipping cache
const outputWithBothBuildTasksCachedButSkipped = runCommand(
`npm run affected:build -- ${files} --skip-nx-cache`
);
expect(outputWithBothBuildTasksCachedButSkipped).not.toContain(
`read the output from cache`
);
// touch myapp1
// --------------------------------------------
updateFile(`apps/${myapp1}/src/main.ts`, c => {
return `${c}\n//some comment`;
});
const outputWithBuildApp2Cached = runCommand(
`npm run affected:build -- ${files}`
);
expect(outputWithBuildApp2Cached).toContain('read the output from cache');
expectCached(outputWithBuildApp2Cached, [myapp2]);
// touch package.json
// --------------------------------------------
updateFile(`package.json`, c => {
const r = JSON.parse(c);
r.description = 'different';
return JSON.stringify(r);
});
const outputWithNoBuildCached = runCommand(
`npm run affected:build -- ${files}`
);
expect(outputWithNoBuildCached).not.toContain(
'read the output from cache'
);
// build individual project with caching
const individualBuildWithCache = runCommand(
`npm run nx -- build ${myapp1}`
);
expect(individualBuildWithCache).toContain('Cached Output');
// skip caching when building individual projects
const individualBuildWithSkippedCache = runCommand(
`npm run nx -- build ${myapp1} --skip-nx-cache`
);
expect(individualBuildWithSkippedCache).not.toContain('Cached Output');
// run lint with caching
// --------------------------------------------
const outputWithNoLintCached = runCommand(
`npm run affected:lint -- ${files}`
);
expect(outputWithNoLintCached).not.toContain(
'read the output from cache'
);
const outputWithBothLintTasksCached = runCommand(
`npm run affected:lint -- ${files}`
);
expect(outputWithBothLintTasksCached).toContain(
'read the output from cache'
);
expectCached(outputWithBothLintTasksCached, [
myapp1,
myapp2,
`${myapp1}-e2e`,
`${myapp2}-e2e`
]);
}, 120000);
function expectCached(actual: string, expected: string[]) {
const section = actual.split('read the output from cache')[1];
const r = section
.split('\n')
.filter(l => l.trim().startsWith('-'))
.map(l => l.split('- ')[1].trim());
r.sort((a, b) => a.localeCompare(b));
expected.sort((a, b) => a.localeCompare(b));
expect(r).toEqual(expected);
}
});
});

View File

@ -7,8 +7,8 @@ mkdir -p tmp/angular
mkdir -p tmp/nx
export SELECTED_CLI=$1
jest --maxWorkers=1 ./build/e2e/new.test.js &&
jest --maxWorkers=1 ./build/e2e/affected.test.js &&
jest --maxWorkers=1 ./build/e2e/affected-git.test.js &&
jest --maxWorkers=1 ./build/e2e/command-line.test.js &&
jest --maxWorkers=1 ./build/e2e/angular.test.js &&
jest --maxWorkers=1 ./build/e2e/cli.test.js &&
jest --maxWorkers=1 ./build/e2e/workspace.test.js &&
jest --maxWorkers=1 ./build/e2e/workspace-aux-commands.test.js &&
jest --maxWorkers=1 ./build/e2e/cypress.test.js

View File

@ -7,15 +7,8 @@ mkdir -p tmp/angular
mkdir -p tmp/nx
export SELECTED_CLI=$1
jest --maxWorkers=1 ./build/e2e/help.test.js &&
jest --maxWorkers=1 ./build/e2e/jest.test.js &&
jest --maxWorkers=1 ./build/e2e/karma.test.js &&
jest --maxWorkers=1 ./build/e2e/list.test.js &&
jest --maxWorkers=1 ./build/e2e/migrate.test.js &&
jest --maxWorkers=1 ./build/e2e/move.angular.test.js &&
jest --maxWorkers=1 ./build/e2e/move.workspace.test.js &&
jest --maxWorkers=1 ./build/e2e/next.test.js &&
jest --maxWorkers=1 ./build/e2e/nx-plugin.test.js &&
jest --maxWorkers=1 ./build/e2e/print-affected.test.js &&
jest --maxWorkers=1 ./build/e2e/delegate-to-cli.test.js &&
jest --maxWorkers=1 ./build/e2e/downgrade-module.test.js

View File

@ -7,12 +7,9 @@ mkdir -p tmp/angular
mkdir -p tmp/nx
export SELECTED_CLI=$1
jest --maxWorkers=1 ./build/e2e/run-many.test.js &&
jest --maxWorkers=1 ./build/e2e/storybook.test.js &&
jest --maxWorkers=1 ./build/e2e/upgrade-module.test.js &&
jest --maxWorkers=1 ./build/e2e/web.test.js &&
jest --maxWorkers=1 ./build/e2e/cache.test.js &&
jest --maxWorkers=1 ./build/e2e/buildable-libraries.test.js &&
jest --maxWorkers=1 ./build/e2e/angular-package.test.js &&
jest --maxWorkers=1 ./build/e2e/react-package.test.js &&
jest --maxWorkers=1 ./build/e2e/ngrx.test.js

View File

@ -9,5 +9,4 @@ mkdir -p tmp/nx
export SELECTED_CLI=$1
jest --maxWorkers=1 ./build/e2e/ng-add.test.js &&
jest --maxWorkers=1 ./build/e2e/node.test.js &&
jest --maxWorkers=1 ./build/e2e/react.test.js &&
jest --maxWorkers=1 ./build/e2e/report.test.js
jest --maxWorkers=1 ./build/e2e/react.test.js