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.
- package/.github/copilot-instructions.md +105 -105
- package/.github/workflows/publish-npm.yml +29 -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/Test.js +1 -1
- 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/gui/index.html +1 -1
- package/package.json +7 -2
- package/src/browserTestServer.js +115 -115
- package/src/cli.js +198 -198
- package/src/gui.js +17 -4
- 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,54 +1,54 @@
|
|
|
1
|
-
// Browser tests for Icon 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
|
-
'Icon loads via fetch and caches results': async ({ pass, fail, log }) => {
|
|
12
|
-
try {
|
|
13
|
-
await import('/gui/components/Icon.js');
|
|
14
|
-
const originalFetch = window.fetch;
|
|
15
|
-
let calls = 0;
|
|
16
|
-
window.fetch = async (url) => {
|
|
17
|
-
calls++;
|
|
18
|
-
if (String(url).endsWith('/icons/test.svg')) {
|
|
19
|
-
return { ok: true, text: async () => '<svg><g id="ok"/></svg>' };
|
|
20
|
-
}
|
|
21
|
-
return { ok: false, text: async () => '' };
|
|
22
|
-
};
|
|
23
|
-
const a = document.createElement('ktf-icon');
|
|
24
|
-
a.name = 'test';
|
|
25
|
-
document.body.appendChild(a);
|
|
26
|
-
await nextTick(); await nextTick();
|
|
27
|
-
const firstLoaded = a.shadowRoot.innerHTML.includes('id="ok"');
|
|
28
|
-
log(`Network calls after first icon: ${calls}`);
|
|
29
|
-
window.fetch = async () => { throw new Error('blocked'); };
|
|
30
|
-
const b = document.createElement('ktf-icon');
|
|
31
|
-
b.name = 'test';
|
|
32
|
-
document.body.appendChild(b);
|
|
33
|
-
await nextTick(); await nextTick();
|
|
34
|
-
const secondLoaded = b.shadowRoot.innerHTML.includes('id="ok"');
|
|
35
|
-
window.fetch = originalFetch;
|
|
36
|
-
if (firstLoaded && secondLoaded) pass('Icon fetched once and loaded cached SVG subsequently'); else fail('Icon did not cache/fetch as expected');
|
|
37
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
38
|
-
},
|
|
39
|
-
|
|
40
|
-
'Icon falls back when fetch fails': async ({ pass, fail }) => {
|
|
41
|
-
try {
|
|
42
|
-
await import('/gui/components/Icon.js');
|
|
43
|
-
const originalFetch = window.fetch;
|
|
44
|
-
window.fetch = async () => ({ ok: false, text: async () => '' });
|
|
45
|
-
const a = document.createElement('ktf-icon');
|
|
46
|
-
a.name = 'does-not-exist';
|
|
47
|
-
document.body.appendChild(a);
|
|
48
|
-
await nextTick(); await nextTick();
|
|
49
|
-
const hasSvg = a.shadowRoot.innerHTML.includes('<svg');
|
|
50
|
-
window.fetch = originalFetch;
|
|
51
|
-
if (hasSvg) pass('Fallback SVG rendered when fetch failed'); else fail('Fallback SVG missing when fetch failed');
|
|
52
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
53
|
-
}
|
|
54
|
-
};
|
|
1
|
+
// Browser tests for Icon 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
|
+
'Icon loads via fetch and caches results': async ({ pass, fail, log }) => {
|
|
12
|
+
try {
|
|
13
|
+
await import('/gui/components/Icon.js');
|
|
14
|
+
const originalFetch = window.fetch;
|
|
15
|
+
let calls = 0;
|
|
16
|
+
window.fetch = async (url) => {
|
|
17
|
+
calls++;
|
|
18
|
+
if (String(url).endsWith('/icons/test.svg')) {
|
|
19
|
+
return { ok: true, text: async () => '<svg><g id="ok"/></svg>' };
|
|
20
|
+
}
|
|
21
|
+
return { ok: false, text: async () => '' };
|
|
22
|
+
};
|
|
23
|
+
const a = document.createElement('ktf-icon');
|
|
24
|
+
a.name = 'test';
|
|
25
|
+
document.body.appendChild(a);
|
|
26
|
+
await nextTick(); await nextTick();
|
|
27
|
+
const firstLoaded = a.shadowRoot.innerHTML.includes('id="ok"');
|
|
28
|
+
log(`Network calls after first icon: ${calls}`);
|
|
29
|
+
window.fetch = async () => { throw new Error('blocked'); };
|
|
30
|
+
const b = document.createElement('ktf-icon');
|
|
31
|
+
b.name = 'test';
|
|
32
|
+
document.body.appendChild(b);
|
|
33
|
+
await nextTick(); await nextTick();
|
|
34
|
+
const secondLoaded = b.shadowRoot.innerHTML.includes('id="ok"');
|
|
35
|
+
window.fetch = originalFetch;
|
|
36
|
+
if (firstLoaded && secondLoaded) pass('Icon fetched once and loaded cached SVG subsequently'); else fail('Icon did not cache/fetch as expected');
|
|
37
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
'Icon falls back when fetch fails': async ({ pass, fail }) => {
|
|
41
|
+
try {
|
|
42
|
+
await import('/gui/components/Icon.js');
|
|
43
|
+
const originalFetch = window.fetch;
|
|
44
|
+
window.fetch = async () => ({ ok: false, text: async () => '' });
|
|
45
|
+
const a = document.createElement('ktf-icon');
|
|
46
|
+
a.name = 'does-not-exist';
|
|
47
|
+
document.body.appendChild(a);
|
|
48
|
+
await nextTick(); await nextTick();
|
|
49
|
+
const hasSvg = a.shadowRoot.innerHTML.includes('<svg');
|
|
50
|
+
window.fetch = originalFetch;
|
|
51
|
+
if (hasSvg) pass('Fallback SVG rendered when fetch failed'); else fail('Fallback SVG missing when fetch failed');
|
|
52
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
53
|
+
}
|
|
54
|
+
};
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
// Browser tests for Logs 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
|
-
'Logs filters by level and reacts to settings changes': async ({ pass, fail, log }) => {
|
|
12
|
-
try {
|
|
13
|
-
const { set: setSettings } = (await import('/gui/components/settingsStore.js')).default?.KTF_SETTINGS || window.KTF_SETTINGS || { set: () => {} };
|
|
14
|
-
await import('/gui/components/Logs.js');
|
|
15
|
-
const logs = document.createElement('ktf-logs');
|
|
16
|
-
document.body.appendChild(logs);
|
|
17
|
-
await nextTick();
|
|
18
|
-
logs.addLog({ message: 'L0', level: 0 }, { message: 'L2', level: 2 }, { message: 'L4', level: 4 });
|
|
19
|
-
await nextTick();
|
|
20
|
-
const text1 = logs.shadowRoot.textContent;
|
|
21
|
-
const cond1 = text1.includes('L0') && text1.includes('L2') && !text1.includes('L4');
|
|
22
|
-
log(`Initial filter text: ${text1.replace(/\s+/g,' ').trim()}`);
|
|
23
|
-
window.KTF_SETTINGS.set({ logLevel: 4 });
|
|
24
|
-
await nextTick();
|
|
25
|
-
const text2 = logs.shadowRoot.textContent;
|
|
26
|
-
const cond2 = text2.includes('L4');
|
|
27
|
-
if (cond1 && cond2) pass('Logs filtered by level and reacted to settings change'); else fail('Filtering by level or settings reaction failed');
|
|
28
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
'Logs clear removes previous entries': async ({ pass, fail, log }) => {
|
|
32
|
-
try {
|
|
33
|
-
await import('/gui/components/Logs.js');
|
|
34
|
-
const logs = document.createElement('ktf-logs');
|
|
35
|
-
document.body.appendChild(logs);
|
|
36
|
-
await nextTick();
|
|
37
|
-
logs.addLog({ message: 'A', level: 2 }, { message: 'B', level: 2 });
|
|
38
|
-
await nextTick();
|
|
39
|
-
const before = logs.shadowRoot.textContent.includes('A') && logs.shadowRoot.textContent.includes('B');
|
|
40
|
-
logs.clear();
|
|
41
|
-
await nextTick();
|
|
42
|
-
const after = logs.shadowRoot.textContent.trim().length === 0 || !logs.shadowRoot.textContent.includes('A');
|
|
43
|
-
log(`Before clear contained A/B: ${before}, after clear emptyish: ${after}`);
|
|
44
|
-
if (before && after) pass('Logs.clear() removed previous entries'); else fail('clear did not remove entries');
|
|
45
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
46
|
-
}
|
|
47
|
-
};
|
|
1
|
+
// Browser tests for Logs 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
|
+
'Logs filters by level and reacts to settings changes': async ({ pass, fail, log }) => {
|
|
12
|
+
try {
|
|
13
|
+
const { set: setSettings } = (await import('/gui/components/settingsStore.js')).default?.KTF_SETTINGS || window.KTF_SETTINGS || { set: () => {} };
|
|
14
|
+
await import('/gui/components/Logs.js');
|
|
15
|
+
const logs = document.createElement('ktf-logs');
|
|
16
|
+
document.body.appendChild(logs);
|
|
17
|
+
await nextTick();
|
|
18
|
+
logs.addLog({ message: 'L0', level: 0 }, { message: 'L2', level: 2 }, { message: 'L4', level: 4 });
|
|
19
|
+
await nextTick();
|
|
20
|
+
const text1 = logs.shadowRoot.textContent;
|
|
21
|
+
const cond1 = text1.includes('L0') && text1.includes('L2') && !text1.includes('L4');
|
|
22
|
+
log(`Initial filter text: ${text1.replace(/\s+/g,' ').trim()}`);
|
|
23
|
+
window.KTF_SETTINGS.set({ logLevel: 4 });
|
|
24
|
+
await nextTick();
|
|
25
|
+
const text2 = logs.shadowRoot.textContent;
|
|
26
|
+
const cond2 = text2.includes('L4');
|
|
27
|
+
if (cond1 && cond2) pass('Logs filtered by level and reacted to settings change'); else fail('Filtering by level or settings reaction failed');
|
|
28
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
'Logs clear removes previous entries': async ({ pass, fail, log }) => {
|
|
32
|
+
try {
|
|
33
|
+
await import('/gui/components/Logs.js');
|
|
34
|
+
const logs = document.createElement('ktf-logs');
|
|
35
|
+
document.body.appendChild(logs);
|
|
36
|
+
await nextTick();
|
|
37
|
+
logs.addLog({ message: 'A', level: 2 }, { message: 'B', level: 2 });
|
|
38
|
+
await nextTick();
|
|
39
|
+
const before = logs.shadowRoot.textContent.includes('A') && logs.shadowRoot.textContent.includes('B');
|
|
40
|
+
logs.clear();
|
|
41
|
+
await nextTick();
|
|
42
|
+
const after = logs.shadowRoot.textContent.trim().length === 0 || !logs.shadowRoot.textContent.includes('A');
|
|
43
|
+
log(`Before clear contained A/B: ${before}, after clear emptyish: ${after}`);
|
|
44
|
+
if (before && after) pass('Logs.clear() removed previous entries'); else fail('clear did not remove entries');
|
|
45
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
46
|
+
}
|
|
47
|
+
};
|
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
// Browser tests for SettingCheckbox 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
|
-
'SettingCheckbox reflects and updates settings': async ({ pass, fail, log }) => {
|
|
12
|
-
try {
|
|
13
|
-
await import('/gui/components/settingsStore.js');
|
|
14
|
-
await import('/gui/components/SettingCheckbox.js');
|
|
15
|
-
window.KTF_SETTINGS.set({ showBrowser: false });
|
|
16
|
-
const el = document.createElement('ktf-setting-checkbox');
|
|
17
|
-
el.name = 'showBrowser';
|
|
18
|
-
el.label = 'Show Browser';
|
|
19
|
-
document.body.appendChild(el);
|
|
20
|
-
await nextTick();
|
|
21
|
-
const input = el.querySelector('input[type="checkbox"]');
|
|
22
|
-
const before = input.checked === false;
|
|
23
|
-
input.checked = true; input.dispatchEvent(new Event('change'));
|
|
24
|
-
await nextTick();
|
|
25
|
-
const after = window.KTF_SETTINGS.get().showBrowser === true;
|
|
26
|
-
log(`Checkbox before:${before} after:${after}`);
|
|
27
|
-
if (before && after) pass('SettingCheckbox updated setting from false to true'); else fail('SettingCheckbox did not update setting');
|
|
28
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
'SettingCheckbox unchecks updates back to false': async ({ pass, fail, log }) => {
|
|
32
|
-
try {
|
|
33
|
-
await import('/gui/components/settingsStore.js');
|
|
34
|
-
await import('/gui/components/SettingCheckbox.js');
|
|
35
|
-
window.KTF_SETTINGS.set({ showBrowser: true });
|
|
36
|
-
const el = document.createElement('ktf-setting-checkbox');
|
|
37
|
-
el.name = 'showBrowser';
|
|
38
|
-
document.body.appendChild(el);
|
|
39
|
-
await nextTick();
|
|
40
|
-
const input = el.querySelector('input[type="checkbox"]');
|
|
41
|
-
input.checked = false; input.dispatchEvent(new Event('change'));
|
|
42
|
-
await nextTick();
|
|
43
|
-
const after = window.KTF_SETTINGS.get().showBrowser === false;
|
|
44
|
-
log(`Setting after uncheck:${after}`);
|
|
45
|
-
if (after) pass('SettingCheckbox updated setting back to false'); else fail('Uncheck did not update setting');
|
|
46
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
47
|
-
}
|
|
48
|
-
};
|
|
1
|
+
// Browser tests for SettingCheckbox 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
|
+
'SettingCheckbox reflects and updates settings': async ({ pass, fail, log }) => {
|
|
12
|
+
try {
|
|
13
|
+
await import('/gui/components/settingsStore.js');
|
|
14
|
+
await import('/gui/components/SettingCheckbox.js');
|
|
15
|
+
window.KTF_SETTINGS.set({ showBrowser: false });
|
|
16
|
+
const el = document.createElement('ktf-setting-checkbox');
|
|
17
|
+
el.name = 'showBrowser';
|
|
18
|
+
el.label = 'Show Browser';
|
|
19
|
+
document.body.appendChild(el);
|
|
20
|
+
await nextTick();
|
|
21
|
+
const input = el.querySelector('input[type="checkbox"]');
|
|
22
|
+
const before = input.checked === false;
|
|
23
|
+
input.checked = true; input.dispatchEvent(new Event('change'));
|
|
24
|
+
await nextTick();
|
|
25
|
+
const after = window.KTF_SETTINGS.get().showBrowser === true;
|
|
26
|
+
log(`Checkbox before:${before} after:${after}`);
|
|
27
|
+
if (before && after) pass('SettingCheckbox updated setting from false to true'); else fail('SettingCheckbox did not update setting');
|
|
28
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
'SettingCheckbox unchecks updates back to false': async ({ pass, fail, log }) => {
|
|
32
|
+
try {
|
|
33
|
+
await import('/gui/components/settingsStore.js');
|
|
34
|
+
await import('/gui/components/SettingCheckbox.js');
|
|
35
|
+
window.KTF_SETTINGS.set({ showBrowser: true });
|
|
36
|
+
const el = document.createElement('ktf-setting-checkbox');
|
|
37
|
+
el.name = 'showBrowser';
|
|
38
|
+
document.body.appendChild(el);
|
|
39
|
+
await nextTick();
|
|
40
|
+
const input = el.querySelector('input[type="checkbox"]');
|
|
41
|
+
input.checked = false; input.dispatchEvent(new Event('change'));
|
|
42
|
+
await nextTick();
|
|
43
|
+
const after = window.KTF_SETTINGS.get().showBrowser === false;
|
|
44
|
+
log(`Setting after uncheck:${after}`);
|
|
45
|
+
if (after) pass('SettingCheckbox updated setting back to false'); else fail('Uncheck did not update setting');
|
|
46
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
47
|
+
}
|
|
48
|
+
};
|
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
// Browser tests for SettingNumber 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
|
-
'SettingNumber reflects and updates settings with clamping': async ({ pass, fail, log }) => {
|
|
12
|
-
try {
|
|
13
|
-
const store = await import('/gui/components/settingsStore.js');
|
|
14
|
-
await import('/gui/components/SettingNumber.js');
|
|
15
|
-
store.setSettings({ delayMs: 500 });
|
|
16
|
-
const el = document.createElement('ktf-setting-number');
|
|
17
|
-
el.name = 'delayMs';
|
|
18
|
-
el.label = 'Delay';
|
|
19
|
-
el.min = 0; el.max = 1000; el.step = 100; el.suffix = 'ms';
|
|
20
|
-
document.body.appendChild(el);
|
|
21
|
-
await nextTick();
|
|
22
|
-
const input = el.querySelector('input[type="number"]');
|
|
23
|
-
const before = String(input.value) === '500';
|
|
24
|
-
input.value = '1200'; input.dispatchEvent(new Event('change'));
|
|
25
|
-
await nextTick();
|
|
26
|
-
const clamped = store.getSettings().delayMs === 1000;
|
|
27
|
-
input.value = 'abc'; input.dispatchEvent(new Event('change'));
|
|
28
|
-
await nextTick();
|
|
29
|
-
const nanToZero = store.getSettings().delayMs === 0;
|
|
30
|
-
log(`before:${before} clamped:${clamped} nanToZero:${nanToZero}`);
|
|
31
|
-
if (before && clamped && nanToZero) pass('SettingNumber reflected, clamped, and sanitized values');
|
|
32
|
-
else fail('SettingNumber did not reflect/clamp/sanitize as expected');
|
|
33
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
'SettingNumber input syncs when settings change externally': async ({ pass, fail }) => {
|
|
37
|
-
try {
|
|
38
|
-
const store = await import('/gui/components/settingsStore.js');
|
|
39
|
-
await import('/gui/components/SettingNumber.js');
|
|
40
|
-
store.setSettings({ delayMs: 0 });
|
|
41
|
-
const el = document.createElement('ktf-setting-number');
|
|
42
|
-
el.name = 'delayMs';
|
|
43
|
-
document.body.appendChild(el);
|
|
44
|
-
await nextTick();
|
|
45
|
-
const input = el.querySelector('input[type="number"]');
|
|
46
|
-
const initial = String(input.value) === '0';
|
|
47
|
-
store.setSettings({ delayMs: 250 });
|
|
48
|
-
await nextTick();
|
|
49
|
-
const updated = String(input.value) === '250';
|
|
50
|
-
if (initial && updated) pass('SettingNumber stayed in sync with external setting change');
|
|
51
|
-
else fail('SettingNumber did not sync input after settings change');
|
|
52
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
53
|
-
}
|
|
54
|
-
};
|
|
1
|
+
// Browser tests for SettingNumber 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
|
+
'SettingNumber reflects and updates settings with clamping': async ({ pass, fail, log }) => {
|
|
12
|
+
try {
|
|
13
|
+
const store = await import('/gui/components/settingsStore.js');
|
|
14
|
+
await import('/gui/components/SettingNumber.js');
|
|
15
|
+
store.setSettings({ delayMs: 500 });
|
|
16
|
+
const el = document.createElement('ktf-setting-number');
|
|
17
|
+
el.name = 'delayMs';
|
|
18
|
+
el.label = 'Delay';
|
|
19
|
+
el.min = 0; el.max = 1000; el.step = 100; el.suffix = 'ms';
|
|
20
|
+
document.body.appendChild(el);
|
|
21
|
+
await nextTick();
|
|
22
|
+
const input = el.querySelector('input[type="number"]');
|
|
23
|
+
const before = String(input.value) === '500';
|
|
24
|
+
input.value = '1200'; input.dispatchEvent(new Event('change'));
|
|
25
|
+
await nextTick();
|
|
26
|
+
const clamped = store.getSettings().delayMs === 1000;
|
|
27
|
+
input.value = 'abc'; input.dispatchEvent(new Event('change'));
|
|
28
|
+
await nextTick();
|
|
29
|
+
const nanToZero = store.getSettings().delayMs === 0;
|
|
30
|
+
log(`before:${before} clamped:${clamped} nanToZero:${nanToZero}`);
|
|
31
|
+
if (before && clamped && nanToZero) pass('SettingNumber reflected, clamped, and sanitized values');
|
|
32
|
+
else fail('SettingNumber did not reflect/clamp/sanitize as expected');
|
|
33
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
'SettingNumber input syncs when settings change externally': async ({ pass, fail }) => {
|
|
37
|
+
try {
|
|
38
|
+
const store = await import('/gui/components/settingsStore.js');
|
|
39
|
+
await import('/gui/components/SettingNumber.js');
|
|
40
|
+
store.setSettings({ delayMs: 0 });
|
|
41
|
+
const el = document.createElement('ktf-setting-number');
|
|
42
|
+
el.name = 'delayMs';
|
|
43
|
+
document.body.appendChild(el);
|
|
44
|
+
await nextTick();
|
|
45
|
+
const input = el.querySelector('input[type="number"]');
|
|
46
|
+
const initial = String(input.value) === '0';
|
|
47
|
+
store.setSettings({ delayMs: 250 });
|
|
48
|
+
await nextTick();
|
|
49
|
+
const updated = String(input.value) === '250';
|
|
50
|
+
if (initial && updated) pass('SettingNumber stayed in sync with external setting change');
|
|
51
|
+
else fail('SettingNumber did not sync input after settings change');
|
|
52
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
53
|
+
}
|
|
54
|
+
};
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
// Browser tests for SettingSelect 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
|
-
'SettingSelect reflects and updates settings': async ({ pass, fail, log }) => {
|
|
12
|
-
try {
|
|
13
|
-
await import('/gui/components/settingsStore.js');
|
|
14
|
-
await import('/gui/components/SettingSelect.js');
|
|
15
|
-
window.KTF_SETTINGS.set({ logLevel: 2 });
|
|
16
|
-
const el = document.createElement('ktf-setting-select');
|
|
17
|
-
el.name = 'logLevel';
|
|
18
|
-
el.label = 'Log Level';
|
|
19
|
-
document.body.appendChild(el);
|
|
20
|
-
await nextTick();
|
|
21
|
-
const select = el.querySelector('select');
|
|
22
|
-
const before = String(select.value) === '2';
|
|
23
|
-
select.value = '1'; select.dispatchEvent(new Event('change'));
|
|
24
|
-
await nextTick();
|
|
25
|
-
const after = window.KTF_SETTINGS.get().logLevel === 1;
|
|
26
|
-
log(`Select value before:${before} after:${after}`);
|
|
27
|
-
if (before && after) pass('SettingSelect updated setting from 2 to 1'); else fail('SettingSelect did not update setting');
|
|
28
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
'SettingSelect stays in sync when settings change externally': async ({ pass, fail }) => {
|
|
32
|
-
try {
|
|
33
|
-
await import('/gui/components/settingsStore.js');
|
|
34
|
-
await import('/gui/components/SettingSelect.js');
|
|
35
|
-
window.KTF_SETTINGS.set({ logLevel: 1 });
|
|
36
|
-
const el = document.createElement('ktf-setting-select');
|
|
37
|
-
el.name = 'logLevel';
|
|
38
|
-
document.body.appendChild(el);
|
|
39
|
-
await nextTick();
|
|
40
|
-
const select = el.querySelector('select');
|
|
41
|
-
window.KTF_SETTINGS.set({ logLevel: 4 });
|
|
42
|
-
await nextTick();
|
|
43
|
-
const synced = String(select.value) === '4';
|
|
44
|
-
if (synced) pass('SettingSelect synced after external settings change'); else fail('Select did not sync after external change');
|
|
45
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
46
|
-
}
|
|
47
|
-
};
|
|
1
|
+
// Browser tests for SettingSelect 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
|
+
'SettingSelect reflects and updates settings': async ({ pass, fail, log }) => {
|
|
12
|
+
try {
|
|
13
|
+
await import('/gui/components/settingsStore.js');
|
|
14
|
+
await import('/gui/components/SettingSelect.js');
|
|
15
|
+
window.KTF_SETTINGS.set({ logLevel: 2 });
|
|
16
|
+
const el = document.createElement('ktf-setting-select');
|
|
17
|
+
el.name = 'logLevel';
|
|
18
|
+
el.label = 'Log Level';
|
|
19
|
+
document.body.appendChild(el);
|
|
20
|
+
await nextTick();
|
|
21
|
+
const select = el.querySelector('select');
|
|
22
|
+
const before = String(select.value) === '2';
|
|
23
|
+
select.value = '1'; select.dispatchEvent(new Event('change'));
|
|
24
|
+
await nextTick();
|
|
25
|
+
const after = window.KTF_SETTINGS.get().logLevel === 1;
|
|
26
|
+
log(`Select value before:${before} after:${after}`);
|
|
27
|
+
if (before && after) pass('SettingSelect updated setting from 2 to 1'); else fail('SettingSelect did not update setting');
|
|
28
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
'SettingSelect stays in sync when settings change externally': async ({ pass, fail }) => {
|
|
32
|
+
try {
|
|
33
|
+
await import('/gui/components/settingsStore.js');
|
|
34
|
+
await import('/gui/components/SettingSelect.js');
|
|
35
|
+
window.KTF_SETTINGS.set({ logLevel: 1 });
|
|
36
|
+
const el = document.createElement('ktf-setting-select');
|
|
37
|
+
el.name = 'logLevel';
|
|
38
|
+
document.body.appendChild(el);
|
|
39
|
+
await nextTick();
|
|
40
|
+
const select = el.querySelector('select');
|
|
41
|
+
window.KTF_SETTINGS.set({ logLevel: 4 });
|
|
42
|
+
await nextTick();
|
|
43
|
+
const synced = String(select.value) === '4';
|
|
44
|
+
if (synced) pass('SettingSelect synced after external settings change'); else fail('Select did not sync after external change');
|
|
45
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
46
|
+
}
|
|
47
|
+
};
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
// Browser tests for settingsStore helpers
|
|
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
|
-
'settingsStore get/set persists to localStorage and dispatches event': async ({ pass, fail }) => {
|
|
12
|
-
try {
|
|
13
|
-
const store = await import('/gui/components/settingsStore.js');
|
|
14
|
-
const before = store.getSettings();
|
|
15
|
-
const p = new Promise(resolve => {
|
|
16
|
-
const unsub = store.subscribe((s) => { unsub(); resolve(s); });
|
|
17
|
-
});
|
|
18
|
-
store.setSettings({ theme: 'dark', logLevel: 4 });
|
|
19
|
-
const evtState = await p;
|
|
20
|
-
const raw = localStorage.getItem('ktf_settings');
|
|
21
|
-
const parsed = JSON.parse(raw || '{}');
|
|
22
|
-
const ok = evtState.theme === 'dark' && evtState.logLevel === 4 && parsed.theme === 'dark' && parsed.logLevel === 4;
|
|
23
|
-
ok ? pass('settingsStore persisted and dispatched change event') : fail(`state:${JSON.stringify(evtState)} raw:${raw}`);
|
|
24
|
-
} catch (e) { fail(e.stack || String(e)); }
|
|
25
|
-
}
|
|
26
|
-
};
|
|
1
|
+
// Browser tests for settingsStore helpers
|
|
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
|
+
'settingsStore get/set persists to localStorage and dispatches event': async ({ pass, fail }) => {
|
|
12
|
+
try {
|
|
13
|
+
const store = await import('/gui/components/settingsStore.js');
|
|
14
|
+
const before = store.getSettings();
|
|
15
|
+
const p = new Promise(resolve => {
|
|
16
|
+
const unsub = store.subscribe((s) => { unsub(); resolve(s); });
|
|
17
|
+
});
|
|
18
|
+
store.setSettings({ theme: 'dark', logLevel: 4 });
|
|
19
|
+
const evtState = await p;
|
|
20
|
+
const raw = localStorage.getItem('ktf_settings');
|
|
21
|
+
const parsed = JSON.parse(raw || '{}');
|
|
22
|
+
const ok = evtState.theme === 'dark' && evtState.logLevel === 4 && parsed.theme === 'dark' && parsed.logLevel === 4;
|
|
23
|
+
ok ? pass('settingsStore persisted and dispatched change event') : fail(`state:${JSON.stringify(evtState)} raw:${raw}`);
|
|
24
|
+
} catch (e) { fail(e.stack || String(e)); }
|
|
25
|
+
}
|
|
26
|
+
};
|