diff --git a/cms-ui/apps/editor-ui/e2e/device-preview.spec.ts b/cms-ui/apps/editor-ui/e2e/device-preview.spec.ts index 87ae9f71c7..3a759736a6 100644 --- a/cms-ui/apps/editor-ui/e2e/device-preview.spec.ts +++ b/cms-ui/apps/editor-ui/e2e/device-preview.spec.ts @@ -159,6 +159,17 @@ test.describe('Device Preview', () => { await expect(trigger).toBeVisible(); }); + // The compare-mode visibility hide (Vorschau button suppressed when + // editorState.compareWithId is set or editMode is one of the + // COMPARE_VERSION_* values) is implemented in + // EditorToolbarComponent.determineVisibleButtons() and should be + // covered by either a Component-level unit test or the existing + // language-compare e2e flows when those land. It is intentionally + // not asserted here — driving the editor into compare-mode purely + // from this spec would require multi-language test data plus a + // brittle reach into Angular's injector from page.evaluate(), + // which the rest of the test suite avoids. + test('removes the legacy Vorschau entry from the kebab menu', async ({ page }) => { const list = findList(page, ITEM_TYPE_PAGE); const row = findItem(list, IMPORTER.get(PAGE_ONE).id); @@ -319,26 +330,44 @@ test.describe('Device Preview', () => { }); /* --------------------------------------------------------------------- * - * Persistence + * URL state * --------------------------------------------------------------------- */ - test.describe('Persistence', () => { + test.describe('URL state', () => { - test('persists the most recently used preset to local storage', async ({ page }) => { + test('writes the active preset id to the URL as `?device=` query param', async ({ page }) => { await openPageInPreview(page, IMPORTER.get(PAGE_ONE)); await pickDevicePreset(page, PRESET_TABLET.id); await expect(page.locator(FRAME_WRAPPER)).toHaveAttribute('data-active-preset', PRESET_TABLET.id); - // The DevicePreviewService persists via the `LocalStorage` wrapper - // which prefixes its keys with `GCMSUI_`. The setting is - // application-wide (`getForAllUsers`), so the unprefixed key is - // `devicePreview.lastPresetId`. - const stored = await page.evaluate(() => localStorage.getItem('GCMSUI_devicePreview.lastPresetId')); + // URL now carries `?device=tablet` + await expect(page).toHaveURL(/[?&]device=tablet(&|$)/); + }); + + test('removes the query param when "Volle Breite" is picked', async ({ page }) => { + await openPageInPreview(page, IMPORTER.get(PAGE_ONE)); + + await pickDevicePreset(page, PRESET_MOBILE.id); + await expect(page).toHaveURL(/[?&]device=mobile(&|$)/); + + await pickDevicePreset(page, 'clear'); + await expect(page).not.toHaveURL(/[?&]device=/); + }); - // LocalStorage wrapper stringifies values, so the expected - // shape is the JSON-encoded preset id. - expect(stored).toBe(JSON.stringify(PRESET_TABLET.id)); + test('restores the active preset when reloading a URL with `?device=`', async ({ page }) => { + await openPageInPreview(page, IMPORTER.get(PAGE_ONE)); + + await pickDevicePreset(page, PRESET_DESKTOP.id); + const urlWithPreset = page.url(); + expect(urlWithPreset).toMatch(/[?&]device=desktop(&|$)/); + + // Hard-reload the URL to simulate the user opening a shared link. + await page.goto(urlWithPreset); + await page.locator('content-frame iframe.master-frame[loaded="true"]').waitFor({ timeout: 60_000 }); + + await expect(page.locator(FRAME_WRAPPER)).toHaveClass(/device-preview-active/); + await expect(page.locator(FRAME_WRAPPER)).toHaveAttribute('data-active-preset', PRESET_DESKTOP.id); }); }); }); diff --git a/cms-ui/apps/editor-ui/src/app/content-frame/components/content-frame/content-frame.component.html b/cms-ui/apps/editor-ui/src/app/content-frame/components/content-frame/content-frame.component.html index a2ff7374a8..f400bcc3d3 100644 --- a/cms-ui/apps/editor-ui/src/app/content-frame/components/content-frame/content-frame.component.html +++ b/cms-ui/apps/editor-ui/src/app/content-frame/components/content-frame/content-frame.component.html @@ -92,10 +92,10 @@
+ @if (devicePreviewActivePreset) { +
+ {{ devicePreviewActivePreset.icon }} + {{ devicePreviewActivePreset.labelKey | gtxI18n }} + {{ devicePreviewActivePreset.width }} × {{ devicePreviewActivePreset.height }} +
+ } +