@muonic/muon 0.0.2-beta.0

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 (124) hide show
  1. package/.nycrc +17 -0
  2. package/.versionrc +3 -0
  3. package/CHANGELOG.md +389 -0
  4. package/components/card/index.js +1 -0
  5. package/components/card/src/card-component.js +43 -0
  6. package/components/card/src/card-styles.css +25 -0
  7. package/components/card/src/config-tokens.json +11 -0
  8. package/components/card/src/design-tokens.json +34 -0
  9. package/components/card/story.js +52 -0
  10. package/components/cta/index.js +1 -0
  11. package/components/cta/src/config-tokens.json +11 -0
  12. package/components/cta/src/cta-component.js +174 -0
  13. package/components/cta/src/cta-styles.css +105 -0
  14. package/components/cta/src/design-tokens.json +132 -0
  15. package/components/cta/story.js +99 -0
  16. package/components/detail/index.js +1 -0
  17. package/components/detail/src/config-tokens.json +11 -0
  18. package/components/detail/src/design-tokens.json +102 -0
  19. package/components/detail/src/detail-component.js +27 -0
  20. package/components/detail/src/detail-styles.css +83 -0
  21. package/components/detail/story.js +33 -0
  22. package/components/form/index.js +1 -0
  23. package/components/form/src/config-tokens.json +11 -0
  24. package/components/form/src/design-tokens.json +9 -0
  25. package/components/form/src/form-component.js +197 -0
  26. package/components/form/src/form-styles.css +10 -0
  27. package/components/form/story.js +71 -0
  28. package/components/icon/index.js +1 -0
  29. package/components/icon/src/config-tokens.json +31 -0
  30. package/components/icon/src/design-tokens.json +8 -0
  31. package/components/icon/src/icon-component.js +91 -0
  32. package/components/icon/src/icon-styles.css +26 -0
  33. package/components/icon/story.js +26 -0
  34. package/components/image/index.js +1 -0
  35. package/components/image/src/config-tokens.json +26 -0
  36. package/components/image/src/image-component.js +96 -0
  37. package/components/image/src/image-styles.css +71 -0
  38. package/components/image/story.js +31 -0
  39. package/components/inputter/index.js +1 -0
  40. package/components/inputter/src/config-tokens.json +14 -0
  41. package/components/inputter/src/design-tokens.json +308 -0
  42. package/components/inputter/src/inputter-component.js +227 -0
  43. package/components/inputter/src/inputter-styles-detail.css +59 -0
  44. package/components/inputter/src/inputter-styles.css +305 -0
  45. package/components/inputter/src/inputter-styles.slotted.css +64 -0
  46. package/components/inputter/story.js +243 -0
  47. package/css/accessibility.css +3 -0
  48. package/css/default.css +9 -0
  49. package/css/global.css +8 -0
  50. package/directives/image-loader-directive.js +116 -0
  51. package/directives/svg-loader-directive.js +94 -0
  52. package/index.js +52 -0
  53. package/mixins/card-mixin.js +27 -0
  54. package/mixins/detail-mixin.js +128 -0
  55. package/mixins/form-associate-mixin.js +36 -0
  56. package/mixins/form-element-mixin.js +378 -0
  57. package/mixins/image-holder-mixin.js +20 -0
  58. package/mixins/mask-mixin.js +159 -0
  59. package/mixins/validation-mixin.js +272 -0
  60. package/muon-element/index.js +97 -0
  61. package/package.json +72 -0
  62. package/rollup.config.mjs +30 -0
  63. package/scripts/build/storybook/index.mjs +11 -0
  64. package/scripts/build/storybook/run.mjs +47 -0
  65. package/scripts/rollup-plugins.mjs +116 -0
  66. package/scripts/serve/index.mjs +11 -0
  67. package/scripts/serve/run.mjs +27 -0
  68. package/scripts/style-dictionary.mjs +64 -0
  69. package/scripts/utils/config.mjs +30 -0
  70. package/scripts/utils/index.mjs +283 -0
  71. package/storybook/find-stories.js +36 -0
  72. package/storybook/server.config.mjs +19 -0
  73. package/storybook/stories.js +86 -0
  74. package/storybook/tokens/color.js +87 -0
  75. package/storybook/tokens/font.js +52 -0
  76. package/storybook/tokens/spacer.js +48 -0
  77. package/tests/README.md +3 -0
  78. package/tests/components/card/__snapshots__/card.test.snap.js +70 -0
  79. package/tests/components/card/card.test.js +81 -0
  80. package/tests/components/cta/__snapshots__/cta.test.snap.js +246 -0
  81. package/tests/components/cta/cta.test.js +212 -0
  82. package/tests/components/form/__snapshots__/form.test.snap.js +115 -0
  83. package/tests/components/form/form.test.js +336 -0
  84. package/tests/components/icon/__snapshots__/icon.test.snap.js +95 -0
  85. package/tests/components/icon/icon.test.js +197 -0
  86. package/tests/components/image/__snapshots__/image.test.snap.js +205 -0
  87. package/tests/components/image/image.test.js +314 -0
  88. package/tests/components/image/images/15.png +0 -0
  89. package/tests/components/image/images/150.png +0 -0
  90. package/tests/components/inputter/__snapshots__/inputter.test.snap.js +357 -0
  91. package/tests/components/inputter/inputter.test.js +427 -0
  92. package/tests/helpers/index.js +30 -0
  93. package/tests/mixins/__snapshots__/card.test.snap.js +35 -0
  94. package/tests/mixins/__snapshots__/detail.test.snap.js +237 -0
  95. package/tests/mixins/__snapshots__/form-element.test.snap.js +137 -0
  96. package/tests/mixins/__snapshots__/mask.test.snap.js +53 -0
  97. package/tests/mixins/__snapshots__/validation.test.snap.js +297 -0
  98. package/tests/mixins/card.test.js +63 -0
  99. package/tests/mixins/detail.test.js +223 -0
  100. package/tests/mixins/form-element.test.js +473 -0
  101. package/tests/mixins/mask.test.js +261 -0
  102. package/tests/mixins/muon-element.test.js +52 -0
  103. package/tests/mixins/validation.test.js +423 -0
  104. package/tests/runner/commands.mjs +19 -0
  105. package/tests/scripts/utils/card-component.js +26 -0
  106. package/tests/scripts/utils/muon.config.test.json +13 -0
  107. package/tests/scripts/utils/single.component.config.json +5 -0
  108. package/tests/scripts/utils/test-runner.mjs +1 -0
  109. package/tests/scripts/utils/utils-test.mjs +284 -0
  110. package/tests/utils/validation.functions.test.js +199 -0
  111. package/tokens/theme/color.json +482 -0
  112. package/tokens/theme/font.json +61 -0
  113. package/tokens/theme/size.json +27 -0
  114. package/tokens/theme/spacer.json +73 -0
  115. package/tokens/utils/formats/reference.js +17 -0
  116. package/tokens/utils/modular-scale.js +33 -0
  117. package/tokens/utils/templates/font-face.css.template +30 -0
  118. package/tokens/utils/transforms/color.js +27 -0
  119. package/tokens/utils/transforms/string.js +6 -0
  120. package/tokens/utils/validation.json +76 -0
  121. package/utils/scroll/index.js +31 -0
  122. package/utils/validation/index.js +205 -0
  123. package/web-test-runner.browserstack.config.mjs +123 -0
  124. package/web-test-runner.config.mjs +44 -0
