kempo-testing-framework 1.2.3 → 1.3.3

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.
Files changed (56) hide show
  1. package/.github/copilot-instructions.md +105 -105
  2. package/.github/workflows/publish-npm.yml +29 -0
  3. package/CONTRIBUTING.md +107 -107
  4. package/gui/components/Collapsible.js +54 -54
  5. package/gui/components/Icon.js +151 -151
  6. package/gui/components/Logs.js +73 -73
  7. package/gui/components/SettingCheckbox.js +42 -42
  8. package/gui/components/SettingNumber.js +77 -77
  9. package/gui/components/SettingSelect.js +67 -67
  10. package/gui/components/Test.js +1 -1
  11. package/gui/components/TestFramework.js +378 -378
  12. package/gui/components/TestSuite.js +181 -181
  13. package/gui/components/TestSummary.js +189 -189
  14. package/gui/components/Theme.js +40 -40
  15. package/gui/components/settingsStore.js +46 -46
  16. package/gui/icons/fail.svg +1 -1
  17. package/gui/icons/pass.svg +1 -1
  18. package/gui/icons/running.svg +1 -1
  19. package/gui/icons/settings.svg +1 -1
  20. package/gui/index.html +1 -1
  21. package/package.json +7 -2
  22. package/src/browserTestServer.js +115 -115
  23. package/src/cli.js +198 -198
  24. package/src/gui.js +17 -4
  25. package/src/runBrowserTests.js +87 -87
  26. package/src/runTestFiles.js +94 -94
  27. package/src/runTests.js +83 -83
  28. package/src/utils/logLevels.js +7 -7
  29. package/test.html +30 -30
  30. package/tests/Counter.js +33 -33
  31. package/tests/cli-flags.node-test.js +54 -54
  32. package/tests/cli-help.node-test.js +61 -61
  33. package/tests/cli-loglevel.node-test.js +40 -40
  34. package/tests/collapsible.browser-test.js +49 -49
  35. package/tests/counter.browser-test.js +140 -140
  36. package/tests/example.node-test.js +103 -103
  37. package/tests/fibonacci.js +92 -92
  38. package/tests/fibonacci.test.js +285 -285
  39. package/tests/icon.browser-test.js +54 -54
  40. package/tests/logs.browser-test.js +47 -47
  41. package/tests/setting-checkbox.browser-test.js +48 -48
  42. package/tests/setting-number.browser-test.js +54 -54
  43. package/tests/setting-select.browser-test.js +47 -47
  44. package/tests/settings-store.browser-test.js +26 -26
  45. package/tests/src-browserTestServer.node-test.js +47 -47
  46. package/tests/src-cli.node-test.js +32 -32
  47. package/tests/src-findTests.node-test.js +41 -41
  48. package/tests/src-logLevels.node-test.js +29 -29
  49. package/tests/src-runBrowserTests.node-test.js +41 -41
  50. package/tests/src-runTestFiles.node-test.js +42 -42
  51. package/tests/src-runTests.node-test.js +56 -56
  52. package/tests/test-framework.browser-test.js +65 -65
  53. package/tests/test-summary.browser-test.js +78 -78
  54. package/tests/test.browser-test.js +56 -56
  55. package/tests/testfile.browser-test.js +60 -60
  56. package/tests/theme.browser-test.js +38 -38
