From d47ffdfe8fd39404bf0819f45430815ed543f4b8 Mon Sep 17 00:00:00 2001 From: Alec Rippberger Date: Tue, 1 Oct 2024 21:17:03 -0500 Subject: [PATCH] Add login component services tests. --- .../extension-login-component.service.spec.ts | 39 +++++++ .../desktop-login-component.service.spec.ts | 63 +++++++++++ .../login/web-login-component.service.spec.ts | 105 ++++++++++++++++++ 3 files changed, 207 insertions(+) create mode 100644 apps/browser/src/auth/popup/login/extension-login-component.service.spec.ts create mode 100644 apps/desktop/src/auth/login/desktop-login-component.service.spec.ts create mode 100644 apps/web/src/app/auth/core/services/login/web-login-component.service.spec.ts diff --git a/apps/browser/src/auth/popup/login/extension-login-component.service.spec.ts b/apps/browser/src/auth/popup/login/extension-login-component.service.spec.ts new file mode 100644 index 0000000000..54137fd5c6 --- /dev/null +++ b/apps/browser/src/auth/popup/login/extension-login-component.service.spec.ts @@ -0,0 +1,39 @@ +import { TestBed } from "@angular/core/testing"; + +import { DefaultLoginComponentService } from "@bitwarden/auth/angular"; + +import { flagEnabled } from "../../../platform/flags"; + +import { ExtensionLoginComponentService } from "./extension-login-component.service"; + +jest.mock("../../../platform/flags", () => ({ + flagEnabled: jest.fn(), +})); + +describe("ExtensionLoginComponentService", () => { + let service: ExtensionLoginComponentService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + ExtensionLoginComponentService, + { provide: DefaultLoginComponentService, useClass: ExtensionLoginComponentService }, + ], + }); + service = TestBed.inject(ExtensionLoginComponentService); + }); + + it("creates the service", () => { + expect(service).toBeTruthy(); + }); + + it("returns true if showPasswordless flag is enabled", () => { + (flagEnabled as jest.Mock).mockReturnValue(true); + expect(service.isLoginViaAuthRequestSupported()).toBe(true); + }); + + it("returns false if showPasswordless flag is disabled", () => { + (flagEnabled as jest.Mock).mockReturnValue(false); + expect(service.isLoginViaAuthRequestSupported()).toBeFalsy(); + }); +}); diff --git a/apps/desktop/src/auth/login/desktop-login-component.service.spec.ts b/apps/desktop/src/auth/login/desktop-login-component.service.spec.ts new file mode 100644 index 0000000000..e2c9316546 --- /dev/null +++ b/apps/desktop/src/auth/login/desktop-login-component.service.spec.ts @@ -0,0 +1,63 @@ +import { TestBed } from "@angular/core/testing"; +import { MockProxy } from "jest-mock-extended"; + +import { DefaultLoginComponentService } from "@bitwarden/auth/angular"; +import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; +import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { ToastService } from "@bitwarden/components"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; + +import { DesktopLoginComponentService } from "./desktop-login-component.service"; + +(global as any).ipc = { + platform: { + isAppImage: jest.fn(), + isSnapStore: jest.fn(), + isDev: jest.fn(), + localhostCallbackService: { + openSsoPrompt: jest.fn(), + }, + }, +}; + +describe("DesktopLoginComponentService", () => { + let service: DesktopLoginComponentService; + let i18nService: MockProxy; + let toastService: MockProxy; + let ssoLoginService: MockProxy; + let passwordGenerationService: MockProxy; + let cryptoFunctionService: MockProxy; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + DesktopLoginComponentService, + { provide: DefaultLoginComponentService, useClass: DesktopLoginComponentService }, + { provide: I18nService, useValue: i18nService }, + { provide: ToastService, useValue: toastService }, + { provide: SsoLoginServiceAbstraction, useValue: ssoLoginService }, + { provide: PasswordGenerationServiceAbstraction, useValue: passwordGenerationService }, + { provide: CryptoFunctionService, useValue: cryptoFunctionService }, + ], + }); + + service = TestBed.inject(DesktopLoginComponentService); + + jest.spyOn(service, "launchSsoBrowserWindow").mockImplementation(async () => {}); + }); + + it("creates the service", () => { + expect(service).toBeTruthy(); + }); + + it("calls launchSsoBrowserWindow if isAppImage, isSnapStore, and isDev are false", async () => { + (global as any).ipc.platform.isAppImage.mockReturnValue(false); + (global as any).ipc.platform.isSnapStore.mockReturnValue(false); + (global as any).ipc.platform.isDev.mockReturnValue(false); + + await service.launchSsoBrowserWindow("user@example.com", "desktop"); + + expect(service.launchSsoBrowserWindow).toHaveBeenCalledWith("user@example.com", "desktop"); + }); +}); diff --git a/apps/web/src/app/auth/core/services/login/web-login-component.service.spec.ts b/apps/web/src/app/auth/core/services/login/web-login-component.service.spec.ts new file mode 100644 index 0000000000..3dbbe1471c --- /dev/null +++ b/apps/web/src/app/auth/core/services/login/web-login-component.service.spec.ts @@ -0,0 +1,105 @@ +import { TestBed } from "@angular/core/testing"; +import { UrlTree } from "@angular/router"; + +import { DefaultLoginComponentService } from "@bitwarden/auth/angular"; +import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; +import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; + +import { RouterService } from "../../../../../../../../apps/web/src/app/core"; +import { flagEnabled } from "../../../../../utils/flags"; +import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service"; + +import { WebLoginComponentService } from "./web-login-component.service"; + +jest.mock("../../../../../utils/flags", () => ({ + flagEnabled: jest.fn(), +})); + +describe("WebLoginComponentService", () => { + let service: WebLoginComponentService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + WebLoginComponentService, + { provide: DefaultLoginComponentService, useClass: WebLoginComponentService }, + { + provide: AcceptOrganizationInviteService, + useValue: { + getOrganizationInvite: jest.fn(), + }, + }, + { + provide: LogService, + useValue: { + error: jest.fn(), + }, + }, + { + provide: PolicyApiServiceAbstraction, + useValue: { + getPoliciesByToken: jest.fn(), + }, + }, + { provide: InternalPolicyService, useValue: {} }, + { + provide: RouterService, + useValue: { + setPreviousUrl: jest.fn(), + }, + }, + ], + }); + service = TestBed.inject(WebLoginComponentService); + }); + + it("creates the service", () => { + expect(service).toBeTruthy(); + }); + + describe("isLoginViaAuthRequestSupported", () => { + it("returns true if showPasswordless flag is enabled", () => { + (flagEnabled as jest.Mock).mockReturnValue(true); + expect(service.isLoginViaAuthRequestSupported()).toBe(true); + }); + + it("returns false if showPasswordless flag is disabled", () => { + (flagEnabled as jest.Mock).mockReturnValue(false); + expect(service.isLoginViaAuthRequestSupported()).toBeFalsy(); + }); + }); + + it("sets the previous URL", () => { + const route = { toString: () => "test-url" } as UrlTree; + const routerServiceSpy = jest.spyOn(service.routerService, "setPreviousUrl"); + service.setPreviousUrl(route); + expect(routerServiceSpy).toHaveBeenCalledWith("test-url"); + }); + + it("returns undefined if organization invite is null", async () => { + jest + .spyOn(service.acceptOrganizationInviteService, "getOrganizationInvite") + .mockResolvedValue(null); + const result = await service.getOrgPolicies(); + expect(result).toBeUndefined(); + }); + + it("logs an error if getPoliciesByToken throws an error", async () => { + const error = new Error("Test error"); + jest.spyOn(service.acceptOrganizationInviteService, "getOrganizationInvite").mockResolvedValue({ + organizationId: "org-id", + token: "token", + email: "email", + organizationUserId: "org-user-id", + initOrganization: false, + orgSsoIdentifier: "sso-id", + orgUserHasExistingUser: false, + organizationName: "org-name", + }); + jest.spyOn(service.policyApiService, "getPoliciesByToken").mockRejectedValue(error); + const logServiceSpy = jest.spyOn(service.logService, "error"); + await service.getOrgPolicies(); + expect(logServiceSpy).toHaveBeenCalledWith(error); + }); +});