@@ -0,0 +1,473 @@
1
+ /* eslint-disable no-undef */
2
+ import { expect, fixture, html, defineCE, unsafeStatic } from '@open-wc/testing';
3
+ import { FormElementMixin } from '@muonic/muon/mixins/form-element-mixin';
4
+ import { MuonElement, classMap } from '@muonic/muon';
5
+ import sinon from 'sinon';
6
+ import { defaultChecks, fillIn, selectEvent } from '../helpers';
7
+
8
+ const MuonFormElement = class extends FormElementMixin(MuonElement) {
9
+
10
+ get standardTemplate() {
11
+ const classes = {
12
+ 'slotted-content': true,
13
+ 'select-arrow': this._isSelect
14
+ };
15
+
16
+ return html `
17
+ <div class="${classMap(classes)}">
18
+ ${this._isMultiple ? this._addHeading : this._addLabel}
19
+ <div class="input-holder">
20
+ ${super.standardTemplate}
21
+ </div>
22
+ </div>`;
23
+ }
24
+
25
+ get singleTemplate() {
26
+ if (this._isSingle) {
27
+ const classes = {
28
+ 'slotted-content': true
29
+ };
30
+
31
+ return html `
32
+ <div class="${classMap(classes)}">
33
+ ${this._addLabel}
34
+ <div class="input-holder">
35
+ ${super.standardTemplate}
36
+ </div>
37
+ </div>`;
38
+ } else {
39
+ return this.standardTemplate;
40
+ }
41
+ }
42
+
43
+ get multipleTemplate() {
44
+ if (this._isMultiple) {
45
+ const classes = {
46
+ 'slotted-content': true
47
+ };
48
+
49
+ return html `
50
+ <div class="${classMap(classes)}">
51
+ ${this._addHeading}
52
+ <div class="input-holder">
53
+ ${super.standardTemplate}
54
+ </div>
55
+ </div>`;
56
+ } else {
57
+ return this.standardTemplate;
58
+ }
59
+ }
60
+
61
+ get selectTemplate() {
62
+ if (this._isSelect) {
63
+ const classes = {
64
+ 'slotted-content': true,
65
+ 'select-arrow': this._isSelect
66
+ };
67
+
68
+ return html `
69
+ <div class="${classMap(classes)}">
70
+ ${this._addLabel}
71
+ <div class="input-holder">
72
+ ${super.standardTemplate}
73
+ </div>
74
+ </div>`;
75
+ } else {
76
+ return this.standardTemplate;
77
+ }
78
+ }
79
+ };
80
+
81
+ const tagName = defineCE(MuonFormElement);
82
+ const tag = unsafeStatic(tagName);
83
+
84
+ describe('form-element', () => {
85
+ afterEach(() => {
86
+ sinon.restore();
87
+ });
88
+
89
+ it('standard', async () => {
90
+ const formElement = await fixture(html`<${tag}></${tag}>`);
91
+
92
+ await defaultChecks(formElement);
93
+
94
+ const shadowRoot = formElement.shadowRoot;
95
+ const holder = shadowRoot.querySelector('.input-holder');
96
+
97
+ expect(holder).to.not.be.null; // eslint-disable-line no-unused-expressions
98
+ expect(formElement.type).to.equal('standard', '`type` property has default value `standard`');
99
+ });
100
+
101
+ it('standard text input', async () => {
102
+ const formElement = await fixture(html`
103
+ <${tag} type="single">
104
+ <label slot="label">input label</label>
105
+ <input type="text" value=""/>
106
+ </${tag}>`);
107
+
108
+ await defaultChecks(formElement);
109
+
110
+ const shadowRoot = formElement.shadowRoot;
111
+ const label = shadowRoot.querySelector('slot[name="label"]');
112
+ const holder = shadowRoot.querySelector('.input-holder');
113
+
114
+ expect(formElement.type).to.equal('single', '`type` property has default value `standard`');
115
+ // eslint-disable-next-line no-unused-expressions
116
+ expect(label).to.not.be.null;
117
+ expect(label.assignedElements()[0].textContent).to.equal('input label', '`label` slot has value `input label`');
118
+ // eslint-disable-next-line no-unused-expressions
119
+ expect(holder).to.not.be.null;
120
+
121
+ const inputElement = formElement.querySelector('input');
122
+
123
+ // eslint-disable-next-line no-unused-expressions
124
+ expect(inputElement).to.not.be.null;
125
+
126
+ const changeEventSpy = sinon.spy();
127
+ formElement.addEventListener('change', changeEventSpy);
128
+
129
+ await fillIn(inputElement, 'hello');
130
+ expect(formElement.value).to.equal('hello', '`value` property has value `hello`');
131
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
132
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('hello', '`change` event has value `hello`');
133
+ });
134
+
135
+ it('text input event', async () => {
136
+ const formElement = await fixture(html`
137
+ <${tag} type="single">
138
+ <label slot="label">input label</label>
139
+ <input type="text" value=""/>
140
+ </${tag}>`);
141
+
142
+ await defaultChecks(formElement);
143
+
144
+ const shadowRoot = formElement.shadowRoot;
145
+ const label = shadowRoot.querySelector('slot[name="label"]');
146
+ const holder = shadowRoot.querySelector('.input-holder');
147
+
148
+ expect(formElement.type).to.equal('single', '`type` property has default value `standard`');
149
+ // eslint-disable-next-line no-unused-expressions
150
+ expect(label).to.not.be.null;
151
+ expect(label.assignedElements()[0].textContent).to.equal('input label', '`label` slot has value `input label`');
152
+ // eslint-disable-next-line no-unused-expressions
153
+ expect(holder).to.not.be.null;
154
+
155
+ const inputElement = formElement.querySelector('input');
156
+
157
+ // eslint-disable-next-line no-unused-expressions
158
+ expect(inputElement).to.not.be.null;
159
+
160
+ const changeEventSpy = sinon.spy();
161
+ formElement.addEventListener('change', changeEventSpy);
162
+
163
+ await fillIn(inputElement, 'hello', 'input');
164
+ expect(formElement.value).to.equal('', '`value` property not changed');
165
+ expect(changeEventSpy.callCount).to.equal(0, '`change` event not fired');
166
+ });
167
+
168
+ it('text default value', async () => {
169
+ const formElement = await fixture(html`
170
+ <${tag} type="single" value="test value">
171
+ <label slot="label">input label</label>
172
+ <input type="text" value=""/>
173
+ </${tag}>`);
174
+
175
+ await defaultChecks(formElement);
176
+
177
+ const shadowRoot = formElement.shadowRoot;
178
+ const label = shadowRoot.querySelector('slot[name="label"]');
179
+ const holder = shadowRoot.querySelector('.input-holder');
180
+
181
+ expect(formElement.type).to.equal('single', '`type` property has default value `standard`');
182
+ // eslint-disable-next-line no-unused-expressions
183
+ expect(label).to.not.be.null;
184
+ expect(label.assignedElements()[0].textContent).to.equal('input label', '`label` slot has value `input label`');
185
+ // eslint-disable-next-line no-unused-expressions
186
+ expect(holder).to.not.be.null;
187
+
188
+ const inputElement = formElement.querySelector('input');
189
+
190
+ // eslint-disable-next-line no-unused-expressions
191
+ expect(inputElement).to.not.be.null;
192
+ expect(inputElement.value).to.equal('test value', '`value` attribute of input has correctt value');
193
+
194
+ const changeEventSpy = sinon.spy();
195
+ formElement.addEventListener('change', changeEventSpy);
196
+
197
+ await fillIn(inputElement, 'hello');
198
+ expect(formElement.value).to.equal('hello', '`value` property has value `hello`');
199
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
200
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('hello', '`change` event has value `hello`');
201
+ });
202
+
203
+ it('text default input value', async () => {
204
+ const formElement = await fixture(html`
205
+ <${tag} type="single">
206
+ <label slot="label">input label</label>
207
+ <input type="text" value="test value"/>
208
+ </${tag}>`);
209
+
210
+ await defaultChecks(formElement);
211
+
212
+ const shadowRoot = formElement.shadowRoot;
213
+ const label = shadowRoot.querySelector('slot[name="label"]');
214
+ const holder = shadowRoot.querySelector('.input-holder');
215
+
216
+ expect(formElement.type).to.equal('single', '`type` property has default value `standard`');
217
+ // eslint-disable-next-line no-unused-expressions
218
+ expect(label).to.not.be.null;
219
+ expect(label.assignedElements()[0].textContent).to.equal('input label', '`label` slot has value `input label`');
220
+ // eslint-disable-next-line no-unused-expressions
221
+ expect(holder).to.not.be.null;
222
+
223
+ const inputElement = formElement.querySelector('input');
224
+
225
+ // eslint-disable-next-line no-unused-expressions
226
+ expect(inputElement).to.not.be.null;
227
+ expect(formElement.value).to.equal('test value', '`value` attribute of input has correctt value');
228
+
229
+ const changeEventSpy = sinon.spy();
230
+ formElement.addEventListener('change', changeEventSpy);
231
+
232
+ await fillIn(inputElement, 'hello');
233
+ expect(formElement.value).to.equal('hello', '`value` property has value `hello`');
234
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
235
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('hello', '`change` event has value `hello`');
236
+ });
237
+
238
+ it('standard text input labelID', async () => {
239
+ const parentElement = await fixture(html`
240
+ <div>
241
+ <h1 id="label-id-test">what does it mean?</h1>
242
+ <${tag} labelID="label-id-test">
243
+ <input type="text" value=""/>
244
+ </${tag}>
245
+ </div>`);
246
+
247
+ const formElement = parentElement.querySelector('test-0');
248
+ await defaultChecks(formElement);
249
+
250
+ const shadowRoot = formElement.shadowRoot;
251
+ const holder = shadowRoot.querySelector('.input-holder');
252
+
253
+ // eslint-disable-next-line no-unused-expressions
254
+ expect(holder).to.not.be.null;
255
+ expect(formElement.type).to.equal('standard', '`type` property has default value `standard`');
256
+
257
+ const slottedInput = formElement.querySelector('input');
258
+ expect(slottedInput.getAttribute('aria-labelledby')).to.equal('label-id-test', '`aria-labelledby` attribute of input has value `label-id-test`');
259
+ });
260
+
261
+ it('standard radio input', async () => {
262
+ const formElement = await fixture(html`
263
+ <${tag} type="multiple" heading="What is your heating source?">
264
+ <input type="radio" id="question-gas" name="question" value="gas" checked></input>
265
+ <label for="question-gas">Gas</label>
266
+ <input type="radio" id="question-electricity" name="question" value="electricity"></input>
267
+ <label for="question-electricity">Electricity</label>
268
+ </${tag}>`);
269
+
270
+ await defaultChecks(formElement);
271
+
272
+ const shadowRoot = formElement.shadowRoot;
273
+ const heading = shadowRoot.querySelector('.input-heading');
274
+ const holder = shadowRoot.querySelector('.input-holder');
275
+
276
+ expect(formElement.type).to.equal('multiple', '`type` property has default value `standard`');
277
+ // eslint-disable-next-line no-unused-expressions
278
+ expect(heading).to.not.be.null;
279
+ expect(heading.textContent).to.equal('What is your heating source?', '`heading` slot has value `What is your heating source?`');
280
+ // eslint-disable-next-line no-unused-expressions
281
+ expect(holder).to.not.be.null;
282
+
283
+ const inputElement = formElement.querySelectorAll('input');
284
+ // eslint-disable-next-line no-unused-expressions
285
+ expect(inputElement).to.not.be.null;
286
+
287
+ const changeEventSpy = sinon.spy();
288
+ formElement.addEventListener('change', changeEventSpy);
289
+
290
+ // eslint-disable-next-line no-unused-expressions
291
+ expect(inputElement[0].checked).to.true;
292
+
293
+ inputElement[1].click();
294
+ // eslint-disable-next-line no-unused-expressions
295
+ expect(inputElement[0].checked).to.false;
296
+ // eslint-disable-next-line no-unused-expressions
297
+ expect(inputElement[1].checked).to.true;
298
+ expect(formElement.value).to.equal('electricity', '`value` property has value `electricity`');
299
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
300
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('electricity', '`change` event has value `electricity`');
301
+
302
+ inputElement[0].click();
303
+ // eslint-disable-next-line no-unused-expressions
304
+ expect(inputElement[0].checked).to.true;
305
+ // eslint-disable-next-line no-unused-expressions
306
+ expect(inputElement[1].checked).to.false;
307
+ expect(formElement.value).to.equal('gas', '`value` property has value `gas`');
308
+ expect(changeEventSpy.callCount).to.equal(2, '`change` event fired');
309
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('gas', '`change` event has value `gas`');
310
+ });
311
+
312
+ it('radio default value', async () => {
313
+ const formElement = await fixture(html`
314
+ <${tag} type="multiple" heading="What is your heating source?" value="electricity">
315
+ <input type="radio" id="question-gas" name="question" value="gas"></input>
316
+ <label for="question-gas">Gas</label>
317
+ <input type="radio" id="question-electricity" name="question" value="electricity"></input>
318
+ <label for="question-electricity">Electricity</label>
319
+ </${tag}>`);
320
+
321
+ await defaultChecks(formElement);
322
+
323
+ const shadowRoot = formElement.shadowRoot;
324
+ const heading = shadowRoot.querySelector('.input-heading');
325
+ const holder = shadowRoot.querySelector('.input-holder');
326
+
327
+ expect(formElement.type).to.equal('multiple', '`type` property has default value `standard`');
328
+ // eslint-disable-next-line no-unused-expressions
329
+ expect(heading).to.not.be.null;
330
+ expect(heading.textContent).to.equal('What is your heating source?', '`heading` slot has value `What is your heating source?`');
331
+ // eslint-disable-next-line no-unused-expressions
332
+ expect(holder).to.not.be.null;
333
+
334
+ const inputElement = formElement.querySelectorAll('input');
335
+ // eslint-disable-next-line no-unused-expressions
336
+ expect(inputElement).to.not.be.null;
337
+
338
+ const changeEventSpy = sinon.spy();
339
+ formElement.addEventListener('change', changeEventSpy);
340
+
341
+ // eslint-disable-next-line no-unused-expressions
342
+ expect(inputElement[0].checked).to.false;
343
+ // eslint-disable-next-line no-unused-expressions
344
+ expect(inputElement[1].checked).to.true;
345
+ });
346
+
347
+ it('standard checkbox input', async () => {
348
+ const formElement = await fixture(html`
349
+ <${tag} heading="What is your heating source?">
350
+ <input type="checkbox" id="question-gas" name="question" value="gas" checked></input>
351
+ <label for="question-gas">Gas</label>
352
+ <input type="checkbox" id="question-electricity" name="question" value="electricity"></input>
353
+ <label for="question-electricity">Electricity</label>
354
+ </${tag}>`);
355
+
356
+ await defaultChecks(formElement);
357
+
358
+ const shadowRoot = formElement.shadowRoot;
359
+ const heading = shadowRoot.querySelector('.input-heading');
360
+ const holder = shadowRoot.querySelector('.input-holder');
361
+
362
+ expect(formElement.type).to.equal('standard', '`type` property has default value `standard`');
363
+ // eslint-disable-next-line no-unused-expressions
364
+ expect(heading).to.not.be.null;
365
+ expect(heading.textContent).to.equal('What is your heating source?', '`heading` slot has value `What is your heating source?`');
366
+ // eslint-disable-next-line no-unused-expressions
367
+ expect(holder).to.not.be.null;
368
+
369
+ const inputElement = formElement.querySelectorAll('input');
370
+ // eslint-disable-next-line no-unused-expressions
371
+ expect(inputElement).to.not.be.null;
372
+
373
+ const changeEventSpy = sinon.spy();
374
+ formElement.addEventListener('change', changeEventSpy);
375
+
376
+ // eslint-disable-next-line no-unused-expressions
377
+ expect(inputElement[0].checked).to.true;
378
+ // eslint-disable-next-line no-unused-expressions
379
+ expect(inputElement[1].checked).to.false;
380
+
381
+ inputElement[1].click();
382
+ // eslint-disable-next-line no-unused-expressions
383
+ expect(inputElement[0].checked).to.true;
384
+ // eslint-disable-next-line no-unused-expressions
385
+ expect(inputElement[1].checked).to.true;
386
+ expect(formElement.value).to.equal('gas,electricity', '`value` property has value `electricity`');
387
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
388
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('gas,electricity', '`change` event has value `electricity`');
389
+
390
+ inputElement[0].click();
391
+ // eslint-disable-next-line no-unused-expressions
392
+ expect(inputElement[0].checked).to.false;
393
+ // eslint-disable-next-line no-unused-expressions
394
+ expect(inputElement[1].checked).to.true;
395
+ expect(formElement.value).to.equal('electricity', '`value` property has value `electricity`');
396
+ expect(changeEventSpy.callCount).to.equal(2, '`change` event fired');
397
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('electricity', '`change` event has value `electricity`');
398
+ });
399
+
400
+ it('checkbox default value', async () => {
401
+ const formElement = await fixture(html`
402
+ <${tag} heading="What is your heating source?" value="gas">
403
+ <input type="checkbox" id="question-gas" name="question" value="gas"></input>
404
+ <label for="question-gas">Gas</label>
405
+ <input type="checkbox" id="question-electricity" name="question" value="electricity"></input>
406
+ <label for="question-electricity">Electricity</label>
407
+ </${tag}>`);
408
+
409
+ await defaultChecks(formElement);
410
+
411
+ const shadowRoot = formElement.shadowRoot;
412
+ const heading = shadowRoot.querySelector('.input-heading');
413
+ const holder = shadowRoot.querySelector('.input-holder');
414
+
415
+ expect(formElement.type).to.equal('standard', '`type` property has default value `standard`');
416
+ // eslint-disable-next-line no-unused-expressions
417
+ expect(heading).to.not.be.null;
418
+ expect(heading.textContent).to.equal('What is your heating source?', '`heading` slot has value `What is your heating source?`');
419
+ // eslint-disable-next-line no-unused-expressions
420
+ expect(holder).to.not.be.null;
421
+
422
+ const inputElement = formElement.querySelectorAll('input');
423
+ // eslint-disable-next-line no-unused-expressions
424
+ expect(inputElement).to.not.be.null;
425
+
426
+ const changeEventSpy = sinon.spy();
427
+ formElement.addEventListener('change', changeEventSpy);
428
+
429
+ // eslint-disable-next-line no-unused-expressions
430
+ expect(inputElement[0].checked).to.true;
431
+ // eslint-disable-next-line no-unused-expressions
432
+ expect(inputElement[1].checked).to.false;
433
+ });
434
+
435
+ it('standard select input', async () => {
436
+ const formElement = await fixture(html`
437
+ <${tag} type="select">
438
+ <label slot="label" for="select-input">What is your heating source?</label>
439
+ <select name="select" id="select-input">
440
+ <option value="">Please Select</option>
441
+ <option value="value1">One</option>
442
+ <option value="value2">Two</option>
443
+ <option value="value3">Three</option>
444
+ <option value="value4">Four</option>
445
+ </select>
446
+ </${tag}>`);
447
+
448
+ await defaultChecks(formElement);
449
+
450
+ const shadowRoot = formElement.shadowRoot;
451
+ const heading = shadowRoot.querySelector('slot[name="label"]');
452
+ const holder = shadowRoot.querySelector('.input-holder');
453
+
454
+ expect(formElement.type).to.equal('select', '`type` property has default value `standard`');
455
+ // eslint-disable-next-line no-unused-expressions
456
+ expect(heading).to.not.be.null;
457
+ expect(heading.assignedElements()[0].textContent).to.equal('What is your heating source?', '`heading` slot has value `What is your heating source?`');
458
+ // eslint-disable-next-line no-unused-expressions
459
+ expect(holder).to.not.be.null;
460
+
461
+ const selectElement = formElement.querySelector('select');
462
+ // eslint-disable-next-line no-unused-expressions
463
+ expect(selectElement).to.not.be.null;
464
+
465
+ const changeEventSpy = sinon.spy();
466
+ formElement.addEventListener('change', changeEventSpy);
467
+
468
+ await selectEvent(selectElement, 'value3');
469
+ expect(formElement.value).to.equal('value3', '`value` property has value `value3`');
470
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
471
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('value3', '`change` event has value `value3`');
472
+ });
473
+ });