mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 13:23:34 +00:00
[PM-17635] [PM-18601] Simplifying mocking and usage of the sdk (#14287)
* feat: add our own custom deep mocker * feat: use new mock service in totp tests * feat: implement userClient mocking * chore: move mock files * feat: replace existing manual sdkService mocking * chore: rename to 'client' * chore: improve docs * feat: refactor sdkService to never return undefined BitwardenClient
This commit is contained in:
@@ -53,15 +53,18 @@ export abstract class SdkService {
|
||||
* This client can be used for operations that require a user context, such as retrieving ciphers
|
||||
* and operations involving crypto. It can also be used for operations that don't require a user context.
|
||||
*
|
||||
* - If the user is not logged when the subscription is created, the observable will complete
|
||||
* immediately with {@link UserNotLoggedInError}.
|
||||
* - If the user is logged in, the observable will emit the client and complete whithout an error
|
||||
* when the user logs out.
|
||||
*
|
||||
* **WARNING:** Do not use `firstValueFrom(userClient$)`! Any operations on the client must be done within the observable.
|
||||
* The client will be destroyed when the observable is no longer subscribed to.
|
||||
* Please let platform know if you need a client that is not destroyed when the observable is no longer subscribed to.
|
||||
*
|
||||
* @param userId The user id for which to retrieve the client
|
||||
*
|
||||
* @throws {UserNotLoggedInError} If the user is not logged in
|
||||
*/
|
||||
abstract userClient$(userId: UserId): Observable<Rc<BitwardenClient> | undefined>;
|
||||
abstract userClient$(userId: UserId): Observable<Rc<BitwardenClient>>;
|
||||
|
||||
/**
|
||||
* This method is used during/after an authentication procedure to set a new client for a specific user.
|
||||
|
||||
@@ -132,15 +132,13 @@ describe("DefaultSdkService", () => {
|
||||
);
|
||||
keyService.userKey$.calledWith(userId).mockReturnValue(userKey$);
|
||||
|
||||
const subject = new BehaviorSubject<Rc<BitwardenClient> | undefined>(undefined);
|
||||
service.userClient$(userId).subscribe(subject);
|
||||
await new Promise(process.nextTick);
|
||||
const userClientTracker = new ObservableTracker(service.userClient$(userId), false);
|
||||
await userClientTracker.pauseUntilReceived(1);
|
||||
|
||||
userKey$.next(undefined);
|
||||
await new Promise(process.nextTick);
|
||||
await userClientTracker.expectCompletion();
|
||||
|
||||
expect(mockClient.free).toHaveBeenCalledTimes(1);
|
||||
expect(subject.value).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ export class DefaultSdkService implements SdkService {
|
||||
private userAgent: string | null = null,
|
||||
) {}
|
||||
|
||||
userClient$(userId: UserId): Observable<Rc<BitwardenClient> | undefined> {
|
||||
userClient$(userId: UserId): Observable<Rc<BitwardenClient>> {
|
||||
return this.sdkClientOverrides.pipe(
|
||||
takeWhile((clients) => clients[userId] !== UnsetClient, false),
|
||||
map((clients) => {
|
||||
@@ -88,6 +88,7 @@ export class DefaultSdkService implements SdkService {
|
||||
|
||||
return this.internalClient$(userId);
|
||||
}),
|
||||
takeWhile((client) => client !== undefined, false),
|
||||
throwIfEmpty(() => new UserNotLoggedInError(userId)),
|
||||
);
|
||||
}
|
||||
@@ -112,7 +113,7 @@ export class DefaultSdkService implements SdkService {
|
||||
* @param userId The user id for which to create the client
|
||||
* @returns An observable that emits the client for the user
|
||||
*/
|
||||
private internalClient$(userId: UserId): Observable<Rc<BitwardenClient> | undefined> {
|
||||
private internalClient$(userId: UserId): Observable<Rc<BitwardenClient>> {
|
||||
const cached = this.sdkClientCache.get(userId);
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
|
||||
58
libs/common/src/platform/spec/mock-deep.spec.ts
Normal file
58
libs/common/src/platform/spec/mock-deep.spec.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { mockDeep } from "./mock-deep";
|
||||
|
||||
class ToBeMocked {
|
||||
property = "value";
|
||||
|
||||
method() {
|
||||
return "method";
|
||||
}
|
||||
|
||||
sub() {
|
||||
return new SubToBeMocked();
|
||||
}
|
||||
}
|
||||
|
||||
class SubToBeMocked {
|
||||
subProperty = "subValue";
|
||||
|
||||
sub() {
|
||||
return new SubSubToBeMocked();
|
||||
}
|
||||
}
|
||||
|
||||
class SubSubToBeMocked {
|
||||
subSubProperty = "subSubValue";
|
||||
}
|
||||
|
||||
describe("deepMock", () => {
|
||||
it("can mock properties", () => {
|
||||
const mock = mockDeep<ToBeMocked>();
|
||||
mock.property.replaceProperty("mocked value");
|
||||
expect(mock.property).toBe("mocked value");
|
||||
});
|
||||
|
||||
it("can mock methods", () => {
|
||||
const mock = mockDeep<ToBeMocked>();
|
||||
mock.method.mockReturnValue("mocked method");
|
||||
expect(mock.method()).toBe("mocked method");
|
||||
});
|
||||
|
||||
it("can mock sub-properties", () => {
|
||||
const mock = mockDeep<ToBeMocked>();
|
||||
mock.sub.mockDeep().subProperty.replaceProperty("mocked sub value");
|
||||
expect(mock.sub().subProperty).toBe("mocked sub value");
|
||||
});
|
||||
|
||||
it("can mock sub-sub-properties", () => {
|
||||
const mock = mockDeep<ToBeMocked>();
|
||||
mock.sub.mockDeep().sub.mockDeep().subSubProperty.replaceProperty("mocked sub-sub value");
|
||||
expect(mock.sub().sub().subSubProperty).toBe("mocked sub-sub value");
|
||||
});
|
||||
|
||||
it("returns the same mock object when calling mockDeep multiple times", () => {
|
||||
const mock = mockDeep<ToBeMocked>();
|
||||
const subMock1 = mock.sub.mockDeep();
|
||||
const subMock2 = mock.sub.mockDeep();
|
||||
expect(subMock1).toBe(subMock2);
|
||||
});
|
||||
});
|
||||
271
libs/common/src/platform/spec/mock-deep.ts
Normal file
271
libs/common/src/platform/spec/mock-deep.ts
Normal file
@@ -0,0 +1,271 @@
|
||||
// This is a modification of the code found in https://github.com/marchaos/jest-mock-extended
|
||||
// to better support deep mocking of objects.
|
||||
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Marc McIntyre
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import { jest } from "@jest/globals";
|
||||
import { FunctionLike } from "jest-mock";
|
||||
import { calledWithFn, MatchersOrLiterals } from "jest-mock-extended";
|
||||
import { PartialDeep } from "type-fest";
|
||||
|
||||
type ProxiedProperty = string | number | symbol;
|
||||
|
||||
export interface GlobalConfig {
|
||||
// ignoreProps is required when we don't want to return anything for a mock (for example, when mocking a promise).
|
||||
ignoreProps?: ProxiedProperty[];
|
||||
}
|
||||
|
||||
const DEFAULT_CONFIG: GlobalConfig = {
|
||||
ignoreProps: ["then"],
|
||||
};
|
||||
|
||||
let GLOBAL_CONFIG = DEFAULT_CONFIG;
|
||||
|
||||
export const JestMockExtended = {
|
||||
DEFAULT_CONFIG,
|
||||
configure: (config: GlobalConfig) => {
|
||||
// Shallow merge so they can override anything they want.
|
||||
GLOBAL_CONFIG = { ...DEFAULT_CONFIG, ...config };
|
||||
},
|
||||
resetConfig: () => {
|
||||
GLOBAL_CONFIG = DEFAULT_CONFIG;
|
||||
},
|
||||
};
|
||||
|
||||
export interface CalledWithMock<T extends FunctionLike> extends jest.Mock<T> {
|
||||
calledWith: (...args: [...MatchersOrLiterals<Parameters<T>>]) => jest.Mock<T>;
|
||||
}
|
||||
|
||||
export interface MockDeepMock<R> {
|
||||
mockDeep: () => DeepMockProxy<R>;
|
||||
}
|
||||
|
||||
export interface ReplaceProperty<T> {
|
||||
/**
|
||||
* mockDeep will by default return a jest.fn() for all properties,
|
||||
* but this allows you to replace the property with a value.
|
||||
* @param value The value to replace the property with.
|
||||
*/
|
||||
replaceProperty(value: T): void;
|
||||
}
|
||||
|
||||
export type _MockProxy<T> = {
|
||||
[K in keyof T]: T[K] extends FunctionLike ? T[K] & CalledWithMock<T[K]> : T[K];
|
||||
};
|
||||
|
||||
export type MockProxy<T> = _MockProxy<T> & T;
|
||||
|
||||
export type _DeepMockProxy<T> = {
|
||||
// This supports deep mocks in the else branch
|
||||
[K in keyof T]: T[K] extends (...args: infer A) => infer R
|
||||
? T[K] & CalledWithMock<T[K]> & MockDeepMock<R>
|
||||
: T[K] & ReplaceProperty<T[K]> & _DeepMockProxy<T[K]>;
|
||||
};
|
||||
|
||||
// we intersect with T here instead of on the mapped type above to
|
||||
// prevent immediate type resolution on a recursive type, this will
|
||||
// help to improve performance for deeply nested recursive mocking
|
||||
// at the same time, this intersection preserves private properties
|
||||
export type DeepMockProxy<T> = _DeepMockProxy<T> & T;
|
||||
|
||||
export type _DeepMockProxyWithFuncPropSupport<T> = {
|
||||
// This supports deep mocks in the else branch
|
||||
[K in keyof T]: T[K] extends FunctionLike
|
||||
? CalledWithMock<T[K]> & DeepMockProxy<T[K]>
|
||||
: DeepMockProxy<T[K]>;
|
||||
};
|
||||
|
||||
export type DeepMockProxyWithFuncPropSupport<T> = _DeepMockProxyWithFuncPropSupport<T> & T;
|
||||
|
||||
export interface MockOpts {
|
||||
deep?: boolean;
|
||||
fallbackMockImplementation?: (...args: any[]) => any;
|
||||
}
|
||||
|
||||
export const mockClear = (mock: MockProxy<any>) => {
|
||||
for (const key of Object.keys(mock)) {
|
||||
if (mock[key] === null || mock[key] === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mock[key]._isMockObject) {
|
||||
mockClear(mock[key]);
|
||||
}
|
||||
|
||||
if (mock[key]._isMockFunction) {
|
||||
mock[key].mockClear();
|
||||
}
|
||||
}
|
||||
|
||||
// This is a catch for if they pass in a jest.fn()
|
||||
if (!mock._isMockObject) {
|
||||
return mock.mockClear();
|
||||
}
|
||||
};
|
||||
|
||||
export const mockReset = (mock: MockProxy<any>) => {
|
||||
for (const key of Object.keys(mock)) {
|
||||
if (mock[key] === null || mock[key] === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mock[key]._isMockObject) {
|
||||
mockReset(mock[key]);
|
||||
}
|
||||
if (mock[key]._isMockFunction) {
|
||||
mock[key].mockReset();
|
||||
}
|
||||
}
|
||||
|
||||
// This is a catch for if they pass in a jest.fn()
|
||||
// Worst case, we will create a jest.fn() (since this is a proxy)
|
||||
// below in the get and call mockReset on it
|
||||
if (!mock._isMockObject) {
|
||||
return mock.mockReset();
|
||||
}
|
||||
};
|
||||
|
||||
export function mockDeep<T>(
|
||||
opts: {
|
||||
funcPropSupport?: true;
|
||||
fallbackMockImplementation?: MockOpts["fallbackMockImplementation"];
|
||||
},
|
||||
mockImplementation?: PartialDeep<T>,
|
||||
): DeepMockProxyWithFuncPropSupport<T>;
|
||||
export function mockDeep<T>(mockImplementation?: PartialDeep<T>): DeepMockProxy<T>;
|
||||
export function mockDeep(arg1: any, arg2?: any) {
|
||||
const [opts, mockImplementation] =
|
||||
typeof arg1 === "object" &&
|
||||
(typeof arg1.fallbackMockImplementation === "function" || arg1.funcPropSupport === true)
|
||||
? [arg1, arg2]
|
||||
: [{}, arg1];
|
||||
return mock(mockImplementation, {
|
||||
deep: true,
|
||||
fallbackMockImplementation: opts.fallbackMockImplementation,
|
||||
});
|
||||
}
|
||||
|
||||
const overrideMockImp = (obj: PartialDeep<any>, opts?: MockOpts) => {
|
||||
const proxy = new Proxy<MockProxy<any>>(obj, handler(opts));
|
||||
for (const name of Object.keys(obj)) {
|
||||
if (typeof obj[name] === "object" && obj[name] !== null) {
|
||||
proxy[name] = overrideMockImp(obj[name], opts);
|
||||
} else {
|
||||
proxy[name] = obj[name];
|
||||
}
|
||||
}
|
||||
|
||||
return proxy;
|
||||
};
|
||||
|
||||
const handler = (opts?: MockOpts): ProxyHandler<any> => ({
|
||||
ownKeys(target: MockProxy<any>) {
|
||||
return Reflect.ownKeys(target);
|
||||
},
|
||||
|
||||
set: (obj: MockProxy<any>, property: ProxiedProperty, value: any) => {
|
||||
obj[property] = value;
|
||||
return true;
|
||||
},
|
||||
|
||||
get: (obj: MockProxy<any>, property: ProxiedProperty) => {
|
||||
const fn = calledWithFn({ fallbackMockImplementation: opts?.fallbackMockImplementation });
|
||||
|
||||
if (!(property in obj)) {
|
||||
if (GLOBAL_CONFIG.ignoreProps?.includes(property)) {
|
||||
return undefined;
|
||||
}
|
||||
// Jest's internal equality checking does some wierd stuff to check for iterable equality
|
||||
if (property === Symbol.iterator) {
|
||||
return obj[property];
|
||||
}
|
||||
|
||||
if (property === "_deepMock") {
|
||||
return obj[property];
|
||||
}
|
||||
// So this calls check here is totally not ideal - jest internally does a
|
||||
// check to see if this is a spy - which we want to say no to, but blindly returning
|
||||
// an proxy for calls results in the spy check returning true. This is another reason
|
||||
// why deep is opt in.
|
||||
if (opts?.deep && property !== "calls") {
|
||||
obj[property] = new Proxy<MockProxy<any>>(fn, handler(opts));
|
||||
obj[property].replaceProperty = <T extends typeof obj, K extends keyof T>(value: T[K]) => {
|
||||
obj[property] = value;
|
||||
};
|
||||
obj[property].mockDeep = () => {
|
||||
if (obj[property]._deepMock) {
|
||||
return obj[property]._deepMock;
|
||||
}
|
||||
|
||||
const mock = mockDeep({
|
||||
fallbackMockImplementation: opts?.fallbackMockImplementation,
|
||||
});
|
||||
(obj[property] as CalledWithMock<any>).mockReturnValue(mock);
|
||||
obj[property]._deepMock = mock;
|
||||
return mock;
|
||||
};
|
||||
obj[property]._isMockObject = true;
|
||||
} else {
|
||||
obj[property] = calledWithFn({
|
||||
fallbackMockImplementation: opts?.fallbackMockImplementation,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-expect-error Hack by author of jest-mock-extended
|
||||
if (obj instanceof Date && typeof obj[property] === "function") {
|
||||
// @ts-expect-error Hack by author of jest-mock-extended
|
||||
return obj[property].bind(obj);
|
||||
}
|
||||
|
||||
return obj[property];
|
||||
},
|
||||
});
|
||||
|
||||
const mock = <T, MockedReturn extends MockProxy<T> & T = MockProxy<T> & T>(
|
||||
mockImplementation: PartialDeep<T> = {} as PartialDeep<T>,
|
||||
opts?: MockOpts,
|
||||
): MockedReturn => {
|
||||
// @ts-expect-error private
|
||||
mockImplementation!._isMockObject = true;
|
||||
return overrideMockImp(mockImplementation, opts);
|
||||
};
|
||||
|
||||
export const mockFn = <T extends FunctionLike>(): CalledWithMock<T> & T => {
|
||||
// @ts-expect-error Hack by author of jest-mock-extended
|
||||
return calledWithFn();
|
||||
};
|
||||
|
||||
export const stub = <T extends object>(): T => {
|
||||
return new Proxy<T>({} as T, {
|
||||
get: (obj, property: ProxiedProperty) => {
|
||||
if (property in obj) {
|
||||
// @ts-expect-error Hack by author of jest-mock-extended
|
||||
return obj[property];
|
||||
}
|
||||
return jest.fn();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export default mock;
|
||||
81
libs/common/src/platform/spec/mock-sdk.service.ts
Normal file
81
libs/common/src/platform/spec/mock-sdk.service.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import {
|
||||
BehaviorSubject,
|
||||
distinctUntilChanged,
|
||||
map,
|
||||
Observable,
|
||||
takeWhile,
|
||||
throwIfEmpty,
|
||||
} from "rxjs";
|
||||
|
||||
import { BitwardenClient } from "@bitwarden/sdk-internal";
|
||||
|
||||
import { UserId } from "../../types/guid";
|
||||
import { SdkService, UserNotLoggedInError } from "../abstractions/sdk/sdk.service";
|
||||
import { Rc } from "../misc/reference-counting/rc";
|
||||
|
||||
import { DeepMockProxy, mockDeep } from "./mock-deep";
|
||||
|
||||
export class MockSdkService implements SdkService {
|
||||
private userClients$ = new BehaviorSubject<{
|
||||
[userId: UserId]: Rc<BitwardenClient> | undefined;
|
||||
}>({});
|
||||
|
||||
private _client$ = new BehaviorSubject(mockDeep<BitwardenClient>());
|
||||
client$ = this._client$.asObservable();
|
||||
|
||||
version$ = new BehaviorSubject("0.0.1-test").asObservable();
|
||||
|
||||
userClient$(userId: UserId): Observable<Rc<BitwardenClient>> {
|
||||
return this.userClients$.pipe(
|
||||
takeWhile((clients) => clients[userId] !== undefined, false),
|
||||
map((clients) => clients[userId] as Rc<BitwardenClient>),
|
||||
distinctUntilChanged(),
|
||||
throwIfEmpty(() => new UserNotLoggedInError(userId)),
|
||||
);
|
||||
}
|
||||
|
||||
setClient(): void {
|
||||
throw new Error("Not supported in mock service");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the non-user scoped client mock.
|
||||
* This is what is returned by the `client$` observable.
|
||||
*/
|
||||
get client(): DeepMockProxy<BitwardenClient> {
|
||||
return this._client$.value;
|
||||
}
|
||||
|
||||
readonly simulate = {
|
||||
/**
|
||||
* Simulates a user login, and returns a user-scoped mock for the user.
|
||||
* This will be return by the `userClient$` observable.
|
||||
*
|
||||
* @param userId The userId to simulate login for.
|
||||
* @returns A user-scoped mock for the user.
|
||||
*/
|
||||
userLogin: (userId: UserId) => {
|
||||
const client = mockDeep<BitwardenClient>();
|
||||
this.userClients$.next({
|
||||
...this.userClients$.getValue(),
|
||||
[userId]: new Rc(client),
|
||||
});
|
||||
return client;
|
||||
},
|
||||
|
||||
/**
|
||||
* Simulates a user logout, and disposes the user-scoped mock for the user.
|
||||
* This will remove the user-scoped mock from the `userClient$` observable.
|
||||
*
|
||||
* @param userId The userId to simulate logout for.
|
||||
*/
|
||||
userLogout: (userId: UserId) => {
|
||||
const clients = this.userClients$.value;
|
||||
clients[userId]?.markForDisposal();
|
||||
this.userClients$.next({
|
||||
...clients,
|
||||
[userId]: undefined,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,38 +1,27 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { of, take } from "rxjs";
|
||||
import { take } from "rxjs";
|
||||
|
||||
import { BitwardenClient, TotpResponse } from "@bitwarden/sdk-internal";
|
||||
import { TotpResponse } from "@bitwarden/sdk-internal";
|
||||
|
||||
import { SdkService } from "../../platform/abstractions/sdk/sdk.service";
|
||||
import { MockSdkService } from "../../platform/spec/mock-sdk.service";
|
||||
|
||||
import { TotpService } from "./totp.service";
|
||||
|
||||
describe("TotpService", () => {
|
||||
let totpService: TotpService;
|
||||
let generateTotpMock: jest.Mock;
|
||||
|
||||
const sdkService = mock<SdkService>();
|
||||
let totpService!: TotpService;
|
||||
let sdkService!: MockSdkService;
|
||||
|
||||
beforeEach(() => {
|
||||
generateTotpMock = jest
|
||||
.fn()
|
||||
.mockReturnValueOnce({
|
||||
sdkService = new MockSdkService();
|
||||
sdkService.client.vault
|
||||
.mockDeep()
|
||||
.totp.mockDeep()
|
||||
.generate_totp.mockReturnValueOnce({
|
||||
code: "123456",
|
||||
period: 30,
|
||||
})
|
||||
.mockReturnValueOnce({ code: "654321", period: 30 })
|
||||
.mockReturnValueOnce({ code: "567892", period: 30 });
|
||||
|
||||
const mockBitwardenClient = {
|
||||
vault: () => ({
|
||||
totp: () => ({
|
||||
generate_totp: generateTotpMock,
|
||||
}),
|
||||
}),
|
||||
};
|
||||
|
||||
sdkService.client$ = of(mockBitwardenClient as unknown as BitwardenClient);
|
||||
|
||||
totpService = new TotpService(sdkService);
|
||||
|
||||
// TOTP is time-based, so we need to mock the current time
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
@@ -8,14 +7,13 @@ import { PinServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { MockSdkService } from "@bitwarden/common/platform/spec/mock-sdk.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import { BitwardenClient } from "@bitwarden/sdk-internal";
|
||||
|
||||
import { BitwardenPasswordProtectedImporter } from "../importers/bitwarden/bitwarden-password-protected-importer";
|
||||
import { Importer } from "../importers/importer";
|
||||
@@ -35,7 +33,7 @@ describe("ImportService", () => {
|
||||
let encryptService: MockProxy<EncryptService>;
|
||||
let pinService: MockProxy<PinServiceAbstraction>;
|
||||
let accountService: MockProxy<AccountService>;
|
||||
let sdkService: MockProxy<SdkService>;
|
||||
let sdkService: MockSdkService;
|
||||
|
||||
beforeEach(() => {
|
||||
cipherService = mock<CipherService>();
|
||||
@@ -46,9 +44,7 @@ describe("ImportService", () => {
|
||||
keyService = mock<KeyService>();
|
||||
encryptService = mock<EncryptService>();
|
||||
pinService = mock<PinServiceAbstraction>();
|
||||
const mockClient = mock<BitwardenClient>();
|
||||
sdkService = mock<SdkService>();
|
||||
sdkService.client$ = of(mockClient, mockClient, mockClient);
|
||||
sdkService = new MockSdkService();
|
||||
|
||||
importService = new ImportService(
|
||||
cipherService,
|
||||
|
||||
@@ -5,17 +5,17 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service";
|
||||
import { EncryptedString } 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 { MockSdkService } from "@bitwarden/common/platform/spec/mock-sdk.service";
|
||||
import { makeStaticByteArray, mockEnc } from "@bitwarden/common/spec";
|
||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { UserKey } from "@bitwarden/common/types/key";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
|
||||
import { BitwardenClient, VerifyAsymmetricKeysResponse } from "@bitwarden/sdk-internal";
|
||||
import { VerifyAsymmetricKeysResponse } from "@bitwarden/sdk-internal";
|
||||
|
||||
import { KeyService } from "../../abstractions/key.service";
|
||||
import { UserAsymmetricKeysRegenerationApiService } from "../abstractions/user-asymmetric-key-regeneration-api.service";
|
||||
@@ -24,24 +24,17 @@ import { DefaultUserAsymmetricKeysRegenerationService } from "./default-user-asy
|
||||
|
||||
function setupVerificationResponse(
|
||||
mockVerificationResponse: VerifyAsymmetricKeysResponse,
|
||||
sdkService: MockProxy<SdkService>,
|
||||
sdkService: MockSdkService,
|
||||
) {
|
||||
const mockKeyPairResponse = {
|
||||
userPublicKey: "userPublicKey",
|
||||
userKeyEncryptedPrivateKey: "userKeyEncryptedPrivateKey",
|
||||
};
|
||||
|
||||
sdkService.client$ = of({
|
||||
crypto: () => ({
|
||||
verify_asymmetric_keys: jest.fn().mockReturnValue(mockVerificationResponse),
|
||||
make_key_pair: jest.fn().mockReturnValue(mockKeyPairResponse),
|
||||
}),
|
||||
free: jest.fn(),
|
||||
echo: jest.fn(),
|
||||
version: jest.fn(),
|
||||
throw: jest.fn(),
|
||||
catch: jest.fn(),
|
||||
} as unknown as BitwardenClient);
|
||||
sdkService.client.crypto
|
||||
.mockDeep()
|
||||
.verify_asymmetric_keys.mockReturnValue(mockVerificationResponse);
|
||||
sdkService.client.crypto.mockDeep().make_key_pair.mockReturnValue(mockKeyPairResponse);
|
||||
}
|
||||
|
||||
function setupUserKeyValidation(
|
||||
@@ -74,7 +67,7 @@ describe("regenerateIfNeeded", () => {
|
||||
let cipherService: MockProxy<CipherService>;
|
||||
let userAsymmetricKeysRegenerationApiService: MockProxy<UserAsymmetricKeysRegenerationApiService>;
|
||||
let logService: MockProxy<LogService>;
|
||||
let sdkService: MockProxy<SdkService>;
|
||||
let sdkService: MockSdkService;
|
||||
let apiService: MockProxy<ApiService>;
|
||||
let configService: MockProxy<ConfigService>;
|
||||
let encryptService: MockProxy<EncryptService>;
|
||||
@@ -84,7 +77,7 @@ describe("regenerateIfNeeded", () => {
|
||||
cipherService = mock<CipherService>();
|
||||
userAsymmetricKeysRegenerationApiService = mock<UserAsymmetricKeysRegenerationApiService>();
|
||||
logService = mock<LogService>();
|
||||
sdkService = mock<SdkService>();
|
||||
sdkService = new MockSdkService();
|
||||
apiService = mock<ApiService>();
|
||||
configService = mock<ConfigService>();
|
||||
encryptService = mock<EncryptService>();
|
||||
|
||||
Reference in New Issue
Block a user