@noma.to/qwik-testing-library 1.5.2 → 1.6.0
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 +104 -0
- package/lib/_virtual/_rolldown/runtime.qwik.cjs +28 -0
- package/lib/_virtual/_rolldown/runtime.qwik.mjs +27 -0
- package/lib/index.qwik.cjs +14 -10
- package/lib/index.qwik.mjs +4 -5
- package/lib/lib/qwik-testing-library.qwik.cjs +77 -93
- package/lib/lib/qwik-testing-library.qwik.mjs +69 -67
- package/lib/setup.qwik.cjs +3 -2
- package/lib/setup.qwik.mjs +4 -4
- package/lib-types/lib/qwik-testing-library.d.ts +4 -3
- package/lib-types/lib/types.d.ts +7 -2
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -92,6 +92,7 @@ src="https://raw.githubusercontent.com/ianlet/qwik-testing-library/main/high-vol
|
|
|
92
92
|
- [Setup](#setup)
|
|
93
93
|
- [Examples](#examples)
|
|
94
94
|
- [Qwikstart](#qwikstart)
|
|
95
|
+
- [Testing Hooks (experimental)](#testing-hooks-experimental)
|
|
95
96
|
- [Mocking Component Callbacks (experimental)](#mocking-component-callbacks-experimental)
|
|
96
97
|
- [Qwik City - `server$` calls](#qwik-city---server-calls)
|
|
97
98
|
- [Gotchas](#gotchas)
|
|
@@ -264,6 +265,109 @@ describe("<Counter />", () => {
|
|
|
264
265
|
})
|
|
265
266
|
```
|
|
266
267
|
|
|
268
|
+
### Testing Hooks (experimental)
|
|
269
|
+
|
|
270
|
+
> [!WARNING]
|
|
271
|
+
> This feature is under a testing phase and thus experimental.
|
|
272
|
+
> Its API may change in the future, so use it at your own risk.
|
|
273
|
+
|
|
274
|
+
`renderHook` lets you test custom hooks in isolation, without building a wrapper component by hand.
|
|
275
|
+
This is especially useful for library authors who need to battle-test the hooks they provide to their users.
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
// use-counter.tsx
|
|
279
|
+
|
|
280
|
+
import { $, useSignal } from "@builder.io/qwik";
|
|
281
|
+
|
|
282
|
+
export function useCounter(initial = 0) {
|
|
283
|
+
const count = useSignal(initial);
|
|
284
|
+
const increment$ = $(() => count.value++);
|
|
285
|
+
|
|
286
|
+
return { count, increment$ };
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
```tsx
|
|
291
|
+
// use-counter.spec.tsx
|
|
292
|
+
|
|
293
|
+
import { renderHook } from "@noma.to/qwik-testing-library";
|
|
294
|
+
import { useCounter } from "./use-counter";
|
|
295
|
+
|
|
296
|
+
describe("useCounter", () => {
|
|
297
|
+
it("should start at 0", async () => {
|
|
298
|
+
const { result } = await renderHook(useCounter);
|
|
299
|
+
|
|
300
|
+
expect(result.count.value).toBe(0);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it("should increment", async () => {
|
|
304
|
+
const { result } = await renderHook(useCounter);
|
|
305
|
+
|
|
306
|
+
await result.increment$();
|
|
307
|
+
|
|
308
|
+
expect(result.count.value).toBe(1);
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
The `result` is the direct return value of your hook callback. Because Qwik signals are stable reactive
|
|
314
|
+
references, you can read and mutate them directly — no `.current` wrapper needed.
|
|
315
|
+
|
|
316
|
+
#### ESLint `qwik/use-method-usage`
|
|
317
|
+
|
|
318
|
+
The Qwik ESLint plugin only allows `use*` calls inside `component$` or `use*`-named functions.
|
|
319
|
+
This is a known limitation — a discussion is in progress with the Qwik team to relax their ESLint rule.
|
|
320
|
+
In the meantime, when you need to pass arguments to your hook, wrap it in a `use*`-named function to stay lint-clean:
|
|
321
|
+
|
|
322
|
+
```tsx
|
|
323
|
+
// passing the hook by reference — lint-clean
|
|
324
|
+
const { result } = await renderHook(useCounter);
|
|
325
|
+
|
|
326
|
+
// passing arguments — extract a use*-named function
|
|
327
|
+
function useCounterFrom10() {
|
|
328
|
+
return useCounter(10);
|
|
329
|
+
}
|
|
330
|
+
const { result } = await renderHook(useCounterFrom10);
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
#### Providing Context
|
|
334
|
+
|
|
335
|
+
If your hook depends on context, use the `wrapper` option to provide it:
|
|
336
|
+
|
|
337
|
+
```tsx
|
|
338
|
+
import { renderHook } from "@noma.to/qwik-testing-library";
|
|
339
|
+
import { component$, createContextId, useContextProvider, useStore, Slot } from "@builder.io/qwik";
|
|
340
|
+
import { useTheme } from "./use-theme";
|
|
341
|
+
|
|
342
|
+
const ThemeContext = createContextId<{ mode: string }>("theme");
|
|
343
|
+
|
|
344
|
+
const ThemeProvider = component$(() => {
|
|
345
|
+
useContextProvider(ThemeContext, useStore({ mode: "dark" }));
|
|
346
|
+
return <Slot />;
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("should read theme from context", async () => {
|
|
350
|
+
const { result } = await renderHook(useTheme, {
|
|
351
|
+
wrapper: ThemeProvider,
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
expect(result.mode).toBe("dark");
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
#### Cleanup
|
|
359
|
+
|
|
360
|
+
`renderHook` integrates with automatic cleanup, just like `render`.
|
|
361
|
+
You can also call `unmount()` manually if needed:
|
|
362
|
+
|
|
363
|
+
```tsx
|
|
364
|
+
const { result, unmount } = await renderHook(useCounter);
|
|
365
|
+
|
|
366
|
+
// ... assertions ...
|
|
367
|
+
|
|
368
|
+
unmount();
|
|
369
|
+
```
|
|
370
|
+
|
|
267
371
|
### Mocking Component Callbacks (experimental)
|
|
268
372
|
|
|
269
373
|
> [!WARNING]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __exportAll = (all, no_symbols) => {
|
|
7
|
+
let target = {};
|
|
8
|
+
for (var name in all) __defProp(target, name, {
|
|
9
|
+
get: all[name],
|
|
10
|
+
enumerable: true
|
|
11
|
+
});
|
|
12
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
+
return target;
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
17
|
+
key = keys[i];
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
19
|
+
get: ((k) => from[k]).bind(null, key),
|
|
20
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
26
|
+
//#endregion
|
|
27
|
+
exports.__exportAll = __exportAll;
|
|
28
|
+
exports.__reExport = __reExport;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __exportAll = (all, no_symbols) => {
|
|
7
|
+
let target = {};
|
|
8
|
+
for (var name in all) __defProp(target, name, {
|
|
9
|
+
get: all[name],
|
|
10
|
+
enumerable: true
|
|
11
|
+
});
|
|
12
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
+
return target;
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
17
|
+
key = keys[i];
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
19
|
+
get: ((k) => from[k]).bind(null, key),
|
|
20
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
26
|
+
//#endregion
|
|
27
|
+
export { __exportAll, __reExport };
|
package/lib/index.qwik.cjs
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
exports.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
require("./_virtual/_rolldown/runtime.qwik.cjs");
|
|
3
|
+
const require_qwik_testing_library = require("./lib/qwik-testing-library.qwik.cjs");
|
|
4
|
+
//#endregion
|
|
5
|
+
exports.cleanup = require_qwik_testing_library.cleanup;
|
|
6
|
+
exports.render = require_qwik_testing_library.render;
|
|
7
|
+
exports.renderHook = require_qwik_testing_library.renderHook;
|
|
8
|
+
var _testing_library_dom = require("@testing-library/dom");
|
|
9
|
+
Object.keys(_testing_library_dom).forEach(function(k) {
|
|
10
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function() {
|
|
13
|
+
return _testing_library_dom[k];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
12
16
|
});
|
package/lib/index.qwik.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "./_virtual/_rolldown/runtime.qwik.mjs";
|
|
2
|
+
import { cleanup, render, renderHook } from "./lib/qwik-testing-library.qwik.mjs";
|
|
2
3
|
export * from "@testing-library/dom";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
render
|
|
6
|
-
};
|
|
4
|
+
//#endregion
|
|
5
|
+
export { cleanup, render, renderHook };
|
|
@@ -1,106 +1,90 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
-
for (let key of __getOwnPropNames(from))
|
|
11
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
-
}
|
|
14
|
-
return to;
|
|
15
|
-
};
|
|
16
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
-
mod
|
|
23
|
-
));
|
|
24
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
25
|
-
const jsxRuntime = require("@builder.io/qwik/jsx-runtime");
|
|
26
|
-
const dom = require("@testing-library/dom");
|
|
27
|
-
const server = require("@builder.io/qwik/server");
|
|
1
|
+
require("../_virtual/_rolldown/runtime.qwik.cjs");
|
|
2
|
+
let _testing_library_dom = require("@testing-library/dom");
|
|
3
|
+
let _builder_io_qwik_server = require("@builder.io/qwik/server");
|
|
4
|
+
let _builder_io_qwik_jsx_runtime = require("@builder.io/qwik/jsx-runtime");
|
|
5
|
+
//#region src/lib/qwik-testing-library.tsx
|
|
28
6
|
if (typeof HTMLTemplateElement !== "undefined") {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return this.content.childNodes;
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
}
|
|
7
|
+
const testTemplate = document.createElement("template");
|
|
8
|
+
const testNode = document.createComment("test");
|
|
9
|
+
testTemplate.insertBefore(testNode, null);
|
|
10
|
+
const needsPatch = testTemplate.childNodes.length === 0;
|
|
11
|
+
testNode.remove();
|
|
12
|
+
if (needsPatch) Object.defineProperty(HTMLTemplateElement.prototype, "childNodes", { get() {
|
|
13
|
+
return this.content.childNodes;
|
|
14
|
+
} });
|
|
41
15
|
}
|
|
42
16
|
if (typeof process === "undefined" || !process.env?.QTL_SKIP_AUTO_CLEANUP) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
});
|
|
47
|
-
}
|
|
17
|
+
if (typeof afterEach === "function") afterEach(() => {
|
|
18
|
+
cleanup();
|
|
19
|
+
});
|
|
48
20
|
}
|
|
49
|
-
|
|
21
|
+
var mountedContainers = /* @__PURE__ */ new Set();
|
|
50
22
|
async function render(ui, options = {}) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
unmount: cleanup2,
|
|
85
|
-
...dom.getQueriesForElement(container, queries)
|
|
86
|
-
};
|
|
23
|
+
const qwik = await import("@builder.io/qwik");
|
|
24
|
+
let { container, baseElement = container } = options;
|
|
25
|
+
const { wrapper: Wrapper } = options;
|
|
26
|
+
const { queries, serverData } = options;
|
|
27
|
+
if (!baseElement) baseElement = document.body;
|
|
28
|
+
if (!container) container = baseElement.insertBefore(document.createElement("host"), baseElement.firstChild);
|
|
29
|
+
const wrappedUi = !Wrapper ? ui : /* @__PURE__ */ (0, _builder_io_qwik_jsx_runtime.jsx)(Wrapper, { children: ui });
|
|
30
|
+
const doc = baseElement.ownerDocument;
|
|
31
|
+
const win = doc.defaultView;
|
|
32
|
+
new Function("document", "window", (0, _builder_io_qwik_server.getQwikLoaderScript)())(doc, win);
|
|
33
|
+
const { cleanup } = await qwik.render(container, wrappedUi, { serverData });
|
|
34
|
+
mountedContainers.add({
|
|
35
|
+
container,
|
|
36
|
+
componentCleanup: cleanup
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
container,
|
|
40
|
+
baseElement,
|
|
41
|
+
asFragment: () => {
|
|
42
|
+
if (typeof document.createRange === "function") return document.createRange().createContextualFragment(container.innerHTML);
|
|
43
|
+
else {
|
|
44
|
+
const template = document.createElement("template");
|
|
45
|
+
template.innerHTML = container.innerHTML;
|
|
46
|
+
return template.content;
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
debug: (el = baseElement, maxLength, options) => Array.isArray(el) ? el.forEach((e) => console.log((0, _testing_library_dom.prettyDOM)(e, maxLength, options))) : console.log((0, _testing_library_dom.prettyDOM)(el, maxLength, {
|
|
50
|
+
...options,
|
|
51
|
+
filterNode: () => true
|
|
52
|
+
})),
|
|
53
|
+
unmount: cleanup,
|
|
54
|
+
...(0, _testing_library_dom.getQueriesForElement)(container, queries)
|
|
55
|
+
};
|
|
87
56
|
}
|
|
88
57
|
function cleanupAtContainer(ref) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
mountedContainers.delete(ref);
|
|
58
|
+
const { container, componentCleanup } = ref;
|
|
59
|
+
componentCleanup();
|
|
60
|
+
if (container?.parentNode === document.body) document.body.removeChild(container);
|
|
61
|
+
mountedContainers.delete(ref);
|
|
95
62
|
}
|
|
96
63
|
function cleanup() {
|
|
97
|
-
|
|
64
|
+
mountedContainers.forEach(cleanupAtContainer);
|
|
98
65
|
}
|
|
66
|
+
async function renderHook(callback, options = {}) {
|
|
67
|
+
const { component$, noSerialize } = await import("@builder.io/qwik");
|
|
68
|
+
const callbackRef = noSerialize(callback);
|
|
69
|
+
const resultRef = noSerialize({ current: void 0 });
|
|
70
|
+
const { unmount } = await render(/* @__PURE__ */ (0, _builder_io_qwik_jsx_runtime.jsx)(component$(() => {
|
|
71
|
+
resultRef.current = callbackRef();
|
|
72
|
+
return /* @__PURE__ */ (0, _builder_io_qwik_jsx_runtime.jsx)(_builder_io_qwik_jsx_runtime.Fragment, {});
|
|
73
|
+
}), {}), { wrapper: options.wrapper });
|
|
74
|
+
return {
|
|
75
|
+
result: resultRef.current,
|
|
76
|
+
unmount
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
99
80
|
exports.cleanup = cleanup;
|
|
100
81
|
exports.render = render;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
82
|
+
exports.renderHook = renderHook;
|
|
83
|
+
Object.keys(_testing_library_dom).forEach(function(k) {
|
|
84
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
85
|
+
enumerable: true,
|
|
86
|
+
get: function() {
|
|
87
|
+
return _testing_library_dom[k];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
106
90
|
});
|
|
@@ -1,79 +1,81 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "../_virtual/_rolldown/runtime.qwik.mjs";
|
|
2
2
|
import { getQueriesForElement, prettyDOM } from "@testing-library/dom";
|
|
3
|
-
export * from "@testing-library/dom";
|
|
4
3
|
import { getQwikLoaderScript } from "@builder.io/qwik/server";
|
|
4
|
+
import { Fragment, jsx } from "@builder.io/qwik/jsx-runtime";
|
|
5
|
+
export * from "@testing-library/dom";
|
|
6
|
+
//#region src/lib/qwik-testing-library.tsx
|
|
5
7
|
if (typeof HTMLTemplateElement !== "undefined") {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return this.content.childNodes;
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
}
|
|
8
|
+
const testTemplate = document.createElement("template");
|
|
9
|
+
const testNode = document.createComment("test");
|
|
10
|
+
testTemplate.insertBefore(testNode, null);
|
|
11
|
+
const needsPatch = testTemplate.childNodes.length === 0;
|
|
12
|
+
testNode.remove();
|
|
13
|
+
if (needsPatch) Object.defineProperty(HTMLTemplateElement.prototype, "childNodes", { get() {
|
|
14
|
+
return this.content.childNodes;
|
|
15
|
+
} });
|
|
18
16
|
}
|
|
19
17
|
if (typeof process === "undefined" || !process.env?.QTL_SKIP_AUTO_CLEANUP) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
});
|
|
24
|
-
}
|
|
18
|
+
if (typeof afterEach === "function") afterEach(() => {
|
|
19
|
+
cleanup();
|
|
20
|
+
});
|
|
25
21
|
}
|
|
26
|
-
|
|
22
|
+
var mountedContainers = /* @__PURE__ */ new Set();
|
|
27
23
|
async function render(ui, options = {}) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
unmount: cleanup2,
|
|
62
|
-
...getQueriesForElement(container, queries)
|
|
63
|
-
};
|
|
24
|
+
const qwik = await import("@builder.io/qwik");
|
|
25
|
+
let { container, baseElement = container } = options;
|
|
26
|
+
const { wrapper: Wrapper } = options;
|
|
27
|
+
const { queries, serverData } = options;
|
|
28
|
+
if (!baseElement) baseElement = document.body;
|
|
29
|
+
if (!container) container = baseElement.insertBefore(document.createElement("host"), baseElement.firstChild);
|
|
30
|
+
const wrappedUi = !Wrapper ? ui : /* @__PURE__ */ jsx(Wrapper, { children: ui });
|
|
31
|
+
const doc = baseElement.ownerDocument;
|
|
32
|
+
const win = doc.defaultView;
|
|
33
|
+
new Function("document", "window", getQwikLoaderScript())(doc, win);
|
|
34
|
+
const { cleanup } = await qwik.render(container, wrappedUi, { serverData });
|
|
35
|
+
mountedContainers.add({
|
|
36
|
+
container,
|
|
37
|
+
componentCleanup: cleanup
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
container,
|
|
41
|
+
baseElement,
|
|
42
|
+
asFragment: () => {
|
|
43
|
+
if (typeof document.createRange === "function") return document.createRange().createContextualFragment(container.innerHTML);
|
|
44
|
+
else {
|
|
45
|
+
const template = document.createElement("template");
|
|
46
|
+
template.innerHTML = container.innerHTML;
|
|
47
|
+
return template.content;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
debug: (el = baseElement, maxLength, options) => Array.isArray(el) ? el.forEach((e) => console.log(prettyDOM(e, maxLength, options))) : console.log(prettyDOM(el, maxLength, {
|
|
51
|
+
...options,
|
|
52
|
+
filterNode: () => true
|
|
53
|
+
})),
|
|
54
|
+
unmount: cleanup,
|
|
55
|
+
...getQueriesForElement(container, queries)
|
|
56
|
+
};
|
|
64
57
|
}
|
|
65
58
|
function cleanupAtContainer(ref) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
mountedContainers.delete(ref);
|
|
59
|
+
const { container, componentCleanup } = ref;
|
|
60
|
+
componentCleanup();
|
|
61
|
+
if (container?.parentNode === document.body) document.body.removeChild(container);
|
|
62
|
+
mountedContainers.delete(ref);
|
|
72
63
|
}
|
|
73
64
|
function cleanup() {
|
|
74
|
-
|
|
65
|
+
mountedContainers.forEach(cleanupAtContainer);
|
|
66
|
+
}
|
|
67
|
+
async function renderHook(callback, options = {}) {
|
|
68
|
+
const { component$, noSerialize } = await import("@builder.io/qwik");
|
|
69
|
+
const callbackRef = noSerialize(callback);
|
|
70
|
+
const resultRef = noSerialize({ current: void 0 });
|
|
71
|
+
const { unmount } = await render(/* @__PURE__ */ jsx(component$(() => {
|
|
72
|
+
resultRef.current = callbackRef();
|
|
73
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
74
|
+
}), {}), { wrapper: options.wrapper });
|
|
75
|
+
return {
|
|
76
|
+
result: resultRef.current,
|
|
77
|
+
unmount
|
|
78
|
+
};
|
|
75
79
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
render
|
|
79
|
-
};
|
|
80
|
+
//#endregion
|
|
81
|
+
export { cleanup, render, renderHook };
|
package/lib/setup.qwik.cjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/setup.ts
|
|
3
3
|
globalThis.qTest = false;
|
|
4
4
|
globalThis.qRuntimeQrl = true;
|
|
5
5
|
globalThis.qDev = true;
|
|
6
6
|
globalThis.qInspector = false;
|
|
7
|
-
|
|
7
|
+
var __qwikSetupComplete = true;
|
|
8
|
+
//#endregion
|
|
8
9
|
exports.__qwikSetupComplete = __qwikSetupComplete;
|
package/lib/setup.qwik.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
//#region src/setup.ts
|
|
1
2
|
globalThis.qTest = false;
|
|
2
3
|
globalThis.qRuntimeQrl = true;
|
|
3
4
|
globalThis.qDev = true;
|
|
4
5
|
globalThis.qInspector = false;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
6
|
+
var __qwikSetupComplete = true;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { __qwikSetupComplete };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { JSXOutput } from "@builder.io/qwik";
|
|
2
|
-
import type {
|
|
3
|
-
declare function render(ui: JSXOutput, options?:
|
|
2
|
+
import type { RenderOptions, RenderHookOptions, RenderHookResult, Result } from "./types";
|
|
3
|
+
declare function render(ui: JSXOutput, options?: RenderOptions): Promise<Result>;
|
|
4
4
|
declare function cleanup(): void;
|
|
5
|
+
declare function renderHook<Result>(callback: () => Result, options?: RenderHookOptions): Promise<RenderHookResult<Result>>;
|
|
5
6
|
export * from "@testing-library/dom";
|
|
6
|
-
export { cleanup, render };
|
|
7
|
+
export { cleanup, render, renderHook };
|
package/lib-types/lib/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { BoundFunctions, prettyFormat, Queries } from "@testing-library/dom";
|
|
2
2
|
import { queries } from "@testing-library/dom";
|
|
3
|
-
import type { Component, RenderOptions } from "@builder.io/qwik";
|
|
4
|
-
export interface
|
|
3
|
+
import type { Component, RenderOptions as QwikRenderOptions } from "@builder.io/qwik";
|
|
4
|
+
export interface RenderOptions extends QwikRenderOptions {
|
|
5
5
|
container?: HTMLElement;
|
|
6
6
|
baseElement?: HTMLElement;
|
|
7
7
|
queries?: Queries & typeof queries;
|
|
@@ -19,3 +19,8 @@ export type ComponentRef = {
|
|
|
19
19
|
container: HTMLElement;
|
|
20
20
|
componentCleanup: () => void;
|
|
21
21
|
};
|
|
22
|
+
export type RenderHookOptions = Pick<RenderOptions, 'wrapper'>;
|
|
23
|
+
export interface RenderHookResult<Result> {
|
|
24
|
+
result: Result;
|
|
25
|
+
unmount: () => void;
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noma.to/qwik-testing-library",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Simple and complete Qwik testing utilities that encourage good testing practices.",
|
|
5
5
|
"repository": "https://github.com/ianlet/qwik-testing-library",
|
|
6
6
|
"homepage": "https://github.com/ianlet/qwik-testing-library",
|
|
@@ -39,18 +39,18 @@
|
|
|
39
39
|
"validate": "pnpm build"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@
|
|
43
|
-
"@types/node": "25.
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"typescript": "
|
|
42
|
+
"@eslint/js": "10",
|
|
43
|
+
"@types/node": "25.6.0",
|
|
44
|
+
"eslint": "10",
|
|
45
|
+
"eslint-plugin-qwik": "1.19.2",
|
|
46
|
+
"globals": "^17.4.0",
|
|
47
|
+
"prettier": "3.8.2",
|
|
48
|
+
"typescript": "6.0.2",
|
|
49
|
+
"typescript-eslint": "^8.58.1",
|
|
50
50
|
"undici": "*",
|
|
51
|
-
"vite": "
|
|
51
|
+
"vite": "8.0.8",
|
|
52
52
|
"vite-tsconfig-paths": "^6.1.1",
|
|
53
|
-
"vitest": "^4.
|
|
53
|
+
"vitest": "^4.1.4"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"@builder.io/qwik": ">= 1.12.0 < 2",
|