test(plugins): trim redundant refresh/tooltip coverage
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.
This commit is contained in:
1 parent
9c6bdd020c
commit
9fabb67bca
3 files changed
+7
-65
No files matched your search
@@ -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":[]}
|
||||
@@ -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<undefined>()
|
||||
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)
|
||||
|
||||
@@ -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') }))
|
||||
|
||||
Reference in new issue
Block a user