|
18 | 18 | */ |
19 | 19 |
|
20 | 20 | /* |
21 | | - * Locks the two invariants of the Astryx sidenav column that live only in |
22 | | - * hand-tuned CSS and were, before this file, verified by nothing (#3834): |
23 | | - * |
24 | | - * 1. Geometry — `.maka-sidenav-motion { height: 100% }` (shell-layout.css). |
25 | | - * Without a definite height the wrapper grows to its unclipped content and |
26 | | - * the footer leaves the window. `sidenav footer stays inside the window` |
27 | | - * is the lock shell-layout.css's comment already names by this path. |
28 | | - * |
29 | | - * 2. The resize handle — the two workaround rules that keep it grabbable: |
30 | | - * `top: var(--h-titlebar)` (shell-layout.css) and `transform: none |
31 | | - * !important` (sidebar.css, the Astryx hitAreaOffsetX fix). A regression |
32 | | - * in either leaves a column that looks right and simply cannot be dragged. |
33 | | - * `resize handle drag ...` grabs the handle at its vertical centre — the |
34 | | - * exact point the bug left ungrabbable — and asserts the width changes. |
35 | | - * |
36 | | - * Both run on `projectSidebarWindow`: the only fixture that boots the shell |
37 | | - * expanded (so the handle is mounted) with a populated, overflowing list (60 |
38 | | - * sessions, so the footer has content to be pushed past). It opens with the |
39 | | - * search modal over an inert shell, so dismiss it first — the same first step |
40 | | - * sidebar-project-row.spec.ts takes. |
| 21 | + * Locks `.maka-sidenav-motion { height: 100% }` in shell-layout.css. Without a |
| 22 | + * definite height, the sidenav grows to its unclipped content and pushes the |
| 23 | + * footer below the window. `projectSidebarWindow` supplies the overflowing |
| 24 | + * session list needed to expose that regression. |
41 | 25 | */ |
42 | 26 |
|
43 | 27 | import { expect, test } from './fixtures'; |
44 | | -import { |
45 | | - SESSION_LIST_EXPANDED_MAX_WIDTH, |
46 | | - SESSION_LIST_EXPANDED_MIN_WIDTH, |
47 | | -} from '../src/renderer/features/session-navigation/testing'; |
48 | | -import type { Locator, Page } from '@playwright/test'; |
| 28 | +import type { Page } from '@playwright/test'; |
49 | 29 |
|
50 | | -async function revealPopulatedSidebar(page: Page): Promise<Locator> { |
| 30 | +async function revealPopulatedSidebar(page: Page): Promise<void> { |
51 | 31 | await page.keyboard.press('Escape'); |
52 | 32 | await expect(page.locator('[data-maka-contract="search-modal"]')).not.toBeVisible(); |
53 | 33 | const sidebar = page.getByRole('navigation', { name: '任务列表' }); |
54 | 34 | await expect(sidebar).toBeVisible(); |
55 | | - return sidebar; |
56 | | -} |
57 | | - |
58 | | -async function wrapperWidth(wrapper: Locator): Promise<number> { |
59 | | - const box = await wrapper.boundingBox(); |
60 | | - if (!box) throw new Error('sidenav wrapper (.maka-sidenav-motion) has no visible bounds'); |
61 | | - return box.width; |
62 | 35 | } |
63 | 36 |
|
64 | 37 | test('sidenav footer stays inside the window under an overflowing list', async ({ |
@@ -98,67 +71,3 @@ test('sidenav footer stays inside the window under an overflowing list', async ( |
98 | 71 | expect(wrapperBox!.y + wrapperBox!.height).toBeLessThanOrEqual(innerHeight + 1); |
99 | 72 | expect(footerBox!.y + footerBox!.height).toBeLessThanOrEqual(innerHeight + 1); |
100 | 73 | }); |
101 | | - |
102 | | -test('resize handle drag from its vertical centre changes the column width', async ({ |
103 | | - projectSidebarWindow: page, |
104 | | -}) => { |
105 | | - await revealPopulatedSidebar(page); |
106 | | - |
107 | | - const handle = page.getByTestId('astryx-sidenav-resize-handle'); |
108 | | - await expect(handle).toBeVisible(); |
109 | | - const wrapper = page.locator('.maka-sidenav-motion'); |
110 | | - |
111 | | - const initialWidth = await wrapperWidth(wrapper); |
112 | | - expect(initialWidth).toBeGreaterThanOrEqual(SESSION_LIST_EXPANDED_MIN_WIDTH); |
113 | | - expect(initialWidth).toBeLessThanOrEqual(SESSION_LIST_EXPANDED_MAX_WIDTH); |
114 | | - |
115 | | - // Grab the vertical centre. The Astryx hitAreaOffsetX bug leaves only the top |
116 | | - // half grabbable, so the centre no-ops unless sidebar.css's `transform: none |
117 | | - // !important` is applied — this point is the regression probe for that rule. |
118 | | - // Let locator actionability resolve the handle's live centre before reading |
119 | | - // its endpoint; replaying a box captured before that wait can miss a moving |
120 | | - // 16px handle under load. |
121 | | - await handle.hover(); |
122 | | - const handleBox = await handle.boundingBox(); |
123 | | - if (!handleBox) throw new Error('resize handle has no visible bounds'); |
124 | | - const grabX = handleBox.x + handleBox.width / 2; |
125 | | - const grabY = handleBox.y + handleBox.height / 2; |
126 | | - |
127 | | - await page.mouse.down(); |
128 | | - |
129 | | - // Astryx flags the separator while a drag is in flight; shell-layout.css keys |
130 | | - // its transition-suppression (`:has([data-resizing])`) on it, so the width |
131 | | - // tracks the pointer live rather than easing behind it. Check the second the |
132 | | - // pointer goes down, so a missed grab fails directly instead of timing out on |
133 | | - // an unrelated width assertion. |
134 | | - await expect(handle).toHaveAttribute('data-resizing', /.*/); |
135 | | - await page.mouse.move(grabX + 80, grabY, { steps: 20 }); |
136 | | - await expect.poll(() => wrapperWidth(wrapper)).toBeGreaterThan(initialWidth + 40); |
137 | | - await page.mouse.up(); |
138 | | - await expect(handle).not.toHaveAttribute('data-resizing', /.*/); |
139 | | - |
140 | | - const widenedWidth = await wrapperWidth(wrapper); |
141 | | - expect(widenedWidth).toBeGreaterThan(initialWidth + 40); |
142 | | - expect(widenedWidth).toBeLessThanOrEqual(SESSION_LIST_EXPANDED_MAX_WIDTH + 1); |
143 | | - |
144 | | - // Drag the other way to prove the handle also narrows the column, grabbing |
145 | | - // the centre again at the handle's new right-edge position. |
146 | | - await handle.hover(); |
147 | | - const widenedHandleBox = await handle.boundingBox(); |
148 | | - if (!widenedHandleBox) throw new Error('resize handle lost its bounds after widening'); |
149 | | - const shrinkX = widenedHandleBox.x + widenedHandleBox.width / 2; |
150 | | - const shrinkY = widenedHandleBox.y + widenedHandleBox.height / 2; |
151 | | - |
152 | | - await page.mouse.down(); |
153 | | - await expect(handle).toHaveAttribute('data-resizing', /.*/); |
154 | | - // Undo the 80px widening. Keeping the reverse drag symmetric means every |
155 | | - // width accepted by the precondition stays above the collapsible region. |
156 | | - await page.mouse.move(shrinkX - 80, shrinkY, { steps: 20 }); |
157 | | - await expect.poll(() => wrapperWidth(wrapper)).toBeLessThan(widenedWidth - 40); |
158 | | - await page.mouse.up(); |
159 | | - await expect(handle).not.toHaveAttribute('data-resizing', /.*/); |
160 | | - |
161 | | - const narrowedWidth = await wrapperWidth(wrapper); |
162 | | - expect(narrowedWidth).toBeLessThan(widenedWidth - 40); |
163 | | - expect(narrowedWidth).toBeGreaterThanOrEqual(SESSION_LIST_EXPANDED_MIN_WIDTH); |
164 | | -}); |
0 commit comments