vitest-browser-qwik 0.2.2 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,7 +43,7 @@ export default defineConfig({
43
43
 
44
44
  ```tsx
45
45
  import { defineConfig } from 'vitest/config'
46
- import { qwikVite } from '@builder.io/qwik/optimizer'
46
+ import { qwikVite } from '@qwik.dev/core/optimizer'
47
47
 
48
48
  // optional, run the tests in SSR mode
49
49
  import { testSSR } from 'vitest-browser-qwik/ssr-plugin'
@@ -97,7 +97,7 @@ test('renders counter with SSR', async () => {
97
97
  ### Hook Testing Example
98
98
 
99
99
  ```tsx
100
- import { useSignal } from "@builder.io/qwik";
100
+ import { useSignal } from "@qwik.dev/core";
101
101
  import { expect, test } from "vitest";
102
102
  import { renderHook } from "vitest-browser-qwik";
103
103
  import { useCounter } from "./fixtures/useCounter";
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as cleanup, c as renderServerHTML, i as SSRRenderOptions, o as render, r as RenderResult, s as renderHook } from "./pure-1MgDxC6b.js";
2
- import { JSXOutput } from "@builder.io/qwik";
1
+ import { a as cleanup, c as renderServerHTML, i as SSRRenderOptions, o as render, r as RenderResult, s as renderHook } from "./pure-dqI6lsdL.js";
2
+ import { JSXOutput } from "@qwik.dev/core";
3
3
 
4
4
  //#region src/index.d.ts
5
5
  declare function renderSSR(jsxNode: JSXOutput): Promise<RenderResult>;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { i as renderServerHTML, n as render, r as renderHook, t as cleanup } from "./pure-BRpTMupH.js";
1
+ import { i as renderServerHTML, n as render, r as renderHook, t as cleanup } from "./pure-BlLa_nxU.js";
2
2
  import { beforeEach } from "vitest";
3
3
  import { page } from "vitest/browser";
4
4
 
@@ -1,7 +1,7 @@
1
1
  import { utils } from "vitest/browser";
2
- import { component$, render } from "@builder.io/qwik";
3
- import { getQwikLoaderScript } from "@builder.io/qwik/server";
4
- import { jsx } from "@builder.io/qwik/jsx-runtime";
2
+ import { component$, render } from "@qwik.dev/core";
3
+ import { getQwikLoaderScript } from "@qwik.dev/core/server";
4
+ import { jsx } from "@qwik.dev/core/jsx-runtime";
5
5
 
6
6
  //#region src/pure.tsx
7
7
  const { debug, getElementLocatorSelectors } = utils;
@@ -40,17 +40,17 @@ function setupContainer(baseElement, container) {
40
40
  baseElement
41
41
  };
42
42
  }