@@ -1,181 +1,181 @@
1
- import { LitElement, html, css, render } from '../lit-all.min.js';
2
- import './Icon.js';
3
- import './Test.js';
4
- import './Logs.js';
5
- import './Collapsible.js';
6
- import { subscribe } from './settingsStore.js';
7
-
8
- export const statusMap = {
9
- notran: 'Not Ran',
10
- queued: 'Queued',
11
- running: 'Running',
12
- pass: 'Pass',
13
- fail: 'Fail'
14
- };
15
-
16
- class TestSuiteEl extends LitElement {
17
- /*
18
- Properties
19
- */
20
- static properties = {
21
- file: { type: String, reflect: true },
22
- testNames: { type: Array },
23
- status: { type: String, reflect: true }
24
- };
25
- #unsubscribe = null;
26
- #testsContainer = null;
27
- constructor(){
28
- super();
29
- this.file = '';
30
- this.testNames = [];
31
- this.status = 'notran';
32
- }
33
-
34
- /*
35
- LifecycleCallbacks
36
- */
37
- connectedCallback(){
38
- super.connectedCallback();
39
- }
40
- firstUpdated(){
41
- // Listen on host so light-DOM children bubble here
42
- this.addEventListener('test_status_change', this.testStatusChangeHandler);
43
- this.#unsubscribe = subscribe(() => this.requestUpdate());
44
- // Ensure a light-DOM container exists for tests and render them there
45
- const existing = this.querySelector('[slot="tests"]');
46
- this.#testsContainer = existing || (() => {
47
- const c = document.createElement('div');
48
- c.setAttribute('slot', 'tests');
49
- this.appendChild(c);
50
- return c;
51
- })();
52
- this.renderTests();
53
- }
54
- disconnectedCallback(){
55
- super.disconnectedCallback();
56
- this.removeEventListener('test_status_change', this.testStatusChangeHandler);
57
- if(this.#unsubscribe) this.#unsubscribe();
58
- }
59
- updated(changedProps){
60
- if(changedProps.has('status')){
61
- this.dispatchEvent(new CustomEvent('testfile_status_change', {
62
- detail: { file: this.file, status: this.status },
63
- bubbles: true,
64
- composed: true
65
- }));
66
- }
67
- if(changedProps.has('file') || changedProps.has('testNames')){
68
- this.renderTests();
69
- }
70
- }
71
-
72
- /*
73
- Methods
74
- */
75
- runAllTests = () => {
76
- const getFrameworkEl = () => {
77
- let node = this;
78
- while(node){
79
- if(node && node.closest){
80
- const fw = node.closest('ktf-test-framework');
81
- if(fw) return fw;
82
- }
83
- const root = node?.getRootNode?.();
84
- const host = root && root.host ? root.host : null;
85
- if(!host) break;
86
- node = host;
87
- }
88
- return document.querySelector('ktf-test-framework');
89
- };
90
- const fw = getFrameworkEl();
91
- if(fw && typeof fw.enqueueSuite==='function') fw.enqueueSuite({ file: this.file, testNames: this.testNames, el: this });
92
- };
93
- testStatusChangeHandler = () => { this.status = this.calcStatus(); };
94
-
95
- /*
96
- Utility Methods
97
- */
98
- getFrameworkEl = () => {
99
- let node = this;
100
- while(node){
101
- if(node && node.closest){
102
- const fw = node.closest('ktf-test-framework');
103
- if(fw) return fw;
104
- }
105
- const root = node?.getRootNode?.();
106
- const host = root && root.host ? root.host : null;
107
- if(!host) break;
108
- node = host;
109
- }
110
- return document.querySelector('ktf-test-framework');
111
- };
112
- calcStatus = () => {
113
- const root = this.#testsContainer || this;
114
- const testElements = root.querySelectorAll('ktf-test');
115
- const statuses = Array.from(testElements).map(el => el.status);
116
- if(statuses.includes('running')) return 'running';
117
- if(statuses.includes('fail')) return 'fail';
118
- if(statuses.length && statuses.every(s => s==='pass')) return 'pass';
119
- return 'notran';
120
- };
121
-
122
- /*
123
- Light DOM rendering for tests
124
- */
125
- renderTests(){
126
- if(!this.#testsContainer) return;
127
- const list = Array.isArray(this.testNames) ? this.testNames : [];
128
- const tpl = html`${list.map(name => html`<ktf-test .file=${this.file} .name=${name}></ktf-test>`)}`;
129
- render(tpl, this.#testsContainer);
130
- }
131
-
132
- /*
133
- Rendering
134
- */
135
- render(){
136
- if(!this.file || !this.testNames.length) return html``;
137
- const titleText = this.file.replace('tests/', '').replace('.node-test.js', '').replace('.browser-test.js', '').replace('.test.js', '');
138
- return html`
139
- <link rel="stylesheet" href="/essential.css">
140
- <ktf-collapsible>
141
- <span slot="title" id="title" class="-ml">${titleText}</span>
142
- <div slot="actions">
143
- ${this.status==='notran' || this.status==='queued' ? html`
144
- <button class="no-btn d-ib ph" @click=${this.runAllTests} aria-label="Run Test Suite" ?disabled=${this.status==='queued'}>
145
- <ktf-icon name="${this.status==='queued'?'scheduled':'play'}"></ktf-icon>
146
- </button>
147
- ` : html`
148
- <span class="d-ib ph status-color" aria-hidden="true">
149
- <ktf-icon name="${this.status}" animation="${this.status==='running'?'spin':'none'}"></ktf-icon>
150
- </span>
151
- `}
152
- </div>
153
- <div id="details">
154
- <div id="status">
155
- <h6>${statusMap[this.status]}</h6>
156
- ${this.status!=='running'?html`
157
- <button class="primary mb" @click=${this.runAllTests} ?disabled=${this.status==='queued'}>Run Test Suite</button>
158
- `:html``}
159
- </div>
160
- <ktf-logs id="fileLogs"></ktf-logs>
161
- <slot name="tests"></slot>
162
- </div>
163
- </ktf-collapsible>
164
- `;
165
- }
166
-
167
- static styles = css`
168
- :host{ --tf_status: var(--tc_default, inherit); }
169
- :host([status="running"]){ --tf_status: var(--tc_primary, #3366ff); }
170
- :host([status="pass"]){ --tf_status: var(--tc_success, rgb(0, 136, 0)); }
171
- :host([status="fail"]){ --tf_status: var(--tc_danger, rgb(255, 0, 51)); }
172
- #title{ font-size: 1.25rem; font-weight: 600; }
173
- div[slot="actions"]{ font-size: 1.25rem; }
174
- #title,
175
- #status{ color: var(--tf_status); }
176
- .status-color{ color: var(--tf_status); }
177
- `;
178
- }
179
-
180
- window.customElements.define('ktf-test-suite', TestSuiteEl);
181
-
1
+ import { LitElement, html, css, render } from '../lit-all.min.js';
2
+ import './Icon.js';
3
+ import './Test.js';
4
+ import './Logs.js';
5
+ import './Collapsible.js';
6
+ import { subscribe } from './settingsStore.js';
7
+
8
+ export const statusMap = {
9
+ notran: 'Not Ran',
10
+ queued: 'Queued',
11
+ running: 'Running',
12
+ pass: 'Pass',
13
+ fail: 'Fail'
14
+ };
15
+
16
+ class TestSuiteEl extends LitElement {
17
+ /*
18
+ Properties
19
+ */
20
+ static properties = {
21
+ file: { type: String, reflect: true },
22
+ testNames: { type: Array },
23
+ status: { type: String, reflect: true }
24
+ };
25
+ #unsubscribe = null;
26
+ #testsContainer = null;
27
+ constructor(){
28
+ super();
29
+ this.file = '';
30
+ this.testNames = [];
31
+ this.status = 'notran';
32
+ }
33
+
34
+ /*
35
+ LifecycleCallbacks
36
+ */
37
+ connectedCallback(){
38
+ super.connectedCallback();
39
+ }
40
+ firstUpdated(){
41
+ // Listen on host so light-DOM children bubble here
42
+ this.addEventListener('test_status_change', this.testStatusChangeHandler);
43
+ this.#unsubscribe = subscribe(() => this.requestUpdate());
44
+ // Ensure a light-DOM container exists for tests and render them there
45
+ const existing = this.querySelector('[slot="tests"]');
46
+ this.#testsContainer = existing || (() => {
47
+ const c = document.createElement('div');
48
+ c.setAttribute('slot', 'tests');
49
+ this.appendChild(c);
50
+ return c;
51
+ })();
52
+ this.renderTests();
53
+ }
54
+ disconnectedCallback(){
55
+ super.disconnectedCallback();
56
+ this.removeEventListener('test_status_change', this.testStatusChangeHandler);
57
+ if(this.#unsubscribe) this.#unsubscribe();
58
+ }
59
+ updated(changedProps){
60
+ if(changedProps.has('status')){
61
+ this.dispatchEvent(new CustomEvent('testfile_status_change', {
62
+ detail: { file: this.file, status: this.status },
63
+ bubbles: true,
64
+ composed: true
65
+ }));
66
+ }
67
+ if(changedProps.has('file') || changedProps.has('testNames')){
68
+ this.renderTests();
69
+ }
70
+ }
71
+
72
+ /*
73
+ Methods
74
+ */
75
+ runAllTests = () => {
76
+ const getFrameworkEl = () => {
77
+ let node = this;
78
+ while(node){
79
+ if(node && node.closest){
80
+ const fw = node.closest('ktf-test-framework');
81
+ if(fw) return fw;
82
+ }
83
+ const root = node?.getRootNode?.();
84
+ const host = root && root.host ? root.host : null;
85
+ if(!host) break;
86
+ node = host;
87
+ }
88
+ return document.querySelector('ktf-test-framework');
89
+ };
90
+ const fw = getFrameworkEl();
91
+ if(fw && typeof fw.enqueueSuite==='function') fw.enqueueSuite({ file: this.file, testNames: this.testNames, el: this });
92
+ };
93
+ testStatusChangeHandler = () => { this.status = this.calcStatus(); };
94
+
95
+ /*
96
+ Utility Methods
97
+ */
98
+ getFrameworkEl = () => {
99
+ let node = this;
100
+ while(node){
101
+ if(node && node.closest){
102
+ const fw = node.closest('ktf-test-framework');
103
+ if(fw) return fw;
104
+ }
105
+ const root = node?.getRootNode?.();
106
+ const host = root && root.host ? root.host : null;
107
+ if(!host) break;
108
+ node = host;
109
+ }
110
+ return document.querySelector('ktf-test-framework');
111
+ };
112
+ calcStatus = () => {
113
+ const root = this.#testsContainer || this;
114
+ const testElements = root.querySelectorAll('ktf-test');
115
+ const statuses = Array.from(testElements).map(el => el.status);
116
+ if(statuses.includes('running')) return 'running';
117
+ if(statuses.includes('fail')) return 'fail';
118
+ if(statuses.length && statuses.every(s => s==='pass')) return 'pass';
119
+ return 'notran';
120
+ };
121
+
122
+ /*
123
+ Light DOM rendering for tests
124
+ */
125
+ renderTests(){
126
+ if(!this.#testsContainer) return;
127
+ const list = Array.isArray(this.testNames) ? this.testNames : [];
128
+ const tpl = html`${list.map(name => html`<ktf-test .file=${this.file} .name=${name}></ktf-test>`)}`;
129
+ render(tpl, this.#testsContainer);
130
+ }
131
+
132
+ /*
133
+ Rendering
134
+ */
135
+ render(){
136
+ if(!this.file || !this.testNames.length) return html``;
137
+ const titleText = this.file.replace('tests/', '').replace('.node-test.js', '').replace('.browser-test.js', '').replace('.test.js', '');
138
+ return html`
139
+ <link rel="stylesheet" href="/kempo.css">
140
+ <ktf-collapsible>
141
+ <span slot="title" id="title" class="-ml">${titleText}</span>
142
+ <div slot="actions">
143
+ ${this.status==='notran' || this.status==='queued' ? html`
144
+ <button class="no-btn d-ib ph" @click=${this.runAllTests} aria-label="Run Test Suite" ?disabled=${this.status==='queued'}>
145
+ <ktf-icon name="${this.status==='queued'?'scheduled':'play'}"></ktf-icon>
146
+ </button>
147
+ ` : html`
148
+ <span class="d-ib ph status-color" aria-hidden="true">
149
+ <ktf-icon name="${this.status}" animation="${this.status==='running'?'spin':'none'}"></ktf-icon>
150
+ </span>
151
+ `}
152
+ </div>
153
+ <div id="details">
154
+ <div id="status">
155
+ <h6>${statusMap[this.status]}</h6>
156
+ ${this.status!=='running'?html`
157
+ <button class="primary mb" @click=${this.runAllTests} ?disabled=${this.status==='queued'}>Run Test Suite</button>
158
+ `:html``}
159
+ </div>
160
+ <ktf-logs id="fileLogs"></ktf-logs>
161
+ <slot name="tests"></slot>
162
+ </div>
163
+ </ktf-collapsible>
164
+ `;
165
+ }
166
+
167
+ static styles = css`
168
+ :host{ --tf_status: var(--tc_default, inherit); }
169
+ :host([status="running"]){ --tf_status: var(--tc_primary, #3366ff); }
170
+ :host([status="pass"]){ --tf_status: var(--tc_success, rgb(0, 136, 0)); }
171
+ :host([status="fail"]){ --tf_status: var(--tc_danger, rgb(255, 0, 51)); }
172
+ #title{ font-size: 1.25rem; font-weight: 600; }
173
+ div[slot="actions"]{ font-size: 1.25rem; }
174
+ #title,
175
+ #status{ color: var(--tf_status); }
176
+ .status-color{ color: var(--tf_status); }
177
+ `;
178
+ }
179
+
180
+ window.customElements.define('ktf-test-suite', TestSuiteEl);
181
+