505 lines
15 KiB
TypeScript
505 lines
15 KiB
TypeScript
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
|
import { exec, execSync } from 'child_process';
|
|
import * as http from 'http';
|
|
import * as treeKill from 'tree-kill';
|
|
import {
|
|
checkFilesDoNotExist,
|
|
checkFilesExist,
|
|
newProject,
|
|
readFile,
|
|
readJson,
|
|
runCLI,
|
|
runCLIAsync,
|
|
runCommandUntil,
|
|
tmpProjPath,
|
|
uniq,
|
|
updateFile,
|
|
workspaceConfigName,
|
|
} from '@nrwl/e2e/utils';
|
|
|
|
function getData(): Promise<any> {
|
|
return new Promise((resolve) => {
|
|
http.get('http://localhost:3333/api', (res) => {
|
|
expect(res.statusCode).toEqual(200);
|
|
let data = '';
|
|
res.on('data', (chunk) => {
|
|
data += chunk;
|
|
});
|
|
res.once('end', () => {
|
|
resolve(JSON.parse(data));
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
describe('Node Applications', () => {
|
|
it('should be able to generate an empty application', async () => {
|
|
newProject();
|
|
const nodeapp = uniq('nodeapp');
|
|
|
|
runCLI(`generate @nrwl/node:app ${nodeapp} --linter=eslint`);
|
|
|
|
const lintResults = runCLI(`lint ${nodeapp}`);
|
|
expect(lintResults).toContain('All files pass linting.');
|
|
|
|
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
|
|
await runCLIAsync(`build ${nodeapp}`);
|
|
|
|
checkFilesExist(`dist/apps/${nodeapp}/main.js`);
|
|
const result = execSync(`node dist/apps/${nodeapp}/main.js`, {
|
|
cwd: tmpProjPath(),
|
|
}).toString();
|
|
expect(result).toContain('Hello World!');
|
|
}, 60000);
|
|
|
|
it('should be able to generate an express application', async (done) => {
|
|
newProject();
|
|
const nodeapp = uniq('nodeapp');
|
|
|
|
runCLI(`generate @nrwl/express:app ${nodeapp} --linter=eslint`);
|
|
const lintResults = runCLI(`lint ${nodeapp}`);
|
|
expect(lintResults).toContain('All files pass linting.');
|
|
|
|
updateFile(
|
|
`apps/${nodeapp}/src/app/test.spec.ts`,
|
|
`
|
|
describe('test', () => {
|
|
it('should work', () => {
|
|
expect(true).toEqual(true);
|
|
})
|
|
})
|
|
`
|
|
);
|
|
|
|
updateFile(`apps/${nodeapp}/src/assets/file.txt`, ``);
|
|
const jestResult = await runCLIAsync(`test ${nodeapp}`);
|
|
expect(jestResult.combinedOutput).toContain(
|
|
'Test Suites: 1 passed, 1 total'
|
|
);
|
|
await runCLIAsync(`build ${nodeapp}`);
|
|
|
|
checkFilesExist(
|
|
`dist/apps/${nodeapp}/main.js`,
|
|
`dist/apps/${nodeapp}/assets/file.txt`,
|
|
`dist/apps/${nodeapp}/main.js.map`
|
|
);
|
|
|
|
const server = exec(`node ./dist/apps/${nodeapp}/main.js`, {
|
|
cwd: tmpProjPath(),
|
|
});
|
|
await new Promise((resolve) => {
|
|
server.stdout.on('data', async (data) => {
|
|
expect(data.toString()).toContain('Listening at http://localhost:3333');
|
|
const result = await getData();
|
|
|
|
expect(result.message).toEqual(`Welcome to ${nodeapp}!`);
|
|
treeKill(server.pid, 'SIGTERM', (err) => {
|
|
expect(err).toBeFalsy();
|
|
resolve(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
const { process } = await runCommandUntil(
|
|
`serve ${nodeapp}`,
|
|
(output) => output.includes('Listening at http://localhost:3333'),
|
|
{ kill: false }
|
|
);
|
|
const result = await getData();
|
|
expect(result.message).toEqual(`Welcome to ${nodeapp}!`);
|
|
treeKill(process.pid, 'SIGTERM', (err) => {
|
|
expect(err).toBeFalsy();
|
|
done();
|
|
});
|
|
}, 120000);
|
|
|
|
it('should be able to generate a nest application', async (done) => {
|
|
newProject();
|
|
const nestapp = uniq('nestapp');
|
|
runCLI(`generate @nrwl/nest:app ${nestapp} --linter=eslint`);
|
|
|
|
const lintResults = runCLI(`lint ${nestapp}`);
|
|
expect(lintResults).toContain('All files pass linting.');
|
|
|
|
updateFile(`apps/${nestapp}/src/assets/file.txt`, ``);
|
|
const jestResult = await runCLIAsync(`test ${nestapp}`);
|
|
expect(jestResult.combinedOutput).toContain(
|
|
'Test Suites: 2 passed, 2 total'
|
|
);
|
|
|
|
await runCLIAsync(`build ${nestapp}`);
|
|
|
|
checkFilesExist(
|
|
`dist/apps/${nestapp}/main.js`,
|
|
`dist/apps/${nestapp}/assets/file.txt`,
|
|
`dist/apps/${nestapp}/main.js.map`
|
|
);
|
|
|
|
const server = exec(`node ./dist/apps/${nestapp}/main.js`, {
|
|
cwd: tmpProjPath(),
|
|
});
|
|
expect(server).toBeTruthy();
|
|
|
|
await new Promise((resolve) => {
|
|
server.stdout.on('data', async (data) => {
|
|
const message = data.toString();
|
|
if (message.includes('Listening at http://localhost:3333')) {
|
|
const result = await getData();
|
|
|
|
expect(result.message).toEqual(`Welcome to ${nestapp}!`);
|
|
treeKill(server.pid, 'SIGTERM', (err) => {
|
|
expect(err).toBeFalsy();
|
|
resolve(true);
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
const { process } = await runCommandUntil(
|
|
`serve ${nestapp}`,
|
|
(output) => output.includes('Listening at http://localhost:3333'),
|
|
{ kill: false }
|
|
);
|
|
const result = await getData();
|
|
expect(result.message).toEqual(`Welcome to ${nestapp}!`);
|
|
treeKill(process.pid, 'SIGTERM', (err) => {
|
|
expect(err).toBeFalsy();
|
|
done();
|
|
});
|
|
}, 120000);
|
|
});
|
|
describe('Build Node apps', () => {
|
|
it('should generate a package.json with the `--generatePackageJson` flag', async () => {
|
|
newProject();
|
|
const nestapp = uniq('nestapp');
|
|
runCLI(`generate @nrwl/nest:app ${nestapp} --linter=eslint`);
|
|
|
|
await runCLIAsync(`build ${nestapp} --generatePackageJson`);
|
|
|
|
checkFilesExist(`dist/apps/${nestapp}/package.json`);
|
|
const packageJson = JSON.parse(
|
|
readFile(`dist/apps/${nestapp}/package.json`)
|
|
);
|
|
expect(packageJson).toEqual(
|
|
expect.objectContaining({
|
|
dependencies: {
|
|
'@nestjs/common': '^7.0.0',
|
|
'@nestjs/core': '^7.0.0',
|
|
},
|
|
main: 'main.js',
|
|
name: expect.any(String),
|
|
version: '0.0.1',
|
|
})
|
|
);
|
|
});
|
|
});
|
|
describe('Node Libraries', () => {
|
|
it('should be able to generate a node library', async () => {
|
|
newProject();
|
|
const nodelib = uniq('nodelib');
|
|
|
|
runCLI(`generate @nrwl/node:lib ${nodelib}`);
|
|
|
|
const lintResults = runCLI(`lint ${nodelib}`);
|
|
expect(lintResults).toContain('All files pass linting.');
|
|
|
|
const jestResult = await runCLIAsync(`test ${nodelib}`);
|
|
expect(jestResult.combinedOutput).toContain(
|
|
'Test Suites: 1 passed, 1 total'
|
|
);
|
|
}, 60000);
|
|
|
|
it('should be able to generate a publishable node library', async () => {
|
|
newProject();
|
|
|
|
const nodeLib = uniq('nodelib');
|
|
runCLI(
|
|
`generate @nrwl/node:lib ${nodeLib} --publishable --importPath=@proj/${nodeLib}`
|
|
);
|
|
checkFilesExist(`libs/${nodeLib}/package.json`);
|
|
const tslibConfig = readJson(`libs/${nodeLib}/tsconfig.lib.json`);
|
|
expect(tslibConfig).toEqual({
|
|
extends: './tsconfig.json',
|
|
compilerOptions: {
|
|
module: 'commonjs',
|
|
outDir: '../../dist/out-tsc',
|
|
declaration: true,
|
|
types: ['node'],
|
|
},
|
|
exclude: ['**/*.spec.ts'],
|
|
include: ['**/*.ts'],
|
|
});
|
|
await runCLIAsync(`build ${nodeLib}`);
|
|
checkFilesExist(
|
|
`dist/libs/${nodeLib}/src/index.js`,
|
|
`dist/libs/${nodeLib}/src/index.d.ts`,
|
|
`dist/libs/${nodeLib}/package.json`
|
|
);
|
|
|
|
const packageJson = readJson(`dist/libs/${nodeLib}/package.json`);
|
|
expect(packageJson).toEqual({
|
|
name: `@proj/${nodeLib}`,
|
|
version: '0.0.1',
|
|
main: 'src/index.js',
|
|
typings: 'src/index.d.ts',
|
|
});
|
|
}, 60000);
|
|
|
|
it('should be able to copy assets', () => {
|
|
newProject();
|
|
const nodelib = uniq('nodelib');
|
|
const nglib = uniq('nglib');
|
|
|
|
// Generating two libraries just to have a lot of files to copy
|
|
runCLI(
|
|
`generate @nrwl/node:lib ${nodelib} --publishable --importPath=@proj/${nodelib}`
|
|
);
|
|
/**
|
|
* The angular lib contains a lot sub directories that would fail without
|
|
* `nodir: true` in the package.impl.ts
|
|
*/
|
|
runCLI(
|
|
`generate @nrwl/angular:lib ${nglib} --publishable --importPath=@proj/${nglib}`
|
|
);
|
|
const workspace = readJson(workspaceConfigName());
|
|
workspace.projects[nodelib].targets.build.options.assets.push({
|
|
input: `./dist/libs/${nglib}`,
|
|
glob: '**/*',
|
|
output: '.',
|
|
});
|
|
|
|
updateFile(workspaceConfigName(), JSON.stringify(workspace));
|
|
|
|
runCLI(`build ${nglib}`);
|
|
runCLI(`build ${nodelib}`);
|
|
checkFilesExist(`./dist/libs/${nodelib}/esm2015/index.js`);
|
|
}, 60000);
|
|
|
|
it('should fail when trying to compile typescript files that are invalid', () => {
|
|
newProject();
|
|
const nodeLib = uniq('nodelib');
|
|
runCLI(
|
|
`generate @nrwl/node:lib ${nodeLib} --publishable --importPath=@proj/${nodeLib}`
|
|
);
|
|
updateFile(
|
|
`libs/${nodeLib}/src/index.ts`,
|
|
stripIndents`
|
|
const temp: number = 'should fail'
|
|
`
|
|
);
|
|
expect(() => runCLI(`build ${nodeLib}`)).toThrow();
|
|
});
|
|
});
|
|
|
|
describe('nest libraries', function () {
|
|
it('should be able to generate a nest library', async () => {
|
|
newProject();
|
|
const nestlib = uniq('nestlib');
|
|
|
|
runCLI(`generate @nrwl/nest:lib ${nestlib}`);
|
|
|
|
const jestConfigContent = readFile(`libs/${nestlib}/jest.config.js`);
|
|
|
|
expect(stripIndents`${jestConfigContent}`).toEqual(
|
|
stripIndents`module.exports = {
|
|
displayName: '${nestlib}',
|
|
preset: '../../jest.preset.js',
|
|
globals: {
|
|
'ts-jest': {
|
|
tsConfig: '<rootDir>/tsconfig.spec.json',
|
|
},
|
|
},
|
|
testEnvironment: 'node',
|
|
transform: {
|
|
'^.+\\.[tj]sx?$': 'ts-jest',
|
|
},
|
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
|
coverageDirectory: '../../coverage/libs/${nestlib}',
|
|
};
|
|
`
|
|
);
|
|
|
|
const lintResults = runCLI(`lint ${nestlib}`);
|
|
expect(lintResults).toContain('All files pass linting.');
|
|
}, 60000);
|
|
|
|
it('should be able to generate a nest library w/ service', async () => {
|
|
newProject();
|
|
const nestlib = uniq('nestlib');
|
|
|
|
runCLI(`generate @nrwl/nest:lib ${nestlib} --service`);
|
|
|
|
const lintResults = runCLI(`lint ${nestlib}`);
|
|
expect(lintResults).toContain('All files pass linting.');
|
|
|
|
const jestResult = await runCLIAsync(`test ${nestlib}`);
|
|
expect(jestResult.combinedOutput).toContain(
|
|
'Test Suites: 1 passed, 1 total'
|
|
);
|
|
}, 60000);
|
|
|
|
it('should be able to generate a nest library w/ controller', async () => {
|
|
newProject();
|
|
const nestlib = uniq('nestlib');
|
|
|
|
runCLI(`generate @nrwl/nest:lib ${nestlib} --controller`);
|
|
|
|
const lintResults = runCLI(`lint ${nestlib}`);
|
|
expect(lintResults).toContain('All files pass linting.');
|
|
|
|
const jestResult = await runCLIAsync(`test ${nestlib}`);
|
|
expect(jestResult.combinedOutput).toContain(
|
|
'Test Suites: 1 passed, 1 total'
|
|
);
|
|
}, 60000);
|
|
|
|
it('should be able to generate a nest library w/ controller and service', async () => {
|
|
newProject();
|
|
const nestlib = uniq('nestlib');
|
|
|
|
runCLI(`generate @nrwl/nest:lib ${nestlib} --controller --service`);
|
|
|
|
const lintResults = runCLI(`lint ${nestlib}`);
|
|
expect(lintResults).toContain('All files pass linting.');
|
|
|
|
const jestResult = await runCLIAsync(`test ${nestlib}`);
|
|
expect(jestResult.combinedOutput).toContain(
|
|
'Test Suites: 2 passed, 2 total'
|
|
);
|
|
}, 60000);
|
|
});
|
|
|
|
describe('with dependencies', () => {
|
|
/**
|
|
* Graph:
|
|
*
|
|
* childLib
|
|
* /
|
|
* app => parentLib =>
|
|
* \
|
|
* \
|
|
* childLib2
|
|
*
|
|
*/
|
|
let app: string;
|
|
let parentLib: string;
|
|
let childLib: string;
|
|
let childLib2: string;
|
|
|
|
beforeEach(() => {
|
|
app = uniq('app');
|
|
parentLib = uniq('parentlib');
|
|
childLib = uniq('childlib');
|
|
childLib2 = uniq('childlib2');
|
|
|
|
newProject();
|
|
|
|
runCLI(`generate @nrwl/express:app ${app}`);
|
|
runCLI(`generate @nrwl/node:lib ${parentLib} --buildable=true`);
|
|
runCLI(`generate @nrwl/node:lib ${childLib} --buildable=true`);
|
|
runCLI(`generate @nrwl/node:lib ${childLib2} --buildable=true`);
|
|
|
|
// create dependencies by importing
|
|
const createDep = (parent, children: string[]) => {
|
|
updateFile(
|
|
`libs/${parent}/src/lib/${parent}.ts`,
|
|
`
|
|
${children
|
|
.map((entry) => `import { ${entry} } from '@proj/${entry}';`)
|
|
.join('\n')}
|
|
|
|
export function ${parent}(): string {
|
|
return '${parent}' + ' ' + ${children
|
|
.map((entry) => `${entry}()`)
|
|
.join('+')}
|
|
}
|
|
`
|
|
);
|
|
};
|
|
|
|
createDep(parentLib, [childLib, childLib2]);
|
|
|
|
updateFile(
|
|
`apps/${app}/src/main.ts`,
|
|
`
|
|
import "@proj/${parentLib}";
|
|
`
|
|
);
|
|
|
|
// we are setting paths to {} to make sure built libs are read from dist
|
|
updateFile('tsconfig.base.json', (c) => {
|
|
const json = JSON.parse(c);
|
|
json.compilerOptions.paths = {};
|
|
return JSON.stringify(json, null, 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}`);
|
|
}
|
|
});
|
|
|
|
it('should build a library without dependencies', () => {
|
|
const childLibOutput = runCLI(`build ${childLib}`);
|
|
|
|
expect(childLibOutput).toContain(
|
|
`Done compiling TypeScript files for library ${childLib}`
|
|
);
|
|
});
|
|
|
|
it('should build a parent library if the dependent libraries have been built before', () => {
|
|
const childLibOutput = runCLI(`build ${childLib}`);
|
|
expect(childLibOutput).toContain(
|
|
`Done compiling TypeScript files for library ${childLib}`
|
|
);
|
|
|
|
const childLib2Output = runCLI(`build ${childLib2}`);
|
|
expect(childLib2Output).toContain(
|
|
`Done compiling TypeScript files for library ${childLib2}`
|
|
);
|
|
|
|
const parentLibOutput = runCLI(`build ${parentLib}`);
|
|
expect(parentLibOutput).toContain(
|
|
`Done compiling TypeScript files for library ${parentLib}`
|
|
);
|
|
|
|
// assert package.json deps have been set
|
|
const assertPackageJson = (
|
|
parent: string,
|
|
lib: string,
|
|
version: string
|
|
) => {
|
|
const jsonFile = readJson(`dist/libs/${parent}/package.json`);
|
|
const childDependencyVersion = jsonFile.dependencies[`@proj/${lib}`];
|
|
expect(childDependencyVersion).toBe(version);
|
|
};
|
|
|
|
assertPackageJson(parentLib, childLib, '0.0.1');
|
|
assertPackageJson(parentLib, childLib2, '0.0.1');
|
|
});
|
|
|
|
it('should build an app composed out of buildable libs', () => {
|
|
const buildWithDeps = runCLI(
|
|
`build ${app} --with-deps --buildLibsFromSource=false`
|
|
);
|
|
expect(buildWithDeps).toContain(`Running target "build" succeeded`);
|
|
checkFilesDoNotExist(`apps/${app}/tsconfig/tsconfig.nx-tmp`);
|
|
|
|
// we remove all path mappings from the root tsconfig, so when trying to build
|
|
// libs from source, the builder will throw
|
|
const failedBuild = runCLI(
|
|
`build ${app} --with-deps --buildLibsFromSource`,
|
|
{ silenceError: true }
|
|
);
|
|
expect(failedBuild).toContain(`Can't resolve`);
|
|
}, 1000000);
|
|
});
|