diff --git a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.spec.ts b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.spec.ts new file mode 100644 index 00000000000..e45a82d82ba --- /dev/null +++ b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.spec.ts @@ -0,0 +1,132 @@ +import { ComponentFixture, TestBed } from "@angular/core/testing"; +import { provideNoopAnimations } from "@angular/platform-browser/animations"; +import { ActivatedRoute, Router } from "@angular/router"; + +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service"; +import { CipherType } from "@bitwarden/common/vault/enums"; +import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service"; +import { DialogRef, DIALOG_DATA, DialogService, ToastService } from "@bitwarden/components"; + +import { RoutedVaultFilterService } from "../../individual-vault/vault-filter/services/routed-vault-filter.service"; + +import { VaultItemDialogComponent } from "./vault-item-dialog.component"; + +// Create a test subclass to more easily access protected members +class TestVaultItemDialogComponent extends VaultItemDialogComponent { + getTestTitle() { + this["updateTitle"](); + return this.title; + } + setTestParams(params: any) { + this.params = params; + } + setTestCipher(cipher: any) { + this.cipher = cipher; + } + setTestFormConfig(formConfig: any) { + this.formConfig = formConfig; + } +} + +describe("VaultItemDialogComponent", () => { + let fixture: ComponentFixture; + let component: TestVaultItemDialogComponent; + + const baseFormConfig = { + mode: "edit", + cipherType: CipherType.Login, + collections: [], + organizations: [], + admin: false, + organizationDataOwnershipDisabled: false, + folders: [], + }; + + const baseParams = { + mode: "view", + formConfig: { ...baseFormConfig }, + disableForm: false, + activeCollectionId: undefined, + isAdminConsoleAction: false, + restore: undefined, + }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TestVaultItemDialogComponent], + providers: [ + provideNoopAnimations(), + { provide: I18nService, useValue: { t: (key: string) => key } }, + { provide: DIALOG_DATA, useValue: { ...baseParams } }, + { provide: DialogRef, useValue: {} }, + { provide: DialogService, useValue: {} }, + { provide: ToastService, useValue: {} }, + { provide: MessagingService, useValue: {} }, + { provide: LogService, useValue: {} }, + { provide: CipherService, useValue: {} }, + { provide: AccountService, useValue: { activeAccount$: { pipe: () => ({}) } } }, + { provide: Router, useValue: {} }, + { provide: ActivatedRoute, useValue: {} }, + { + provide: BillingAccountProfileStateService, + useValue: { hasPremiumFromAnySource$: () => ({}) }, + }, + { provide: PremiumUpgradePromptService, useValue: {} }, + { provide: CipherAuthorizationService, useValue: {} }, + { provide: ApiService, useValue: {} }, + { provide: EventCollectionService, useValue: {} }, + { provide: RoutedVaultFilterService, useValue: {} }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(TestVaultItemDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe("dialog title", () => { + it("sets title for view mode and Login type", () => { + component.setTestCipher({ type: CipherType.Login }); + component.setTestParams({ mode: "view" }); + component.setTestFormConfig({ ...baseFormConfig, cipherType: CipherType.Login }); + expect(component.getTestTitle()).toBe("viewItemHeaderLogin"); + }); + + it("sets title for form mode (edit) and Card type", () => { + component.setTestCipher(undefined); + component.setTestParams({ mode: "form" }); + component.setTestFormConfig({ ...baseFormConfig, mode: "edit", cipherType: CipherType.Card }); + expect(component.getTestTitle()).toBe("editItemHeaderCard"); + }); + + it("sets title for form mode (add) and Identity type", () => { + component.setTestCipher(undefined); + component.setTestParams({ mode: "form" }); + component.setTestFormConfig({ + ...baseFormConfig, + mode: "add", + cipherType: CipherType.Identity, + }); + expect(component.getTestTitle()).toBe("newItemHeaderIdentity"); + }); + + it("sets title for form mode (clone) and Card type", () => { + component.setTestCipher(undefined); + component.setTestParams({ mode: "form" }); + component.setTestFormConfig({ + ...baseFormConfig, + mode: "clone", + cipherType: CipherType.Card, + }); + expect(component.getTestTitle()).toBe("newItemHeaderCard"); + }); + }); +}); diff --git a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts index b1c591ef5ef..42ad477ff51 100644 --- a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts +++ b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts @@ -535,8 +535,6 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { } private updateTitle(): void { - const mode = this.formConfig.mode || this.params.mode; - const type = this.cipher?.type ?? this.formConfig.cipherType; const translation: { [key: string]: { [key: number]: string } } = { view: { [CipherType.Login]: "viewItemHeaderLogin", @@ -560,11 +558,15 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { [CipherType.SshKey]: "editItemHeaderSshKey", }, }; + const type = this.cipher?.type ?? this.formConfig.cipherType; + let mode: "view" | "edit" | "new" = "view"; - const effectiveMode = - mode === "partial-edit" || mode === "edit" ? "edit" : translation[mode] ? mode : "new"; + if (this.params.mode === "form") { + mode = + this.formConfig.mode === "edit" || this.formConfig.mode === "partial-edit" ? "edit" : "new"; + } - const fullTranslation = translation[effectiveMode][type]; + const fullTranslation = translation[mode][type]; this.title = this.i18nService.t(fullTranslation); }