diff --git a/NEWS.md b/NEWS.md index d94949db1..75591e939 100644 --- a/NEWS.md +++ b/NEWS.md @@ -15,6 +15,7 @@ border-radius: 128px; of a list with no way back. - Clearing a search or loading a saved view no longer leaves a list with no way back, and saved views keep their top collection. + - The saved views menu no longer reopens after loading a view. ## v2.5.0 - Admin Defaults diff --git a/frontend/src/components/browser/drawer/browser-settings-saved.vue b/frontend/src/components/browser/drawer/browser-settings-saved.vue index 1d780e929..8a9b4dd49 100644 --- a/frontend/src/components/browser/drawer/browser-settings-saved.vue +++ b/frontend/src/components/browser/drawer/browser-settings-saved.vue @@ -3,6 +3,7 @@
Saved Views
({ + default: { currentRoute: { value: { params: {}, query: {} } } }, +})); +vi.mock("@/api/v4/browser", () => ({ getSavedSettingsList: vi.fn() })); + +import BrowserSettingsSaved from "@/components/browser/drawer/browser-settings-saved.vue"; +import vuetify from "@/plugins/vuetify"; +import { useBrowserStore } from "@/stores/browser"; + +const SAVED = [ + { pk: 3, name: "Added Recently" }, + { pk: 7, name: "DC by Year" }, +]; + +describe("picking a saved view", () => { + let wrapper; + + beforeAll(() => { + // VOverlay reads the bare global; happy-dom has no visual viewport. + globalThis.visualViewport ??= { + width: 1024, + height: 768, + offsetLeft: 0, + offsetTop: 0, + scale: 1, + addEventListener() {}, + removeEventListener() {}, + }; + }); + + afterEach(() => { + wrapper?.unmount(); + document.body.replaceChildren(); + }); + + const openMenu = async () => { + const pinia = createTestingPinia({ + initialState: { browser: { savedSettingsList: SAVED } }, + }); + wrapper = mount(BrowserSettingsSaved, { + attachTo: document.body, + global: { plugins: [vuetify, pinia] }, + }); + wrapper.find("input").element.focus(); + await wrapper.find(".v-field").trigger("mousedown"); + await flushPromises(); + return { + combobox: wrapper.findComponent(VCombobox), + store: useBrowserStore(pinia), + }; + }; + + const pickView = async (name) => { + const opened = await openMenu(); + const option = [...document.querySelectorAll('[role="option"]')].find( + (el) => el.textContent.trim() === name, + ); + option.click(); + await flushPromises(); + return opened; + }; + + test("the menu stays closed when the view's settings land", async () => { + const { combobox, store } = await pickView("DC by Year"); + expect(store.loadSavedSettings).toHaveBeenCalledWith(7); + expect(combobox.vm.menu).toBe(false); + + // What loadSavedSettings does once the view arrives. + store.settings.orderBy = "date"; + await flushPromises(); + + expect(combobox.vm.menu).toBe(false); + }); + + test("the loaded view's name is cleared", async () => { + const { combobox, store } = await pickView("DC by Year"); + expect(combobox.vm.search).toBe("DC by Year"); + + store.settings.orderBy = "date"; + await flushPromises(); + + expect(combobox.props("modelValue")).toBeNull(); + expect(combobox.vm.search).toBe(""); + }); + + test("a page load doesn't close a menu opened after it started", async () => { + const { combobox, store } = await openMenu(); + expect(combobox.vm.menu).toBe(true); + + // loadBrowserPage re-sets the breadcrumbs on every response. + store.settings.breadcrumbs = []; + await flushPromises(); + + expect(combobox.vm.menu).toBe(true); + expect(combobox.vm.isFocused).toBe(true); + }); +}); + +export default {};