242 lines
7.5 KiB
TypeScript

import {
cleanupProject,
listFiles,
newProject,
rmDist,
runCLI,
uniq,
updateFile,
updateProjectConfig,
} from '@nrwl/e2e/utils';
describe('cache', () => {
beforeEach(() => newProject());
afterEach(() => cleanupProject());
it('should cache command execution', async () => {
const myapp1 = uniq('myapp1');
const myapp2 = uniq('myapp2');
runCLI(`generate @nrwl/web:app ${myapp1}`);
runCLI(`generate @nrwl/web:app ${myapp2}`);
const files = `--files="apps/${myapp1}/src/main.ts,apps/${myapp2}/src/main.ts"`;
// run build with caching
// --------------------------------------------
const outputThatPutsDataIntoCache = runCLI(`affected:build ${files}`);
const filesApp1 = listFiles(`dist/apps/${myapp1}`);
const filesApp2 = listFiles(`dist/apps/${myapp2}`);
// now the data is in cache
expect(outputThatPutsDataIntoCache).not.toContain(
'read the output from the cache'
);
rmDist();
const outputWithBothBuildTasksCached = runCLI(`affected:build ${files}`);
expect(outputWithBothBuildTasksCached).toContain(
'read the output from the cache'
);
expectCached(outputWithBothBuildTasksCached, [myapp1, myapp2]);
expect(listFiles(`dist/apps/${myapp1}`)).toEqual(filesApp1);
expect(listFiles(`dist/apps/${myapp2}`)).toEqual(filesApp2);
// run with skipping cache
const outputWithBothBuildTasksCachedButSkipped = runCLI(
`affected:build ${files} --skip-nx-cache`
);
expect(outputWithBothBuildTasksCachedButSkipped).not.toContain(
`read the output from the cache`
);
// touch myapp1
// --------------------------------------------
updateFile(`apps/${myapp1}/src/main.ts`, (c) => {
return `${c}\n//some comment`;
});
const outputWithBuildApp2Cached = runCLI(`affected:build ${files}`);
expect(outputWithBuildApp2Cached).toContain(
'read the output from the cache'
);
expectMatchedOutput(outputWithBuildApp2Cached, [myapp2]);
// touch package.json
// --------------------------------------------
updateFile(`package.json`, (c) => {
const r = JSON.parse(c);
r.description = 'different';
return JSON.stringify(r);
});
const outputWithNoBuildCached = runCLI(`affected:build ${files}`);
expect(outputWithNoBuildCached).not.toContain(
'read the output from the cache'
);
// build individual project with caching
const individualBuildWithCache = runCLI(`build ${myapp1}`);
expect(individualBuildWithCache).toContain(
'existing outputs match the cache'
);
// skip caching when building individual projects
const individualBuildWithSkippedCache = runCLI(
`build ${myapp1} --skip-nx-cache`
);
expect(individualBuildWithSkippedCache).not.toContain(
'existing outputs match the cache'
);
// run lint with caching
// --------------------------------------------
const outputWithNoLintCached = runCLI(`affected:lint ${files}`);
expect(outputWithNoLintCached).not.toContain(
'read the output from the cache'
);
const outputWithBothLintTasksCached = runCLI(`affected:lint ${files}`);
expect(outputWithBothLintTasksCached).toContain(
'read the output from the cache'
);
expectCached(outputWithBothLintTasksCached, [
myapp1,
myapp2,
`${myapp1}-e2e`,
`${myapp2}-e2e`,
]);
// cache task failures
// --------------------------------------------
// updateFile('workspace.json', (c) => {
// const workspaceJson = JSON.parse(c);
// workspaceJson.projects[myapp1].targets.lint = {
// executor: '@nrwl/workspace:run-commands',
// options: {
// command: 'echo hi && exit 1',
// },
// };
// return JSON.stringify(workspaceJson, null, 2);
// });
// const failingRun = runCLI(`lint ${myapp1}`, {
// silenceError: true,
// env: { ...process.env, NX_CACHE_FAILURES: 'true' },
// });
// expect(failingRun).not.toContain('[retrieved from cache]');
//
// const cachedFailingRun = runCLI(`lint ${myapp1}`, {
// silenceError: true,
// env: { ...process.env, NX_CACHE_FAILURES: 'true' },
// });
// expect(cachedFailingRun).toContain('[retrieved from cache]');
// run without caching
// --------------------------------------------
// disable caching
// --------------------------------------------
updateFile('nx.json', (c) => {
const nxJson = JSON.parse(c);
nxJson.tasksRunnerOptions = {
default: {
options: {
cacheableOperations: [],
},
},
};
return JSON.stringify(nxJson, null, 2);
});
const outputWithoutCachingEnabled1 = runCLI(`affected:build ${files}`);
expect(outputWithoutCachingEnabled1).not.toContain(
'read the output from the cache'
);
const outputWithoutCachingEnabled2 = runCLI(`affected:build ${files}`);
expect(outputWithoutCachingEnabled2).not.toContain(
'read the output from the cache'
);
}, 120000);
it('should only cache specific files if build outputs is configured with specific files', async () => {
const mylib1 = uniq('mylib1');
runCLI(`generate @nrwl/react:lib ${mylib1} --buildable`);
// Update outputs in workspace.json to just be a particular file
updateProjectConfig(mylib1, (config) => {
config.targets['build-base'] = {
...config.targets.build,
};
config.targets.build = {
executor: '@nrwl/workspace:run-commands',
outputs: [`dist/libs/${mylib1}/index.esm.js`],
options: {
commands: [
{
command: `npx nx run ${mylib1}:build-base`,
},
],
parallel: false,
},
};
return config;
});
// run build with caching
// --------------------------------------------
const outputThatPutsDataIntoCache = runCLI(`run ${mylib1}:build`);
// now the data is in cache
expect(outputThatPutsDataIntoCache).not.toContain('cache');
rmDist();
const outputWithBuildTasksCached = runCLI(`run ${mylib1}:build`);
expect(outputWithBuildTasksCached).toContain('cache');
expectCached(outputWithBuildTasksCached, [mylib1]);
// Ensure that only the specific file in outputs was copied to cache
expect(listFiles(`dist/libs/${mylib1}`)).toEqual([`index.esm.js`]);
}, 120000);
function expectCached(
actualOutput: string,
expectedCachedProjects: string[]
) {
expectProjectMatchTaskCacheStatus(actualOutput, expectedCachedProjects);
}
function expectMatchedOutput(
actualOutput: string,
expectedMatchedOutputProjects: string[]
) {
expectProjectMatchTaskCacheStatus(
actualOutput,
expectedMatchedOutputProjects,
'existing outputs match the cache'
);
}
function expectProjectMatchTaskCacheStatus(
actualOutput: string,
expectedProjects: string[],
cacheStatus: string = 'local cache'
) {
const matchingProjects = [];
const lines = actualOutput.split('\n');
lines.forEach((s) => {
if (s.trimStart().startsWith(`> nx run`)) {
const projectName = s
.trimStart()
.split(`> nx run `)[1]
.split(':')[0]
.trim();
if (s.indexOf(cacheStatus) > -1) {
matchingProjects.push(projectName);
}
}
});
matchingProjects.sort((a, b) => a.localeCompare(b));
expectedProjects.sort((a, b) => a.localeCompare(b));
expect(matchingProjects).toEqual(expectedProjects);
}
});