import { checkFilesExist, newProject, readFile, readJson, runCLI, runCommand, updateFile, exists, ensureProject, uniq, forEachCli, workspaceConfigName } from './utils'; forEachCli(() => { describe('Command line', () => { it('lint should ensure module boundaries', () => { ensureProject(); const myapp = uniq('myapp'); const myapp2 = uniq('myapp2'); const mylib = uniq('mylib'); const lazylib = uniq('lazylib'); const invalidtaglib = uniq('invalidtaglib'); const validtaglib = uniq('validtaglib'); runCLI(`generate @nrwl/angular:app ${myapp} --tags=validtag`); runCLI(`generate @nrwl/angular:app ${myapp2}`); runCLI(`generate @nrwl/angular:lib ${mylib}`); runCLI(`generate @nrwl/angular:lib ${lazylib}`); runCLI(`generate @nrwl/angular:lib ${invalidtaglib} --tags=invalidtag`); runCLI(`generate @nrwl/angular:lib ${validtaglib} --tags=validtag`); const tslint = readJson('tslint.json'); tslint.rules['nx-enforce-module-boundaries'][1].depConstraints = [ { sourceTag: 'validtag', onlyDependOnLibsWithTags: ['validtag'] }, ...tslint.rules['nx-enforce-module-boundaries'][1].depConstraints ]; updateFile('tslint.json', JSON.stringify(tslint, null, 2)); updateFile( `apps/${myapp}/src/main.ts`, ` import '../../../libs/${mylib}'; import '@proj/${lazylib}'; import '@proj/${mylib}/deep'; import '@proj/${myapp2}'; import '@proj/${invalidtaglib}'; import '@proj/${validtaglib}'; const s = {loadChildren: '@proj/${lazylib}'}; ` ); const out = runCLI(`lint ${myapp}`, { silenceError: true }); expect(out).toContain('library imports must start with @proj/'); expect(out).toContain('imports of lazy-loaded libraries are forbidden'); expect(out).toContain('deep imports into libraries are forbidden'); expect(out).toContain('imports of apps are forbidden'); expect(out).toContain( 'A project tagged with "validtag" can only depend on libs tagged with "validtag"' ); }, 1000000); describe('nx lint', () => { afterAll(() => { newProject(); }); it('should run nx lint', () => { ensureProject(); const appBefore = uniq('before'); const appAfter = uniq('after'); runCLI(`generate @nrwl/angular:app ${appBefore}`); runCommand(`mv apps/${appBefore} apps/${appAfter}`); const stdout = runCommand('./node_modules/.bin/nx workspace-lint'); expect(stdout).toContain( `- Cannot find project '${appBefore}' in 'apps/${appBefore}'` ); expect(stdout).toContain( 'The following file(s) do not belong to any projects:' ); expect(stdout).toContain(`- apps/${appAfter}/browserslist`); expect(stdout).toContain( `- apps/${appAfter}/src/app/app.component.css` ); expect(stdout).toContain( `- apps/${appAfter}/src/app/app.component.html` ); expect(stdout).toContain( `- apps/${appAfter}/src/app/app.component.spec.ts` ); }); }); it('format should check and reformat the code', () => { ensureProject(); const myapp = uniq('myapp'); const mylib = uniq('mylib'); runCLI(`generate @nrwl/angular:app ${myapp}`); runCLI(`generate @nrwl/angular:lib ${mylib}`); updateFile( `apps/${myapp}/src/main.ts`, ` const x = 1111; ` ); updateFile( `apps/${myapp}/src/app/app.module.ts`, ` const y = 1111; ` ); updateFile( `apps/${myapp}/src/app/app.component.ts`, ` const z = 1111; ` ); updateFile( `libs/${mylib}/index.ts`, ` const x = 1111; ` ); updateFile( `libs/${mylib}/src/${mylib}.module.ts`, ` const y = 1111; ` ); let stdout = runCommand( `npm run -s format:check -- --files="libs/${mylib}/index.ts" --libs-and-apps` ); expect(stdout).toContain(`libs/${mylib}/index.ts`); expect(stdout).toContain(`libs/${mylib}/src/${mylib}.module.ts`); stdout = runCommand(`npm run -s format:check -- --all`); expect(stdout).toContain(`apps/${myapp}/src/main.ts`); expect(stdout).toContain(`apps/${myapp}/src/app/app.module.ts`); expect(stdout).toContain(`apps/${myapp}/src/app/app.component.ts`); runCommand( `npm run format:write -- --files="apps/${myapp}/src/app/app.module.ts,apps/${myapp}/src/app/app.component.ts"` ); stdout = runCommand('npm run -s format:check -- --all'); expect(stdout).toContain(`apps/${myapp}/src/main.ts`); expect(stdout).not.toContain(`apps/${myapp}/src/app/app.module.ts`); expect(stdout).not.toContain(`apps/${myapp}/src/app/app.component.ts`); runCommand('npm run format:write -- --all'); expect(runCommand('npm run -s format:check -- --all')).toEqual(''); }); it('should support workspace-specific schematics', () => { ensureProject(); const custom = uniq('custom'); runCLI(`g workspace-schematic ${custom} --no-interactive`); checkFilesExist( `tools/schematics/${custom}/index.ts`, `tools/schematics/${custom}/schema.json` ); const json = readJson(`tools/schematics/${custom}/schema.json`); json.properties['directory'] = { type: 'string', description: 'lib directory' }; updateFile( `tools/schematics/${custom}/schema.json`, JSON.stringify(json) ); const indexFile = readFile(`tools/schematics/${custom}/index.ts`); updateFile( `tools/schematics/${custom}/index.ts`, indexFile.replace( 'name: schema.name', 'name: schema.name, directory: schema.directory' ) ); const workspace = uniq('workspace'); const dryRunOutput = runCommand( `npm run workspace-schematic ${custom} ${workspace} -- --no-interactive --directory=dir -d` ); expect(exists(`libs/dir/${workspace}/src/index.ts`)).toEqual(false); expect(dryRunOutput).toContain(`update ${workspaceConfigName()}`); expect(dryRunOutput).toContain('update nx.json'); const output = runCommand( `npm run workspace-schematic ${custom} ${workspace} -- --no-interactive --directory=dir` ); checkFilesExist(`libs/dir/${workspace}/src/index.ts`); expect(output).toContain(`update ${workspaceConfigName()}`); expect(output).toContain('update nx.json'); const another = uniq('another'); runCLI(`g workspace-schematic ${another} --no-interactive`); const listSchematicsOutput = runCommand( 'npm run workspace-schematic -- --list-schematics' ); expect(listSchematicsOutput).toContain( 'nx workspace-schematic "--list-schematics"' ); expect(listSchematicsOutput).toContain(custom); expect(listSchematicsOutput).toContain(another); const promptOutput = runCommand( `npm run workspace-schematic ${custom} mylib2 --` ); expect(promptOutput).toContain( 'In which directory should the library be generated?' ); }, 1000000); describe('dep-graph', () => { beforeAll(() => { newProject(); runCLI('generate @nrwl/angular:app myapp'); runCLI('generate @nrwl/angular:app myapp2'); runCLI('generate @nrwl/angular:app myapp3'); runCLI('generate @nrwl/angular:lib mylib'); runCLI('generate @nrwl/angular:lib mylib2'); updateFile( 'apps/myapp/src/main.ts', ` import '@proj/mylib'; const s = {loadChildren: '@proj/mylib2'}; ` ); updateFile( 'apps/myapp2/src/app/app.component.spec.ts', `import '@proj/mylib';` ); updateFile( 'libs/mylib/src/mylib.module.spec.ts', `import '@proj/mylib2';` ); }); it('dep-graph should output json (without critical path) to file', () => { const file = 'dep-graph.json'; runCommand(`npm run dep-graph -- --file="${file}"`); expect(() => checkFilesExist(file)).not.toThrow(); const jsonFileContents = readJson(file); expect(jsonFileContents).toEqual({ deps: { mylib2: [], myapp3: [], 'myapp3-e2e': [ { projectName: 'myapp3', type: 'implicit' } ], myapp2: [ { projectName: 'mylib', type: 'es6Import' } ], 'myapp2-e2e': [ { projectName: 'myapp2', type: 'implicit' } ], mylib: [ { projectName: 'mylib2', type: 'es6Import' } ], myapp: [ { projectName: 'mylib', type: 'es6Import' }, { projectName: 'mylib2', type: 'loadChildren' } ], 'myapp-e2e': [ { projectName: 'myapp', type: 'implicit' } ] }, criticalPath: [] }); }, 1000000); it('dep-graph should output json with critical path to file', () => { const file = 'dep-graph.json'; runCommand( `npm run affected:dep-graph -- --files="libs/mylib/src/index.ts" --file="${file}"` ); expect(() => checkFilesExist(file)).not.toThrow(); const jsonFileContents = readJson(file); expect(jsonFileContents.criticalPath).toContain('myapp'); expect(jsonFileContents.criticalPath).toContain('myapp2'); expect(jsonFileContents.criticalPath).toContain('mylib'); expect(jsonFileContents.criticalPath).not.toContain('mylib2'); }, 1000000); it('dep-graph should output dot to file', () => { const file = 'dep-graph.dot'; runCommand( `npm run dep-graph -- --files="libs/mylib/index.ts" --file="${file}"` ); expect(() => checkFilesExist(file)).not.toThrow(); const fileContents = readFile(file); expect(fileContents).toContain('"myapp" -> "mylib"'); expect(fileContents).toContain('"myapp2" -> "mylib"'); expect(fileContents).toContain('"mylib" -> "mylib2"'); }, 1000000); it('dep-graph should output html to file', () => { const file = 'dep-graph.html'; runCommand( `npm run dep-graph -- --files="libs/mylib/index.ts" --file="${file}"` ); expect(() => checkFilesExist(file)).not.toThrow(); const fileContents = readFile(file); expect(fileContents).toContain(''); expect(fileContents).toContain('