@magnit-ce/code-tests 0.0.1

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.
@@ -0,0 +1,966 @@
1
+ // src/code-tests.css?raw
2
+ var code_tests_default = `:host
3
+ {
4
+ /*** gray ***/
5
+ --uchu-light-gray-raw: 95.57% 0.003 286.35;
6
+ --uchu-light-gray: oklch(var(--uchu-light-gray-raw));
7
+
8
+ --uchu-gray-raw: 84.68% 0.002 197.12;
9
+ --uchu-gray: oklch(var(--uchu-gray-raw));
10
+
11
+ --uchu-dark-gray-raw: 63.12% 0.004 219.55;
12
+ --uchu-dark-gray: oklch(var(--uchu-dark-gray-raw));
13
+
14
+ /*** red ***/
15
+ --uchu-light-red-raw: 88.98% 0.052 3.28;
16
+ --uchu-light-red: oklch(var(--uchu-light-red-raw));
17
+
18
+ --uchu-dark-red-raw: 45.8% 0.177 17.7;
19
+ --uchu-dark-red: oklch(var(--uchu-dark-red-raw));
20
+
21
+ /*** purple ***/
22
+ --uchu-light-purple-raw: 89.1% 0.046 305.24;
23
+ --uchu-light-purple: oklch(var(--uchu-light-purple-raw));
24
+
25
+ --uchu-dark-purple-raw: 39.46% 0.164 298.29;
26
+ --uchu-dark-purple: oklch(var(--uchu-dark-purple-raw));
27
+
28
+ /*** blue ***/
29
+ --uchu-light-blue-raw: 89.66% 0.046 260.67;
30
+ --uchu-light-blue: oklch(var(--uchu-light-blue-raw));
31
+
32
+ --uchu-blue-raw: 62.39% 0.181 258.33;
33
+ --uchu-blue: oklch(var(--uchu-blue-raw));
34
+
35
+ --uchu-dark-blue-raw: 43.48% 0.17 260.2;
36
+ --uchu-dark-blue: oklch(var(--uchu-dark-blue-raw));
37
+
38
+ /*** green ***/
39
+ --uchu-light-green-raw: 93.96% 0.05 148.74;
40
+ --uchu-light-green: oklch(var(--uchu-light-green-raw));
41
+
42
+ --uchu-green-raw: 79.33% 0.179 145.62;
43
+ --uchu-green: oklch(var(--uchu-green-raw));
44
+
45
+ --uchu-dark-green-raw: 58.83% 0.158 145.05;
46
+ --uchu-dark-green: oklch(var(--uchu-dark-green-raw));
47
+
48
+ /*** general ***/
49
+ --uchu-yang-raw: 99.4% 0 0;
50
+ --uchu-yang: oklch(var(--uchu-yang-raw));
51
+
52
+ --uchu-yin-raw: 14.38% 0.007 256.88;
53
+ --uchu-yin: oklch(var(--uchu-yin-raw));
54
+
55
+ /*** code-tests vars ***/
56
+
57
+ --spacer: calc(1em - 7px);
58
+ --small-spacer: calc(var(--spacer) / 2);
59
+
60
+ --color-success: var(--uchu-green);
61
+ --color-fail: var(--uchu-red);
62
+ --color-process: var(--uchu-blue);
63
+
64
+ --text-surface: var(--uchu-yin);
65
+ --text-result: var(--uchu-yang); /* --uchu-yang: #fdfdfd; */
66
+ --text-collapse-icon: var(--uchu-dark-gray); /* --uchu-dark-gray: #878a8b; */
67
+ --text-hook-summary: var(--uchu-dark-purple);
68
+ --text-success: var(--uchu-dark-green); /* --uchu-dark-green: #2e943a; */
69
+ --text-fail: var(--uchu-dark-red); /* --uchu-dark-red: #a30d30; */
70
+ --text-process: var(--uchu-dark-blue); /* --uchu-dark-blue: #0949ac; */
71
+ --text-button: var(--uchu-yang); /* --uchu-dark-blue: #0949ac; */
72
+ --text-placeholder: var(--uchu-dark-gray);
73
+
74
+ --surface-0: var(--uchu-light-gray);
75
+ --surface-test: var(--uchu-yang);
76
+ --surface-test-summary: var(--uchu-gray);
77
+ --surface-hook-summary: var(--uchu-light-purple);
78
+ --surface-success: var(--uchu-light-green);
79
+ --surface-fail: var(--uchu-light-red);
80
+ --surface-process: var(--uchu-light-blue);
81
+ --surface-button: var(--uchu-blue); /* --uchu-blue: #3984f2 */
82
+ --surface-button-hover: var(--uchu-light-blue);
83
+ --surface-button-active: var(--uchu-dark-blue);
84
+
85
+ --border-test: solid 1px var(--uchu-dark-gray);
86
+ --border-hook: solid 1px var(--uchu-dark-purple);
87
+ --border-success: solid 1px var(--uchu-dark-green);
88
+ --border-fail: solid 1px var(--uchu-dark-red);
89
+ --border-process: solid 1px var(--uchu-dark-blue);
90
+ --border-button: solid 1px var(--uchu-blue);
91
+
92
+ --info-icon: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2022.812714%2022.814663%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20style%3D%22fill%3Atransparent%3Bstroke%3Atransparent%3Bstroke-width%3A0.999999%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dasharray%3Anone%3Bstroke-dashoffset%3A29.2913%3Bstroke-opacity%3A1%22%20d%3D%22M%2022.295505%2C11.407332%20A%2010.889144%2C10.889144%200%200%201%2011.406424%2C22.296479%2010.889144%2C10.889144%200%200%201%200.51720881%2C11.407332%2010.889144%2C10.889144%200%200%201%2011.406424%2C0.51818382%2010.889144%2C10.889144%200%200%201%2022.295505%2C11.407332%20Z%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22m%2013.945668%2C4.3053761%20c%200.150778%2C-0.96462%20-0.30687%2C-1.43709%20-1.36997%2C-1.43709%20-1.063%2C0%20-1.668452%2C0.47247%20-1.81923%2C1.43709%20-0.150779%2C0.96462%200.306971%2C1.43708%201.369971%2C1.43708%201.004%2C0%201.66845%2C-0.47246%201.819229%2C-1.43708%20z%20M%2011.693889%2C17.829726%2013.373994%2C7.0811161%20h%20-2.9333%20L%208.7605887%2C17.829726%20Z%22%20style%3D%22font-size%3A19.6861px%3Bfont-family%3APassageway%3B-inkscape-font-specification%3APassageway%3Bfill%3A%23a30d30%3Bstroke-width%3A2.5%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dashoffset%3A29.2913%22%20aria-label%3D%22i%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');
93
+
94
+ --font-text: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
95
+
96
+ /*** styles ***/
97
+
98
+ color-scheme: light dark;
99
+ display: grid;
100
+ gap: var(--spacer);
101
+ background-color: var(--surface-0);
102
+ color: var(--text-surface);
103
+ padding: var(--small-spacer);
104
+ font-family: var(--font-text);
105
+ }
106
+ @media (prefers-color-scheme: dark)
107
+ {
108
+ :host
109
+ {
110
+ --text-surface: var(--uchu-yang);
111
+ --text-result: var(--uchu-yang);
112
+
113
+ --surface-0: var(--uchu-yin);
114
+ --surface-test: oklch(25.11% 0.006 258.36);
115
+ --surface-test-summary: oklch(35.02% 0.005 236.66);
116
+ }
117
+ }
118
+
119
+ #header
120
+ {
121
+ display: grid;
122
+ grid-template-columns: 1fr auto;
123
+ align-items: center;
124
+ gap: var(--spacer);
125
+ border-bottom: solid 2px;
126
+ padding: var(--spacer);
127
+ margin-bottom: var(--spacer);
128
+ user-select: none;
129
+ }
130
+
131
+ #title
132
+ {
133
+ font-weight: bold;
134
+ font-size: 16px;
135
+ }
136
+
137
+ .hook
138
+ {
139
+ display: none;
140
+ }
141
+ :host(.has-before-hook) #before-all-details
142
+ ,:host(.has-before-hook) #after-all-details
143
+ {
144
+ display: initial;
145
+ }
146
+
147
+ #tests
148
+ {
149
+ margin: 0;
150
+ padding: 0;
151
+ list-style: none;
152
+ display: grid;
153
+ grid-auto-rows: max-content;
154
+ gap: var(--spacer);
155
+ }
156
+
157
+ summary
158
+ {
159
+ display: grid;
160
+ gap: var(--spacer);
161
+ padding: var(--small-spacer) var(--spacer);
162
+ align-items: center;
163
+ }
164
+ summary::before
165
+ {
166
+ content: '';
167
+ width: 16px;
168
+ height: 16px;
169
+ background: url("data:image/svg+xml,%3Csvg%20viewBox%3D'0%200%2020%2020'%20width%3D'14px'%20height%3D'14px'%20fill%3D'none'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cg%20stroke-width%3D'0'%3E%3C%2Fg%3E%3Cg%20stroke-linecap%3D'round'%20stroke-linejoin%3D'round'%3E%3C%2Fg%3E%3Cg%3E%3Cpath%20d%3D'M8.72798%2015.795L3.72798%207.795C3.10356%206.79593%203.82183%205.5%204.99998%205.5L15%205.5C16.1781%205.5%2016.8964%206.79593%2016.272%207.795L11.272%2015.795C10.6845%2016.735%209.31549%2016.735%208.72798%2015.795Z'%20fill%3D'%23878a8b'%3E%3C%2Fpath%3E%3C%2Fg%3E%3C%2Fsvg%3E");
170
+ transform: rotate(-90deg);
171
+ transition: transform ease-out 200ms;
172
+ }
173
+ [open] > summary::before
174
+ {
175
+ transform: rotate(0);
176
+ /* background: var(--surface-test-summary); */
177
+ }
178
+
179
+ #before-all-summary
180
+ ,#after-all-summary
181
+ {
182
+ background: var(--surface-hook-summary);
183
+ color: var(--text-hook-summary);
184
+ grid-template-columns: auto auto 1fr;
185
+ }
186
+
187
+ .result-icon
188
+ {
189
+ --size: 24px;
190
+ width: var(--size);
191
+ height: var(--size);
192
+
193
+ display: flex;
194
+ align-items: center;
195
+ justify-content: center;
196
+
197
+ border: solid 1px currentColor;
198
+ border-radius: 50%;
199
+ }
200
+ .result-icon::before
201
+ {
202
+ content: '\u22EF';
203
+ }
204
+
205
+ .hook
206
+ {
207
+ border: var(--border-hook);
208
+ }
209
+
210
+ .test
211
+ ,#before-all-details
212
+ ,#after-all-details
213
+ {
214
+ border: var(--border-test);
215
+ border-radius: 2px;
216
+ }
217
+
218
+ .test summary
219
+ {
220
+ background: var(--surface-test-summary);
221
+ grid-template-columns: auto auto 1fr auto;
222
+ }
223
+
224
+ .test.running .result-icon
225
+ ,.hook.running .result-icon
226
+ {
227
+ border: var(--border-process);
228
+ background: var(--surface-process);
229
+ }
230
+ .test.success .result-icon
231
+ ,.hook.success .result-icon
232
+ {
233
+ border: var(--border-success);
234
+ background: var(--surface-success)
235
+ url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24"><path fill="%232e943a" d="M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z"/></svg>');
236
+ background-repeat: no-repeat;
237
+ background-position: center;
238
+ }
239
+ .test.fail .result-icon
240
+ ,.hook.fail .result-icon
241
+ {
242
+ border: var(--border-fail);
243
+ background: var(--surface-fail)
244
+ var(--info-icon);
245
+ background-repeat: no-repeat;
246
+ background-position: center;
247
+ transform: rotate(175deg);
248
+ }
249
+ .test:is(.success,.fail) .result-icon::before
250
+ ,.hook:is(.success,.fail) .result-icon::before
251
+ {
252
+ display: none;
253
+ }
254
+ .test:is(.running) .result-icon::before
255
+ ,.hook:is(.running) .result-icon::before
256
+ {
257
+ content: '';
258
+ --size: 18px;
259
+ --color: var(--text-process);
260
+ --animation-timing-function: linear;
261
+ --animation-duration: 2s;
262
+ width: var(--size);
263
+ height: var(--size);
264
+ mask-image: radial-gradient(circle at 50% 50%, transparent calc(var(--size) / 3), black calc(var(--size) / 3));
265
+ background-image: conic-gradient(transparent, transparent 135deg, var(--color));
266
+ border-radius: 50%;
267
+ animation: var(--animation-timing-function) var(--animation-duration) infinite spin;
268
+ margin: 2px;
269
+ }
270
+
271
+ .description
272
+ {
273
+ user-select: none;
274
+ }
275
+
276
+ .test .result
277
+ ,.hook .result
278
+ {
279
+ background: var(--surface-test);
280
+ border: var(--border-test);
281
+ border-radius: 2px;
282
+ margin: var(--small-spacer);
283
+ }
284
+
285
+ .test .result:empty::before
286
+ ,.results:empty::before
287
+ {
288
+ content: "[Test has not been run]";
289
+ font-style: italic;
290
+ font-size: 11px;
291
+ color: var(--text-placeholder);
292
+ }
293
+ .results:empty::before
294
+ {
295
+ content: "[Tests have not been run]";
296
+ }
297
+ .before-result:empty
298
+ ,.after-result:empty
299
+ {
300
+ display: none;
301
+ }
302
+
303
+ .test .result
304
+ ,.results
305
+ ,.before-result
306
+ ,.after-result
307
+ {
308
+ padding: var(--small-spacer) var(--spacer);
309
+ }
310
+
311
+ pre
312
+ {
313
+ margin: var(--small-spacer);
314
+ }
315
+
316
+ .run
317
+ {
318
+ width: auto;
319
+ min-width: auto;
320
+ max-width: auto;
321
+ appearance: none;
322
+ display: inline-flex;
323
+ justify-content: center;
324
+ align-items: center;
325
+ padding: 3px 10px 3px 7px;
326
+ font-size: 11px;
327
+ gap: var(--small-spacer);
328
+ border: var(--border-button);
329
+ background: var(--surface-button);
330
+ border-radius: 4px;
331
+ text-shadow: 1px 1px rgb(0 0 0 / .2);
332
+ color: var(--text-button);
333
+ }
334
+ .run:hover
335
+ {
336
+ background: oklch(68.39% 0.181 258.33);
337
+ }
338
+ .run:active
339
+ {
340
+ background: oklch(50.39% 0.181 258.33);
341
+ }
342
+ .run::before
343
+ {
344
+ content: '';
345
+ display: block;
346
+ width: 16px;
347
+ height: 16px;
348
+ transform: rotate(-90deg);
349
+ background:
350
+ url("data:image/svg+xml,%3Csvg%20viewBox%3D'0%200%2020%2020'%20width%3D'16px'%20height%3D'16px'%20fill%3D'none'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cg%20stroke-width%3D'0'%3E%3C%2Fg%3E%3Cg%20stroke-linecap%3D'round'%20stroke-linejoin%3D'round'%3E%3C%2Fg%3E%3Cg%3E%3Cpath%20d%3D'M8.72798%2015.795L3.72798%207.795C3.10356%206.79593%203.82183%205.5%204.99998%205.5L15%205.5C16.1781%205.5%2016.8964%206.79593%2016.272%207.795L11.272%2015.795C10.6845%2016.735%209.31549%2016.735%208.72798%2015.795Z'%20fill%3D'%23fdfdfd'%3E%3C%2Fpath%3E%3C%2Fg%3E%3C%2Fsvg%3E");
351
+ }
352
+
353
+
354
+
355
+ @keyframes spin
356
+ {
357
+ from { transform: rotate(0deg); }
358
+ to { transform: rotate(360deg); }
359
+ }`;
360
+
361
+ // src/code-tests.html?raw
362
+ var code_tests_default2 = '<slot name="header">\n <header id="header">\n <span id="title"><slot name="title"><span id="title-text">Tests</span></slot></span>\n <slot name="play-button">\n <button type="button" class="run" data-all>\n <slot name="play-button-label">\n <span id="play-button-label" class="button-label label icon">Run Tests</span>\n </slot>\n </button>\n </slot>\n <slot name="details"></slot>\n </header>\n</slot>\n<details id="before-all-details" class="hook">\n <summary id="before-all-summary">\n <span id="before-all-result-icon" class="result-icon"></span>\n <span id="before-all-description" class="description">Results from Before All Hook</span>\n </summary>\n <div id="before-all-results" class="results"></div>\n</details>\n<ul id="tests"></ul>\n<details id="after-all-details" class="hook">\n <summary id="after-all-summary">\n <span id="after-all-result-icon" class="result-icon"></span>\n <span id="after-all-description" class="description">Results from After All Hook</span>\n </summary>\n <div id="after-all-results" class="results"></div>\n</details>';
363
+
364
+ // src/api.ts
365
+ var TestPromise = class extends Promise {
366
+ async toBeDefined(valueName) {
367
+ const target = await this;
368
+ if (target == void 0) {
369
+ throw new Error(`${valueName != null ? valueName : "Value"} is undefined`);
370
+ }
371
+ }
372
+ async toBe(value, exact = false) {
373
+ const target = await this;
374
+ const result = exact == true ? target === value : target == value;
375
+ if (result == false) {
376
+ throw new Error(` Value is not equal.
377
+ Expected: ${value}
378
+ Result: ${target}`);
379
+ }
380
+ }
381
+ async toContainText(value) {
382
+ const target = await this;
383
+ }
384
+ async toHaveAttribute(value) {
385
+ const target = await this;
386
+ if (!(target instanceof HTMLElement)) {
387
+ throw new Error("Unable to check for attribute on non-HTMLElement target");
388
+ }
389
+ if (target.getAttribute(value)) {
390
+ throw new Error("Taret does not have attribute");
391
+ }
392
+ }
393
+ };
394
+ var BEFOREALL = Symbol("beforeAll");
395
+ var BEFOREEACH = Symbol("beforeEach");
396
+ var AFTERALL = Symbol("afterAll");
397
+ var AFTEREACH = Symbol("afterEach");
398
+ var CodeTests = class {
399
+ static timeoutMS = 500;
400
+ static #expectInterval;
401
+ static #expectPromise;
402
+ static expect(value) {
403
+ const promise = new TestPromise(async (resolve, reject) => {
404
+ if (value instanceof Promise) {
405
+ const result = await value;
406
+ resolve(result);
407
+ return;
408
+ }
409
+ resolve(value);
410
+ });
411
+ return promise;
412
+ }
413
+ static expectSync(value) {
414
+ const promise = new TestPromise(async (resolve, reject) => {
415
+ if (value instanceof Promise) {
416
+ const result = await value;
417
+ resolve(result);
418
+ return;
419
+ }
420
+ resolve(value);
421
+ });
422
+ return promise;
423
+ }
424
+ static expectBefore(value) {
425
+ const promise = new TestPromise(async (resolve, reject) => {
426
+ if (value instanceof Promise) {
427
+ const result = await value;
428
+ resolve(result);
429
+ return;
430
+ }
431
+ resolve(value);
432
+ });
433
+ return promise;
434
+ }
435
+ };
436
+ function expect(value) {
437
+ return CodeTests.expect(value);
438
+ }
439
+
440
+ // src/code-tests.ts
441
+ var NOTESTDEFINED = Symbol("No Test Defined");
442
+ var COMPONENT_STYLESHEET = new CSSStyleSheet();
443
+ COMPONENT_STYLESHEET.replaceSync(code_tests_default);
444
+ var COMPONENT_TAG_NAME = "code-tests";
445
+ var CodeTestsElement = class extends HTMLElement {
446
+ componentParts = /* @__PURE__ */ new Map();
447
+ getElement(id) {
448
+ if (this.componentParts.get(id) == null) {
449
+ const part = this.findElement(id);
450
+ if (part != null) {
451
+ this.componentParts.set(id, part);
452
+ }
453
+ }
454
+ return this.componentParts.get(id);
455
+ }
456
+ findElement(id) {
457
+ return this.shadowRoot.getElementById(id);
458
+ }
459
+ #hooks = /* @__PURE__ */ new Map();
460
+ #hookIds = {
461
+ [BEFOREALL]: generateId(),
462
+ [BEFOREEACH]: generateId(),
463
+ [AFTEREACH]: generateId(),
464
+ [AFTERALL]: generateId()
465
+ };
466
+ #continueRunningTests = true;
467
+ constructor() {
468
+ super();
469
+ this.attachShadow({ mode: "open" });
470
+ this.shadowRoot.innerHTML = code_tests_default2;
471
+ this.shadowRoot.adoptedStyleSheets.push(COMPONENT_STYLESHEET);
472
+ this.#boundClickHandler = this.#onClick.bind(this);
473
+ }
474
+ connectedCallback() {
475
+ this.addEventListener("click", this.#boundClickHandler);
476
+ const testsPath = this.getAttribute("src") ?? this.getAttribute("test") ?? this.getAttribute("tests") ?? this.getAttribute("run") ?? this.getAttribute("path");
477
+ if (testsPath == null) {
478
+ return;
479
+ }
480
+ this.loadTests(testsPath);
481
+ }
482
+ disconnectedCallback() {
483
+ this.removeEventListener("click", this.#boundClickHandler);
484
+ }
485
+ #boundClickHandler;
486
+ #onClick(event) {
487
+ const runButton = event.composedPath().find((item) => item instanceof HTMLButtonElement && item.classList.contains("run"));
488
+ if (runButton == null) {
489
+ return;
490
+ }
491
+ const parentListItem = runButton.closest("li");
492
+ if (parentListItem == null) {
493
+ const isRunAll = runButton.hasAttribute("data-all");
494
+ if (isRunAll == true) {
495
+ this.runTests();
496
+ }
497
+ return;
498
+ }
499
+ const testId = parentListItem.dataset.testId;
500
+ if (testId == null) {
501
+ return;
502
+ }
503
+ const test = this.#tests.get(testId);
504
+ if (test == null) {
505
+ return;
506
+ }
507
+ this.#runTest(testId, test);
508
+ }
509
+ async loadTests(path) {
510
+ this.classList.remove("has-before-hook");
511
+ this.classList.remove("has-after-hook");
512
+ try {
513
+ const lastSlashIndexInCurrentPath = window.location.href.lastIndexOf("/");
514
+ const currentPathHasExtension = window.location.href.substring(lastSlashIndexInCurrentPath).indexOf(".") != -1;
515
+ const currentPath = currentPathHasExtension == true ? window.location.href.substring(0, lastSlashIndexInCurrentPath + 1) : window.location.href;
516
+ const moduleDirectory = currentPath + path.substring(0, path.lastIndexOf("/") + 1);
517
+ const modulePath = currentPath + path;
518
+ let moduleContent = await (await fetch(modulePath)).text();
519
+ moduleContent = moduleContent.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g, `'${moduleDirectory}$1'`);
520
+ const moduleFile = new File([moduleContent], path.substring(path.lastIndexOf("/")), { type: "text/javascript" });
521
+ const moduleURL = URL.createObjectURL(moduleFile);
522
+ const module = await import(moduleURL);
523
+ const tests = module.tests ?? module.default;
524
+ if (tests == void 0) {
525
+ throw new Error(`Unable to find tests definition in file at path: ${path}`);
526
+ }
527
+ const beforeAll = tests[BEFOREALL];
528
+ if (beforeAll != null) {
529
+ const hookMap = this.#hooks.get(BEFOREALL);
530
+ if (hookMap == null) {
531
+ const map = /* @__PURE__ */ new Map();
532
+ map.set(beforeAll, /* @__PURE__ */ new Set());
533
+ this.#hooks.set(BEFOREALL, map);
534
+ }
535
+ this.classList.add("has-before-hook");
536
+ }
537
+ const beforeEach = tests[BEFOREEACH];
538
+ if (beforeEach != null) {
539
+ const hookMap = this.#hooks.get(BEFOREEACH);
540
+ if (hookMap == null) {
541
+ const map = /* @__PURE__ */ new Map();
542
+ map.set(beforeEach, /* @__PURE__ */ new Set());
543
+ this.#hooks.set(BEFOREEACH, map);
544
+ }
545
+ }
546
+ const afterAll = tests[AFTERALL];
547
+ if (afterAll != null) {
548
+ const hookMap = this.#hooks.get(AFTERALL);
549
+ if (hookMap == null) {
550
+ const map = /* @__PURE__ */ new Map();
551
+ map.set(afterAll, /* @__PURE__ */ new Set());
552
+ this.#hooks.set(AFTERALL, map);
553
+ }
554
+ this.classList.add("has-after-hook");
555
+ }
556
+ const afterEach = tests[AFTEREACH];
557
+ if (afterEach != null) {
558
+ const hookMap = this.#hooks.get(AFTEREACH);
559
+ if (hookMap == null) {
560
+ const map = /* @__PURE__ */ new Map();
561
+ map.set(afterEach, /* @__PURE__ */ new Set());
562
+ this.#hooks.set(AFTEREACH, map);
563
+ }
564
+ }
565
+ for (const [description, test] of Object.entries(tests)) {
566
+ const id = this.#addTest(description, test);
567
+ if (beforeAll != null) {
568
+ const hookMap = this.#hooks.get(BEFOREALL);
569
+ if (hookMap != null) {
570
+ const testIds = hookMap.get(beforeAll);
571
+ if (testIds != null) {
572
+ testIds.add(id);
573
+ }
574
+ }
575
+ }
576
+ if (beforeEach != null) {
577
+ const hookMap = this.#hooks.get(BEFOREEACH);
578
+ if (hookMap != null) {
579
+ const testIds = hookMap.get(beforeEach);
580
+ if (testIds != null) {
581
+ testIds.add(id);
582
+ }
583
+ }
584
+ }
585
+ if (afterAll != null) {
586
+ const hookMap = this.#hooks.get(AFTERALL);
587
+ if (hookMap != null) {
588
+ const testIds = hookMap.get(afterAll);
589
+ if (testIds != null) {
590
+ testIds.add(id);
591
+ }
592
+ }
593
+ }
594
+ if (afterEach != null) {
595
+ const hookMap = this.#hooks.get(AFTEREACH);
596
+ if (hookMap != null) {
597
+ const testIds = hookMap.get(afterEach);
598
+ if (testIds != null) {
599
+ testIds.add(id);
600
+ }
601
+ }
602
+ }
603
+ }
604
+ } catch (error) {
605
+ this.#addProcessError("An error occurred while loading the tasks:", error);
606
+ }
607
+ }
608
+ async runTests() {
609
+ this.#continueRunningTests = true;
610
+ this.classList.add("running");
611
+ this.toggleAttribute("success", false);
612
+ this.#clearTestStatuses();
613
+ const inOrder = this.hasAttribute("in-order");
614
+ const beforeHooks = this.#hooks.get(BEFOREALL);
615
+ if (beforeHooks != null) {
616
+ let hookResult;
617
+ try {
618
+ const hookElement = this.getElement(`before-all-details`);
619
+ hookElement.toggleAttribute("success", false);
620
+ hookElement.classList.add("running");
621
+ hookElement.part.add("running");
622
+ hookElement.classList.remove("success", "fail");
623
+ hookElement.part.remove("success", "fail");
624
+ for (const [hook, ids] of beforeHooks) {
625
+ hookResult = await hook();
626
+ this.#handleHookResult(hookResult, true, "before");
627
+ }
628
+ hookElement.part.remove("running");
629
+ } catch (error) {
630
+ this.#handleHookResult(hookResult, false, "before", error);
631
+ console.error(error);
632
+ this.#continueRunningTests = false;
633
+ return;
634
+ }
635
+ }
636
+ if (inOrder == false) {
637
+ const promises = [];
638
+ for (const [id, test] of this.#tests) {
639
+ promises.push(this.#runTest(id, test));
640
+ }
641
+ await Promise.all(promises);
642
+ } else {
643
+ for (const [id, test] of this.#tests) {
644
+ if (this.#continueRunningTests == false) {
645
+ break;
646
+ }
647
+ await this.#runTest(id, test);
648
+ }
649
+ }
650
+ if (this.#continueRunningTests == false) {
651
+ return;
652
+ }
653
+ const afterHooks = this.#hooks.get(AFTERALL);
654
+ if (afterHooks != null) {
655
+ let hookResult;
656
+ try {
657
+ const hookElement = this.getElement(`after-all-details`);
658
+ hookElement.toggleAttribute("success", false);
659
+ hookElement.classList.add("running");
660
+ hookElement.part.add("running");
661
+ hookElement.classList.remove("success", "fail");
662
+ hookElement.part.remove("success", "fail");
663
+ for (const [hook, ids] of afterHooks) {
664
+ hookResult = await hook();
665
+ this.#handleHookResult(hookResult, true, "after");
666
+ }
667
+ hookElement.part.remove("running");
668
+ } catch (error) {
669
+ this.#handleHookResult(hookResult, false, "after", error);
670
+ console.error(error);
671
+ this.#continueRunningTests = false;
672
+ return;
673
+ }
674
+ }
675
+ const failedTests = this.shadowRoot.querySelectorAll('[success="false"]');
676
+ this.setAttribute("success", failedTests.length == 0 ? "true" : "false");
677
+ this.classList.remove("running");
678
+ }
679
+ #clearTestStatuses() {
680
+ for (const [testId, test] of this.#tests) {
681
+ const testElement = this.getElement("tests").querySelector(`[data-test-id="${testId}"]`);
682
+ if (testElement == null) {
683
+ this.#addProcessError(`Unable to find test element for test: ${testId}`);
684
+ return;
685
+ }
686
+ testElement.toggleAttribute("success", false);
687
+ testElement.classList.remove("success", "fail");
688
+ testElement.part.remove("success", "fail");
689
+ }
690
+ }
691
+ async #runTest(testId, test) {
692
+ const testElement = this.getElement("tests").querySelector(`[data-test-id="${testId}"]`);
693
+ if (testElement == null) {
694
+ this.#addProcessError(`Unable to find test element for test: ${testId}`);
695
+ return;
696
+ }
697
+ testElement.toggleAttribute("success", false);
698
+ testElement.classList.add("running");
699
+ testElement.part.add("running");
700
+ testElement.classList.remove("success", "fail");
701
+ testElement.part.remove("success", "fail");
702
+ const errorMessageElement = testElement.querySelector(".error-message");
703
+ if (errorMessageElement != null) {
704
+ errorMessageElement.textContent = "";
705
+ }
706
+ const detailsElement = testElement.querySelector("details");
707
+ if (detailsElement != null) {
708
+ detailsElement.open = false;
709
+ }
710
+ let beforeResult = NOTESTDEFINED;
711
+ let testResult;
712
+ let afterResult = NOTESTDEFINED;
713
+ let testType;
714
+ try {
715
+ const beforeHooks = this.#hooks.get(BEFOREEACH);
716
+ if (beforeHooks != null) {
717
+ for (const [hook, ids] of beforeHooks) {
718
+ if (ids.has(testId)) {
719
+ beforeResult = await hook();
720
+ break;
721
+ }
722
+ }
723
+ }
724
+ testResult = await test();
725
+ const afterHooks = this.#hooks.get(AFTEREACH);
726
+ if (afterHooks != null) {
727
+ for (const [hook, ids] of afterHooks) {
728
+ if (ids.has(testId)) {
729
+ afterResult = await hook();
730
+ break;
731
+ }
732
+ }
733
+ }
734
+ testType = "before";
735
+ if (beforeResult != NOTESTDEFINED) {
736
+ this.#handleTestResult(testElement, beforeResult, true, void 0, testType);
737
+ }
738
+ testType = void 0;
739
+ this.#handleTestResult(testElement, testResult, true, void 0, testType);
740
+ testType = "after";
741
+ if (afterResult != NOTESTDEFINED) {
742
+ this.#handleTestResult(testElement, afterResult, true, void 0, testType);
743
+ }
744
+ } catch (error) {
745
+ this.#handleTestResult(testElement, testResult, false, error, testType);
746
+ console.error(error);
747
+ this.#continueRunningTests = false;
748
+ } finally {
749
+ testElement?.classList.remove("running");
750
+ }
751
+ }
752
+ #handleTestResult(testElement, result, finishedTest, error, beforeOrAfter) {
753
+ if (result instanceof HTMLElement) {
754
+ this.#setTestResult(testElement, result, finishedTest, beforeOrAfter);
755
+ } else if (result == void 0) {
756
+ const trueMessage = beforeOrAfter == void 0 ? "Passed" : "Hook Ran Successfully";
757
+ const defaultResult = this.#createDefaultResult(finishedTest == true ? `${trueMessage}` : `Failed${error != null ? `:
758
+ ${error.message}` : ""}`, finishedTest, beforeOrAfter);
759
+ this.#setTestResult(testElement, defaultResult, finishedTest, beforeOrAfter);
760
+ } else if (typeof result == "string") {
761
+ const defaultResult = this.#createDefaultResult(`${result}${error == null ? "" : `:
762
+ ${error.message}`}`, finishedTest, beforeOrAfter);
763
+ this.#setTestResult(testElement, defaultResult, finishedTest, beforeOrAfter);
764
+ } else if (typeof result == "object") {
765
+ const objectResult = result;
766
+ if (objectResult.success != void 0 && objectResult.expected != void 0 && objectResult.value != void 0) {
767
+ const trueMessage = beforeOrAfter == void 0 ? "Passed" : "Success";
768
+ const falseMessage = beforeOrAfter == void 0 ? "Failed" : "Fail";
769
+ const defaultResult = this.#createDefaultResult(
770
+ `${objectResult.success == true ? `${trueMessage}:` : `${falseMessage}:`}
771
+ Expected:${objectResult.expected}
772
+ Result:${objectResult.value}`,
773
+ objectResult.success,
774
+ beforeOrAfter
775
+ );
776
+ this.#setTestResult(testElement, defaultResult, finishedTest, beforeOrAfter);
777
+ }
778
+ }
779
+ const detailsElement = testElement.querySelector("details");
780
+ if (detailsElement != null) {
781
+ detailsElement.open = true;
782
+ }
783
+ }
784
+ #handleHookResult(result, finishedTest, beforeOrAfter, error) {
785
+ if (result instanceof HTMLElement) {
786
+ this.#setHookResult(result, finishedTest, beforeOrAfter);
787
+ } else {
788
+ let defaultResult;
789
+ if (result == void 0) {
790
+ defaultResult = this.#createDefaultResult(finishedTest == true ? "Hook Ran Successfully" : `Failed${error != null ? `:
791
+ ${error.message}` : ""}`, finishedTest);
792
+ this.#setHookResult(defaultResult, finishedTest, beforeOrAfter);
793
+ } else if (typeof result == "string") {
794
+ defaultResult = this.#createDefaultResult(`${result}${error == null ? "" : `:
795
+ ${error.message}`}`, finishedTest);
796
+ this.#setHookResult(defaultResult, finishedTest, beforeOrAfter);
797
+ } else if (typeof result == "object") {
798
+ const objectResult = result;
799
+ if (objectResult.success != void 0 && objectResult.expected != void 0 && objectResult.value != void 0) {
800
+ defaultResult = this.#createDefaultResult(
801
+ `${objectResult.success == true ? "Success:" : "Fail:"}
802
+ Expected:${objectResult.expected}
803
+ Result:${objectResult.value}`,
804
+ objectResult.success
805
+ );
806
+ this.#setHookResult(defaultResult, finishedTest, beforeOrAfter);
807
+ }
808
+ }
809
+ }
810
+ const detailsElement = this.getElement(`${beforeOrAfter}-all-details`);
811
+ if (detailsElement != null) {
812
+ detailsElement.open = true;
813
+ }
814
+ }
815
+ static create(properties) {
816
+ const element = document.createElement("code-tests");
817
+ console.log(properties);
818
+ return element;
819
+ }
820
+ #tests = /* @__PURE__ */ new Map();
821
+ #addTest(description, test) {
822
+ const testId = generateId();
823
+ this.#tests.set(testId, test);
824
+ const testElement = this.#createTest(testId, description);
825
+ this.getElement("tests").append(testElement);
826
+ return testId;
827
+ }
828
+ #createTest(testId, description) {
829
+ const testElement = document.createElement("li");
830
+ testElement.dataset.testId = testId;
831
+ testElement.classList.add("test");
832
+ const detailsElement = document.createElement("details");
833
+ detailsElement.classList.add("test-details");
834
+ const summaryElement = document.createElement("summary");
835
+ summaryElement.classList.add("test-summary");
836
+ const resultIcon = document.createElement("div");
837
+ resultIcon.classList.add("result-icon");
838
+ summaryElement.append(resultIcon);
839
+ const descriptionElement = document.createElement("span");
840
+ descriptionElement.classList.add("description", "test-description");
841
+ descriptionElement.textContent = description;
842
+ summaryElement.append(descriptionElement);
843
+ const runButton = document.createElement("button");
844
+ runButton.classList.add("run", "test-run");
845
+ runButton.textContent = "Run Test";
846
+ runButton.title = "Run Test";
847
+ summaryElement.append(runButton);
848
+ const beforeResultElement = document.createElement("div");
849
+ beforeResultElement.classList.add("before-result", "test-before-result");
850
+ const resultElement = document.createElement("div");
851
+ resultElement.classList.add("result", "test-result");
852
+ const afterResultElement = document.createElement("div");
853
+ afterResultElement.classList.add("after-result", "test-after-result");
854
+ detailsElement.append(summaryElement);
855
+ detailsElement.append(beforeResultElement);
856
+ detailsElement.append(resultElement);
857
+ detailsElement.append(afterResultElement);
858
+ testElement.append(detailsElement);
859
+ return testElement;
860
+ }
861
+ #setTestResult(testElement, valueElement, success, beforeOrAfter) {
862
+ testElement.setAttribute("success", success == true ? "true" : "false");
863
+ testElement.classList.toggle("success", success);
864
+ testElement.part.toggle("success", success);
865
+ testElement.classList.toggle("fail", !success);
866
+ testElement.part.toggle("fail", !success);
867
+ const resultElement = testElement.querySelector(`.${beforeOrAfter == void 0 ? "result" : beforeOrAfter == "before" ? "before-result" : "after-result"}`);
868
+ if (resultElement == null) {
869
+ this.#addProcessError(`Unable to find result element`);
870
+ return;
871
+ }
872
+ resultElement.innerHTML = "";
873
+ resultElement.appendChild(valueElement);
874
+ }
875
+ #createDefaultResult(message, success, beforeOrAfter) {
876
+ const codeElement = document.createElement("code");
877
+ const preElement = document.createElement("pre");
878
+ preElement.textContent = message;
879
+ preElement.classList.add(success == true ? "success-message" : "error-message");
880
+ codeElement.appendChild(preElement);
881
+ return codeElement;
882
+ }
883
+ #setHookResult(valueElement, success, beforeOrAfter) {
884
+ const detailsElement = this.getElement(`${beforeOrAfter}-all-details`);
885
+ const resultsElement = this.getElement(`${beforeOrAfter}-all-results`);
886
+ detailsElement.setAttribute("success", success == true ? "true" : "false");
887
+ detailsElement.classList.toggle("success", success);
888
+ detailsElement.part.toggle("success", success);
889
+ detailsElement.classList.toggle("fail", !success);
890
+ detailsElement.part.toggle("fail", !success);
891
+ resultsElement.innerHTML = "";
892
+ resultsElement.appendChild(valueElement);
893
+ }
894
+ #addProcessError(message, error) {
895
+ if (error instanceof Error) {
896
+ message += `
897
+ ${error.message}`;
898
+ console.error(error);
899
+ }
900
+ const errorElement = document.createElement("li");
901
+ const codeElement = document.createElement("code");
902
+ const preElement = document.createElement("pre");
903
+ preElement.textContent = message;
904
+ codeElement.append(preElement);
905
+ errorElement.append(codeElement);
906
+ this.getElement("tests").append(errorElement);
907
+ }
908
+ #updateListType(type) {
909
+ if (type == "ordered") {
910
+ const list = this.shadowRoot.querySelector("ul");
911
+ if (list == null) {
912
+ return;
913
+ }
914
+ const items = this.shadowRoot?.querySelectorAll("li");
915
+ const newList = document.createElement("ol");
916
+ if (items != null) {
917
+ newList.append(...items);
918
+ }
919
+ newList.id = "tests";
920
+ list.replaceWith(newList);
921
+ } else {
922
+ const list = this.shadowRoot.querySelector("ol");
923
+ if (list == null) {
924
+ return;
925
+ }
926
+ const items = this.shadowRoot?.querySelectorAll("li");
927
+ const newList = document.createElement("ul");
928
+ newList.id = "tests";
929
+ if (items != null) {
930
+ newList.append(...items);
931
+ }
932
+ list.replaceWith(newList);
933
+ }
934
+ }
935
+ static observedAttributes = ["in-order"];
936
+ attributeChangedCallback(attributeName, oldValue, newValue) {
937
+ if (attributeName == "in-order") {
938
+ if (newValue == void 0) {
939
+ this.#updateListType("unordered");
940
+ } else {
941
+ this.#updateListType("ordered");
942
+ }
943
+ }
944
+ }
945
+ };
946
+ function generateId() {
947
+ const rnd = new Uint8Array(20);
948
+ crypto.getRandomValues(rnd);
949
+ const b64 = [].slice.apply(rnd).map(function(ch) {
950
+ return String.fromCharCode(ch);
951
+ }).join("");
952
+ const secret = btoa(b64).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
953
+ return secret;
954
+ }
955
+ if (customElements.get(COMPONENT_TAG_NAME) == null) {
956
+ customElements.define(COMPONENT_TAG_NAME, CodeTestsElement);
957
+ }
958
+ export {
959
+ AFTERALL,
960
+ AFTEREACH,
961
+ BEFOREALL,
962
+ BEFOREEACH,
963
+ CodeTests,
964
+ CodeTestsElement,
965
+ expect
966
+ };