mirror of
https://github.com/bitwarden/browser.git
synced 2024-10-24 08:09:59 +02:00
Passing test for observables
This commit is contained in:
parent
1cdcba203f
commit
69e8f4fa6e
@ -1,4 +1,4 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { firstValueFrom, of } from "rxjs";
|
||||
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
@ -6,6 +6,7 @@ import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
||||
import {
|
||||
FakeStateProvider,
|
||||
@ -16,7 +17,7 @@ import {
|
||||
import { CollectionId, OrganizationId, UserId } from "@bitwarden/common/types/guid";
|
||||
import { OrgKey } from "@bitwarden/common/types/key";
|
||||
|
||||
import { CollectionData } from "../models";
|
||||
import { CollectionData, CollectionView } from "../models";
|
||||
|
||||
import {
|
||||
DefaultCollectionvNextService,
|
||||
@ -46,31 +47,40 @@ describe("DefaultCollectionService", () => {
|
||||
});
|
||||
|
||||
// Arrange cryptoService - orgKeys and mock decryption
|
||||
const cryptoService = mockCryptoService();
|
||||
const [cryptoService, encryptService] = mockCryptoService();
|
||||
const orgKey1 = makeSymmetricCryptoKey<OrgKey>(64, 1);
|
||||
const orgKey2 = makeSymmetricCryptoKey<OrgKey>(64, 2);
|
||||
cryptoService.orgKeys$.mockReturnValue(
|
||||
of({
|
||||
[org1]: makeSymmetricCryptoKey<OrgKey>(),
|
||||
[org2]: makeSymmetricCryptoKey<OrgKey>(),
|
||||
[org1]: orgKey1,
|
||||
[org2]: orgKey2,
|
||||
}),
|
||||
);
|
||||
|
||||
const collectionService = new DefaultCollectionvNextService(
|
||||
cryptoService,
|
||||
mock<EncryptService>(),
|
||||
encryptService,
|
||||
mockI18nService(),
|
||||
fakeStateProvider,
|
||||
);
|
||||
|
||||
// Assert emitted values
|
||||
const result = await firstValueFrom(collectionService.decryptedCollections$(of(userId)));
|
||||
expect(result.length).toBe(2);
|
||||
expect(result[0]).toMatchObject({
|
||||
id: collection1.id,
|
||||
name: "DECRYPTED_STRING",
|
||||
});
|
||||
expect(result[1]).toMatchObject({
|
||||
id: collection2.id,
|
||||
name: "DECRYPTED_STRING",
|
||||
});
|
||||
// expect(result.length).toBe(2);
|
||||
expect(result).toContainEqual(collectionViewFactory(collection1));
|
||||
expect(result).toContainEqual(collectionViewFactory(collection2));
|
||||
|
||||
// Assert that the correct org keys were used for each encrypted string
|
||||
const collection1NameData = new EncString(collection1.name).data;
|
||||
const collection2NameData = new EncString(collection2.name).data;
|
||||
expect(encryptService.decryptToUtf8).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ data: collection1NameData }),
|
||||
orgKey1,
|
||||
);
|
||||
expect(encryptService.decryptToUtf8).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ data: collection2NameData }),
|
||||
orgKey2,
|
||||
);
|
||||
});
|
||||
|
||||
it("handles null collection state", async () => {
|
||||
@ -81,10 +91,10 @@ describe("DefaultCollectionService", () => {
|
||||
// Arrange state provider
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
const fakeStateProvider = new FakeStateProvider(mockAccountServiceWith(userId));
|
||||
await fakeStateProvider.setUserState(ENCRYPTED_COLLECTION_DATA_KEY, null);
|
||||
await fakeStateProvider.setUserState(ENCRYPTED_COLLECTION_DATA_KEY, null, userId);
|
||||
|
||||
// Arrange cryptoService - orgKeys and mock decryption
|
||||
const cryptoService = mockCryptoService();
|
||||
const [cryptoService, encryptService] = mockCryptoService();
|
||||
cryptoService.orgKeys$.mockReturnValue(
|
||||
of({
|
||||
[org1]: makeSymmetricCryptoKey<OrgKey>(),
|
||||
@ -94,7 +104,75 @@ describe("DefaultCollectionService", () => {
|
||||
|
||||
const collectionService = new DefaultCollectionvNextService(
|
||||
cryptoService,
|
||||
mock<EncryptService>(),
|
||||
encryptService,
|
||||
mockI18nService(),
|
||||
fakeStateProvider,
|
||||
);
|
||||
|
||||
const encryptedCollections = await firstValueFrom(
|
||||
collectionService.encryptedCollections$(of(userId)),
|
||||
);
|
||||
expect(encryptedCollections.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("encryptedCollections$", () => {
|
||||
it("emits encrypted collections from state", async () => {
|
||||
// Arrange test collections
|
||||
const org1 = Utils.newGuid() as OrganizationId;
|
||||
const org2 = Utils.newGuid() as OrganizationId;
|
||||
|
||||
const collection1 = collectionDataFactory(org1);
|
||||
const collection2 = collectionDataFactory(org2);
|
||||
|
||||
// Arrange state provider
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
const fakeStateProvider = new FakeStateProvider(mockAccountServiceWith(userId));
|
||||
await fakeStateProvider.setUserState(
|
||||
ENCRYPTED_COLLECTION_DATA_KEY,
|
||||
{
|
||||
[collection1.id]: collection1,
|
||||
[collection2.id]: collection2,
|
||||
},
|
||||
userId,
|
||||
);
|
||||
|
||||
// Arrange cryptoService - just so we don't get errors
|
||||
const [cryptoService, encryptService] = mockCryptoService();
|
||||
cryptoService.orgKeys$.mockReturnValue(of({}));
|
||||
|
||||
const collectionService = new DefaultCollectionvNextService(
|
||||
cryptoService,
|
||||
encryptService,
|
||||
mockI18nService(),
|
||||
fakeStateProvider,
|
||||
);
|
||||
|
||||
const result = await firstValueFrom(collectionService.encryptedCollections$(of(userId)));
|
||||
expect(result.length).toBe(2);
|
||||
expect(result[0]).toMatchObject({
|
||||
id: collection1.id,
|
||||
name: makeEncString("ENC_NAME_" + collection1.id),
|
||||
});
|
||||
expect(result[1]).toMatchObject({
|
||||
id: collection2.id,
|
||||
name: makeEncString("ENC_NAME_" + collection2.id),
|
||||
});
|
||||
});
|
||||
|
||||
it("handles null collection state", async () => {
|
||||
// Arrange state provider
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
const fakeStateProvider = new FakeStateProvider(mockAccountServiceWith(userId));
|
||||
await fakeStateProvider.setUserState(ENCRYPTED_COLLECTION_DATA_KEY, null);
|
||||
|
||||
// Arrange cryptoService - orgKeys and mock decryption
|
||||
const [cryptoService, encryptService] = mockCryptoService();
|
||||
cryptoService.orgKeys$.mockReturnValue(of({}));
|
||||
|
||||
const collectionService = new DefaultCollectionvNextService(
|
||||
cryptoService,
|
||||
encryptService,
|
||||
mockI18nService(),
|
||||
fakeStateProvider,
|
||||
);
|
||||
@ -103,11 +181,6 @@ describe("DefaultCollectionService", () => {
|
||||
collectionService.decryptedCollections$(of(userId)),
|
||||
);
|
||||
expect(decryptedCollections.length).toBe(0);
|
||||
|
||||
const encryptedCollections = await firstValueFrom(
|
||||
collectionService.encryptedCollections$(of(userId)),
|
||||
);
|
||||
expect(encryptedCollections.length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -118,23 +191,34 @@ const mockI18nService = () => {
|
||||
return i18nService;
|
||||
};
|
||||
|
||||
const mockCryptoService = () => {
|
||||
const mockCryptoService: () => [MockProxy<CryptoService>, MockProxy<EncryptService>] = () => {
|
||||
const cryptoService = mock<CryptoService>();
|
||||
const encryptService = mock<EncryptService>();
|
||||
encryptService.decryptToUtf8
|
||||
.calledWith(expect.any(EncString), expect.anything())
|
||||
.mockResolvedValue("DECRYPTED_STRING");
|
||||
.calledWith(expect.any(EncString), expect.any(SymmetricCryptoKey))
|
||||
.mockImplementation((encString, key) =>
|
||||
Promise.resolve(encString.data.replace("ENC_", "DEC_")),
|
||||
);
|
||||
|
||||
(window as any).bitwardenContainerService = new ContainerService(cryptoService, encryptService);
|
||||
|
||||
return cryptoService;
|
||||
return [cryptoService, encryptService];
|
||||
};
|
||||
|
||||
const collectionDataFactory = (orgId: OrganizationId) => {
|
||||
const collection = new CollectionData({} as any);
|
||||
collection.id = Utils.newGuid() as CollectionId;
|
||||
collection.organizationId = orgId;
|
||||
collection.name = makeEncString("ENC_STRING").encryptedString;
|
||||
collection.name = makeEncString("ENC_NAME_" + collection.id).encryptedString;
|
||||
|
||||
return collection;
|
||||
};
|
||||
|
||||
const collectionViewFactory = (data: CollectionData) =>
|
||||
Object.assign(new CollectionView(), {
|
||||
id: data.id,
|
||||
name: "DEC_NAME_" + data.id,
|
||||
assigned: true,
|
||||
externalId: null,
|
||||
organizationId: data.organizationId,
|
||||
});
|
||||
|
@ -46,8 +46,15 @@ export function makeStaticByteArray(length: number, start = 0) {
|
||||
return arr;
|
||||
}
|
||||
|
||||
export function makeSymmetricCryptoKey<T extends SymmetricCryptoKey>(length: 32 | 64 = 64) {
|
||||
return new SymmetricCryptoKey(makeStaticByteArray(length)) as T;
|
||||
/**
|
||||
* Creates a symmetric crypto key for use in tests. This is deterministic, i.e. it will produce identical keys
|
||||
* for identical argument values. Provide a unique value to the `seed` parameter to create different keys.
|
||||
*/
|
||||
export function makeSymmetricCryptoKey<T extends SymmetricCryptoKey>(
|
||||
length: 32 | 64 = 64,
|
||||
seed = 0,
|
||||
) {
|
||||
return new SymmetricCryptoKey(makeStaticByteArray(length, seed)) as T;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user