43
- function render$1(ui, { container, baseElement } = {}) {
43
+ async function render$1(ui, { container, baseElement } = {}) {
44
44
  csrQwikLoader();
45
45
  const setup = setupContainer(baseElement, container);
46
- render(setup.container, ui);
46
+ await render(setup.container, ui);
47
47
  return createRenderResult(setup.container, setup.baseElement);
48
48
  }
49
49
  function setHTMLWithScripts(container, html) {
50
50
  container.innerHTML = html;
51
51
  container.querySelectorAll("script").forEach((oldScript) => {
52
52
  const newScript = document.createElement("script");
53
- for (const attr of oldScript.attributes) newScript.setAttribute(attr.name, attr.value);
53
+ for (const attr of Array.from(oldScript.attributes)) newScript.setAttribute(attr.name, attr.value);
54
54
  newScript.text = oldScript.textContent ?? "";
55
55
  oldScript.parentNode?.replaceChild(newScript, oldScript);
56
56
  });
@@ -66,7 +66,7 @@ async function renderHook(hook) {
66
66
  const renderPromise = new Promise((resolve) => {
67
67
  resolveRender = resolve;
68
68
  });
69
- const screen = render$1(/* @__PURE__ */ jsx(component$(() => {
69
+ const screen = await render$1(/* @__PURE__ */ jsx(component$(() => {
70
70
  resultContainer.value = hook();
71
71
  resolveRender();
72
72
  return /* @__PURE__ */ jsx("div", { "data-testid": "hook-result" });
@@ -1,5 +1,5 @@
1
1
  import { Locator, LocatorSelectors, PrettyDOMOptions } from "vitest/browser";
2
- import { JSXOutput } from "@builder.io/qwik";
2
+ import { JSXOutput } from "@qwik.dev/core";
3
3
 
4
4
  //#region src/pure.d.ts
5
5
  interface RenderResult extends LocatorSelectors {
@@ -20,7 +20,7 @@ interface SSRRenderOptions {
20
20
  declare function render$1(ui: JSXOutput, {
21
21
  container,
22
22
  baseElement
23
- }?: RenderOptions): RenderResult;
23
+ }?: RenderOptions): Promise<RenderResult>;
24
24
  declare function renderServerHTML(html: string, {
25
25
  container,
26
26
  baseElement
package/dist/pure.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as cleanup, c as renderServerHTML, i as SSRRenderOptions, n as RenderOptions, o as render, r as RenderResult, s as renderHook, t as RenderHookResult } from "./pure-1MgDxC6b.js";
1
+ import { a as cleanup, c as renderServerHTML, i as SSRRenderOptions, n as RenderOptions, o as render, r as RenderResult, s as renderHook, t as RenderHookResult } from "./pure-dqI6lsdL.js";
2
2
  export { RenderHookResult, RenderOptions, RenderResult, SSRRenderOptions, cleanup, render, renderHook, renderServerHTML };
package/dist/pure.js CHANGED
@@ -1,3 +1,3 @@
1
- import { i as renderServerHTML, n as render, r as renderHook, t as cleanup } from "./pure-BRpTMupH.js";
1
+ import { i as renderServerHTML, n as render, r as renderHook, t as cleanup } from "./pure-BlLa_nxU.js";
2
2
 
3
3
  export { cleanup, render, renderHook, renderServerHTML };
@@ -1,5 +1,4 @@
1
1
  import { dirname, relative, resolve } from "node:path";
2
- import { symbolMapper } from "@builder.io/qwik/optimizer";
3
2
  import MagicString from "magic-string";
4
3
  import { parseSync } from "oxc-parser";
5
4
  import { ResolverFactory } from "oxc-resolver";
@@ -212,40 +211,80 @@ function hasCommandsImport(node) {
212
211
  if (!isImportDeclaration(node) || node.source?.value !== "vitest/browser" || !node.specifiers) return false;
213
212
  return node.specifiers.some((spec) => spec.type === "ImportSpecifier" && spec.imported.type === "Identifier" && spec.imported.name === "commands");
214
213
  }
214
+ const getClientModule = async (viteServer, moduleId) => {
215
+ const clientEnv = viteServer.environments.client;
216
+ await clientEnv.fetchModule(moduleId);
217
+ const resolved = await clientEnv.moduleGraph.resolveUrl(moduleId);
218
+ const resolvedId = resolved?.[1];
219
+ if (!resolvedId) throw new Error(`Could not resolve module "${moduleId}" in client environment`);
220
+ const module = clientEnv.moduleGraph.getModuleById(resolvedId);
221
+ console.log("Resolved client module", moduleId, resolved, module);
222
+ if (!module) throw new Error(`Module "${moduleId}" not found in client module graph.`);
223
+ return module;
224
+ };
215
225
  async function renderComponentToSSR(ctx, Component, props = {}) {
216
226
  const viteServer = ctx.project.vite;
217
- const { jsx } = await viteServer.ssrLoadModule("@builder.io/qwik");
227
+ const { jsx } = await viteServer.ssrLoadModule("@qwik.dev/core");
218
228
  const jsxElement = jsx(Component, props);
219
- const { renderToStream } = await viteServer.ssrLoadModule("@builder.io/qwik/server");
220
- let html = "";
229
+ const { renderToStream } = await viteServer.ssrLoadModule("@qwik.dev/core/server");
230
+ const mapping = {};
231
+ if (!ctx.testPath) throw new Error("ctx.testPath is required for SSR rendering");
232
+ const module = await getClientModule(viteServer, ctx.testPath);
233
+ for (const importedModule of module?.importedModules || []) {
234
+ const meta = importedModule.info?.meta;
235
+ if (meta?.segment) {
236
+ const symbol = meta.segment.hash;
237
+ if (symbol && importedModule.id) mapping[symbol] = `/@fs${importedModule.id}`;
238
+ }
239
+ }
240
+ const handlersId = (await getClientModule(viteServer, "@qwik.dev/core/handlers.mjs")).id;
241
+ if (!handlersId) throw new Error("Handlers module ID could not be resolved");
242
+ const handlersExports = await viteServer.ssrLoadModule("@qwik.dev/core/handlers.mjs");
243
+ for (const key of Object.keys(handlersExports)) if (key.startsWith("_")) mapping[key] = handlersId;
244
+ const qwikManifest = {
245
+ manifestHash: "dev",
246
+ mapping
247
+ };
248
+ console.log(mapping);
249
+ let html = "<script>var _import=(s)=>{console.log('importing', s);return import(s)}<\/script>";
221
250
  await renderToStream(jsxElement, {
251
+ manifest: qwikManifest,
222
252
  containerTagName: "div",
223
253
  base: "/",
224
- qwikLoader: { include: "always" },
225
- symbolMapper: globalThis.qwikSymbolMapper,
226
254
  stream: { write(chunk) {
227
- html += chunk;
255
+ html += chunk.replace(/=import\(/g, "=_import(");
228
256
  } }
229
257
  });
258
+ console.log("FINAL HTML", html);
230
259
  return { html };
231
260
  }
232
261
 
233
262
  //#endregion
234
263
  //#region src/ssr-plugin.ts
235
264
  const isJSorTS = createRegExp(exactly(".").and(anyOf("j", "t")).and("s").and(maybe("x")).at.lineEnd());
265
+ function isBrowserOnlySource(source) {
266
+ if (!source) return false;
267
+ return source === "vitest" || source.startsWith("vitest/") || source === "vitest-browser-qwik" || source.startsWith("vitest-browser-qwik/") || source.includes("@vitest/");
268
+ }
269
+ function referencesStrippedId(node, strippedIds) {
270
+ if (!node || typeof node !== "object") return false;
271
+ if (node.type === "Identifier") return strippedIds.has(node.name);
272
+ if (node.type === "MemberExpression") return referencesStrippedId(node.object, strippedIds);
273
+ if (isCallExpression(node)) return referencesStrippedId(node.callee, strippedIds);
274
+ return false;
275
+ }
276
+ function isVariableDeclaration(node) {
277
+ return node.type === "VariableDeclaration";
278
+ }
279
+ let userDefines = {};
236
280
  const renderSSRCommand = async (ctx, componentPath, componentName, props = {}) => {
237
281
  const absoluteComponentPath = resolve(process.cwd(), componentPath);
238
- const viteServer = ctx.project.vite;
239
- if (!viteServer.config.define) return;
240
- for (const [key, value] of Object.entries(viteServer.config.env)) viteServer.config.define[`__vite_ssr_import_meta__.env.${key}`] = JSON.stringify(value);
241
- const Component = (await viteServer.ssrLoadModule(absoluteComponentPath))[componentName];
282
+ const Component = (await ctx.project.vite.ssrLoadModule(absoluteComponentPath))[componentName];
242
283
  if (!Component) throw new Error(`Component "${componentName}" not found in ${absoluteComponentPath}`);
243
284
  return await renderComponentToSSR(ctx, Component, props);
244
285
  };
245
286
  const renderSSRLocalCommand = async (ctx, testFilePath, componentName, allLocalComponents, props = {}) => {
246
287
  const viteServer = ctx.project.vite;
247
- if (!viteServer.config.define) return;
248
- for (const [key, value] of Object.entries(viteServer.config.env)) viteServer.config.define[`__vite_ssr_import_meta__.env.${key}`] = JSON.stringify(value);
249
288
  const { readFileSync, writeFileSync, unlinkSync } = await import("node:fs");
250
289
  const { dirname: dirname$1, join } = await import("node:path");
251
290
  const tempFileName = `ssr-test-${Date.now()}-${Math.random().toString(36).slice(2, 11)}.tsx`;
@@ -254,16 +293,28 @@ const renderSSRLocalCommand = async (ctx, testFilePath, componentName, allLocalC
254
293
  const originalContent = readFileSync(testFilePath, "utf8");
255
294
  const ast = parseSync(testFilePath, originalContent);
256
295
  const s = new MagicString(originalContent);
296
+ const strippedIds = /* @__PURE__ */ new Set();
257
297
  function cleanTestFile(node) {
258
- if (isImportDeclaration(node)) {
259
- const source = node.source?.value;
260
- if (source === "vitest" || source?.includes("@vitest/")) s.remove(node.start, node.end);
298
+ if (isImportDeclaration(node) && isBrowserOnlySource(node.source?.value)) {
299
+ for (const spec of node.specifiers || []) if (spec.local?.name) strippedIds.add(spec.local.name);
300
+ s.remove(node.start, node.end);
301
+ return;
261
302
  }
262
303
  if (isExpressionStatement(node) && node.expression?.type === "CallExpression") {
263
304
  const callExpr = node.expression;
264
305
  if (callExpr.callee.type === "Identifier") {
265
306
  const calleeName = callExpr.callee.name;
266
- if (calleeName === "test" || calleeName === "describe" || calleeName === "it") s.remove(node.start, node.end);
307
+ if (calleeName === "test" || calleeName === "describe" || calleeName === "it") {
308
+ s.remove(node.start, node.end);
309
+ return;
310
+ }
311
+ }
312
+ }
313
+ if (isVariableDeclaration(node)) {
314
+ if (node.declarations.every((d) => referencesStrippedId(d.init, strippedIds))) {
315
+ for (const d of node.declarations) if (d.id.type === "Identifier") strippedIds.add(d.id.name);
316
+ s.remove(node.start, node.end);
317
+ return;
267
318
  }
268
319
  }
269
320
  traverseChildren(node, cleanTestFile);
@@ -291,6 +342,12 @@ function testSSR() {
291
342
  return {
292
343
  name: "vitest:ssr-transform",
293
344
  enforce: "pre",
345
+ config(config) {
346
+ if (config.define) userDefines = {
347
+ ...userDefines,
348
+ ...config.define
349
+ };
350
+ },
294
351
  transform: {
295
352
  filter: {
296
353
  id: isJSorTS,
@@ -377,7 +434,9 @@ function testSSR() {
377
434
  }
378
435
  },
379
436
  configResolved(config) {
380
- globalThis.qwikSymbolMapper = symbolMapper;
437
+ if (!config.define) config.define = {};
438
+ for (const [key, value] of Object.entries(userDefines)) if (config.define) config.define[key] = value;
439
+ for (const [key, value] of Object.entries(config.env)) if (config.define) config.define[`__vite_ssr_import_meta__.env.${key}`] = JSON.stringify(value);
381
440
  if (config.test?.browser?.enabled) config.test.browser.commands = {
382
441
  ...config.test.browser.commands,
383
442
  renderSSR: renderSSRCommand,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vitest-browser-qwik",
3
- "version": "0.2.2",
3
+ "version": "0.3.2",
4
4
  "description": "Render Qwik components using Vitest Browser Mode",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -40,26 +40,26 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@oxc-project/types": "^0.95.0",
43
- "magic-string": "^0.30.21",
43
+ "magic-string": "^0.30.17",
44
44
  "oxc-parser": "^0.95.0",
45
- "oxc-resolver": "^11.16.2"
45
+ "oxc-resolver": "^11.11.1"
46
46
  },
47
47
  "peerDependencies": {
48
- "@builder.io/qwik": ">=1.14.1",
48
+ "@qwik.dev/core": "*",
49
49
  "vite": ">=6.3.5",
50
- "vitest": "^4.0.0"
50
+ "vitest": "^4.0.18"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@biomejs/biome": "2.0.0",
54
- "@builder.io/qwik": "^1.18.0",
55
- "@playwright/test": "1.52.0",
56
- "@types/node": "^22.19.3",
54
+ "@playwright/test": "see flake.nix",
55
+ "@qwik.dev/core": "*",
56
+ "@types/node": "^22.15.17",
57
57
  "@vitest/browser-playwright": "^4.0.18",
58
- "bumpp": "^10.3.2",
59
- "ignore": "^7.0.5",
60
58
  "magic-regexp": "^0.10.0",
61
- "tsdown": "^0.15.12",
62
- "typescript": "^5.9.3",
59
+ "bumpp": "^10.1.0",
60
+ "ignore": "^7.0.5",
61
+ "tsdown": "^0.15.9",
62
+ "typescript": "^5.8.3",
63
63
  "vitest": "^4.0.18"
64
64
  },
65
65
  "scripts": {