1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-02-01 23:01:28 +01:00

[PM-16917] Remove jest-extended dependency (#12798)

* add toContainPartialObjects matcher (replacing toIncludeAllPartialMembers from jest-extended)
* replace jest-extended matchers with equivalent default matchers
This commit is contained in:
Thomas Rittson 2025-01-16 01:43:26 +10:00 committed by GitHub
parent bdab4aa939
commit 8c13ea894b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 146 additions and 54 deletions

View File

@ -210,10 +210,10 @@
"eslint-plugin-storybook",
"eslint-plugin-tailwindcss",
"husky",
"jest-extended",
"jest-junit",
"jest-mock-extended",
"jest-preset-angular",
"jest-diff",
"lint-staged",
"ts-jest"
],

View File

@ -152,7 +152,7 @@ describe("VaultHeaderV2Component", () => {
it("defaults the initial state to true", (done) => {
// The initial value of the `state$` variable above is undefined
component["initialDisclosureVisibility$"].subscribe((initialVisibility) => {
expect(initialVisibility).toBeTrue();
expect(initialVisibility).toBe(true);
done();
});

View File

@ -179,7 +179,7 @@ describe("ViewV2Component", () => {
flush(); // Resolve all promises
expect(doAutofill).toHaveBeenCalledOnce();
expect(doAutofill).toHaveBeenCalledTimes(1);
}));
it('invokes `copy` when action="copy-username"', fakeAsync(() => {
@ -187,7 +187,7 @@ describe("ViewV2Component", () => {
flush(); // Resolve all promises
expect(copy).toHaveBeenCalledOnce();
expect(copy).toHaveBeenCalledTimes(1);
}));
it('invokes `copy` when action="copy-password"', fakeAsync(() => {
@ -195,7 +195,7 @@ describe("ViewV2Component", () => {
flush(); // Resolve all promises
expect(copy).toHaveBeenCalledOnce();
expect(copy).toHaveBeenCalledTimes(1);
}));
it('invokes `copy` when action="copy-totp"', fakeAsync(() => {
@ -203,7 +203,7 @@ describe("ViewV2Component", () => {
flush(); // Resolve all promises
expect(copy).toHaveBeenCalledOnce();
expect(copy).toHaveBeenCalledTimes(1);
}));
it("closes the popout after a load action", fakeAsync(() => {
@ -218,9 +218,9 @@ describe("ViewV2Component", () => {
flush(); // Resolve all promises
expect(doAutofill).toHaveBeenCalledOnce();
expect(doAutofill).toHaveBeenCalledTimes(1);
expect(focusSpy).toHaveBeenCalledWith(99);
expect(closeSpy).toHaveBeenCalledOnce();
expect(closeSpy).toHaveBeenCalledTimes(1);
}));
});
});

View File

@ -488,7 +488,7 @@ describe("VaultPopupListFiltersService", () => {
state$.next(true);
service.filterVisibilityState$.subscribe((filterVisibility) => {
expect(filterVisibility).toBeTrue();
expect(filterVisibility).toBe(true);
done();
});
});
@ -496,7 +496,7 @@ describe("VaultPopupListFiltersService", () => {
it("updates stored filter state", async () => {
await service.updateFilterVisibility(false);
expect(update).toHaveBeenCalledOnce();
expect(update).toHaveBeenCalledTimes(1);
// Get callback passed to `update`
const updateCallback = update.mock.calls[0][0];
expect(updateCallback()).toBe(false);

View File

@ -91,7 +91,7 @@ describe("DefaultvNextCollectionService", () => {
// Assert emitted values
expect(result.length).toBe(2);
expect(result).toIncludeAllPartialMembers([
expect(result).toContainPartialObjects([
{
id: collection1.id,
name: "DEC_NAME_" + collection1.id,
@ -167,7 +167,7 @@ describe("DefaultvNextCollectionService", () => {
const result = await firstValueFrom(collectionService.encryptedCollections$(userId));
expect(result.length).toBe(2);
expect(result).toIncludeAllPartialMembers([
expect(result).toContainPartialObjects([
{
id: collection1.id,
name: makeEncString("ENC_NAME_" + collection1.id),
@ -205,7 +205,7 @@ describe("DefaultvNextCollectionService", () => {
const result = await firstValueFrom(collectionService.encryptedCollections$(userId));
expect(result.length).toBe(3);
expect(result).toIncludeAllPartialMembers([
expect(result).toContainPartialObjects([
{
id: collection1.id,
name: makeEncString("UPDATED_ENC_NAME_" + collection1.id),
@ -230,7 +230,7 @@ describe("DefaultvNextCollectionService", () => {
const result = await firstValueFrom(collectionService.encryptedCollections$(userId));
expect(result.length).toBe(1);
expect(result).toIncludeAllPartialMembers([
expect(result).toContainPartialObjects([
{
id: collection1.id,
name: makeEncString("ENC_NAME_" + collection1.id),
@ -253,7 +253,7 @@ describe("DefaultvNextCollectionService", () => {
const result = await firstValueFrom(collectionService.encryptedCollections$(userId));
expect(result.length).toBe(1);
expect(result).toIncludeAllPartialMembers([
expect(result).toContainPartialObjects([
{
id: newCollection3.id,
name: makeEncString("ENC_NAME_" + newCollection3.id),

View File

@ -1,6 +1,10 @@
import { webcrypto } from "crypto";
import { addCustomMatchers } from "@bitwarden/common/spec";
import "jest-preset-angular/setup-jest";
addCustomMatchers();
Object.defineProperty(window, "CSS", { value: null });
Object.defineProperty(window, "getComputedStyle", {
value: () => {

View File

@ -8,6 +8,6 @@
"@bitwarden/key-management": ["../key-management/src"]
}
},
"include": ["src", "spec"],
"include": ["src", "spec", "../../libs/common/custom-matchers.d.ts"],
"exclude": ["node_modules", "dist"]
}

View File

@ -1,16 +1,12 @@
import * as matchers from "jest-extended";
import { toBeFulfilled, toBeResolved, toBeRejected } from "./promise-fulfilled";
import { toAlmostEqual } from "./to-almost-equal";
import { toContainPartialObjects } from "./to-contain-partial-objects";
import { toEqualBuffer } from "./to-equal-buffer";
export * from "./to-equal-buffer";
export * from "./to-almost-equal";
export * from "./promise-fulfilled";
// add all jest-extended matchers
expect.extend(matchers);
export function addCustomMatchers() {
expect.extend({
toEqualBuffer: toEqualBuffer,
@ -18,6 +14,7 @@ export function addCustomMatchers() {
toBeFulfilled: toBeFulfilled,
toBeResolved: toBeResolved,
toBeRejected: toBeRejected,
toContainPartialObjects,
});
}
@ -59,4 +56,9 @@ export interface CustomMatchers<R = unknown> {
* @returns CustomMatcherResult indicating whether or not the test passed
*/
toBeRejected(withinMs?: number): Promise<R>;
/**
* Matches if the received array contains all the expected objects using partial matching (expect.objectContaining).
* @param expected An array of partial objects that should be contained in the received array.
*/
toContainPartialObjects<T>(expected: Array<T>): R;
}

View File

@ -0,0 +1,77 @@
describe("toContainPartialObjects", () => {
describe("matches", () => {
it("if the array only contains the partial objects", () => {
const actual = [
{
id: 1,
name: "foo",
},
{
id: 2,
name: "bar",
},
];
const expected = [{ id: 1 }, { id: 2 }];
expect(actual).toContainPartialObjects(expected);
});
it("if the array contains the partial objects and other objects", () => {
const actual = [
{
id: 1,
name: "foo",
},
{
id: 2,
name: "bar",
},
{
id: 3,
name: "baz",
},
];
const expected = [{ id: 1 }, { id: 2 }];
expect(actual).toContainPartialObjects(expected);
});
});
describe("doesn't match", () => {
it("if the array does not contain any partial objects", () => {
const actual = [
{
id: 1,
name: "foo",
},
{
id: 2,
name: "bar",
},
];
const expected = [{ id: 1, name: "Foo" }];
expect(actual).not.toContainPartialObjects(expected);
});
it("if the array contains some but not all partial objects", () => {
const actual = [
{
id: 1,
name: "foo",
},
{
id: 2,
name: "bar",
},
];
const expected = [{ id: 2 }, { id: 3 }];
expect(actual).not.toContainPartialObjects(expected);
});
});
});

View File

@ -0,0 +1,31 @@
import { EOL } from "os";
import { diff } from "jest-diff";
export const toContainPartialObjects: jest.CustomMatcher = function (
received: Array<any>,
expected: Array<any>,
) {
const matched = this.equals(
received,
expect.arrayContaining(expected.map((e) => expect.objectContaining(e))),
);
if (matched) {
return {
message: () =>
"Expected the received array NOT to include partial matches for all expected objects." +
EOL +
diff(expected, received),
pass: true,
};
}
return {
message: () =>
"Expected the received array to contain partial matches for all expected objects." +
EOL +
diff(expected, received),
pass: false,
};
};

View File

@ -184,7 +184,7 @@ describe("KeyServiceLegacyEncryptorProvider", () => {
singleUserId$.complete();
expect(completed).toBeTrue();
expect(completed).toBe(true);
});
it("completes when `userKey$` emits a falsy value after emitting a truthy value", () => {
@ -199,7 +199,7 @@ describe("KeyServiceLegacyEncryptorProvider", () => {
userKey$.next(null);
expect(completed).toBeTrue();
expect(completed).toBe(true);
});
it("completes once `dependencies.singleUserId$` emits and `userKey$` completes", () => {
@ -214,7 +214,7 @@ describe("KeyServiceLegacyEncryptorProvider", () => {
userKey$.complete();
expect(completed).toBeTrue();
expect(completed).toBe(true);
});
});
@ -445,7 +445,7 @@ describe("KeyServiceLegacyEncryptorProvider", () => {
singleOrganizationId$.complete();
expect(completed).toBeTrue();
expect(completed).toBe(true);
});
it("completes when `orgKeys$` emits a falsy value after emitting a truthy value", () => {
@ -466,7 +466,7 @@ describe("KeyServiceLegacyEncryptorProvider", () => {
orgKey$.next(OrgRecords);
orgKey$.next(null);
expect(completed).toBeTrue();
expect(completed).toBe(true);
});
it("completes once `dependencies.singleOrganizationId$` emits and `userKey$` completes", () => {
@ -486,7 +486,7 @@ describe("KeyServiceLegacyEncryptorProvider", () => {
orgKey$.complete();
expect(completed).toBeTrue();
expect(completed).toBe(true);
});
});
});

View File

@ -56,7 +56,7 @@ describe("errorOnChange", () => {
source$.complete();
expect(complete).toBeTrue();
expect(complete).toBe(true);
});
it("errors when the input changes", async () => {

View File

@ -77,7 +77,7 @@ describe("Folder Service", () => {
const result = await firstValueFrom(folderService.folders$(mockUserId));
expect(result.length).toBe(2);
expect(result).toIncludeAllPartialMembers([
expect(result).toContainPartialObjects([
{ id: "1", name: makeEncString("ENC_STRING_1") },
{ id: "2", name: makeEncString("ENC_STRING_2") },
]);
@ -98,7 +98,7 @@ describe("Folder Service", () => {
const result = await firstValueFrom(folderService.folderViews$(mockUserId));
expect(result.length).toBe(3);
expect(result).toIncludeAllPartialMembers([
expect(result).toContainPartialObjects([
{ id: "1", name: "DEC" },
{ id: "2", name: "DEC" },
{ name: "No Folder" },

24
package-lock.json generated
View File

@ -151,7 +151,7 @@
"html-webpack-injector": "1.1.4",
"html-webpack-plugin": "5.6.3",
"husky": "9.1.4",
"jest-extended": "4.0.2",
"jest-diff": "29.7.0",
"jest-junit": "16.0.0",
"jest-mock-extended": "3.0.7",
"jest-preset-angular": "14.1.1",
@ -20729,28 +20729,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-extended": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/jest-extended/-/jest-extended-4.0.2.tgz",
"integrity": "sha512-FH7aaPgtGYHc9mRjriS0ZEHYM5/W69tLrFTIdzm+yJgeoCmmrSB/luSfMSqWP9O29QWHPEmJ4qmU6EwsZideog==",
"dev": true,
"license": "MIT",
"dependencies": {
"jest-diff": "^29.0.0",
"jest-get-type": "^29.0.0"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
},
"peerDependencies": {
"jest": ">=27.2.5"
},
"peerDependenciesMeta": {
"jest": {
"optional": true
}
}
},
"node_modules/jest-get-type": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",

View File

@ -111,7 +111,7 @@
"html-webpack-injector": "1.1.4",
"html-webpack-plugin": "5.6.3",
"husky": "9.1.4",
"jest-extended": "4.0.2",
"jest-diff": "29.7.0",
"jest-junit": "16.0.0",
"jest-mock-extended": "3.0.7",
"jest-preset-angular": "14.1.1",