Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[🐞] trigger()/waitForDrain resolve before a lazily loaded useVisibleTask$ runs

Open
#9,121 3 comments 0 reactions 0 assignees View on GitHub

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
Domain
frontend, testing

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

Open in Codespaces

Starts the project's dev container in your browser, under your own GitHub account.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from QwikDev/qwik

All issues in QwikDev/qwik

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.