mirror of
https://github.com/bitwarden/browser
synced 2026-02-10 21:50:15 +00:00
Test account service
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { Substitute, Arg } from "@fluffy-spoon/substitute";
|
||||
import { Observable } from "rxjs";
|
||||
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
|
||||
@@ -41,3 +42,22 @@ export function makeStaticByteArray(length: number, start = 0) {
|
||||
* Use to mock a return value of a static fromJSON method.
|
||||
*/
|
||||
export const mockFromJson = (stub: any) => (stub + "_fromJSON") as any;
|
||||
|
||||
export function trackEmissions<T>(observable: Observable<T>): T[] {
|
||||
const emissions: T[] = [];
|
||||
observable.subscribe((value) => {
|
||||
switch (typeof value) {
|
||||
case "string":
|
||||
case "number":
|
||||
case "boolean":
|
||||
emissions.push(value);
|
||||
break;
|
||||
case "object":
|
||||
emissions.push({ ...value });
|
||||
break;
|
||||
default:
|
||||
emissions.push(JSON.parse(JSON.stringify(value)));
|
||||
}
|
||||
});
|
||||
return emissions;
|
||||
}
|
||||
|
||||
109
libs/common/src/auth/services/account.service.spec.ts
Normal file
109
libs/common/src/auth/services/account.service.spec.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { MockProxy, mock } from "jest-mock-extended";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
import { trackEmissions } from "../../../spec/utils";
|
||||
import { LogService } from "../../platform/abstractions/log.service";
|
||||
import { MessagingService } from "../../platform/abstractions/messaging.service";
|
||||
import { UserId } from "../../types/guid";
|
||||
import { AuthenticationStatus } from "../enums/authentication-status";
|
||||
|
||||
import { AccountServiceImplementation } from "./account.service";
|
||||
|
||||
describe("accountService", () => {
|
||||
let messagingService: MockProxy<MessagingService>;
|
||||
let logService: MockProxy<LogService>;
|
||||
let sut: AccountServiceImplementation;
|
||||
const userId = "userId" as UserId;
|
||||
|
||||
beforeEach(() => {
|
||||
messagingService = mock<MessagingService>();
|
||||
logService = mock<LogService>();
|
||||
|
||||
sut = new AccountServiceImplementation(messagingService, logService);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe("setAccountStatus", () => {
|
||||
let sutAccounts: BehaviorSubject<Record<UserId, AuthenticationStatus>>;
|
||||
let accountsNext: jest.SpyInstance;
|
||||
let emissions: Record<UserId, AuthenticationStatus>[];
|
||||
|
||||
beforeEach(() => {
|
||||
sutAccounts = sut["accounts"];
|
||||
accountsNext = jest.spyOn(sutAccounts, "next");
|
||||
emissions = [];
|
||||
sutAccounts.subscribe((value) => emissions.push(JSON.parse(JSON.stringify(value))));
|
||||
});
|
||||
|
||||
it("should not emit if the status is the same", () => {
|
||||
sut.setAccountStatus(userId, AuthenticationStatus.Locked);
|
||||
sut.setAccountStatus(userId, AuthenticationStatus.Locked);
|
||||
|
||||
expect(sutAccounts.value).toEqual({ userId: AuthenticationStatus.Locked });
|
||||
expect(accountsNext).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should emit if the status is different", () => {
|
||||
const emissions = trackEmissions(sutAccounts);
|
||||
sut.setAccountStatus(userId, AuthenticationStatus.Unlocked);
|
||||
sut.setAccountStatus(userId, AuthenticationStatus.Locked);
|
||||
|
||||
expect(emissions).toEqual([
|
||||
{}, // initial value
|
||||
{ userId: AuthenticationStatus.Unlocked },
|
||||
{ userId: AuthenticationStatus.Locked },
|
||||
]);
|
||||
});
|
||||
|
||||
it("should emit logout if the status is logged out", () => {
|
||||
const emissions = trackEmissions(sut.accountLogout$);
|
||||
sut.setAccountStatus(userId, AuthenticationStatus.Unlocked);
|
||||
sut.setAccountStatus(userId, AuthenticationStatus.LoggedOut);
|
||||
|
||||
expect(emissions).toEqual([userId]);
|
||||
});
|
||||
|
||||
it("should emit lock if the status is locked", () => {
|
||||
const emissions = trackEmissions(sut.accountLock$);
|
||||
sut.setAccountStatus(userId, AuthenticationStatus.Unlocked);
|
||||
sut.setAccountStatus(userId, AuthenticationStatus.Locked);
|
||||
|
||||
expect(emissions).toEqual([userId]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("switchAccount", () => {
|
||||
let emissions: { id: string; status: AuthenticationStatus }[];
|
||||
|
||||
beforeEach(() => {
|
||||
emissions = [];
|
||||
sut.activeAccount$.subscribe((value) => emissions.push(value));
|
||||
});
|
||||
|
||||
it("should emit undefined if no account is provided", () => {
|
||||
sut.switchAccount(undefined);
|
||||
|
||||
expect(emissions).toEqual([undefined]);
|
||||
});
|
||||
|
||||
it("should emit the active account and status", () => {
|
||||
sut.setAccountStatus(userId, AuthenticationStatus.Unlocked);
|
||||
sut.switchAccount(userId);
|
||||
sut.setAccountStatus(userId, AuthenticationStatus.Locked);
|
||||
sut.switchAccount(undefined);
|
||||
sut.switchAccount(undefined);
|
||||
expect(emissions).toEqual([
|
||||
undefined, // initial value
|
||||
{ id: userId, status: AuthenticationStatus.Unlocked },
|
||||
{ id: userId, status: AuthenticationStatus.Locked },
|
||||
]);
|
||||
});
|
||||
|
||||
it("should throw if switched to an unknown account", () => {
|
||||
expect(() => sut.switchAccount(userId)).toThrowError("Account does not exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -23,7 +23,7 @@ export class AccountServiceImplementation implements InternalAccountService {
|
||||
activeAccount$ = this.activeAccountId.pipe(
|
||||
combineLatestWith(this.accounts$),
|
||||
map(([id, accounts]) => (id ? { id, status: accounts[id] } : undefined)),
|
||||
distinctUntilChanged((a, b) => a.id === b.id && a.status === b.status),
|
||||
distinctUntilChanged(),
|
||||
share()
|
||||
);
|
||||
accountLock$ = this.lock.asObservable();
|
||||
|
||||
Reference in New Issue
Block a user