From 26eae2ef3e5fc4482a17869bf051f306b5e09c7c Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 27 Jul 2026 16:10:14 -0400 Subject: [PATCH] test(ui): deflake workboard view provider release and drawer dialog tests (#114722) The provider-release test raced vi.waitFor's 1s default against the lazy workboard-card-dashboard import; on loaded CI runners the import chain outlives the timeout, so board.get was never observed. Await the element definition and its first update instead, which issue board.get synchronously. Wrap the body in try/finally: the leaked open drawer from a failure corrupted scoped querySelector results in the shared jsdom document and cascaded into the drawer dialog test. --- ui/src/pages/workboard/view.test.ts | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/ui/src/pages/workboard/view.test.ts b/ui/src/pages/workboard/view.test.ts index c185c1217377..e0783e98fcd4 100644 --- a/ui/src/pages/workboard/view.test.ts +++ b/ui/src/pages/workboard/view.test.ts @@ -143,15 +143,29 @@ describe("renderWorkboard", () => { } as unknown as GatewayBrowserClient, }); - renderInto(container, props); - await vi.waitFor(() => expect(request).toHaveBeenCalledWith("board.get", { sessionKey })); + try { + renderInto(container, props); + // The dashboard element is lazily imported; on loaded CI runners that + // import can outlive vi.waitFor's default timeout. Await the definition + // and the upgraded element's first update, which acquires the provider + // and issues board.get synchronously. + await customElements.whenDefined("openclaw-workboard-card-dashboard"); + const dashboard = container.querySelector("openclaw-workboard-card-dashboard"); + expect(dashboard).not.toBeNull(); + await dashboard!.updateComplete; + expect(request).toHaveBeenCalledWith("board.get", { sessionKey }); - state.detailCardId = null; - renderInto(container, props); - await nextFrame(); + state.detailCardId = null; + renderInto(container, props); + await nextFrame(); - expect(removeListener).toHaveBeenCalledOnce(); - container.remove(); + expect(removeListener).toHaveBeenCalledOnce(); + } finally { + // A leaked open drawer poisons later dialog tests in this shared jsdom + // document, so tear down even when an assertion above fails. + render(nothing, container); + container.remove(); + } }); it("keeps manual recovery refresh visible while data is loading", () => {