@magnit-ce/code-tests 0.0.5 → 0.0.7

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.
@@ -27,7 +27,8 @@ __export(code_tests_exports, {
27
27
  CodeTestEventType: () => CodeTestEventType,
28
28
  CodeTests: () => CodeTests,
29
29
  CodeTestsElement: () => CodeTestsElement,
30
- expect: () => expect
30
+ expect: () => expect,
31
+ prompt: () => prompt
31
32
  });
32
33
  module.exports = __toCommonJS(code_tests_exports);
33
34
 
@@ -114,6 +115,7 @@ var code_tests_default = `:host
114
115
  --surface-button: var(--uchu-blue); /* --uchu-blue: #3984f2 */
115
116
  --surface-button-hover: var(--uchu-light-blue);
116
117
  --surface-button-active: var(--uchu-dark-blue);
118
+ --surface-button-cancel: var(--uchu-dark-blue);
117
119
 
118
120
  --border-test: solid 1px var(--uchu-dark-gray);
119
121
  --border-hook: solid 1px var(--uchu-dark-purple);
@@ -209,6 +211,26 @@ summary::before
209
211
  /* background: var(--surface-test-summary); */
210
212
  }
211
213
 
214
+ :host(.running) .run[data-all]
215
+ {
216
+ background-color: var(--surface-test-summary);
217
+ border-color: var(--surface-test-summary);
218
+ }
219
+ :host(.running) .run[data-all]:hover
220
+ {
221
+ background-color: var(--uchu-dark-gray);
222
+ border-color: var(--uchu-dark-gray);
223
+ }
224
+ :host(.running) .run[data-all]:active
225
+ {
226
+ background-color: var(--surface-test);
227
+ border-color: var(--surface-test);
228
+ }
229
+ :host(.running) .run[data-all]::before
230
+ {
231
+ display: none;
232
+ }
233
+
212
234
  #before-all-summary
213
235
  ,#after-all-summary
214
236
  {
@@ -393,7 +415,7 @@ pre
393
415
  }`;
394
416
 
395
417
  // src/code-tests.html?raw
396
- 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>';
418
+ 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>\n\n<template id="prompt-template">\n <div class="prompt" part="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>';
397
419
 
398
420
  // src/api.ts
399
421
  var TestPromise = class extends Promise {
@@ -429,7 +451,7 @@ var BEFOREALL = Symbol("beforeAll");
429
451
  var BEFOREEACH = Symbol("beforeEach");
430
452
  var AFTERALL = Symbol("afterAll");
431
453
  var AFTEREACH = Symbol("afterEach");
432
- var CodeTests = class {
454
+ var CodeTests = class _CodeTests {
433
455
  static timeoutMS = 500;
434
456
  static #expectInterval;
435
457
  static #expectPromise;
@@ -466,10 +488,61 @@ var CodeTests = class {
466
488
  });
467
489
  return promise;
468
490
  }
491
+ static async prompt(host, parent, message, options) {
492
+ return new Promise((resolve, reject) => {
493
+ const template = host.findElement("prompt-template");
494
+ const promptElement = _CodeTests.createElementFromTemplate(template);
495
+ promptElement.querySelector(".label").textContent = message;
496
+ const clickHandler = (event) => {
497
+ const composedPath = event.composedPath();
498
+ const acceptButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("accept"));
499
+ if (acceptButton != null) {
500
+ const result = options?.onAccept?.() ?? true;
501
+ promptElement.removeEventListener("click", clickHandler);
502
+ resolve(result);
503
+ return;
504
+ }
505
+ const rejectButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("reject"));
506
+ if (rejectButton != null) {
507
+ const result = options?.onReject?.() ?? false;
508
+ promptElement.removeEventListener("click", clickHandler);
509
+ resolve(result);
510
+ return;
511
+ }
512
+ };
513
+ promptElement.addEventListener("click", clickHandler);
514
+ if (options?.acceptLabel != null) {
515
+ promptElement.querySelector(".accept").textContent = options.acceptLabel;
516
+ }
517
+ if (options?.rejectLabel != null) {
518
+ promptElement.querySelector(".reject").textContent = options.rejectLabel;
519
+ }
520
+ const details = parent instanceof HTMLDetailsElement ? parent : parent.querySelector(".test-details");
521
+ if (details != null) {
522
+ details.open = true;
523
+ }
524
+ parent.querySelector(".result")?.append(promptElement);
525
+ });
526
+ }
527
+ static createElementFromTemplate(target, parent) {
528
+ const templateNode = target instanceof HTMLTemplateElement ? target : document.querySelector(target);
529
+ if (templateNode == null) {
530
+ throw new Error(`Unable to find template element from selector: ${target}`);
531
+ }
532
+ const firstChild = templateNode.content.cloneNode(true).querySelector("*");
533
+ if (firstChild == null) {
534
+ throw new Error(`Unable to find first child of template element`);
535
+ }
536
+ parent?.append(firstChild);
537
+ return firstChild;
538
+ }
469
539
  };
470
540
  function expect(value) {
471
541
  return CodeTests.expect(value);
472
542
  }
543
+ function prompt(host, parent, message, options) {
544
+ return CodeTests.prompt(host, parent, message, options);
545
+ }
473
546
 
474
547
  // node_modules/.pnpm/ce-part-utils@0.0.0/node_modules/ce-part-utils/dist/ce-part-utils.js
475
548
  var DEFAULT_ELEMENT_SELECTOR = ":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";
@@ -550,7 +623,14 @@ var CodeTestsElement = class extends HTMLElement {
550
623
  if (parentListItem == null) {
551
624
  const isRunAll = runButton.hasAttribute("data-all");
552
625
  if (isRunAll == true) {
553
- this.runTests();
626
+ if (this.classList.contains("running")) {
627
+ if (this.classList.contains("canceled")) {
628
+ return;
629
+ }
630
+ this.cancel();
631
+ } else {
632
+ this.runTests();
633
+ }
554
634
  }
555
635
  return;
556
636
  }
@@ -562,6 +642,9 @@ var CodeTestsElement = class extends HTMLElement {
562
642
  if (test == null) {
563
643
  return;
564
644
  }
645
+ this.#isCanceled = false;
646
+ this.classList.remove("canceled");
647
+ this.part.remove("canceled");
565
648
  this.#runTest(testId, test);
566
649
  }
567
650
  #getCurrentTestsPath() {
@@ -672,11 +755,21 @@ var CodeTestsElement = class extends HTMLElement {
672
755
  this.#addProcessError("An error occurred while loading the tasks:", error);
673
756
  }
674
757
  }
