kempo-testing-framework 1.2.4 → 1.3.4

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 (54) hide show
  1. package/.github/copilot-instructions.md +105 -105
  2. package/.github/workflows/publish-npm.yml +41 -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/TestFramework.js +378 -378
  11. package/gui/components/TestSuite.js +181 -181
  12. package/gui/components/TestSummary.js +189 -189
  13. package/gui/components/Theme.js +40 -40
  14. package/gui/components/settingsStore.js +46 -46
  15. package/gui/icons/fail.svg +1 -1
  16. package/gui/icons/pass.svg +1 -1
  17. package/gui/icons/running.svg +1 -1
  18. package/gui/icons/settings.svg +1 -1
  19. package/package.json +5 -1
  20. package/src/browserTestServer.js +115 -115
  21. package/src/cli.js +198 -198
  22. package/src/gui.js +15 -2
  23. package/src/runBrowserTests.js +87 -87
  24. package/src/runTestFiles.js +94 -94
  25. package/src/runTests.js +83 -83
  26. package/src/utils/logLevels.js +7 -7
  27. package/test.html +30 -30
  28. package/tests/Counter.js +33 -33
  29. package/tests/cli-flags.node-test.js +54 -54
  30. package/tests/cli-help.node-test.js +61 -61
  31. package/tests/cli-loglevel.node-test.js +40 -40
  32. package/tests/collapsible.browser-test.js +49 -49
  33. package/tests/counter.browser-test.js +140 -140
  34. package/tests/example.node-test.js +103 -103
  35. package/tests/fibonacci.js +92 -92
  36. package/tests/fibonacci.test.js +285 -285
  37. package/tests/icon.browser-test.js +54 -54
  38. package/tests/logs.browser-test.js +47 -47
  39. package/tests/setting-checkbox.browser-test.js +48 -48
  40. package/tests/setting-number.browser-test.js +54 -54
  41. package/tests/setting-select.browser-test.js +47 -47
  42. package/tests/settings-store.browser-test.js +26 -26
  43. package/tests/src-browserTestServer.node-test.js +47 -47
  44. package/tests/src-cli.node-test.js +32 -32
  45. package/tests/src-findTests.node-test.js +41 -41
  46. package/tests/src-logLevels.node-test.js +29 -29
  47. package/tests/src-runBrowserTests.node-test.js +41 -41
  48. package/tests/src-runTestFiles.node-test.js +42 -42
  49. package/tests/src-runTests.node-test.js +56 -56
  50. package/tests/test-framework.browser-test.js +65 -65
  51. package/tests/test-summary.browser-test.js +78 -78
  52. package/tests/test.browser-test.js +56 -56
  53. package/tests/testfile.browser-test.js +60 -60
  54. 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="/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
-
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
+