[🐞] trigger()/waitForDrain resolve before a lazily loaded useVisibleTask$ runs
Maintainers usually reply within 1 day
@Hansin050203 is already working on this.
Since Oct 19, 2026.
- #9257 by @kenny-ish — closed without merging
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 55/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- typescript
Research direction
Start at executeAfterFlush and runTask, then trace how waitForDrain, trigger with waitForIdle, and createDOM().userEvent await event-handler work. Run the reproduction with npm install && npm test, including src/repro.spec.tsx. Done means the qvisible userEvent assertion observes “visible” without an artificial delay, including when the segment loads lazily.
Written by the indexing model from the issue text.
Description
Which component is affected?
Qwik Runtime
Describe the bug
In v2, useVisibleTask$ runs from executeAfterFlush, which calls runTask() without keeping the returned promise:
function executeAfterFlush(container, cursorData) {
const visibleTasks = cursorData.afterFlushTasks;
// ...
for (let i = 0; i < visibleTasks.length; i++) {
runTask(visibleTasks[i], container, visibleTasks[i].$el$);
}
}
When the task's segment isn't loaded yet, runTask returns a pending promise that nothing tracks. The render promise settles first, so waitForDrain(), trigger(..., { waitForIdle: true }) and therefore createDOM().userEvent all resolve before the visible task has run. State the task writes lands later, outside anything a test can await.
Expected: await userEvent(el, 'qvisible') (or waitForDrain) resolves after the visible task it started has completed and its resulting render has flushed, as it already does for event handlers.
Actual: it resolves while the task is still waiting on its segment import, and assertions see the pre-task DOM. In real test suites this shows up as flaky tests: they pass when the segment module is already warm and fail under parallel load.
Reproduction
https://github.com/ianlet/qwik-v2-visible-task-drain-repro
Steps to reproduce
npm install && npm test
// src/slow-dep.ts: simulates a lazily loaded segment taking 50ms to load
await new Promise((resolve) => setTimeout(resolve, 50));
export const label = "visible";
// src/cmp.tsx
import { component$, useSignal, useVisibleTask$ } from "@qwik.dev/core";
import { label } from "./slow-dep";
export const Cmp = component$(() => {
const text = useSignal("initial");
useVisibleTask$(() => {
text.value = label;
});
return <div>{text.value}</div>;
});
// src/repro.spec.tsx
import { createDOM } from "@qwik.dev/core/testing";
import { Cmp } from "./cmp";
test("userEvent('qvisible') waits for the visible task it starts", async () => {
const { render, screen, userEvent } = await createDOM();
await render(<Cmp />);
await userEvent("div", "qvisible");
expect(screen.querySelector("div")!.textContent).toBe("visible"); // ❌ 'initial'
});
test("control: the visible task does complete eventually", async () => {
const { render, screen, userEvent } = await createDOM();
await render(<Cmp />);
await userEvent("div", "qvisible");
await new Promise((resolve) => setTimeout(resolve, 200));
expect(screen.querySelector("div")!.textContent).toBe("visible"); // ✅
});
The first test fails deterministically; the control passes. Without the artificial delay in slow-dep.ts, the same failure happens intermittently, depending on how fast the segment loads.
The tests run in vitest's happy-dom environment, so the Qwik Vite plugin applies client transforms and the visible task becomes a lazily loaded segment. Under vitest's default node environment both tests pass.
System Info
System:
OS: Linux 7.1 Arch Linux
CPU: (8) x64 Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
Memory: 4.26 GB / 15.36 GB
Container: Yes
Shell: 5.3.15 - /bin/bash
Binaries:
Node: 24.14.1 - ~/.asdf/installs/nodejs/24.14.1/bin/node
npm: 11.11.0 - ~/.asdf/plugins/nodejs/shims/npm
pnpm: 10.33.0 - ~/.asdf/shims/pnpm
npmPackages:
@qwik.dev/core: 2.0.0-rc.0 => 2.0.0-rc.0
happy-dom: ^20.14.5 => 20.14.5
typescript: ^5.9.3 => 5.9.3
vite: ^8.3.2 => 8.3.2
vitest: ^4.1.4 => 4.1.11
Additional Information
Found while adding Qwik v2 support to @noma.to/qwik-testing-library. Testing Library-style render() helpers rely on "await render, then the DOM reflects visible tasks". That held in v1, and in v2 it can't be implemented reliably without a way to await these tasks.
- Dominant language
- TypeScript
- Stars
- 22.1k
- Forks
- 1.4k
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 132
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- Ships a Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from QwikDev/qwik
-
[🐞] Production SSR render errors are never logged or passed to `next()` (node middleware returns on `headersSent` first)Possibly taken @bunnysayzz claimed this 16 days ago. OpenIMPORTANT
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
QwikDev/qwik#9191 · 6 comments ·
Maintainers usually reply within 1 day
-
docs router V2
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
DX enhancement V2
Difficulty 2/5 1-3 hours Newbie friendliness 64/100
QwikDev/qwik#8480 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
QwikDev/qwik#9310 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 4/5 1-2 days Newbie friendliness 63/100
QwikDev/qwik#9308 · 1 comment ·
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Graphify-Labs/graphify#4860 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
sveltejs/eslint-plugin-svelte#1615 ·
Maintainers usually reply within 7 days
-
Parallel reticle_verify opens per-flow leases without the source lease's ignoreHTTPSErrorsPossibly taken @as992949791 claimed this today. Opengood first issue help wanted
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
reticlehq/reticle#2033 · 1 comment ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day