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.
- package/.github/copilot-instructions.md +105 -105
- package/.github/workflows/publish-npm.yml +41 -0
- package/CONTRIBUTING.md +107 -107
- package/gui/components/Collapsible.js +54 -54
- package/gui/components/Icon.js +151 -151
- package/gui/components/Logs.js +73 -73
- package/gui/components/SettingCheckbox.js +42 -42
- package/gui/components/SettingNumber.js +77 -77
- package/gui/components/SettingSelect.js +67 -67
- package/gui/components/TestFramework.js +378 -378
- package/gui/components/TestSuite.js +181 -181
- package/gui/components/TestSummary.js +189 -189
- package/gui/components/Theme.js +40 -40
- package/gui/components/settingsStore.js +46 -46
- package/gui/icons/fail.svg +1 -1
- package/gui/icons/pass.svg +1 -1
- package/gui/icons/running.svg +1 -1
- package/gui/icons/settings.svg +1 -1
- package/package.json +5 -1
- package/src/browserTestServer.js +115 -115
- package/src/cli.js +198 -198
- package/src/gui.js +15 -2
- package/src/runBrowserTests.js +87 -87
- package/src/runTestFiles.js +94 -94
- package/src/runTests.js +83 -83
- package/src/utils/logLevels.js +7 -7
- package/test.html +30 -30
- package/tests/Counter.js +33 -33
- package/tests/cli-flags.node-test.js +54 -54
- package/tests/cli-help.node-test.js +61 -61
- package/tests/cli-loglevel.node-test.js +40 -40
- package/tests/collapsible.browser-test.js +49 -49
- package/tests/counter.browser-test.js +140 -140
- package/tests/example.node-test.js +103 -103
- package/tests/fibonacci.js +92 -92
- package/tests/fibonacci.test.js +285 -285
- package/tests/icon.browser-test.js +54 -54
- package/tests/logs.browser-test.js +47 -47
- package/tests/setting-checkbox.browser-test.js +48 -48
- package/tests/setting-number.browser-test.js +54 -54
- package/tests/setting-select.browser-test.js +47 -47
- package/tests/settings-store.browser-test.js +26 -26
- package/tests/src-browserTestServer.node-test.js +47 -47
- package/tests/src-cli.node-test.js +32 -32
- package/tests/src-findTests.node-test.js +41 -41
- package/tests/src-logLevels.node-test.js +29 -29
- package/tests/src-runBrowserTests.node-test.js +41 -41
- package/tests/src-runTestFiles.node-test.js +42 -42
- package/tests/src-runTests.node-test.js +56 -56
- package/tests/test-framework.browser-test.js +65 -65
- package/tests/test-summary.browser-test.js +78 -78
- package/tests/test.browser-test.js +56 -56
- package/tests/testfile.browser-test.js +60 -60
- package/tests/theme.browser-test.js +38 -38
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
// Browser tests for TestFramework component
|
|
2
|
-
|
|
3
|
-
const nextTick = () => new Promise(r => setTimeout(r));
|
|
4
|
-
|
|
5
|
-
export const beforeEach = async () => {
|
|
6
|
-
document.body.innerHTML = '';
|
|
7
|
-
try { localStorage.removeItem('ktf_settings'); } catch {}
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export default {
|
|
11
|
-
'TestFramework queues and deduplicates tasks, updates statuses': async ({ pass, fail }) => {
|
|
12
|
-
try {
|
|
13
|
-
await import('/gui/components/settingsStore.js');
|
|
14
|
-
await import('/gui/components/Collapsible.js');
|
|
15
|
-
await import('/gui/components/Logs.js');
|
|
16
|
-
await import('/gui/components/Icon.js');
|
|
17
|
-
await import('/gui/components/Test.js');
|
|
18
|
-
await import('/gui/components/TestSuite.js');
|
|
19
|
-
await import('/gui/components/TestFramework.js');
|
|
20
|
-
|
|
21
|
-
const fw = document.createElement('ktf-test-framework');
|
|
22
|
-
const suite = document.createElement('ktf-test-suite');
|
|
23
|
-
suite.file = 'tests/example.node-test.js';
|
|
24
|
-
suite.testNames = ['X','Y'];
|
|
25
|
-
document.body.appendChild(fw);
|
|
26
|
-
fw.appendChild(suite);
|
|
27
|
-
await nextTick(); await nextTick();
|
|
28
|
-
|
|
29
|
-
const [t1, t2] = suite.querySelectorAll('ktf-test');
|
|
30
|
-
|
|
31
|
-
// Stub fetch to simulate run responses quickly
|
|
32
|
-
const originalFetch = window.fetch;
|
|
33
|
-
window.fetch = async (url) => {
|
|
34
|
-
// Return a minimal results payload depending on testNames query
|
|
35
|
-
const u = new URL(String(url), window.location.origin);
|
|
36
|
-
const testNames = u.searchParams.get('testNames');
|
|
37
|
-
if (testNames) {
|
|
38
|
-
const name = testNames;
|
|
39
|
-
return { ok: true, json: async () => ({ results: { tests: { [name]: { passed: true, logs: [{ message: `PASS ${name}`, type: 'pass', level: 2 }] } }, beforeAllLogs: [], afterAllLogs: [] } }) };
|
|
40
|
-
}
|
|
41
|
-
// Suite run: both tests pass
|
|
42
|
-
return { ok: true, json: async () => ({ results: { tests: { X: { passed: true, logs: [] }, Y: { passed: true, logs: [] } }, beforeAllLogs: [], afterAllLogs: [] } }) };
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// Enqueue duplicate test; ensure dedupe keeps one queued (status leaves 'notran')
|
|
46
|
-
fw.enqueueTest({ file: suite.file, name: 'X', el: t1 });
|
|
47
|
-
fw.enqueueTest({ file: suite.file, name: 'X', el: t1 });
|
|
48
|
-
await nextTick();
|
|
49
|
-
const queuedOnce = t1.status !== 'notran';
|
|
50
|
-
|
|
51
|
-
// Run individual test via queue processing; wait until it passes
|
|
52
|
-
for (let i=0;i<20 && t1.status !== 'pass'; i++){ await nextTick(); }
|
|
53
|
-
const xPassed = t1.status === 'pass';
|
|
54
|
-
|
|
55
|
-
// Enqueue suite; children should go queued then pass
|
|
56
|
-
fw.enqueueSuite({ file: suite.file, testNames: ['X','Y'], el: suite });
|
|
57
|
-
for (let i=0;i<30 && !(suite.status === 'pass' && t2.status === 'pass'); i++){ await nextTick(); }
|
|
58
|
-
const suiteOk = suite.status === 'pass' && t2.status === 'pass';
|
|
59
|
-
|
|
60
|
-
window.fetch = originalFetch;
|
|
61
|
-
if (queuedOnce && xPassed && suiteOk) pass('TestFramework deduped queue and updated statuses');
|
|
62
|
-
else fail('TestFramework queue or status updates failed');
|
|
63
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
64
|
-
}
|
|
65
|
-
};
|
|
1
|
+
// Browser tests for TestFramework component
|
|
2
|
+
|
|
3
|
+
const nextTick = () => new Promise(r => setTimeout(r));
|
|
4
|
+
|
|
5
|
+
export const beforeEach = async () => {
|
|
6
|
+
document.body.innerHTML = '';
|
|
7
|
+
try { localStorage.removeItem('ktf_settings'); } catch {}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
'TestFramework queues and deduplicates tasks, updates statuses': async ({ pass, fail }) => {
|
|
12
|
+
try {
|
|
13
|
+
await import('/gui/components/settingsStore.js');
|
|
14
|
+
await import('/gui/components/Collapsible.js');
|
|
15
|
+
await import('/gui/components/Logs.js');
|
|
16
|
+
await import('/gui/components/Icon.js');
|
|
17
|
+
await import('/gui/components/Test.js');
|
|
18
|
+
await import('/gui/components/TestSuite.js');
|
|
19
|
+
await import('/gui/components/TestFramework.js');
|
|
20
|
+
|
|
21
|
+
const fw = document.createElement('ktf-test-framework');
|
|
22
|
+
const suite = document.createElement('ktf-test-suite');
|
|
23
|
+
suite.file = 'tests/example.node-test.js';
|
|
24
|
+
suite.testNames = ['X','Y'];
|
|
25
|
+
document.body.appendChild(fw);
|
|
26
|
+
fw.appendChild(suite);
|
|
27
|
+
await nextTick(); await nextTick();
|
|
28
|
+
|
|
29
|
+
const [t1, t2] = suite.querySelectorAll('ktf-test');
|
|
30
|
+
|
|
31
|
+
// Stub fetch to simulate run responses quickly
|
|
32
|
+
const originalFetch = window.fetch;
|
|
33
|
+
window.fetch = async (url) => {
|
|
34
|
+
// Return a minimal results payload depending on testNames query
|
|
35
|
+
const u = new URL(String(url), window.location.origin);
|
|
36
|
+
const testNames = u.searchParams.get('testNames');
|
|
37
|
+
if (testNames) {
|
|
38
|
+
const name = testNames;
|
|
39
|
+
return { ok: true, json: async () => ({ results: { tests: { [name]: { passed: true, logs: [{ message: `PASS ${name}`, type: 'pass', level: 2 }] } }, beforeAllLogs: [], afterAllLogs: [] } }) };
|
|
40
|
+
}
|
|
41
|
+
// Suite run: both tests pass
|
|
42
|
+
return { ok: true, json: async () => ({ results: { tests: { X: { passed: true, logs: [] }, Y: { passed: true, logs: [] } }, beforeAllLogs: [], afterAllLogs: [] } }) };
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Enqueue duplicate test; ensure dedupe keeps one queued (status leaves 'notran')
|
|
46
|
+
fw.enqueueTest({ file: suite.file, name: 'X', el: t1 });
|
|
47
|
+
fw.enqueueTest({ file: suite.file, name: 'X', el: t1 });
|
|
48
|
+
await nextTick();
|
|
49
|
+
const queuedOnce = t1.status !== 'notran';
|
|
50
|
+
|
|
51
|
+
// Run individual test via queue processing; wait until it passes
|
|
52
|
+
for (let i=0;i<20 && t1.status !== 'pass'; i++){ await nextTick(); }
|
|
53
|
+
const xPassed = t1.status === 'pass';
|
|
54
|
+
|
|
55
|
+
// Enqueue suite; children should go queued then pass
|
|
56
|
+
fw.enqueueSuite({ file: suite.file, testNames: ['X','Y'], el: suite });
|
|
57
|
+
for (let i=0;i<30 && !(suite.status === 'pass' && t2.status === 'pass'); i++){ await nextTick(); }
|
|
58
|
+
const suiteOk = suite.status === 'pass' && t2.status === 'pass';
|
|
59
|
+
|
|
60
|
+
window.fetch = originalFetch;
|
|
61
|
+
if (queuedOnce && xPassed && suiteOk) pass('TestFramework deduped queue and updated statuses');
|
|
62
|
+
else fail('TestFramework queue or status updates failed');
|
|
63
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
64
|
+
}
|
|
65
|
+
};
|
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
// Browser tests for TestSummary component
|
|
2
|
-
|
|
3
|
-
const nextTick = () => new Promise(r => setTimeout(r));
|
|
4
|
-
|
|
5
|
-
export const beforeEach = async () => {
|
|
6
|
-
document.body.innerHTML = '';
|
|
7
|
-
try { localStorage.removeItem('ktf_settings'); } catch {}
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export default {
|
|
11
|
-
'TestSummary initializes counts from child suites and tests': async ({ pass, fail }) => {
|
|
12
|
-
try {
|
|
13
|
-
await import('/gui/components/settingsStore.js');
|
|
14
|
-
await import('/gui/components/Collapsible.js');
|
|
15
|
-
await import('/gui/components/Logs.js');
|
|
16
|
-
await import('/gui/components/Icon.js');
|
|
17
|
-
await import('/gui/components/Test.js');
|
|
18
|
-
await import('/gui/components/TestSuite.js');
|
|
19
|
-
await import('/gui/components/TestSummary.js');
|
|
20
|
-
await import('/gui/components/TestFramework.js');
|
|
21
|
-
|
|
22
|
-
const fw = document.createElement('ktf-test-framework');
|
|
23
|
-
const summary = document.createElement('ktf-test-summary');
|
|
24
|
-
const suite = document.createElement('ktf-test-suite');
|
|
25
|
-
suite.file = 'tests/example.node-test.js';
|
|
26
|
-
suite.testNames = ['A','B'];
|
|
27
|
-
fw.appendChild(summary);
|
|
28
|
-
fw.appendChild(suite);
|
|
29
|
-
document.body.appendChild(fw);
|
|
30
|
-
await nextTick(); await nextTick();
|
|
31
|
-
|
|
32
|
-
const text = summary.shadowRoot.textContent.replace(/\s+/g,' ');
|
|
33
|
-
const filesTotal = /Files[\s\S]*Total:\s*1/.test(text);
|
|
34
|
-
const testsTotal = /Tests[\s\S]*Total:\s*2/.test(text);
|
|
35
|
-
if (filesTotal && testsTotal) pass('TestSummary counted files and tests on init'); else fail(`Counts missing:\n${text}`);
|
|
36
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
'TestSummary updates status, counts, and queue length': async ({ pass, fail }) => {
|
|
40
|
-
try {
|
|
41
|
-
await import('/gui/components/settingsStore.js');
|
|
42
|
-
await import('/gui/components/Collapsible.js');
|
|
43
|
-
await import('/gui/components/Logs.js');
|
|
44
|
-
await import('/gui/components/Icon.js');
|
|
45
|
-
await import('/gui/components/Test.js');
|
|
46
|
-
await import('/gui/components/TestSuite.js');
|
|
47
|
-
await import('/gui/components/TestSummary.js');
|
|
48
|
-
await import('/gui/components/TestFramework.js');
|
|
49
|
-
|
|
50
|
-
const fw = document.createElement('ktf-test-framework');
|
|
51
|
-
const summary = document.createElement('ktf-test-summary');
|
|
52
|
-
const suite = document.createElement('ktf-test-suite');
|
|
53
|
-
suite.file = 'tests/example.node-test.js';
|
|
54
|
-
suite.testNames = ['A','B'];
|
|
55
|
-
fw.appendChild(summary);
|
|
56
|
-
fw.appendChild(suite);
|
|
57
|
-
document.body.appendChild(fw);
|
|
58
|
-
await nextTick(); await nextTick();
|
|
59
|
-
|
|
60
|
-
// Simulate queue updates
|
|
61
|
-
fw.dispatchEvent(new CustomEvent('ktf:queue-updated', { detail: { length: 2 } }));
|
|
62
|
-
await nextTick();
|
|
63
|
-
const queueShown = summary.shadowRoot.textContent.includes('Queue: 2');
|
|
64
|
-
|
|
65
|
-
// Simulate status changes on tests to drive summary
|
|
66
|
-
const [t1, t2] = suite.querySelectorAll('ktf-test');
|
|
67
|
-
t1.status = 'running';
|
|
68
|
-
await nextTick();
|
|
69
|
-
const running = summary.getAttribute('status') === 'running' || summary.status === 'running';
|
|
70
|
-
t1.status = 'pass'; t2.status = 'pass';
|
|
71
|
-
await nextTick(); await nextTick();
|
|
72
|
-
const passOk = summary.getAttribute('status') === 'pass' || summary.status === 'pass';
|
|
73
|
-
|
|
74
|
-
if (queueShown && running && passOk) pass('TestSummary reflected queue and status transitions');
|
|
75
|
-
else fail('TestSummary did not update as expected');
|
|
76
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
77
|
-
}
|
|
78
|
-
};
|
|
1
|
+
// Browser tests for TestSummary component
|
|
2
|
+
|
|
3
|
+
const nextTick = () => new Promise(r => setTimeout(r));
|
|
4
|
+
|
|
5
|
+
export const beforeEach = async () => {
|
|
6
|
+
document.body.innerHTML = '';
|
|
7
|
+
try { localStorage.removeItem('ktf_settings'); } catch {}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
'TestSummary initializes counts from child suites and tests': async ({ pass, fail }) => {
|
|
12
|
+
try {
|
|
13
|
+
await import('/gui/components/settingsStore.js');
|
|
14
|
+
await import('/gui/components/Collapsible.js');
|
|
15
|
+
await import('/gui/components/Logs.js');
|
|
16
|
+
await import('/gui/components/Icon.js');
|
|
17
|
+
await import('/gui/components/Test.js');
|
|
18
|
+
await import('/gui/components/TestSuite.js');
|
|
19
|
+
await import('/gui/components/TestSummary.js');
|
|
20
|
+
await import('/gui/components/TestFramework.js');
|
|
21
|
+
|
|
22
|
+
const fw = document.createElement('ktf-test-framework');
|
|
23
|
+
const summary = document.createElement('ktf-test-summary');
|
|
24
|
+
const suite = document.createElement('ktf-test-suite');
|
|
25
|
+
suite.file = 'tests/example.node-test.js';
|
|
26
|
+
suite.testNames = ['A','B'];
|
|
27
|
+
fw.appendChild(summary);
|
|
28
|
+
fw.appendChild(suite);
|
|
29
|
+
document.body.appendChild(fw);
|
|
30
|
+
await nextTick(); await nextTick();
|
|
31
|
+
|
|
32
|
+
const text = summary.shadowRoot.textContent.replace(/\s+/g,' ');
|
|
33
|
+
const filesTotal = /Files[\s\S]*Total:\s*1/.test(text);
|
|
34
|
+
const testsTotal = /Tests[\s\S]*Total:\s*2/.test(text);
|
|
35
|
+
if (filesTotal && testsTotal) pass('TestSummary counted files and tests on init'); else fail(`Counts missing:\n${text}`);
|
|
36
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
'TestSummary updates status, counts, and queue length': async ({ pass, fail }) => {
|
|
40
|
+
try {
|
|
41
|
+
await import('/gui/components/settingsStore.js');
|
|
42
|
+
await import('/gui/components/Collapsible.js');
|
|
43
|
+
await import('/gui/components/Logs.js');
|
|
44
|
+
await import('/gui/components/Icon.js');
|
|
45
|
+
await import('/gui/components/Test.js');
|
|
46
|
+
await import('/gui/components/TestSuite.js');
|
|
47
|
+
await import('/gui/components/TestSummary.js');
|
|
48
|
+
await import('/gui/components/TestFramework.js');
|
|
49
|
+
|
|
50
|
+
const fw = document.createElement('ktf-test-framework');
|
|
51
|
+
const summary = document.createElement('ktf-test-summary');
|
|
52
|
+
const suite = document.createElement('ktf-test-suite');
|
|
53
|
+
suite.file = 'tests/example.node-test.js';
|
|
54
|
+
suite.testNames = ['A','B'];
|
|
55
|
+
fw.appendChild(summary);
|
|
56
|
+
fw.appendChild(suite);
|
|
57
|
+
document.body.appendChild(fw);
|
|
58
|
+
await nextTick(); await nextTick();
|
|
59
|
+
|
|
60
|
+
// Simulate queue updates
|
|
61
|
+
fw.dispatchEvent(new CustomEvent('ktf:queue-updated', { detail: { length: 2 } }));
|
|
62
|
+
await nextTick();
|
|
63
|
+
const queueShown = summary.shadowRoot.textContent.includes('Queue: 2');
|
|
64
|
+
|
|
65
|
+
// Simulate status changes on tests to drive summary
|
|
66
|
+
const [t1, t2] = suite.querySelectorAll('ktf-test');
|
|
67
|
+
t1.status = 'running';
|
|
68
|
+
await nextTick();
|
|
69
|
+
const running = summary.getAttribute('status') === 'running' || summary.status === 'running';
|
|
70
|
+
t1.status = 'pass'; t2.status = 'pass';
|
|
71
|
+
await nextTick(); await nextTick();
|
|
72
|
+
const passOk = summary.getAttribute('status') === 'pass' || summary.status === 'pass';
|
|
73
|
+
|
|
74
|
+
if (queueShown && running && passOk) pass('TestSummary reflected queue and status transitions');
|
|
75
|
+
else fail('TestSummary did not update as expected');
|
|
76
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
77
|
+
}
|
|
78
|
+
};
|
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
// Browser tests for Test component
|
|
2
|
-
|
|
3
|
-
const nextTick = () => new Promise(r => setTimeout(r));
|
|
4
|
-
|
|
5
|
-
export const beforeEach = async () => {
|
|
6
|
-
document.body.innerHTML = '';
|
|
7
|
-
try { localStorage.removeItem('ktf_settings'); } catch {}
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export default {
|
|
11
|
-
'Test renders and shows play icon before run': async ({ pass, fail }) => {
|
|
12
|
-
try {
|
|
13
|
-
await import('/gui/components/settingsStore.js');
|
|
14
|
-
await import('/gui/components/Collapsible.js');
|
|
15
|
-
await import('/gui/components/Logs.js');
|
|
16
|
-
await import('/gui/components/Icon.js');
|
|
17
|
-
await import('/gui/components/Test.js');
|
|
18
|
-
|
|
19
|
-
const t = document.createElement('ktf-test');
|
|
20
|
-
t.name = 'Sample Test';
|
|
21
|
-
t.file = 'tests/example.node-test.js';
|
|
22
|
-
document.body.appendChild(t);
|
|
23
|
-
await nextTick();
|
|
24
|
-
|
|
25
|
-
const hasPlay = !!t.shadowRoot.querySelector('div[slot="actions"] ktf-icon[name="play"]');
|
|
26
|
-
if (hasPlay) pass('Test component renders with initial play icon'); else fail('Missing play icon on Test component');
|
|
27
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
'Test status updates through running/pass/fail': async ({ pass, fail }) => {
|
|
31
|
-
try {
|
|
32
|
-
await import('/gui/components/settingsStore.js');
|
|
33
|
-
await import('/gui/components/Collapsible.js');
|
|
34
|
-
await import('/gui/components/Logs.js');
|
|
35
|
-
await import('/gui/components/Icon.js');
|
|
36
|
-
await import('/gui/components/Test.js');
|
|
37
|
-
|
|
38
|
-
const t = document.createElement('ktf-test');
|
|
39
|
-
t.name = 'Sample Test';
|
|
40
|
-
t.file = 'tests/example.node-test.js';
|
|
41
|
-
document.body.appendChild(t);
|
|
42
|
-
await nextTick();
|
|
43
|
-
|
|
44
|
-
t.status = 'running';
|
|
45
|
-
await nextTick();
|
|
46
|
-
const running = t.getAttribute('status') === 'running' || t.status === 'running';
|
|
47
|
-
t.status = 'pass';
|
|
48
|
-
await nextTick();
|
|
49
|
-
const passOk = t.getAttribute('status') === 'pass' || t.status === 'pass';
|
|
50
|
-
t.status = 'fail';
|
|
51
|
-
await nextTick();
|
|
52
|
-
const failOk = t.getAttribute('status') === 'fail' || t.status === 'fail';
|
|
53
|
-
if (running && passOk && failOk) pass('Test component reflected status transitions running→pass→fail'); else fail('Status transitions failed to reflect on Test');
|
|
54
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
55
|
-
}
|
|
56
|
-
};
|
|
1
|
+
// Browser tests for Test component
|
|
2
|
+
|
|
3
|
+
const nextTick = () => new Promise(r => setTimeout(r));
|
|
4
|
+
|
|
5
|
+
export const beforeEach = async () => {
|
|
6
|
+
document.body.innerHTML = '';
|
|
7
|
+
try { localStorage.removeItem('ktf_settings'); } catch {}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
'Test renders and shows play icon before run': async ({ pass, fail }) => {
|
|
12
|
+
try {
|
|
13
|
+
await import('/gui/components/settingsStore.js');
|
|
14
|
+
await import('/gui/components/Collapsible.js');
|
|
15
|
+
await import('/gui/components/Logs.js');
|
|
16
|
+
await import('/gui/components/Icon.js');
|
|
17
|
+
await import('/gui/components/Test.js');
|
|
18
|
+
|
|
19
|
+
const t = document.createElement('ktf-test');
|
|
20
|
+
t.name = 'Sample Test';
|
|
21
|
+
t.file = 'tests/example.node-test.js';
|
|
22
|
+
document.body.appendChild(t);
|
|
23
|
+
await nextTick();
|
|
24
|
+
|
|
25
|
+
const hasPlay = !!t.shadowRoot.querySelector('div[slot="actions"] ktf-icon[name="play"]');
|
|
26
|
+
if (hasPlay) pass('Test component renders with initial play icon'); else fail('Missing play icon on Test component');
|
|
27
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
'Test status updates through running/pass/fail': async ({ pass, fail }) => {
|
|
31
|
+
try {
|
|
32
|
+
await import('/gui/components/settingsStore.js');
|
|
33
|
+
await import('/gui/components/Collapsible.js');
|
|
34
|
+
await import('/gui/components/Logs.js');
|
|
35
|
+
await import('/gui/components/Icon.js');
|
|
36
|
+
await import('/gui/components/Test.js');
|
|
37
|
+
|
|
38
|
+
const t = document.createElement('ktf-test');
|
|
39
|
+
t.name = 'Sample Test';
|
|
40
|
+
t.file = 'tests/example.node-test.js';
|
|
41
|
+
document.body.appendChild(t);
|
|
42
|
+
await nextTick();
|
|
43
|
+
|
|
44
|
+
t.status = 'running';
|
|
45
|
+
await nextTick();
|
|
46
|
+
const running = t.getAttribute('status') === 'running' || t.status === 'running';
|
|
47
|
+
t.status = 'pass';
|
|
48
|
+
await nextTick();
|
|
49
|
+
const passOk = t.getAttribute('status') === 'pass' || t.status === 'pass';
|
|
50
|
+
t.status = 'fail';
|
|
51
|
+
await nextTick();
|
|
52
|
+
const failOk = t.getAttribute('status') === 'fail' || t.status === 'fail';
|
|
53
|
+
if (running && passOk && failOk) pass('Test component reflected status transitions running→pass→fail'); else fail('Status transitions failed to reflect on Test');
|
|
54
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
55
|
+
}
|
|
56
|
+
};
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
// Browser tests for TestSuite component
|
|
2
|
-
|
|
3
|
-
const nextTick = () => new Promise(r => setTimeout(r));
|
|
4
|
-
|
|
5
|
-
export const beforeEach = async () => {
|
|
6
|
-
document.body.innerHTML = '';
|
|
7
|
-
try { localStorage.removeItem('ktf_settings'); } catch {}
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export default {
|
|
11
|
-
'TestSuite renders children and initial play icon': async ({ pass, fail }) => {
|
|
12
|
-
try {
|
|
13
|
-
await import('/gui/components/settingsStore.js');
|
|
14
|
-
await import('/gui/components/Collapsible.js');
|
|
15
|
-
await import('/gui/components/Logs.js');
|
|
16
|
-
await import('/gui/components/Icon.js');
|
|
17
|
-
await import('/gui/components/Test.js');
|
|
18
|
-
await import('/gui/components/TestSuite.js');
|
|
19
|
-
|
|
20
|
-
const tf = document.createElement('ktf-test-suite');
|
|
21
|
-
tf.file = 'tests/example.node-test.js';
|
|
22
|
-
tf.testNames = ['A', 'B'];
|
|
23
|
-
document.body.appendChild(tf);
|
|
24
|
-
await nextTick(); await nextTick();
|
|
25
|
-
|
|
26
|
-
const hasPlay = !!tf.shadowRoot.querySelector('div[slot="actions"] ktf-icon[name="play"]');
|
|
27
|
-
if (hasPlay) pass('TestSuite renders children and shows initial play icon'); else fail('Missing play icon on TestSuite');
|
|
28
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
'TestSuite aggregates status from children': async ({ pass, fail }) => {
|
|
32
|
-
try {
|
|
33
|
-
await import('/gui/components/settingsStore.js');
|
|
34
|
-
await import('/gui/components/Collapsible.js');
|
|
35
|
-
await import('/gui/components/Logs.js');
|
|
36
|
-
await import('/gui/components/Icon.js');
|
|
37
|
-
await import('/gui/components/Test.js');
|
|
38
|
-
await import('/gui/components/TestSuite.js');
|
|
39
|
-
|
|
40
|
-
const tf = document.createElement('ktf-test-suite');
|
|
41
|
-
tf.file = 'tests/example.node-test.js';
|
|
42
|
-
tf.testNames = ['A', 'B'];
|
|
43
|
-
document.body.appendChild(tf);
|
|
44
|
-
await nextTick(); await nextTick();
|
|
45
|
-
|
|
46
|
-
const children = tf.querySelectorAll('ktf-test');
|
|
47
|
-
children[0].status = 'running';
|
|
48
|
-
await nextTick();
|
|
49
|
-
const statusRunning = tf.getAttribute('status') === 'running' || tf.status === 'running';
|
|
50
|
-
children[0].status = 'pass';
|
|
51
|
-
children[1].status = 'fail';
|
|
52
|
-
await nextTick();
|
|
53
|
-
const statusFail = tf.getAttribute('status') === 'fail' || tf.status === 'fail';
|
|
54
|
-
children[1].status = 'pass';
|
|
55
|
-
await nextTick();
|
|
56
|
-
const statusPass = tf.getAttribute('status') === 'pass' || tf.status === 'pass';
|
|
57
|
-
if (statusRunning && statusFail && statusPass) pass('TestSuite aggregated status from children correctly'); else fail('Status propagation failed on TestSuite');
|
|
58
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
59
|
-
}
|
|
60
|
-
};
|
|
1
|
+
// Browser tests for TestSuite component
|
|
2
|
+
|
|
3
|
+
const nextTick = () => new Promise(r => setTimeout(r));
|
|
4
|
+
|
|
5
|
+
export const beforeEach = async () => {
|
|
6
|
+
document.body.innerHTML = '';
|
|
7
|
+
try { localStorage.removeItem('ktf_settings'); } catch {}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
'TestSuite renders children and initial play icon': async ({ pass, fail }) => {
|
|
12
|
+
try {
|
|
13
|
+
await import('/gui/components/settingsStore.js');
|
|
14
|
+
await import('/gui/components/Collapsible.js');
|
|
15
|
+
await import('/gui/components/Logs.js');
|
|
16
|
+
await import('/gui/components/Icon.js');
|
|
17
|
+
await import('/gui/components/Test.js');
|
|
18
|
+
await import('/gui/components/TestSuite.js');
|
|
19
|
+
|
|
20
|
+
const tf = document.createElement('ktf-test-suite');
|
|
21
|
+
tf.file = 'tests/example.node-test.js';
|
|
22
|
+
tf.testNames = ['A', 'B'];
|
|
23
|
+
document.body.appendChild(tf);
|
|
24
|
+
await nextTick(); await nextTick();
|
|
25
|
+
|
|
26
|
+
const hasPlay = !!tf.shadowRoot.querySelector('div[slot="actions"] ktf-icon[name="play"]');
|
|
27
|
+
if (hasPlay) pass('TestSuite renders children and shows initial play icon'); else fail('Missing play icon on TestSuite');
|
|
28
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
'TestSuite aggregates status from children': async ({ pass, fail }) => {
|
|
32
|
+
try {
|
|
33
|
+
await import('/gui/components/settingsStore.js');
|
|
34
|
+
await import('/gui/components/Collapsible.js');
|
|
35
|
+
await import('/gui/components/Logs.js');
|
|
36
|
+
await import('/gui/components/Icon.js');
|
|
37
|
+
await import('/gui/components/Test.js');
|
|
38
|
+
await import('/gui/components/TestSuite.js');
|
|
39
|
+
|
|
40
|
+
const tf = document.createElement('ktf-test-suite');
|
|
41
|
+
tf.file = 'tests/example.node-test.js';
|
|
42
|
+
tf.testNames = ['A', 'B'];
|
|
43
|
+
document.body.appendChild(tf);
|
|
44
|
+
await nextTick(); await nextTick();
|
|
45
|
+
|
|
46
|
+
const children = tf.querySelectorAll('ktf-test');
|
|
47
|
+
children[0].status = 'running';
|
|
48
|
+
await nextTick();
|
|
49
|
+
const statusRunning = tf.getAttribute('status') === 'running' || tf.status === 'running';
|
|
50
|
+
children[0].status = 'pass';
|
|
51
|
+
children[1].status = 'fail';
|
|
52
|
+
await nextTick();
|
|
53
|
+
const statusFail = tf.getAttribute('status') === 'fail' || tf.status === 'fail';
|
|
54
|
+
children[1].status = 'pass';
|
|
55
|
+
await nextTick();
|
|
56
|
+
const statusPass = tf.getAttribute('status') === 'pass' || tf.status === 'pass';
|
|
57
|
+
if (statusRunning && statusFail && statusPass) pass('TestSuite aggregated status from children correctly'); else fail('Status propagation failed on TestSuite');
|
|
58
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
59
|
+
}
|
|
60
|
+
};
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
// Browser tests for Theme component
|
|
2
|
-
|
|
3
|
-
const nextTick = () => new Promise(r => setTimeout(r));
|
|
4
|
-
|
|
5
|
-
export const beforeEach = async () => {
|
|
6
|
-
document.body.innerHTML = '';
|
|
7
|
-
try { localStorage.removeItem('ktf_settings'); } catch {}
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export default {
|
|
11
|
-
'Theme applies document theme on settings change': async ({ pass, fail }) => {
|
|
12
|
-
try {
|
|
13
|
-
await import('/gui/components/settingsStore.js');
|
|
14
|
-
await import('/gui/components/Theme.js');
|
|
15
|
-
const el = document.createElement('ktf-theme');
|
|
16
|
-
document.body.appendChild(el);
|
|
17
|
-
await nextTick();
|
|
18
|
-
window.KTF_SETTINGS.set({ theme: 'dark' });
|
|
19
|
-
await nextTick();
|
|
20
|
-
const themeAttr = document.documentElement.getAttribute('theme');
|
|
21
|
-
if (themeAttr === 'dark') pass('Theme component applied document theme to dark'); else fail(`Theme not applied: ${themeAttr}`);
|
|
22
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
'Theme switches back to light': async ({ pass, fail }) => {
|
|
26
|
-
try {
|
|
27
|
-
await import('/gui/components/settingsStore.js');
|
|
28
|
-
await import('/gui/components/Theme.js');
|
|
29
|
-
const el = document.createElement('ktf-theme');
|
|
30
|
-
document.body.appendChild(el);
|
|
31
|
-
await nextTick();
|
|
32
|
-
window.KTF_SETTINGS.set({ theme: 'light' });
|
|
33
|
-
await nextTick();
|
|
34
|
-
const themeAttr = document.documentElement.getAttribute('theme');
|
|
35
|
-
if (themeAttr === 'light') pass('Theme component applied document theme back to light'); else fail(`Theme not applied: ${themeAttr}`);
|
|
36
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
37
|
-
}
|
|
38
|
-
};
|
|
1
|
+
// Browser tests for Theme component
|
|
2
|
+
|
|
3
|
+
const nextTick = () => new Promise(r => setTimeout(r));
|
|
4
|
+
|
|
5
|
+
export const beforeEach = async () => {
|
|
6
|
+
document.body.innerHTML = '';
|
|
7
|
+
try { localStorage.removeItem('ktf_settings'); } catch {}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
'Theme applies document theme on settings change': async ({ pass, fail }) => {
|
|
12
|
+
try {
|
|
13
|
+
await import('/gui/components/settingsStore.js');
|
|
14
|
+
await import('/gui/components/Theme.js');
|
|
15
|
+
const el = document.createElement('ktf-theme');
|
|
16
|
+
document.body.appendChild(el);
|
|
17
|
+
await nextTick();
|
|
18
|
+
window.KTF_SETTINGS.set({ theme: 'dark' });
|
|
19
|
+
await nextTick();
|
|
20
|
+
const themeAttr = document.documentElement.getAttribute('theme');
|
|
21
|
+
if (themeAttr === 'dark') pass('Theme component applied document theme to dark'); else fail(`Theme not applied: ${themeAttr}`);
|
|
22
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
'Theme switches back to light': async ({ pass, fail }) => {
|
|
26
|
+
try {
|
|
27
|
+
await import('/gui/components/settingsStore.js');
|
|
28
|
+
await import('/gui/components/Theme.js');
|
|
29
|
+
const el = document.createElement('ktf-theme');
|
|
30
|
+
document.body.appendChild(el);
|
|
31
|
+
await nextTick();
|
|
32
|
+
window.KTF_SETTINGS.set({ theme: 'light' });
|
|
33
|
+
await nextTick();
|
|
34
|
+
const themeAttr = document.documentElement.getAttribute('theme');
|
|
35
|
+
if (themeAttr === 'light') pass('Theme component applied document theme back to light'); else fail(`Theme not applied: ${themeAttr}`);
|
|
36
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
37
|
+
}
|
|
38
|
+
};
|