diff --git a/e2e/angular/src/angular-app.test.ts b/e2e/angular/src/angular-app.test.ts index 382950e32d9b1..43e41369196b8 100644 --- a/e2e/angular/src/angular-app.test.ts +++ b/e2e/angular/src/angular-app.test.ts @@ -1,6 +1,5 @@ import { toClassName } from '@nrwl/workspace'; import { - forEachCli, newProject, readFile, readJson, @@ -9,26 +8,25 @@ import { updateFile, } from '@nrwl/e2e/utils'; -forEachCli('angular', (cli) => { - describe('Angular Nrwl app builder', () => { - let app; - let buildableLib; +describe('Angular Nrwl app builder', () => { + let app; + let buildableLib; - beforeEach(() => { - app = uniq('app'); - buildableLib = uniq('buildlib1'); + beforeEach(() => { + app = uniq('app'); + buildableLib = uniq('buildlib1'); - newProject(); + newProject(); - runCLI(`generate @nrwl/angular:app ${app} --style=css --no-interactive`); - runCLI( - `generate @nrwl/angular:library ${buildableLib} --buildable=true --no-interactive` - ); + runCLI(`generate @nrwl/angular:app ${app} --style=css --no-interactive`); + runCLI( + `generate @nrwl/angular:library ${buildableLib} --buildable=true --no-interactive` + ); - // update the app module to include a ref to the buildable lib - updateFile( - `apps/${app}/src/app/app.module.ts`, - ` + // update the app module to include a ref to the buildable lib + updateFile( + `apps/${app}/src/app/app.module.ts`, + ` import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import {${toClassName( @@ -45,26 +43,23 @@ forEachCli('angular', (cli) => { }) export class AppModule {} ` - ); + ); - // update the angular.json - const workspaceJson = readJson(`angular.json`); - workspaceJson.projects[app].architect.build.builder = - '@nrwl/angular:webpack-browser'; - updateFile('angular.json', JSON.stringify(workspaceJson, null, 2)); - }); + // update the angular.json + const workspaceJson = readJson(`angular.json`); + workspaceJson.projects[app].architect.build.builder = + '@nrwl/angular:webpack-browser'; + updateFile('angular.json', JSON.stringify(workspaceJson, null, 2)); + }); - it('should build the dependent buildable lib as well as the app', () => { - const libOutput = runCLI(`build ${app} --with-deps`); - expect(libOutput).toContain( - `Building entry point '@proj/${buildableLib}'` - ); - expect(libOutput).toContain(`ng run ${app}:build`); + it('should build the dependent buildable lib as well as the app', () => { + const libOutput = runCLI(`build ${app} --with-deps`); + expect(libOutput).toContain(`Building entry point '@proj/${buildableLib}'`); + expect(libOutput).toContain(`nx run ${app}:build`); - // to proof it has been built from source the "main.js" should actually contain - // the path to dist - const mainBundle = readFile(`dist/apps/${app}/main.js`); - expect(mainBundle).toContain(`dist/libs/${buildableLib}`); - }); + // to proof it has been built from source the "main.js" should actually contain + // the path to dist + const mainBundle = readFile(`dist/apps/${app}/main.js`); + expect(mainBundle).toContain(`dist/libs/${buildableLib}`); }); }); diff --git a/e2e/angular/src/angular-core.test.ts b/e2e/angular/src/angular-core.test.ts index 52e2bcada3468..32453d7d8f293 100644 --- a/e2e/angular/src/angular-core.test.ts +++ b/e2e/angular/src/angular-core.test.ts @@ -1,7 +1,6 @@ import { checkFilesExist, expectTestsPass, - forEachCli, getSize, newProject, runCLI, @@ -12,25 +11,24 @@ import { } from '@nrwl/e2e/utils'; import { toClassName } from '@nrwl/workspace'; -forEachCli(() => { - describe('Angular Package', () => { - beforeEach(() => { - newProject(); - }); - - it('should work', async () => { - const myapp = uniq('myapp'); - const mylib = uniq('mylib'); - runCLI( - `generate @nrwl/angular:app ${myapp} --directory=myDir --no-interactive` - ); - runCLI( - `generate @nrwl/angular:lib ${mylib} --directory=myDir --add-module-spec --no-interactive` - ); - - updateFile( - `apps/my-dir/${myapp}/src/app/app.module.ts`, - ` +describe('Angular Package', () => { + beforeEach(() => { + newProject(); + }); + + it('should work', async () => { + const myapp = uniq('myapp'); + const mylib = uniq('mylib'); + runCLI( + `generate @nrwl/angular:app ${myapp} --directory=myDir --no-interactive` + ); + runCLI( + `generate @nrwl/angular:lib ${mylib} --directory=myDir --add-module-spec --no-interactive` + ); + + updateFile( + `apps/my-dir/${myapp}/src/app/app.module.ts`, + ` import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { MyDir${toClassName( @@ -45,87 +43,86 @@ forEachCli(() => { }) export class AppModule {} ` - ); - runCLI(`build my-dir-${myapp} --prod --output-hashing none`); - - checkFilesExist(`dist/apps/my-dir/${myapp}/main.js`); - - // This is a loose requirement because there are a lot of - // influences external from this project that affect this. - const es2015BundleSize = getSize( - tmpProjPath(`dist/apps/my-dir/${myapp}/main.js`) - ); - console.log( - `The current es2015 bundle size is ${es2015BundleSize / 1000} KB` - ); - expect(es2015BundleSize).toBeLessThanOrEqual(125000); - - // running tests for the app - expectTestsPass(await runCLIAsync(`test my-dir-${myapp} --no-watch`)); - - // running tests for the lib - expectTestsPass(await runCLIAsync(`test my-dir-${mylib} --no-watch`)); - - // if (supportUi()) { - // try { - // const r = runCLI(`e2e my-dir-${myapp}-e2e --headless --no-watch`); - // console.log(r); - // expect(r).toContain('All specs passed!'); - // } catch (e) { - // console.log(e); - // if (e.stdout) { - // console.log(e.stdout.toString()); - // } - // if (e.stderr) { - // console.log(e.stdout.toString()); - // } - // throw e; - // } - // } - }, 1000000); - - it('should support router config generation (lazy)', async () => { - const myapp = uniq('myapp'); - const mylib = uniq('mylib'); - runCLI(`generate @nrwl/angular:app ${myapp} --directory=myDir --routing`); - runCLI( - `generate @nrwl/angular:lib ${mylib} --directory=myDir --routing --lazy --parentModule=apps/my-dir/${myapp}/src/app/app.module.ts` - ); - - runCLI(`build my-dir-${myapp} --aot`); - expectTestsPass(await runCLIAsync(`test my-dir-${myapp} --no-watch`)); - }, 1000000); - - it('should support router config generation (eager)', async () => { - const myapp = uniq('myapp'); - runCLI(`generate @nrwl/angular:app ${myapp} --directory=myDir --routing`); - const mylib = uniq('mylib'); - runCLI( - `generate @nrwl/angular:lib ${mylib} --directory=myDir --routing --parentModule=apps/my-dir/${myapp}/src/app/app.module.ts` - ); - - runCLI(`build my-dir-${myapp} --aot`); - expectTestsPass(await runCLIAsync(`test my-dir-${myapp} --no-watch`)); - }, 1000000); - - it('should support Ivy', async () => { - const myapp = uniq('myapp'); - runCLI( - `generate @nrwl/angular:app ${myapp} --directory=myDir --routing --enable-ivy` - ); - - runCLI(`build my-dir-${myapp} --aot`); - expectTestsPass(await runCLIAsync(`test my-dir-${myapp} --no-watch`)); - }, 1000000); - - it('should support eslint', async () => { - const myapp = uniq('myapp'); - runCLI(`generate @nrwl/angular:app ${myapp} --linter=eslint`); - expect(runCLI(`lint ${myapp}`)).toContain('All files pass linting.'); - - const mylib = uniq('mylib'); - runCLI(`generate @nrwl/angular:lib ${mylib} --linter=eslint`); - expect(runCLI(`lint ${mylib}`)).toContain('All files pass linting.'); - }); + ); + runCLI(`build my-dir-${myapp} --prod --output-hashing none`); + + checkFilesExist(`dist/apps/my-dir/${myapp}/main.js`); + + // This is a loose requirement because there are a lot of + // influences external from this project that affect this. + const es2015BundleSize = getSize( + tmpProjPath(`dist/apps/my-dir/${myapp}/main.js`) + ); + console.log( + `The current es2015 bundle size is ${es2015BundleSize / 1000} KB` + ); + expect(es2015BundleSize).toBeLessThanOrEqual(125000); + + // running tests for the app + expectTestsPass(await runCLIAsync(`test my-dir-${myapp} --no-watch`)); + + // running tests for the lib + expectTestsPass(await runCLIAsync(`test my-dir-${mylib} --no-watch`)); + + // if (supportUi()) { + // try { + // const r = runCLI(`e2e my-dir-${myapp}-e2e --headless --no-watch`); + // console.log(r); + // expect(r).toContain('All specs passed!'); + // } catch (e) { + // console.log(e); + // if (e.stdout) { + // console.log(e.stdout.toString()); + // } + // if (e.stderr) { + // console.log(e.stdout.toString()); + // } + // throw e; + // } + // } + }, 1000000); + + it('should support router config generation (lazy)', async () => { + const myapp = uniq('myapp'); + const mylib = uniq('mylib'); + runCLI(`generate @nrwl/angular:app ${myapp} --directory=myDir --routing`); + runCLI( + `generate @nrwl/angular:lib ${mylib} --directory=myDir --routing --lazy --parentModule=apps/my-dir/${myapp}/src/app/app.module.ts` + ); + + runCLI(`build my-dir-${myapp} --aot`); + expectTestsPass(await runCLIAsync(`test my-dir-${myapp} --no-watch`)); + }, 1000000); + + it('should support router config generation (eager)', async () => { + const myapp = uniq('myapp'); + runCLI(`generate @nrwl/angular:app ${myapp} --directory=myDir --routing`); + const mylib = uniq('mylib'); + runCLI( + `generate @nrwl/angular:lib ${mylib} --directory=myDir --routing --parentModule=apps/my-dir/${myapp}/src/app/app.module.ts` + ); + + runCLI(`build my-dir-${myapp} --aot`); + expectTestsPass(await runCLIAsync(`test my-dir-${myapp} --no-watch`)); + }, 1000000); + + it('should support Ivy', async () => { + const myapp = uniq('myapp'); + runCLI( + `generate @nrwl/angular:app ${myapp} --directory=myDir --routing --enable-ivy` + ); + + runCLI(`build my-dir-${myapp} --aot`); + expectTestsPass(await runCLIAsync(`test my-dir-${myapp} --no-watch`)); + }, 1000000); + + it('should support eslint', async () => { + const myapp = uniq('myapp'); + runCLI(`generate @nrwl/angular:app ${myapp} --linter=eslint`); + expect(runCLI(`lint ${myapp}`)).toContain('All files pass linting.'); + + const mylib = uniq('mylib'); + runCLI(`generate @nrwl/angular:lib ${mylib} --linter=eslint`); + expect(runCLI(`lint ${mylib}`)).toContain('All files pass linting.'); }); }); diff --git a/e2e/angular/src/angular-library.test.ts b/e2e/angular/src/angular-library.test.ts index 990d49bde8227..8fb3e09bbe5cc 100644 --- a/e2e/angular/src/angular-library.test.ts +++ b/e2e/angular/src/angular-library.test.ts @@ -1,6 +1,5 @@ import { toClassName } from '@nrwl/workspace'; import { - forEachCli, newProject, readJson, runCLI, @@ -8,94 +7,93 @@ import { updateFile, } from '@nrwl/e2e/utils'; -forEachCli('angular', (cli) => { - ['publishable', 'buildable'].forEach((testConfig) => { - describe('Build Angular library', () => { - /** - * Graph: - * - * childLib - * / - * parentLib => - * \ - * \ - * childLib2 - * - */ - let parentLib: string; - let childLib: string; - let childLib2: string; - - beforeEach(() => { - parentLib = uniq('parentlib'); - childLib = uniq('childlib'); - childLib2 = uniq('childlib2'); - - newProject(); - - if (testConfig === 'buildable') { - runCLI( - `generate @nrwl/angular:library ${parentLib} --buildable=true --no-interactive` - ); - runCLI( - `generate @nrwl/angular:library ${childLib} --buildable=true --no-interactive` - ); - runCLI( - `generate @nrwl/angular:library ${childLib2} --buildable=true --no-interactive` - ); - } else { - runCLI( - `generate @nrwl/angular:library ${parentLib} --publishable=true --importPath=@proj/${parentLib} --no-interactive` - ); - runCLI( - `generate @nrwl/angular:library ${childLib} --publishable=true --importPath=@proj/${childLib} --no-interactive` - ); - runCLI( - `generate @nrwl/angular:library ${childLib2} --publishable=true --importPath=@proj/${childLib2} --no-interactive` - ); - - // create secondary entrypoint - updateFile( - `libs/${childLib}/sub/package.json`, - ` +['publishable', 'buildable'].forEach((testConfig) => { + describe('Build Angular library', () => { + /** + * Graph: + * + * childLib + * / + * parentLib => + * \ + * \ + * childLib2 + * + */ + let parentLib: string; + let childLib: string; + let childLib2: string; + + beforeEach(() => { + parentLib = uniq('parentlib'); + childLib = uniq('childlib'); + childLib2 = uniq('childlib2'); + + newProject(); + + if (testConfig === 'buildable') { + runCLI( + `generate @nrwl/angular:library ${parentLib} --buildable=true --no-interactive` + ); + runCLI( + `generate @nrwl/angular:library ${childLib} --buildable=true --no-interactive` + ); + runCLI( + `generate @nrwl/angular:library ${childLib2} --buildable=true --no-interactive` + ); + } else { + runCLI( + `generate @nrwl/angular:library ${parentLib} --publishable=true --importPath=@proj/${parentLib} --no-interactive` + ); + runCLI( + `generate @nrwl/angular:library ${childLib} --publishable=true --importPath=@proj/${childLib} --no-interactive` + ); + runCLI( + `generate @nrwl/angular:library ${childLib2} --publishable=true --importPath=@proj/${childLib2} --no-interactive` + ); + + // create secondary entrypoint + updateFile( + `libs/${childLib}/sub/package.json`, + ` { "ngPackage": {} } ` - ); - updateFile( - `libs/${childLib}/sub/src/lib/sub.module.ts`, - ` + ); + updateFile( + `libs/${childLib}/sub/src/lib/sub.module.ts`, + ` import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [CommonModule] }) export class SubModule {} ` - ); - - updateFile( - `libs/${childLib}/sub/src/public_api.ts`, - `export * from './lib/sub.module';` - ); - - updateFile( - `libs/${childLib}/sub/src/index.ts`, - `export * from './public_api';` - ); - - updateFile(`tsconfig.base.json`, (s) => { - return s.replace( - `"@proj/${childLib}": ["libs/${childLib}/src/index.ts"],`, - `"@proj/${childLib}": ["libs/${childLib}/src/index.ts"], + ); + + updateFile( + `libs/${childLib}/sub/src/public_api.ts`, + `export * from './lib/sub.module';` + ); + + updateFile( + `libs/${childLib}/sub/src/index.ts`, + `export * from './public_api';` + ); + + updateFile(`tsconfig.base.json`, (s) => { + return s.replace( + `"@proj/${childLib}": ["libs/${childLib}/src/index.ts"],`, + `"@proj/${childLib}": ["libs/${childLib}/src/index.ts"], "@proj/${childLib}/sub": ["libs/${childLib}/sub/src/index.ts"], ` - ); - }); - } + ); + }); + } - // create dependencies by importing - const createDep = (parent, children: string[]) => { - let moduleContent = ` + // create dependencies by importing + const createDep = (parent, children: string[]) => { + let moduleContent = ` import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; ${children @@ -108,8 +106,8 @@ forEachCli('angular', (cli) => { .join('\n')} `; - if (testConfig === 'publishable') { - moduleContent += ` + if (testConfig === 'publishable') { + moduleContent += ` import { SubModule } from '@proj/${childLib}/sub'; @NgModule({ @@ -118,59 +116,49 @@ forEachCli('angular', (cli) => { .join(',')}, SubModule] }) export class ${toClassName(parent)}Module {}`; - } + } - updateFile( - `libs/${parent}/src/lib/${parent}.module.ts`, - moduleContent - ); - }; + updateFile(`libs/${parent}/src/lib/${parent}.module.ts`, moduleContent); + }; - createDep(parentLib, [childLib, childLib2]); - }); + createDep(parentLib, [childLib, childLib2]); + }); - it('should throw an error if the dependent library has not been built before building the parent lib', () => { - expect.assertions(2); + it('should throw an error if the dependent library has not been built before building the parent lib', () => { + expect.assertions(2); + + try { + runCLI(`build ${parentLib}`); + } catch (e) { + expect(e.stderr.toString()).toContain( + `Some of the project ${parentLib}'s dependencies have not been built yet. Please build these libraries before:` + ); + expect(e.stderr.toString()).toContain(`${childLib}`); + } + }); - try { - runCLI(`build ${parentLib}`); - } catch (e) { - expect(e.stderr.toString()).toContain( - `Some of the project ${parentLib}'s dependencies have not been built yet. Please build these libraries before:` - ); - expect(e.stderr.toString()).toContain(`${childLib}`); - } - }); - - it('should build the library when it does not have any deps', () => { - const libOutput = runCLI(`build ${childLib}`); - expect(libOutput).toContain(`Built @proj/${childLib}`); - }); - - it('should properly add references to any dependency into the parent package.json', () => { - const childLibOutput = runCLI(`build ${childLib}`); - const childLib2Output = runCLI(`build ${childLib2}`); - const parentLibOutput = runCLI(`build ${parentLib}`); - - expect(childLibOutput).toContain(`Built @proj/${childLib}`); - expect(childLib2Output).toContain(`Built @proj/${childLib2}`); - expect(parentLibOutput).toContain(`Built @proj/${parentLib}`); - - const jsonFile = readJson(`dist/libs/${parentLib}/package.json`); - // expect(jsonFile.dependencies).toEqual({ tslib: '^2.0.0' }); - - expect(jsonFile.dependencies['tslib']).toEqual('^2.0.0'); - expect(jsonFile.dependencies[`@proj/${childLib}`]).toBeDefined(); - expect(jsonFile.dependencies[`@proj/${childLib2}`]).toBeDefined(); - expect(jsonFile.peerDependencies['@angular/common']).toBeDefined(); - expect(jsonFile.peerDependencies['@angular/core']).toBeDefined(); - }); + it('should build the library when it does not have any deps', () => { + const libOutput = runCLI(`build ${childLib}`); + expect(libOutput).toContain(`Built @proj/${childLib}`); }); - }); -}); -forEachCli('nx', () => { - describe('Build Angular library', () => { - it('should work', async () => {}, 1000000); + it('should properly add references to any dependency into the parent package.json', () => { + const childLibOutput = runCLI(`build ${childLib}`); + const childLib2Output = runCLI(`build ${childLib2}`); + const parentLibOutput = runCLI(`build ${parentLib}`); + + expect(childLibOutput).toContain(`Built @proj/${childLib}`); + expect(childLib2Output).toContain(`Built @proj/${childLib2}`); + expect(parentLibOutput).toContain(`Built @proj/${parentLib}`); + + const jsonFile = readJson(`dist/libs/${parentLib}/package.json`); + // expect(jsonFile.dependencies).toEqual({ tslib: '^2.0.0' }); + + expect(jsonFile.dependencies['tslib']).toEqual('^2.0.0'); + expect(jsonFile.dependencies[`@proj/${childLib}`]).toBeDefined(); + expect(jsonFile.dependencies[`@proj/${childLib2}`]).toBeDefined(); + expect(jsonFile.peerDependencies['@angular/common']).toBeDefined(); + expect(jsonFile.peerDependencies['@angular/core']).toBeDefined(); + }); }); }); diff --git a/e2e/angular/src/angularjs.test.ts b/e2e/angular/src/angularjs.test.ts deleted file mode 100644 index 92d2b70b802a7..0000000000000 --- a/e2e/angular/src/angularjs.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { - forEachCli, - newProject, - patchKarmaToWorkOnWSL, - runCLI, - runCommand, - uniq, - updateFile, -} from '@nrwl/e2e/utils'; - -forEachCli('angular', () => { - // TODO: This test is super flaky, investigate and re-enable. - describe('AngularJS Schematics', () => { - beforeEach(() => { - newProject(); - }); - - describe('DowngradeModule', () => { - it('should generate a downgradeModule setup', async () => { - const myapp = uniq('myapp'); - runCLI(`generate @nrwl/angular:app ${myapp} --unit-test-runner=karma`); - patchKarmaToWorkOnWSL(); - - updateFile( - `apps/${myapp}/src/legacy.js`, - `window.angular.module('legacy', []);` - ); - - runCLI( - `generate @nrwl/angular:downgrade-module legacy --angularJsImport=./legacy --project=${myapp}` - ); - - runCommand('yarn postinstall'); - - runCLI(`build ${myapp}`); - expect(runCLI(`test ${myapp} --no-watch`)).toContain('3 SUCCESS'); - }, 1000000); - }); - - describe('UpgradeModule', () => { - it('should generate an UpgradeModule setup', async () => { - const myapp = uniq('myapp'); - runCLI(`generate @nrwl/angular:app ${myapp} --unit-test-runner=karma`); - patchKarmaToWorkOnWSL(); - - updateFile( - `apps/${myapp}/src/legacy.js`, - ` - const angular = window.angular.module('legacy', []); - angular.component('proj-root-legacy', { - template: 'Expected Value' - }); - ` - ); - - updateFile( - `apps/${myapp}/src/app/app.component.html`, - ` - EXPECTED [] - ` - ); - - updateFile(`apps/${myapp}/src/app/app.component.spec.ts`, ``); - - runCLI( - 'generate @nrwl/angular:upgrade-module legacy --angularJsImport=./legacy ' + - `--angularJsCmpSelector=proj-root-legacy --project=${myapp}` - ); - - runCommand('yarn postinstall'); - - runCLI(`build ${myapp}`); - expect(runCLI(`test ${myapp} --no-watch`)).toContain('1 SUCCESS'); - }, 1000000); - }); - }); -}); - -forEachCli('nx', () => { - describe('DowngradeModule', () => { - it('not supported', async () => {}, 1000000); - }); -}); diff --git a/e2e/angular/src/karma.test.ts b/e2e/angular/src/karma.test.ts deleted file mode 100644 index 36177043f18e1..0000000000000 --- a/e2e/angular/src/karma.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { - forEachCli, - newProject, - patchKarmaToWorkOnWSL, - runCLI, - runCLIAsync, - uniq, -} from '@nrwl/e2e/utils'; - -forEachCli(() => { - // TODO: This test is super flaky, investigate and re-enable. - xdescribe('Karma', () => { - it('should be able to generate a testable library using karma', async (done) => { - newProject(); - - // run an app - const myapp = uniq('myapp'); - runCLI( - `generate @nrwl/angular:app ${myapp} --unit-test-runner karma --no-interactive` - ); - - const mylib = uniq('mylib'); - runCLI( - `generate @nrwl/angular:lib ${mylib} --unit-test-runner karma --add-module-spec --no-interactive` - ); - patchKarmaToWorkOnWSL(); - - await Promise.all([ - runCLIAsync(`generate @nrwl/angular:service test --project ${mylib}`), - runCLIAsync(`generate @nrwl/angular:component test --project ${mylib}`), - ]); - - const karmaResult = await runCLIAsync(`test ${mylib}`); - expect(karmaResult.stdout).toContain('3 SUCCESS'); - - await Promise.all([ - runCLIAsync(`generate @nrwl/angular:service test --project ${myapp}`), - runCLIAsync(`generate @nrwl/angular:component test --project ${myapp}`), - ]); - const karmaResult2 = await runCLIAsync(`test ${myapp}`); - expect(karmaResult2.stdout).toContain('5 SUCCESS'); - - done(); - }, 60000); - }); -}); diff --git a/e2e/angular/src/ng-add.test.ts b/e2e/angular/src/ng-add.test.ts index a8ecabf026f48..d1b8616c39395 100644 --- a/e2e/angular/src/ng-add.test.ts +++ b/e2e/angular/src/ng-add.test.ts @@ -1,6 +1,5 @@ import { checkFilesExist, - forEachCli, readJson, runCLI, runCommand, @@ -9,349 +8,333 @@ import { updateFile, } from '@nrwl/e2e/utils'; -forEachCli('angular', () => { - xdescribe('Nrwl Convert to Nx Workspace', () => { - it('should generate a workspace', () => { - runNgNew(); - - // update package.json - const packageJson = readJson('package.json'); - packageJson.description = 'some description'; - updateFile('package.json', JSON.stringify(packageJson, null, 2)); - // confirm that @nrwl and @ngrx dependencies do not exist yet - expect(packageJson.devDependencies['@nrwl/workspace']).not.toBeDefined(); - expect(packageJson.dependencies['@ngrx/store']).not.toBeDefined(); - expect(packageJson.dependencies['@ngrx/effects']).not.toBeDefined(); - expect(packageJson.dependencies['@ngrx/router-store']).not.toBeDefined(); - expect( - packageJson.devDependencies['@ngrx/store-devtools'] - ).not.toBeDefined(); - - // update tsconfig.json - const tsconfigJson = readJson('tsconfig.base.json'); - tsconfigJson.compilerOptions.paths = { a: ['b'] }; - updateFile('tsconfig.json', JSON.stringify(tsconfigJson, null, 2)); - - updateFile('src/scripts.ts', ''); - - // update angular-cli.json - const angularCLIJson = readJson('angular.json'); - angularCLIJson.projects.proj.architect.build.options.scripts = angularCLIJson.projects.proj.architect.test.options.scripts = [ - 'src/scripts.ts', - ]; - angularCLIJson.projects.proj.architect.test.options.styles = [ - 'src/styles.css', - ]; - updateFile('angular.json', JSON.stringify(angularCLIJson, null, 2)); - - // run the command - runNgAdd('--npmScope projscope'); - - // check that prettier config exits and that files have been moved! - checkFilesExist( - '.vscode/extensions.json', - '.prettierrc', - 'apps/proj/src/main.ts', - 'apps/proj/src/app/app.module.ts' - ); - - expect(readJson('.vscode/extensions.json').recommendations).toEqual([ - 'nrwl.angular-console', - 'angular.ng-template', - 'ms-vscode.vscode-typescript-tslint-plugin', - 'esbenp.prettier-vscode', - ]); - - // check that package.json got merged - const updatedPackageJson = readJson('package.json'); - expect(updatedPackageJson.description).toEqual('some description'); - expect(updatedPackageJson.scripts).toEqual({ - ng: 'nx', - nx: 'nx', - start: 'ng serve', - build: 'ng build', - test: 'ng test', - lint: 'nx workspace-lint && ng lint', - e2e: 'ng e2e', - 'affected:apps': 'nx affected:apps', - 'affected:libs': 'nx affected:libs', - 'affected:build': 'nx affected:build', - 'affected:e2e': 'nx affected:e2e', - 'affected:test': 'nx affected:test', - 'affected:lint': 'nx affected:lint', - 'affected:dep-graph': 'nx affected:dep-graph', - affected: 'nx affected', - format: 'nx format:write', - 'format:write': 'nx format:write', - 'format:check': 'nx format:check', - update: 'ng update @nrwl/workspace', - 'update:check': 'ng update', - postinstall: 'node ./decorate-angular-cli.js', - 'dep-graph': 'nx dep-graph', - 'workspace-generator': 'nx workspace-generator', - help: 'nx help', - }); - expect( - updatedPackageJson.devDependencies['@nrwl/workspace'] - ).toBeDefined(); - expect(updatedPackageJson.devDependencies['@angular/cli']).toBeDefined(); - - const nxJson = readJson('nx.json'); - expect(nxJson).toEqual({ - npmScope: 'projscope', - implicitDependencies: { - 'angular.json': '*', - 'package.json': '*', - 'tslint.json': '*', - '.eslintrc.json': '*', - 'tsconfig.base.json': '*', - 'nx.json': '*', +xdescribe('Nrwl Convert to Nx Workspace', () => { + it('should generate a workspace', () => { + runNgNew(); + + // update package.json + const packageJson = readJson('package.json'); + packageJson.description = 'some description'; + updateFile('package.json', JSON.stringify(packageJson, null, 2)); + // confirm that @nrwl and @ngrx dependencies do not exist yet + expect(packageJson.devDependencies['@nrwl/workspace']).not.toBeDefined(); + expect(packageJson.dependencies['@ngrx/store']).not.toBeDefined(); + expect(packageJson.dependencies['@ngrx/effects']).not.toBeDefined(); + expect(packageJson.dependencies['@ngrx/router-store']).not.toBeDefined(); + expect( + packageJson.devDependencies['@ngrx/store-devtools'] + ).not.toBeDefined(); + + // update tsconfig.json + const tsconfigJson = readJson('tsconfig.base.json'); + tsconfigJson.compilerOptions.paths = { a: ['b'] }; + updateFile('tsconfig.json', JSON.stringify(tsconfigJson, null, 2)); + + updateFile('src/scripts.ts', ''); + + // update angular-cli.json + const angularCLIJson = readJson('angular.json'); + angularCLIJson.projects.proj.architect.build.options.scripts = angularCLIJson.projects.proj.architect.test.options.scripts = [ + 'src/scripts.ts', + ]; + angularCLIJson.projects.proj.architect.test.options.styles = [ + 'src/styles.css', + ]; + updateFile('angular.json', JSON.stringify(angularCLIJson, null, 2)); + + // run the command + runNgAdd('--npmScope projscope'); + + // check that prettier config exits and that files have been moved! + checkFilesExist( + '.vscode/extensions.json', + '.prettierrc', + 'apps/proj/src/main.ts', + 'apps/proj/src/app/app.module.ts' + ); + + expect(readJson('.vscode/extensions.json').recommendations).toEqual([ + 'nrwl.angular-console', + 'angular.ng-template', + 'ms-vscode.vscode-typescript-tslint-plugin', + 'esbenp.prettier-vscode', + ]); + + // check that package.json got merged + const updatedPackageJson = readJson('package.json'); + expect(updatedPackageJson.description).toEqual('some description'); + expect(updatedPackageJson.scripts).toEqual({ + ng: 'nx', + nx: 'nx', + start: 'ng serve', + build: 'ng build', + test: 'ng test', + lint: 'nx workspace-lint && ng lint', + e2e: 'ng e2e', + 'affected:apps': 'nx affected:apps', + 'affected:libs': 'nx affected:libs', + 'affected:build': 'nx affected:build', + 'affected:e2e': 'nx affected:e2e', + 'affected:test': 'nx affected:test', + 'affected:lint': 'nx affected:lint', + 'affected:dep-graph': 'nx affected:dep-graph', + affected: 'nx affected', + format: 'nx format:write', + 'format:write': 'nx format:write', + 'format:check': 'nx format:check', + update: 'ng update @nrwl/workspace', + 'update:check': 'ng update', + postinstall: 'node ./decorate-angular-cli.js', + 'dep-graph': 'nx dep-graph', + 'workspace-generator': 'nx workspace-generator', + help: 'nx help', + }); + expect(updatedPackageJson.devDependencies['@nrwl/workspace']).toBeDefined(); + expect(updatedPackageJson.devDependencies['@angular/cli']).toBeDefined(); + + const nxJson = readJson('nx.json'); + expect(nxJson).toEqual({ + npmScope: 'projscope', + implicitDependencies: { + 'angular.json': '*', + 'package.json': '*', + 'tslint.json': '*', + '.eslintrc.json': '*', + 'tsconfig.base.json': '*', + 'nx.json': '*', + }, + projects: { + proj: { + tags: [], }, - projects: { - proj: { - tags: [], - }, - 'proj-e2e': { - tags: [], - }, + 'proj-e2e': { + tags: [], }, - }); - - // check if angular-cli.json get merged - const updatedAngularCLIJson = readJson('angular.json'); - expect(updatedAngularCLIJson.projects.proj.root).toEqual('apps/proj'); - expect(updatedAngularCLIJson.projects.proj.sourceRoot).toEqual( - 'apps/proj/src' - ); + }, + }); - expect(updatedAngularCLIJson.projects.proj.architect.build).toEqual({ - builder: '@angular-devkit/build-angular:browser', - options: { - aot: true, - outputPath: 'dist/apps/proj', - index: 'apps/proj/src/index.html', - main: 'apps/proj/src/main.ts', - polyfills: 'apps/proj/src/polyfills.ts', - tsConfig: 'apps/proj/tsconfig.app.json', - assets: ['apps/proj/src/favicon.ico', 'apps/proj/src/assets'], - styles: ['apps/proj/src/styles.css'], - scripts: ['apps/proj/src/scripts.ts'], - }, - configurations: { - production: { - fileReplacements: [ - { - replace: 'apps/proj/src/environments/environment.ts', - with: 'apps/proj/src/environments/environment.prod.ts', - }, - ], - budgets: [ - { - maximumError: '5mb', - maximumWarning: '2mb', - type: 'initial', - }, - { - maximumError: '10kb', - maximumWarning: '6kb', - type: 'anyComponentStyle', - }, - ], - optimization: true, - outputHashing: 'all', - sourceMap: false, - extractCss: true, - namedChunks: false, - extractLicenses: true, - vendorChunk: false, - buildOptimizer: true, - }, - }, - }); - expect(updatedAngularCLIJson.projects.proj.architect.serve).toEqual({ - builder: '@angular-devkit/build-angular:dev-server', - options: { - browserTarget: 'proj:build', + // check if angular-cli.json get merged + const updatedAngularCLIJson = readJson('angular.json'); + expect(updatedAngularCLIJson.projects.proj.root).toEqual('apps/proj'); + expect(updatedAngularCLIJson.projects.proj.sourceRoot).toEqual( + 'apps/proj/src' + ); + + expect(updatedAngularCLIJson.projects.proj.architect.build).toEqual({ + builder: '@angular-devkit/build-angular:browser', + options: { + aot: true, + outputPath: 'dist/apps/proj', + index: 'apps/proj/src/index.html', + main: 'apps/proj/src/main.ts', + polyfills: 'apps/proj/src/polyfills.ts', + tsConfig: 'apps/proj/tsconfig.app.json', + assets: ['apps/proj/src/favicon.ico', 'apps/proj/src/assets'], + styles: ['apps/proj/src/styles.css'], + scripts: ['apps/proj/src/scripts.ts'], + }, + configurations: { + production: { + fileReplacements: [ + { + replace: 'apps/proj/src/environments/environment.ts', + with: 'apps/proj/src/environments/environment.prod.ts', + }, + ], + budgets: [ + { + maximumError: '5mb', + maximumWarning: '2mb', + type: 'initial', + }, + { + maximumError: '10kb', + maximumWarning: '6kb', + type: 'anyComponentStyle', + }, + ], + optimization: true, + outputHashing: 'all', + sourceMap: false, + extractCss: true, + namedChunks: false, + extractLicenses: true, + vendorChunk: false, + buildOptimizer: true, }, - configurations: { - production: { - browserTarget: 'proj:build:production', - }, + }, + }); + expect(updatedAngularCLIJson.projects.proj.architect.serve).toEqual({ + builder: '@angular-devkit/build-angular:dev-server', + options: { + browserTarget: 'proj:build', + }, + configurations: { + production: { + browserTarget: 'proj:build:production', }, - }); + }, + }); - expect(updatedAngularCLIJson.projects.proj.architect.test).toEqual({ - builder: '@angular-devkit/build-angular:karma', - options: { - main: 'apps/proj/src/test.ts', - polyfills: 'apps/proj/src/polyfills.ts', - tsConfig: 'apps/proj/tsconfig.spec.json', - karmaConfig: 'apps/proj/karma.conf.js', - styles: ['apps/proj/src/styles.css'], - scripts: ['apps/proj/src/scripts.ts'], - assets: ['apps/proj/src/favicon.ico', 'apps/proj/src/assets'], - }, - }); + expect(updatedAngularCLIJson.projects.proj.architect.test).toEqual({ + builder: '@angular-devkit/build-angular:karma', + options: { + main: 'apps/proj/src/test.ts', + polyfills: 'apps/proj/src/polyfills.ts', + tsConfig: 'apps/proj/tsconfig.spec.json', + karmaConfig: 'apps/proj/karma.conf.js', + styles: ['apps/proj/src/styles.css'], + scripts: ['apps/proj/src/scripts.ts'], + assets: ['apps/proj/src/favicon.ico', 'apps/proj/src/assets'], + }, + }); - expect(updatedAngularCLIJson.projects.proj.architect.lint).toEqual({ - builder: '@angular-devkit/build-angular:tslint', - options: { - tsConfig: [ - 'apps/proj/tsconfig.app.json', - 'apps/proj/tsconfig.spec.json', - ], - exclude: ['**/node_modules/**'], - }, - }); + expect(updatedAngularCLIJson.projects.proj.architect.lint).toEqual({ + builder: '@angular-devkit/build-angular:tslint', + options: { + tsConfig: [ + 'apps/proj/tsconfig.app.json', + 'apps/proj/tsconfig.spec.json', + ], + exclude: ['**/node_modules/**'], + }, + }); - expect(updatedAngularCLIJson.projects['proj-e2e'].root).toEqual( - 'apps/proj-e2e' - ); - expect(updatedAngularCLIJson.projects['proj-e2e'].architect.e2e).toEqual({ - builder: '@angular-devkit/build-angular:protractor', - configurations: { - production: { - devServerTarget: 'proj:serve:production', - }, + expect(updatedAngularCLIJson.projects['proj-e2e'].root).toEqual( + 'apps/proj-e2e' + ); + expect(updatedAngularCLIJson.projects['proj-e2e'].architect.e2e).toEqual({ + builder: '@angular-devkit/build-angular:protractor', + configurations: { + production: { + devServerTarget: 'proj:serve:production', }, - options: { - protractorConfig: 'apps/proj-e2e/protractor.conf.js', - devServerTarget: 'proj:serve', - }, - }); - expect(updatedAngularCLIJson.projects['proj-e2e'].architect.lint).toEqual( - { - builder: '@angular-devkit/build-angular:tslint', - options: { - tsConfig: 'apps/proj-e2e/tsconfig.json', - exclude: ['**/node_modules/**'], - }, - } - ); + }, + options: { + protractorConfig: 'apps/proj-e2e/protractor.conf.js', + devServerTarget: 'proj:serve', + }, + }); + expect(updatedAngularCLIJson.projects['proj-e2e'].architect.lint).toEqual({ + builder: '@angular-devkit/build-angular:tslint', + options: { + tsConfig: 'apps/proj-e2e/tsconfig.json', + exclude: ['**/node_modules/**'], + }, + }); - const updatedTslint = readJson('tslint.json'); - expect(updatedTslint.rules['nx-enforce-module-boundaries']).toEqual([ - true, - { - allow: [], - depConstraints: [{ sourceTag: '*', onlyDependOnLibsWithTags: ['*'] }], - }, - ]); + const updatedTslint = readJson('tslint.json'); + expect(updatedTslint.rules['nx-enforce-module-boundaries']).toEqual([ + true, + { + allow: [], + depConstraints: [{ sourceTag: '*', onlyDependOnLibsWithTags: ['*'] }], + }, + ]); + + runCLI('build --prod --outputHashing none'); + checkFilesExist('dist/apps/proj/main-es2015.js'); + }); - runCLI('build --prod --outputHashing none'); - checkFilesExist('dist/apps/proj/main-es2015.js'); - }); + it('should generate a workspace and not change dependencies, devDependencies, or vscode extensions if they already exist', () => { + // create a new AngularCLI app + runNgNew(); + const nxVersion = '9.3.0'; + const schematicsVersion = '9.3.0'; + const ngrxVersion = '9.2.0'; + // update package.json + const existingPackageJson = readJson('package.json'); + existingPackageJson.devDependencies['@nrwl/workspace'] = schematicsVersion; + existingPackageJson.dependencies['@ngrx/store'] = ngrxVersion; + existingPackageJson.dependencies['@ngrx/effects'] = ngrxVersion; + existingPackageJson.dependencies['@ngrx/router-store'] = ngrxVersion; + existingPackageJson.devDependencies['@ngrx/store-devtools'] = ngrxVersion; + updateFile('package.json', JSON.stringify(existingPackageJson, null, 2)); + + updateFile( + '.vscode/extensions.json', + JSON.stringify({ + recommendations: ['eamodio.gitlens', 'angular.ng-template'], + }) + ); + // run the command + runNgAdd('--npmScope projscope --skip-install'); + + // check that dependencies and devDependencies remained the same + const packageJson = readJson('package.json'); + expect(packageJson.devDependencies['@nrwl/workspace']).toEqual( + schematicsVersion + ); + expect(packageJson.dependencies['@ngrx/store']).toEqual(ngrxVersion); + expect(packageJson.dependencies['@ngrx/effects']).toEqual(ngrxVersion); + expect(packageJson.dependencies['@ngrx/router-store']).toEqual(ngrxVersion); + expect(packageJson.devDependencies['@ngrx/store-devtools']).toEqual( + ngrxVersion + ); + + expect(readJson('.vscode/extensions.json').recommendations).toEqual([ + 'eamodio.gitlens', + 'angular.ng-template', + 'nrwl.angular-console', + 'ms-vscode.vscode-typescript-tslint-plugin', + 'esbenp.prettier-vscode', + ]); + }); - it('should generate a workspace and not change dependencies, devDependencies, or vscode extensions if they already exist', () => { - // create a new AngularCLI app - runNgNew(); - const nxVersion = '9.3.0'; - const schematicsVersion = '9.3.0'; - const ngrxVersion = '9.2.0'; - // update package.json - const existingPackageJson = readJson('package.json'); - existingPackageJson.devDependencies[ - '@nrwl/workspace' - ] = schematicsVersion; - existingPackageJson.dependencies['@ngrx/store'] = ngrxVersion; - existingPackageJson.dependencies['@ngrx/effects'] = ngrxVersion; - existingPackageJson.dependencies['@ngrx/router-store'] = ngrxVersion; - existingPackageJson.devDependencies['@ngrx/store-devtools'] = ngrxVersion; - updateFile('package.json', JSON.stringify(existingPackageJson, null, 2)); + it('should handle different types of errors', () => { + // create a new AngularCLI app + runNgNew(); - updateFile( - '.vscode/extensions.json', - JSON.stringify({ - recommendations: ['eamodio.gitlens', 'angular.ng-template'], - }) - ); - // run the command + // Only remove e2e directory + runCommand('mv e2e e2e-bak'); + try { runNgAdd('--npmScope projscope --skip-install'); - - // check that dependencies and devDependencies remained the same - const packageJson = readJson('package.json'); - expect(packageJson.devDependencies['@nrwl/workspace']).toEqual( - schematicsVersion - ); - expect(packageJson.dependencies['@ngrx/store']).toEqual(ngrxVersion); - expect(packageJson.dependencies['@ngrx/effects']).toEqual(ngrxVersion); - expect(packageJson.dependencies['@ngrx/router-store']).toEqual( - ngrxVersion - ); - expect(packageJson.devDependencies['@ngrx/store-devtools']).toEqual( - ngrxVersion + fail('Did not handle not having a e2e directory'); + } catch (e) { + expect(e.stderr.toString()).toContain( + 'Your workspace could not be converted into an Nx Workspace because of the above error.' ); + } - expect(readJson('.vscode/extensions.json').recommendations).toEqual([ - 'eamodio.gitlens', - 'angular.ng-template', - 'nrwl.angular-console', - 'ms-vscode.vscode-typescript-tslint-plugin', - 'esbenp.prettier-vscode', - ]); - }); + // Put e2e back + runCommand('mv e2e-bak e2e'); - it('should handle different types of errors', () => { - // create a new AngularCLI app - runNgNew(); - - // Only remove e2e directory - runCommand('mv e2e e2e-bak'); - try { - runNgAdd('--npmScope projscope --skip-install'); - fail('Did not handle not having a e2e directory'); - } catch (e) { - expect(e.stderr.toString()).toContain( - 'Your workspace could not be converted into an Nx Workspace because of the above error.' - ); - } - - // Put e2e back - runCommand('mv e2e-bak e2e'); - - // Remove package.json - runCommand('mv package.json package.json.bak'); - try { - runNgAdd('--npmScope projscope --skip-install'); - fail('Did not handle not having a package.json'); - } catch (e) { - expect(e.stderr.toString()).toContain( - 'Your workspace could not be converted into an Nx Workspace because of the above error.' - ); - } - - // Put package.json back - runCommand('mv package.json.bak package.json'); + // Remove package.json + runCommand('mv package.json package.json.bak'); + try { + runNgAdd('--npmScope projscope --skip-install'); + fail('Did not handle not having a package.json'); + } catch (e) { + expect(e.stderr.toString()).toContain( + 'Your workspace could not be converted into an Nx Workspace because of the above error.' + ); + } - // Remove src - runCommand('mv src src-bak'); - try { - runNgAdd('--npmScope projscope --skip-install'); - fail('Did not handle not having a src directory'); - } catch (e) { - expect(e.stderr.toString()).toContain('Path: src does not exist'); - } + // Put package.json back + runCommand('mv package.json.bak package.json'); - // Put src back - runCommand('mv src-bak src'); - }); + // Remove src + runCommand('mv src src-bak'); + try { + runNgAdd('--npmScope projscope --skip-install'); + fail('Did not handle not having a src directory'); + } catch (e) { + expect(e.stderr.toString()).toContain('Path: src does not exist'); + } - it('should support preserveAngularCLILayout', () => { - runNgNew(); - runNgAdd('--preserveAngularCLILayout'); + // Put src back + runCommand('mv src-bak src'); + }); - const updatedAngularCLIJson = readJson('angular.json'); - expect(updatedAngularCLIJson.projects.proj.root).toEqual(''); - expect(updatedAngularCLIJson.projects.proj.sourceRoot).toEqual('src'); + it('should support preserveAngularCLILayout', () => { + runNgNew(); + runNgAdd('--preserveAngularCLILayout'); - const output = runCLI('build'); - expect(output).toContain(`> ng run proj:build`); - }); - }); -}); + const updatedAngularCLIJson = readJson('angular.json'); + expect(updatedAngularCLIJson.projects.proj.root).toEqual(''); + expect(updatedAngularCLIJson.projects.proj.sourceRoot).toEqual('src'); -forEachCli('nx', () => { - xdescribe('ng-add', () => { - it('is not supported', () => {}); + const output = runCLI('build'); + expect(output).toContain(`> ng run proj:build`); }); }); diff --git a/e2e/angular/src/ngrx.test.ts b/e2e/angular/src/ngrx.test.ts index 7a82ecf98bd7d..09905c3b69fe4 100644 --- a/e2e/angular/src/ngrx.test.ts +++ b/e2e/angular/src/ngrx.test.ts @@ -1,6 +1,5 @@ import { expectTestsPass, - forEachCli, newProject, readJson, runCLI, @@ -8,66 +7,64 @@ import { uniq, } from '@nrwl/e2e/utils'; -forEachCli(() => { - describe('ngrx', () => { - it('should work', async () => { - newProject(); +describe('ngrx', () => { + it('should work', async () => { + newProject(); - const myapp = uniq('myapp'); - runCLI(`generate @nrwl/angular:app ${myapp} --no-interactive`); + const myapp = uniq('myapp'); + runCLI(`generate @nrwl/angular:app ${myapp} --no-interactive`); - // Generate root ngrx state management - runCLI( - `generate @nrwl/angular:ngrx users --module=apps/${myapp}/src/app/app.module.ts --root --minimal=false --syntax=classes --useDataPersistence=true` - ); - const packageJson = readJson('package.json'); - expect(packageJson.dependencies['@ngrx/store']).toBeDefined(); - expect(packageJson.dependencies['@ngrx/effects']).toBeDefined(); - expect(packageJson.dependencies['@ngrx/router-store']).toBeDefined(); - expect(packageJson.devDependencies['@ngrx/store-devtools']).toBeDefined(); + // Generate root ngrx state management + runCLI( + `generate @nrwl/angular:ngrx users --module=apps/${myapp}/src/app/app.module.ts --root --minimal=false --syntax=classes --useDataPersistence=true` + ); + const packageJson = readJson('package.json'); + expect(packageJson.dependencies['@ngrx/store']).toBeDefined(); + expect(packageJson.dependencies['@ngrx/effects']).toBeDefined(); + expect(packageJson.dependencies['@ngrx/router-store']).toBeDefined(); + expect(packageJson.devDependencies['@ngrx/store-devtools']).toBeDefined(); - const mylib = uniq('mylib'); - // Generate feature library and ngrx state within that library - runCLI(`g @nrwl/angular:lib ${mylib} --prefix=fl`); - runCLI( - `generate @nrwl/angular:ngrx flights --module=libs/${mylib}/src/lib/${mylib}.module.ts --facade --syntax=classes` - ); + const mylib = uniq('mylib'); + // Generate feature library and ngrx state within that library + runCLI(`g @nrwl/angular:lib ${mylib} --prefix=fl`); + runCLI( + `generate @nrwl/angular:ngrx flights --module=libs/${mylib}/src/lib/${mylib}.module.ts --facade --syntax=classes` + ); - expect(runCLI(`build ${myapp}`)).toContain('chunk {main} main.js,'); - expectTestsPass(await runCLIAsync(`test ${myapp} --no-watch`)); - expectTestsPass(await runCLIAsync(`test ${mylib} --no-watch`)); - }, 1000000); + expect(runCLI(`build ${myapp}`)).toContain('chunk {main} main.js,'); + expectTestsPass(await runCLIAsync(`test ${myapp} --no-watch`)); + expectTestsPass(await runCLIAsync(`test ${mylib} --no-watch`)); + }, 1000000); - it('should work with creators', async () => { - newProject(); + it('should work with creators', async () => { + newProject(); - const myapp = uniq('myapp'); - runCLI(`generate @nrwl/angular:app ${myapp} --routing --no-interactive`); + const myapp = uniq('myapp'); + runCLI(`generate @nrwl/angular:app ${myapp} --routing --no-interactive`); - // Generate root ngrx state management - runCLI( - `generate @nrwl/angular:ngrx users --module=apps/${myapp}/src/app/app.module.ts --root` - ); - const packageJson = readJson('package.json'); - expect(packageJson.dependencies['@ngrx/entity']).toBeDefined(); - expect(packageJson.dependencies['@ngrx/store']).toBeDefined(); - expect(packageJson.dependencies['@ngrx/effects']).toBeDefined(); - expect(packageJson.dependencies['@ngrx/router-store']).toBeDefined(); - expect(packageJson.devDependencies['@ngrx/schematics']).toBeDefined(); - expect(packageJson.devDependencies['@ngrx/store-devtools']).toBeDefined(); + // Generate root ngrx state management + runCLI( + `generate @nrwl/angular:ngrx users --module=apps/${myapp}/src/app/app.module.ts --root` + ); + const packageJson = readJson('package.json'); + expect(packageJson.dependencies['@ngrx/entity']).toBeDefined(); + expect(packageJson.dependencies['@ngrx/store']).toBeDefined(); + expect(packageJson.dependencies['@ngrx/effects']).toBeDefined(); + expect(packageJson.dependencies['@ngrx/router-store']).toBeDefined(); + expect(packageJson.devDependencies['@ngrx/schematics']).toBeDefined(); + expect(packageJson.devDependencies['@ngrx/store-devtools']).toBeDefined(); - const mylib = uniq('mylib'); - // Generate feature library and ngrx state within that library - runCLI(`g @nrwl/angular:lib ${mylib} --prefix=fl`); + const mylib = uniq('mylib'); + // Generate feature library and ngrx state within that library + runCLI(`g @nrwl/angular:lib ${mylib} --prefix=fl`); - const flags = `--facade --barrels`; - runCLI( - `generate @nrwl/angular:ngrx flights --module=libs/${mylib}/src/lib/${mylib}.module.ts ${flags}` - ); + const flags = `--facade --barrels`; + runCLI( + `generate @nrwl/angular:ngrx flights --module=libs/${mylib}/src/lib/${mylib}.module.ts ${flags}` + ); - expect(runCLI(`build ${myapp}`)).toContain('chunk {main} main.js,'); - expectTestsPass(await runCLIAsync(`test ${myapp} --no-watch`)); - expectTestsPass(await runCLIAsync(`test ${mylib} --no-watch`)); - }, 1000000); - }); + expect(runCLI(`build ${myapp}`)).toContain('chunk {main} main.js,'); + expectTestsPass(await runCLIAsync(`test ${myapp} --no-watch`)); + expectTestsPass(await runCLIAsync(`test ${mylib} --no-watch`)); + }, 1000000); }); diff --git a/e2e/angular/src/protractor.test.ts b/e2e/angular/src/protractor.test.ts deleted file mode 100644 index 7ddf426c93f08..0000000000000 --- a/e2e/angular/src/protractor.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { forEachCli, newProject, runCLI, uniq } from '@nrwl/e2e/utils'; - -forEachCli(() => { - describe('Protractor', () => { - it('empty test', () => { - expect(1).toEqual(1); - }); - }); - - xdescribe('Protractor', () => { - beforeEach(() => { - newProject(); - }); - - it('should work', async () => { - const myapp = uniq('myapp'); - runCLI( - `generate @nrwl/angular:app ${myapp} --directory=myDir --routing --e2eTestRunner=protractor` - ); - - try { - const r = runCLI(`e2e my-dir-${myapp}-e2e --no-webdriver-update`); - console.log(r); - expect(r).toContain('Executed 1 of 1 spec SUCCESS'); - } catch (e) { - console.log(e); - if (e.stdout) { - console.log(e.stdout.toString()); - } - if (e.stderr) { - console.log(e.stdout.toString()); - } - throw e; - } - }, 1000000); - }); -}); diff --git a/e2e/cli/src/cli.test.ts b/e2e/cli/src/cli.test.ts index 45a97a71acccd..b49e1f79fcf41 100644 --- a/e2e/cli/src/cli.test.ts +++ b/e2e/cli/src/cli.test.ts @@ -1,7 +1,6 @@ import { packagesWeCareAbout } from '@nrwl/workspace/src/command-line/report'; import { renameSync } from 'fs'; import { - forEachCli, newProject, readFile, readJson, @@ -12,209 +11,173 @@ import { updateFile, } from '@nrwl/e2e/utils'; -forEachCli('nx', () => { - describe('Help', () => { - it('should show help', async () => { - newProject(); - // sss - const myapp = uniq('myapp'); - runCLI(`generate @nrwl/web:app ${myapp}`); +describe('Help', () => { + it('should show help', async () => { + newProject(); + const myapp = uniq('myapp'); + runCLI(`generate @nrwl/web:app ${myapp}`); - let mainHelp = runCLI(`--help`); - expect(mainHelp).toContain('Run a target for a project'); - expect(mainHelp).toContain('Run task for affected projects'); + 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'); + 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 genHelp = runCLI(`g @nrwl/web:app --help`); + expect(genHelp).toContain( + 'The file extension to be used for style files. (default: css)' + ); - const buildHelp = runCLI(`build ${myapp} --help`); - expect(buildHelp).toContain('The name of the main entry-point file.'); + const buildHelp = runCLI(`build ${myapp} --help`); + expect(buildHelp).toContain('The name of the main entry-point file.'); - const affectedHelp = runCLI(`affected --help`); - expect(affectedHelp).toContain('Run task for affected projects'); + const affectedHelp = runCLI(`affected --help`); + expect(affectedHelp).toContain('Run task for affected projects'); - const version = runCLI(`--version`); - expect(version).toContain(process.env.PUBLISHED_VERSION); // stub value - }, 120000); - }); + const version = runCLI(`--version`); + expect(version).toContain(process.env.PUBLISHED_VERSION); // stub value + }, 120000); }); -forEachCli('angular', () => { - describe('help', () => { - it('should show help', async () => { - newProject(); - const myapp = uniq('myapp'); - runCLI(`generate @nrwl/web:app ${myapp}`); - - 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.' - ); +describe('report', () => { + it(`should report package versions`, async () => { + newProject(); - const buildHelp = runCLI(`build ${myapp} --help`); - expect(buildHelp).toContain('The name of the main entry-point file.'); + const reportOutput = runCommand('npm run nx report'); - const affectedHelp = runCLI(`affected --help`); - expect(affectedHelp).toContain('Run task for affected projects'); - - const version = runCLI(`--version`); - expect(version).toContain(process.env.PUBLISHED_VERSION); // stub value - }, 120000); - }); + packagesWeCareAbout.forEach((p) => { + expect(reportOutput).toContain(p); + }); + }, 120000); }); -forEachCli(() => { - describe('report', () => { - it(`should report package versions`, async () => { - newProject(); - - const reportOutput = runCommand('npm run nx report'); - - packagesWeCareAbout.forEach((p) => { - expect(reportOutput).toContain(p); - }); - }, 120000); +describe('list', () => { + beforeEach(() => { + newProject(); }); - describe('list', () => { - beforeEach(() => { - newProject(); - }); - - it(`should work`, async () => { - let listOutput = runCommand('npm run nx -- list'); + it(`should work`, async () => { + let listOutput = runCommand('npm run nx -- list'); - expect(listOutput).toContain('NX Installed plugins'); + expect(listOutput).toContain('NX Installed plugins'); - // just check for some, not all - expect(listOutput).toContain('@nrwl/angular'); + // just check for some, not all + expect(listOutput).toContain('@nrwl/angular'); - // temporarily make it look like this isn't installed - renameSync( - tmpProjPath('node_modules/@nrwl/angular'), - tmpProjPath('node_modules/@nrwl/angular_tmp') - ); + // 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'); + listOutput = runCommand('npm run nx -- list'); + expect(listOutput).toContain('NX Also available'); - // look for specific plugin - listOutput = runCommand('npm run nx -- list @nrwl/workspace'); + // look for specific plugin + listOutput = runCommand('npm run nx -- list @nrwl/workspace'); - expect(listOutput).toContain('Capabilities in @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 schematics + expect(listOutput).toContain('workspace'); + expect(listOutput).toContain('ng-add'); + expect(listOutput).toContain('library'); - // check for builders - expect(listOutput).toContain('run-commands'); + // check for builders + expect(listOutput).toContain('run-commands'); - // // look for uninstalled core plugin - listOutput = runCommand('npm run nx -- list @nrwl/angular'); + // // look for uninstalled core plugin + listOutput = runCommand('npm run nx -- list @nrwl/angular'); - expect(listOutput).toContain( - 'NX NOTE @nrwl/angular is not currently installed' - ); + expect(listOutput).toContain( + 'NX NOTE @nrwl/angular is not currently installed' + ); - // look for an unknown plugin - listOutput = runCommand('npm run nx -- list @wibble/fish'); + // look for an unknown plugin + listOutput = runCommand('npm run nx -- list @wibble/fish'); - expect(listOutput).toContain( - 'NX NOTE @wibble/fish is not currently installed' - ); + expect(listOutput).toContain( + 'NX NOTE @wibble/fish is not currently installed' + ); - // 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); - }); + // 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', () => { - newProject(); - - 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', - }, +describe('migrate', () => { + it('should run migrations', () => { + newProject(); + + 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`, - ` + 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`, - ` + 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 = ` + ); + + 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') { @@ -239,42 +202,39 @@ forEachCli(() => { } `; - 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' - ); - expect(readFile(`package.json`).endsWith(`}\n`)).toEqual(true); - - // 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'); + 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'); + expect(readFile(`package.json`).endsWith(`}\n`)).toEqual(true); + + // 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'); }); }); diff --git a/e2e/utils/index.ts b/e2e/utils/index.ts index 437b2189d24d8..762485f3c36a6 100644 --- a/e2e/utils/index.ts +++ b/e2e/utils/index.ts @@ -15,10 +15,8 @@ interface RunCmdOpts { cwd?: string; } -let cli; - export function currentCli() { - return cli ? cli : 'nx'; + return process.env.SELECTED_CLI ? process.env.SELECTED_CLI : 'nx'; } let projName: string; @@ -32,52 +30,6 @@ export function uniq(prefix: string) { return `${prefix}${Math.floor(Math.random() * 10000000)}`; } -export function forEachCli( - selectedCliOrFunction: string | Function, - callback?: (currentCLIName) => void -) { - let clis; - if (process.env.SELECTED_CLI && selectedCliOrFunction && callback) { - if (selectedCliOrFunction == process.env.SELECTED_CLI) { - clis = [process.env.SELECTED_CLI]; - } else { - clis = []; - } - } else if (process.env.SELECTED_CLI) { - clis = [process.env.SELECTED_CLI]; - } else { - clis = callback ? [selectedCliOrFunction] : ['nx', 'angular']; - } - - const cb: any = callback ? callback : selectedCliOrFunction; - clis.forEach((c) => { - describe(`[${c}]`, () => { - beforeAll(() => { - cli = c; - }); - cb(c); - }); - }); -} - -export function patchKarmaToWorkOnWSL(): void { - try { - const karma = readFile('karma.conf.js'); - if (process.env['WINDOWSTMP']) { - updateFile( - 'karma.conf.js', - karma.replace( - `const { constants } = require('karma');`, - ` - const { constants } = require('karma'); - process.env['TMPDIR']="${process.env['WINDOWSTMP']}"; - ` - ) - ); - } - } catch (e) {} -} - export function workspaceConfigName() { return currentCli() === 'angular' ? 'angular.json' : 'workspace.json'; } diff --git a/e2e/workspace/src/create-nx-workspace.test.ts b/e2e/workspace/src/create-nx-workspace.test.ts index 140face8ed970..17cabf9df3b60 100644 --- a/e2e/workspace/src/create-nx-workspace.test.ts +++ b/e2e/workspace/src/create-nx-workspace.test.ts @@ -1,122 +1,113 @@ -import { - currentCli, - forEachCli, - runCreateWorkspace, - uniq, -} from '@nrwl/e2e/utils'; +import { runCreateWorkspace, uniq } from '@nrwl/e2e/utils'; import { existsSync, mkdirSync } from 'fs-extra'; import { execSync } from 'child_process'; -forEachCli(() => { - describe('create-nx-workspace', () => { - it('should be able to create an empty workspace', () => { - const wsName = uniq('empty'); - runCreateWorkspace(wsName, { - preset: 'empty', - }); +describe('create-nx-workspace', () => { + it('should be able to create an empty workspace', () => { + const wsName = uniq('empty'); + runCreateWorkspace(wsName, { + preset: 'empty', }); + }); - it('should be able to create an oss workspace', () => { - const wsName = uniq('oss'); - runCreateWorkspace(wsName, { - preset: 'oss', - }); + it('should be able to create an oss workspace', () => { + const wsName = uniq('oss'); + runCreateWorkspace(wsName, { + preset: 'oss', }); + }); - it('should be able to create an angular workspace', () => { - const wsName = uniq('angular'); - const appName = uniq('app'); - runCreateWorkspace(wsName, { - preset: 'angular', - style: 'css', - appName, - }); + it('should be able to create an angular workspace', () => { + const wsName = uniq('angular'); + const appName = uniq('app'); + runCreateWorkspace(wsName, { + preset: 'angular', + style: 'css', + appName, }); + }); - it('should be able to create an react workspace', () => { - const wsName = uniq('react'); - const appName = uniq('app'); - runCreateWorkspace(wsName, { - preset: 'react', - style: 'css', - appName, - }); + it('should be able to create an react workspace', () => { + const wsName = uniq('react'); + const appName = uniq('app'); + runCreateWorkspace(wsName, { + preset: 'react', + style: 'css', + appName, }); + }); - it('should be able to create an next workspace', () => { - const wsName = uniq('next'); - const appName = uniq('app'); - runCreateWorkspace(wsName, { - preset: 'next', - style: 'css', - appName, - }); + it('should be able to create an next workspace', () => { + const wsName = uniq('next'); + const appName = uniq('app'); + runCreateWorkspace(wsName, { + preset: 'next', + style: 'css', + appName, }); + }); - it('should be able to create an web-components workspace', () => { - const wsName = uniq('web-components'); - const appName = uniq('app'); - runCreateWorkspace(wsName, { - preset: 'web-components', - style: 'css', - appName, - }); + it('should be able to create an web-components workspace', () => { + const wsName = uniq('web-components'); + const appName = uniq('app'); + runCreateWorkspace(wsName, { + preset: 'web-components', + style: 'css', + appName, }); + }); - it('should be able to create an angular + nest workspace', () => { - const wsName = uniq('angular-nest'); - const appName = uniq('app'); - runCreateWorkspace(wsName, { - preset: 'angular-nest', - style: 'css', - appName, - }); + it('should be able to create an angular + nest workspace', () => { + const wsName = uniq('angular-nest'); + const appName = uniq('app'); + runCreateWorkspace(wsName, { + preset: 'angular-nest', + style: 'css', + appName, }); + }); - it('should be able to create an react + express workspace', () => { - const wsName = uniq('react-express'); - const appName = uniq('app'); - runCreateWorkspace(wsName, { - preset: 'react-express', - style: 'css', - appName, - }); + it('should be able to create an react + express workspace', () => { + const wsName = uniq('react-express'); + const appName = uniq('app'); + runCreateWorkspace(wsName, { + preset: 'react-express', + style: 'css', + appName, }); + }); - it('should be able to create a workspace with a custom base branch and HEAD', () => { - const wsName = uniq('branch'); - runCreateWorkspace(wsName, { - preset: 'empty', - base: 'main', - }); + it('should be able to create a workspace with a custom base branch and HEAD', () => { + const wsName = uniq('branch'); + runCreateWorkspace(wsName, { + preset: 'empty', + base: 'main', }); + }); - it('should be able to create a nest workspace', () => { - const wsName = uniq('nest'); - const appName = uniq('app'); - runCreateWorkspace(wsName, { - preset: 'nest', - appName, - }); + it('should be able to create a nest workspace', () => { + const wsName = uniq('nest'); + const appName = uniq('app'); + runCreateWorkspace(wsName, { + preset: 'nest', + appName, }); + }); - it('should handle spaces in workspace path', () => { - const wsName = uniq('empty'); - - const tmpDir = `./tmp/${currentCli()}/with space`; + it('should handle spaces in workspace path', () => { + const wsName = uniq('empty'); - mkdirSync(tmpDir); + const tmpDir = `./tmp/nx/with space`; - const command = `npx create-nx-workspace@${ - process.env.PUBLISHED_VERSION - } ${wsName} --cli=${currentCli()} --preset=empty --no-nxCloud --no-interactive`; - execSync(command, { - cwd: tmpDir, - stdio: [0, 1, 2], - env: process.env, - }); + mkdirSync(tmpDir); - expect(existsSync(`${tmpDir}/${wsName}/package.json`)).toBeTruthy(); + const command = `npx create-nx-workspace@${process.env.PUBLISHED_VERSION} ${wsName} --cli=nx --preset=empty --no-nxCloud --no-interactive`; + execSync(command, { + cwd: tmpDir, + stdio: [0, 1, 2], + env: process.env, }); + + expect(existsSync(`${tmpDir}/${wsName}/package.json`)).toBeTruthy(); }); }); diff --git a/e2e/workspace/src/custom-layout.test.ts b/e2e/workspace/src/custom-layout.test.ts index dcdbdef3be7b0..b5e3f38792d47 100644 --- a/e2e/workspace/src/custom-layout.test.ts +++ b/e2e/workspace/src/custom-layout.test.ts @@ -1,6 +1,5 @@ import { checkFilesExist, - forEachCli, readFile, readJson, runCLI, @@ -11,67 +10,59 @@ import { yarnAdd, } from '@nrwl/e2e/utils'; -forEachCli('nx', () => { - describe('custom workspace layout', () => { - it('should work', async () => { - const proj = setCurrentProjName(uniq('custom-layout-proj')); - runCreateWorkspace(proj, { preset: 'oss' }); - yarnAdd('@nrwl/react @nrwl/angular @nrwl/express'); +describe('custom workspace layout', () => { + it('should work', async () => { + const proj = setCurrentProjName(uniq('custom-layout-proj')); + runCreateWorkspace(proj, { preset: 'oss' }); + yarnAdd('@nrwl/react @nrwl/angular @nrwl/express'); - const nxJson = readJson('nx.json'); - expect(nxJson.workspaceLayout).toEqual({ - libsDir: 'packages', - appsDir: 'packages', - }); + const nxJson = readJson('nx.json'); + expect(nxJson.workspaceLayout).toEqual({ + libsDir: 'packages', + appsDir: 'packages', + }); - const reactApp = uniq('reactapp'); - const reactLib = uniq('reactlib'); + const reactApp = uniq('reactapp'); + const reactLib = uniq('reactlib'); - const ngApp = uniq('ngapp'); - const ngLib = uniq('nglib'); + const ngApp = uniq('ngapp'); + const ngLib = uniq('nglib'); - const expressApp = uniq('expessapp'); - const expressLib = uniq('expresslib'); + const expressApp = uniq('expessapp'); + const expressLib = uniq('expresslib'); - runCLI(`generate @nrwl/react:app ${reactApp} --no-interactive`); - runCLI(`generate @nrwl/react:lib ${reactLib} --no-interactive`); + runCLI(`generate @nrwl/react:app ${reactApp} --no-interactive`); + runCLI(`generate @nrwl/react:lib ${reactLib} --no-interactive`); - runCLI(`generate @nrwl/angular:app ${ngApp} --no-interactive`); - runCLI(`generate @nrwl/angular:lib ${ngLib} --no-interactive`); + runCLI(`generate @nrwl/angular:app ${ngApp} --no-interactive`); + runCLI(`generate @nrwl/angular:lib ${ngLib} --no-interactive`); - runCLI(`generate @nrwl/express:app ${expressApp} --no-interactive`); - runCLI(`generate @nrwl/express:lib ${expressLib} --no-interactive`); + runCLI(`generate @nrwl/express:app ${expressApp} --no-interactive`); + runCLI(`generate @nrwl/express:lib ${expressLib} --no-interactive`); - checkFilesExist( - `packages/${reactLib}/src/index.ts`, - `packages/${reactApp}/src/main.tsx`, - `packages/${reactApp}-e2e/cypress.json`, + checkFilesExist( + `packages/${reactLib}/src/index.ts`, + `packages/${reactApp}/src/main.tsx`, + `packages/${reactApp}-e2e/cypress.json`, - `packages/${ngLib}/src/index.ts`, - `packages/${ngApp}/src/main.ts`, - `packages/${ngApp}-e2e/cypress.json`, + `packages/${ngLib}/src/index.ts`, + `packages/${ngApp}/src/main.ts`, + `packages/${ngApp}-e2e/cypress.json`, - `packages/${expressLib}/src/index.ts`, - `packages/${expressApp}/src/main.ts` - ); + `packages/${expressLib}/src/index.ts`, + `packages/${expressApp}/src/main.ts` + ); - const workspaceJson = readFile('workspace.json'); - expect(workspaceJson).not.toContain('apps/'); - expect(workspaceJson).not.toContain('libs/'); + const workspaceJson = readFile('workspace.json'); + expect(workspaceJson).not.toContain('apps/'); + expect(workspaceJson).not.toContain('libs/'); - const libTestResults = await runCLIAsync(`test ${expressLib}`); - expect(libTestResults.stdout).toContain(`nx run ${expressLib}:test`); + const libTestResults = await runCLIAsync(`test ${expressLib}`); + expect(libTestResults.stdout).toContain(`nx run ${expressLib}:test`); - const appBuildResults = await runCLIAsync(`build ${expressApp}`); - expect(appBuildResults.stdout).toContain(`nx run ${expressApp}:build`); + const appBuildResults = await runCLIAsync(`build ${expressApp}`); + expect(appBuildResults.stdout).toContain(`nx run ${expressApp}:build`); - checkFilesExist(`dist/packages/${expressApp}/main.js`); - }, 1000000); - }); -}); - -forEachCli('angular', () => { - describe('custom workspace layout', () => { - it('should work', () => {}); - }); + checkFilesExist(`dist/packages/${expressApp}/main.js`); + }, 1000000); }); diff --git a/e2e/workspace/src/run-commands.test.ts b/e2e/workspace/src/run-commands.test.ts index 53e860bdfaa80..1ad6703d7d14d 100644 --- a/e2e/workspace/src/run-commands.test.ts +++ b/e2e/workspace/src/run-commands.test.ts @@ -1,5 +1,4 @@ import { - forEachCli, newProject, readJson, runCLI, @@ -8,54 +7,52 @@ import { workspaceConfigName, } from '@nrwl/e2e/utils'; -forEachCli(() => { - describe('Run Commands', () => { - it('should not override environment variables already set when setting a custom env file path', async (done) => { - newProject(); - const nodeapp = uniq('nodeapp'); - updateFile( - `.env`, - 'SHARED_VAR=shared-root-value\nROOT_ONLY=root-only-value' - ); - runCLI(`generate @nrwl/express:app ${nodeapp}`); - updateFile( - `apps/${nodeapp}/.custom.env`, - 'SHARED_VAR=shared-nested-value\nNESTED_ONLY=nested-only-value' - ); +describe('Run Commands', () => { + it('should not override environment variables already set when setting a custom env file path', async (done) => { + newProject(); + const nodeapp = uniq('nodeapp'); + updateFile( + `.env`, + 'SHARED_VAR=shared-root-value\nROOT_ONLY=root-only-value' + ); + runCLI(`generate @nrwl/express:app ${nodeapp}`); + updateFile( + `apps/${nodeapp}/.custom.env`, + 'SHARED_VAR=shared-nested-value\nNESTED_ONLY=nested-only-value' + ); - const command = `echo "$SHARED_VAR $ROOT_ONLY $NESTED_ONLY"`; - const envFile = `apps/${nodeapp}/.custom.env`; - runCLI( - `generate @nrwl/workspace:run-commands echoEnvVariables --command='${command}' --envFile='${envFile}' --project=${nodeapp}` - ); + const command = `echo "$SHARED_VAR $ROOT_ONLY $NESTED_ONLY"`; + const envFile = `apps/${nodeapp}/.custom.env`; + runCLI( + `generate @nrwl/workspace:run-commands echoEnvVariables --command='${command}' --envFile='${envFile}' --project=${nodeapp}` + ); - const result = runCLI('echoEnvVariables'); - expect(result).toContain('shared-root-value'); - expect(result).not.toContain('shared-nested-value'); - expect(result).toContain('root-only-value'); - expect(result).toContain('nested-only-value'); - done(); - }, 120000); + const result = runCLI('echoEnvVariables'); + expect(result).toContain('shared-root-value'); + expect(result).not.toContain('shared-nested-value'); + expect(result).toContain('root-only-value'); + expect(result).toContain('nested-only-value'); + done(); + }, 120000); - it('should interpolate provided arguments', async (done) => { - newProject(); - const myapp = uniq('myapp1'); + it('should interpolate provided arguments', async (done) => { + newProject(); + const myapp = uniq('myapp1'); - runCLI(`generate @nrwl/web:app ${myapp}`); + runCLI(`generate @nrwl/web:app ${myapp}`); - const config = readJson(workspaceConfigName()); - config.projects[myapp].architect.echo = { - builder: '@nrwl/workspace:run-commands', - options: { - commands: [`echo 'print: {args.var1}'`, `echo 'print: {args.var2}'`], - }, - }; - updateFile(workspaceConfigName(), JSON.stringify(config)); + const config = readJson(workspaceConfigName()); + config.projects[myapp].architect.echo = { + builder: '@nrwl/workspace:run-commands', + options: { + commands: [`echo 'print: {args.var1}'`, `echo 'print: {args.var2}'`], + }, + }; + updateFile(workspaceConfigName(), JSON.stringify(config)); - const result = runCLI('echo --var1=x --var2=y'); - expect(result).toContain('print: x'); - expect(result).toContain('print: y'); - done(); - }, 120000); - }); + const result = runCLI('echo --var1=x --var2=y'); + expect(result).toContain('print: x'); + expect(result).toContain('print: y'); + done(); + }, 120000); }); diff --git a/e2e/workspace/src/workspace-aux-commands.test.ts b/e2e/workspace/src/workspace-aux-commands.test.ts index 7a4c9e116b30c..44c7873183233 100644 --- a/e2e/workspace/src/workspace-aux-commands.test.ts +++ b/e2e/workspace/src/workspace-aux-commands.test.ts @@ -1,13 +1,11 @@ import { checkFilesExist, exists, - forEachCli, newProject, readFile, readJson, runCLI, runCommand, - runCommandAsync, tmpProjPath, uniq, updateFile, @@ -16,53 +14,52 @@ import { import { NxJson } from '@nrwl/workspace'; import { classify } from '@nrwl/workspace/src/utils/strings'; -forEachCli((cli) => { - beforeAll(() => { - newProject(); - }); +beforeAll(() => { + newProject(); +}); - describe('lint', () => { - it('lint should ensure module boundaries', () => { - const myapp = uniq('myapp'); - const myapp2 = uniq('myapp2'); - const mylib = uniq('mylib'); - const lazylib = uniq('lazylib'); - const invalidtaglib = uniq('invalidtaglib'); - const validtaglib = uniq('validtaglib'); - - runCLI(`generate @nrwl/angular:app ${myapp} --tags=validtag`); - runCLI(`generate @nrwl/angular:app ${myapp2}`); - runCLI(`generate @nrwl/angular:lib ${mylib}`); - runCLI(`generate @nrwl/angular:lib ${lazylib}`); - runCLI(`generate @nrwl/angular:lib ${invalidtaglib} --tags=invalidtag`); - runCLI(`generate @nrwl/angular:lib ${validtaglib} --tags=validtag`); - - const 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)); - - const tsConfig = readJson('tsconfig.base.json'); - - /** - * apps do not add themselves to the tsconfig file. - * - * Let's add it so that we can trigger the lint failure - */ - tsConfig.compilerOptions.paths[`@proj/${myapp2}`] = [ - `apps/${myapp2}/src/main.ts`, - ]; - - tsConfig.compilerOptions.paths[`@secondScope/${lazylib}`] = - tsConfig.compilerOptions.paths[`@proj/${lazylib}`]; - delete tsConfig.compilerOptions.paths[`@proj/${lazylib}`]; - updateFile('tsconfig.base.json', JSON.stringify(tsConfig, null, 2)); - - updateFile( - `apps/${myapp}/src/main.ts`, - ` +describe('lint', () => { + it('lint should ensure module boundaries', () => { + const myapp = uniq('myapp'); + const myapp2 = uniq('myapp2'); + const mylib = uniq('mylib'); + const lazylib = uniq('lazylib'); + const invalidtaglib = uniq('invalidtaglib'); + const validtaglib = uniq('validtaglib'); + + runCLI(`generate @nrwl/angular:app ${myapp} --tags=validtag`); + runCLI(`generate @nrwl/angular:app ${myapp2}`); + runCLI(`generate @nrwl/angular:lib ${mylib}`); + runCLI(`generate @nrwl/angular:lib ${lazylib}`); + runCLI(`generate @nrwl/angular:lib ${invalidtaglib} --tags=invalidtag`); + runCLI(`generate @nrwl/angular:lib ${validtaglib} --tags=validtag`); + + const 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)); + + const tsConfig = readJson('tsconfig.base.json'); + + /** + * apps do not add themselves to the tsconfig file. + * + * Let's add it so that we can trigger the lint failure + */ + tsConfig.compilerOptions.paths[`@proj/${myapp2}`] = [ + `apps/${myapp2}/src/main.ts`, + ]; + + tsConfig.compilerOptions.paths[`@secondScope/${lazylib}`] = + tsConfig.compilerOptions.paths[`@proj/${lazylib}`]; + delete tsConfig.compilerOptions.paths[`@proj/${lazylib}`]; + updateFile('tsconfig.base.json', JSON.stringify(tsConfig, null, 2)); + + updateFile( + `apps/${myapp}/src/main.ts`, + ` import '../../../libs/${mylib}'; import '@secondScope/${lazylib}'; import '@proj/${myapp2}'; @@ -71,1081 +68,1065 @@ forEachCli((cli) => { const s = {loadChildren: '@proj/${lazylib}'}; ` + ); + + const out = runCLI(`lint ${myapp}`, { silenceError: true }); + expect(out).toContain( + 'libraries cannot be imported by a relative or absolute path, and must begin with a npm scope' + ); + expect(out).toContain('imports of lazy-loaded libraries are forbidden'); + expect(out).toContain('imports of apps are forbidden'); + expect(out).toContain( + 'A project tagged with "validtag" can only depend on libs tagged with "validtag"' + ); + }, 1000000); + + describe('nx workspace-lint', () => { + it('should identify issues with the workspace', () => { + const appBefore = uniq('before'); + const appAfter = uniq('after'); + + runCLI(`generate @nrwl/angular:app ${appBefore}`); + 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}'` ); - - const out = runCLI(`lint ${myapp}`, { silenceError: true }); - expect(out).toContain( - 'libraries cannot be imported by a relative or absolute path, and must begin with a npm scope' + expect(stdout).toContain( + 'The following file(s) do not belong to any projects:' ); - 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"' + expect(stdout).toContain(`- apps/${appAfter}/jest.config.js`); + expect(stdout).toContain(`- apps/${appAfter}/src/app/app.component.css`); + expect(stdout).toContain(`- apps/${appAfter}/src/app/app.component.html`); + expect(stdout).toContain( + `- apps/${appAfter}/src/app/app.component.spec.ts` ); - }, 1000000); - - describe('nx workspace-lint', () => { - it('should identify issues with the workspace', () => { - const appBefore = uniq('before'); - const appAfter = uniq('after'); - - runCLI(`generate @nrwl/angular:app ${appBefore}`); - 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}/jest.config.js`); - expect(stdout).toContain( - `- apps/${appAfter}/src/app/app.component.css` - ); - expect(stdout).toContain( - `- apps/${appAfter}/src/app/app.component.html` - ); - expect(stdout).toContain( - `- apps/${appAfter}/src/app/app.component.spec.ts` - ); - }); }); }); +}); - describe('format', () => { - it('format should check and reformat the code', () => { - const myapp = uniq('myapp'); - const mylib = uniq('mylib'); +describe('format', () => { + it('format should check and reformat the code', () => { + 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`, - ` + 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`, - ` + updateFile( + `apps/${myapp}/src/app/app.module.ts`, + ` const y = 1111; ` - ); + ); - updateFile( - `apps/${myapp}/src/app/app.component.ts`, - ` + updateFile( + `apps/${myapp}/src/app/app.component.ts`, + ` const z = 1111; ` - ); + ); - updateFile( - `libs/${mylib}/index.ts`, - ` + updateFile( + `libs/${mylib}/index.ts`, + ` const x = 1111; ` - ); - updateFile( - `libs/${mylib}/src/${mylib}.module.ts`, - ` + ); + updateFile( + `libs/${mylib}/src/${mylib}.module.ts`, + ` const y = 1111; ` - ); + ); - updateFile( - `README.md`, - ` + updateFile( + `README.md`, + ` my new readme; ` - ); - - let stdout = runCommand( - `npm run -s format:check -- --files="libs/${mylib}/index.ts,package.json" --libs-and-apps` - ); - expect(stdout).toContain(`libs/${mylib}/index.ts`); - expect(stdout).toContain(`libs/${mylib}/src/${mylib}.module.ts`); - expect(stdout).not.toContain(`README.md`); // It will be contained only in case of exception, that we fallback to all - - 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`); - - stdout = runCommand(`npm run -s format:check -- --projects=${myapp}`); - 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`); - expect(stdout).not.toContain(`libs/${mylib}/index.ts`); - expect(stdout).not.toContain(`libs/${mylib}/src/${mylib}.module.ts`); - expect(stdout).not.toContain(`README.md`); - - stdout = runCommand( - `npm run -s format:check -- --projects=${myapp},${mylib}` - ); - 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`); - expect(stdout).toContain(`libs/${mylib}/index.ts`); - expect(stdout).toContain(`libs/${mylib}/src/${mylib}.module.ts`); - expect(stdout).not.toContain(`README.md`); - - stdout = runCommand( - `npm run -s format:check -- --projects=${myapp},${mylib} --all` - ); - expect(stdout).toContain( - 'Arguments all and projects are mutually exclusive' - ); - - 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')).not.toContain( - `apps/${myapp}/src/main.ts` - ); - }); + ); + + let stdout = runCommand( + `npm run -s format:check -- --files="libs/${mylib}/index.ts,package.json" --libs-and-apps` + ); + expect(stdout).toContain(`libs/${mylib}/index.ts`); + expect(stdout).toContain(`libs/${mylib}/src/${mylib}.module.ts`); + expect(stdout).not.toContain(`README.md`); // It will be contained only in case of exception, that we fallback to all + + 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`); + + stdout = runCommand(`npm run -s format:check -- --projects=${myapp}`); + 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`); + expect(stdout).not.toContain(`libs/${mylib}/index.ts`); + expect(stdout).not.toContain(`libs/${mylib}/src/${mylib}.module.ts`); + expect(stdout).not.toContain(`README.md`); + + stdout = runCommand( + `npm run -s format:check -- --projects=${myapp},${mylib}` + ); + 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`); + expect(stdout).toContain(`libs/${mylib}/index.ts`); + expect(stdout).toContain(`libs/${mylib}/src/${mylib}.module.ts`); + expect(stdout).not.toContain(`README.md`); + + stdout = runCommand( + `npm run -s format:check -- --projects=${myapp},${mylib} --all` + ); + expect(stdout).toContain( + 'Arguments all and projects are mutually exclusive' + ); + + 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')).not.toContain( + `apps/${myapp}/src/main.ts` + ); }); +}); - describe('workspace-generator', () => { - let custom: string; - let failing: string; - - beforeEach(() => { - custom = uniq('custom'); - failing = uniq('custom-failing'); - runCLI(`g workspace-generator ${custom} --no-interactive`); - runCLI(`g workspace-generator ${failing} --no-interactive`); - - checkFilesExist( - `tools/generators/${custom}/index.ts`, - `tools/generators/${custom}/schema.json` - ); - checkFilesExist( - `tools/generators/${failing}/index.ts`, - `tools/generators/${failing}/schema.json` - ); - }); +describe('workspace-generator', () => { + let custom: string; + let failing: string; + + beforeEach(() => { + custom = uniq('custom'); + failing = uniq('custom-failing'); + runCLI(`g workspace-generator ${custom} --no-interactive`); + runCLI(`g workspace-generator ${failing} --no-interactive`); + + checkFilesExist( + `tools/generators/${custom}/index.ts`, + `tools/generators/${custom}/schema.json` + ); + checkFilesExist( + `tools/generators/${failing}/index.ts`, + `tools/generators/${failing}/schema.json` + ); + }); - it('should compile only generator files with dependencies', () => { - const workspace = uniq('workspace'); + it('should compile only generator files with dependencies', () => { + const workspace = uniq('workspace'); - updateFile( - 'tools/utils/utils.ts', - ` + updateFile( + 'tools/utils/utils.ts', + ` export const noop = () => {} ` - ); - updateFile( - 'tools/utils/logger.ts', - ` + ); + updateFile( + 'tools/utils/logger.ts', + ` export const log = (...args: any[]) => console.log(...args) ` - ); - updateFile( - `tools/generators/utils.ts`, - ` + ); + updateFile( + `tools/generators/utils.ts`, + ` export const noop = ()=>{} ` - ); - updateFile(`tools/generators/${custom}/index.ts`, (content) => { - return ` + ); + updateFile(`tools/generators/${custom}/index.ts`, (content) => { + return ` import { log } from '../../utils/logger'; \n ${content} `; - }); - - runCommand( - `nx workspace-generator ${custom} ${workspace} --no-interactive -d` - ); - - expect(() => - checkFilesExist( - `dist/out-tsc/tools/generators/${custom}/index.js`, - `dist/out-tsc/tools/generators/utils.js`, - `dist/out-tsc/tools/utils/logger.js` - ) - ).not.toThrow(); - expect(() => - checkFilesExist(`dist/out-tsc/tools/utils/utils.js`) - ).toThrow(); }); - it('should support workspace-specific generators', async () => { - const json = readJson(`tools/generators/${custom}/schema.json`); - json.properties['directory'] = { - type: 'string', - description: 'lib directory', - }; - json.properties['skipTsConfig'] = { - type: 'boolean', - description: 'skip changes to tsconfig', - }; - updateFile( - `tools/generators/${custom}/schema.json`, - JSON.stringify(json) - ); + runCommand( + `nx workspace-generator ${custom} ${workspace} --no-interactive -d` + ); - const indexFile = readFile(`tools/generators/${custom}/index.ts`); - updateFile( - `tools/generators/${custom}/index.ts`, - indexFile.replace( - 'name: schema.name', - 'name: schema.name, directory: schema.directory, skipTsConfig: schema.skipTsConfig' - ) - ); - - const workspace = uniq('workspace'); - const dryRunOutput = runCLI( - `workspace-generator ${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'); - - const output = runCLI( - `workspace-generator ${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 jsonFailing = readJson(`tools/generators/${failing}/schema.json`); - jsonFailing.properties = {}; - jsonFailing.required = []; - updateFile( - `tools/generators/${failing}/schema.json`, - JSON.stringify(jsonFailing) - ); + expect(() => + checkFilesExist( + `dist/out-tsc/tools/generators/${custom}/index.js`, + `dist/out-tsc/tools/generators/utils.js`, + `dist/out-tsc/tools/utils/logger.js` + ) + ).not.toThrow(); + expect(() => + checkFilesExist(`dist/out-tsc/tools/utils/utils.js`) + ).toThrow(); + }); - updateFile( - `tools/generators/${failing}/index.ts`, - ` + it('should support workspace-specific generators', async () => { + const json = readJson(`tools/generators/${custom}/schema.json`); + json.properties['directory'] = { + type: 'string', + description: 'lib directory', + }; + json.properties['skipTsConfig'] = { + type: 'boolean', + description: 'skip changes to tsconfig', + }; + updateFile(`tools/generators/${custom}/schema.json`, JSON.stringify(json)); + + const indexFile = readFile(`tools/generators/${custom}/index.ts`); + updateFile( + `tools/generators/${custom}/index.ts`, + indexFile.replace( + 'name: schema.name', + 'name: schema.name, directory: schema.directory, skipTsConfig: schema.skipTsConfig' + ) + ); + + const workspace = uniq('workspace'); + const dryRunOutput = runCLI( + `workspace-generator ${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'); + + const output = runCLI( + `workspace-generator ${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 jsonFailing = readJson(`tools/generators/${failing}/schema.json`); + jsonFailing.properties = {}; + jsonFailing.required = []; + updateFile( + `tools/generators/${failing}/schema.json`, + JSON.stringify(jsonFailing) + ); + + updateFile( + `tools/generators/${failing}/index.ts`, + ` export default function() { throw new Error(); } ` - ); + ); - try { - await runCLI(`workspace-generator ${failing} --no-interactive`); - fail(`Should exit 1 for a workspace-generator that throws an error`); - } catch (e) {} + try { + await runCLI(`workspace-generator ${failing} --no-interactive`); + fail(`Should exit 1 for a workspace-generator that throws an error`); + } catch (e) {} - const listOutput = runCLI('workspace-generator --list-generators'); - expect(listOutput).toContain(custom); - expect(listOutput).toContain(failing); - }, 1000000); - }); + const listOutput = runCLI('workspace-generator --list-generators'); + expect(listOutput).toContain(custom); + expect(listOutput).toContain(failing); + }, 1000000); +}); - describe('dep-graph', () => { - let myapp: string; - let myapp2: string; - let myapp3: string; - let myappE2e: string; - let myapp2E2e: string; - let myapp3E2e: string; - let mylib: string; - let mylib2: string; - beforeAll(() => { - myapp = uniq('myapp'); - myapp2 = uniq('myapp2'); - myapp3 = uniq('myapp3'); - myappE2e = myapp + '-e2e'; - myapp2E2e = myapp2 + '-e2e'; - myapp3E2e = myapp3 + '-e2e'; - mylib = uniq('mylib'); - mylib2 = uniq('mylib2'); - - runCLI(`generate @nrwl/angular:app ${myapp}`); - runCLI(`generate @nrwl/angular:app ${myapp2}`); - runCLI(`generate @nrwl/angular:app ${myapp3}`); - runCLI(`generate @nrwl/angular:lib ${mylib}`); - runCLI(`generate @nrwl/angular:lib ${mylib2}`); - - updateFile( - `apps/${myapp}/src/main.ts`, - ` +describe('dep-graph', () => { + let myapp: string; + let myapp2: string; + let myapp3: string; + let myappE2e: string; + let myapp2E2e: string; + let myapp3E2e: string; + let mylib: string; + let mylib2: string; + beforeAll(() => { + myapp = uniq('myapp'); + myapp2 = uniq('myapp2'); + myapp3 = uniq('myapp3'); + myappE2e = myapp + '-e2e'; + myapp2E2e = myapp2 + '-e2e'; + myapp3E2e = myapp3 + '-e2e'; + mylib = uniq('mylib'); + mylib2 = uniq('mylib2'); + + runCLI(`generate @nrwl/angular:app ${myapp}`); + runCLI(`generate @nrwl/angular:app ${myapp2}`); + runCLI(`generate @nrwl/angular:app ${myapp3}`); + runCLI(`generate @nrwl/angular:lib ${mylib}`); + runCLI(`generate @nrwl/angular:lib ${mylib2}`); + + updateFile( + `apps/${myapp}/src/main.ts`, + ` import '@proj/${mylib}'; const s = {loadChildren: '@proj/${mylib2}'}; ` - ); - - updateFile( - `apps/${myapp2}/src/app/app.component.spec.ts`, - `import '@proj/${mylib}';` - ); - - updateFile( - `libs/${mylib}/src/mylib.module.spec.ts`, - `import '@proj/${mylib2}';` - ); - }); - - it('dep-graph should output json to file', () => { - 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( - jasmine.objectContaining({ - [myapp3E2e]: [ - { - source: myapp3E2e, - target: myapp3, - type: 'implicit', - }, - ], - [myapp2]: [ - { - source: myapp2, - target: mylib, - type: 'static', - }, - ], - [myapp2E2e]: [ - { - source: myapp2E2e, - target: myapp2, - type: 'implicit', - }, - ], - [mylib]: [ - { - source: mylib, - target: mylib2, - type: 'static', - }, - ], - [mylib2]: [], - [myapp]: [ - { - source: myapp, - target: mylib, - type: 'static', - }, - { source: myapp, target: mylib2, type: 'dynamic' }, - ], - [myappE2e]: [ - { - source: myappE2e, - 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(); + updateFile( + `apps/${myapp2}/src/app/app.component.spec.ts`, + `import '@proj/${mylib}';` + ); - const jsonFileContents2 = readJson('project-graph.json'); + updateFile( + `libs/${mylib}/src/mylib.module.spec.ts`, + `import '@proj/${mylib2}';` + ); + }); - expect(jsonFileContents2.criticalPath).toContain(myapp); - expect(jsonFileContents2.criticalPath).toContain(myapp2); - expect(jsonFileContents2.criticalPath).toContain(mylib); - expect(jsonFileContents2.criticalPath).not.toContain(mylib2); - }, 1000000); + it('dep-graph should 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( + jasmine.objectContaining({ + [myapp3E2e]: [ + { + source: myapp3E2e, + target: myapp3, + type: 'implicit', + }, + ], + [myapp2]: [ + { + source: myapp2, + target: mylib, + type: 'static', + }, + ], + [myapp2E2e]: [ + { + source: myapp2E2e, + target: myapp2, + type: 'implicit', + }, + ], + [mylib]: [ + { + source: mylib, + target: mylib2, + type: 'static', + }, + ], + [mylib2]: [], + [myapp]: [ + { + source: myapp, + target: mylib, + type: 'static', + }, + { source: myapp, target: mylib2, type: 'dynamic' }, + ], + [myappE2e]: [ + { + source: myappE2e, + 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); + + it('dep-graph should focus requested project', () => { + runCommand( + `npm run dep-graph -- --focus=${myapp} --file=project-graph.json` + ); + + expect(() => checkFilesExist('project-graph.json')).not.toThrow(); + + const jsonFileContents = readJson('project-graph.json'); + const projectNames = Object.keys(jsonFileContents.graph.nodes); + + expect(projectNames).toContain(myapp); + expect(projectNames).toContain(mylib); + expect(projectNames).toContain(mylib2); + expect(projectNames).toContain(myappE2e); + + expect(projectNames).not.toContain(myapp2); + expect(projectNames).not.toContain(myapp3); + expect(projectNames).not.toContain(myapp2E2e); + expect(projectNames).not.toContain(myapp3E2e); + }, 1000000); + + it('dep-graph should exclude requested projects', () => { + runCommand( + `npm run dep-graph -- --exclude=${myappE2e},${myapp2E2e},${myapp3E2e} --file=project-graph.json` + ); + + expect(() => checkFilesExist('project-graph.json')).not.toThrow(); + + const jsonFileContents = readJson('project-graph.json'); + const projectNames = Object.keys(jsonFileContents.graph.nodes); + + expect(projectNames).toContain(myapp); + expect(projectNames).toContain(mylib); + expect(projectNames).toContain(mylib2); + expect(projectNames).toContain(myapp2); + expect(projectNames).toContain(myapp3); + + expect(projectNames).not.toContain(myappE2e); + expect(projectNames).not.toContain(myapp2E2e); + expect(projectNames).not.toContain(myapp3E2e); + }, 1000000); + + it('dep-graph should exclude requested projects that were included by a focus', () => { + runCommand( + `npm run dep-graph -- --focus=${myapp} --exclude=${myappE2e} --file=project-graph.json` + ); + + expect(() => checkFilesExist('project-graph.json')).not.toThrow(); + + const jsonFileContents = readJson('project-graph.json'); + const projectNames = Object.keys(jsonFileContents.graph.nodes); + + expect(projectNames).toContain(myapp); + expect(projectNames).toContain(mylib); + expect(projectNames).toContain(mylib2); + + expect(projectNames).not.toContain(myappE2e); + expect(projectNames).not.toContain(myapp2); + expect(projectNames).not.toContain(myapp3); + expect(projectNames).not.toContain(myapp2E2e); + expect(projectNames).not.toContain(myapp3E2e); + }, 1000000); + + it('dep-graph should output a deployable static website in an html file accompanied by a folder with static assets', () => { + runCommand(`npm run dep-graph -- --file=project-graph.html`); + + expect(() => checkFilesExist('project-graph.html')).not.toThrow(); + expect(() => checkFilesExist('static/styles.css')).not.toThrow(); + expect(() => checkFilesExist('static/runtime.js')).not.toThrow(); + expect(() => checkFilesExist('static/polyfills.esm.js')).not.toThrow(); + expect(() => checkFilesExist('static/main.esm.js')).not.toThrow(); + }); +}); - it('dep-graph should focus requested project', () => { - runCommand( - `npm run dep-graph -- --focus=${myapp} --file=project-graph.json` - ); +describe('Move Angular Project', () => { + let app1: string; + let app2: string; + let newPath: string; - expect(() => checkFilesExist('project-graph.json')).not.toThrow(); + beforeEach(() => { + app1 = uniq('app1'); + app2 = uniq('app2'); + newPath = `subfolder/${app2}`; + runCLI(`generate @nrwl/angular:app ${app1}`); + }); - const jsonFileContents = readJson('project-graph.json'); - const projectNames = Object.keys(jsonFileContents.graph.nodes); + /** + * Tries moving an app from ${app1} -> subfolder/${app2} + */ + it('should work for apps', () => { + const moveOutput = runCLI( + `generate @nrwl/angular:move --project ${app1} ${newPath}` + ); + + // just check the output + expect(moveOutput).toContain(`DELETE apps/${app1}`); + expect(moveOutput).toContain(`CREATE apps/${newPath}/.browserslistrc`); + expect(moveOutput).toContain(`CREATE apps/${newPath}/jest.config.js`); + expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.app.json`); + expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.json`); + expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.spec.json`); + expect(moveOutput).toContain(`CREATE apps/${newPath}/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`); + }); - expect(projectNames).toContain(myapp); - expect(projectNames).toContain(mylib); - expect(projectNames).toContain(mylib2); - expect(projectNames).toContain(myappE2e); + /** + * 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` + ); + }); - expect(projectNames).not.toContain(myapp2); - expect(projectNames).not.toContain(myapp3); - expect(projectNames).not.toContain(myapp2E2e); - expect(projectNames).not.toContain(myapp3E2e); - }, 1000000); + /** + * Tries moving a library from ${lib} -> shared/${lib} + */ + it('should work for libraries', () => { + const lib1 = uniq('mylib'); + const lib2 = uniq('mylib'); + runCLI(`generate @nrwl/angular:lib ${lib1}`); - it('dep-graph should exclude requested projects', () => { - runCommand( - `npm run dep-graph -- --exclude=${myappE2e},${myapp2E2e},${myapp3E2e} --file=project-graph.json` - ); + /** + * Create a library which imports the module from the other lib + */ - expect(() => checkFilesExist('project-graph.json')).not.toThrow(); + runCLI(`generate @nrwl/angular:lib ${lib2}`); - const jsonFileContents = readJson('project-graph.json'); - const projectNames = Object.keys(jsonFileContents.graph.nodes); + updateFile( + `libs/${lib2}/src/lib/${lib2}.module.ts`, + `import { ${classify(lib1)}Module } from '@proj/${lib1}'; - expect(projectNames).toContain(myapp); - expect(projectNames).toContain(mylib); - expect(projectNames).toContain(mylib2); - expect(projectNames).toContain(myapp2); - expect(projectNames).toContain(myapp3); + export class ExtendedModule extends ${classify(lib1)}Module { }` + ); - expect(projectNames).not.toContain(myappE2e); - expect(projectNames).not.toContain(myapp2E2e); - expect(projectNames).not.toContain(myapp3E2e); - }, 1000000); + const moveOutput = runCLI( + `generate @nrwl/angular:move --projectName=${lib1} --destination=shared/${lib1}` + ); - it('dep-graph should exclude requested projects that were included by a focus', () => { - runCommand( - `npm run dep-graph -- --focus=${myapp} --exclude=${myappE2e} --file=project-graph.json` - ); + const newPath = `libs/shared/${lib1}`; + const newModule = `Shared${classify(lib1)}Module`; - expect(() => checkFilesExist('project-graph.json')).not.toThrow(); + const testSetupPath = `${newPath}/src/test-setup.ts`; + expect(moveOutput).toContain(`CREATE ${testSetupPath}`); + checkFilesExist(testSetupPath); - const jsonFileContents = readJson('project-graph.json'); - const projectNames = Object.keys(jsonFileContents.graph.nodes); + 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}`); - expect(projectNames).toContain(myapp); - expect(projectNames).toContain(mylib); - expect(projectNames).toContain(mylib2); + 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'`); - expect(projectNames).not.toContain(myappE2e); - expect(projectNames).not.toContain(myapp2); - expect(projectNames).not.toContain(myapp3); - expect(projectNames).not.toContain(myapp2E2e); - expect(projectNames).not.toContain(myapp3E2e); - }, 1000000); + /** + * 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}`); + }); +}); - it('dep-graph should output a deployable static website in an html file accompanied by a folder with static assets', () => { - runCommand(`npm run dep-graph -- --file=project-graph.html`); +describe('Move Project', () => { + /** + * 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'); + const lib3 = uniq('mylib'); + 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'` + ); - expect(() => checkFilesExist('project-graph.html')).not.toThrow(); - expect(() => checkFilesExist('static/styles.css')).not.toThrow(); - expect(() => checkFilesExist('static/runtime.js')).not.toThrow(); - expect(() => checkFilesExist('static/polyfills.esm.js')).not.toThrow(); - expect(() => checkFilesExist('static/main.esm.js')).not.toThrow(); - }); - }); + /** + * Create a library which imports a class from lib1 + */ - describe('Move Angular Project', () => { - const workspace = cli === 'angular' ? 'angular' : 'workspace'; + runCLI(`generate @nrwl/workspace:lib ${lib2}/ui`); - let app1: string; - let app2: string; - let newPath: string; + updateFile( + `libs/${lib2}/ui/src/lib/${lib2}-ui.ts`, + `import { fromLibOne } from '@proj/${lib1}/data-access'; - beforeEach(() => { - app1 = uniq('app1'); - app2 = uniq('app2'); - newPath = `subfolder/${app2}`; - runCLI(`generate @nrwl/angular:app ${app1}`); - }); + export const fromLibTwo = () => fromLibOne();` + ); /** - * Tries moving an app from ${app1} -> subfolder/${app2} + * Create a library which has an implicit dependency on lib1 */ - it('should work for apps', () => { - const moveOutput = runCLI( - `generate @nrwl/angular:move --project ${app1} ${newPath}` - ); - // just check the output - expect(moveOutput).toContain(`DELETE apps/${app1}`); - expect(moveOutput).toContain(`CREATE apps/${newPath}/.browserslistrc`); - expect(moveOutput).toContain(`CREATE apps/${newPath}/jest.config.js`); - expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.app.json`); - expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.json`); - expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.spec.json`); - expect(moveOutput).toContain(`CREATE apps/${newPath}/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`); - }); + runCLI(`generate @nrwl/workspace:lib ${lib3}`); + let nxJson = JSON.parse(readFile('nx.json')) as NxJson; + nxJson.projects[lib3].implicitDependencies = [`${lib1}-data-access`]; + updateFile(`nx.json`, JSON.stringify(nxJson)); /** - * Tries moving an e2e project from ${app1} -> ${newPath} + * Now try to move lib1 */ - 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` - ); + 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(`displayName: 'shared-${lib1}-data-access'`); + expect(jestConfig).toContain(`preset: '../../../../jest.preset.js'`); + expect(jestConfig).toContain( + `coverageDirectory: '../../../../coverage/${newPath}'` + ); + + const tsConfigPath = `${newPath}/tsconfig.json`; + expect(moveOutput).toContain(`CREATE ${tsConfigPath}`); + checkFilesExist(tsConfigPath); + + 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'); + nxJson = JSON.parse(readFile('nx.json')) as NxJson; + expect(nxJson.projects[`${lib1}-data-access`]).toBeUndefined(); + expect(nxJson.projects[newName]).toEqual({ + tags: [], }); + expect(nxJson.projects[lib3].implicitDependencies).toEqual([ + `shared-${lib1}-data-access`, + ]); + + expect(moveOutput).toContain('UPDATE tsconfig.base.json'); + const rootTsConfig = readJson('tsconfig.base.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.lintFilePatterns).toEqual([ + `libs/shared/${lib1}/data-access/**/*.ts`, + ]); /** - * Tries moving a library from ${lib} -> shared/${lib} + * Check that the import in lib2 has been updated */ - it('should work for libraries', () => { - const lib1 = uniq('mylib'); - const lib2 = uniq('mylib'); - runCLI(`generate @nrwl/angular:lib ${lib1}`); - - /** - * Create a library which imports the module from the other lib - */ - - runCLI(`generate @nrwl/angular:lib ${lib2}`); - - updateFile( - `libs/${lib2}/src/lib/${lib2}.module.ts`, - `import { ${classify(lib1)}Module } from '@proj/${lib1}'; - - export class ExtendedModule extends ${classify(lib1)}Module { }` - ); - - const moveOutput = runCLI( - `generate @nrwl/angular:move --projectName=${lib1} --destination=shared/${lib1}` - ); - - const newPath = `libs/shared/${lib1}`; - const newModule = `Shared${classify(lib1)}Module`; - - const testSetupPath = `${newPath}/src/test-setup.ts`; - expect(moveOutput).toContain(`CREATE ${testSetupPath}`); - checkFilesExist(testSetupPath); - - const modulePath = `${newPath}/src/lib/shared-${lib1}.module.ts`; - expect(moveOutput).toContain(`CREATE ${modulePath}`); - checkFilesExist(modulePath); - const moduleFile = readFile(modulePath); - expect(moduleFile).toContain(`export class ${newModule}`); - - const indexPath = `${newPath}/src/index.ts`; - expect(moveOutput).toContain(`CREATE ${indexPath}`); - checkFilesExist(indexPath); - const index = readFile(indexPath); - expect(index).toContain(`export * from './lib/shared-${lib1}.module'`); - - /** - * Check that the import in lib2 has been updated - */ - const lib2FilePath = `libs/${lib2}/src/lib/${lib2}.module.ts`; - const lib2File = readFile(lib2FilePath); - expect(lib2File).toContain( - `import { ${newModule} } from '@proj/shared/${lib1}';` - ); - expect(lib2File).toContain(`extends ${newModule}`); - }); + 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';` + ); }); - describe('Move Project', () => { - const workspace = cli === 'angular' ? 'angular' : 'workspace'; + it('should work for libs created with --importPath', () => { + const importPath = '@wibble/fish'; + const lib1 = uniq('mylib'); + const lib2 = uniq('mylib'); + const lib3 = uniq('mylib'); + runCLI( + `generate @nrwl/workspace:lib ${lib1}/data-access --importPath=${importPath}` + ); + + 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'` + ); /** - * Tries moving a library from ${lib}/data-access -> shared/${lib}/data-access + * Create a library which imports a class from lib1 */ - it('should work for libraries', () => { - const lib1 = uniq('mylib'); - const lib2 = uniq('mylib'); - const lib3 = uniq('mylib'); - 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 lib1 - */ - - runCLI(`generate @nrwl/workspace:lib ${lib2}/ui`); + runCLI(`generate @nrwl/workspace:lib ${lib2}/ui`); - updateFile( - `libs/${lib2}/ui/src/lib/${lib2}-ui.ts`, - `import { fromLibOne } from '@proj/${lib1}/data-access'; + updateFile( + `libs/${lib2}/ui/src/lib/${lib2}-ui.ts`, + `import { fromLibOne } from '${importPath}'; export const fromLibTwo = () => fromLibOne();` - ); - - /** - * Create a library which has an implicit dependency on lib1 - */ - - runCLI(`generate @nrwl/workspace:lib ${lib3}`); - let nxJson = JSON.parse(readFile('nx.json')) as NxJson; - nxJson.projects[lib3].implicitDependencies = [`${lib1}-data-access`]; - updateFile(`nx.json`, JSON.stringify(nxJson)); + ); - /** - * Now try to move lib1 - */ - - 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(`displayName: 'shared-${lib1}-data-access'`); - expect(jestConfig).toContain(`preset: '../../../../jest.preset.js'`); - expect(jestConfig).toContain( - `coverageDirectory: '../../../../coverage/${newPath}'` - ); - - const tsConfigPath = `${newPath}/tsconfig.json`; - expect(moveOutput).toContain(`CREATE ${tsConfigPath}`); - checkFilesExist(tsConfigPath); + /** + * Create a library which has an implicit dependency on lib1 + */ - 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' - ); + runCLI(`generate @nrwl/workspace:lib ${lib3}`); + let nxJson = JSON.parse(readFile('nx.json')) as NxJson; + nxJson.projects[lib3].implicitDependencies = [`${lib1}-data-access`]; + updateFile(`nx.json`, JSON.stringify(nxJson)); - 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' - ); + /** + * Now try to move lib1 + */ - 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'); - nxJson = JSON.parse(readFile('nx.json')) as NxJson; - expect(nxJson.projects[`${lib1}-data-access`]).toBeUndefined(); - expect(nxJson.projects[newName]).toEqual({ - tags: [], - }); - expect(nxJson.projects[lib3].implicitDependencies).toEqual([ - `shared-${lib1}-data-access`, - ]); - - expect(moveOutput).toContain('UPDATE tsconfig.base.json'); - const rootTsConfig = readJson('tsconfig.base.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.lintFilePatterns).toEqual([ - `libs/shared/${lib1}/data-access/**/*.ts`, - ]); - - /** - * 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';` - ); + 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(`displayName: 'shared-${lib1}-data-access'`); + expect(jestConfig).toContain(`preset: '../../../../jest.preset.js'`); + expect(jestConfig).toContain( + `coverageDirectory: '../../../../coverage/${newPath}'` + ); + + const tsConfigPath = `${newPath}/tsconfig.json`; + expect(moveOutput).toContain(`CREATE ${tsConfigPath}`); + checkFilesExist(tsConfigPath); + + 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'); + nxJson = JSON.parse(readFile('nx.json')) as NxJson; + expect(nxJson.projects[`${lib1}-data-access`]).toBeUndefined(); + expect(nxJson.projects[newName]).toEqual({ + tags: [], }); + expect(nxJson.projects[lib3].implicitDependencies).toEqual([ + `shared-${lib1}-data-access`, + ]); + + expect(moveOutput).toContain('UPDATE tsconfig.base.json'); + const rootTsConfig = readJson('tsconfig.base.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.lintFilePatterns).toEqual([ + `libs/shared/${lib1}/data-access/**/*.ts`, + ]); - it('should work for libs created with --importPath', () => { - const importPath = '@wibble/fish'; - const lib1 = uniq('mylib'); - const lib2 = uniq('mylib'); - const lib3 = uniq('mylib'); - runCLI( - `generate @nrwl/workspace:lib ${lib1}/data-access --importPath=${importPath}` - ); - - 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 lib1 - */ - - runCLI(`generate @nrwl/workspace:lib ${lib2}/ui`); - - updateFile( - `libs/${lib2}/ui/src/lib/${lib2}-ui.ts`, - `import { fromLibOne } from '${importPath}'; - - export const fromLibTwo = () => fromLibOne();` - ); - - /** - * Create a library which has an implicit dependency on lib1 - */ - - runCLI(`generate @nrwl/workspace:lib ${lib3}`); - let nxJson = JSON.parse(readFile('nx.json')) as NxJson; - nxJson.projects[lib3].implicitDependencies = [`${lib1}-data-access`]; - updateFile(`nx.json`, JSON.stringify(nxJson)); - - /** - * Now try to move lib1 - */ - - 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(`displayName: 'shared-${lib1}-data-access'`); - expect(jestConfig).toContain(`preset: '../../../../jest.preset.js'`); - expect(jestConfig).toContain( - `coverageDirectory: '../../../../coverage/${newPath}'` - ); - - const tsConfigPath = `${newPath}/tsconfig.json`; - expect(moveOutput).toContain(`CREATE ${tsConfigPath}`); - checkFilesExist(tsConfigPath); - - 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'); - nxJson = JSON.parse(readFile('nx.json')) as NxJson; - expect(nxJson.projects[`${lib1}-data-access`]).toBeUndefined(); - expect(nxJson.projects[newName]).toEqual({ - tags: [], - }); - expect(nxJson.projects[lib3].implicitDependencies).toEqual([ - `shared-${lib1}-data-access`, - ]); - - expect(moveOutput).toContain('UPDATE tsconfig.base.json'); - const rootTsConfig = readJson('tsconfig.base.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.lintFilePatterns).toEqual([ - `libs/shared/${lib1}/data-access/**/*.ts`, - ]); - - /** - * 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';` - ); - }); + /** + * 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';` + ); + }); - it('should work for custom workspace layouts', () => { - const lib1 = uniq('mylib'); - const lib2 = uniq('mylib'); - const lib3 = uniq('mylib'); + it('should work for custom workspace layouts', () => { + const lib1 = uniq('mylib'); + const lib2 = uniq('mylib'); + const lib3 = uniq('mylib'); - let nxJson = readJson('nx.json'); - nxJson.workspaceLayout = { libsDir: 'packages' }; - updateFile('nx.json', JSON.stringify(nxJson)); + let nxJson = readJson('nx.json'); + nxJson.workspaceLayout = { libsDir: 'packages' }; + updateFile('nx.json', JSON.stringify(nxJson)); - runCLI(`generate @nrwl/workspace:lib ${lib1}/data-access`); + runCLI(`generate @nrwl/workspace:lib ${lib1}/data-access`); - updateFile( - `packages/${lib1}/data-access/src/lib/${lib1}-data-access.ts`, - `export function fromLibOne() { console.log('This is completely pointless'); }` - ); + updateFile( + `packages/${lib1}/data-access/src/lib/${lib1}-data-access.ts`, + `export function fromLibOne() { console.log('This is completely pointless'); }` + ); - updateFile( - `packages/${lib1}/data-access/src/index.ts`, - `export * from './lib/${lib1}-data-access.ts'` - ); + updateFile( + `packages/${lib1}/data-access/src/index.ts`, + `export * from './lib/${lib1}-data-access.ts'` + ); - /** - * Create a library which imports a class from lib1 - */ + /** + * Create a library which imports a class from lib1 + */ - runCLI(`generate @nrwl/workspace:lib ${lib2}/ui`); + runCLI(`generate @nrwl/workspace:lib ${lib2}/ui`); - updateFile( - `packages/${lib2}/ui/src/lib/${lib2}-ui.ts`, - `import { fromLibOne } from '@proj/${lib1}/data-access'; + updateFile( + `packages/${lib2}/ui/src/lib/${lib2}-ui.ts`, + `import { fromLibOne } from '@proj/${lib1}/data-access'; export const fromLibTwo = () => fromLibOne();` - ); + ); - /** - * Create a library which has an implicit dependency on lib1 - */ - - runCLI(`generate @nrwl/workspace:lib ${lib3}`); - nxJson = JSON.parse(readFile('nx.json')) as NxJson; - nxJson.projects[lib3].implicitDependencies = [`${lib1}-data-access`]; - updateFile(`nx.json`, JSON.stringify(nxJson)); + /** + * Create a library which has an implicit dependency on lib1 + */ - /** - * Now try to move lib1 - */ + runCLI(`generate @nrwl/workspace:lib ${lib3}`); + nxJson = JSON.parse(readFile('nx.json')) as NxJson; + nxJson.projects[lib3].implicitDependencies = [`${lib1}-data-access`]; + updateFile(`nx.json`, JSON.stringify(nxJson)); - const moveOutput = runCLI( - `generate @nrwl/workspace:move --project ${lib1}-data-access shared/${lib1}/data-access` - ); - - expect(moveOutput).toContain(`DELETE packages/${lib1}/data-access`); - expect(exists(`packages/${lib1}/data-access`)).toBeFalsy(); + /** + * Now try to move lib1 + */ - const newPath = `packages/shared/${lib1}/data-access`; - const newName = `shared-${lib1}-data-access`; + const moveOutput = runCLI( + `generate @nrwl/workspace:move --project ${lib1}-data-access shared/${lib1}/data-access` + ); + + expect(moveOutput).toContain(`DELETE packages/${lib1}/data-access`); + expect(exists(`packages/${lib1}/data-access`)).toBeFalsy(); + + const newPath = `packages/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(`displayName: 'shared-${lib1}-data-access'`); + expect(jestConfig).toContain(`preset: '../../../../jest.preset.js'`); + expect(jestConfig).toContain( + `coverageDirectory: '../../../../coverage/${newPath}'` + ); + + const tsConfigPath = `${newPath}/tsconfig.json`; + expect(moveOutput).toContain(`CREATE ${tsConfigPath}`); + checkFilesExist(tsConfigPath); + + 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'); + nxJson = JSON.parse(readFile('nx.json')) as NxJson; + expect(nxJson.projects[`${lib1}-data-access`]).toBeUndefined(); + expect(nxJson.projects[newName]).toEqual({ + tags: [], + }); + expect(nxJson.projects[lib3].implicitDependencies).toEqual([ + `shared-${lib1}-data-access`, + ]); + + expect(moveOutput).toContain('UPDATE tsconfig.base.json'); + const rootTsConfig = readJson('tsconfig.base.json'); + expect( + rootTsConfig.compilerOptions.paths[`@proj/${lib1}/data-access`] + ).toBeUndefined(); + expect( + rootTsConfig.compilerOptions.paths[`@proj/shared/${lib1}/data-access`] + ).toEqual([`packages/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.lintFilePatterns).toEqual([ + `packages/shared/${lib1}/data-access/**/*.ts`, + ]); - const readmePath = `${newPath}/README.md`; - expect(moveOutput).toContain(`CREATE ${readmePath}`); - checkFilesExist(readmePath); + /** + * Check that the import in lib2 has been updated + */ + const lib2FilePath = `packages/${lib2}/ui/src/lib/${lib2}-ui.ts`; + const lib2File = readFile(lib2FilePath); + expect(lib2File).toContain( + `import { fromLibOne } from '@proj/shared/${lib1}/data-access';` + ); + + nxJson = readJson('nx.json'); + delete nxJson.workspaceLayout; + updateFile('nx.json', JSON.stringify(nxJson)); + }); +}); - const jestConfigPath = `${newPath}/jest.config.js`; - expect(moveOutput).toContain(`CREATE ${jestConfigPath}`); - checkFilesExist(jestConfigPath); - const jestConfig = readFile(jestConfigPath); - expect(jestConfig).toContain(`displayName: 'shared-${lib1}-data-access'`); - expect(jestConfig).toContain(`preset: '../../../../jest.preset.js'`); - expect(jestConfig).toContain( - `coverageDirectory: '../../../../coverage/${newPath}'` - ); +describe('Remove Project', () => { + /** + * Tries creating then deleting a lib + */ + it('should work', () => { + const lib1 = uniq('mylib'); + const lib2 = uniq('mylib'); - const tsConfigPath = `${newPath}/tsconfig.json`; - expect(moveOutput).toContain(`CREATE ${tsConfigPath}`); - checkFilesExist(tsConfigPath); + runCLI(`generate @nrwl/workspace:lib ${lib1}`); + expect(exists(tmpProjPath(`libs/${lib1}`))).toBeTruthy(); - 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' - ); + /** + * Create a library which has an implicit dependency on lib1 + */ - 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' - ); + runCLI(`generate @nrwl/workspace:lib ${lib2}`); + let nxJson = JSON.parse(readFile('nx.json')) as NxJson; + nxJson.projects[lib2].implicitDependencies = [lib1]; + updateFile(`nx.json`, JSON.stringify(nxJson)); - 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'); - nxJson = JSON.parse(readFile('nx.json')) as NxJson; - expect(nxJson.projects[`${lib1}-data-access`]).toBeUndefined(); - expect(nxJson.projects[newName]).toEqual({ - tags: [], - }); - expect(nxJson.projects[lib3].implicitDependencies).toEqual([ - `shared-${lib1}-data-access`, - ]); - - expect(moveOutput).toContain('UPDATE tsconfig.base.json'); - const rootTsConfig = readJson('tsconfig.base.json'); - expect( - rootTsConfig.compilerOptions.paths[`@proj/${lib1}/data-access`] - ).toBeUndefined(); - expect( - rootTsConfig.compilerOptions.paths[`@proj/shared/${lib1}/data-access`] - ).toEqual([`packages/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.lintFilePatterns).toEqual([ - `packages/shared/${lib1}/data-access/**/*.ts`, - ]); - - /** - * Check that the import in lib2 has been updated - */ - const lib2FilePath = `packages/${lib2}/ui/src/lib/${lib2}-ui.ts`; - const lib2File = readFile(lib2FilePath); - expect(lib2File).toContain( - `import { fromLibOne } from '@proj/shared/${lib1}/data-access';` - ); + /** + * Try removing the project (should fail) + */ - nxJson = readJson('nx.json'); - delete nxJson.workspaceLayout; - updateFile('nx.json', JSON.stringify(nxJson)); - }); - }); + let error; + try { + runCLI(`generate @nrwl/workspace:remove --project ${lib1}`); + } catch (e) { + error = e; + } - describe('Remove Project', () => { - const workspace = cli === 'angular' ? 'angular' : 'workspace'; + expect(error).toBeDefined(); + expect(error.stderr.toString()).toContain( + `${lib1} is still depended on by the following projects:\n${lib2}` + ); /** - * Tries creating then deleting a lib + * Try force removing the project */ - it('should work', () => { - const lib1 = uniq('mylib'); - const lib2 = uniq('mylib'); - - runCLI(`generate @nrwl/workspace:lib ${lib1}`); - expect(exists(tmpProjPath(`libs/${lib1}`))).toBeTruthy(); - - /** - * Create a library which has an implicit dependency on lib1 - */ - - runCLI(`generate @nrwl/workspace:lib ${lib2}`); - let nxJson = JSON.parse(readFile('nx.json')) as NxJson; - nxJson.projects[lib2].implicitDependencies = [lib1]; - updateFile(`nx.json`, JSON.stringify(nxJson)); - - /** - * Try removing the project (should fail) - */ - - let error; - try { - runCLI(`generate @nrwl/workspace:remove --project ${lib1}`); - } catch (e) { - error = e; - } - - expect(error).toBeDefined(); - expect(error.stderr.toString()).toContain( - `${lib1} is still depended on by the following projects:\n${lib2}` - ); - /** - * Try force removing the project - */ + const removeOutputForced = runCLI( + `generate @nrwl/workspace:remove --project ${lib1} --forceRemove` + ); - const removeOutputForced = runCLI( - `generate @nrwl/workspace:remove --project ${lib1} --forceRemove` - ); - - expect(removeOutputForced).toContain(`DELETE libs/${lib1}`); - expect(exists(tmpProjPath(`libs/${lib1}`))).toBeFalsy(); + expect(removeOutputForced).toContain(`DELETE libs/${lib1}`); + expect(exists(tmpProjPath(`libs/${lib1}`))).toBeFalsy(); - expect(removeOutputForced).toContain(`UPDATE nx.json`); - nxJson = JSON.parse(readFile('nx.json')) as NxJson; - expect(nxJson.projects[`${lib1}`]).toBeUndefined(); - expect(nxJson.projects[lib2].implicitDependencies).toEqual([]); + expect(removeOutputForced).toContain(`UPDATE nx.json`); + nxJson = JSON.parse(readFile('nx.json')) as NxJson; + expect(nxJson.projects[`${lib1}`]).toBeUndefined(); + expect(nxJson.projects[lib2].implicitDependencies).toEqual([]); - expect(removeOutputForced).toContain(`UPDATE ${workspace}.json`); - const workspaceJson = readJson(`${workspace}.json`); - expect(workspaceJson.projects[`${lib1}`]).toBeUndefined(); - }); + expect(removeOutputForced).toContain(`UPDATE workspace.json`); + const workspaceJson = readJson(`workspace.json`); + expect(workspaceJson.projects[`${lib1}`]).toBeUndefined(); }); }); diff --git a/e2e/workspace/src/workspace.test.ts b/e2e/workspace/src/workspace.test.ts index 625e46ccf867a..c28f9e38bc573 100644 --- a/e2e/workspace/src/workspace.test.ts +++ b/e2e/workspace/src/workspace.test.ts @@ -1,6 +1,5 @@ import { NxJson } from '@nrwl/workspace'; import { - forEachCli, listFiles, newProject, readFile, @@ -15,79 +14,74 @@ import { 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; - }); +/** + * 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', () => { - 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} --buildable`); - runCLI(`generate @nrwl/react:lib ${mylib2} --buildable`); - - updateFile( - `apps/${myapp}/src/main.ts`, - ` +describe('run-one', () => { + it('should build specific project', () => { + 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} --buildable`); + runCLI(`generate @nrwl/react:lib ${mylib2} --buildable`); + + 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 project ${myapp} and its 2 deps` - ); - expect(testsWithDeps).toContain(myapp); - expect(testsWithDeps).toContain(mylib1); - expect(testsWithDeps).toContain(mylib2); - - const testsWithoutDeps = runCLI(`test ${myapp}`); - expect(testsWithoutDeps).not.toContain(mylib1); - }, 1000000); - }); + ); + + 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 project ${myapp} and its 2 deps` + ); + 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} --buildable --defaults`); - runCLI(`generate @nrwl/angular:lib ${libB} --buildable --defaults`); - runCLI(`generate @nrwl/angular:lib ${libC} --buildable --defaults`); - runCLI(`generate @nrwl/angular:lib ${libD} --defaults`); - - // libA depends on libC - updateFile( - `libs/${libA}/src/lib/${libA}.module.spec.ts`, - ` +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} --buildable --defaults`); + runCLI(`generate @nrwl/angular:lib ${libB} --buildable --defaults`); + runCLI(`generate @nrwl/angular:lib ${libC} --buildable --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', () => { @@ -95,123 +89,121 @@ forEachCli((cliName) => { }); }); ` - ); - - // 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); - - it('should run only failed projects', () => { - newProject(); - const myapp = uniq('myapp'); - const myapp2 = uniq('myapp2'); - runCLI(`generate @nrwl/angular:app ${myapp}`); - runCLI(`generate @nrwl/angular:app ${myapp2}`); - - // set broken test for myapp - updateFile( - `apps/${myapp}/src/app/app.component.spec.ts`, - ` + ); + + // 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); + + it('should run only failed projects', () => { + newProject(); + const myapp = uniq('myapp'); + const myapp2 = uniq('myapp2'); + runCLI(`generate @nrwl/angular:app ${myapp}`); + runCLI(`generate @nrwl/angular:app ${myapp2}`); + + // set broken test for myapp + updateFile( + `apps/${myapp}/src/app/app.component.spec.ts`, + ` describe('sample test', () => { it('should test', () => { expect(1).toEqual(2); }); }); ` - ); - - const failedTests = runCLI(`run-many --target=test --all`, { - silenceError: true, - }); - expect(failedTests).toContain(`Running target test for projects:`); - expect(failedTests).toContain(`- ${myapp}`); - expect(failedTests).toContain(`- ${myapp2}`); - expect(failedTests).toContain(`Failed projects:`); - expect(readJson('node_modules/.cache/nx/results.json')).toEqual({ - command: 'test', - results: { - [myapp]: false, - [myapp2]: 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 = runCLI( - `run-many --target=test --all --only-failed` - ); - expect(isolatedTests).toContain(`Running target test for projects`); - expect(isolatedTests).toContain(`- ${myapp}`); - expect(isolatedTests).not.toContain(`- ${myapp2}`); - - const interpolatedTests = runCLI(`run-many --target=test --all`); - expect(interpolatedTests).toContain(`Running target \"test\" succeeded`); - }, 1000000); - }); + ); - describe('affected:*', () => { - it('should print, build, and test affected apps', () => { - newProject(); - 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 --importPath=@proj/${mypublishablelib}` - ); - - updateFile( - `apps/${myapp}/src/app/app.component.spec.ts`, - ` + const failedTests = runCLI(`run-many --target=test --all`, { + silenceError: true, + }); + expect(failedTests).toContain(`Running target test for projects:`); + expect(failedTests).toContain(`- ${myapp}`); + expect(failedTests).toContain(`- ${myapp2}`); + expect(failedTests).toContain(`Failed projects:`); + expect(readJson('node_modules/.cache/nx/results.json')).toEqual({ + command: 'test', + results: { + [myapp]: false, + [myapp2]: 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 = runCLI(`run-many --target=test --all --only-failed`); + expect(isolatedTests).toContain(`Running target test for projects`); + expect(isolatedTests).toContain(`- ${myapp}`); + expect(isolatedTests).not.toContain(`- ${myapp2}`); + + const interpolatedTests = runCLI(`run-many --target=test --all`); + expect(interpolatedTests).toContain(`Running target \"test\" succeeded`); + }, 1000000); +}); + +describe('affected:*', () => { + it('should print, build, and test affected apps', () => { + newProject(); + 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 --importPath=@proj/${mypublishablelib}` + ); + + updateFile( + `apps/${myapp}/src/app/app.component.spec.ts`, + ` import '@proj/${mylib}'; describe('sample test', () => { it('should test', () => { @@ -219,10 +211,10 @@ forEachCli((cliName) => { }); }); ` - ); - updateFile( - `libs/${mypublishablelib}/src/lib/${mypublishablelib}.module.spec.ts`, - ` + ); + updateFile( + `libs/${mypublishablelib}/src/lib/${mypublishablelib}.module.spec.ts`, + ` import '@proj/${mylib}'; describe('sample test', () => { it('should test', () => { @@ -230,216 +222,216 @@ forEachCli((cliName) => { }); }); ` - ); - 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.base.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('node_modules/.cache/nx/results.json')).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', () => { - newProject(); - - 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"`); + ); + expect( 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}"`); + `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.base.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('node_modules/.cache/nx/results.json')).toEqual({ + command: 'test', + results: { + [myapp]: false, + [mylib]: true, + [mypublishablelib]: true, + }, }); - it('should detect changes to projects based on the workspace.json', () => { - const workspaceJson = readJson(workspaceConfigName()); + // 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); +}); - 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}"`); - }); +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', () => { + newProject(); + + 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 affect all projects by removing projects', () => { - const workspaceJson = readJson(workspaceConfigName()); - delete workspaceJson.projects[mylib]; - updateFile(workspaceConfigName(), JSON.stringify(workspaceJson)); + it('should detect changes to projects based on the workspace.json', () => { + const workspaceJson = readJson(workspaceConfigName()); - const nxJson = readJson('nx.json'); - delete nxJson.projects[mylib]; - updateFile('nx.json', JSON.stringify(nxJson)); + 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}"`); + }); - 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}"`); - }); + 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} --buildable`); - - updateFile( - `apps/${myapp}/src/main.tsx`, - ` +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} --buildable`); + + updateFile( + `apps/${myapp}/src/main.tsx`, + ` import React from 'react'; import ReactDOM from 'react-dom'; import "@proj/${mylib}"; @@ -449,11 +441,11 @@ forEachCli((cliName) => { ReactDOM.render(, document.getElementById('root')); ` - ); + ); - updateFile( - `apps/${myapp2}/src/main.tsx`, - ` + updateFile( + `apps/${myapp2}/src/main.tsx`, + ` import React from 'react'; import ReactDOM from 'react-dom'; import "@proj/${mylib}"; @@ -462,323 +454,300 @@ forEachCli((cliName) => { ReactDOM.render(, 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 nx -- test ${myapp}`, - outputs: [], + ); + + 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', }, - ]); - 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: `${myapp}:build`, - overrides: {}, - target: { - project: myapp, - target: 'build', - }, - command: `npm run nx -- build ${myapp}`, - outputs: [`dist/apps/${myapp}`], + command: `npm run nx -- 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: `${myapp}:build`, + overrides: {}, + target: { + project: myapp, + target: 'build', }, - { - id: `${mypublishablelib}:build`, - overrides: {}, - target: { - project: mypublishablelib, - target: 'build', - }, - command: `npm run nx -- build ${mypublishablelib}`, - outputs: [`dist/libs/${mypublishablelib}`], + command: `npm run nx -- build ${myapp}`, + outputs: [`dist/apps/${myapp}`], + }, + { + id: `${mypublishablelib}:build`, + overrides: {}, + target: { + project: mypublishablelib, + target: 'build', }, - ]); - 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)) - ); - } - }); + command: `npm run nx -- build ${mypublishablelib}`, + outputs: [`dist/libs/${mypublishablelib}`], + }, + ]); + 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', () => { - 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 build with caching - // -------------------------------------------- - const outputThatPutsDataIntoCache = runCommand( - `npm run affected:build -- ${files}` - ); - const filesApp1 = listFiles(`dist/apps/${myapp1}`); - const filesApp2 = listFiles(`dist/apps/${myapp2}`); - // 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`, - ]); - - // run without caching - // -------------------------------------------- - - // disable caching - // -------------------------------------------- - updateFile('nx.json', (c) => { - const nxJson = JSON.parse(c); - nxJson.tasksRunnerOptions = { - default: { - options: { - cacheableOperations: [], - }, +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 build with caching + // -------------------------------------------- + const outputThatPutsDataIntoCache = runCommand( + `npm run affected:build -- ${files}` + ); + const filesApp1 = listFiles(`dist/apps/${myapp1}`); + const filesApp2 = listFiles(`dist/apps/${myapp2}`); + // 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('from cache'); + + // skip caching when building individual projects + const individualBuildWithSkippedCache = runCommand( + `npm run nx -- build ${myapp1} --skip-nx-cache` + ); + expect(individualBuildWithSkippedCache).not.toContain('from cache'); + + // 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`, + ]); + + // run without caching + // -------------------------------------------- + + // disable caching + // -------------------------------------------- + updateFile('nx.json', (c) => { + const nxJson = JSON.parse(c); + nxJson.tasksRunnerOptions = { + default: { + options: { + cacheableOperations: [], }, - }; - return JSON.stringify(nxJson, null, 2); - }); - - const outputWithoutCachingEnabled1 = runCommand( - `npm run affected:build -- ${files}` - ); - - 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' - ); - }, 120000); - - it('should only cache specific files if build outputs is configured with specific files', async () => { - newProject(); - - const mylib1 = uniq('mylib1'); - runCLI(`generate @nrwl/react:lib ${mylib1} --buildable`); - - // Update outputs in workspace.json to just be a particular file - const workspaceJson = readJson(workspaceConfigName()); - - workspaceJson.projects[mylib1].architect['build-base'] = { - ...workspaceJson.projects[mylib1].architect.build, - }; - workspaceJson.projects[mylib1].architect.build = { - builder: '@nrwl/workspace:run-commands', - outputs: [`dist/libs/${mylib1}/${mylib1}.esm.js`], - options: { - commands: [ - { - command: `npm run nx run ${mylib1}:build-base`, - }, - ], - parallel: false, }, }; - updateFile(workspaceConfigName(), JSON.stringify(workspaceJson)); - - // run build with caching - // -------------------------------------------- - const outputThatPutsDataIntoCache = runCLI(`run ${mylib1}:build`); - // now the data is in cache - expect(outputThatPutsDataIntoCache).not.toContain('Cached Output:'); - - rmDist(); - - const outputWithBuildTasksCached = runCLI(`run ${mylib1}:build`); - expect(outputWithBuildTasksCached).toContain('Cached Output:'); - expectCached(outputWithBuildTasksCached, [mylib1]); - // Ensure that only the specific file in outputs was copied to cache - expect(listFiles(`dist/libs/${mylib1}`)).toEqual([`${mylib1}.esm.js`]); - }, 120000); - - function expectCached( - actualOutput: string, - expectedCachedProjects: string[] - ) { - const cachedProjects = []; - const lines = actualOutput.split('\n'); - lines.forEach((s, i) => { - if (s.startsWith(`> nx run`)) { - const projectName = s.split(`> nx run `)[1].split(':')[0].trim(); - if (lines[i + 2].indexOf('Cached Output') > -1) { - cachedProjects.push(projectName); - } - } - if (s.startsWith(`> ng run`)) { - const projectName = s.split(`> ng run `)[1].split(':')[0].trim(); - if (lines[i + 2].indexOf('Cached Output') > -1) { - cachedProjects.push(projectName); - } + return JSON.stringify(nxJson, null, 2); + }); + + const outputWithoutCachingEnabled1 = runCommand( + `npm run affected:build -- ${files}` + ); + + 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' + ); + }, 120000); + + it('should only cache specific files if build outputs is configured with specific files', async () => { + newProject(); + + const mylib1 = uniq('mylib1'); + runCLI(`generate @nrwl/react:lib ${mylib1} --buildable`); + + // Update outputs in workspace.json to just be a particular file + const workspaceJson = readJson(workspaceConfigName()); + + workspaceJson.projects[mylib1].architect['build-base'] = { + ...workspaceJson.projects[mylib1].architect.build, + }; + workspaceJson.projects[mylib1].architect.build = { + builder: '@nrwl/workspace:run-commands', + outputs: [`dist/libs/${mylib1}/${mylib1}.esm.js`], + options: { + commands: [ + { + command: `npm run nx run ${mylib1}:build-base`, + }, + ], + parallel: false, + }, + }; + updateFile(workspaceConfigName(), JSON.stringify(workspaceJson)); + + // run build with caching + // -------------------------------------------- + const outputThatPutsDataIntoCache = runCLI(`run ${mylib1}:build`); + // now the data is in cache + expect(outputThatPutsDataIntoCache).not.toContain('from cache'); + + rmDist(); + + const outputWithBuildTasksCached = runCLI(`run ${mylib1}:build`); + expect(outputWithBuildTasksCached).toContain('from cache'); + expectCached(outputWithBuildTasksCached, [mylib1]); + // Ensure that only the specific file in outputs was copied to cache + expect(listFiles(`dist/libs/${mylib1}`)).toEqual([`${mylib1}.esm.js`]); + }, 120000); + + function expectCached( + actualOutput: string, + expectedCachedProjects: string[] + ) { + const cachedProjects = []; + const lines = actualOutput.split('\n'); + lines.forEach((s, i) => { + if (s.startsWith(`> nx run`)) { + const projectName = s.split(`> nx run `)[1].split(':')[0].trim(); + if (s.indexOf('from cache') > -1) { + cachedProjects.push(projectName); } - }); + } + }); - cachedProjects.sort((a, b) => a.localeCompare(b)); - expectedCachedProjects.sort((a, b) => a.localeCompare(b)); - expect(cachedProjects).toEqual(expectedCachedProjects); - } - }); + cachedProjects.sort((a, b) => a.localeCompare(b)); + expectedCachedProjects.sort((a, b) => a.localeCompare(b)); + expect(cachedProjects).toEqual(expectedCachedProjects); + } +}); - describe('workspace structure', () => { - it('should have a vscode/extensions.json file created', () => { - newProject(); - const extensions = readJson('.vscode/extensions.json'); - if (cliName === 'angular') { - expect(extensions).toEqual({ - recommendations: [ - 'nrwl.angular-console', - 'angular.ng-template', - 'ms-vscode.vscode-typescript-tslint-plugin', - 'esbenp.prettier-vscode', - 'firsttris.vscode-jest-runner', - ], - }); - } else { - expect(extensions).toEqual({ - recommendations: [ - 'ms-vscode.vscode-typescript-tslint-plugin', - 'esbenp.prettier-vscode', - 'firsttris.vscode-jest-runner', - ], - }); - } +describe('workspace structure', () => { + it('should have a vscode/extensions.json file created', () => { + newProject(); + const extensions = readJson('.vscode/extensions.json'); + expect(extensions).toEqual({ + recommendations: [ + 'ms-vscode.vscode-typescript-tslint-plugin', + 'esbenp.prettier-vscode', + 'firsttris.vscode-jest-runner', + ], }); }); }); diff --git a/packages/cli/bin/nx.ts b/packages/cli/bin/nx.ts index 523f812eb7da7..1863d3a65b24f 100644 --- a/packages/cli/bin/nx.ts +++ b/packages/cli/bin/nx.ts @@ -2,7 +2,8 @@ // polyfill rxjs observable to avoid issues with multiple version fo Observable installed in node_modules // https://twitter.com/BenLesh/status/1192478226385428483?s=20 -(Symbol as any).observable = Symbol('observable polyfill'); +if (!(Symbol as any).observable) + (Symbol as any).observable = Symbol('observable polyfill'); import chalk from 'chalk'; import { findWorkspaceRoot } from '../lib/find-workspace-root'; import { initLocal } from '../lib/init-local'; diff --git a/packages/cli/lib/init-local.ts b/packages/cli/lib/init-local.ts index 69544f35a19c8..065a17a60ad95 100644 --- a/packages/cli/lib/init-local.ts +++ b/packages/cli/lib/init-local.ts @@ -2,7 +2,6 @@ import * as path from 'path'; import * as fs from 'fs'; import { Workspace } from './workspace'; import { parseRunOneOptions } from './parse-run-one-options'; -import { useNxToRunNxBuilderOrGenerator } from './use-nx-to-run-nx-builder-or-generator'; /** * Nx is being run inside a workspace. @@ -13,38 +12,32 @@ process.env.NX_CLI_SET = 'true'; export function initLocal(workspace: Workspace) { require('@nrwl/workspace/' + 'src/utils/perf-logging'); + require('@nrwl/tao/src/compat/compat.js'); + const supportedNxCommands = require('@nrwl/workspace/' + 'src/command-line/supported-nx-commands').supportedNxCommands; + const runOpts = runOneOptions(workspace); + const running = runOpts !== false; if (supportedNxCommands.includes(process.argv[2])) { // required to make sure nrwl/workspace import works - if (workspace.type === 'nx') { - require('@nrwl/tao/src/compat/compat.js'); - } require('@nrwl/workspace' + '/src/command-line/nx-commands').commandsObject .argv; + } else if (running) { + require('@nrwl/workspace' + '/src/command-line/run-one').runOne(runOpts); + } else if (generating()) { + loadCli(workspace, '@nrwl/tao/index.js'); } else { - // not using the tasks runner - if (runOpts === false || process.env.NX_SKIP_TASKS_RUNNER) { - loadCli(workspace, useNxToRunNxBuilderOrGenerator()); + if (workspace.type === 'nx') { + loadCli(workspace, '@nrwl/tao/index.js'); } else { - require('@nrwl/workspace' + '/src/command-line/run-one').runOne(runOpts); + loadCli(workspace, '@angular/cli/lib/init.js'); } } } -function loadCli(workspace: Workspace, useNxCli: boolean) { - let cliPath: string; - if (workspace.type === 'nx' || useNxCli) { - cliPath = '@nrwl/tao/index.js'; - } else if (workspace.type === 'angular') { - cliPath = '@angular/cli/lib/init.js'; - } else { - console.error(`Cannot recognize the workspace type.`); - process.exit(1); - } - +function loadCli(workspace: Workspace, cliPath: string) { try { const cli = require.resolve(cliPath, { paths: [workspace.dir] }); require(cli); @@ -74,3 +67,8 @@ function runOneOptions( return false; } } + +function generating(): boolean { + const command = process.argv.slice(2)[0]; + return command === 'g' || command === 'generate'; +} diff --git a/packages/cli/lib/run-cli.ts b/packages/cli/lib/run-cli.ts index eda42b27ec3e1..e7be3b365de25 100644 --- a/packages/cli/lib/run-cli.ts +++ b/packages/cli/lib/run-cli.ts @@ -7,7 +7,7 @@ if (process.env.NX_TERMINAL_OUTPUT_PATH) { ); } -if (!process.env.NX_WORKSPACE_ROOT || !process.env.NX_CLI_PATH) { +if (!process.env.NX_WORKSPACE_ROOT) { console.error('Invalid Nx command invocation'); process.exit(1); } @@ -16,15 +16,12 @@ requireCli(); function requireCli() { process.env.NX_CLI_SET = 'true'; try { - const cli = require.resolve(process.env.NX_CLI_PATH, { + const cli = require.resolve('@nrwl/tao/index.js', { paths: [process.env.NX_WORKSPACE_ROOT], }); require(cli); } catch (e) { - console.error( - `Could not find ${process.env.NX_CLI_PATH} module in this workspace.`, - e - ); + console.error(`Could not find @nrwl/tao module in this workspace.`, e); process.exit(1); } } diff --git a/packages/cli/lib/use-nx-to-run-nx-builder-or-generator.ts b/packages/cli/lib/use-nx-to-run-nx-builder-or-generator.ts deleted file mode 100644 index 437f7b4d69b44..0000000000000 --- a/packages/cli/lib/use-nx-to-run-nx-builder-or-generator.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { parseRunOneOptions } from './parse-run-one-options'; -import { findWorkspaceRoot } from './find-workspace-root'; -import * as fs from 'fs'; -import * as path from 'path'; -import { - WorkspaceDefinition, - Workspaces, -} from '@nrwl/tao/src/shared/workspace'; - -const ws = new Workspaces(); -export function useNxToRunNxBuilderOrGenerator() { - try { - const dir = findWorkspaceRoot(__dirname).dir; - const args = process.argv.slice(2); - const wd = ws.readWorkspaceConfiguration(dir); - return isNxBuilder(dir, args, wd) || isNxGenerator(dir, args, wd); - } catch (e) { - return false; - } -} - -function isNxBuilder(dir: string, args: string[], wd: WorkspaceDefinition) { - try { - const angularJsonPath = path.join(dir, 'angular.json'); - const angularJson = JSON.parse(fs.readFileSync(angularJsonPath).toString()); - const runOpts = parseRunOneOptions(angularJson, args); - if (runOpts === false) return false; - return ws.isNxBuilder( - wd.projects[runOpts.project].architect[runOpts.target] - ); - } catch (e) { - return false; - } -} - -function isNxGenerator(dir: string, args: string[], wd: WorkspaceDefinition) { - try { - if (args[0] != 'g' && args[0] != 'generate') return false; - const defaultCollection = wd.cli ? wd.cli.defaultCollection : null; - - let [collectionName, generatorName] = args[1].split(':'); - if (!generatorName) { - generatorName = collectionName; - collectionName = defaultCollection; - } - return ws.isNxGenerator(collectionName, generatorName); - } catch (e) { - return false; - } -} diff --git a/packages/workspace/src/core/file-utils.ts b/packages/workspace/src/core/file-utils.ts index a2c45db6b8e50..4c93f4449d890 100644 --- a/packages/workspace/src/core/file-utils.ts +++ b/packages/workspace/src/core/file-utils.ts @@ -166,10 +166,6 @@ export function readWorkspaceJson(): any { return readJsonFile(`${appRootPath}/${workspaceFileName()}`); } -export function defaultCliCommand() { - return workspaceFileName() === 'angular.json' ? 'ng' : 'nx'; -} - export function workspaceFileName() { if (fileExists(`${appRootPath}/angular.json`)) { return 'angular.json'; diff --git a/packages/workspace/src/schematics/library/library.ts b/packages/workspace/src/schematics/library/library.ts index eb2eeb3a719d7..b9a789323328c 100644 --- a/packages/workspace/src/schematics/library/library.ts +++ b/packages/workspace/src/schematics/library/library.ts @@ -26,7 +26,6 @@ import { offsetFromRoot, } from '@nrwl/workspace'; -import { defaultCliCommand } from '../../core/file-utils'; import { generateProjectLint, addLintFiles } from '../../utils/lint'; import { addProjectToNxJsonInTree, libsDir } from '../../utils/ast-utils'; import { toJS, updateTsConfigsToJs, maybeJs } from '../../utils/rules/to-js'; @@ -97,7 +96,7 @@ function createFiles(options: NormalizedSchema): Rule { className, name, propertyName, - cliCommand: defaultCliCommand(), + cliCommand: 'nx', tmpl: '', offsetFromRoot: offsetFromRoot(options.projectRoot), hasUnitTestRunner: options.unitTestRunner !== 'none', diff --git a/packages/workspace/src/tasks-runner/task-orchestrator.ts b/packages/workspace/src/tasks-runner/task-orchestrator.ts index 0afd667353e9f..50032cf927271 100644 --- a/packages/workspace/src/tasks-runner/task-orchestrator.ts +++ b/packages/workspace/src/tasks-runner/task-orchestrator.ts @@ -1,5 +1,4 @@ import { Cache, TaskWithCachedResult } from './cache'; -import { defaultCliCommand, workspaceFileName } from '../core/file-utils'; import { ProjectGraph } from '../core/project-graph'; import { AffectedEventType, Task } from './tasks-runner'; import { getOutputs, unparse } from './utils'; @@ -9,7 +8,6 @@ import { output } from '../utils/output'; import * as fs from 'fs'; import { appRootPath } from '../utils/app-root'; import * as dotenv from 'dotenv'; -import { Workspaces } from '@nrwl/tao/src/shared/workspace'; export class TaskOrchestrator { workspaceRoot = appRootPath; @@ -106,8 +104,7 @@ export class TaskOrchestrator { this.initiatingProject === t.task.target.project ) { const args = this.getCommandArgs(t.task); - output.logCommand(`${this.getCliCommand(t.task)} ${args.join(' ')}`); - output.note({ title: `Cached Output:` }); + output.logCommand(`nx ${args.join(' ')}`, true); process.stdout.write(t.cachedResult.terminalOutput); } @@ -160,7 +157,7 @@ export class TaskOrchestrator { : process.env.FORCE_COLOR ); const args = this.getCommandArgs(task); - const commandLine = `${this.getCliCommand(task)} ${args.join(' ')}`; + const commandLine = `nx ${args.join(' ')}`; if (forwardOutput) { output.logCommand(commandLine); @@ -232,7 +229,7 @@ export class TaskOrchestrator { undefined ); const args = this.getCommandArgs(task); - const commandLine = `${this.getCliCommand(task)} ${args.join(' ')}`; + const commandLine = `nx ${args.join(' ')}`; if (forwardOutput) { output.logCommand(commandLine); @@ -298,10 +295,6 @@ export class TaskOrchestrator { ...process.env, NX_INVOKED_BY_RUNNER: 'true', NX_WORKSPACE_ROOT: this.workspaceRoot, - NX_CLI_PATH: - this.getCliCommand(task) === 'nx' - ? '@nrwl/tao/index.js' - : '@angular/cli/lib/init.js', }; if (outputPath) { @@ -357,15 +350,6 @@ export class TaskOrchestrator { process.exit(); }); } - - private getCliCommand(task: Task) { - const ws = new Workspaces(); - const target = ws.readWorkspaceConfiguration(this.workspaceRoot).projects[ - task.target.project - ].architect[task.target.target]; - const isNxBuilder = ws.isNxBuilder(target); - return isNxBuilder ? 'nx' : defaultCliCommand(); - } } function parseEnv(path: string) { diff --git a/packages/workspace/src/tasks-runner/tasks-runner-v1.ts b/packages/workspace/src/tasks-runner/tasks-runner-v1.ts deleted file mode 100644 index aa2b3a90e026f..0000000000000 --- a/packages/workspace/src/tasks-runner/tasks-runner-v1.ts +++ /dev/null @@ -1,184 +0,0 @@ -import * as runAll from 'npm-run-all'; -import { Observable } from 'rxjs'; -import { basename } from 'path'; -import { - AffectedEventType, - Task, - TaskCompleteEvent, - TasksRunner, -} from './tasks-runner'; -import { output } from '../utils/output'; -import { readJsonFile } from '../utils/fileutils'; -import { getCommand, getCommandAsString } from './utils'; -import { defaultCliCommand } from '../core/file-utils'; -import { ProjectGraph } from '../core/project-graph'; -import { NxJson } from '../core/shared-interfaces'; - -export interface DefaultTasksRunnerOptions { - parallel?: boolean; - maxParallel?: number; -} - -function taskDependsOnDeps( - task: Task, - deps: Task[], - projectGraph: ProjectGraph -) { - function hasDep(source: string, target: string, visitedProjects: string[]) { - if (!projectGraph.dependencies[source]) { - return false; - } - - if (projectGraph.dependencies[source].find((d) => d.target === target)) { - return true; - } - - return !!projectGraph.dependencies[source].find((r) => { - if (visitedProjects.indexOf(r.target) > -1) return null; - return hasDep(r.target, target, [...visitedProjects, r.target]); - }); - } - - return !!deps.find((dep) => - hasDep(task.target.project, dep.target.project, []) - ); -} - -function topologicallySortTasks(tasks: Task[], projectGraph: ProjectGraph) { - const visited: { [k: string]: boolean } = {}; - const sorted = []; - - const visitNode = (id: string) => { - if (visited[id]) return; - visited[id] = true; - projectGraph.dependencies[id].forEach((d) => { - visitNode(d.target); - }); - sorted.push(id); - }; - tasks.forEach((t) => visitNode(t.target.project)); - const sortedTasks = [...tasks]; - sortedTasks.sort((a, b) => - sorted.indexOf(a.target.project) > sorted.indexOf(b.target.project) ? 1 : -1 - ); - return sortedTasks; -} - -export function splitTasksIntoStages( - tasks: Task[], - projectGraph: ProjectGraph -) { - if (tasks.length === 0) return []; - const res = []; - topologicallySortTasks(tasks, projectGraph).forEach((t) => { - const stageWithNoDeps = res.find( - (tasksInStage) => !taskDependsOnDeps(t, tasksInStage, projectGraph) - ); - if (stageWithNoDeps) { - stageWithNoDeps.push(t); - } else { - res.push([t]); - } - }); - return res; -} - -export const defaultTasksRunner: TasksRunner = ( - tasks: Task[], - options: DefaultTasksRunnerOptions, - context: { target: string; projectGraph: ProjectGraph; nxJson: NxJson } -): Observable => { - return new Observable((subscriber) => { - runTasks(tasks, options, context) - .then((data) => data.forEach((d) => subscriber.next(d))) - .catch((e) => { - console.error('Unexpected error:'); - console.error(e); - process.exit(1); - }) - .finally(() => { - subscriber.complete(); - // fix for https://github.com/nrwl/nx/issues/1666 - if (process.stdin['unref']) (process.stdin as any).unref(); - }); - }); -}; - -// TODO: delete this tasks runner in Nx 10 -async function runTasks( - tasks: Task[], - options: DefaultTasksRunnerOptions, - context: { target: string; projectGraph: ProjectGraph } -): Promise> { - const cli = defaultCliCommand(); - assertPackageJsonScriptExists(cli); - const isYarn = basename(process.env.npm_execpath || 'npm').startsWith('yarn'); - const stages = - context.target === 'build' - ? splitTasksIntoStages(tasks, context.projectGraph) - : [tasks]; - - const res = []; - for (let i = 0; i < stages.length; ++i) { - const tasksInStage = stages[i]; - try { - const commands = tasksInStage.map((t) => - getCommandAsString(cli, isYarn, t) - ); - await runAll(commands, { - parallel: options.parallel || false, - maxParallel: options.maxParallel || 3, - continueOnError: true, - stdin: process.stdin, - stdout: process.stdout, - stderr: process.stderr, - }); - res.push(...tasksToStatuses(tasksInStage, true)); - } catch (e) { - e.results.forEach((result, i) => { - res.push({ - task: tasksInStage[i], - type: AffectedEventType.TaskComplete, - success: result.code === 0, - }); - }); - res.push(...markStagesAsNotSuccessful(stages.splice(i + 1))); - return res; - } - } - return res; -} - -function markStagesAsNotSuccessful(stages: Task[][]) { - return stages.reduce((m, c) => [...m, ...tasksToStatuses(c, false)], []); -} - -function tasksToStatuses(tasks: Task[], success: boolean) { - return tasks.map((task) => ({ - task, - type: AffectedEventType.TaskComplete, - success, - })); -} - -function assertPackageJsonScriptExists(cli: string) { - // Make sure the `package.json` has the `nx: "nx"` command needed by `npm-run-all` - const packageJson = readJsonFile('./package.json'); - if (!packageJson.scripts || !packageJson.scripts[cli]) { - output.error({ - title: `The "scripts" section of your 'package.json' must contain "${cli}": "${cli}"`, - bodyLines: [ - output.colors.gray('...'), - ' "scripts": {', - output.colors.gray(' ...'), - ` "${cli}": "${cli}"`, - output.colors.gray(' ...'), - ' }', - output.colors.gray('...'), - ], - }); - return process.exit(1); - } -} - -export default defaultTasksRunner; diff --git a/packages/workspace/src/utils/output.ts b/packages/workspace/src/utils/output.ts index 16a833a51dbdc..ebfa5c57ce3cd 100644 --- a/packages/workspace/src/utils/output.ts +++ b/packages/workspace/src/utils/output.ts @@ -179,11 +179,15 @@ class CLIOutput { this.addNewline(); } - logCommand(message: string) { + logCommand(message: string, isCached: boolean = false) { this.addNewline(); this.writeToStdOut(chalk.bold(`> ${message} `)); + if (isCached) { + this.writeToStdOut(chalk.bold.grey(`[retrieved from cache]`)); + } + this.addNewline(); } diff --git a/scripts/e2e-ci.sh b/scripts/e2e-ci.sh index dac9a1b5863c8..143d7f432c77a 100755 --- a/scripts/e2e-ci.sh +++ b/scripts/e2e-ci.sh @@ -1,33 +1,26 @@ #!/usr/bin/env bash if [ "$1" == "1" ]; then - export SELECTED_CLI=angular - ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-workspace,e2e-cli affected + ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-workspace affected elif [ "$1" == "2" ]; then - export SELECTED_CLI=nx - ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-workspace,e2e-cli affected + ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-cli,e2e-nx-plugin affected elif [ "$1" == "3" ]; then - export SELECTED_CLI=angular - ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-angular affected + ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-cypress,e2e-jest affected elif [ "$1" == "4" ]; then - export SELECTED_CLI=nx - ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-cypress,e2e-jest,e2e-nx-plugin affected + ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-react affected elif [ "$1" == "5" ]; then - export SELECTED_CLI=nx - ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-react affected + ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-next affected elif [ "$1" == "6" ]; then - export SELECTED_CLI=nx - ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-next affected + ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-node affected elif [ "$1" == "7" ]; then - export SELECTED_CLI=nx - ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-node affected + ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-web,e2e-linter,e2e-storybook affected elif [ "$1" == "8" ]; then - export SELECTED_CLI=nx - ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-web,e2e-linter,e2e-storybook affected + export SELECTED_CLI=angular + ts-node --project scripts/tsconfig.e2e.json ./scripts/e2e.ts e2e-angular affected fi