From 8e6f2c8545089faf2f3f59706512bb83160cda5f Mon Sep 17 00:00:00 2001 From: Isaac Ivins Date: Fri, 23 Jan 2026 10:52:57 -0500 Subject: [PATCH] added testing suite & all expected FFs --- .../src/auth/delete-account.component.html | 2 +- .../src/auth/delete-account.component.spec.ts | 121 ++++++++++++++++++ .../src/auth/delete-account.component.ts | 14 +- libs/common/src/enums/feature-flag.enum.ts | 12 +- 4 files changed, 133 insertions(+), 16 deletions(-) create mode 100644 apps/desktop/src/auth/delete-account.component.spec.ts diff --git a/apps/desktop/src/auth/delete-account.component.html b/apps/desktop/src/auth/delete-account.component.html index 08448e2422d..f8cc671af82 100644 --- a/apps/desktop/src/auth/delete-account.component.html +++ b/apps/desktop/src/auth/delete-account.component.html @@ -6,7 +6,7 @@ {{ "deleteAccountWarning" | i18n }} - @if (migrationMilestone3) { + @if (migrationMilestone4) { { + let component: DeleteAccountComponent; + let i18nService: MockProxy; + let formBuilder: FormBuilder; + let accountApiService: MockProxy; + let toastService: MockProxy; + let configService: MockProxy; + + beforeEach(() => { + jest.clearAllMocks(); + + i18nService = mock(); + formBuilder = new FormBuilder(); + accountApiService = mock(); + toastService = mock(); + configService = mock(); + + i18nService.t.mockImplementation((key: any) => key); + + component = new DeleteAccountComponent( + i18nService, + formBuilder, + accountApiService, + toastService, + configService, + ); + }); + + describe("submit", () => { + const mockVerification: VerificationWithSecret = { + type: 0, + secret: "masterPassword123", + }; + + beforeEach(() => { + component.deleteForm.patchValue({ + verification: mockVerification, + }); + }); + + describe("when feature flag is enabled", () => { + beforeEach(() => { + component["migrationMilestone4"] = true; + }); + + it("should delete account and show success toast on successful deletion", async () => { + accountApiService.deleteAccount.mockResolvedValue(undefined); + + await component.submit(); + + expect(accountApiService.deleteAccount).toHaveBeenCalledWith(mockVerification); + expect(toastService.showToast).toHaveBeenCalledWith({ + variant: "success", + title: "accountDeleted", + message: "accountDeletedDesc", + }); + expect(component["invalidSecret"]).toBe(false); + }); + + it("should set invalidSecret to true when deletion fails", async () => { + accountApiService.deleteAccount.mockRejectedValue(new Error("Invalid credentials")); + + await component.submit(); + + expect(accountApiService.deleteAccount).toHaveBeenCalledWith(mockVerification); + expect(toastService.showToast).not.toHaveBeenCalled(); + expect(component["invalidSecret"]).toBe(true); + }); + + it("should reset invalidSecret to false before attempting deletion", async () => { + component["invalidSecret"] = true; + accountApiService.deleteAccount.mockResolvedValue(undefined); + + await component.submit(); + + expect(component["invalidSecret"]).toBe(false); + }); + }); + + describe("when feature flag is disabled", () => { + beforeEach(() => { + component["migrationMilestone4"] = false; + }); + + it("should delete account and show success toast on successful deletion", async () => { + accountApiService.deleteAccount.mockResolvedValue(undefined); + + await component.submit(); + + expect(accountApiService.deleteAccount).toHaveBeenCalledWith(mockVerification); + expect(toastService.showToast).toHaveBeenCalledWith({ + variant: "success", + title: "accountDeleted", + message: "accountDeletedDesc", + }); + }); + + it("should not set invalidSecret when deletion fails", async () => { + const initialInvalidSecret = component["invalidSecret"]; + accountApiService.deleteAccount.mockRejectedValue(new Error("Invalid credentials")); + + await component.submit(); + + expect(accountApiService.deleteAccount).toHaveBeenCalledWith(mockVerification); + expect(toastService.showToast).not.toHaveBeenCalled(); + expect(component["invalidSecret"]).toBe(initialInvalidSecret); + }); + }); + }); +}); diff --git a/apps/desktop/src/auth/delete-account.component.ts b/apps/desktop/src/auth/delete-account.component.ts index b3bad0eba96..15c2b9d669d 100644 --- a/apps/desktop/src/auth/delete-account.component.ts +++ b/apps/desktop/src/auth/delete-account.component.ts @@ -50,9 +50,9 @@ export class DeleteAccountComponent implements OnInit { protected invalidSecret = false; /** - * Feature flag for UI Migration Milestone 3 + * Feature flag for UI Migration Milestone 4 */ - protected migrationMilestone3 = false; + protected migrationMilestone4 = false; constructor( private i18nService: I18nService, @@ -63,8 +63,8 @@ export class DeleteAccountComponent implements OnInit { ) {} async ngOnInit() { - this.migrationMilestone3 = await this.configService.getFeatureFlag( - FeatureFlag.DesktopUiMigrationMilestone3, + this.migrationMilestone4 = await this.configService.getFeatureFlag( + FeatureFlag.DesktopUiMigrationMilestone4, ); } @@ -78,8 +78,8 @@ export class DeleteAccountComponent implements OnInit { submit = async () => { try { - if (this.migrationMilestone3) { - this.invalidSecret = false; // Reset error state before attempting + if (this.migrationMilestone4) { + this.invalidSecret = false; } const verification = this.deleteForm.get("verification").value; await this.accountApiService.deleteAccount(verification); @@ -89,7 +89,7 @@ export class DeleteAccountComponent implements OnInit { message: this.i18nService.t("accountDeletedDesc"), }); } catch { - if (this.migrationMilestone3) { + if (this.migrationMilestone4) { this.invalidSecret = true; } } diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index f3afd03b975..5684f6e977a 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -77,8 +77,9 @@ export enum FeatureFlag { /* Desktop */ DesktopUiMigrationMilestone1 = "desktop-ui-migration-milestone-1", - DesktopUiMigrationMilestone3 = "desktop-ui-migration-milestone-3", DesktopUiMigrationMilestone2 = "desktop-ui-migration-milestone-2", + DesktopUiMigrationMilestone3 = "desktop-ui-migration-milestone-3", + DesktopUiMigrationMilestone4 = "desktop-ui-migration-milestone-4", /* UIF */ RouterFocusManagement = "router-focus-management", @@ -168,8 +169,9 @@ export const DefaultFeatureFlagValue = { /* Desktop */ [FeatureFlag.DesktopUiMigrationMilestone1]: FALSE, - [FeatureFlag.DesktopUiMigrationMilestone3]: FALSE, [FeatureFlag.DesktopUiMigrationMilestone2]: FALSE, + [FeatureFlag.DesktopUiMigrationMilestone3]: FALSE, + [FeatureFlag.DesktopUiMigrationMilestone4]: FALSE, /* UIF */ [FeatureFlag.RouterFocusManagement]: FALSE, @@ -186,12 +188,6 @@ export function getFeatureFlagValue( serverConfig: ServerConfig | null, flag: Flag, ) { - if (flag === FeatureFlag.DesktopUiMigrationMilestone1) { - return true; - } - if (flag === FeatureFlag.DesktopUiMigrationMilestone3) { - return true; - } if (serverConfig?.featureStates == null || serverConfig.featureStates[flag] == null) { return DefaultFeatureFlagValue[flag]; }