mirror of
https://github.com/bitwarden/browser
synced 2025-12-22 11:13:46 +00:00
* Add creationDate of account to AccountInfo * Added initialization of creationDate. * Removed extra changes. * Fixed tests to initialize creation date * Added helper method to abstract account initialization in tests. * More test updates. * Linting * Additional test fixes. * Fixed spec reference * Fixed imports * Linting. * Fixed browser test. * Modified tsconfig to reference spec file. * Fixed import. * Removed dependency on os. This is necessary so that the @bitwarden/common/spec lib package can be referenced in tests without node. * Revert "Removed dependency on os. This is necessary so that the @bitwarden/common/spec lib package can be referenced in tests without node." This reverts commit669f6557b6. * Updated stories to hard-code new field. * Removed changes to tsconfig * Revert "Removed changes to tsconfig" This reverts commitb7d916e8dc.
241 lines
9.2 KiB
TypeScript
241 lines
9.2 KiB
TypeScript
import { TestBed } from "@angular/core/testing";
|
|
import { Router } from "@angular/router";
|
|
import { mock, MockProxy } from "jest-mock-extended";
|
|
import { BehaviorSubject, of } from "rxjs";
|
|
|
|
import { AccountService, Account } from "@bitwarden/common/auth/abstractions/account.service";
|
|
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
|
import { mockAccountInfoWith } from "@bitwarden/common/spec";
|
|
import { UserId } from "@bitwarden/common/types/guid";
|
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
|
import { CipherRepromptType, CipherType } from "@bitwarden/common/vault/enums";
|
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
|
import { DialogService } from "@bitwarden/components";
|
|
import { PasswordRepromptService } from "@bitwarden/vault";
|
|
|
|
import { DesktopAutofillService } from "../../../autofill/services/desktop-autofill.service";
|
|
import { DesktopSettingsService } from "../../../platform/services/desktop-settings.service";
|
|
import {
|
|
DesktopFido2UserInterfaceService,
|
|
DesktopFido2UserInterfaceSession,
|
|
} from "../../services/desktop-fido2-user-interface.service";
|
|
|
|
import { Fido2CreateComponent } from "./fido2-create.component";
|
|
|
|
describe("Fido2CreateComponent", () => {
|
|
let component: Fido2CreateComponent;
|
|
let mockDesktopSettingsService: MockProxy<DesktopSettingsService>;
|
|
let mockFido2UserInterfaceService: MockProxy<DesktopFido2UserInterfaceService>;
|
|
let mockAccountService: MockProxy<AccountService>;
|
|
let mockCipherService: MockProxy<CipherService>;
|
|
let mockDesktopAutofillService: MockProxy<DesktopAutofillService>;
|
|
let mockDialogService: MockProxy<DialogService>;
|
|
let mockDomainSettingsService: MockProxy<DomainSettingsService>;
|
|
let mockLogService: MockProxy<LogService>;
|
|
let mockPasswordRepromptService: MockProxy<PasswordRepromptService>;
|
|
let mockRouter: MockProxy<Router>;
|
|
let mockSession: MockProxy<DesktopFido2UserInterfaceSession>;
|
|
let mockI18nService: MockProxy<I18nService>;
|
|
|
|
const activeAccountSubject = new BehaviorSubject<Account | null>({
|
|
id: "test-user-id" as UserId,
|
|
...mockAccountInfoWith({
|
|
email: "test@example.com",
|
|
name: "Test User",
|
|
}),
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
mockDesktopSettingsService = mock<DesktopSettingsService>();
|
|
mockFido2UserInterfaceService = mock<DesktopFido2UserInterfaceService>();
|
|
mockAccountService = mock<AccountService>();
|
|
mockCipherService = mock<CipherService>();
|
|
mockDesktopAutofillService = mock<DesktopAutofillService>();
|
|
mockDialogService = mock<DialogService>();
|
|
mockDomainSettingsService = mock<DomainSettingsService>();
|
|
mockLogService = mock<LogService>();
|
|
mockPasswordRepromptService = mock<PasswordRepromptService>();
|
|
mockRouter = mock<Router>();
|
|
mockSession = mock<DesktopFido2UserInterfaceSession>();
|
|
mockI18nService = mock<I18nService>();
|
|
|
|
mockFido2UserInterfaceService.getCurrentSession.mockReturnValue(mockSession);
|
|
mockAccountService.activeAccount$ = activeAccountSubject;
|
|
|
|
await TestBed.configureTestingModule({
|
|
providers: [
|
|
Fido2CreateComponent,
|
|
{ provide: DesktopSettingsService, useValue: mockDesktopSettingsService },
|
|
{ provide: DesktopFido2UserInterfaceService, useValue: mockFido2UserInterfaceService },
|
|
{ provide: AccountService, useValue: mockAccountService },
|
|
{ provide: CipherService, useValue: mockCipherService },
|
|
{ provide: DesktopAutofillService, useValue: mockDesktopAutofillService },
|
|
{ provide: DialogService, useValue: mockDialogService },
|
|
{ provide: DomainSettingsService, useValue: mockDomainSettingsService },
|
|
{ provide: LogService, useValue: mockLogService },
|
|
{ provide: PasswordRepromptService, useValue: mockPasswordRepromptService },
|
|
{ provide: Router, useValue: mockRouter },
|
|
{ provide: I18nService, useValue: mockI18nService },
|
|
],
|
|
}).compileComponents();
|
|
|
|
component = TestBed.inject(Fido2CreateComponent);
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.restoreAllMocks();
|
|
});
|
|
|
|
function createMockCiphers(): CipherView[] {
|
|
const cipher1 = new CipherView();
|
|
cipher1.id = "cipher-1";
|
|
cipher1.name = "Test Cipher 1";
|
|
cipher1.type = CipherType.Login;
|
|
cipher1.login = {
|
|
username: "test1@example.com",
|
|
uris: [{ uri: "https://example.com", match: null }],
|
|
matchesUri: jest.fn().mockReturnValue(true),
|
|
get hasFido2Credentials() {
|
|
return false;
|
|
},
|
|
} as any;
|
|
cipher1.reprompt = CipherRepromptType.None;
|
|
cipher1.deletedDate = null;
|
|
|
|
return [cipher1];
|
|
}
|
|
|
|
describe("ngOnInit", () => {
|
|
beforeEach(() => {
|
|
mockSession.getRpId.mockResolvedValue("example.com");
|
|
Object.defineProperty(mockDesktopAutofillService, "lastRegistrationRequest", {
|
|
get: jest.fn().mockReturnValue({
|
|
userHandle: new Uint8Array([1, 2, 3]),
|
|
}),
|
|
configurable: true,
|
|
});
|
|
mockDomainSettingsService.getUrlEquivalentDomains.mockReturnValue(of(new Set<string>()));
|
|
});
|
|
|
|
it("should initialize session and set show header to false", async () => {
|
|
const mockCiphers = createMockCiphers();
|
|
mockCipherService.getAllDecrypted.mockResolvedValue(mockCiphers);
|
|
|
|
await component.ngOnInit();
|
|
|
|
expect(mockFido2UserInterfaceService.getCurrentSession).toHaveBeenCalled();
|
|
expect(component.session).toBe(mockSession);
|
|
});
|
|
|
|
it("should show error dialog when no active session found", async () => {
|
|
mockFido2UserInterfaceService.getCurrentSession.mockReturnValue(null);
|
|
mockDialogService.openSimpleDialog.mockResolvedValue(false);
|
|
|
|
await component.ngOnInit();
|
|
|
|
expect(mockDialogService.openSimpleDialog).toHaveBeenCalledWith({
|
|
title: { key: "unableToSavePasskey" },
|
|
content: { key: "closeThisBitwardenWindow" },
|
|
type: "danger",
|
|
acceptButtonText: { key: "closeThisWindow" },
|
|
acceptAction: expect.any(Function),
|
|
cancelButtonText: null,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("addCredentialToCipher", () => {
|
|
beforeEach(() => {
|
|
component.session = mockSession;
|
|
});
|
|
|
|
it("should add passkey to cipher", async () => {
|
|
const cipher = createMockCiphers()[0];
|
|
|
|
await component.addCredentialToCipher(cipher);
|
|
|
|
expect(mockSession.notifyConfirmCreateCredential).toHaveBeenCalledWith(true, cipher);
|
|
});
|
|
|
|
it("should not add passkey when password reprompt is cancelled", async () => {
|
|
const cipher = createMockCiphers()[0];
|
|
cipher.reprompt = CipherRepromptType.Password;
|
|
mockPasswordRepromptService.showPasswordPrompt.mockResolvedValue(false);
|
|
|
|
await component.addCredentialToCipher(cipher);
|
|
|
|
expect(mockSession.notifyConfirmCreateCredential).toHaveBeenCalledWith(false, cipher);
|
|
});
|
|
|
|
it("should call openSimpleDialog when cipher already has a fido2 credential", async () => {
|
|
const cipher = createMockCiphers()[0];
|
|
Object.defineProperty(cipher.login, "hasFido2Credentials", {
|
|
get: jest.fn().mockReturnValue(true),
|
|
});
|
|
mockDialogService.openSimpleDialog.mockResolvedValue(true);
|
|
|
|
await component.addCredentialToCipher(cipher);
|
|
|
|
expect(mockDialogService.openSimpleDialog).toHaveBeenCalledWith({
|
|
title: { key: "overwritePasskey" },
|
|
content: { key: "alreadyContainsPasskey" },
|
|
type: "warning",
|
|
});
|
|
expect(mockSession.notifyConfirmCreateCredential).toHaveBeenCalledWith(true, cipher);
|
|
});
|
|
|
|
it("should not add passkey when user cancels overwrite dialog", async () => {
|
|
const cipher = createMockCiphers()[0];
|
|
Object.defineProperty(cipher.login, "hasFido2Credentials", {
|
|
get: jest.fn().mockReturnValue(true),
|
|
});
|
|
mockDialogService.openSimpleDialog.mockResolvedValue(false);
|
|
|
|
await component.addCredentialToCipher(cipher);
|
|
|
|
expect(mockSession.notifyConfirmCreateCredential).toHaveBeenCalledWith(false, cipher);
|
|
});
|
|
});
|
|
|
|
describe("confirmPasskey", () => {
|
|
beforeEach(() => {
|
|
component.session = mockSession;
|
|
});
|
|
|
|
it("should confirm passkey creation successfully", async () => {
|
|
await component.confirmPasskey();
|
|
|
|
expect(mockSession.notifyConfirmCreateCredential).toHaveBeenCalledWith(true);
|
|
});
|
|
|
|
it("should call openSimpleDialog when session is null", async () => {
|
|
component.session = null;
|
|
mockDialogService.openSimpleDialog.mockResolvedValue(false);
|
|
|
|
await component.confirmPasskey();
|
|
|
|
expect(mockDialogService.openSimpleDialog).toHaveBeenCalledWith({
|
|
title: { key: "unableToSavePasskey" },
|
|
content: { key: "closeThisBitwardenWindow" },
|
|
type: "danger",
|
|
acceptButtonText: { key: "closeThisWindow" },
|
|
acceptAction: expect.any(Function),
|
|
cancelButtonText: null,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("closeModal", () => {
|
|
it("should close modal and notify session", async () => {
|
|
component.session = mockSession;
|
|
|
|
await component.closeModal();
|
|
|
|
expect(mockSession.notifyConfirmCreateCredential).toHaveBeenCalledWith(false);
|
|
expect(mockSession.confirmChosenCipher).toHaveBeenCalledWith(null);
|
|
});
|
|
});
|
|
});
|