1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-11 13:53:34 +00:00

[PM-27059] Browser: Retain vault filters when editing a cipher from the dropdown (#16910)

* Skip clearing vault filters if a cipher is being edited

* add unit tests for clearVaultStateGuard
This commit is contained in:
Nik Gilmore
2025-10-24 09:36:16 -07:00
committed by GitHub
parent f5f9d1881e
commit b26be1eec6
2 changed files with 85 additions and 3 deletions

View File

@@ -0,0 +1,77 @@
import { TestBed } from "@angular/core/testing";
import { RouterStateSnapshot } from "@angular/router";
import { VaultV2Component } from "../components/vault-v2/vault-v2.component";
import { VaultPopupItemsService } from "../services/vault-popup-items.service";
import { VaultPopupListFiltersService } from "../services/vault-popup-list-filters.service";
import { clearVaultStateGuard } from "./clear-vault-state.guard";
describe("clearVaultStateGuard", () => {
let applyFilterSpy: jest.Mock;
let resetFilterFormSpy: jest.Mock;
beforeEach(() => {
applyFilterSpy = jest.fn();
resetFilterFormSpy = jest.fn();
TestBed.configureTestingModule({
providers: [
{
provide: VaultPopupItemsService,
useValue: { applyFilter: applyFilterSpy },
},
{
provide: VaultPopupListFiltersService,
useValue: { resetFilterForm: resetFilterFormSpy },
},
],
});
});
afterEach(() => {
jest.clearAllMocks();
});
it.each([
"/view-cipher?cipherId=123",
"/edit-cipher?cipherId=123",
"/clone-cipher?cipherId=123",
"/assign-collections?cipherId=123",
])("should not clear vault state when viewing or editing a cipher: %s", (url) => {
const nextState = { url } as RouterStateSnapshot;
const result = TestBed.runInInjectionContext(() =>
clearVaultStateGuard({} as VaultV2Component, null, null, nextState),
);
expect(result).toBe(true);
expect(applyFilterSpy).not.toHaveBeenCalled();
expect(resetFilterFormSpy).not.toHaveBeenCalled();
});
it.each(["/settings", "/tabs/settings"])(
"should clear vault state when navigating to non-cipher routes: %s",
(url) => {
const nextState = { url } as RouterStateSnapshot;
const result = TestBed.runInInjectionContext(() =>
clearVaultStateGuard({} as VaultV2Component, null, null, nextState),
);
expect(result).toBe(true);
expect(applyFilterSpy).toHaveBeenCalledWith("");
expect(resetFilterFormSpy).toHaveBeenCalled();
},
);
it("should not clear vault state when not changing states", () => {
const result = TestBed.runInInjectionContext(() =>
clearVaultStateGuard({} as VaultV2Component, null, null, null),
);
expect(result).toBe(true);
expect(applyFilterSpy).not.toHaveBeenCalled();
expect(resetFilterFormSpy).not.toHaveBeenCalled();
});
});

View File

@@ -7,7 +7,8 @@ import { VaultPopupListFiltersService } from "../services/vault-popup-list-filte
/**
* Guard to clear the vault state (search and filter) when navigating away from the vault view.
* This ensures the search and filter state is reset when navigating between different tabs, except viewing a cipher.
* This ensures the search and filter state is reset when navigating between different tabs,
* except viewing or editing a cipher.
*/
export const clearVaultStateGuard: CanDeactivateFn<VaultV2Component> = (
component: VaultV2Component,
@@ -17,7 +18,7 @@ export const clearVaultStateGuard: CanDeactivateFn<VaultV2Component> = (
) => {
const vaultPopupItemsService = inject(VaultPopupItemsService);
const vaultPopupListFiltersService = inject(VaultPopupListFiltersService);
if (nextState && !isViewingCipher(nextState.url)) {
if (nextState && !isCipherOpen(nextState.url)) {
vaultPopupItemsService.applyFilter("");
vaultPopupListFiltersService.resetFilterForm();
}
@@ -25,4 +26,8 @@ export const clearVaultStateGuard: CanDeactivateFn<VaultV2Component> = (
return true;
};
const isViewingCipher = (url: string): boolean => url.includes("view-cipher");
const isCipherOpen = (url: string): boolean =>
url.includes("view-cipher") ||
url.includes("assign-collections") ||
url.includes("edit-cipher") ||
url.includes("clone-cipher");