mirror of
https://github.com/bitwarden/browser
synced 2026-02-03 02:03:53 +00:00
update tests for DefaultAuthRequestAnsweringService
This commit is contained in:
@@ -2,7 +2,6 @@ import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthRequestAnsweringService } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AuthServerNotificationTags } from "@bitwarden/common/auth/enums/auth-server-notification-tags";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
@@ -32,7 +31,7 @@ describe("ExtensionAuthRequestAnsweringService", () => {
|
||||
let platformUtilsService: MockProxy<PlatformUtilsService>;
|
||||
let systemNotificationsService: MockProxy<SystemNotificationsService>;
|
||||
|
||||
let sut: AuthRequestAnsweringService;
|
||||
let sut: ExtensionAuthRequestAnsweringService;
|
||||
|
||||
const userId = "9f4c3452-6a45-48af-a7d0-74d3e8b65e4c" as UserId;
|
||||
const authRequestId = "auth-request-id-123";
|
||||
|
||||
@@ -2,7 +2,6 @@ import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthRequestAnsweringService } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||
@@ -21,7 +20,7 @@ describe("DesktopAuthRequestAnsweringService", () => {
|
||||
let pendingAuthRequestsState: MockProxy<PendingAuthRequestsStateService>;
|
||||
let i18nService: MockProxy<I18nService>;
|
||||
|
||||
let sut: AuthRequestAnsweringService;
|
||||
let sut: DesktopAuthRequestAnsweringService;
|
||||
|
||||
const userId = "9f4c3452-6a45-48af-a7d0-74d3e8b65e4c" as UserId;
|
||||
const authRequestId = "auth-request-id-123";
|
||||
|
||||
@@ -6,10 +6,6 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import {
|
||||
ButtonLocation,
|
||||
SystemNotificationEvent,
|
||||
} from "@bitwarden/common/platform/system-notifications/system-notifications.service";
|
||||
import { UserId } from "@bitwarden/user-core";
|
||||
|
||||
import { AuthRequestAnsweringService } from "../../abstractions/auth-request-answering/auth-request-answering.service.abstraction";
|
||||
@@ -31,7 +27,6 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
|
||||
const userId = "9f4c3452-6a45-48af-a7d0-74d3e8b65e4c" as UserId;
|
||||
const otherUserId = "554c3112-9a75-23af-ab80-8dk3e9bl5i8e" as UserId;
|
||||
const authRequestId = "auth-request-id-123";
|
||||
|
||||
beforeEach(() => {
|
||||
accountService = mock<AccountService>();
|
||||
@@ -63,18 +58,6 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe("receivedPendingAuthRequest()", () => {
|
||||
it("should throw an error", async () => {
|
||||
// Act
|
||||
const promise = sut.receivedPendingAuthRequest(userId, authRequestId);
|
||||
|
||||
// Assert
|
||||
await expect(promise).rejects.toThrow(
|
||||
"receivedPendingAuthRequest() not implemented for this client",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("userMeetsConditionsToShowApprovalDialog()", () => {
|
||||
it("should return true if user is Unlocked, active, and not required to set/change their master password", async () => {
|
||||
// Arrange
|
||||
@@ -128,70 +111,12 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("handleAuthRequestNotificationClicked()", () => {
|
||||
it("should throw an error", async () => {
|
||||
// Arrange
|
||||
const event: SystemNotificationEvent = {
|
||||
id: "123",
|
||||
buttonIdentifier: ButtonLocation.NotificationButton,
|
||||
};
|
||||
|
||||
// Act
|
||||
const promise = sut.handleAuthRequestNotificationClicked(event);
|
||||
|
||||
// Assert
|
||||
await expect(promise).rejects.toThrow(
|
||||
"handleAuthRequestNotificationClicked() not implemented for this client",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("processPendingAuthRequests()", () => {
|
||||
it("should send an 'openLoginApproval' message if there is at least one pending auth request for the user in state", async () => {
|
||||
// Arrange
|
||||
const pendingRequests: PendingAuthUserMarker[] = [{ userId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequests));
|
||||
|
||||
// Act
|
||||
await sut.processPendingAuthRequests();
|
||||
|
||||
// Assert
|
||||
expect(messagingService.send).toHaveBeenCalledWith("openLoginApproval");
|
||||
expect(messagingService.send).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should NOT send a message if there are no pending auth requests in state", async () => {
|
||||
// Arrange
|
||||
const pendingRequests: PendingAuthUserMarker[] = [];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequests));
|
||||
|
||||
// Act
|
||||
await sut.processPendingAuthRequests();
|
||||
|
||||
// Assert
|
||||
expect(messagingService.send).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should NOT send a message if there are no pending auth requests in state for the active user", async () => {
|
||||
// Arrange
|
||||
const pendingRequests: PendingAuthUserMarker[] = [
|
||||
{ userId: otherUserId, receivedAtMs: Date.now() },
|
||||
]; // pending auth marker for a different user
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequests));
|
||||
|
||||
// Act
|
||||
await sut.processPendingAuthRequests();
|
||||
|
||||
// Assert
|
||||
expect(messagingService.send).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("setupUnlockListenersForProcessingAuthRequests()", () => {
|
||||
let destroy$: Subject<void>;
|
||||
let activeAccount$: BehaviorSubject<any>;
|
||||
let activeAccountStatus$: BehaviorSubject<AuthenticationStatus>;
|
||||
let authStatusForSubjects: Map<UserId, BehaviorSubject<AuthenticationStatus>>;
|
||||
let pendingRequestMarkers: PendingAuthUserMarker[];
|
||||
|
||||
beforeEach(() => {
|
||||
destroy$ = new Subject<void>();
|
||||
@@ -203,6 +128,7 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
});
|
||||
activeAccountStatus$ = new BehaviorSubject(AuthenticationStatus.Locked);
|
||||
authStatusForSubjects = new Map();
|
||||
pendingRequestMarkers = [];
|
||||
|
||||
accountService.activeAccount$ = activeAccount$;
|
||||
authService.activeAccountStatus$ = activeAccountStatus$;
|
||||
@@ -224,8 +150,9 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
describe("active account switching", () => {
|
||||
it("should process pending auth requests when switching to an unlocked user", async () => {
|
||||
// Arrange
|
||||
const processSpy = jest.spyOn(sut, "processPendingAuthRequests");
|
||||
authStatusForSubjects.set(otherUserId, new BehaviorSubject(AuthenticationStatus.Unlocked));
|
||||
pendingRequestMarkers = [{ userId: otherUserId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequestMarkers));
|
||||
|
||||
// Act
|
||||
sut.setupUnlockListenersForProcessingAuthRequests(destroy$);
|
||||
@@ -240,13 +167,14 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
|
||||
// Assert
|
||||
await new Promise((resolve) => setTimeout(resolve, 0)); // Allows observable chain to complete before assertion
|
||||
expect(processSpy).toHaveBeenCalledTimes(1);
|
||||
expect(messagingService.send).toHaveBeenCalledWith("openLoginApproval");
|
||||
});
|
||||
|
||||
it("should NOT process pending auth requests when switching to a locked user", async () => {
|
||||
// Arrange
|
||||
const processSpy = jest.spyOn(sut, "processPendingAuthRequests");
|
||||
authStatusForSubjects.set(otherUserId, new BehaviorSubject(AuthenticationStatus.Locked));
|
||||
pendingRequestMarkers = [{ userId: otherUserId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequestMarkers));
|
||||
|
||||
// Act
|
||||
sut.setupUnlockListenersForProcessingAuthRequests(destroy$);
|
||||
@@ -259,13 +187,14 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
|
||||
// Assert
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
expect(processSpy).not.toHaveBeenCalled();
|
||||
expect(messagingService.send).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should NOT process pending auth requests when switching to a logged out user", async () => {
|
||||
// Arrange
|
||||
const processSpy = jest.spyOn(sut, "processPendingAuthRequests");
|
||||
authStatusForSubjects.set(otherUserId, new BehaviorSubject(AuthenticationStatus.LoggedOut));
|
||||
pendingRequestMarkers = [{ userId: otherUserId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequestMarkers));
|
||||
|
||||
// Act
|
||||
sut.setupUnlockListenersForProcessingAuthRequests(destroy$);
|
||||
@@ -278,12 +207,13 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
|
||||
// Assert
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
expect(processSpy).not.toHaveBeenCalled();
|
||||
expect(messagingService.send).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should NOT process pending auth requests when active account becomes null", async () => {
|
||||
// Arrange
|
||||
const processSpy = jest.spyOn(sut, "processPendingAuthRequests");
|
||||
pendingRequestMarkers = [{ userId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequestMarkers));
|
||||
|
||||
// Act
|
||||
sut.setupUnlockListenersForProcessingAuthRequests(destroy$);
|
||||
@@ -291,15 +221,16 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
|
||||
// Assert
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
expect(processSpy).not.toHaveBeenCalled();
|
||||
expect(messagingService.send).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should handle multiple user switches correctly", async () => {
|
||||
// Arrange
|
||||
const processSpy = jest.spyOn(sut, "processPendingAuthRequests");
|
||||
const secondUserId = "second-user-id" as UserId;
|
||||
authStatusForSubjects.set(otherUserId, new BehaviorSubject(AuthenticationStatus.Unlocked));
|
||||
authStatusForSubjects.set(secondUserId, new BehaviorSubject(AuthenticationStatus.Locked));
|
||||
pendingRequestMarkers = [{ userId: otherUserId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequestMarkers));
|
||||
|
||||
// Act
|
||||
sut.setupUnlockListenersForProcessingAuthRequests(destroy$);
|
||||
@@ -323,15 +254,16 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
// Assert
|
||||
expect(processSpy).toHaveBeenCalledTimes(1);
|
||||
expect(messagingService.send).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("authentication status transitions", () => {
|
||||
it("should process pending auth requests when active account transitions to Unlocked", async () => {
|
||||
// Arrange
|
||||
const processSpy = jest.spyOn(sut, "processPendingAuthRequests");
|
||||
activeAccountStatus$.next(AuthenticationStatus.Locked);
|
||||
pendingRequestMarkers = [{ userId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequestMarkers));
|
||||
|
||||
// Act
|
||||
sut.setupUnlockListenersForProcessingAuthRequests(destroy$);
|
||||
@@ -339,13 +271,14 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
|
||||
// Assert
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
expect(processSpy).toHaveBeenCalledTimes(1);
|
||||
expect(messagingService.send).toHaveBeenCalledWith("openLoginApproval");
|
||||
});
|
||||
|
||||
it("should process pending auth requests when transitioning from LoggedOut to Unlocked", async () => {
|
||||
// Arrange
|
||||
const processSpy = jest.spyOn(sut, "processPendingAuthRequests");
|
||||
activeAccountStatus$.next(AuthenticationStatus.LoggedOut);
|
||||
pendingRequestMarkers = [{ userId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequestMarkers));
|
||||
|
||||
// Act
|
||||
sut.setupUnlockListenersForProcessingAuthRequests(destroy$);
|
||||
@@ -353,32 +286,34 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
|
||||
// Assert
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
expect(processSpy).toHaveBeenCalledTimes(1);
|
||||
expect(messagingService.send).toHaveBeenCalledWith("openLoginApproval");
|
||||
});
|
||||
|
||||
it("should NOT process pending auth requests when transitioning from Unlocked to Locked", async () => {
|
||||
// Arrange
|
||||
const processSpy = jest.spyOn(sut, "processPendingAuthRequests");
|
||||
activeAccountStatus$.next(AuthenticationStatus.Unlocked);
|
||||
pendingRequestMarkers = [{ userId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequestMarkers));
|
||||
|
||||
// Act
|
||||
sut.setupUnlockListenersForProcessingAuthRequests(destroy$);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
// Reset spy to ignore the initial trigger (from null -> Unlocked)
|
||||
processSpy.mockClear();
|
||||
// Clear any calls from the initial trigger (from null -> Unlocked)
|
||||
messagingService.send.mockClear();
|
||||
|
||||
activeAccountStatus$.next(AuthenticationStatus.Locked);
|
||||
|
||||
// Assert
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
expect(processSpy).not.toHaveBeenCalled();
|
||||
expect(messagingService.send).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should NOT process pending auth requests when transitioning from Locked to LoggedOut", async () => {
|
||||
// Arrange
|
||||
const processSpy = jest.spyOn(sut, "processPendingAuthRequests");
|
||||
activeAccountStatus$.next(AuthenticationStatus.Locked);
|
||||
pendingRequestMarkers = [{ userId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequestMarkers));
|
||||
|
||||
// Act
|
||||
sut.setupUnlockListenersForProcessingAuthRequests(destroy$);
|
||||
@@ -386,32 +321,34 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
|
||||
// Assert
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
expect(processSpy).not.toHaveBeenCalled();
|
||||
expect(messagingService.send).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should NOT process pending auth requests when staying in Unlocked status", async () => {
|
||||
// Arrange
|
||||
const processSpy = jest.spyOn(sut, "processPendingAuthRequests");
|
||||
activeAccountStatus$.next(AuthenticationStatus.Unlocked);
|
||||
pendingRequestMarkers = [{ userId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequestMarkers));
|
||||
|
||||
// Act
|
||||
sut.setupUnlockListenersForProcessingAuthRequests(destroy$);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
// Reset spy to ignore the initial trigger (from null -> Unlocked)
|
||||
processSpy.mockClear();
|
||||
// Clear any calls from the initial trigger (from null -> Unlocked)
|
||||
messagingService.send.mockClear();
|
||||
|
||||
activeAccountStatus$.next(AuthenticationStatus.Unlocked);
|
||||
|
||||
// Assert
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
expect(processSpy).not.toHaveBeenCalled();
|
||||
expect(messagingService.send).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should handle multiple status transitions correctly", async () => {
|
||||
// Arrange
|
||||
const processSpy = jest.spyOn(sut, "processPendingAuthRequests");
|
||||
activeAccountStatus$.next(AuthenticationStatus.Locked);
|
||||
pendingRequestMarkers = [{ userId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequestMarkers));
|
||||
|
||||
// Act
|
||||
sut.setupUnlockListenersForProcessingAuthRequests(destroy$);
|
||||
@@ -429,15 +366,17 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
// Assert
|
||||
expect(processSpy).toHaveBeenCalledTimes(2);
|
||||
expect(messagingService.send).toHaveBeenCalledTimes(2);
|
||||
expect(messagingService.send).toHaveBeenCalledWith("openLoginApproval");
|
||||
});
|
||||
});
|
||||
|
||||
describe("subscription cleanup", () => {
|
||||
it("should stop processing when destroy$ emits", async () => {
|
||||
// Arrange
|
||||
const processSpy = jest.spyOn(sut, "processPendingAuthRequests");
|
||||
authStatusForSubjects.set(otherUserId, new BehaviorSubject(AuthenticationStatus.Unlocked));
|
||||
pendingRequestMarkers = [{ userId: otherUserId, receivedAtMs: Date.now() }];
|
||||
pendingAuthRequestsState.getAll$.mockReturnValue(of(pendingRequestMarkers));
|
||||
|
||||
// Act
|
||||
sut.setupUnlockListenersForProcessingAuthRequests(destroy$);
|
||||
@@ -456,7 +395,7 @@ describe("DefaultAuthRequestAnsweringService", () => {
|
||||
|
||||
// Assert
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
expect(processSpy).not.toHaveBeenCalled();
|
||||
expect(messagingService.send).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user