<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> New workspaces are generated with `@nx/angular` as a production dependency even though the generated code does not use any runtime helper from it. ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> New workspaces should be generated with `@nx/angular` as a development dependency. When generating a new MF host or dynamic MF application (host or remote), the `@nx/angular` package should be moved to the production dependencies because the generated code uses some runtime helpers from it. ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #27333
866 lines
24 KiB
TypeScript
866 lines
24 KiB
TypeScript
import 'nx/src/internal-testing-utils/mock-project-graph';
|
|
|
|
import {
|
|
readJson,
|
|
readProjectConfiguration,
|
|
updateJson,
|
|
type Tree,
|
|
} from '@nx/devkit';
|
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
|
import { E2eTestRunner } from '../../utils/test-runners';
|
|
import { nxVersion } from '../../utils/versions';
|
|
import { generateTestApplication } from '../utils/testing';
|
|
import { setupMf } from './setup-mf';
|
|
|
|
describe('Init MF', () => {
|
|
let tree: Tree;
|
|
|
|
beforeEach(async () => {
|
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
await generateTestApplication(tree, {
|
|
name: 'app1',
|
|
routing: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
await generateTestApplication(tree, {
|
|
name: 'remote1',
|
|
routing: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
});
|
|
|
|
test.each([
|
|
['app1', 'host'],
|
|
['remote1', 'remote'],
|
|
])(
|
|
'should create webpack and mf configs correctly',
|
|
async (app, type: 'host' | 'remote') => {
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: app,
|
|
mfType: type,
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
expect(tree.exists(`${app}/module-federation.config.js`)).toBeTruthy();
|
|
expect(tree.exists(`${app}/webpack.config.js`)).toBeTruthy();
|
|
expect(tree.exists(`${app}/webpack.prod.config.js`)).toBeTruthy();
|
|
|
|
const webpackContents = tree.read(`${app}/webpack.config.js`, 'utf-8');
|
|
expect(webpackContents).toMatchSnapshot();
|
|
|
|
const mfConfigContents = tree.read(
|
|
`${app}/module-federation.config.js`,
|
|
'utf-8'
|
|
);
|
|
expect(mfConfigContents).toMatchSnapshot();
|
|
}
|
|
);
|
|
|
|
test.each([
|
|
['app1', 'host'],
|
|
['remote1', 'remote'],
|
|
])(
|
|
'should create webpack and mf configs correctly when --typescriptConfiguration=true',
|
|
async (app, type: 'host' | 'remote') => {
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: app,
|
|
mfType: type,
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
expect(tree.exists(`${app}/module-federation.config.ts`)).toBeTruthy();
|
|
expect(tree.exists(`${app}/webpack.config.ts`)).toBeTruthy();
|
|
expect(tree.exists(`${app}/webpack.prod.config.ts`)).toBeTruthy();
|
|
|
|
const webpackContents = tree.read(`${app}/webpack.config.ts`, 'utf-8');
|
|
expect(webpackContents).toMatchSnapshot();
|
|
|
|
const mfConfigContents = tree.read(
|
|
`${app}/module-federation.config.ts`,
|
|
'utf-8'
|
|
);
|
|
expect(mfConfigContents).toMatchSnapshot();
|
|
}
|
|
);
|
|
|
|
test.each([
|
|
['app1', 'host'],
|
|
['remote1', 'remote'],
|
|
])(
|
|
'create bootstrap file with the contents of main.ts',
|
|
async (app, type: 'host' | 'remote') => {
|
|
// ARRANGE
|
|
const mainContents = tree.read(`${app}/src/main.ts`, 'utf-8');
|
|
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: app,
|
|
mfType: type,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const bootstrapContents = tree.read(`${app}/src/bootstrap.ts`, 'utf-8');
|
|
const updatedMainContents = tree.read(`${app}/src/main.ts`, 'utf-8');
|
|
|
|
expect(bootstrapContents).toEqual(mainContents);
|
|
expect(updatedMainContents).not.toEqual(mainContents);
|
|
}
|
|
);
|
|
|
|
test.each([
|
|
['app1', 'host'],
|
|
['remote1', 'remote'],
|
|
])(
|
|
'should alter main.ts to import the bootstrap file dynamically',
|
|
async (app, type: 'host' | 'remote') => {
|
|
// ARRANGE
|
|
const mainContents = tree.read(`${app}/src/main.ts`, 'utf-8');
|
|
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: app,
|
|
mfType: type,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const updatedMainContents = tree.read(`${app}/src/main.ts`, 'utf-8');
|
|
|
|
expect(updatedMainContents).toEqual(
|
|
`import('./bootstrap').catch(err => console.error(err));`
|
|
);
|
|
expect(updatedMainContents).not.toEqual(mainContents);
|
|
}
|
|
);
|
|
|
|
test.each([
|
|
['app1', 'host'],
|
|
['remote1', 'remote'],
|
|
])(
|
|
'should change the build and serve target and set correct path to webpack config',
|
|
async (app, type: 'host' | 'remote') => {
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: app,
|
|
mfType: type,
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const { build, serve } = readProjectConfiguration(tree, app).targets;
|
|
|
|
expect(serve.executor).toEqual(
|
|
type === 'host'
|
|
? '@nx/angular:module-federation-dev-server'
|
|
: '@nx/angular:dev-server'
|
|
);
|
|
expect(build.executor).toEqual('@nx/angular:webpack-browser');
|
|
expect(build.options.customWebpackConfig.path).toEqual(
|
|
`${app}/webpack.config.js`
|
|
);
|
|
}
|
|
);
|
|
|
|
test.each([
|
|
['app1', 'host'],
|
|
['remote1', 'remote'],
|
|
])(
|
|
'should change the build and serve target and set correct path to webpack config when --typescriptConfiguration=true',
|
|
async (app, type: 'host' | 'remote') => {
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: app,
|
|
mfType: type,
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const { build, serve } = readProjectConfiguration(tree, app).targets;
|
|
|
|
expect(serve.executor).toEqual(
|
|
type === 'host'
|
|
? '@nx/angular:module-federation-dev-server'
|
|
: '@nx/angular:dev-server'
|
|
);
|
|
expect(build.executor).toEqual('@nx/angular:webpack-browser');
|
|
expect(build.options.customWebpackConfig.path).toEqual(
|
|
`${app}/webpack.config.ts`
|
|
);
|
|
}
|
|
);
|
|
|
|
it('should not generate a webpack prod file for dynamic host', async () => {
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
federationType: 'dynamic',
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const { build } = readProjectConfiguration(tree, 'app1').targets;
|
|
expect(tree.exists('app1/webpack.prod.config.ts')).toBeFalsy();
|
|
expect(build.configurations.production.customWebpackConfig).toBeUndefined();
|
|
});
|
|
|
|
it('should generate the remote entry module and component correctly', async () => {
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'remote1',
|
|
mfType: 'remote',
|
|
prefix: 'my-org',
|
|
standalone: false,
|
|
});
|
|
|
|
// ASSERT
|
|
expect(
|
|
tree.read('remote1/src/app/remote-entry/entry.component.ts', 'utf-8')
|
|
).toMatchSnapshot();
|
|
expect(
|
|
tree.read('remote1/src/app/remote-entry/entry.module.ts', 'utf-8')
|
|
).toMatchSnapshot();
|
|
});
|
|
|
|
it('should generate the remote entry component correctly when prefix is not provided', async () => {
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'remote1',
|
|
mfType: 'remote',
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
expect(
|
|
tree.read('remote1/src/app/remote-entry/entry.component.ts', 'utf-8')
|
|
).toMatchSnapshot();
|
|
});
|
|
|
|
it('should add the remote config to the host when --remotes flag supplied', async () => {
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
remotes: ['remote1'],
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const mfConfigContents = tree.read(
|
|
`app1/module-federation.config.js`,
|
|
'utf-8'
|
|
);
|
|
|
|
expect(mfConfigContents).toContain(`'remote1'`);
|
|
});
|
|
|
|
it('should add the remote config to the host when --remotes flag supplied when --typescriptConfiguration=true', async () => {
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
remotes: ['remote1'],
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const mfConfigContents = tree.read(
|
|
`app1/module-federation.config.ts`,
|
|
'utf-8'
|
|
);
|
|
|
|
expect(mfConfigContents).toContain(`'remote1'`);
|
|
});
|
|
|
|
it('should add a remote application and add it to a specified host applications webpack config when no other remote has been added to it', async () => {
|
|
// ARRANGE
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'remote1',
|
|
mfType: 'remote',
|
|
host: 'app1',
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
});
|
|
|
|
// ASSERT
|
|
const hostMfConfig = tree.read('app1/module-federation.config.js', 'utf-8');
|
|
expect(hostMfConfig).toMatchSnapshot();
|
|
});
|
|
|
|
it('should add a remote application and add it to a specified host applications webpack config when no other remote has been added to it when --typescriptConfiguration=true', async () => {
|
|
// ARRANGE
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'remote1',
|
|
mfType: 'remote',
|
|
host: 'app1',
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const hostMfConfig = tree.read('app1/module-federation.config.ts', 'utf-8');
|
|
expect(hostMfConfig).toMatchSnapshot();
|
|
});
|
|
|
|
it('should add a remote application and add it to a specified host applications webpack config that contains a remote application already', async () => {
|
|
// ARRANGE
|
|
await generateTestApplication(tree, {
|
|
name: 'remote2',
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
await setupMf(tree, {
|
|
appName: 'remote1',
|
|
mfType: 'remote',
|
|
host: 'app1',
|
|
port: 4201,
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'remote2',
|
|
mfType: 'remote',
|
|
host: 'app1',
|
|
port: 4202,
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const hostMfConfig = tree.read('app1/module-federation.config.js', 'utf-8');
|
|
expect(hostMfConfig).toMatchSnapshot();
|
|
});
|
|
|
|
it('should add a remote application and add it to a specified host applications webpack config that contains a remote application already when --typescriptConfiguration=true', async () => {
|
|
// ARRANGE
|
|
await generateTestApplication(tree, {
|
|
name: 'remote2',
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
await setupMf(tree, {
|
|
appName: 'remote1',
|
|
mfType: 'remote',
|
|
host: 'app1',
|
|
port: 4201,
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'remote2',
|
|
mfType: 'remote',
|
|
host: 'app1',
|
|
port: 4202,
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const hostMfConfig = tree.read('app1/module-federation.config.ts', 'utf-8');
|
|
expect(hostMfConfig).toMatchSnapshot();
|
|
});
|
|
|
|
it('should add a remote application and add it to a specified host applications router config', async () => {
|
|
// ARRANGE
|
|
await generateTestApplication(tree, {
|
|
name: 'remote2',
|
|
routing: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
routing: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
await setupMf(tree, {
|
|
appName: 'remote1',
|
|
mfType: 'remote',
|
|
host: 'app1',
|
|
port: 4201,
|
|
routing: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'remote2',
|
|
mfType: 'remote',
|
|
host: 'app1',
|
|
port: 4202,
|
|
routing: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const hostAppRoutes = tree.read('app1/src/app/app.routes.ts', 'utf-8');
|
|
expect(hostAppRoutes).toMatchSnapshot();
|
|
});
|
|
|
|
it('should modify the associated cypress project to add the workaround correctly', async () => {
|
|
// ARRANGE
|
|
await generateTestApplication(tree, {
|
|
name: 'test-app',
|
|
routing: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
e2eTestRunner: E2eTestRunner.Cypress,
|
|
});
|
|
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'test-app',
|
|
mfType: 'host',
|
|
routing: true,
|
|
e2eProjectName: 'test-app-e2e',
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const cypressCommands = tree.read(
|
|
'test-app-e2e/src/support/e2e.ts',
|
|
'utf-8'
|
|
);
|
|
expect(cypressCommands).toContain(
|
|
"Cannot use 'import.meta' outside a module"
|
|
);
|
|
});
|
|
|
|
describe('--federationType=dynamic', () => {
|
|
it('should create a host with the correct configurations', async () => {
|
|
// ARRANGE & ACT
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
routing: true,
|
|
federationType: 'dynamic',
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
expect(tree.read('app1/module-federation.config.js', 'utf-8')).toContain(
|
|
'remotes: []'
|
|
);
|
|
expect(
|
|
tree.exists('app1/public/module-federation.manifest.json')
|
|
).toBeTruthy();
|
|
expect(tree.read('app1/src/main.ts', 'utf-8')).toMatchSnapshot();
|
|
});
|
|
|
|
it('should create a host with the correct configurations when --typescriptConfiguration=true', async () => {
|
|
// ARRANGE & ACT
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
routing: true,
|
|
federationType: 'dynamic',
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
expect(tree.read('app1/module-federation.config.ts', 'utf-8')).toContain(
|
|
'remotes: []'
|
|
);
|
|
expect(
|
|
tree.exists('app1/public/module-federation.manifest.json')
|
|
).toBeTruthy();
|
|
expect(tree.read('app1/src/main.ts', 'utf-8')).toMatchSnapshot();
|
|
});
|
|
|
|
it('should wire up existing remote to dynamic host correctly', async () => {
|
|
await setupMf(tree, {
|
|
appName: 'remote1',
|
|
mfType: 'remote',
|
|
port: 4201,
|
|
routing: true,
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
routing: true,
|
|
federationType: 'dynamic',
|
|
remotes: ['remote1'],
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
expect(tree.read('app1/module-federation.config.js', 'utf-8')).toContain(
|
|
'remotes: []'
|
|
);
|
|
expect(
|
|
readJson(tree, 'app1/public/module-federation.manifest.json')
|
|
).toEqual({
|
|
remote1: 'http://localhost:4201',
|
|
});
|
|
expect(
|
|
tree.read('app1/src/app/app.routes.ts', 'utf-8')
|
|
).toMatchSnapshot();
|
|
});
|
|
|
|
it('should wire up existing remote to dynamic host correctly when --typescriptConfiguration=true', async () => {
|
|
await setupMf(tree, {
|
|
appName: 'remote1',
|
|
mfType: 'remote',
|
|
port: 4201,
|
|
routing: true,
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
routing: true,
|
|
federationType: 'dynamic',
|
|
remotes: ['remote1'],
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
expect(tree.read('app1/module-federation.config.ts', 'utf-8')).toContain(
|
|
'remotes: []'
|
|
);
|
|
expect(
|
|
readJson(tree, 'app1/public/module-federation.manifest.json')
|
|
).toEqual({
|
|
remote1: 'http://localhost:4201',
|
|
});
|
|
expect(
|
|
tree.read('app1/src/app/app.routes.ts', 'utf-8')
|
|
).toMatchSnapshot();
|
|
});
|
|
});
|
|
|
|
it('should add a remote to dynamic host correctly', async () => {
|
|
// ARRANGE
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
routing: true,
|
|
federationType: 'dynamic',
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'remote1',
|
|
mfType: 'remote',
|
|
port: 4201,
|
|
host: 'app1',
|
|
routing: true,
|
|
typescriptConfiguration: false,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
expect(tree.read('app1/module-federation.config.js', 'utf-8')).toContain(
|
|
'remotes: []'
|
|
);
|
|
expect(
|
|
readJson(tree, 'app1/public/module-federation.manifest.json')
|
|
).toEqual({
|
|
remote1: 'http://localhost:4201',
|
|
});
|
|
expect(tree.read('app1/src/app/app.routes.ts', 'utf-8')).toMatchSnapshot();
|
|
});
|
|
|
|
it('should add a remote to dynamic host correctly when --typescriptConfiguration=true', async () => {
|
|
// ARRANGE
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
routing: true,
|
|
federationType: 'dynamic',
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ACT
|
|
await setupMf(tree, {
|
|
appName: 'remote1',
|
|
mfType: 'remote',
|
|
port: 4201,
|
|
host: 'app1',
|
|
routing: true,
|
|
typescriptConfiguration: true,
|
|
standalone: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
expect(tree.read('app1/module-federation.config.ts', 'utf-8')).toContain(
|
|
'remotes: []'
|
|
);
|
|
expect(
|
|
readJson(tree, 'app1/public/module-federation.manifest.json')
|
|
).toEqual({
|
|
remote1: 'http://localhost:4201',
|
|
});
|
|
expect(tree.read('app1/src/app/app.routes.ts', 'utf-8')).toMatchSnapshot();
|
|
});
|
|
|
|
it('should not touch the package.json when run with `--skipPackageJson`', async () => {
|
|
let initialPackageJson;
|
|
updateJson(tree, 'package.json', (json) => {
|
|
json.dependencies = {};
|
|
json.devDependencies = {};
|
|
initialPackageJson = json;
|
|
|
|
return json;
|
|
});
|
|
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
skipFormat: true,
|
|
skipPackageJson: true,
|
|
});
|
|
|
|
const packageJson = readJson(tree, 'package.json');
|
|
expect(packageJson).toEqual(initialPackageJson);
|
|
});
|
|
|
|
it('should generate the host app component test file correctly', async () => {
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
prefix: 'my-org',
|
|
});
|
|
|
|
expect(tree.read('app1/src/app/app.component.spec.ts', 'utf-8'))
|
|
.toMatchInlineSnapshot(`
|
|
"import { fakeAsync, TestBed, tick } from '@angular/core/testing';
|
|
import { AppComponent } from './app.component';
|
|
import { NxWelcomeComponent } from './nx-welcome.component';
|
|
import { Router, RouterModule } from '@angular/router';
|
|
|
|
describe('AppComponent', () => {
|
|
beforeEach(async () => {
|
|
await TestBed.configureTestingModule({
|
|
imports: [
|
|
RouterModule.forRoot([{ path: '', component: NxWelcomeComponent }]),
|
|
AppComponent,
|
|
NxWelcomeComponent,
|
|
],
|
|
}).compileComponents();
|
|
});
|
|
|
|
it('should create the app', () => {
|
|
const fixture = TestBed.createComponent(AppComponent);
|
|
const app = fixture.componentInstance;
|
|
expect(app).toBeTruthy();
|
|
});
|
|
|
|
it(\`should have as title 'app1'\`, () => {
|
|
const fixture = TestBed.createComponent(AppComponent);
|
|
const app = fixture.componentInstance;
|
|
expect(app.title).toEqual('app1');
|
|
});
|
|
|
|
it('should render title', fakeAsync(() => {
|
|
const fixture = TestBed.createComponent(AppComponent);
|
|
const router = TestBed.inject(Router);
|
|
fixture.ngZone?.run(() => router.navigate(['']));
|
|
tick();
|
|
fixture.detectChanges();
|
|
const compiled = fixture.nativeElement as HTMLElement;
|
|
expect(compiled.querySelector('h1')?.textContent).toContain('Welcome app1');
|
|
}));
|
|
});
|
|
"
|
|
`);
|
|
});
|
|
|
|
it('should move the @nx/angular plugin to dependencies when --mfType=host', async () => {
|
|
updateJson(tree, 'package.json', (json) => ({
|
|
...json,
|
|
devDependencies: {
|
|
...json.devDependencies,
|
|
'@nx/angular': nxVersion,
|
|
},
|
|
}));
|
|
|
|
await setupMf(tree, { appName: 'app1', mfType: 'host' });
|
|
|
|
const { devDependencies, dependencies } = readJson(tree, 'package.json');
|
|
expect(devDependencies['@nx/angular']).toBeUndefined();
|
|
expect(dependencies['@nx/angular']).toBe(nxVersion);
|
|
});
|
|
|
|
it('should move the @nx/angular plugin to dependencies when --federationType=dynamic', async () => {
|
|
updateJson(tree, 'package.json', (json) => ({
|
|
...json,
|
|
devDependencies: {
|
|
...json.devDependencies,
|
|
'@nx/angular': nxVersion,
|
|
},
|
|
}));
|
|
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'remote',
|
|
federationType: 'dynamic',
|
|
});
|
|
|
|
const { devDependencies, dependencies } = readJson(tree, 'package.json');
|
|
expect(devDependencies['@nx/angular']).toBeUndefined();
|
|
expect(dependencies['@nx/angular']).toBe(nxVersion);
|
|
});
|
|
|
|
describe('angular compat support', () => {
|
|
beforeEach(() => {
|
|
updateJson(tree, 'package.json', (json) => ({
|
|
...json,
|
|
dependencies: {
|
|
...json.dependencies,
|
|
'@angular/core': '~17.2.0',
|
|
},
|
|
}));
|
|
});
|
|
|
|
it('should generate the host app component test file using RouterTestingModule', async () => {
|
|
await setupMf(tree, {
|
|
appName: 'app1',
|
|
mfType: 'host',
|
|
prefix: 'my-org',
|
|
});
|
|
|
|
expect(tree.read('app1/src/app/app.component.spec.ts', 'utf-8'))
|
|
.toMatchInlineSnapshot(`
|
|
"import { fakeAsync, TestBed, tick } from '@angular/core/testing';
|
|
import { AppComponent } from './app.component';
|
|
import { NxWelcomeComponent } from './nx-welcome.component';
|
|
import { RouterTestingModule } from '@angular/router/testing';
|
|
import { Router } from '@angular/router';
|
|
|
|
describe('AppComponent', () => {
|
|
beforeEach(async () => {
|
|
await TestBed.configureTestingModule({
|
|
imports: [
|
|
RouterTestingModule.withRoutes([
|
|
{ path: '', component: NxWelcomeComponent },
|
|
]),
|
|
AppComponent,
|
|
NxWelcomeComponent,
|
|
],
|
|
}).compileComponents();
|
|
});
|
|
|
|
it('should create the app', () => {
|
|
const fixture = TestBed.createComponent(AppComponent);
|
|
const app = fixture.componentInstance;
|
|
expect(app).toBeTruthy();
|
|
});
|
|
|
|
it(\`should have as title 'app1'\`, () => {
|
|
const fixture = TestBed.createComponent(AppComponent);
|
|
const app = fixture.componentInstance;
|
|
expect(app.title).toEqual('app1');
|
|
});
|
|
|
|
it('should render title', fakeAsync(() => {
|
|
const fixture = TestBed.createComponent(AppComponent);
|
|
const router = TestBed.inject(Router);
|
|
fixture.ngZone?.run(() => router.navigate(['']));
|
|
tick();
|
|
fixture.detectChanges();
|
|
const compiled = fixture.nativeElement as HTMLElement;
|
|
expect(compiled.querySelector('h1')?.textContent).toContain('Welcome app1');
|
|
}));
|
|
});
|
|
"
|
|
`);
|
|
});
|
|
});
|
|
});
|