Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/browser/cdp/emitter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import * as logger from "../../utils/logger";
import { EventEmitter } from "events";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type AnyFunc = (...args: any) => unknown;

export class CDPEventEmitter<Events extends { [key in keyof Events]: unknown }> extends EventEmitter {
private _callbackMap: Map<AnyFunc, AnyFunc> = new Map();

on<U extends string & keyof Events>(event: U, listener: (params: Events[U]) => void | Promise<void>): this {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const eventListenerWithErrorBoundary = (params: Events[U]): void | Promise<void> => {
Expand All @@ -18,10 +23,19 @@ export class CDPEventEmitter<Events extends { [key in keyof Events]: unknown }>
}
};

this._callbackMap.set(listener, eventListenerWithErrorBoundary);

return super.on(event, eventListenerWithErrorBoundary);
}

off<U extends string & keyof Events>(event: U, listener: (params: Events[U]) => void | Promise<void>): this {
return super.off(event, listener);
const eventListenerWithErrorBoundary = this._callbackMap.get(listener);

if (eventListenerWithErrorBoundary) {
this._callbackMap.delete(listener);
super.off(event, eventListenerWithErrorBoundary);
}

return this;
}
}
5 changes: 5 additions & 0 deletions src/browser/cdp/selectivity/hash-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ export class HashProvider {

const cwd = process.cwd();
const files = await globExtra.expandPaths(pattern, { root: cwd });

if (!files.length) {
throw new Error(`Selectivity: Couldn't find files by disableSelectivityPattern "${pattern}"`);
}

const filesSorted = files.sort();
const hash = crypto.createHash("md5");

Expand Down
5 changes: 4 additions & 1 deletion src/browser/cdp/selectivity/testplane-selectivity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ export const readTestFileWithTestplaneDependenciesCollecting = <T>(file: string,
}

return fn().finally(() => {
testFileDependenciesCache.set(file, Array.from(jsTestplaneDeps).sort());
testFileDependenciesCache.set(
file,
Array.from(jsTestplaneDeps).sort((a, b) => a.localeCompare(b)),
);
});
};
10 changes: 8 additions & 2 deletions src/browser/cdp/selectivity/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,13 @@ export const transformSourceDependencies = (
}
}

return { css: Array.from(cssSet).sort(), js: Array.from(jsSet).sort(), modules: Array.from(modulesSet).sort() };
const cmpStr = (a: string, b: string): number => a.localeCompare(b);

return {
css: Array.from(cssSet).sort(cmpStr),
js: Array.from(jsSet).sort(cmpStr),
modules: Array.from(modulesSet).sort(cmpStr),
};
};

/** Merges two sorted deps array into one with uniq values */
Expand Down Expand Up @@ -299,7 +305,7 @@ export const mergeSourceDependencies = (

// Ensures file consistency
export const shallowSortObject = (obj: Record<string, unknown>): void => {
const testBrowsers = Object.keys(obj).sort();
const testBrowsers = Object.keys(obj).sort((a, b) => a.localeCompare(b));

for (const testBrowser of testBrowsers) {
const testBrowserDeps = obj[testBrowser];
Expand Down
16 changes: 16 additions & 0 deletions test/src/browser/cdp/selectivity/hash-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ describe("CDP/Selectivity/HashProvider", () => {
let fsStub: { createReadStream: SinonStub };
let hashMock: { update: SinonStub; digest: SinonStub };
let streamMock: EventEmitter;
let globExtraStub: { expandPaths: SinonStub };

beforeEach(() => {
hashMock = {
Expand All @@ -22,10 +23,12 @@ describe("CDP/Selectivity/HashProvider", () => {
fsStub = {
createReadStream: sandbox.stub().returns(streamMock),
};
globExtraStub = { expandPaths: sandbox.stub().resolves([]) };

HashProvider = proxyquire("src/browser/cdp/selectivity/hash-provider", {
"node:crypto": cryptoStub,
"node:fs": fsStub,
"../../../bundle/glob-extra": globExtraStub,
}).HashProvider;
});

Expand Down Expand Up @@ -185,4 +188,17 @@ describe("CDP/Selectivity/HashProvider", () => {
assert.calledWith(hash2Mock.update, Buffer.from("data2"));
});
});

describe("calculateForPattern", () => {
it("should reject with an error if can't find files by pattern", async () => {
const filePattern = "/pattern/of/**/file-that-does-not-exist.js";
const provider = new HashProvider();

globExtraStub.expandPaths.resolves([]);

const result = provider.calculateForPattern(filePattern);

assert.isRejected(result, /Couldn't find files/);
});
});
});
21 changes: 21 additions & 0 deletions test/src/browser/cdp/selectivity/hash-reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,27 @@ describe("CDP/Selectivity/HashReader", () => {

assert.calledOnce(readHashFileContentsStub);
});

it("should throw error if no files are found by pattern", async () => {
const reader = new HashReader("/test/selectivity", "none");
const pattern = "src/**/*.js";
const patternError = new Error(
`Selectivity: Couldn't find files by disableSelectivityPattern "${pattern}"`,
);
const hashFileContents = {
files: {},
modules: {},
patterns: {},
};

readHashFileContentsStub.resolves(hashFileContents);
hashProviderMock.calculateForPattern.withArgs(pattern).rejects(patternError);

const result = reader.patternHasChanged(pattern);

assert.isRejected(result, /Couldn't find files by disableSelectivityPattern/);
assert.calledWith(hashProviderMock.calculateForPattern, pattern);
});
});

describe("getTestChangedDeps", () => {
Expand Down
Loading