@skirbi/sugar 0.0.6 → 0.0.8

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/Changes CHANGED
@@ -1,5 +1,69 @@
1
1
  Revision history for @skirbi/sugar
2
2
 
3
+ 0.0.8 2026-02-23 03:32:55Z
4
+
5
+ * Add assertComponentContract testing method. The idea is this:
6
+
7
+ class FooBar extends HTMLElementSugar {
8
+ ...
9
+ static exampleHTML = '<foo-bar attrs="here"></foo-bar>";
10
+ static exampleRenderedHTML = '<some-thing></some-thing>';
11
+
12
+ // your connected callback code here
13
+ }
14
+
15
+ Now you can test the component to adhere to the contract by using
16
+ assertComponentContract:
17
+
18
+ import { setupDomForTesting, assertComponentContract } from
19
+ '@skirbi/sugar/testing';
20
+
21
+ // test setup here
22
+
23
+ t.test('Test exampleHTML and friends', t => {
24
+
25
+ class TestExampleHTML extends HTMLElementSugar {
26
+ static HtmlTemplate = 'track-item-template';
27
+ static exampleHTML = '<test-example-html></test-example-html>';
28
+ static exampleRenderedHTML = `
29
+ <div class="track-row"><div class="track-info">ok</div></div>
30
+ `;
31
+
32
+ connectedCallback() {
33
+ if (this._rendered) return;
34
+ this._rendered = true;
35
+ this.appendChild(this.renderFromTemplate());
36
+ }
37
+ }
38
+ document.body.innerHTML = `
39
+ <template id="track-item-template">
40
+ <div class="track-row"><div class="track-info">ok</div></div>
41
+ </template>
42
+ `;
43
+
44
+ TestExampleHTML.register();
45
+ t.equal(TestExampleHTML.tag, 'test-example-html');
46
+ assertComponentContract(TestExampleHTML,
47
+ '<test-example-html></test-example-html>');
48
+ t.end();
49
+
50
+ });
51
+
52
+ While the test system has been setup in @skirbi/sugar we do *not*
53
+ enforce it. Component authors are free to use the infrastructure. It is
54
+ build as an nice to have feature. Be aware, that the testing framework
55
+ is tap, so in case a component author uses a different testframework you
56
+ may need to roll your own solution.
57
+
58
+ 0.0.7 2026-02-20 16:54:59Z
59
+
60
+ * Fix exports in lib/index.mjs: allow SugarInput and SugarSelect to be
61
+ imported from @skirbi/sugar and also all registerAlias-functions to be
62
+ exported from aliases and aliases-register
63
+ * Add tap version exclusions due to bug
64
+ https://github.com/tapjs/tapjs/issues/1062. Broke with node 24.10.x and tap
65
+ >= 21.6.0
66
+
3
67
  0.0.6 2026-02-20 04:30:44Z
4
68
 
5
69
  * Add a way to actually add aliases. It seems between time of initial
package/lib/index.mjs CHANGED
@@ -2,6 +2,11 @@
2
2
  //
3
3
  // SPDX-License-Identifier: MIT
4
4
 
5
- const VERSION = "0.0.6";
5
+ const VERSION = "0.0.8";
6
+
6
7
  export { HTMLElementSugar } from './htmlelement.mjs';
8
+ export { HTMLElementSugarInput } from './htmlelement-input.mjs';
9
+ export { HTMLElementSugarSelect } from './htmlelement-select.mjs';
7
10
  export { parseBoolean } from './boolean.mjs';
11
+ export { registerDevAlias, applyDevAliases } from './aliases.mjs';
12
+ export { registerAliases } from './aliases-register.mjs';
package/lib/testing.mjs CHANGED
@@ -4,32 +4,132 @@
4
4
 
5
5
  import { JSDOM } from 'jsdom';
6
6
  import { fileURLToPath, pathToFileURL } from 'url';
7
+ import t from 'tap';
7
8
  import path from 'path';
8
9
 
9
10
  /**
10
- * Set up a jsdom environment and load one or more modules.
11
+ * Initialize a jsdom-based DOM environment for component testing.
11
12
  *
12
- * @param {...string} modulePaths - relative paths to modules to import
13
+ * This function:
14
+ * - Creates a new JSDOM instance
15
+ * - Exposes common DOM globals on `global`
16
+ * - Optionally imports one or more modules after the DOM is ready
17
+ *
18
+ * It is intended for use in test files before mounting custom elements.
19
+ *
20
+ * @param {string} [html='<!doctype html><html><body></body></html>']
21
+ * Initial HTML document to load into jsdom.
22
+ *
23
+ * @param {...string} modulePaths
24
+ * Relative paths (from project root) to modules that should be imported
25
+ * after the DOM environment is initialized.
26
+ *
27
+ * @returns {Promise<void>}
13
28
  */
14
29
  export async function setupDomForTesting(
15
30
  html = '<!doctype html><html><body></body></html>',
16
- ...modulePaths) {
31
+ ...modulePaths
32
+ ) {
17
33
  const dom = new JSDOM(html);
18
34
 
35
+ // Expose minimal DOM globals required for custom elements.
19
36
  global.DocumentFragment = dom.window.DocumentFragment;
20
37
  global.HTMLElement = dom.window.HTMLElement;
21
38
  global.HTMLTemplateElement = dom.window.HTMLTemplateElement;
22
- global.Node = dom.window.Node
39
+ global.Node = dom.window.Node;
23
40
  global.customElements = dom.window.customElements;
24
41
  global.document = dom.window.document;
25
42
  global.window = dom.window;
26
43
  global.MutationObserver = dom.window.MutationObserver;
27
44
 
28
-
29
45
  const projectRoot = process.cwd();
30
46
 
47
+ // Import modules after DOM is ready.
31
48
  for (const relPath of modulePaths) {
32
49
  const absURL = pathToFileURL(path.resolve(projectRoot, relPath));
33
50
  await import(absURL.href);
34
51
  }
35
52
  }