758
+ #isCanceled = false;
759
+ cancel() {
760
+ this.#isCanceled = true;
761
+ this.classList.add("canceled");
762
+ this.part.add("canceled");
763
+ }
675
764
  async runTests() {
676
765
  this.dispatchEvent(new CustomEvent("beforeall" /* BeforeAll */, { bubbles: true, composed: true }));
677
766
  this.#continueRunningTests = true;
678
767
  this.classList.add("running");
768
+ this.#isCanceled = false;
769
+ this.classList.remove("canceled");
770
+ this.part.remove("canceled");
679
771
  this.toggleAttribute("success", false);
772
+ this.findElement("play-button-label").textContent = "Cancel";
680
773
  this.#clearTestStatuses();
681
774
  const inOrder = this.hasAttribute("in-order");
682
775
  const beforeHooks = this.#hooks.get(BEFOREALL);
@@ -687,7 +780,10 @@ var CodeTestsElement = class extends HTMLElement {
687
780
  beforeAllHookElement.classList.add("running");
688
781
  beforeAllHookElement.part.add("running");
689
782
  for (const [hook, ids] of beforeHooks) {
690
- hookResult = await hook();
783
+ if (this.#isCanceled == true) {
784
+ throw new Error("Test has been cancelled");
785
+ }
786
+ hookResult = await hook(this, beforeAllHookElement);
691
787
  this.#handleHookResult(hookResult, true, "before");
692
788
  }
693
789
  beforeAllHookElement.part.remove("running");
@@ -698,6 +794,7 @@ var CodeTestsElement = class extends HTMLElement {
698
794
  this.#continueRunningTests = false;
699
795
  this.classList.remove("running");
700
796
  this.part.remove("running");
797
+ this.findElement("play-button-label").textContent = "Run Tests";
701
798
  this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
702
799
  return;
703
800
  }
@@ -719,6 +816,7 @@ var CodeTestsElement = class extends HTMLElement {
719
816
  if (this.#continueRunningTests == false) {
720
817
  this.classList.remove("running");
721
818
  this.part.remove("running");
819
+ this.findElement("play-button-label").textContent = "Run Tests";
722
820
  this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
723
821
  return;
724
822
  }
@@ -730,7 +828,10 @@ var CodeTestsElement = class extends HTMLElement {
730
828
  afterAllHookElement.classList.add("running");
731
829
  afterAllHookElement.part.add("running");
732
830
  for (const [hook, ids] of afterHooks) {
733
- hookResult = await hook();
831
+ if (this.#isCanceled == true) {
832
+ throw new Error("Test has been cancelled");
833
+ }
834
+ hookResult = await hook(this, afterAllHookElement);
734
835
  this.#handleHookResult(hookResult, true, "after");
735
836
  }
736
837
  afterAllHookElement.part.remove("running");
@@ -741,6 +842,7 @@ var CodeTestsElement = class extends HTMLElement {
741
842
  this.#continueRunningTests = false;
742
843
  this.classList.remove("running");
743
844
  this.part.remove("running");
845
+ this.findElement("play-button-label").textContent = "Run Tests";
744
846
  this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
745
847
  return;
746
848
  }
@@ -749,6 +851,7 @@ var CodeTestsElement = class extends HTMLElement {
749
851
  this.setAttribute("success", failedTests.length == 0 ? "true" : "false");
750
852
  this.classList.remove("running");
751
853
  this.part.remove("running");
854
+ this.findElement("play-button-label").textContent = "Run Tests";
752
855
  this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
753
856
  }
754
857
  #clearTestStatuses() {
@@ -801,36 +904,43 @@ var CodeTestsElement = class extends HTMLElement {
801
904
  let testType;
802
905
  try {
803
906
  const allowTest = this.dispatchEvent(new CustomEvent("beforetest" /* BeforeTest */, { bubbles: true, cancelable: true, composed: true, detail: { testElement } }));
804
- if (allowTest == true) {
805
- const beforeHooks = this.#hooks.get(BEFOREEACH);
806
- if (beforeHooks != null) {
807
- for (const [hook, ids] of beforeHooks) {
808
- if (ids.has(testId)) {
809
- beforeResult = await hook();
810
- break;
811
- }
907
+ if (allowTest == false || this.#isCanceled == true) {
908
+ throw new Error("Test has been cancelled");
909
+ }
910
+ const beforeHooks = this.#hooks.get(BEFOREEACH);
911
+ if (beforeHooks != null) {
912
+ for (const [hook, ids] of beforeHooks) {
913
+ if (ids.has(testId)) {
914
+ beforeResult = await hook(this, testElement);
915
+ break;
812
916
  }
813
917
  }
814
- testResult = await test();
815
- const afterHooks = this.#hooks.get(AFTEREACH);
816
- if (afterHooks != null) {
817
- for (const [hook, ids] of afterHooks) {
818
- if (ids.has(testId)) {
819
- afterResult = await hook();
820
- break;
821
- }
918
+ }
919
+ if (this.#isCanceled == true) {
920
+ throw new Error("Test has been cancelled");
921
+ }
922
+ testResult = await test(this, testElement);
923
+ if (this.#isCanceled == true) {
924
+ throw new Error("Test has been cancelled");
925
+ }
926
+ const afterHooks = this.#hooks.get(AFTEREACH);
927
+ if (afterHooks != null) {
928
+ for (const [hook, ids] of afterHooks) {
929
+ if (ids.has(testId)) {
930
+ afterResult = await hook(this, testElement);
931
+ break;
822
932
  }
823
933
  }
824
- testType = "before";
825
- if (beforeResult != NOTESTDEFINED) {
826
- this.#handleTestResult(testElement, beforeResult, true, void 0, testType);
827
- }
828
- testType = void 0;
829
- this.#handleTestResult(testElement, testResult, true, void 0, testType);
830
- testType = "after";
831
- if (afterResult != NOTESTDEFINED) {
832
- this.#handleTestResult(testElement, afterResult, true, void 0, testType);
833
- }
934
+ }
935
+ testType = "before";
936
+ if (beforeResult != NOTESTDEFINED) {
937
+ this.#handleTestResult(testElement, beforeResult, true, void 0, testType);
938
+ }
939
+ testType = void 0;
940
+ this.#handleTestResult(testElement, testResult, true, void 0, testType);
941
+ testType = "after";
942
+ if (afterResult != NOTESTDEFINED) {
943
+ this.#handleTestResult(testElement, afterResult, true, void 0, testType);
834
944
  }
835
945
  } catch (error) {
836
946
  this.#handleTestResult(testElement, testResult, false, error, testType);
@@ -909,7 +1019,6 @@ Result:${objectResult.value}`,
909
1019
  }
910
1020
  static create(properties) {
911
1021
  const element = document.createElement("code-tests");
912
- console.log(properties);
913
1022
  return element;
914
1023
  }
915
1024
  #tests = /* @__PURE__ */ new Map();
@@ -1082,5 +1191,6 @@ if (customElements.get(COMPONENT_TAG_NAME) == null) {
1082
1191
  CodeTestEventType,
1083
1192
  CodeTests,
1084
1193
  CodeTestsElement,
1085
- expect
1194
+ expect,
1195
+ prompt
1086
1196
  });
@@ -14,8 +14,17 @@ declare class CodeTests {
14
14
  static expect<T>(value: T): TestPromise<T>;
15
15
  static expectSync<T>(value: T): TestPromise<T>;
16
16
  static expectBefore<T>(value: T): TestPromise<T>;
17
+ static prompt(host: CodeTestsElement, parent: HTMLElement, message: string, options?: PromptOptions): Promise<boolean>;
18
+ static createElementFromTemplate(target: string | HTMLTemplateElement, parent?: HTMLElement): HTMLElement;
17
19
  }
18
20
  declare function expect(value: any): TestPromise<any>;
21
+ type PromptOptions = {
22
+ acceptLabel?: string;
23
+ rejectLabel?: string;
24
+ onAccept?: () => void;
25
+ onReject?: () => void;
26
+ };
27
+ declare function prompt(host: CodeTestsElement, parent: HTMLElement, message: string, options?: PromptOptions): Promise<boolean>;
19
28
 
20
29
  type CodeTestsProperties = {};
21
30
  declare enum CodeTestEventType {
@@ -33,10 +42,11 @@ declare class CodeTestsElement extends HTMLElement {
33
42
  connectedCallback(): void;
34
43
  disconnectedCallback(): void;
35
44
  loadTests(testsPath?: string): Promise<void>;
45
+ cancel(): void;
36
46
  runTests(): Promise<void>;
37
47
  static create(properties: CodeTestsProperties): HTMLElement;
38
48
  static observedAttributes: string[];
39
49
  attributeChangedCallback(attributeName: string, oldValue: string, newValue: string): void;
40
50
  }
41
51
 
42
- export { AFTERALL, AFTEREACH, BEFOREALL, BEFOREEACH, CodeTestEventType, CodeTests, CodeTestsElement, type CodeTestsProperties, expect };
52
+ export { AFTERALL, AFTEREACH, BEFOREALL, BEFOREEACH, CodeTestEventType, CodeTests, CodeTestsElement, type CodeTestsProperties, expect, prompt };
@@ -14,8 +14,17 @@ declare class CodeTests {
14
14
  static expect<T>(value: T): TestPromise<T>;
15
15
  static expectSync<T>(value: T): TestPromise<T>;
16
16
  static expectBefore<T>(value: T): TestPromise<T>;
17
+ static prompt(host: CodeTestsElement, parent: HTMLElement, message: string, options?: PromptOptions): Promise<boolean>;
18
+ static createElementFromTemplate(target: string | HTMLTemplateElement, parent?: HTMLElement): HTMLElement;
17
19
  }
18
20
  declare function expect(value: any): TestPromise<any>;
21
+ type PromptOptions = {
22
+ acceptLabel?: string;
23
+ rejectLabel?: string;
24
+ onAccept?: () => void;
25
+ onReject?: () => void;
26
+ };
27
+ declare function prompt(host: CodeTestsElement, parent: HTMLElement, message: string, options?: PromptOptions): Promise<boolean>;
19
28
 
20
29
  type CodeTestsProperties = {};
21
30
  declare enum CodeTestEventType {
@@ -33,10 +42,11 @@ declare class CodeTestsElement extends HTMLElement {
33
42
  connectedCallback(): void;
34
43
  disconnectedCallback(): void;
35
44
  loadTests(testsPath?: string): Promise<void>;
45
+ cancel(): void;
36
46
  runTests(): Promise<void>;
37
47
  static create(properties: CodeTestsProperties): HTMLElement;
38
48
  static observedAttributes: string[];
39
49
  attributeChangedCallback(attributeName: string, oldValue: string, newValue: string): void;
40
50
  }
41
51
 
42
- export { AFTERALL, AFTEREACH, BEFOREALL, BEFOREEACH, CodeTestEventType, CodeTests, CodeTestsElement, type CodeTestsProperties, expect };
52
+ export { AFTERALL, AFTEREACH, BEFOREALL, BEFOREEACH, CodeTestEventType, CodeTests, CodeTestsElement, type CodeTestsProperties, expect, prompt };
@@ -81,6 +81,7 @@ var code_tests_default = `:host
81
81
  --surface-button: var(--uchu-blue); /* --uchu-blue: #3984f2 */
82
82
  --surface-button-hover: var(--uchu-light-blue);
83
83
  --surface-button-active: var(--uchu-dark-blue);
84
+ --surface-button-cancel: var(--uchu-dark-blue);
84
85
 
85
86
  --border-test: solid 1px var(--uchu-dark-gray);
86
87
  --border-hook: solid 1px var(--uchu-dark-purple);
@@ -176,6 +177,26 @@ summary::before
176
177
  /* background: var(--surface-test-summary); */
177
178
  }
178
179
 
180
+ :host(.running) .run[data-all]
181
+ {
182
+ background-color: var(--surface-test-summary);
183
+ border-color: var(--surface-test-summary);
184
+ }
185
+ :host(.running) .run[data-all]:hover
186
+ {
187
+ background-color: var(--uchu-dark-gray);
188
+ border-color: var(--uchu-dark-gray);
189
+ }
190
+ :host(.running) .run[data-all]:active
191
+ {
192
+ background-color: var(--surface-test);
193
+ border-color: var(--surface-test);
194
+ }
195
+ :host(.running) .run[data-all]::before
196
+ {
197
+ display: none;
198
+ }
199
+
179
200
  #before-all-summary
180
201
  ,#after-all-summary
181
202
  {
@@ -360,7 +381,7 @@ pre
360
381
  }`;
361
382
 
362
383
  // src/code-tests.html?raw
363
- 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>';
384
+ 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>\n\n<template id="prompt-template">\n <div class="prompt" part="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>';
364
385
 
365
386
  // src/api.ts
366
387
  var TestPromise = class extends Promise {
@@ -396,7 +417,7 @@ var BEFOREALL = Symbol("beforeAll");
396
417
  var BEFOREEACH = Symbol("beforeEach");
397
418
  var AFTERALL = Symbol("afterAll");
398
419
  var AFTEREACH = Symbol("afterEach");
399
- var CodeTests = class {
420
+ var CodeTests = class _CodeTests {
400
421
  static timeoutMS = 500;
401
422
  static #expectInterval;
402
423
  static #expectPromise;
@@ -433,10 +454,61 @@ var CodeTests = class {
433
454
  });
434
455
  return promise;
435
456
  }
457
+ static async prompt(host, parent, message, options) {
458
+ return new Promise((resolve, reject) => {
459
+ const template = host.findElement("prompt-template");
460
+ const promptElement = _CodeTests.createElementFromTemplate(template);
461
+ promptElement.querySelector(".label").textContent = message;
462
+ const clickHandler = (event) => {
463
+ const composedPath = event.composedPath();
464
+ const acceptButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("accept"));
465
+ if (acceptButton != null) {
466
+ const result = options?.onAccept?.() ?? true;
467
+ promptElement.removeEventListener("click", clickHandler);
468
+ resolve(result);
469
+ return;
470
+ }
471
+ const rejectButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("reject"));
472
+ if (rejectButton != null) {
473
+ const result = options?.onReject?.() ?? false;
474
+ promptElement.removeEventListener("click", clickHandler);
475
+ resolve(result);
476
+ return;
477
+ }
478
+ };
479
+ promptElement.addEventListener("click", clickHandler);
480
+ if (options?.acceptLabel != null) {
481
+ promptElement.querySelector(".accept").textContent = options.acceptLabel;
482
+ }
483
+ if (options?.rejectLabel != null) {
484
+ promptElement.querySelector(".reject").textContent = options.rejectLabel;
485
+ }
486
+ const details = parent instanceof HTMLDetailsElement ? parent : parent.querySelector(".test-details");
487
+ if (details != null) {
488
+ details.open = true;
489
+ }
490
+ parent.querySelector(".result")?.append(promptElement);
491
+ });
492
+ }
493
+ static createElementFromTemplate(target, parent) {
494
+ const templateNode = target instanceof HTMLTemplateElement ? target : document.querySelector(target);
495
+ if (templateNode == null) {
496
+ throw new Error(`Unable to find template element from selector: ${target}`);
497
+ }
498
+ const firstChild = templateNode.content.cloneNode(true).querySelector("*");
499
+ if (firstChild == null) {
500
+ throw new Error(`Unable to find first child of template element`);
501
+ }
502
+ parent?.append(firstChild);
503
+ return firstChild;
504
+ }
436
505
  };
437
506
  function expect(value) {
438
507
  return CodeTests.expect(value);
439
508
  }
509
+ function prompt(host, parent, message, options) {
510
+ return CodeTests.prompt(host, parent, message, options);
511
+ }
440
512
 
441
513
  // node_modules/.pnpm/ce-part-utils@0.0.0/node_modules/ce-part-utils/dist/ce-part-utils.js
442
514
  var DEFAULT_ELEMENT_SELECTOR = ":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";
@@ -517,7 +589,14 @@ var CodeTestsElement = class extends HTMLElement {
517
589
  if (parentListItem == null) {
518
590
  const isRunAll = runButton.hasAttribute("data-all");
519
591
  if (isRunAll == true) {
520
- this.runTests();
592
+ if (this.classList.contains("running")) {
593
+ if (this.classList.contains("canceled")) {
594
+ return;
595
+ }
596
+ this.cancel();
597
+ } else {
598
+ this.runTests();
599
+ }
521
600
  }
522
601
  return;
523
602
  }
@@ -529,6 +608,9 @@ var CodeTestsElement = class extends HTMLElement {
529
608
  if (test == null) {
530
609
  return;
531
610
  }
611
+ this.#isCanceled = false;
612
+ this.classList.remove("canceled");
613
+ this.part.remove("canceled");
532
614
  this.#runTest(testId, test);
533
615
  }
534
616
  #getCurrentTestsPath() {
@@ -639,11 +721,21 @@ var CodeTestsElement = class extends HTMLElement {
639
721
  this.#addProcessError("An error occurred while loading the tasks:", error);
640
722
  }
641
723
  }
724
+ #isCanceled = false;
725
+ cancel() {
726
+ this.#isCanceled = true;
727
+ this.classList.add("canceled");
728
+ this.part.add("canceled");
729
+ }
642
730
  async runTests() {
643
731
  this.dispatchEvent(new CustomEvent("beforeall" /* BeforeAll */, { bubbles: true, composed: true }));
644
732
  this.#continueRunningTests = true;
645
733
  this.classList.add("running");
734
+ this.#isCanceled = false;
735
+ this.classList.remove("canceled");
736
+ this.part.remove("canceled");
646
737
  this.toggleAttribute("success", false);
738
+ this.findElement("play-button-label").textContent = "Cancel";
647
739
  this.#clearTestStatuses();
648
740
  const inOrder = this.hasAttribute("in-order");
649
741
  const beforeHooks = this.#hooks.get(BEFOREALL);
@@ -654,7 +746,10 @@ var CodeTestsElement = class extends HTMLElement {
654
746
  beforeAllHookElement.classList.add("running");
655
747
  beforeAllHookElement.part.add("running");
656
748
  for (const [hook, ids] of beforeHooks) {
657
- hookResult = await hook();
749
+ if (this.#isCanceled == true) {
750
+ throw new Error("Test has been cancelled");
751
+ }
752
+ hookResult = await hook(this, beforeAllHookElement);
658
753
  this.#handleHookResult(hookResult, true, "before");
659
754
  }
660
755
  beforeAllHookElement.part.remove("running");
@@ -665,6 +760,7 @@ var CodeTestsElement = class extends HTMLElement {
665
760
  this.#continueRunningTests = false;
666
761
  this.classList.remove("running");
667
762
  this.part.remove("running");
763
+ this.findElement("play-button-label").textContent = "Run Tests";
668
764
  this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
669
765
  return;
670
766
  }
@@ -686,6 +782,7 @@ var CodeTestsElement = class extends HTMLElement {
686
782
  if (this.#continueRunningTests == false) {
687
783
  this.classList.remove("running");
688
784
  this.part.remove("running");
785
+ this.findElement("play-button-label").textContent = "Run Tests";
689
786
  this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
690
787
  return;
691
788
  }
@@ -697,7 +794,10 @@ var CodeTestsElement = class extends HTMLElement {
697
794
  afterAllHookElement.classList.add("running");
698
795
  afterAllHookElement.part.add("running");
699
796
  for (const [hook, ids] of afterHooks) {
700
- hookResult = await hook();
797
+ if (this.#isCanceled == true) {
798
+ throw new Error("Test has been cancelled");
799
+ }
800
+ hookResult = await hook(this, afterAllHookElement);
701
801
  this.#handleHookResult(hookResult, true, "after");
702
802
  }
703
803
  afterAllHookElement.part.remove("running");
@@ -708,6 +808,7 @@ var CodeTestsElement = class extends HTMLElement {
708
808
  this.#continueRunningTests = false;
709
809
  this.classList.remove("running");
710
810
  this.part.remove("running");
811
+ this.findElement("play-button-label").textContent = "Run Tests";
711
812
  this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
712
813
  return;
713
814
  }
@@ -716,6 +817,7 @@ var CodeTestsElement = class extends HTMLElement {
716
817
  this.setAttribute("success", failedTests.length == 0 ? "true" : "false");
717
818
  this.classList.remove("running");
718
819
  this.part.remove("running");
820
+ this.findElement("play-button-label").textContent = "Run Tests";
719
821
  this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
720
822
  }
721
823
  #clearTestStatuses() {
@@ -768,36 +870,43 @@ var CodeTestsElement = class extends HTMLElement {
768
870
  let testType;
769
871
  try {
770
872
  const allowTest = this.dispatchEvent(new CustomEvent("beforetest" /* BeforeTest */, { bubbles: true, cancelable: true, composed: true, detail: { testElement } }));
771
- if (allowTest == true) {
772
- const beforeHooks = this.#hooks.get(BEFOREEACH);
773
- if (beforeHooks != null) {
774
- for (const [hook, ids] of beforeHooks) {
775
- if (ids.has(testId)) {
776
- beforeResult = await hook();
777
- break;
778
- }
873
+ if (allowTest == false || this.#isCanceled == true) {
874
+ throw new Error("Test has been cancelled");
875
+ }
876
+ const beforeHooks = this.#hooks.get(BEFOREEACH);
877
+ if (beforeHooks != null) {
878
+ for (const [hook, ids] of beforeHooks) {
879
+ if (ids.has(testId)) {
880
+ beforeResult = await hook(this, testElement);
881
+ break;
779
882
  }
780
883
  }
781
- testResult = await test();
782
- const afterHooks = this.#hooks.get(AFTEREACH);
783
- if (afterHooks != null) {
784
- for (const [hook, ids] of afterHooks) {
785
- if (ids.has(testId)) {
786
- afterResult = await hook();
787
- break;
788
- }
884
+ }
885
+ if (this.#isCanceled == true) {
886
+ throw new Error("Test has been cancelled");
887
+ }
888
+ testResult = await test(this, testElement);
889
+ if (this.#isCanceled == true) {
890
+ throw new Error("Test has been cancelled");
891
+ }
892
+ const afterHooks = this.#hooks.get(AFTEREACH);
893
+ if (afterHooks != null) {
894
+ for (const [hook, ids] of afterHooks) {
895
+ if (ids.has(testId)) {
896
+ afterResult = await hook(this, testElement);
897
+ break;
789
898
  }
790
899
  }
791
- testType = "before";
792
- if (beforeResult != NOTESTDEFINED) {
793
- this.#handleTestResult(testElement, beforeResult, true, void 0, testType);
794
- }
795
- testType = void 0;
796
- this.#handleTestResult(testElement, testResult, true, void 0, testType);
797
- testType = "after";
798
- if (afterResult != NOTESTDEFINED) {
799
- this.#handleTestResult(testElement, afterResult, true, void 0, testType);
800
- }
900
+ }
901
+ testType = "before";
902
+ if (beforeResult != NOTESTDEFINED) {
903
+ this.#handleTestResult(testElement, beforeResult, true, void 0, testType);
904
+ }
905
+ testType = void 0;
906
+ this.#handleTestResult(testElement, testResult, true, void 0, testType);
907
+ testType = "after";
908
+ if (afterResult != NOTESTDEFINED) {
909
+ this.#handleTestResult(testElement, afterResult, true, void 0, testType);
801
910
  }
802
911
  } catch (error) {
803
912
  this.#handleTestResult(testElement, testResult, false, error, testType);
@@ -876,7 +985,6 @@ Result:${objectResult.value}`,
876
985
  }
877
986
  static create(properties) {
878
987
  const element = document.createElement("code-tests");
879
- console.log(properties);
880
988
  return element;
881
989
  }
882
990
  #tests = /* @__PURE__ */ new Map();
@@ -1048,5 +1156,6 @@ export {
1048
1156
  CodeTestEventType,
1049
1157
  CodeTests,
1050
1158
  CodeTestsElement,
1051
- expect
1159
+ expect,
1160
+ prompt
1052
1161
  };
@@ -1,4 +1,4 @@
1
- var H=`:host
1
+ var S=`:host
2
2
  {
3
3
  /*** gray ***/
4
4
  --uchu-light-gray-raw: 95.57% 0.003 286.35;
@@ -80,6 +80,7 @@ var H=`:host
80
80
  --surface-button: var(--uchu-blue); /* --uchu-blue: #3984f2 */
81
81
  --surface-button-hover: var(--uchu-light-blue);
82
82
  --surface-button-active: var(--uchu-dark-blue);
83
+ --surface-button-cancel: var(--uchu-dark-blue);
83
84
 
84
85
  --border-test: solid 1px var(--uchu-dark-gray);
85
86
  --border-hook: solid 1px var(--uchu-dark-purple);
@@ -175,6 +176,26 @@ summary::before
175
176
  /* background: var(--surface-test-summary); */
176
177
  }
177
178
 
179
+ :host(.running) .run[data-all]
180
+ {
181
+ background-color: var(--surface-test-summary);
182
+ border-color: var(--surface-test-summary);
183
+ }
184
+ :host(.running) .run[data-all]:hover
185
+ {
186
+ background-color: var(--uchu-dark-gray);
187
+ border-color: var(--uchu-dark-gray);
188
+ }
189
+ :host(.running) .run[data-all]:active
190
+ {
191
+ background-color: var(--surface-test);
192
+ border-color: var(--surface-test);
193
+ }
194
+ :host(.running) .run[data-all]::before
195
+ {
196
+ display: none;
197
+ }
198
+
178
199
  #before-all-summary
179
200
  ,#after-all-summary
180
201
  {
@@ -383,15 +404,28 @@ pre
383
404
  <span id="after-all-description" class="description">Results from After All Hook</span>
384
405
  </summary>
385
406
  <div id="after-all-results" class="results"></div>
386
- </details>`;var T=class extends Promise{async toBeDefined(t){if(await this==null)throw new Error(`${t??"Value"} is undefined`)}async toBe(t,s=!1){let e=await this;if((s==!0?e===t:e==t)==!1)throw new Error(` Value is not equal.
407
+ </details>
408
+
409
+ <template id="prompt-template">
410
+ <div class="prompt" part="prompt">
411
+ <div class="prompt-display">
412
+ <span class="icon prompt-icon"></span>
413
+ <span class="label prompt-label"></span>
414
+ </div>
415
+ <div class="prompt-actions">
416
+ <button class="prompt-button accept" type="button">Accept</button>
417
+ <button class="prompt-button reject" type="button">Reject</button>
418
+ </div>
419
+ </div>
420
+ </template>`;var T=class extends Promise{async toBeDefined(t){if(await this==null)throw new Error(`${t??"Value"} is undefined`)}async toBe(t,s=!1){let e=await this;if((s==!0?e===t:e==t)==!1)throw new Error(` Value is not equal.
387
421
  Expected: ${t}
388
- Result: ${e}`)}async toContainText(t){let s=await this}async toHaveAttribute(t){let s=await this;if(!(s instanceof HTMLElement))throw new Error("Unable to check for attribute on non-HTMLElement target");if(s.getAttribute(t))throw new Error("Taret does not have attribute")}},y=Symbol("beforeAll"),v=Symbol("beforeEach"),k=Symbol("afterAll"),x=Symbol("afterEach"),M=class{static timeoutMS=500;static#e;static#p;static expect(t){return new T(async(e,a)=>{if(t instanceof Promise){let r=await t;e(r);return}e(t)})}static expectSync(t){return new T(async(e,a)=>{if(t instanceof Promise){let r=await t;e(r);return}e(t)})}static expectBefore(t){return new T(async(e,a)=>{if(t instanceof Promise){let r=await t;e(r);return}e(t)})}};function j(h){return M.expect(h)}var $=":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";function D(h){let t=[...h.querySelectorAll(`${$}[id]`)];for(let e=0;e<t.length;e++)t[e].part.add(t[e].id);let s=[...h.querySelectorAll(`${$}[class]`)];for(let e=0;e<s.length;e++)s[e].part.add(...s[e].classList)}var z=(a=>(a.BeforeAll="beforeall",a.AfterAll="afterall",a.BeforeTest="beforetest",a.AfterTest="aftertest",a))(z||{}),R=Symbol("No Test Defined"),B=new CSSStyleSheet;B.replaceSync(H);var P="code-tests",S=class extends HTMLElement{componentParts=new Map;getElement(t){if(this.componentParts.get(t)==null){let s=this.findElement(t);s!=null&&this.componentParts.set(t,s)}return this.componentParts.get(t)}findElement(t){return this.shadowRoot.getElementById(t)}#e=new Map;#p={[y]:L(),[v]:L(),[x]:L(),[k]:L()};#t=!0;constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML=F,this.shadowRoot.adoptedStyleSheets.push(B),this.#c=this.#h.bind(this)}connectedCallback(){if(D(this.shadowRoot),this.addEventListener("click",this.#c),this.getAttribute("auto")=="false")return;let t=this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path");t!=null&&this.loadTests(t)}disconnectedCallback(){this.removeEventListener("click",this.#c)}#c;#h(t){let s=t.composedPath().find(n=>n instanceof HTMLButtonElement&&n.classList.contains("run"));if(s==null)return;let e=s.closest("li");if(e==null){s.hasAttribute("data-all")==!0&&this.runTests();return}let a=e.dataset.testId;if(a==null)return;let r=this.#s.get(a);r!=null&&this.#u(a,r)}#f(){return this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path")}async loadTests(t){let s=t??this.#f();if(s!=null)try{this.getElement("tests").innerHTML="",this.#s.clear(),this.classList.remove("has-before-hook"),this.classList.remove("has-after-hook");let e=window.location.href.lastIndexOf("/"),r=window.location.href.substring(e).indexOf(".")!=-1==!0?window.location.href.substring(0,e+1):window.location.href,n=r+s.substring(0,s.lastIndexOf("/")+1),o=r+s,l=await(await fetch(o)).text();l=l.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g,`'${n}$1'`);let u=new File([l],s.substring(s.lastIndexOf("/")),{type:"text/javascript"}),f=await import(URL.createObjectURL(u)),g=f.tests??f.default;if(g==null)throw new Error(`Unable to find tests definition in file at path: ${s}`);let E=g[y];if(E!=null){if(this.#e.get(y)==null){let c=new Map;c.set(E,new Set),this.#e.set(y,c)}this.classList.add("has-before-hook")}let m=g[v];if(m!=null&&this.#e.get(v)==null){let c=new Map;c.set(m,new Set),this.#e.set(v,c)}let b=g[k];if(b!=null){if(this.#e.get(k)==null){let c=new Map;c.set(b,new Set),this.#e.set(k,c)}this.classList.add("has-after-hook")}let A=g[x];if(A!=null&&this.#e.get(x)==null){let c=new Map;c.set(A,new Set),this.#e.set(x,c)}for(let[w,c]of Object.entries(g)){let C=this.#m(w,c);if(E!=null){let d=this.#e.get(y);if(d!=null){let p=d.get(E);p?.add(C)}}if(m!=null){let d=this.#e.get(v);if(d!=null){let p=d.get(m);p?.add(C)}}if(b!=null){let d=this.#e.get(k);if(d!=null){let p=d.get(b);p?.add(C)}}if(A!=null){let d=this.#e.get(x);if(d!=null){let p=d.get(A);p?.add(C)}}}}catch(e){this.#i("An error occurred while loading the tasks:",e)}}async runTests(){this.dispatchEvent(new CustomEvent("beforeall",{bubbles:!0,composed:!0})),this.#t=!0,this.classList.add("running"),this.toggleAttribute("success",!1),this.#g();let t=this.hasAttribute("in-order"),s=this.#e.get(y);if(s!=null){let r;try{let n=this.getElement("before-all-details");n.classList.add("running"),n.part.add("running");for(let[o,l]of s)r=await o(),this.#n(r,!0,"before");n.part.remove("running"),n.classList.remove("running")}catch(n){this.#n(r,!1,"before",n),console.error(n),this.#t=!1,this.classList.remove("running"),this.part.remove("running"),this.dispatchEvent(new CustomEvent("afterall",{bubbles:!0,composed:!0}));return}}if(t==!1){let r=[];for(let[n,o]of this.#s)r.push(this.#u(n,o));await Promise.all(r)}else for(let[r,n]of this.#s){if(this.#t==!1)break;await this.#u(r,n)}if(this.#t==!1){this.classList.remove("running"),this.part.remove("running"),this.dispatchEvent(new CustomEvent("afterall",{bubbles:!0,composed:!0}));return}let e=this.#e.get(k);if(e!=null){let r;try{let n=this.getElement("after-all-details");n.classList.add("running"),n.part.add("running");for(let[o,l]of e)r=await o(),this.#n(r,!0,"after");n.part.remove("running"),n.classList.remove("running")}catch(n){this.#n(r,!1,"after",n),console.error(n),this.#t=!1,this.classList.remove("running"),this.part.remove("running"),this.dispatchEvent(new CustomEvent("afterall",{bubbles:!0,composed:!0}));return}}let a=this.shadowRoot.querySelectorAll('[success="false"]');this.setAttribute("success",a.length==0?"true":"false"),this.classList.remove("running"),this.part.remove("running"),this.dispatchEvent(new CustomEvent("afterall",{bubbles:!0,composed:!0}))}#g(){for(let[e,a]of this.#s){let r=this.getElement("tests").querySelector(`[data-test-id="${e}"]`);if(r==null){this.#i(`Unable to find test element for test: ${e}`);return}r.toggleAttribute("success",!1),r.classList.remove("success","fail"),r.part.remove("success","fail")}let t=this.getElement("before-all-details");t.toggleAttribute("success",!1),t.classList.remove("success","fail"),t.part.remove("success","fail");let s=this.getElement("after-all-details");s.toggleAttribute("success",!1),s.classList.remove("success","fail"),s.part.remove("success","fail")}async#u(t,s){let e=this.getElement("tests").querySelector(`[data-test-id="${t}"]`);if(e==null){this.#i(`Unable to find test element for test: ${t}`);return}e.toggleAttribute("success",!1),e.classList.add("running"),e.part.add("running"),e.classList.remove("success","fail"),e.part.remove("success","fail");let a=e.querySelector(".result-icon");a?.classList.remove("success","fail"),a?.part.remove("success","fail"),a?.classList.add("running"),a?.part.add("running");let r=e.querySelector(".error-message");r!=null&&(r.textContent="");let n=e.querySelector("details");n!=null&&(n.open=!1);let o=R,l,u=R,i;try{if(this.dispatchEvent(new CustomEvent("beforetest",{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:e}}))==!0){let g=this.#e.get(v);if(g!=null){for(let[m,b]of g)if(b.has(t)){o=await m();break}}l=await s();let E=this.#e.get(x);if(E!=null){for(let[m,b]of E)if(b.has(t)){u=await m();break}}i="before",o!=R&&this.#a(e,o,!0,void 0,i),i=void 0,this.#a(e,l,!0,void 0,i),i="after",u!=R&&this.#a(e,u,!0,void 0,i)}}catch(f){this.#a(e,l,!1,f,i),console.error(f),this.#t=!1}finally{e?.classList.remove("running"),e?.part.remove("running"),a?.classList.remove("running"),a?.part.remove("running"),this.dispatchEvent(new CustomEvent("aftertest",{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:e}}))}}#a(t,s,e,a,r){if(s instanceof HTMLElement)this.#o(t,s,e,r);else if(s==null){let o=r==null?"Passed":"Hook Ran Successfully",l=this.#r(e==!0?`${o}`:`Failed${a!=null?`:
389
- ${a.message}`:""}`,e,r);this.#o(t,l,e,r)}else if(typeof s=="string"){let o=this.#r(`${s}${a==null?"":`:
390
- ${a.message}`}`,e,r);this.#o(t,o,e,r)}else if(typeof s=="object"){let o=s;if(o.success!=null&&o.expected!=null&&o.value!=null){let l=r==null?"Passed":"Success",u=r==null?"Failed":"Fail",i=this.#r(`${o.success==!0?`${l}:`:`${u}:`}
422
+ Result: ${e}`)}async toContainText(t){let s=await this}async toHaveAttribute(t){let s=await this;if(!(s instanceof HTMLElement))throw new Error("Unable to check for attribute on non-HTMLElement target");if(s.getAttribute(t))throw new Error("Taret does not have attribute")}},v=Symbol("beforeAll"),y=Symbol("beforeEach"),k=Symbol("afterAll"),w=Symbol("afterEach"),L=class d{static timeoutMS=500;static#e;static#h;static expect(t){return new T(async(e,r)=>{if(t instanceof Promise){let n=await t;e(n);return}e(t)})}static expectSync(t){return new T(async(e,r)=>{if(t instanceof Promise){let n=await t;e(n);return}e(t)})}static expectBefore(t){return new T(async(e,r)=>{if(t instanceof Promise){let n=await t;e(n);return}e(t)})}static async prompt(t,s,e,r){return new Promise((n,a)=>{let o=t.findElement("prompt-template"),l=d.createElementFromTemplate(o);l.querySelector(".label").textContent=e;let u=h=>{let f=h.composedPath();if(f.find(i=>i instanceof HTMLButtonElement&&i.classList.contains("accept"))!=null){let i=r?.onAccept?.()??!0;l.removeEventListener("click",u),n(i);return}if(f.find(i=>i instanceof HTMLButtonElement&&i.classList.contains("reject"))!=null){let i=r?.onReject?.()??!1;l.removeEventListener("click",u),n(i);return}};l.addEventListener("click",u),r?.acceptLabel!=null&&(l.querySelector(".accept").textContent=r.acceptLabel),r?.rejectLabel!=null&&(l.querySelector(".reject").textContent=r.rejectLabel);let c=s instanceof HTMLDetailsElement?s:s.querySelector(".test-details");c!=null&&(c.open=!0),s.querySelector(".result")?.append(l)})}static createElementFromTemplate(t,s){let e=t instanceof HTMLTemplateElement?t:document.querySelector(t);if(e==null)throw new Error(`Unable to find template element from selector: ${t}`);let r=e.content.cloneNode(!0).querySelector("*");if(r==null)throw new Error("Unable to find first child of template element");return s?.append(r),r}};function I(d){return L.expect(d)}function U(d,t,s,e){return L.prompt(d,t,s,e)}var $=":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";function P(d){let t=[...d.querySelectorAll(`${$}[id]`)];for(let e=0;e<t.length;e++)t[e].part.add(t[e].id);let s=[...d.querySelectorAll(`${$}[class]`)];for(let e=0;e<s.length;e++)s[e].part.add(...s[e].classList)}var N=(r=>(r.BeforeAll="beforeall",r.AfterAll="afterall",r.BeforeTest="beforetest",r.AfterTest="aftertest",r))(N||{}),H=Symbol("No Test Defined"),D=new CSSStyleSheet;D.replaceSync(S);var B="code-tests",R=class extends HTMLElement{componentParts=new Map;getElement(t){if(this.componentParts.get(t)==null){let s=this.findElement(t);s!=null&&this.componentParts.set(t,s)}return this.componentParts.get(t)}findElement(t){return this.shadowRoot.getElementById(t)}#e=new Map;#h={[v]:C(),[y]:C(),[w]:C(),[k]:C()};#s=!0;constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML=F,this.shadowRoot.adoptedStyleSheets.push(D),this.#u=this.#f.bind(this)}connectedCallback(){if(P(this.shadowRoot),this.addEventListener("click",this.#u),this.getAttribute("auto")=="false")return;let t=this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path");t!=null&&this.loadTests(t)}disconnectedCallback(){this.removeEventListener("click",this.#u)}#u;#f(t){let s=t.composedPath().find(a=>a instanceof HTMLButtonElement&&a.classList.contains("run"));if(s==null)return;let e=s.closest("li");if(e==null){if(s.hasAttribute("data-all")==!0)if(this.classList.contains("running")){if(this.classList.contains("canceled"))return;this.cancel()}else this.runTests();return}let r=e.dataset.testId;if(r==null)return;let n=this.#r.get(r);n!=null&&(this.#t=!1,this.classList.remove("canceled"),this.part.remove("canceled"),this.#d(r,n))}#m(){return this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path")}async loadTests(t){let s=t??this.#m();if(s!=null)try{this.getElement("tests").innerHTML="",this.#r.clear(),this.classList.remove("has-before-hook"),this.classList.remove("has-after-hook");let e=window.location.href.lastIndexOf("/"),n=window.location.href.substring(e).indexOf(".")!=-1==!0?window.location.href.substring(0,e+1):window.location.href,a=n+s.substring(0,s.lastIndexOf("/")+1),o=n+s,l=await(await fetch(o)).text();l=l.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g,`'${a}$1'`);let u=new File([l],s.substring(s.lastIndexOf("/")),{type:"text/javascript"}),h=await import(URL.createObjectURL(u)),f=h.tests??h.default;if(f==null)throw new Error(`Unable to find tests definition in file at path: ${s}`);let E=f[v];if(E!=null){if(this.#e.get(v)==null){let p=new Map;p.set(E,new Set),this.#e.set(v,p)}this.classList.add("has-before-hook")}let b=f[y];if(b!=null&&this.#e.get(y)==null){let p=new Map;p.set(b,new Set),this.#e.set(y,p)}let i=f[k];if(i!=null){if(this.#e.get(k)==null){let p=new Map;p.set(i,new Set),this.#e.set(k,p)}this.classList.add("has-after-hook")}let A=f[w];if(A!=null&&this.#e.get(w)==null){let p=new Map;p.set(A,new Set),this.#e.set(w,p)}for(let[x,p]of Object.entries(f)){let M=this.#b(x,p);if(E!=null){let m=this.#e.get(v);if(m!=null){let g=m.get(E);g?.add(M)}}if(b!=null){let m=this.#e.get(y);if(m!=null){let g=m.get(b);g?.add(M)}}if(i!=null){let m=this.#e.get(k);if(m!=null){let g=m.get(i);g?.add(M)}}if(A!=null){let m=this.#e.get(w);if(m!=null){let g=m.get(A);g?.add(M)}}}}catch(e){this.#c("An error occurred while loading the tasks:",e)}}#t=!1;cancel(){this.#t=!0,this.classList.add("canceled"),this.part.add("canceled")}async runTests(){this.dispatchEvent(new CustomEvent("beforeall",{bubbles:!0,composed:!0})),this.#s=!0,this.classList.add("running"),this.#t=!1,this.classList.remove("canceled"),this.part.remove("canceled"),this.toggleAttribute("success",!1),this.findElement("play-button-label").textContent="Cancel",this.#g();let t=this.hasAttribute("in-order"),s=this.#e.get(v);if(s!=null){let n;try{let a=this.getElement("before-all-details");a.classList.add("running"),a.part.add("running");for(let[o,l]of s){if(this.#t==!0)throw new Error("Test has been cancelled");n=await o(this,a),this.#o(n,!0,"before")}a.part.remove("running"),a.classList.remove("running")}catch(a){this.#o(n,!1,"before",a),console.error(a),this.#s=!1,this.classList.remove("running"),this.part.remove("running"),this.findElement("play-button-label").textContent="Run Tests",this.dispatchEvent(new CustomEvent("afterall",{bubbles:!0,composed:!0}));return}}if(t==!1){let n=[];for(let[a,o]of this.#r)n.push(this.#d(a,o));await Promise.all(n)}else for(let[n,a]of this.#r){if(this.#s==!1)break;await this.#d(n,a)}if(this.#s==!1){this.classList.remove("running"),this.part.remove("running"),this.findElement("play-button-label").textContent="Run Tests",this.dispatchEvent(new CustomEvent("afterall",{bubbles:!0,composed:!0}));return}let e=this.#e.get(k);if(e!=null){let n;try{let a=this.getElement("after-all-details");a.classList.add("running"),a.part.add("running");for(let[o,l]of e){if(this.#t==!0)throw new Error("Test has been cancelled");n=await o(this,a),this.#o(n,!0,"after")}a.part.remove("running"),a.classList.remove("running")}catch(a){this.#o(n,!1,"after",a),console.error(a),this.#s=!1,this.classList.remove("running"),this.part.remove("running"),this.findElement("play-button-label").textContent="Run Tests",this.dispatchEvent(new CustomEvent("afterall",{bubbles:!0,composed:!0}));return}}let r=this.shadowRoot.querySelectorAll('[success="false"]');this.setAttribute("success",r.length==0?"true":"false"),this.classList.remove("running"),this.part.remove("running"),this.findElement("play-button-label").textContent="Run Tests",this.dispatchEvent(new CustomEvent("afterall",{bubbles:!0,composed:!0}))}#g(){for(let[e,r]of this.#r){let n=this.getElement("tests").querySelector(`[data-test-id="${e}"]`);if(n==null){this.#c(`Unable to find test element for test: ${e}`);return}n.toggleAttribute("success",!1),n.classList.remove("success","fail"),n.part.remove("success","fail")}let t=this.getElement("before-all-details");t.toggleAttribute("success",!1),t.classList.remove("success","fail"),t.part.remove("success","fail");let s=this.getElement("after-all-details");s.toggleAttribute("success",!1),s.classList.remove("success","fail"),s.part.remove("success","fail")}async#d(t,s){let e=this.getElement("tests").querySelector(`[data-test-id="${t}"]`);if(e==null){this.#c(`Unable to find test element for test: ${t}`);return}e.toggleAttribute("success",!1),e.classList.add("running"),e.part.add("running"),e.classList.remove("success","fail"),e.part.remove("success","fail");let r=e.querySelector(".result-icon");r?.classList.remove("success","fail"),r?.part.remove("success","fail"),r?.classList.add("running"),r?.part.add("running");let n=e.querySelector(".error-message");n!=null&&(n.textContent="");let a=e.querySelector("details");a!=null&&(a.open=!1);let o=H,l,u=H,c;try{if(this.dispatchEvent(new CustomEvent("beforetest",{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:e}}))==!1||this.#t==!0)throw new Error("Test has been cancelled");let f=this.#e.get(y);if(f!=null){for(let[b,i]of f)if(i.has(t)){o=await b(this,e);break}}if(this.#t==!0)throw new Error("Test has been cancelled");if(l=await s(this,e),this.#t==!0)throw new Error("Test has been cancelled");let E=this.#e.get(w);if(E!=null){for(let[b,i]of E)if(i.has(t)){u=await b(this,e);break}}c="before",o!=H&&this.#a(e,o,!0,void 0,c),c=void 0,this.#a(e,l,!0,void 0,c),c="after",u!=H&&this.#a(e,u,!0,void 0,c)}catch(h){this.#a(e,l,!1,h,c),console.error(h),this.#s=!1}finally{e?.classList.remove("running"),e?.part.remove("running"),r?.classList.remove("running"),r?.part.remove("running"),this.dispatchEvent(new CustomEvent("aftertest",{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:e}}))}}#a(t,s,e,r,n){if(s instanceof HTMLElement)this.#l(t,s,e,n);else if(s==null){let o=n==null?"Passed":"Hook Ran Successfully",l=this.#n(e==!0?`${o}`:`Failed${r!=null?`:
423
+ ${r.message}`:""}`,e,n);this.#l(t,l,e,n)}else if(typeof s=="string"){let o=this.#n(`${s}${r==null?"":`:
424
+ ${r.message}`}`,e,n);this.#l(t,o,e,n)}else if(typeof s=="object"){let o=s;if(o.success!=null&&o.expected!=null&&o.value!=null){let l=n==null?"Passed":"Success",u=n==null?"Failed":"Fail",c=this.#n(`${o.success==!0?`${l}:`:`${u}:`}
391
425
  Expected:${o.expected}
392
- Result:${o.value}`,o.success,r);this.#o(t,i,e,r)}}let n=t.querySelector("details");n!=null&&(n.open=!0)}#n(t,s,e,a){if(t instanceof HTMLElement)this.#l(t,s,e);else{let n;if(t==null)n=this.#r(s==!0?"Hook Ran Successfully":`Failed${a!=null?`:
393
- ${a.message}`:""}`,s),this.#l(n,s,e);else if(typeof t=="string")n=this.#r(`${t}${a==null?"":`:
394
- ${a.message}`}`,s),this.#l(n,s,e);else if(typeof t=="object"){let o=t;o.success!=null&&o.expected!=null&&o.value!=null&&(n=this.#r(`${o.success==!0?"Success:":"Fail:"}
426
+ Result:${o.value}`,o.success,n);this.#l(t,c,e,n)}}let a=t.querySelector("details");a!=null&&(a.open=!0)}#o(t,s,e,r){if(t instanceof HTMLElement)this.#i(t,s,e);else{let a;if(t==null)a=this.#n(s==!0?"Hook Ran Successfully":`Failed${r!=null?`:
427
+ ${r.message}`:""}`,s),this.#i(a,s,e);else if(typeof t=="string")a=this.#n(`${t}${r==null?"":`:
428
+ ${r.message}`}`,s),this.#i(a,s,e);else if(typeof t=="object"){let o=t;o.success!=null&&o.expected!=null&&o.value!=null&&(a=this.#n(`${o.success==!0?"Success:":"Fail:"}
395
429
  Expected:${o.expected}
396
- Result:${o.value}`,o.success),this.#l(n,s,e))}}let r=this.getElement(`${e}-all-details`);r!=null&&(r.open=!0)}static create(t){let s=document.createElement("code-tests");return console.log(t),s}#s=new Map;#m(t,s){let e=L();this.#s.set(e,s);let a=this.#b(e,t);return this.getElement("tests").append(a),e}#b(t,s){let e=document.createElement("li");e.dataset.testId=t,e.classList.add("test"),e.part.add("test");let a=document.createElement("details");a.classList.add("test-details"),a.part.add("test-details");let r=document.createElement("summary");r.classList.add("test-summary"),r.part.add("test-summary");let n=document.createElement("div");n.classList.add("result-icon"),n.part.add("result-icon"),r.append(n);let o=document.createElement("span");o.classList.add("description","test-description"),o.textContent=s,r.append(o);let l=document.createElement("button");l.classList.add("run","test-run"),l.part.add("run","test-run"),l.textContent="Run Test",l.title="Run Test",r.append(l);let u=document.createElement("div");u.classList.add("before-result","test-before-result"),u.part.add("before-result","test-before-result");let i=document.createElement("div");i.classList.add("result","test-result"),i.part.add("result","test-result");let f=document.createElement("div");return f.classList.add("after-result","test-after-result"),f.part.add("after-result","test-after-result"),a.append(r),a.append(u),a.append(i),a.append(f),e.append(a),e}#o(t,s,e,a){t.setAttribute("success",e==!0?"true":"false"),t.classList.toggle("success",e),t.part.toggle("success",e),t.classList.toggle("fail",!e),t.part.toggle("fail",!e);let r=t.querySelector(".result-icon");r?.classList.toggle("success",e),r?.part.toggle("success",e),r?.classList.toggle("fail",!e),r?.part.toggle("fail",!e);let n=t.querySelector(`.${a==null?"result":a=="before"?"before-result":"after-result"}`);if(n==null){this.#i("Unable to find result element");return}n.innerHTML="",n.appendChild(s)}#r(t,s,e){let a=document.createElement("code");a.classList.add("code"),a.part.add("code");let r=document.createElement("pre");r.textContent=t;let n=s==!0?"success-message":"error-message";return r.classList.add("pre",n),r.part.add("pre",n),a.appendChild(r),a}#l(t,s,e){let a=this.getElement(`${e}-all-details`),r=this.getElement(`${e}-all-results`);a.setAttribute("success",s==!0?"true":"false"),a.classList.toggle("success",s),a.part.toggle("success",s),a.classList.toggle("fail",!s),a.part.toggle("fail",!s),r.innerHTML="",r.appendChild(t)}#i(t,s){s instanceof Error&&(t+=`
397
- ${s.message}`,console.error(s));let e=document.createElement("li");e.classList.add("error","process-error"),e.part.add("error","process-error");let a=document.createElement("code");a.classList.add("code","process-error-code"),a.part.add("code","process-error-code");let r=document.createElement("pre");r.classList.add("pre","process-error-pre"),r.part.add("pre","process-error-pre"),r.textContent=t,a.append(r),e.append(a),this.getElement("tests").append(e)}#d(t){if(t=="ordered"){let s=this.shadowRoot.querySelector("ul");if(s==null)return;let e=this.shadowRoot?.querySelectorAll("li"),a=document.createElement("ol");e!=null&&a.append(...e),a.id="tests",s.replaceWith(a)}else{let s=this.shadowRoot.querySelector("ol");if(s==null)return;let e=this.shadowRoot?.querySelectorAll("li"),a=document.createElement("ul");a.id="tests",e!=null&&a.append(...e),s.replaceWith(a)}}static observedAttributes=["in-order"];attributeChangedCallback(t,s,e){t=="in-order"&&(e==null?this.#d("unordered"):this.#d("ordered"))}};function L(){let h=new Uint8Array(20);crypto.getRandomValues(h);let t=[].slice.apply(h).map(function(e){return String.fromCharCode(e)}).join("");return btoa(t).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,"")}customElements.get(P)==null&&customElements.define(P,S);export{k as AFTERALL,x as AFTEREACH,y as BEFOREALL,v as BEFOREEACH,z as CodeTestEventType,M as CodeTests,S as CodeTestsElement,j as expect};
430
+ Result:${o.value}`,o.success),this.#i(a,s,e))}}let n=this.getElement(`${e}-all-details`);n!=null&&(n.open=!0)}static create(t){return document.createElement("code-tests")}#r=new Map;#b(t,s){let e=C();this.#r.set(e,s);let r=this.#E(e,t);return this.getElement("tests").append(r),e}#E(t,s){let e=document.createElement("li");e.dataset.testId=t,e.classList.add("test"),e.part.add("test");let r=document.createElement("details");r.classList.add("test-details"),r.part.add("test-details");let n=document.createElement("summary");n.classList.add("test-summary"),n.part.add("test-summary");let a=document.createElement("div");a.classList.add("result-icon"),a.part.add("result-icon"),n.append(a);let o=document.createElement("span");o.classList.add("description","test-description"),o.textContent=s,n.append(o);let l=document.createElement("button");l.classList.add("run","test-run"),l.part.add("run","test-run"),l.textContent="Run Test",l.title="Run Test",n.append(l);let u=document.createElement("div");u.classList.add("before-result","test-before-result"),u.part.add("before-result","test-before-result");let c=document.createElement("div");c.classList.add("result","test-result"),c.part.add("result","test-result");let h=document.createElement("div");return h.classList.add("after-result","test-after-result"),h.part.add("after-result","test-after-result"),r.append(n),r.append(u),r.append(c),r.append(h),e.append(r),e}#l(t,s,e,r){t.setAttribute("success",e==!0?"true":"false"),t.classList.toggle("success",e),t.part.toggle("success",e),t.classList.toggle("fail",!e),t.part.toggle("fail",!e);let n=t.querySelector(".result-icon");n?.classList.toggle("success",e),n?.part.toggle("success",e),n?.classList.toggle("fail",!e),n?.part.toggle("fail",!e);let a=t.querySelector(`.${r==null?"result":r=="before"?"before-result":"after-result"}`);if(a==null){this.#c("Unable to find result element");return}a.innerHTML="",a.appendChild(s)}#n(t,s,e){let r=document.createElement("code");r.classList.add("code"),r.part.add("code");let n=document.createElement("pre");n.textContent=t;let a=s==!0?"success-message":"error-message";return n.classList.add("pre",a),n.part.add("pre",a),r.appendChild(n),r}#i(t,s,e){let r=this.getElement(`${e}-all-details`),n=this.getElement(`${e}-all-results`);r.setAttribute("success",s==!0?"true":"false"),r.classList.toggle("success",s),r.part.toggle("success",s),r.classList.toggle("fail",!s),r.part.toggle("fail",!s),n.innerHTML="",n.appendChild(t)}#c(t,s){s instanceof Error&&(t+=`
431
+ ${s.message}`,console.error(s));let e=document.createElement("li");e.classList.add("error","process-error"),e.part.add("error","process-error");let r=document.createElement("code");r.classList.add("code","process-error-code"),r.part.add("code","process-error-code");let n=document.createElement("pre");n.classList.add("pre","process-error-pre"),n.part.add("pre","process-error-pre"),n.textContent=t,r.append(n),e.append(r),this.getElement("tests").append(e)}#p(t){if(t=="ordered"){let s=this.shadowRoot.querySelector("ul");if(s==null)return;let e=this.shadowRoot?.querySelectorAll("li"),r=document.createElement("ol");e!=null&&r.append(...e),r.id="tests",s.replaceWith(r)}else{let s=this.shadowRoot.querySelector("ol");if(s==null)return;let e=this.shadowRoot?.querySelectorAll("li"),r=document.createElement("ul");r.id="tests",e!=null&&r.append(...e),s.replaceWith(r)}}static observedAttributes=["in-order"];attributeChangedCallback(t,s,e){t=="in-order"&&(e==null?this.#p("unordered"):this.#p("ordered"))}};function C(){let d=new Uint8Array(20);crypto.getRandomValues(d);let t=[].slice.apply(d).map(function(e){return String.fromCharCode(e)}).join("");return btoa(t).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,"")}customElements.get(B)==null&&customElements.define(B,R);export{k as AFTERALL,w as AFTEREACH,v as BEFOREALL,y as BEFOREEACH,N as CodeTestEventType,L as CodeTests,R as CodeTestsElement,I as expect,U as prompt};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magnit-ce/code-tests",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "A custom html element that interprets and runs tests in a browser.",
5
5
  "type": "module",
6
6
  "main": "dist/code-tests.js",