Skip to content

Commit

Permalink
feat: cache component tests
Browse files Browse the repository at this point in the history
  • Loading branch information
atanasster committed Apr 19, 2021
1 parent a24f528 commit 2489506
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 51 deletions.
14 changes: 9 additions & 5 deletions core/instrument/src/misc/chached-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import findCacheDir from 'find-cache-dir';
export class CachedFileResource<T> {
private folderKey: string;
private fileKey: string;
private filePath: string;
private filePath: string | string[];

/**
*
* @param folderKey folder(category) name
* @param fileKey unique (hash) key for the file
* @param filePath full file path and name for the cached file
*/
constructor(folderKey: string, fileKey: string, filePath: string) {
constructor(folderKey: string, fileKey: string, filePath: string | string[]) {
this.folderKey = folderKey;
this.fileKey = fileKey;
this.filePath = filePath;
Expand Down Expand Up @@ -47,9 +47,13 @@ export class CachedFileResource<T> {
get = (): T | undefined => {
const cachedFileName = this.getCachedFile();
if (fs.existsSync(cachedFileName)) {
const cacheStats = fs.statSync(cachedFileName);
const fileStats = fs.statSync(this.filePath);
if (cacheStats.mtime.getTime() >= fileStats.mtime.getTime()) {
const cacheModified = fs.statSync(cachedFileName).mtime.getTime();
const fileModified = Array.isArray(this.filePath)
? this.filePath.reduce((m, f) => {
return Math.max(m, fs.statSync(f).mtime.getTime());
}, 0)
: fs.statSync(this.filePath).mtime.getTime();
if (cacheModified >= fileModified) {
const fileData = fs.readFileSync(cachedFileName, 'utf8');
const json = JSON.parse(fileData);
return Object.keys(json).length ? json : undefined;
Expand Down
59 changes: 27 additions & 32 deletions core/instrument/src/misc/jest-tests.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import path from 'path';
import { JestConfig } from '@component-controls/jest-extract';
import {
JestConfig,
runProjectTests,
findJestConfig,
getRelatedTests,
JestResults,
} from '@component-controls/jest-extract';
import { JestTests } from '@component-controls/core';
import { CachedFileResource } from './chached-file';

/**
* Separates the files into projects and runs jest tests
Expand All @@ -27,44 +29,37 @@ export const extractTests = async (
testFiles: string[];
coverageFiles: string[];
},
component,
file,
) => {
acc.testFiles.push(
...getRelatedTests(component).map(
f => `.${path.sep}${path.relative(projectFolder, f)}`,
),
);
acc.coverageFiles.push(
`.${path.sep}${path.relative(projectFolder, component)}`,
);
/* const dateModified = fs.statSync(projectFolder).mtime;
const fileHash = createHash('md5')
.update(dateModified.toString())
.update(projectFolder)
.digest('hex');
const cached = new CachedFileResource<JestResults>(
'jest-tests',
`${componentFilePath}-${fileHash}`,
componentFilePath,
);
const cachedTest = cached.get();
if (cachedTest) {
results.push({
testFileName: path.relative(fileDir, testFile),
testResults: cachedTest.testResults,
coverage: cachedTest.coverage,
});
} */
acc.testFiles.push(...getRelatedTests(file));
acc.coverageFiles.push(file);
return acc;
},
{ testFiles: [], coverageFiles: [] },
);
if (tests.testFiles.length) {
const testResults = await runProjectTests(tests.testFiles, projectFolder, {
collectCoverageOnlyFrom: tests.coverageFiles,
...options,
const cached = new CachedFileResource<JestResults>('jest-tests', files[0], [
...tests.testFiles,
...tests.coverageFiles,
]);
const cachedResults = cached.get();
if (cachedResults) {
return cachedResults;
}
const testResults = await runProjectTests({
testFiles: tests.testFiles.map(
f => `.${path.sep}${path.relative(projectFolder, f)}`,
),
projectFolder,
relativeFolder: path.dirname(files[0]),
options: {
...options,
collectCoverageOnlyFrom: tests.coverageFiles.map(
f => `.${path.sep}${path.relative(projectFolder, f)}`,
),
},
});
cached.set(testResults);
return testResults;
}
return undefined;
Expand Down
41 changes: 30 additions & 11 deletions core/jest-extract/src/run-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,35 @@ export interface JestResults {
coverage: Record<string, CoverageSummaryData>;
}

interface TestWorkerInput {
interface RunTestsInput {
/**
* related test files to execute
*/
testFiles: string[];
/**
* the folder with jest configuration or package.json
*/
projectFolder: string;
/**
* if supplied, this is the folder from which to report the file names relative to
* for example this could be the folder where the tested component resides
*/
relativeFolder?: string;
/**
* jest options. Can provide collectCoverageOnlyFrom to limit the files coverage is collected from
*/
options: Partial<Config.Argv>;
}
const runTestsWorker: fastq.asyncWorker<
unknown,
TestWorkerInput,
RunTestsInput,
JestResults | undefined
> = async ({ testFiles, projectFolder, options }: TestWorkerInput) => {
> = async ({
testFiles,
projectFolder,
options,
relativeFolder,
}: RunTestsInput) => {
let runResults: {
results: AggregatedResult;
globalConfig: Config.GlobalConfig;
Expand Down Expand Up @@ -70,13 +89,14 @@ const runTestsWorker: fastq.asyncWorker<
return undefined;
}
const { coverageMap, testResults } = runResults.results;
const relFolder = relativeFolder || projectFolder;
const result: JestResults = {
results: testResults.map(
({ leaks, memoryUsage, perfStats, testFilePath, testResults }) => ({
leaks,
memoryUsage,
perfStats: { ...perfStats },
testFilePath: path.relative(projectFolder, testFilePath),
testFilePath: path.relative(relFolder, testFilePath),
testResults: [...testResults],
}),
),
Expand All @@ -91,15 +111,15 @@ const runTestsWorker: fastq.asyncWorker<
0,
);
if (totals) {
result.coverage[path.relative(projectFolder, file)] = summary;
result.coverage[path.relative(relFolder, file)] = summary;
}
});
}
return result;
};

let queue: fastq.queueAsPromised<
TestWorkerInput,
RunTestsInput,
JestResults | undefined
> | null = null;

Expand All @@ -115,8 +135,9 @@ export const runTests = async (
): Promise<JestResults> => {
const testFiles = [path.basename(testFilePath)];
const projectFolder = findJestConfig(testFilePath);
const relativeFolder = path.dirname(testFilePath);

return runProjectTests(testFiles, projectFolder, options);
return runProjectTests({ testFiles, relativeFolder, projectFolder, options });
};

/**
Expand All @@ -127,13 +148,11 @@ export const runTests = async (
* @returns jest test results and coverage
*/
export const runProjectTests = async (
testFiles: string[],
projectFolder: string,
options: Partial<Config.Argv> = {},
props: RunTestsInput,
): Promise<JestResults> => {
if (!queue) {
queue = fastq.promise(runTestsWorker, 1);
}
const result = await queue.push({ testFiles, projectFolder, options });
const result = await queue.push(props);
return (result as unknown) as JestResults;
};
19 changes: 16 additions & 3 deletions core/loader/src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,24 @@ async function loader(this: WebpackLoaderContext): Promise<string> {
if (store?.doc) {
log('loaded: ', filePath);
if (store.stories && store.components && store.packages) {
Object.keys(store.components).forEach(key => {
if (store.components?.[key]?.request) {
this.addDependency(store.components[key].request as string);
const dependencies: string[] = [];
Object.values(store.components).forEach(component => {
if (component.request) {
dependencies.push(component.request as string);
if (component.jest) {
const componentFolder = path.dirname(component.request);
component.jest.results.forEach(r => {
dependencies.push(
path.resolve(componentFolder, r.testFilePath),
);
});
Object.keys(component.jest.coverage).forEach(f => {
dependencies.push(path.resolve(componentFolder, f));
});
}
}
});
new Set(dependencies).forEach(d => this.addDependency(d));
addStoriesDoc(filePath, this._compilation.records.hash, {
stories: store.stories,
components: store.components,
Expand Down

0 comments on commit 2489506

Please sign in to comment.