53
+
54
+ /**
55
+ * Test a component's example contract.
56
+ *
57
+ * This helper verifies:
58
+ *
59
+ * 1. `Class.exampleHTML` matches the provided `example` snippet.
60
+ * 2. After mounting and lifecycle execution, the rendered output
61
+ * matches `Class.exampleRenderedHTML`.
62
+ *
63
+ * The component must define:
64
+ *
65
+ * - `static exampleHTML`
66
+ * - `static exampleRenderedHTML`
67
+ *
68
+ * @template {typeof HTMLElement} T
69
+ *
70
+ * @param {T & {
71
+ * register?: () => void,
72
+ * init?: () => void,
73
+ * exampleHTML: string,
74
+ * exampleRenderedHTML: string
75
+ * }} Class
76
+ * The component class under test.
77
+ *
78
+ * @param {Object} options
79
+ * @param {boolean} [options.register=true]
80
+ * Whether to call `Class.register()` (default) or `Class.init()`.
81
+ *
82
+ * @param {string} options.example
83
+ * Expected authoring HTML to compare against `Class.exampleHTML`.
84
+ *
85
+ * @param {import('tap').Test} options.tap
86
+ * Tap test instance used for assertions.
87
+ *
88
+ * @returns {Promise<void>}
89
+ */
90
+ export async function assertComponentContract(Class, example) {
91
+ Class.init();
92
+
93
+ t.type(Class.exampleHTML, 'string', 'Has exampleHTML');
94
+
95
+ // Compare authoring example.
96
+ let needle = htmlToFragment(example);
97
+ let haystack = htmlToFragment(Class.exampleHTML);
98
+
99
+ t.ok(
100
+ needle.isEqualNode(haystack),
101
+ 'Provided example is correct',
102
+ );
103
+
104
+ t.equal(haystack.childElementCount, 1, '.. and has exactly one root element');
105
+ const el = haystack.firstElementChild;
106
+ t.ok(el, "... and produced such element");
107
+ document.body.appendChild(el);
108
+
109
+ await new Promise(r => setTimeout(r, 0));
110
+
111
+ t.type(Class.exampleRenderedHTML, 'string', '.. and has example rendered');
112
+ needle = htmlToFragment(Class.exampleRenderedHTML);
113
+ haystack = htmlToFragment(el.innerHTML);
114
+
115
+ t.ok(
116
+ needle.isEqualNode(haystack),
117
+ 'connectedCallback works',
118
+ );
119
+ }
120
+
121
+ /**
122
+ * Convert an HTML string into a DocumentFragment.
123
+ *
124
+ * The fragment is not connected to the document and does not
125
+ * trigger custom element lifecycle callbacks.
126
+ *
127
+ * @param {string} html - HTML string to parse.
128
+ * @returns {DocumentFragment}
129
+ */
130
+ function htmlToFragment(html) {
131
+ const tpl = document.createElement('template');
132
+ tpl.innerHTML = html.trim();
133
+ return tpl.content;
134
+ }
135
+
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "name": "Wesley Schwengle"
5
5
  },
6
6
  "bugs": {
7
- "url": "https://gitlab.com/opndev/javascript/skirbi/-/issues"
7
+ "url": "https://gitlab.com/skirbi/sugar/-/issues"
8
8
  },
9
9
  "dependencies": {
10
10
  "@opndev/util": "latest"
@@ -13,7 +13,10 @@
13
13
  "devDependencies": {
14
14
  "jsdoc": "latest",
15
15
  "jsdom": "latest",
16
- "tap": "latest"
16
+ "tap": "<21.6.0 || >21.6.1"
17
+ },
18
+ "engines": {
19
+ "node": ">24.10"
17
20
  },
18
21
  "exports": {
19
22
  ".": "./lib/index.mjs",
@@ -25,7 +28,7 @@
25
28
  "./htmlelement-select": "./lib/htmlelement-select.mjs",
26
29
  "./testing": "./lib/testing.mjs"
27
30
  },
28
- "homepage": "https://gitlab.com/opndev/javascript/skirbi",
31
+ "homepage": "https://gitlab.com/skirbi/sugar",
29
32
  "keywords": [
30
33
  "custom elements",
31
34
  "web components",
@@ -38,7 +41,7 @@
38
41
  "name": "@skirbi/sugar",
39
42
  "repository": {
40
43
  "type": "git",
41
- "url": "git+https://gitlab.com/opndev/javascript/skirbi.git"
44
+ "url": "git+https://gitlab.com/skirbi/sugar.git"
42
45
  },
43
46
  "scripts": {
44
47
  "build": "rzil build",
@@ -49,5 +52,5 @@
49
52
  },
50
53
  "sideEffects": false,
51
54
  "type": "module",
52
- "version": "0.0.6"
55
+ "version": "0.0.8"
53
56
  }