640 lines
20 KiB
TypeScript
640 lines
20 KiB
TypeScript
import type { NxJsonConfiguration } from '@nx/devkit';
|
|
import {
|
|
getPackageManagerCommand,
|
|
isNotWindows,
|
|
newProject,
|
|
readFile,
|
|
readJson,
|
|
cleanupProject,
|
|
runCLI,
|
|
runCLIAsync,
|
|
runCommand,
|
|
uniq,
|
|
updateFile,
|
|
updateProjectConfig,
|
|
checkFilesExist,
|
|
isWindows,
|
|
fileExists,
|
|
removeFile,
|
|
readResolvedConfiguration,
|
|
} from '@nx/e2e/utils';
|
|
|
|
describe('Nx Affected and Graph Tests', () => {
|
|
let proj: string;
|
|
|
|
beforeAll(() => (proj = newProject()));
|
|
afterAll(() => cleanupProject());
|
|
|
|
describe('affected:*', () => {
|
|
it('should print, build, and test affected apps', async () => {
|
|
process.env.CI = 'true';
|
|
const myapp = uniq('myapp');
|
|
const myapp2 = uniq('myapp2');
|
|
const mylib = uniq('mylib');
|
|
const mylib2 = uniq('mylib2');
|
|
const mypublishablelib = uniq('mypublishablelib');
|
|
runCLI(`generate @nx/web:app ${myapp}`);
|
|
runCLI(`generate @nx/web:app ${myapp2}`);
|
|
runCLI(`generate @nx/js:lib ${mylib}`);
|
|
runCLI(`generate @nx/js:lib ${mylib2}`);
|
|
runCLI(
|
|
`generate @nx/js:lib ${mypublishablelib} --publishable --importPath=@${proj}/${mypublishablelib} --tags=ui`
|
|
);
|
|
|
|
updateFile(
|
|
`apps/${myapp}/src/app/app.element.spec.ts`,
|
|
`
|
|
import * as x from '@${proj}/${mylib}';
|
|
describe('sample test', () => {
|
|
it('should test', () => {
|
|
expect(1).toEqual(1);
|
|
});
|
|
});
|
|
`
|
|
);
|
|
updateFile(
|
|
`libs/${mypublishablelib}/src/lib/${mypublishablelib}.spec.ts`,
|
|
`
|
|
import * as x from '@${proj}/${mylib}';
|
|
describe('sample test', () => {
|
|
it('should test', () => {
|
|
expect(1).toEqual(1);
|
|
});
|
|
});
|
|
`
|
|
);
|
|
|
|
const affectedApps = runCLI(
|
|
`show projects --affected --files="libs/${mylib}/src/index.ts"`
|
|
);
|
|
expect(affectedApps).toContain(myapp);
|
|
expect(affectedApps).not.toContain(myapp2);
|
|
|
|
const implicitlyAffectedApps = runCLI(
|
|
'show projects --affected --files="tsconfig.base.json"'
|
|
);
|
|
expect(implicitlyAffectedApps).toContain(myapp);
|
|
expect(implicitlyAffectedApps).toContain(myapp2);
|
|
|
|
const noAffectedApps = runCLI(
|
|
'show projects --affected projects --files="README.md"'
|
|
);
|
|
expect(noAffectedApps).not.toContain(myapp);
|
|
expect(noAffectedApps).not.toContain(myapp2);
|
|
|
|
const affectedLibs = runCLI(
|
|
`show projects --affected --files="libs/${mylib}/src/index.ts"`
|
|
);
|
|
expect(affectedLibs).toContain(mypublishablelib);
|
|
expect(affectedLibs).toContain(mylib);
|
|
expect(affectedLibs).not.toContain(mylib2);
|
|
|
|
const implicitlyAffectedLibs = runCLI(
|
|
'show projects --affected --files="tsconfig.base.json"'
|
|
);
|
|
expect(implicitlyAffectedLibs).toContain(mypublishablelib);
|
|
expect(implicitlyAffectedLibs).toContain(mylib);
|
|
expect(implicitlyAffectedLibs).toContain(mylib2);
|
|
|
|
const noAffectedLibsNonExistentFile = runCLI(
|
|
'show projects --affected --files="tsconfig.json"'
|
|
);
|
|
expect(noAffectedLibsNonExistentFile).not.toContain(mypublishablelib);
|
|
expect(noAffectedLibsNonExistentFile).not.toContain(mylib);
|
|
expect(noAffectedLibsNonExistentFile).not.toContain(mylib2);
|
|
|
|
const noAffectedLibs = runCLI(
|
|
'show projects --affected --files="README.md"'
|
|
);
|
|
expect(noAffectedLibs).not.toContain(mypublishablelib);
|
|
expect(noAffectedLibs).not.toContain(mylib);
|
|
expect(noAffectedLibs).not.toContain(mylib2);
|
|
|
|
// build
|
|
const build = runCLI(
|
|
`affected:build --files="libs/${mylib}/src/index.ts" --parallel`
|
|
);
|
|
expect(build).toContain(`Running target build for 3 projects:`);
|
|
expect(build).toContain(`- ${myapp}`);
|
|
expect(build).toContain(`- ${mypublishablelib}`);
|
|
expect(build).not.toContain('is not registered with the build command');
|
|
expect(build).toContain('Successfully ran target build');
|
|
|
|
const buildExcluded = runCLI(
|
|
`affected:build --files="libs/${mylib}/src/index.ts" --exclude=${myapp}`
|
|
);
|
|
expect(buildExcluded).toContain(`Running target build for 2 projects:`);
|
|
expect(buildExcluded).toContain(`- ${mypublishablelib}`);
|
|
|
|
const buildExcludedByTag = runCLI(
|
|
`affected:build --files="libs/${mylib}/src/index.ts" --exclude=tag:ui`
|
|
);
|
|
expect(buildExcludedByTag).toContain(
|
|
`Running target build for 2 projects:`
|
|
);
|
|
expect(buildExcludedByTag).not.toContain(`- ${mypublishablelib}`);
|
|
|
|
// test
|
|
updateFile(
|
|
`apps/${myapp}/src/app/app.element.spec.ts`,
|
|
readFile(`apps/${myapp}/src/app/app.element.spec.ts`).replace(
|
|
'.toEqual(1)',
|
|
'.toEqual(2)'
|
|
)
|
|
);
|
|
|
|
const failedTests = runCLI(
|
|
`affected:test --files="libs/${mylib}/src/index.ts"`,
|
|
{ silenceError: true }
|
|
);
|
|
expect(failedTests).toContain(mylib);
|
|
expect(failedTests).toContain(myapp);
|
|
expect(failedTests).toContain(mypublishablelib);
|
|
expect(failedTests).toContain(`Failed tasks:`);
|
|
|
|
// Fix failing Unit Test
|
|
updateFile(
|
|
`apps/${myapp}/src/app/app.element.spec.ts`,
|
|
readFile(`apps/${myapp}/src/app/app.element.spec.ts`).replace(
|
|
'.toEqual(2)',
|
|
'.toEqual(1)'
|
|
)
|
|
);
|
|
}, 1000000);
|
|
});
|
|
|
|
describe('affected (with git)', () => {
|
|
let myapp;
|
|
let myapp2;
|
|
let mylib;
|
|
|
|
beforeEach(() => {
|
|
myapp = uniq('myapp');
|
|
myapp2 = uniq('myapp');
|
|
mylib = uniq('mylib');
|
|
const nxJson: NxJsonConfiguration = readJson('nx.json');
|
|
|
|
updateFile('nx.json', JSON.stringify(nxJson));
|
|
runCommand(`git init`);
|
|
runCommand(`git config user.email "test@test.com"`);
|
|
runCommand(`git config user.name "Test"`);
|
|
runCommand(`git config commit.gpgsign false`);
|
|
try {
|
|
runCommand(
|
|
`git add . && git commit -am "initial commit" && git checkout -b main`
|
|
);
|
|
} catch (e) {}
|
|
});
|
|
|
|
function generateAll() {
|
|
runCLI(`generate @nx/web:app ${myapp}`);
|
|
runCLI(`generate @nx/web:app ${myapp2}`);
|
|
runCLI(`generate @nx/js:lib ${mylib}`);
|
|
runCommand(`git add . && git commit -am "add all"`);
|
|
}
|
|
|
|
it('should not affect other projects by generating a new project', () => {
|
|
// TODO: investigate why affected gives different results on windows
|
|
if (isNotWindows()) {
|
|
runCLI(`generate @nx/web:app ${myapp}`);
|
|
expect(runCLI('print-affected --select projects')).toContain(myapp);
|
|
runCommand(`git add . && git commit -am "add ${myapp}"`);
|
|
|
|
runCLI(`generate @nx/web:app ${myapp2}`);
|
|
let output = runCLI('print-affected --select projects');
|
|
expect(output).not.toContain(myapp);
|
|
expect(output).toContain(myapp2);
|
|
runCommand(`git add . && git commit -am "add ${myapp2}"`);
|
|
|
|
runCLI(`generate @nx/js:lib ${mylib}`);
|
|
output = runCLI('print-affected --select projects');
|
|
expect(output).not.toContain(myapp);
|
|
expect(output).not.toContain(myapp2);
|
|
expect(output).toContain(mylib);
|
|
}
|
|
}, 1000000);
|
|
|
|
it('should detect changes to projects based on tags changes', async () => {
|
|
// TODO: investigate why affected gives different results on windows
|
|
if (isNotWindows()) {
|
|
generateAll();
|
|
await updateProjectConfig(myapp, (config) => ({
|
|
...config,
|
|
tags: ['tag'],
|
|
}));
|
|
const output = runCLI('print-affected --select projects');
|
|
expect(output).toContain(myapp);
|
|
expect(output).not.toContain(myapp2);
|
|
expect(output).not.toContain(mylib);
|
|
}
|
|
});
|
|
|
|
it('should affect all projects by removing projects', async () => {
|
|
generateAll();
|
|
const root = (await readResolvedConfiguration())[mylib].root;
|
|
removeFile(root);
|
|
const output = runCLI('print-affected --select projects');
|
|
expect(output).toContain(myapp);
|
|
expect(output).toContain(myapp2);
|
|
expect(output).not.toContain(mylib);
|
|
});
|
|
|
|
it('should detect changes to implicitly dependant projects', async () => {
|
|
generateAll();
|
|
await updateProjectConfig(myapp, (config) => ({
|
|
...config,
|
|
implicitDependencies: ['*', `!${myapp2}`],
|
|
}));
|
|
|
|
runCommand('git commit -m "setup test"');
|
|
updateFile(`libs/${mylib}/index.html`, '<html></html>');
|
|
|
|
const output = runCLI('print-affected --select projects');
|
|
|
|
expect(output).toContain(myapp);
|
|
expect(output).not.toContain(myapp2);
|
|
expect(output).toContain(mylib);
|
|
|
|
// Clear implicit deps to not interfere with other tests.
|
|
await updateProjectConfig(myapp, (config) => ({
|
|
...config,
|
|
implicitDependencies: [],
|
|
}));
|
|
});
|
|
|
|
it('should handle file renames', () => {
|
|
generateAll();
|
|
|
|
// Move file
|
|
updateFile(
|
|
`apps/${myapp2}/src/index.html`,
|
|
readFile(`apps/${myapp}/src/index.html`)
|
|
);
|
|
removeFile(`apps/${myapp}/src/index.html`);
|
|
|
|
const affectedProjects = runCLI(
|
|
'print-affected --uncommitted --select projects'
|
|
)
|
|
.replace(
|
|
/.*nx print-affected --uncommitted --select projects( --verbose)?\n/,
|
|
''
|
|
)
|
|
.split(', ');
|
|
|
|
expect(affectedProjects).toContain(myapp);
|
|
expect(affectedProjects).toContain(myapp2);
|
|
});
|
|
});
|
|
|
|
describe('graph', () => {
|
|
let myapp: string;
|
|
let myapp2: string;
|
|
let myapp3: string;
|
|
let myappE2e: string;
|
|
let myapp2E2e: string;
|
|
let myapp3E2e: string;
|
|
let mylib: string;
|
|
let mylib2: string;
|
|
|
|
beforeAll(() => {
|
|
myapp = uniq('myapp');
|
|
myapp2 = uniq('myapp2');
|
|
myapp3 = uniq('myapp3');
|
|
myappE2e = `${myapp}-e2e`;
|
|
myapp2E2e = `${myapp2}-e2e`;
|
|
myapp3E2e = `${myapp3}-e2e`;
|
|
mylib = uniq('mylib');
|
|
mylib2 = uniq('mylib2');
|
|
|
|
runCLI(`generate @nx/web:app ${myapp}`);
|
|
runCLI(`generate @nx/web:app ${myapp2}`);
|
|
runCLI(`generate @nx/web:app ${myapp3}`);
|
|
runCLI(`generate @nx/js:lib ${mylib}`);
|
|
runCLI(`generate @nx/js:lib ${mylib2}`);
|
|
|
|
runCommand(`git init`);
|
|
runCommand(`git config user.email "test@test.com"`);
|
|
runCommand(`git config user.name "Test"`);
|
|
runCommand(`git config commit.gpgsign false`);
|
|
runCommand(
|
|
`git add . && git commit -am "initial commit" && git checkout -b main`
|
|
);
|
|
|
|
updateFile(
|
|
`apps/${myapp}/src/main.ts`,
|
|
`
|
|
import '@${proj}/${mylib}';
|
|
|
|
const s = {loadChildren: '@${proj}/${mylib2}'};
|
|
`
|
|
);
|
|
|
|
updateFile(
|
|
`apps/${myapp2}/src/app/app.element.spec.ts`,
|
|
`import '@${proj}/${mylib}';`
|
|
);
|
|
|
|
updateFile(
|
|
`libs/${mylib}/src/${mylib}.spec.ts`,
|
|
`import '@${proj}/${mylib2}';`
|
|
);
|
|
});
|
|
|
|
it('graph should output json to file', () => {
|
|
runCLI(`graph --file=project-graph.json`);
|
|
|
|
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
|
|
|
|
const jsonFileContents = readJson('project-graph.json');
|
|
|
|
expect(jsonFileContents.graph.dependencies).toEqual(
|
|
expect.objectContaining({
|
|
[myapp3E2e]: [
|
|
{
|
|
source: myapp3E2e,
|
|
target: myapp3,
|
|
type: 'implicit',
|
|
},
|
|
],
|
|
[myapp2]: [
|
|
{
|
|
source: myapp2,
|
|
target: mylib,
|
|
type: 'static',
|
|
},
|
|
],
|
|
[myapp2E2e]: [
|
|
{
|
|
source: myapp2E2e,
|
|
target: myapp2,
|
|
type: 'implicit',
|
|
},
|
|
],
|
|
[mylib]: [
|
|
{
|
|
source: mylib,
|
|
target: mylib2,
|
|
type: 'static',
|
|
},
|
|
],
|
|
[mylib2]: [],
|
|
[myapp]: [
|
|
{
|
|
source: myapp,
|
|
target: mylib,
|
|
type: 'static',
|
|
},
|
|
],
|
|
[myappE2e]: [
|
|
{
|
|
source: myappE2e,
|
|
target: myapp,
|
|
type: 'implicit',
|
|
},
|
|
],
|
|
[myapp3]: [],
|
|
})
|
|
);
|
|
|
|
runCLI(
|
|
`affected:graph --files="libs/${mylib}/src/index.ts" --file="project-graph.json"`
|
|
);
|
|
|
|
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
|
|
|
|
const jsonFileContents2 = readJson('project-graph.json');
|
|
|
|
expect(jsonFileContents2.criticalPath).toContain(myapp);
|
|
expect(jsonFileContents2.criticalPath).toContain(myapp2);
|
|
expect(jsonFileContents2.criticalPath).toContain(mylib);
|
|
expect(jsonFileContents2.criticalPath).not.toContain(mylib2);
|
|
}, 1000000);
|
|
|
|
if (isNotWindows()) {
|
|
it('graph should output json to file by absolute path', () => {
|
|
runCLI(`graph --file=/tmp/project-graph.json`);
|
|
|
|
expect(() => checkFilesExist('/tmp/project-graph.json')).not.toThrow();
|
|
}, 1000000);
|
|
}
|
|
|
|
if (isWindows()) {
|
|
it('graph should output json to file by absolute path in Windows', () => {
|
|
runCLI(`graph --file=C:\\tmp\\project-graph.json`);
|
|
|
|
expect(fileExists('C:\\tmp\\project-graph.json')).toBeTruthy();
|
|
}, 1000000);
|
|
}
|
|
|
|
it('graph should focus requested project', () => {
|
|
runCLI(`graph --focus=${myapp} --file=project-graph.json`);
|
|
|
|
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
|
|
|
|
const jsonFileContents = readJson('project-graph.json');
|
|
const projectNames = Object.keys(jsonFileContents.graph.nodes);
|
|
|
|
expect(projectNames).toContain(myapp);
|
|
expect(projectNames).toContain(mylib);
|
|
expect(projectNames).toContain(mylib2);
|
|
expect(projectNames).toContain(myappE2e);
|
|
|
|
expect(projectNames).not.toContain(myapp2);
|
|
expect(projectNames).not.toContain(myapp3);
|
|
expect(projectNames).not.toContain(myapp2E2e);
|
|
expect(projectNames).not.toContain(myapp3E2e);
|
|
}, 1000000);
|
|
|
|
it('graph should exclude requested projects', () => {
|
|
runCLI(
|
|
`graph --exclude=${myappE2e},${myapp2E2e},${myapp3E2e} --file=project-graph.json`
|
|
);
|
|
|
|
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
|
|
|
|
const jsonFileContents = readJson('project-graph.json');
|
|
const projectNames = Object.keys(jsonFileContents.graph.nodes);
|
|
|
|
expect(projectNames).toContain(myapp);
|
|
expect(projectNames).toContain(mylib);
|
|
expect(projectNames).toContain(mylib2);
|
|
expect(projectNames).toContain(myapp2);
|
|
expect(projectNames).toContain(myapp3);
|
|
|
|
expect(projectNames).not.toContain(myappE2e);
|
|
expect(projectNames).not.toContain(myapp2E2e);
|
|
expect(projectNames).not.toContain(myapp3E2e);
|
|
}, 1000000);
|
|
|
|
it('graph should exclude requested projects that were included by a focus', () => {
|
|
runCLI(
|
|
`graph --focus=${myapp} --exclude=${myappE2e} --file=project-graph.json`
|
|
);
|
|
|
|
expect(() => checkFilesExist('project-graph.json')).not.toThrow();
|
|
|
|
const jsonFileContents = readJson('project-graph.json');
|
|
const projectNames = Object.keys(jsonFileContents.graph.nodes);
|
|
|
|
expect(projectNames).toContain(myapp);
|
|
expect(projectNames).toContain(mylib);
|
|
expect(projectNames).toContain(mylib2);
|
|
|
|
expect(projectNames).not.toContain(myappE2e);
|
|
expect(projectNames).not.toContain(myapp2);
|
|
expect(projectNames).not.toContain(myapp3);
|
|
expect(projectNames).not.toContain(myapp2E2e);
|
|
expect(projectNames).not.toContain(myapp3E2e);
|
|
}, 1000000);
|
|
|
|
it('graph should output a deployable static website in an html file accompanied by a folder with static assets', () => {
|
|
runCLI(`graph --file=project-graph.html`);
|
|
|
|
expect(() => checkFilesExist('project-graph.html')).not.toThrow();
|
|
expect(() => checkFilesExist('static/styles.css')).not.toThrow();
|
|
expect(() => checkFilesExist('static/runtime.js')).not.toThrow();
|
|
expect(() => checkFilesExist('static/main.js')).not.toThrow();
|
|
expect(() => checkFilesExist('static/environment.js')).not.toThrow();
|
|
|
|
const environmentJs = readFile('static/environment.js');
|
|
|
|
expect(environmentJs).toContain('window.projectGraphResponse');
|
|
expect(environmentJs).toContain('"affected":[]');
|
|
});
|
|
|
|
it('graph should output valid json when stdout is specified', () => {
|
|
const result = runCLI(`affected -t build --graph stdout`);
|
|
let model;
|
|
expect(() => (model = JSON.parse(result))).not.toThrow();
|
|
expect(model).toHaveProperty('graph');
|
|
expect(model).toHaveProperty('tasks');
|
|
});
|
|
|
|
it('should include affected projects in environment file', () => {
|
|
runCLI(`graph --affected --file=project-graph.html`);
|
|
|
|
const environmentJs = readFile('static/environment.js');
|
|
const affectedProjects = environmentJs
|
|
.match(/"affected":\[(.*?)\]/)[1]
|
|
?.split(',');
|
|
|
|
expect(affectedProjects).toContain(`"${myapp}"`);
|
|
expect(affectedProjects).toContain(`"${myappE2e}"`);
|
|
expect(affectedProjects).toContain(`"${myapp2}"`);
|
|
expect(affectedProjects).toContain(`"${myapp2E2e}"`);
|
|
expect(affectedProjects).toContain(`"${mylib}"`);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Print-affected', () => {
|
|
let proj: string;
|
|
|
|
beforeAll(() => (proj = newProject()));
|
|
afterAll(() => cleanupProject());
|
|
|
|
it('should print information about affected projects', async () => {
|
|
const myapp = uniq('myapp-a');
|
|
const myapp2 = uniq('myapp-b');
|
|
const mylib = uniq('mylib');
|
|
const mylib2 = uniq('mylib2');
|
|
const mypublishablelib = uniq('mypublishablelib');
|
|
|
|
runCLI(`generate @nx/web:app ${myapp}`);
|
|
runCLI(`generate @nx/web:app ${myapp2}`);
|
|
runCLI(`generate @nx/js:lib ${mylib}`);
|
|
runCLI(`generate @nx/js:lib ${mylib2}`);
|
|
runCLI(`generate @nx/js:lib ${mypublishablelib}`);
|
|
|
|
const app1ElementSpec = readFile(
|
|
`apps/${myapp}/src/app/app.element.spec.ts`
|
|
);
|
|
|
|
updateFile(
|
|
`apps/${myapp}/src/app/app.element.spec.ts`,
|
|
`
|
|
import "@${proj}/${mylib}";
|
|
import "@${proj}/${mypublishablelib}";
|
|
${app1ElementSpec}
|
|
`
|
|
);
|
|
|
|
const app2ElementSpec = readFile(
|
|
`apps/${myapp2}/src/app/app.element.spec.ts`
|
|
);
|
|
|
|
updateFile(
|
|
`apps/${myapp2}/src/app/app.element.spec.ts`,
|
|
`
|
|
import "@${proj}/${mylib}";
|
|
import "@${proj}/${mypublishablelib}";
|
|
${app2ElementSpec}
|
|
`
|
|
);
|
|
|
|
const resWithoutTarget = JSON.parse(
|
|
(
|
|
await runCLIAsync(
|
|
`print-affected --files=apps/${myapp}/src/app/app.element.spec.ts`,
|
|
{
|
|
silent: true,
|
|
}
|
|
)
|
|
).stdout
|
|
);
|
|
expect(resWithoutTarget.tasks).toEqual([]);
|
|
compareTwoArrays(resWithoutTarget.projects, [`${myapp}-e2e`, myapp]);
|
|
|
|
const resWithTarget = JSON.parse(
|
|
(
|
|
await runCLIAsync(
|
|
`print-affected --files=apps/${myapp}/src/app/app.element.spec.ts --target=test`,
|
|
{ silent: true }
|
|
)
|
|
).stdout.trim()
|
|
);
|
|
|
|
const { runNx } = getPackageManagerCommand();
|
|
expect(resWithTarget.tasks[0]).toMatchObject({
|
|
id: `${myapp}:test`,
|
|
overrides: {},
|
|
target: {
|
|
project: myapp,
|
|
target: 'test',
|
|
},
|
|
command: `${runNx} run ${myapp}:test`,
|
|
outputs: [`coverage/apps/${myapp}`],
|
|
});
|
|
compareTwoArrays(resWithTarget.projects, [myapp]);
|
|
|
|
const resWithTargetWithSelect1 = (
|
|
await runCLIAsync(
|
|
`print-affected --files=apps/${myapp}/src/app/app.element.spec.ts --target=test --select=projects`,
|
|
{ silent: true }
|
|
)
|
|
).stdout.trim();
|
|
compareTwoSerializedArrays(resWithTargetWithSelect1, myapp);
|
|
|
|
const resWithTargetWithSelect2 = (
|
|
await runCLIAsync(
|
|
`print-affected --files=apps/${myapp}/src/app/app.element.spec.ts --target=test --select="tasks.target.project"`,
|
|
{ silent: true }
|
|
)
|
|
).stdout.trim();
|
|
compareTwoSerializedArrays(resWithTargetWithSelect2, myapp);
|
|
}, 120000);
|
|
|
|
function compareTwoSerializedArrays(a: string, b: string) {
|
|
compareTwoArrays(
|
|
a.split(',').map((_) => _.trim()),
|
|
b.split(',').map((_) => _.trim())
|
|
);
|
|
}
|
|
|
|
function compareTwoArrays(a: string[], b: string[]) {
|
|
expect(a.sort((x, y) => x.localeCompare(y))).toEqual(
|
|
b.sort((x, y) => x.localeCompare(y))
|
|
);
|
|
}
|
|
});
|