From 3d8040a79ccd348d231b4c5f3af0e0601fba9512 Mon Sep 17 00:00:00 2001 From: devsi-bruno Date: Wed, 23 Sep 2026 19:02:27 +0530 Subject: [PATCH 1/4] test(playground): cover remaining layout persistence cases EOF Co-authored-by: Cursor --- .../playground/layout-persistence.spec.ts | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/packages/bruno-api-docs/e2e/tests/playground/layout-persistence.spec.ts b/packages/bruno-api-docs/e2e/tests/playground/layout-persistence.spec.ts index 72700fd5..0e4d122e 100644 --- a/packages/bruno-api-docs/e2e/tests/playground/layout-persistence.spec.ts +++ b/packages/bruno-api-docs/e2e/tests/playground/layout-persistence.spec.ts @@ -135,4 +135,101 @@ test.describe('playground layout persistence (desktop)', () => { await expect(playground.content).toBeVisible(); expect(Math.abs((await playground.bottomPanelHeight()) - resized)).toBeLessThan(5); }); + + // BRU-4083 AC2: height (bottom) and width (inline) are stored independently. + test('keeps the bottom height after the inline width is resized', async ({ page, playground }) => { + await playground.open('bottom'); + await playground.grabBottomResizer(); + await playground.movePointerToY(300); + await playground.releasePointer(); + const height = await playground.bottomPanelHeight(); + expect(height).toBeGreaterThan(560); + + await playground.selectDock('inline'); + await playground.grabInlineResizer(); + await playground.movePointerToX(500); + await playground.releasePointer(); + const width = await playground.inlinePanelWidth(); + expect(width).toBeGreaterThan(700); + + await playground.selectDock('bottom'); + expect(Math.abs((await playground.bottomPanelHeight()) - height)).toBeLessThan(5); + + await page.reload(); + await expect(playground.bottomPanel).toBeVisible(); + expect(Math.abs((await playground.bottomPanelHeight()) - height)).toBeLessThan(5); + + await playground.selectDock('inline'); + expect(Math.abs((await playground.inlinePanelWidth()) - width)).toBeLessThan(5); + }); + + // BRU-4083 AC3: first visit with nothing stored uses the default size (60% height / 40% width). + test('opens at the default bottom height when nothing is stored', async ({ playground }) => { + await playground.open('bottom'); + await expect(playground.bottomPanel).toBeVisible(); + expect(await playground.bottomPanelHeight()).toBeGreaterThan(520); + expect(await playground.bottomPanelHeight()).toBeLessThan(560); + }); + + test('opens at the default inline width when nothing is stored', async ({ playground }) => { + await playground.open('inline'); + await expect(playground.inlinePanel).toBeVisible(); + expect(await playground.inlinePanelWidth()).toBeGreaterThan(490); + expect(await playground.inlinePanelWidth()).toBeLessThan(540); + }); + + test('ignores a corrupt stored height and uses the default', async ({ page, playground }) => { + await page.addInitScript(() => { + sessionStorage.setItem('oc-docs:playgroundBottomHeight', 'not-a-number'); + }); + + await playground.open('bottom'); + await expect(playground.bottomPanel).toBeVisible(); + expect(await playground.bottomPanelHeight()).toBeGreaterThan(520); + expect(await playground.bottomPanelHeight()).toBeLessThan(560); + }); + + test('clamps an out-of-range stored height to the viewport', async ({ page, playground }) => { + await page.addInitScript(() => { + sessionStorage.setItem('oc-docs:playgroundBottomHeight', '99999'); + }); + + await playground.open('bottom'); + await expect(playground.bottomPanel).toBeVisible(); + const height = await playground.bottomPanelHeight(); + expect(height).toBeGreaterThan(850); + expect(height).toBeLessThanOrEqual(900); + }); + + // BRU-4083 AC6: no stored dock and no dock in the URL → default bottom. + test('a fresh Try it with no stored dock opens in the bottom dock', async ({ requestPage, playground }) => { + await requestPage.open(REQUEST_PATH); + await requestPage.urlBar.tryButton.click(); + await expect(playground.bottomPanel).toBeVisible(); + await expect(playground.inlinePanel).toHaveCount(0); + await expect(playground.modalPanel).toHaveCount(0); + }); + + // BRU-4083 AC7 / AC8: sizes and dock live in sessionStorage, written after the gesture. + test('writes the resized height to sessionStorage, not localStorage', async ({ page, playground }) => { + await playground.open('bottom'); + await playground.grabBottomResizer(); + await playground.movePointerToY(300); + await playground.releasePointer(); + + const session = await page.evaluate(() => sessionStorage.getItem('oc-docs:playgroundBottomHeight')); + const local = await page.evaluate(() => localStorage.getItem('oc-docs:playgroundBottomHeight')); + expect(session).not.toBeNull(); + expect(Number(session)).toBeGreaterThan(560); + expect(local).toBeNull(); + }); + + test('writes the chosen dock to sessionStorage on switch', async ({ page, playground }) => { + await playground.open('bottom'); + await playground.selectDock('inline'); + await expect(playground.inlinePanel).toBeVisible(); + + expect(await page.evaluate(() => sessionStorage.getItem('oc-docs:playgroundDock'))).toBe('inline'); + expect(await page.evaluate(() => localStorage.getItem('oc-docs:playgroundDock'))).toBeNull(); + }); }); From 82ddfdfa533f06a628a6e45ade8e1a170d986834 Mon Sep 17 00:00:00 2001 From: devsi-bruno Date: Wed, 23 Sep 2026 19:22:42 +0530 Subject: [PATCH 2/4] test(playground): fold sessionStorage checks into existing layout tests EOF Co-authored-by: Cursor --- .../playground/layout-persistence.spec.ts | 33 ++++--------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/packages/bruno-api-docs/e2e/tests/playground/layout-persistence.spec.ts b/packages/bruno-api-docs/e2e/tests/playground/layout-persistence.spec.ts index 0e4d122e..0c40f386 100644 --- a/packages/bruno-api-docs/e2e/tests/playground/layout-persistence.spec.ts +++ b/packages/bruno-api-docs/e2e/tests/playground/layout-persistence.spec.ts @@ -16,6 +16,10 @@ test.describe('playground layout persistence (desktop)', () => { await playground.releasePointer(); const resized = await playground.bottomPanelHeight(); expect(resized).toBeGreaterThan(560); + expect(await page.evaluate(() => localStorage.getItem('oc-docs:playgroundBottomHeight'))).toBeNull(); + expect(Number(await page.evaluate(() => sessionStorage.getItem('oc-docs:playgroundBottomHeight')))).toBeGreaterThan( + 560 + ); await page.reload(); await expect(playground.bottomPanel).toBeVisible(); @@ -38,6 +42,7 @@ test.describe('playground layout persistence (desktop)', () => { }); test('reopens in the last-used dock after closing (fresh open, no dock in URL)', async ({ + page, requestPage, playground }) => { @@ -47,6 +52,8 @@ test.describe('playground layout persistence (desktop)', () => { await playground.selectDock('inline'); await expect(playground.inlinePanel).toBeVisible(); + expect(await page.evaluate(() => sessionStorage.getItem('oc-docs:playgroundDock'))).toBe('inline'); + expect(await page.evaluate(() => localStorage.getItem('oc-docs:playgroundDock'))).toBeNull(); await playground.close(); await expect(playground.header).toHaveCount(0); @@ -136,7 +143,6 @@ test.describe('playground layout persistence (desktop)', () => { expect(Math.abs((await playground.bottomPanelHeight()) - resized)).toBeLessThan(5); }); - // BRU-4083 AC2: height (bottom) and width (inline) are stored independently. test('keeps the bottom height after the inline width is resized', async ({ page, playground }) => { await playground.open('bottom'); await playground.grabBottomResizer(); @@ -163,7 +169,6 @@ test.describe('playground layout persistence (desktop)', () => { expect(Math.abs((await playground.inlinePanelWidth()) - width)).toBeLessThan(5); }); - // BRU-4083 AC3: first visit with nothing stored uses the default size (60% height / 40% width). test('opens at the default bottom height when nothing is stored', async ({ playground }) => { await playground.open('bottom'); await expect(playground.bottomPanel).toBeVisible(); @@ -201,7 +206,6 @@ test.describe('playground layout persistence (desktop)', () => { expect(height).toBeLessThanOrEqual(900); }); - // BRU-4083 AC6: no stored dock and no dock in the URL → default bottom. test('a fresh Try it with no stored dock opens in the bottom dock', async ({ requestPage, playground }) => { await requestPage.open(REQUEST_PATH); await requestPage.urlBar.tryButton.click(); @@ -209,27 +213,4 @@ test.describe('playground layout persistence (desktop)', () => { await expect(playground.inlinePanel).toHaveCount(0); await expect(playground.modalPanel).toHaveCount(0); }); - - // BRU-4083 AC7 / AC8: sizes and dock live in sessionStorage, written after the gesture. - test('writes the resized height to sessionStorage, not localStorage', async ({ page, playground }) => { - await playground.open('bottom'); - await playground.grabBottomResizer(); - await playground.movePointerToY(300); - await playground.releasePointer(); - - const session = await page.evaluate(() => sessionStorage.getItem('oc-docs:playgroundBottomHeight')); - const local = await page.evaluate(() => localStorage.getItem('oc-docs:playgroundBottomHeight')); - expect(session).not.toBeNull(); - expect(Number(session)).toBeGreaterThan(560); - expect(local).toBeNull(); - }); - - test('writes the chosen dock to sessionStorage on switch', async ({ page, playground }) => { - await playground.open('bottom'); - await playground.selectDock('inline'); - await expect(playground.inlinePanel).toBeVisible(); - - expect(await page.evaluate(() => sessionStorage.getItem('oc-docs:playgroundDock'))).toBe('inline'); - expect(await page.evaluate(() => localStorage.getItem('oc-docs:playgroundDock'))).toBeNull(); - }); }); From c7d86c194a7d9f9a64e2b0856e02af51327268f3 Mon Sep 17 00:00:00 2001 From: devsi-bruno Date: Fri, 25 Sep 2026 16:21:37 +0530 Subject: [PATCH 3/4] test(playground): share layout storage keys and read them via the page object EOF Co-authored-by: Cursor --- .../e2e/components/playground.component.ts | 7 +++ .../playground/layout-persistence.spec.ts | 51 ++++++++++--------- .../src/utils/playgroundDock.ts | 3 ++ 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/packages/bruno-api-docs/e2e/components/playground.component.ts b/packages/bruno-api-docs/e2e/components/playground.component.ts index b8e5df11..277a4966 100644 --- a/packages/bruno-api-docs/e2e/components/playground.component.ts +++ b/packages/bruno-api-docs/e2e/components/playground.component.ts @@ -181,4 +181,11 @@ export class PlaygroundComponent extends BaseComponent { async grabInlineResizer(): Promise { await this.grabHandle(this.inlineResizer); } + + async storedItem(area: 'session' | 'local', key: string): Promise { + return this.page.evaluate( + ([area, key]) => (area === 'local' ? localStorage : sessionStorage).getItem(key), + [area, key] as [typeof area, string] + ); + } } diff --git a/packages/bruno-api-docs/e2e/tests/playground/layout-persistence.spec.ts b/packages/bruno-api-docs/e2e/tests/playground/layout-persistence.spec.ts index 0c40f386..016fa4cc 100644 --- a/packages/bruno-api-docs/e2e/tests/playground/layout-persistence.spec.ts +++ b/packages/bruno-api-docs/e2e/tests/playground/layout-persistence.spec.ts @@ -1,4 +1,5 @@ import { test, expect } from '../../playwright'; +import { DOCK_STORAGE_KEY, HEIGHT_STORAGE_KEY } from '../../../src/utils/playgroundDock'; const DESKTOP = { width: 1280, height: 900 }; const openAt = (dock: string): string => `/#/?pg=1&dock=${dock}`; @@ -16,10 +17,8 @@ test.describe('playground layout persistence (desktop)', () => { await playground.releasePointer(); const resized = await playground.bottomPanelHeight(); expect(resized).toBeGreaterThan(560); - expect(await page.evaluate(() => localStorage.getItem('oc-docs:playgroundBottomHeight'))).toBeNull(); - expect(Number(await page.evaluate(() => sessionStorage.getItem('oc-docs:playgroundBottomHeight')))).toBeGreaterThan( - 560 - ); + expect(await playground.storedItem('local', HEIGHT_STORAGE_KEY)).toBeNull(); + expect(Number(await playground.storedItem('session', HEIGHT_STORAGE_KEY))).toBeGreaterThan(560); await page.reload(); await expect(playground.bottomPanel).toBeVisible(); @@ -42,7 +41,6 @@ test.describe('playground layout persistence (desktop)', () => { }); test('reopens in the last-used dock after closing (fresh open, no dock in URL)', async ({ - page, requestPage, playground }) => { @@ -52,8 +50,8 @@ test.describe('playground layout persistence (desktop)', () => { await playground.selectDock('inline'); await expect(playground.inlinePanel).toBeVisible(); - expect(await page.evaluate(() => sessionStorage.getItem('oc-docs:playgroundDock'))).toBe('inline'); - expect(await page.evaluate(() => localStorage.getItem('oc-docs:playgroundDock'))).toBeNull(); + expect(await playground.storedItem('session', DOCK_STORAGE_KEY)).toBe('inline'); + expect(await playground.storedItem('local', DOCK_STORAGE_KEY)).toBeNull(); await playground.close(); await expect(playground.header).toHaveCount(0); @@ -64,9 +62,9 @@ test.describe('playground layout persistence (desktop)', () => { }); test('a dock in the URL wins over the stored dock', async ({ page, playground }) => { - await page.addInitScript(() => { - sessionStorage.setItem('oc-docs:playgroundDock', 'inline'); - }); + await page.addInitScript((key) => { + sessionStorage.setItem(key, 'inline'); + }, DOCK_STORAGE_KEY); await page.goto(openAt('modal')); await expect(playground.modalPanel).toBeVisible(); @@ -78,9 +76,9 @@ test.describe('playground layout persistence (desktop)', () => { requestPage, playground }) => { - await page.addInitScript(() => { - sessionStorage.setItem('oc-docs:playgroundDock', 'sideways'); - }); + await page.addInitScript((key) => { + sessionStorage.setItem(key, 'sideways'); + }, DOCK_STORAGE_KEY); await requestPage.open(REQUEST_PATH); await requestPage.urlBar.tryButton.click(); @@ -172,32 +170,35 @@ test.describe('playground layout persistence (desktop)', () => { test('opens at the default bottom height when nothing is stored', async ({ playground }) => { await playground.open('bottom'); await expect(playground.bottomPanel).toBeVisible(); - expect(await playground.bottomPanelHeight()).toBeGreaterThan(520); - expect(await playground.bottomPanelHeight()).toBeLessThan(560); + const height = await playground.bottomPanelHeight(); + expect(height).toBeGreaterThan(520); + expect(height).toBeLessThanOrEqual(560); }); test('opens at the default inline width when nothing is stored', async ({ playground }) => { await playground.open('inline'); await expect(playground.inlinePanel).toBeVisible(); - expect(await playground.inlinePanelWidth()).toBeGreaterThan(490); - expect(await playground.inlinePanelWidth()).toBeLessThan(540); + const width = await playground.inlinePanelWidth(); + expect(width).toBeGreaterThan(490); + expect(width).toBeLessThanOrEqual(540); }); test('ignores a corrupt stored height and uses the default', async ({ page, playground }) => { - await page.addInitScript(() => { - sessionStorage.setItem('oc-docs:playgroundBottomHeight', 'not-a-number'); - }); + await page.addInitScript((key) => { + sessionStorage.setItem(key, 'not-a-number'); + }, HEIGHT_STORAGE_KEY); await playground.open('bottom'); await expect(playground.bottomPanel).toBeVisible(); - expect(await playground.bottomPanelHeight()).toBeGreaterThan(520); - expect(await playground.bottomPanelHeight()).toBeLessThan(560); + const height = await playground.bottomPanelHeight(); + expect(height).toBeGreaterThan(520); + expect(height).toBeLessThanOrEqual(560); }); test('clamps an out-of-range stored height to the viewport', async ({ page, playground }) => { - await page.addInitScript(() => { - sessionStorage.setItem('oc-docs:playgroundBottomHeight', '99999'); - }); + await page.addInitScript((key) => { + sessionStorage.setItem(key, '99999'); + }, HEIGHT_STORAGE_KEY); await playground.open('bottom'); await expect(playground.bottomPanel).toBeVisible(); diff --git a/packages/bruno-api-docs/src/utils/playgroundDock.ts b/packages/bruno-api-docs/src/utils/playgroundDock.ts index 4a47f28e..917f4ae8 100644 --- a/packages/bruno-api-docs/src/utils/playgroundDock.ts +++ b/packages/bruno-api-docs/src/utils/playgroundDock.ts @@ -12,6 +12,9 @@ export const isDockMode = (value: string | null | undefined): value is DockMode value === 'inline' || value === 'bottom' || value === 'modal'; export const DOCK_STORAGE_KEY = 'oc-docs:playgroundDock'; +export const HEIGHT_STORAGE_KEY = 'oc-docs:playgroundBottomHeight'; +export const WIDTH_STORAGE_KEY = 'oc-docs:playgroundInlineWidth'; +export const COLLAPSED_STORAGE_KEY = 'oc-docs:playgroundBottomCollapsed'; export const readStoredDock = (storage: Storage | null): DockMode | null => { if (!storage) return null; From adac276d02bf756700080a1570b50ecd30246414 Mon Sep 17 00:00:00 2001 From: Arpit Date: Wed, 30 Sep 2026 14:33:38 +0530 Subject: [PATCH 4/4] Create changeset for layout persistence tests Add a changeset for layout persistence test coverage. --- .changeset/smooth-carrots-flow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/smooth-carrots-flow.md diff --git a/.changeset/smooth-carrots-flow.md b/.changeset/smooth-carrots-flow.md new file mode 100644 index 00000000..0638cf22 --- /dev/null +++ b/.changeset/smooth-carrots-flow.md @@ -0,0 +1,5 @@ +--- +"@usebruno/api-docs": patch +--- + +test(playground): cover remaining layout persistence cases