1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 07:43:35 +00:00

[PM-26055] Vault item dialog header fix (#16553)

* [PM-26055] Fix dialog title mode mapping logic

* [PM-26055] Add unit tests
This commit is contained in:
Shane Melton
2025-09-23 16:40:52 -07:00
committed by GitHub
parent 9639b72055
commit dcbe4f9e09
2 changed files with 139 additions and 5 deletions

View File

@@ -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<TestVaultItemDialogComponent>;
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");
});
});
});

View File

@@ -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);
}