cleanup(angular): consolidate and improve e2e-angular-core tests (#15726)
This commit is contained in:
parent
db20f655d9
commit
9dbc90d45e
@ -1,79 +0,0 @@
|
|||||||
import {
|
|
||||||
cleanupProject,
|
|
||||||
newProject,
|
|
||||||
runCLI,
|
|
||||||
uniq,
|
|
||||||
updateFile,
|
|
||||||
} from '@nrwl/e2e/utils';
|
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
describe('Angular Package', () => {
|
|
||||||
describe('linting', () => {
|
|
||||||
beforeAll(() => newProject());
|
|
||||||
afterAll(() => cleanupProject());
|
|
||||||
|
|
||||||
it('should support eslint and pass linting on the standard generated code', async () => {
|
|
||||||
const myapp = uniq('myapp');
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/angular:app ${myapp} --linter=eslint --no-interactive`
|
|
||||||
);
|
|
||||||
expect(runCLI(`lint ${myapp}`)).toContain('All files pass linting.');
|
|
||||||
|
|
||||||
const mylib = uniq('mylib');
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/angular:lib ${mylib} --linter=eslint --no-interactive`
|
|
||||||
);
|
|
||||||
expect(runCLI(`lint ${mylib}`)).toContain('All files pass linting.');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should support eslint and successfully lint external HTML files and inline templates', async () => {
|
|
||||||
const myapp = uniq('myapp');
|
|
||||||
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/angular:app ${myapp} --linter=eslint --no-interactive`
|
|
||||||
);
|
|
||||||
|
|
||||||
const templateWhichFailsBananaInBoxLintCheck = `<div ([foo])="bar"></div>`;
|
|
||||||
const wrappedAsInlineTemplate = `
|
|
||||||
import { Component } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'inline-template-component',
|
|
||||||
template: \`
|
|
||||||
${templateWhichFailsBananaInBoxLintCheck}
|
|
||||||
\`,
|
|
||||||
})
|
|
||||||
export class InlineTemplateComponent {}
|
|
||||||
`;
|
|
||||||
|
|
||||||
// External HTML template file
|
|
||||||
updateFile(
|
|
||||||
`apps/${myapp}/src/app/app.component.html`,
|
|
||||||
templateWhichFailsBananaInBoxLintCheck
|
|
||||||
);
|
|
||||||
|
|
||||||
// Inline template within component.ts file
|
|
||||||
updateFile(
|
|
||||||
`apps/${myapp}/src/app/inline-template.component.ts`,
|
|
||||||
wrappedAsInlineTemplate
|
|
||||||
);
|
|
||||||
|
|
||||||
const appLintStdOut = runCLI(`lint ${myapp}`, { silenceError: true });
|
|
||||||
expect(appLintStdOut).toContain(
|
|
||||||
path.normalize(`apps/${myapp}/src/app/app.component.html`)
|
|
||||||
);
|
|
||||||
expect(appLintStdOut).toContain(`1:6`);
|
|
||||||
expect(appLintStdOut).toContain(`Invalid binding syntax`);
|
|
||||||
expect(appLintStdOut).toContain(
|
|
||||||
path.normalize(`apps/${myapp}/src/app/inline-template.component.ts`)
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(appLintStdOut).toContain(`5:21`);
|
|
||||||
expect(appLintStdOut).toContain(
|
|
||||||
`The selector should start with one of these prefixes`
|
|
||||||
);
|
|
||||||
expect(appLintStdOut).toContain(`7:18`);
|
|
||||||
expect(appLintStdOut).toContain(`Invalid binding syntax`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,151 +1,169 @@
|
|||||||
import {
|
import {
|
||||||
|
checkFilesExist,
|
||||||
cleanupProject,
|
cleanupProject,
|
||||||
expectTestsPass,
|
|
||||||
newProject,
|
newProject,
|
||||||
|
removeFile,
|
||||||
runCLI,
|
runCLI,
|
||||||
runCLIAsync,
|
|
||||||
uniq,
|
uniq,
|
||||||
updateFile,
|
updateFile,
|
||||||
} from '@nrwl/e2e/utils';
|
} from '@nrwl/e2e/utils';
|
||||||
|
|
||||||
describe('Angular Config', () => {
|
describe('angular.json v1 config', () => {
|
||||||
beforeAll(() => newProject());
|
const app1 = uniq('app1');
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
newProject();
|
||||||
|
runCLI(`generate @nrwl/angular:app ${app1} --no-interactive`);
|
||||||
|
// reset workspace to use v1 config
|
||||||
|
updateFile(`angular.json`, angularV1Json(app1));
|
||||||
|
removeFile(`apps/${app1}/project.json`);
|
||||||
|
removeFile(`apps/${app1}-e2e/project.json`);
|
||||||
|
});
|
||||||
afterAll(() => cleanupProject());
|
afterAll(() => cleanupProject());
|
||||||
|
|
||||||
it('should upgrade the config correctly', async () => {
|
it('should support projects in angular.json v1 config', async () => {
|
||||||
const myapp = uniq('myapp');
|
expect(runCLI(`build ${app1}`)).toContain('Successfully ran target build');
|
||||||
runCLI(`generate @nrwl/angular:app ${myapp} --no-interactive`);
|
expect(runCLI(`test ${app1} --no-watch`)).toContain(
|
||||||
|
'Successfully ran target test'
|
||||||
|
);
|
||||||
|
}, 1000000);
|
||||||
|
|
||||||
// update the angular.json, first reset to v1 config
|
it('should generate new app with project.json and keep the existing in angular.json', async () => {
|
||||||
updateFile(`angular.json`, angularV1Json(myapp));
|
// create new app
|
||||||
|
const app2 = uniq('app2');
|
||||||
|
runCLI(`generate @nrwl/angular:app ${app2} --no-interactive`);
|
||||||
|
|
||||||
const myapp2 = uniq('myapp');
|
// should generate project.json for new projects
|
||||||
runCLI(`generate @nrwl/angular:app ${myapp2} --no-interactive`);
|
checkFilesExist(`apps/${app2}/project.json`);
|
||||||
expectTestsPass(await runCLIAsync(`test ${myapp2} --no-watch`));
|
// check it works correctly
|
||||||
|
expect(runCLI(`build ${app2}`)).toContain('Successfully ran target build');
|
||||||
|
expect(runCLI(`test ${app2} --no-watch`)).toContain(
|
||||||
|
'Successfully ran target test'
|
||||||
|
);
|
||||||
|
// check existing app in angular.json still works
|
||||||
|
expect(runCLI(`build ${app1}`)).toContain('Successfully ran target build');
|
||||||
|
expect(runCLI(`test ${app1} --no-watch`)).toContain(
|
||||||
|
'Successfully ran target test'
|
||||||
|
);
|
||||||
}, 1000000);
|
}, 1000000);
|
||||||
});
|
});
|
||||||
|
|
||||||
const angularV1Json = (appName: string) => `{
|
const angularV1Json = (appName: string) => `{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"projects": {
|
"projects": {
|
||||||
"${appName}": {
|
"${appName}": {
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"root": "apps/${appName}",
|
"root": "apps/${appName}",
|
||||||
"sourceRoot": "apps/${appName}/src",
|
"sourceRoot": "apps/${appName}/src",
|
||||||
"prefix": "v1anuglar",
|
"prefix": "v1angular",
|
||||||
"architect": {
|
"architect": {
|
||||||
"build": {
|
"build": {
|
||||||
"builder": "@angular-devkit/build-angular:browser",
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
"outputs": ["{options.outputPath}"],
|
"outputs": ["{options.outputPath}"],
|
||||||
"options": {
|
"options": {
|
||||||
"outputPath": "dist/apps/${appName}",
|
"outputPath": "dist/apps/${appName}",
|
||||||
"index": "apps/${appName}/src/index.html",
|
"index": "apps/${appName}/src/index.html",
|
||||||
"main": "apps/${appName}/src/main.ts",
|
"main": "apps/${appName}/src/main.ts",
|
||||||
"polyfills": "apps/${appName}/src/polyfills.ts",
|
"polyfills": ["zone.js"],
|
||||||
"tsConfig": "apps/${appName}/tsconfig.app.json",
|
"tsConfig": "apps/${appName}/tsconfig.app.json",
|
||||||
"assets": ["apps/${appName}/src/favicon.ico", "apps/${appName}/src/assets"],
|
"assets": ["apps/${appName}/src/favicon.ico", "apps/${appName}/src/assets"],
|
||||||
"styles": ["apps/${appName}/src/styles.css"],
|
"styles": ["apps/${appName}/src/styles.css"],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"budgets": [
|
|
||||||
{
|
|
||||||
"type": "initial",
|
|
||||||
"maximumWarning": "500kb",
|
|
||||||
"maximumError": "1mb"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "anyComponentStyle",
|
|
||||||
"maximumWarning": "2kb",
|
|
||||||
"maximumError": "4kb"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"fileReplacements": [
|
|
||||||
{
|
|
||||||
"replace": "apps/${appName}/src/environments/environment.ts",
|
|
||||||
"with": "apps/${appName}/src/environments/environment.prod.ts"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outputHashing": "all"
|
|
||||||
},
|
|
||||||
"development": {
|
|
||||||
"buildOptimizer": false,
|
|
||||||
"optimization": false,
|
|
||||||
"vendorChunk": true,
|
|
||||||
"extractLicenses": false,
|
|
||||||
"sourceMap": true,
|
|
||||||
"namedChunks": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"defaultConfiguration": "production"
|
|
||||||
},
|
},
|
||||||
"serve": {
|
"configurations": {
|
||||||
"builder": "@angular-devkit/build-angular:dev-server",
|
"production": {
|
||||||
"configurations": {
|
"budgets": [
|
||||||
"production": {
|
{
|
||||||
"browserTarget": "${appName}:build:production"
|
"type": "initial",
|
||||||
},
|
"maximumWarning": "500kb",
|
||||||
"development": {
|
"maximumError": "1mb"
|
||||||
"browserTarget": "${appName}:build:development"
|
},
|
||||||
}
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "2kb",
|
||||||
|
"maximumError": "4kb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputHashing": "all"
|
||||||
},
|
},
|
||||||
"defaultConfiguration": "development"
|
"development": {
|
||||||
},
|
"buildOptimizer": false,
|
||||||
"extract-i18n": {
|
"optimization": false,
|
||||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
"vendorChunk": true,
|
||||||
"options": {
|
"extractLicenses": false,
|
||||||
"browserTarget": "${appName}:build"
|
"sourceMap": true,
|
||||||
|
"namedChunks": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"defaultConfiguration": "production"
|
||||||
"builder": "@nrwl/linter:eslint",
|
},
|
||||||
"options": {
|
"serve": {
|
||||||
"lintFilePatterns": [
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
"apps/${appName}/src/**/*.ts",
|
"configurations": {
|
||||||
"apps/${appName}/src/**/*.html"
|
"production": {
|
||||||
]
|
"browserTarget": "${appName}:build:production"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"browserTarget": "${appName}:build:development"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"test": {
|
"defaultConfiguration": "development"
|
||||||
"builder": "@nrwl/jest:jest",
|
},
|
||||||
"outputs": ["coverage/apps/${appName}"],
|
"extract-i18n": {
|
||||||
"options": {
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
"jestConfig": "apps/${appName}/jest.config.ts",
|
"options": {
|
||||||
"passWithNoTests": true
|
"browserTarget": "${appName}:build"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tags": []
|
"lint": {
|
||||||
|
"builder": "@nrwl/linter:eslint",
|
||||||
|
"options": {
|
||||||
|
"lintFilePatterns": [
|
||||||
|
"apps/${appName}/src/**/*.ts",
|
||||||
|
"apps/${appName}/src/**/*.html"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@nrwl/jest:jest",
|
||||||
|
"outputs": ["coverage/apps/${appName}"],
|
||||||
|
"options": {
|
||||||
|
"jestConfig": "apps/${appName}/jest.config.ts",
|
||||||
|
"passWithNoTests": true
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"${appName}-e2e": {
|
"tags": []
|
||||||
"root": "apps/${appName}-e2e",
|
},
|
||||||
"sourceRoot": "apps/${appName}-e2e/src",
|
"${appName}-e2e": {
|
||||||
"projectType": "application",
|
"root": "apps/${appName}-e2e",
|
||||||
"architect": {
|
"sourceRoot": "apps/${appName}-e2e/src",
|
||||||
"e2e": {
|
"projectType": "application",
|
||||||
"builder": "@nrwl/cypress:cypress",
|
"architect": {
|
||||||
"options": {
|
"e2e": {
|
||||||
"cypressConfig": "apps/${appName}-e2e/cypress.json",
|
"builder": "@nrwl/cypress:cypress",
|
||||||
"devServerTarget": "${appName}:serve:development"
|
"options": {
|
||||||
},
|
"cypressConfig": "apps/${appName}-e2e/cypress.json",
|
||||||
"configurations": {
|
"devServerTarget": "${appName}:serve:development",
|
||||||
"production": {
|
"testingType": "e2e"
|
||||||
"devServerTarget": "${appName}:serve:production"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"lint": {
|
"configurations": {
|
||||||
"builder": "@nrwl/linter:eslint",
|
"production": {
|
||||||
"outputs": ["{options.outputFile}"],
|
"devServerTarget": "${appName}:serve:production"
|
||||||
"options": {
|
|
||||||
"lintFilePatterns": ["apps/${appName}-e2e/**/*.{js,ts}"]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tags": [],
|
"lint": {
|
||||||
"implicitDependencies": ["${appName}"]
|
"builder": "@nrwl/linter:eslint",
|
||||||
}
|
"outputs": ["{options.outputFile}"],
|
||||||
|
"options": {
|
||||||
|
"lintFilePatterns": ["apps/${appName}-e2e/**/*.{js,ts}"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [],
|
||||||
|
"implicitDependencies": ["${appName}"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@ -1,61 +1,58 @@
|
|||||||
|
import { names } from '@nrwl/devkit';
|
||||||
import {
|
import {
|
||||||
cleanupProject,
|
cleanupProject,
|
||||||
killPort,
|
killProcessAndPorts,
|
||||||
newProject,
|
newProject,
|
||||||
promisifiedTreeKill,
|
|
||||||
readProjectConfig,
|
readProjectConfig,
|
||||||
runCLI,
|
runCLI,
|
||||||
runCommandUntil,
|
runCommandUntil,
|
||||||
uniq,
|
uniq,
|
||||||
updateFile,
|
updateFile,
|
||||||
updateProjectConfig,
|
|
||||||
} from '@nrwl/e2e/utils';
|
} from '@nrwl/e2e/utils';
|
||||||
import { ChildProcess } from 'child_process';
|
|
||||||
|
|
||||||
import { names } from '@nrwl/devkit';
|
describe('Angular Module Federation', () => {
|
||||||
|
|
||||||
describe('Angular Projects', () => {
|
|
||||||
let proj: string;
|
let proj: string;
|
||||||
let oldValue;
|
let oldVerboseLoggingValue: string;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
proj = newProject();
|
proj = newProject();
|
||||||
oldValue = process.env.NX_E2E_VERBOSE_LOGGING;
|
oldVerboseLoggingValue = process.env.NX_E2E_VERBOSE_LOGGING;
|
||||||
process.env.NX_E2E_VERBOSE_LOGGING = 'true';
|
process.env.NX_E2E_VERBOSE_LOGGING = 'true';
|
||||||
});
|
});
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
cleanupProject();
|
cleanupProject();
|
||||||
process.env.NX_E2E_VERBOSE_LOGGING = oldValue;
|
process.env.NX_E2E_VERBOSE_LOGGING = oldVerboseLoggingValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should serve the host and remote apps successfully, even with a shared library with a secondary entry point between them', async () => {
|
it('should generate valid host and remote apps', async () => {
|
||||||
// ACT + ASSERT
|
|
||||||
const port1 = 4200;
|
|
||||||
const port2 = 4206;
|
|
||||||
const hostApp = uniq('app');
|
const hostApp = uniq('app');
|
||||||
const remoteApp1 = uniq('remote');
|
const remoteApp1 = uniq('remote');
|
||||||
const sharedLib = uniq('shared-lib');
|
const sharedLib = uniq('shared-lib');
|
||||||
const secondaryEntry = uniq('secondary');
|
const secondaryEntry = uniq('secondary');
|
||||||
|
const hostPort = 4300;
|
||||||
|
const remotePort = 4301;
|
||||||
|
|
||||||
// generate host app
|
// generate host app
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/angular:host ${hostApp} --style=css --no-interactive`
|
`generate @nrwl/angular:host ${hostApp} --style=css --no-interactive`
|
||||||
);
|
);
|
||||||
|
// generate remote app
|
||||||
// generate remote apps
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/angular:remote ${remoteApp1} --host=${hostApp} --port=${port2} --style=css --no-interactive`
|
`generate @nrwl/angular:remote ${remoteApp1} --host=${hostApp} --port=${remotePort} --style=css --no-interactive`
|
||||||
);
|
);
|
||||||
|
|
||||||
// generate a shared lib
|
// check default generated host is built successfully
|
||||||
|
const buildOutput = runCLI(`build ${hostApp}`);
|
||||||
|
expect(buildOutput).toContain('Successfully ran target build');
|
||||||
|
|
||||||
|
// generate a shared lib with a seconary entry point
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/angular:library ${sharedLib} --buildable --no-interactive`
|
`generate @nrwl/angular:library ${sharedLib} --buildable --no-interactive`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/angular:library-secondary-entry-point --library=${sharedLib} --name=${secondaryEntry} --no-interactive`
|
`generate @nrwl/angular:library-secondary-entry-point --library=${sharedLib} --name=${secondaryEntry} --no-interactive`
|
||||||
);
|
);
|
||||||
|
// update host & remote files to use shared library
|
||||||
// update the files to use shared library
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${hostApp}/src/app/app.module.ts`,
|
`apps/${hostApp}/src/app/app.module.ts`,
|
||||||
`import { NgModule } from '@angular/core';
|
`import { NgModule } from '@angular/core';
|
||||||
@ -123,169 +120,79 @@ describe('Angular Projects', () => {
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
let process: ChildProcess;
|
const process = await runCommandUntil(
|
||||||
|
`serve ${hostApp} --port=${hostPort} --dev-remotes=${remoteApp1}`,
|
||||||
try {
|
(output) =>
|
||||||
process = await runCommandUntil(
|
output.includes(`listening on localhost:${remotePort}`) &&
|
||||||
`serve ${hostApp} --dev-remotes=${remoteApp1}`,
|
output.includes(`listening on localhost:${hostPort}`)
|
||||||
(output) => {
|
|
||||||
return (
|
|
||||||
output.includes(`listening on localhost:${port2}`) &&
|
|
||||||
output.includes(`listening on localhost:${port1}`)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// port and process cleanup
|
|
||||||
try {
|
|
||||||
if (process && process.pid) {
|
|
||||||
await promisifiedTreeKill(process.pid, 'SIGKILL');
|
|
||||||
}
|
|
||||||
await killPort(port1);
|
|
||||||
await killPort(port2);
|
|
||||||
} catch (err) {
|
|
||||||
expect(err).toBeFalsy();
|
|
||||||
}
|
|
||||||
}, 300000);
|
|
||||||
|
|
||||||
it('should build the host app successfully', async () => {
|
|
||||||
// ARRANGE
|
|
||||||
const hostApp = uniq('app');
|
|
||||||
const remoteApp1 = uniq('remote');
|
|
||||||
|
|
||||||
// generate host app
|
|
||||||
runCLI(`generate @nrwl/angular:host ${hostApp} --no-interactive`);
|
|
||||||
|
|
||||||
// generate remote apps
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/angular:remote ${remoteApp1} --host=${hostApp} --no-interactive`
|
|
||||||
);
|
|
||||||
|
|
||||||
// ACT
|
|
||||||
const buildOutput = runCLI(`build ${hostApp}`);
|
|
||||||
|
|
||||||
// ASSERT
|
|
||||||
expect(buildOutput).toContain('Successfully ran target build');
|
|
||||||
}, 300000);
|
|
||||||
|
|
||||||
it('should serve a ssr remote app successfully', async () => {
|
|
||||||
// ARRANGE
|
|
||||||
const remoteApp1 = uniq('remote');
|
|
||||||
// generate remote apps
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/angular:remote ${remoteApp1} --ssr --no-interactive`
|
|
||||||
);
|
|
||||||
|
|
||||||
const port = 4301;
|
|
||||||
|
|
||||||
let process = await runCommandUntil(
|
|
||||||
`serve-ssr ${remoteApp1} --port=${port}`,
|
|
||||||
(output) => {
|
|
||||||
return (
|
|
||||||
output.includes(`Browser application bundle generation complete.`) &&
|
|
||||||
output.includes(`Server application bundle generation complete.`) &&
|
|
||||||
output.includes(
|
|
||||||
`Angular Universal Live Development Server is listening`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// port and process cleanup
|
// port and process cleanup
|
||||||
try {
|
await killProcessAndPorts(process.pid, hostPort, remotePort);
|
||||||
if (process && process.pid) {
|
}, 300000);
|
||||||
await promisifiedTreeKill(process.pid, 'SIGKILL');
|
|
||||||
}
|
it('should convert apps to MF successfully', async () => {
|
||||||
await killPort(port);
|
const app1 = uniq('app1');
|
||||||
} catch (err) {
|
const app2 = uniq('app2');
|
||||||
expect(err).toBeFalsy();
|
const app1Port = 4400;
|
||||||
}
|
const app2Port = 4401;
|
||||||
}, 10_000_000);
|
|
||||||
|
// generate apps
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/angular:application ${app1} --routing --no-interactive`
|
||||||
|
);
|
||||||
|
runCLI(`generate @nrwl/angular:application ${app2} --no-interactive`);
|
||||||
|
|
||||||
|
// convert apps
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/angular:setup-mf ${app1} --mfType=host --port=${app1Port} --no-interactive`
|
||||||
|
);
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/angular:setup-mf ${app2} --mfType=remote --host=${app1} --port=${app2Port} --no-interactive`
|
||||||
|
);
|
||||||
|
|
||||||
|
const process = await runCommandUntil(
|
||||||
|
`serve ${app1} --dev-remotes=${app2}`,
|
||||||
|
(output) =>
|
||||||
|
output.includes(`listening on localhost:${app1Port}`) &&
|
||||||
|
output.includes(`listening on localhost:${app2Port}`)
|
||||||
|
);
|
||||||
|
|
||||||
|
// port and process cleanup
|
||||||
|
await killProcessAndPorts(process.pid, app1Port, app2Port);
|
||||||
|
}, 20_000_000);
|
||||||
|
|
||||||
// TODO(colum): enable when this issue is resolved https://github.com/module-federation/universe/issues/604
|
// TODO(colum): enable when this issue is resolved https://github.com/module-federation/universe/issues/604
|
||||||
xit('should scaffold a ssr MF setup successfully', async () => {
|
xit('should scaffold MF + SSR setup successfully', async () => {
|
||||||
// ARRANGE
|
const host = uniq('host');
|
||||||
const remoteApp1 = uniq('remote1');
|
const remote1 = uniq('remote1');
|
||||||
const remoteApp2 = uniq('remote2');
|
const remote2 = uniq('remote2');
|
||||||
const hostApp = uniq('host1');
|
|
||||||
// generate remote apps
|
// generate remote apps
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/angular:host ${hostApp} --ssr --remotes=${remoteApp1},${remoteApp2} --no-interactive`
|
`generate @nrwl/angular:host ${host} --ssr --remotes=${remote1},${remote2} --no-interactive`
|
||||||
);
|
);
|
||||||
|
|
||||||
// ports
|
// ports
|
||||||
const remoteApp1Port =
|
const hostPort = 4500;
|
||||||
readProjectConfig(remoteApp1).targets.serve.options.port;
|
const remote1Port = readProjectConfig(remote1).targets.serve.options.port;
|
||||||
const remoteApp2Port =
|
const remote2Port = readProjectConfig(remote2).targets.serve.options.port;
|
||||||
readProjectConfig(remoteApp2).targets.serve.options.port;
|
|
||||||
|
|
||||||
const port = 4401;
|
const process = await runCommandUntil(
|
||||||
|
`serve-ssr ${host} --port=${hostPort}`,
|
||||||
let process = await runCommandUntil(
|
(output) =>
|
||||||
`serve-ssr ${hostApp} --port=${port}`,
|
output.includes(
|
||||||
(output) => {
|
`Node Express server listening on http://localhost:${remote1Port}`
|
||||||
return (
|
) &&
|
||||||
output.includes(
|
output.includes(
|
||||||
`Node Express server listening on http://localhost:${remoteApp1Port}`
|
`Node Express server listening on http://localhost:${remote2Port}`
|
||||||
) &&
|
) &&
|
||||||
output.includes(
|
output.includes(
|
||||||
`Node Express server listening on http://localhost:${remoteApp2Port}`
|
`Angular Universal Live Development Server is listening`
|
||||||
) &&
|
)
|
||||||
output.includes(
|
|
||||||
`Angular Universal Live Development Server is listening`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// port and process cleanup
|
// port and process cleanup
|
||||||
try {
|
await killProcessAndPorts(process.pid, hostPort, remote1Port, remote2Port);
|
||||||
if (process && process.pid) {
|
|
||||||
await promisifiedTreeKill(process.pid, 'SIGKILL');
|
|
||||||
}
|
|
||||||
await killPort(port);
|
|
||||||
await killPort(remoteApp1Port);
|
|
||||||
await killPort(remoteApp2Port);
|
|
||||||
} catch (err) {
|
|
||||||
expect(err).toBeFalsy();
|
|
||||||
}
|
|
||||||
}, 20_000_000);
|
}, 20_000_000);
|
||||||
|
|
||||||
it('Custom Webpack Config for SSR - should serve the app correctly', async () => {
|
|
||||||
// ARRANGE
|
|
||||||
const ssrApp = uniq('app');
|
|
||||||
|
|
||||||
runCLI(`generate @nrwl/angular:app ${ssrApp} --no-interactive`);
|
|
||||||
runCLI(`generate @nrwl/angular:setup-ssr ${ssrApp} --no-interactive`);
|
|
||||||
|
|
||||||
updateProjectConfig(ssrApp, (project) => {
|
|
||||||
project.targets.server.executor = '@nrwl/angular:webpack-server';
|
|
||||||
return project;
|
|
||||||
});
|
|
||||||
|
|
||||||
const port = 4501;
|
|
||||||
|
|
||||||
// ACT
|
|
||||||
let process = await runCommandUntil(
|
|
||||||
`serve-ssr ${ssrApp} --port=${port}`,
|
|
||||||
(output) => {
|
|
||||||
return output.includes(
|
|
||||||
`Angular Universal Live Development Server is listening on http://localhost:${port}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// port and process cleanup
|
|
||||||
try {
|
|
||||||
if (process && process.pid) {
|
|
||||||
await promisifiedTreeKill(process.pid, 'SIGKILL');
|
|
||||||
}
|
|
||||||
await killPort(port);
|
|
||||||
} catch (err) {
|
|
||||||
expect(err).toBeFalsy();
|
|
||||||
}
|
|
||||||
}, 300000);
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -64,11 +64,10 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
project = uniq('proj');
|
|
||||||
packageManager = getSelectedPackageManager();
|
packageManager = getSelectedPackageManager();
|
||||||
// TODO: solve issues with pnpm and remove this fallback
|
// TODO: solve issues with pnpm and remove this fallback
|
||||||
packageManager = packageManager === 'pnpm' ? 'yarn' : packageManager;
|
packageManager = packageManager === 'pnpm' ? 'yarn' : packageManager;
|
||||||
runNgNew(project, packageManager);
|
project = runNgNew(packageManager);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@ -436,55 +435,12 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support a workspace with multiple libraries', () => {
|
it('should support a workspace with multiple projects', () => {
|
||||||
// add some libraries
|
// add other projects
|
||||||
const lib1 = uniq('lib1');
|
|
||||||
const lib2 = uniq('lib2');
|
|
||||||
runCommand(`ng g @schematics/angular:library ${lib1}`);
|
|
||||||
runCommand(`ng g @schematics/angular:library ${lib2}`);
|
|
||||||
|
|
||||||
runNgAdd('@nrwl/angular', '--npm-scope projscope');
|
|
||||||
|
|
||||||
// check angular.json does not exist
|
|
||||||
checkFilesDoNotExist('angular.json');
|
|
||||||
|
|
||||||
// check building lib1
|
|
||||||
let output = runCLI(`build ${lib1}`);
|
|
||||||
expect(output).toContain(`> nx run ${lib1}:build:production`);
|
|
||||||
expect(output).toContain(
|
|
||||||
`Successfully ran target build for project ${lib1}`
|
|
||||||
);
|
|
||||||
checkFilesExist(`dist/${lib1}/package.json`);
|
|
||||||
|
|
||||||
output = runCLI(`build ${lib1}`);
|
|
||||||
expect(output).toContain(
|
|
||||||
`> nx run ${lib1}:build:production [local cache]`
|
|
||||||
);
|
|
||||||
expect(output).toContain(
|
|
||||||
`Successfully ran target build for project ${lib1}`
|
|
||||||
);
|
|
||||||
|
|
||||||
// check building lib2
|
|
||||||
output = runCLI(`build ${lib2}`);
|
|
||||||
expect(output).toContain(`> nx run ${lib2}:build:production`);
|
|
||||||
expect(output).toContain(
|
|
||||||
`Successfully ran target build for project ${lib2}`
|
|
||||||
);
|
|
||||||
checkFilesExist(`dist/${lib2}/package.json`);
|
|
||||||
|
|
||||||
output = runCLI(`build ${lib2}`);
|
|
||||||
expect(output).toContain(
|
|
||||||
`> nx run ${lib2}:build:production [local cache]`
|
|
||||||
);
|
|
||||||
expect(output).toContain(
|
|
||||||
`Successfully ran target build for project ${lib2}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should support a workspace with multiple applications', () => {
|
|
||||||
// add another app
|
|
||||||
const app1 = uniq('app1');
|
const app1 = uniq('app1');
|
||||||
|
const lib1 = uniq('lib1');
|
||||||
runCommand(`ng g @schematics/angular:application ${app1}`);
|
runCommand(`ng g @schematics/angular:application ${app1}`);
|
||||||
|
runCommand(`ng g @schematics/angular:library ${lib1}`);
|
||||||
|
|
||||||
runNgAdd('@nrwl/angular', '--npm-scope projscope');
|
runNgAdd('@nrwl/angular', '--npm-scope projscope');
|
||||||
|
|
||||||
@ -526,5 +482,21 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
|
|||||||
expect(output).toContain(
|
expect(output).toContain(
|
||||||
`Successfully ran target build for project ${app1}`
|
`Successfully ran target build for project ${app1}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// check building lib1
|
||||||
|
output = runCLI(`build ${lib1}`);
|
||||||
|
expect(output).toContain(`> nx run ${lib1}:build:production`);
|
||||||
|
expect(output).toContain(
|
||||||
|
`Successfully ran target build for project ${lib1}`
|
||||||
|
);
|
||||||
|
checkFilesExist(`dist/${lib1}/package.json`);
|
||||||
|
|
||||||
|
output = runCLI(`build ${lib1}`);
|
||||||
|
expect(output).toContain(
|
||||||
|
`> nx run ${lib1}:build:production [local cache]`
|
||||||
|
);
|
||||||
|
expect(output).toContain(
|
||||||
|
`Successfully ran target build for project ${lib1}`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,45 +0,0 @@
|
|||||||
import * as isCI from 'is-ci';
|
|
||||||
import {
|
|
||||||
checkFilesExist,
|
|
||||||
getSelectedPackageManager,
|
|
||||||
packageInstall,
|
|
||||||
readJson,
|
|
||||||
runCommand,
|
|
||||||
runNgNew,
|
|
||||||
tmpProjPath,
|
|
||||||
uniq,
|
|
||||||
updateFile,
|
|
||||||
} from '@nrwl/e2e/utils';
|
|
||||||
import { PackageManager } from 'nx/src/utils/package-manager';
|
|
||||||
import { removeSync } from 'fs-extra';
|
|
||||||
|
|
||||||
describe('using Nx executors and generators with Angular CLI', () => {
|
|
||||||
let project: string;
|
|
||||||
let packageManager: PackageManager;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
project = uniq('proj');
|
|
||||||
packageManager = getSelectedPackageManager();
|
|
||||||
runNgNew(project, packageManager);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
if (isCI) {
|
|
||||||
try {
|
|
||||||
removeSync(tmpProjPath());
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should convert Nx executors into Angular CLI compatible builders', () => {
|
|
||||||
packageInstall('@nrwl/angular');
|
|
||||||
const angularJson = readJson('angular.json');
|
|
||||||
angularJson.projects[project].architect.build.builder =
|
|
||||||
'@nrwl/angular:webpack-browser';
|
|
||||||
updateFile('angular.json', JSON.stringify(angularJson, null, 2));
|
|
||||||
|
|
||||||
runCommand(`npx ng build ${project} --configuration=development`);
|
|
||||||
|
|
||||||
checkFilesExist(`dist/${project}/main.js`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,11 +1,13 @@
|
|||||||
|
import { names } from '@nrwl/devkit';
|
||||||
import {
|
import {
|
||||||
checkFilesExist,
|
checkFilesExist,
|
||||||
cleanupProject,
|
cleanupProject,
|
||||||
getSize,
|
getSize,
|
||||||
killPorts,
|
killPorts,
|
||||||
|
killProcessAndPorts,
|
||||||
newProject,
|
newProject,
|
||||||
promisifiedTreeKill,
|
|
||||||
readFile,
|
readFile,
|
||||||
|
removeFile,
|
||||||
runCLI,
|
runCLI,
|
||||||
runCommandUntil,
|
runCommandUntil,
|
||||||
runCypressTests,
|
runCypressTests,
|
||||||
@ -14,95 +16,151 @@ import {
|
|||||||
updateFile,
|
updateFile,
|
||||||
updateProjectConfig,
|
updateProjectConfig,
|
||||||
} from '@nrwl/e2e/utils';
|
} from '@nrwl/e2e/utils';
|
||||||
|
import { normalize } from 'path';
|
||||||
import { names } from '@nrwl/devkit';
|
|
||||||
|
|
||||||
describe('Angular Projects', () => {
|
describe('Angular Projects', () => {
|
||||||
let proj: string;
|
let proj: string;
|
||||||
|
const app1 = uniq('app1');
|
||||||
|
const lib1 = uniq('lib1');
|
||||||
|
let app1DefaultModule: string;
|
||||||
|
let app1DefaultComponentTemplate: string;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
proj = newProject();
|
||||||
|
runCLI(`generate @nrwl/angular:app ${app1} --no-interactive`);
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/angular:lib ${lib1} --add-module-spec --no-interactive`
|
||||||
|
);
|
||||||
|
app1DefaultModule = readFile(`apps/${app1}/src/app/app.module.ts`);
|
||||||
|
app1DefaultComponentTemplate = readFile(
|
||||||
|
`apps/${app1}/src/app/app.component.html`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
updateFile(`apps/${app1}/src/app/app.module.ts`, app1DefaultModule);
|
||||||
|
updateFile(
|
||||||
|
`apps/${app1}/src/app/app.component.html`,
|
||||||
|
app1DefaultComponentTemplate
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
beforeAll(() => (proj = newProject()));
|
|
||||||
afterAll(() => cleanupProject());
|
afterAll(() => cleanupProject());
|
||||||
|
|
||||||
it('should generate an app, a lib, link them, build, serve and test both correctly', async () => {
|
it('should successfully generate apps and libs and work correctly', async () => {
|
||||||
const myapp = uniq('myapp');
|
const standaloneApp = uniq('standalone-app');
|
||||||
const myapp2 = uniq('myapp2');
|
|
||||||
const mylib = uniq('mylib');
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/angular:app ${myapp} --directory=myDir --no-interactive`
|
`generate @nrwl/angular:app ${standaloneApp} --directory=myDir --standalone=true --no-interactive`
|
||||||
);
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/angular:app ${myapp2} --standalone=true --directory=myDir --no-interactive`
|
|
||||||
);
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/angular:lib ${mylib} --directory=myDir --add-module-spec --no-interactive`
|
|
||||||
);
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/my-dir/${myapp}/src/app/app.module.ts`,
|
`apps/${app1}/src/app/app.module.ts`,
|
||||||
|
`
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { ${names(lib1).className}Module } from '@${proj}/${lib1}';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { NxWelcomeComponent } from './nx-welcome.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [BrowserModule, ${names(lib1).className}Module],
|
||||||
|
declarations: [AppComponent, NxWelcomeComponent],
|
||||||
|
bootstrap: [AppComponent]
|
||||||
|
})
|
||||||
|
export class AppModule {}
|
||||||
`
|
`
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
|
||||||
import { MyDir${
|
|
||||||
names(mylib).className
|
|
||||||
}Module } from '@${proj}/my-dir/${mylib}';
|
|
||||||
import { AppComponent } from './app.component';
|
|
||||||
import { NxWelcomeComponent } from './nx-welcome.component';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [BrowserModule, MyDir${names(mylib).className}Module],
|
|
||||||
declarations: [AppComponent, NxWelcomeComponent],
|
|
||||||
bootstrap: [AppComponent]
|
|
||||||
})
|
|
||||||
export class AppModule {}
|
|
||||||
`
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// check build
|
||||||
runCLI(
|
runCLI(
|
||||||
`run-many --target build --projects=my-dir-${myapp},my-dir-${myapp2} --parallel --prod --output-hashing none`
|
`run-many --target build --projects=${app1},my-dir-${standaloneApp} --parallel --prod --output-hashing none`
|
||||||
);
|
);
|
||||||
|
checkFilesExist(`dist/apps/${app1}/main.js`);
|
||||||
checkFilesExist(`dist/apps/my-dir/${myapp}/main.js`);
|
checkFilesExist(`dist/apps/my-dir/${standaloneApp}/main.js`);
|
||||||
|
|
||||||
// This is a loose requirement because there are a lot of
|
// This is a loose requirement because there are a lot of
|
||||||
// influences external from this project that affect this.
|
// influences external from this project that affect this.
|
||||||
const es2015BundleSize = getSize(
|
const es2015BundleSize = getSize(tmpProjPath(`dist/apps/${app1}/main.js`));
|
||||||
tmpProjPath(`dist/apps/my-dir/${myapp}/main.js`)
|
|
||||||
);
|
|
||||||
console.log(
|
console.log(
|
||||||
`The current es2015 bundle size is ${es2015BundleSize / 1000} KB`
|
`The current es2015 bundle size is ${es2015BundleSize / 1000} KB`
|
||||||
);
|
);
|
||||||
expect(es2015BundleSize).toBeLessThanOrEqual(160000);
|
expect(es2015BundleSize).toBeLessThanOrEqual(160000);
|
||||||
|
|
||||||
|
// check unit tests
|
||||||
runCLI(
|
runCLI(
|
||||||
`run-many --target test --projects=my-dir-${myapp},my-dir-${mylib} --parallel`
|
`run-many --target test --projects=${app1},my-dir-${standaloneApp},${lib1} --parallel`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// check e2e tests
|
||||||
if (runCypressTests()) {
|
if (runCypressTests()) {
|
||||||
const e2eResults = runCLI(`e2e my-dir-${myapp}-e2e --no-watch`);
|
const e2eResults = runCLI(`e2e ${app1}-e2e --no-watch`);
|
||||||
expect(e2eResults).toContain('All specs passed!');
|
expect(e2eResults).toContain('All specs passed!');
|
||||||
expect(await killPorts()).toBeTruthy();
|
expect(await killPorts()).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const appPort = 4207;
|
||||||
const process = await runCommandUntil(
|
const process = await runCommandUntil(
|
||||||
`serve my-dir-${myapp} -- --port=4207`,
|
`serve ${app1} -- --port=${appPort}`,
|
||||||
(output) => output.includes(`listening on localhost:4207`)
|
(output) => output.includes(`listening on localhost:4207`)
|
||||||
);
|
);
|
||||||
|
|
||||||
// port and process cleanup
|
// port and process cleanup
|
||||||
try {
|
await killProcessAndPorts(process.pid, appPort);
|
||||||
await promisifiedTreeKill(process.pid, 'SIGKILL');
|
}, 1000000);
|
||||||
await killPorts(4207);
|
|
||||||
} catch (err) {
|
it('should lint correctly with eslint and handle external HTML files and inline templates', async () => {
|
||||||
expect(err).toBeFalsy();
|
// check apps and lib pass linting for initial generated code
|
||||||
}
|
runCLI(`run-many --target lint --projects=${app1},${lib1} --parallel`);
|
||||||
|
|
||||||
|
// External HTML template file
|
||||||
|
const templateWhichFailsBananaInBoxLintCheck = `<div ([foo])="bar"></div>`;
|
||||||
|
updateFile(
|
||||||
|
`apps/${app1}/src/app/app.component.html`,
|
||||||
|
templateWhichFailsBananaInBoxLintCheck
|
||||||
|
);
|
||||||
|
// Inline template within component.ts file
|
||||||
|
const wrappedAsInlineTemplate = `
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'inline-template-component',
|
||||||
|
template: \`
|
||||||
|
${templateWhichFailsBananaInBoxLintCheck}
|
||||||
|
\`,
|
||||||
|
})
|
||||||
|
export class InlineTemplateComponent {}
|
||||||
|
`;
|
||||||
|
updateFile(
|
||||||
|
`apps/${app1}/src/app/inline-template.component.ts`,
|
||||||
|
wrappedAsInlineTemplate
|
||||||
|
);
|
||||||
|
|
||||||
|
const appLintStdOut = runCLI(`lint ${app1}`, {
|
||||||
|
silenceError: true,
|
||||||
|
});
|
||||||
|
expect(appLintStdOut).toContain(
|
||||||
|
normalize(`apps/${app1}/src/app/app.component.html`)
|
||||||
|
);
|
||||||
|
expect(appLintStdOut).toContain(`1:6`);
|
||||||
|
expect(appLintStdOut).toContain(`Invalid binding syntax`);
|
||||||
|
expect(appLintStdOut).toContain(
|
||||||
|
normalize(`apps/${app1}/src/app/inline-template.component.ts`)
|
||||||
|
);
|
||||||
|
expect(appLintStdOut).toContain(`5:19`);
|
||||||
|
expect(appLintStdOut).toContain(
|
||||||
|
`The selector should start with one of these prefixes`
|
||||||
|
);
|
||||||
|
expect(appLintStdOut).toContain(`7:16`);
|
||||||
|
expect(appLintStdOut).toContain(`Invalid binding syntax`);
|
||||||
|
|
||||||
|
// cleanup added component
|
||||||
|
removeFile(`apps/${app1}/src/app/inline-template.component.ts`);
|
||||||
}, 1000000);
|
}, 1000000);
|
||||||
|
|
||||||
it('should build the dependent buildable lib and its child lib, as well as the app', async () => {
|
it('should build the dependent buildable lib and its child lib, as well as the app', async () => {
|
||||||
// ARRANGE
|
// ARRANGE
|
||||||
const app = uniq('app');
|
|
||||||
const buildableLib = uniq('buildlib1');
|
const buildableLib = uniq('buildlib1');
|
||||||
const buildableChildLib = uniq('buildlib2');
|
const buildableChildLib = uniq('buildlib2');
|
||||||
|
|
||||||
runCLI(`generate @nrwl/angular:app ${app} --style=css --no-interactive`);
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/angular:library ${buildableLib} --buildable=true --no-interactive`
|
`generate @nrwl/angular:library ${buildableLib} --buildable=true --no-interactive`
|
||||||
);
|
);
|
||||||
@ -112,7 +170,7 @@ describe('Angular Projects', () => {
|
|||||||
|
|
||||||
// update the app module to include a ref to the buildable lib
|
// update the app module to include a ref to the buildable lib
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${app}/src/app/app.module.ts`,
|
`apps/${app1}/src/app/app.module.ts`,
|
||||||
`
|
`
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
@ -152,7 +210,7 @@ describe('Angular Projects', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// update the angular.json
|
// update the angular.json
|
||||||
updateProjectConfig(app, (config) => {
|
updateProjectConfig(app1, (config) => {
|
||||||
config.targets.build.executor = '@nrwl/angular:webpack-browser';
|
config.targets.build.executor = '@nrwl/angular:webpack-browser';
|
||||||
config.targets.build.options = {
|
config.targets.build.options = {
|
||||||
...config.targets.build.options,
|
...config.targets.build.options,
|
||||||
@ -162,17 +220,17 @@ describe('Angular Projects', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ACT
|
// ACT
|
||||||
const libOutput = runCLI(`build ${app} --configuration=development`);
|
const libOutput = runCLI(`build ${app1} --configuration=development`);
|
||||||
|
|
||||||
// ASSERT
|
// ASSERT
|
||||||
expect(libOutput).toContain(
|
expect(libOutput).toContain(
|
||||||
`Building entry point '@${proj}/${buildableLib}'`
|
`Building entry point '@${proj}/${buildableLib}'`
|
||||||
);
|
);
|
||||||
expect(libOutput).toContain(`nx run ${app}:build:development`);
|
expect(libOutput).toContain(`nx run ${app1}:build:development`);
|
||||||
|
|
||||||
// to proof it has been built from source the "main.js" should actually contain
|
// to proof it has been built from source the "main.js" should actually contain
|
||||||
// the path to dist
|
// the path to dist
|
||||||
const mainBundle = readFile(`dist/apps/${app}/main.js`);
|
const mainBundle = readFile(`dist/apps/${app1}/main.js`);
|
||||||
expect(mainBundle).toContain(`dist/libs/${buildableLib}`);
|
expect(mainBundle).toContain(`dist/libs/${buildableLib}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
getSelectedPackageManager,
|
getSelectedPackageManager,
|
||||||
runNgNew,
|
runNgNew,
|
||||||
tmpProjPath,
|
tmpProjPath,
|
||||||
uniq,
|
|
||||||
} from '../../utils';
|
} from '../../utils';
|
||||||
import { PackageManager } from 'nx/src/utils/package-manager';
|
import { PackageManager } from 'nx/src/utils/package-manager';
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
@ -13,10 +12,10 @@ describe('make-angular-cli-faster', () => {
|
|||||||
let packageManager: PackageManager;
|
let packageManager: PackageManager;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
project = uniq('proj');
|
|
||||||
packageManager = getSelectedPackageManager();
|
packageManager = getSelectedPackageManager();
|
||||||
// TODO: solve issues with pnpm and remove this fallback
|
// TODO: solve issues with pnpm and remove this fallback
|
||||||
packageManager = packageManager === 'pnpm' ? 'yarn' : packageManager;
|
packageManager = packageManager === 'pnpm' ? 'yarn' : packageManager;
|
||||||
|
project = runNgNew(packageManager);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@ -25,9 +24,6 @@ describe('make-angular-cli-faster', () => {
|
|||||||
|
|
||||||
// TODO(colum): skip until we can investigate why it is installing incorrect version
|
// TODO(colum): skip until we can investigate why it is installing incorrect version
|
||||||
xit('should successfully install make-angular-cli-faster with nx cloud', () => {
|
xit('should successfully install make-angular-cli-faster with nx cloud', () => {
|
||||||
// ARRANGE
|
|
||||||
runNgNew(project, packageManager);
|
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
execSync(
|
execSync(
|
||||||
`NPM_CONFIG_REGISTRY=https://registry.npmjs.org npx --yes make-angular-cli-faster@latest --useNxCloud=true`,
|
`NPM_CONFIG_REGISTRY=https://registry.npmjs.org npx --yes make-angular-cli-faster@latest --useNxCloud=true`,
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import {
|
|||||||
runCLI,
|
runCLI,
|
||||||
runCommand,
|
runCommand,
|
||||||
runNgNew,
|
runNgNew,
|
||||||
uniq,
|
|
||||||
} from '../../utils';
|
} from '../../utils';
|
||||||
|
|
||||||
describe('nx init (Angular CLI)', () => {
|
describe('nx init (Angular CLI)', () => {
|
||||||
@ -18,11 +17,11 @@ describe('nx init (Angular CLI)', () => {
|
|||||||
let pmc: ReturnType<typeof getPackageManagerCommand>;
|
let pmc: ReturnType<typeof getPackageManagerCommand>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
project = uniq('proj');
|
|
||||||
packageManager = getSelectedPackageManager();
|
packageManager = getSelectedPackageManager();
|
||||||
// TODO: solve issues with pnpm and remove this fallback
|
// TODO: solve issues with pnpm and remove this fallback
|
||||||
packageManager = packageManager === 'pnpm' ? 'yarn' : packageManager;
|
packageManager = packageManager === 'pnpm' ? 'yarn' : packageManager;
|
||||||
pmc = getPackageManagerCommand({ packageManager });
|
pmc = getPackageManagerCommand({ packageManager });
|
||||||
|
project = runNgNew(packageManager);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@ -30,8 +29,6 @@ describe('nx init (Angular CLI)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should successfully convert an Angular CLI workspace to an Nx workspace', () => {
|
it('should successfully convert an Angular CLI workspace to an Nx workspace', () => {
|
||||||
runNgNew(project, packageManager);
|
|
||||||
|
|
||||||
const output = runCommand(
|
const output = runCommand(
|
||||||
`${pmc.runUninstalledPackage} nx@${getPublishedVersion()} init -y`
|
`${pmc.runUninstalledPackage} nx@${getPublishedVersion()} init -y`
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { copySync, ensureDirSync, moveSync, removeSync } from 'fs-extra';
|
|||||||
import {
|
import {
|
||||||
createFile,
|
createFile,
|
||||||
directoryExists,
|
directoryExists,
|
||||||
|
tmpBackupNgCliProjPath,
|
||||||
tmpBackupProjPath,
|
tmpBackupProjPath,
|
||||||
updateFile,
|
updateFile,
|
||||||
updateJson,
|
updateJson,
|
||||||
@ -9,10 +10,10 @@ import {
|
|||||||
import {
|
import {
|
||||||
e2eCwd,
|
e2eCwd,
|
||||||
getLatestLernaVersion,
|
getLatestLernaVersion,
|
||||||
getNpmMajorVersion,
|
|
||||||
getPublishedVersion,
|
getPublishedVersion,
|
||||||
getSelectedPackageManager,
|
getSelectedPackageManager,
|
||||||
isVerbose,
|
isVerbose,
|
||||||
|
isVerboseE2ERun,
|
||||||
} from './get-env-info';
|
} from './get-env-info';
|
||||||
import * as isCI from 'is-ci';
|
import * as isCI from 'is-ci';
|
||||||
|
|
||||||
@ -28,6 +29,8 @@ import {
|
|||||||
runCommand,
|
runCommand,
|
||||||
} from './command-utils';
|
} from './command-utils';
|
||||||
import { output } from '@nrwl/devkit';
|
import { output } from '@nrwl/devkit';
|
||||||
|
import { readFileSync } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
let projName: string;
|
let projName: string;
|
||||||
|
|
||||||
@ -311,24 +314,51 @@ export function packageInstall(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Angular CLI workspace or restores a cached one if exists.
|
||||||
|
* @returns the workspace name
|
||||||
|
*/
|
||||||
export function runNgNew(
|
export function runNgNew(
|
||||||
projectName: string,
|
|
||||||
packageManager = getSelectedPackageManager(),
|
packageManager = getSelectedPackageManager(),
|
||||||
angularCliVersion = defaultAngularCliVersion
|
angularCliVersion = defaultAngularCliVersion
|
||||||
): string {
|
): string {
|
||||||
projName = projectName;
|
const pmc = getPackageManagerCommand({ packageManager });
|
||||||
|
|
||||||
const npmMajorVersion = getNpmMajorVersion();
|
if (directoryExists(tmpBackupNgCliProjPath())) {
|
||||||
const command = `npx ${
|
const angularJson = JSON.parse(
|
||||||
+npmMajorVersion >= 7 ? '--yes' : ''
|
readFileSync(join(tmpBackupNgCliProjPath(), 'angular.json'), 'utf-8')
|
||||||
} @angular/cli@${angularCliVersion} new ${projectName} --package-manager=${packageManager}`;
|
);
|
||||||
|
// the name of the workspace matches the name of the generated default app,
|
||||||
|
// we need to reuse the same name that's cached in order to avoid issues
|
||||||
|
// with tests relying on a different name
|
||||||
|
projName = Object.keys(angularJson.projects)[0];
|
||||||
|
copySync(tmpBackupNgCliProjPath(), tmpProjPath());
|
||||||
|
|
||||||
return execSync(command, {
|
if (isVerboseE2ERun()) {
|
||||||
|
logInfo(
|
||||||
|
`NX`,
|
||||||
|
`E2E restored an Angular CLI project from cache: ${tmpProjPath()}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return projName;
|
||||||
|
}
|
||||||
|
|
||||||
|
projName = uniq('ng-proj');
|
||||||
|
const command = `${pmc.runUninstalledPackage} @angular/cli@${angularCliVersion} new ${projName} --package-manager=${packageManager}`;
|
||||||
|
execSync(command, {
|
||||||
cwd: e2eCwd,
|
cwd: e2eCwd,
|
||||||
stdio: isVerbose() ? 'inherit' : 'pipe',
|
stdio: isVerbose() ? 'inherit' : 'pipe',
|
||||||
env: process.env,
|
env: process.env,
|
||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
});
|
});
|
||||||
|
copySync(tmpProjPath(), tmpBackupNgCliProjPath());
|
||||||
|
|
||||||
|
if (isVerboseE2ERun()) {
|
||||||
|
logInfo(`NX`, `E2E created an Angular CLI project: ${tmpProjPath()}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return projName;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function newLernaWorkspace({
|
export function newLernaWorkspace({
|
||||||
|
|||||||
@ -119,3 +119,9 @@ export function getSize(filePath: string): number {
|
|||||||
export function tmpBackupProjPath(path?: string) {
|
export function tmpBackupProjPath(path?: string) {
|
||||||
return path ? `${e2eCwd}/proj-backup/${path}` : `${e2eCwd}/proj-backup`;
|
return path ? `${e2eCwd}/proj-backup/${path}` : `${e2eCwd}/proj-backup`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function tmpBackupNgCliProjPath(path?: string) {
|
||||||
|
return path
|
||||||
|
? `${e2eCwd}/ng-cli-proj-backup/${path}`
|
||||||
|
: `${e2eCwd}/ng-cli-proj-backup`;
|
||||||
|
}
|
||||||
|
|||||||
@ -39,3 +39,19 @@ export async function killPorts(port?: number): Promise<boolean> {
|
|||||||
? await killPort(port)
|
? await killPort(port)
|
||||||
: (await killPort(3333)) && (await killPort(4200));
|
: (await killPort(3333)) && (await killPort(4200));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function killProcessAndPorts(
|
||||||
|
pid: number | undefined,
|
||||||
|
...ports: number[]
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
if (pid) {
|
||||||
|
await promisifiedTreeKill(pid, 'SIGKILL');
|
||||||
|
}
|
||||||
|
for (const port of ports) {
|
||||||
|
await killPort(port);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).toBeFalsy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user