From 9fabb67bca088b6dff6bb6550471aca34a4bc2b5 Mon Sep 17 00:00:00 2001 From: Yif <877193178@qq.com> Date: Sun, 27 Sep 2026 02:28:09 +0800 Subject: [PATCH] test(plugins): trim redundant refresh/tooltip coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the plugin-manager refresh e2e to a single failure round: the store's success and retry outcomes are covered deterministically by manager-store.client.spec.ts, while the e2e keeps its unique value — real 500ms tooltip timing, a running spinner animation, aria-busy, and the portaled failure toast over kept cards. Regenerate refresh.expected.md. Remove the components spec tooltip-delay case; ui-primitives' tooltip.client.spec.tsx already covers 499/500ms hover/focus delay, early cancellation, and portaling. PluginManagerPage.tsx stays at 100% coverage. --- .../plugin-manager/refresh.expected.md | 12 ------ apps/web/tests/plugin-manager.e2e.ts | 17 +++----- .../tests/components.client.spec.tsx | 43 ------------------- 3 files changed, 7 insertions(+), 65 deletions(-) diff --git a/apps/web/tests/expected/plugin-manager/refresh.expected.md b/apps/web/tests/expected/plugin-manager/refresh.expected.md index 24ac557b62..75dda78845 100644 --- a/apps/web/tests/expected/plugin-manager/refresh.expected.md +++ b/apps/web/tests/expected/plugin-manager/refresh.expected.md @@ -4,21 +4,9 @@ Hover at 500ms: Focus at 499ms: 0 tooltips Focus at 500ms: - tooltip "刷新" -success: pending -- button "刷新" [disabled] -{"busy":"true","spinners":1,"cards":11,"skeletons":0,"alerts":[],"retry":0,"toasts":[]} -success: settled -- button "刷新" -{"busy":"false","spinners":0,"cards":11,"skeletons":0,"alerts":[],"retry":0,"toasts":[]} failure: pending - button "刷新" [disabled] {"busy":"true","spinners":1,"cards":11,"skeletons":0,"alerts":[],"retry":0,"toasts":[]} failure: settled - button "刷新" {"busy":"false","spinners":0,"cards":11,"skeletons":0,"alerts":[],"retry":0,"toasts":["刷新失败,请重试"]} -retry: pending -- button "刷新" [disabled] -{"busy":"true","spinners":1,"cards":11,"skeletons":0,"alerts":[],"retry":0,"toasts":[]} -retry: settled -- button "刷新" -{"busy":"false","spinners":0,"cards":11,"skeletons":0,"alerts":[],"retry":0,"toasts":[]} diff --git a/apps/web/tests/plugin-manager.e2e.ts b/apps/web/tests/plugin-manager.e2e.ts index 7fded39f73..bd36ca4970 100644 --- a/apps/web/tests/plugin-manager.e2e.ts +++ b/apps/web/tests/plugin-manager.e2e.ts @@ -283,14 +283,15 @@ describe('web e2e: plugin manager', () => { await probe.clock.pauseAt(await probe.evaluate(() => Date.now() + 1000)) const spy = vi.spyOn(scaffold.ctx.pluginManager, 'listBundles') try { - for (const outcome of ['success', 'failure', 'retry'] as const) { + { + // One failure round exercises the full path: kept cards and spinner while pending, + // then the failure toast with no inline error over the stale cards. Success and retry + // outcomes are the store's deterministic concern, covered by manager-store.client.spec.ts. + const outcome = 'failure' as const const release = Promise.withResolvers() const called = spy.mock.calls.length spy.mockImplementationOnce(() => { - const read = release.promise.then(() => { - if (outcome === 'failure') throw new Error('Fixture plugin refresh failed') - return listBundles() - }) + const read = release.promise.then(() => { throw new Error('Fixture plugin refresh failed') }) reads.push(read) return read }) @@ -320,11 +321,7 @@ describe('web e2e: plugin manager', () => { expect(await panel.getByRole('alert').count()).toBe(0) expect(await panel.getByRole('button', { name: '重试', exact: true }).count()).toBe(0) const toasts = probe.locator('body > [role="alert"]') - if (outcome === 'failure') { - await expect.poll(() => toasts.allTextContents()).toEqual(['刷新失败,请重试']) - } else { - expect(await toasts.count()).toBe(0) - } + await expect.poll(() => toasts.allTextContents()).toEqual(['刷新失败,请重试']) await recordRefresh(`${outcome}: settled`) } finally { release.resolve(undefined) diff --git a/packages/client/ui-plugin-manager/tests/components.client.spec.tsx b/packages/client/ui-plugin-manager/tests/components.client.spec.tsx index 153ab26a86..625672a34d 100644 --- a/packages/client/ui-plugin-manager/tests/components.client.spec.tsx +++ b/packages/client/ui-plugin-manager/tests/components.client.spec.tsx @@ -364,49 +364,6 @@ describe('PluginManagerPage', () => { } }) - it.each(['hover', 'keyboard'] as const)('shows a portaled refresh tooltip after 500ms of %s and cancels early departure', (trigger) => { - vi.useFakeTimers() - try { - const { unmount } = renderTab() - const refresh = screen.getByRole('button', { name: en.refresh }) - const enter = () => { - if (trigger === 'hover') fireEvent.mouseEnter(refresh) - else { - fireEvent.keyDown(document, { key: 'Tab' }) - fireEvent.focus(refresh) - } - } - const leave = () => { - if (trigger === 'hover') fireEvent.mouseLeave(refresh) - else fireEvent.blur(refresh) - } - expect(refresh.getAttribute('title')).toBeNull() - enter() - act(() => { vi.advanceTimersByTime(499) }) - expect(screen.queryByRole('tooltip', { hidden: true })).toBeNull() - leave() - act(() => { vi.advanceTimersByTime(1) }) - expect(screen.queryByRole('tooltip', { hidden: true })).toBeNull() - enter() - act(() => { vi.advanceTimersByTime(499) }) - expect(screen.queryByRole('tooltip', { hidden: true })).toBeNull() - act(() => { vi.advanceTimersByTime(1) }) - const tooltip = screen.getByRole('tooltip', { hidden: true }) - expect(tooltip.textContent).toBe(en.refresh) - expect(tooltip.parentElement).toBe(document.body) - fireEvent.click(refresh) - expect(screen.queryByRole('tooltip', { hidden: true })).toBeNull() - leave() - enter() - unmount() - act(() => { vi.advanceTimersByTime(500) }) - expect(screen.queryByRole('tooltip', { hidden: true })).toBeNull() - } finally { - cleanup() - vi.useRealTimers() - } - }) - it('keeps the read failure and its retry visible while a detail page is open', () => { const { actions, set } = renderTab({ packages: [pkg()] }) fireEvent.click(screen.getByRole('button', { name: en.openDetail.replace('{name}', 'dsh-better-sidebar') }))