@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,423 @@
1
+ /* eslint-disable no-undef */
2
+ import { expect, fixture, html, defineCE, unsafeStatic } from '@open-wc/testing';
3
+ import { MuonElement } from '@muonic/muon';
4
+ import sinon from 'sinon';
5
+ import { defaultChecks, fillIn, selectEvent } from '../helpers';
6
+ import { ValidationMixin } from '@muonic/muon/mixins/validation-mixin';
7
+
8
+ const MuonValidationElement = class extends ValidationMixin(MuonElement) {
9
+
10
+ get standardTemplate() {
11
+ return html `
12
+ <div class="slotted-content">
13
+ ${this._isMultiple ? this._addHeading : this._addLabel}
14
+ <div class="input-holder">
15
+ ${super.standardTemplate}
16
+ </div>
17
+ ${this.isPristine ? html`` : this._addValidationMessage}
18
+ </div>
19
+ `;
20
+ }
21
+
22
+ get customTemplate() {
23
+ return html `
24
+ <div class="slotted-content">
25
+ ${this._isMultiple ? this._addHeading : this._addLabel}
26
+ <div class="input-holder">
27
+ ${super.standardTemplate}
28
+ </div>
29
+ ${this._addValidationListMessage}
30
+ </div>
31
+ `;
32
+ }
33
+
34
+ _onChange(changeEvent) {
35
+ this._pristine = false;
36
+ super._onChange(changeEvent);
37
+ this.validate();
38
+ }
39
+
40
+ _onBlur(blurEvent) {
41
+ this._pristine = false;
42
+ super._onBlur(blurEvent);
43
+ this.validate();
44
+ }
45
+
46
+ _onInput(inputEvent) {
47
+ this._pristine = false;
48
+ super._onInput(inputEvent);
49
+ if (this.validation?.length > 0 && this._isSingle) {
50
+ if (this.value !== this._slottedValue) {
51
+ this.value = this._slottedValue;
52
+ this._fireChangeEvent();
53
+ }
54
+ this.validate();
55
+ }
56
+ }
57
+ };
58
+
59
+ const tagName = defineCE(MuonValidationElement);
60
+ const tag = unsafeStatic(tagName);
61
+
62
+ describe('form-element-validation', () => {
63
+ it('standard', async () => {
64
+ const validationElement = await fixture(html`<${tag}></${tag}>`);
65
+
66
+ await defaultChecks(validationElement);
67
+
68
+ const shadowRoot = validationElement.shadowRoot;
69
+ const holder = shadowRoot.querySelector('.input-holder');
70
+
71
+ expect(holder).to.not.be.null; // eslint-disable-line no-unused-expressions
72
+ expect(validationElement.type).to.equal('standard', '`type` property has default value `standard`');
73
+ });
74
+
75
+ it('text validation', async () => {
76
+ const formElement = await fixture(html`
77
+ <${tag} validation=["isRequired","isBetween(5,10)"] disableNative="true">
78
+ <label slot="label">input label</label>
79
+ <input type="text" value=""/>
80
+ </${tag}>`);
81
+
82
+ await defaultChecks(formElement);
83
+
84
+ const shadowRoot = formElement.shadowRoot;
85
+ const inputElement = formElement.querySelector('input');
86
+
87
+ // eslint-disable-next-line no-unused-expressions
88
+ expect(inputElement).to.not.be.null;
89
+
90
+ const changeEventSpy = sinon.spy();
91
+ formElement.addEventListener('change', changeEventSpy);
92
+
93
+ await fillIn(inputElement, 'hello');
94
+ expect(formElement.value).to.equal('hello', '`value` property has value `hello`');
95
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
96
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('hello', '`change` event has value `hello`');
97
+
98
+ await fillIn(inputElement, '');
99
+ expect(formElement.value).to.equal('', '`value` property has value ``');
100
+ expect(changeEventSpy.callCount).to.equal(2, '`change` event fired');
101
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('', '`change` event has value ``');
102
+
103
+ await formElement.updateComplete;
104
+ let validationMessage = shadowRoot.querySelector('.validation');
105
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
106
+ expect(validationMessage.textContent.trim()).to.equal('This field is required.', 'validation message has correct value');
107
+
108
+ await fillIn(inputElement, 'hello world');
109
+ expect(formElement.value).to.equal('hello world', '`value` property has value `hello world`');
110
+ expect(changeEventSpy.callCount).to.equal(3, '`change` event fired');
111
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('hello world', '`change` event has value `hello world`');
112
+
113
+ await formElement.updateComplete;
114
+ validationMessage = shadowRoot.querySelector('.validation');
115
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
116
+ expect(validationMessage.textContent.trim()).to.equal('Length must be between 5 and 10 characters.', 'validation message has correct value');
117
+ });
118
+
119
+ it('text validation on input', async () => {
120
+ const formElement = await fixture(html`
121
+ <${tag} validation=["isRequired","isBetween(5,10)"] disableNative="true">
122
+ <label slot="label">input label</label>
123
+ <input type="text" value=""/>
124
+ </${tag}>`);
125
+
126
+ await defaultChecks(formElement);
127
+
128
+ const shadowRoot = formElement.shadowRoot;
129
+ const inputElement = formElement.querySelector('input');
130
+
131
+ // eslint-disable-next-line no-unused-expressions
132
+ expect(inputElement).to.not.be.null;
133
+
134
+ const changeEventSpy = sinon.spy();
135
+ formElement.addEventListener('change', changeEventSpy);
136
+
137
+ await fillIn(inputElement, 'hello', 'input');
138
+ expect(formElement.value).to.equal('hello', '`value` property has value `hello`');
139
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
140
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('hello', '`change` event has value `hello`');
141
+
142
+ await fillIn(inputElement, '', 'input');
143
+ expect(formElement.value).to.equal('', '`value` property has value ``');
144
+ expect(changeEventSpy.callCount).to.equal(2, '`change` event fired');
145
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('', '`change` event has value ``');
146
+
147
+ await formElement.updateComplete;
148
+ let validationMessage = shadowRoot.querySelector('.validation');
149
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
150
+ expect(validationMessage.textContent.trim()).to.equal('This field is required.', 'validation message has correct value');
151
+
152
+ await fillIn(inputElement, 'hello world', 'input');
153
+ expect(formElement.value).to.equal('hello world', '`value` property has value `hello world`');
154
+ expect(changeEventSpy.callCount).to.equal(3, '`change` event fired');
155
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('hello world', '`change` event has value `hello world`');
156
+
157
+ await formElement.updateComplete;
158
+ validationMessage = shadowRoot.querySelector('.validation');
159
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
160
+ expect(validationMessage.textContent.trim()).to.equal('Length must be between 5 and 10 characters.', 'validation message has correct value');
161
+ });
162
+
163
+ it('text native validation', async () => {
164
+ const formElement = await fixture(html`
165
+ <${tag} validation=["isRequired"]>
166
+ <label slot="label">input label</label>
167
+ <input type="text" value="" required/>
168
+ </${tag}>`);
169
+
170
+ await defaultChecks(formElement);
171
+
172
+ const shadowRoot = formElement.shadowRoot;
173
+ const inputElement = formElement.querySelector('input');
174
+
175
+ // eslint-disable-next-line no-unused-expressions
176
+ expect(inputElement).to.not.be.null;
177
+
178
+ const changeEventSpy = sinon.spy();
179
+ formElement.addEventListener('change', changeEventSpy);
180
+
181
+ await fillIn(inputElement, 'hello');
182
+ expect(formElement.value).to.equal('hello', '`value` property has value `hello`');
183
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
184
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('hello', '`change` event has value `hello`');
185
+
186
+ await fillIn(inputElement, '');
187
+ expect(formElement.value).to.equal('', '`value` property has value ``');
188
+ expect(changeEventSpy.callCount).to.equal(2, '`change` event fired');
189
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('', '`change` event has value ``');
190
+
191
+ await formElement.updateComplete;
192
+ let validationMessage = shadowRoot.querySelector('.validation');
193
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
194
+ expect(validationMessage.textContent.trim().toLowerCase()).contains('this field is required', 'validation message has correct value');
195
+
196
+ await fillIn(inputElement, 'test validation');
197
+ expect(formElement.value).to.equal('test validation', '`value` property has value `test validation`');
198
+ expect(changeEventSpy.callCount).to.equal(3, '`change` event fired');
199
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('test validation', '`change` event has value `test validation`');
200
+
201
+ await formElement.updateComplete;
202
+ validationMessage = shadowRoot.querySelector('.validation');
203
+ expect(validationMessage).to.be.null; // eslint-disable-line no-unused-expressions
204
+ });
205
+
206
+ it('tel native validation', async () => {
207
+ const formElement = await fixture(html`
208
+ <${tag} validation=["isRequired"]>
209
+ <label slot="label">input label</label>
210
+ <input type="tel" value="" pattern="[0-9]{3}" title="match the pattern"/>
211
+ </${tag}>`);
212
+
213
+ await defaultChecks(formElement);
214
+
215
+ const shadowRoot = formElement.shadowRoot;
216
+ const inputElement = formElement.querySelector('input');
217
+
218
+ // eslint-disable-next-line no-unused-expressions
219
+ expect(inputElement).to.not.be.null;
220
+
221
+ const changeEventSpy = sinon.spy();
222
+ formElement.addEventListener('change', changeEventSpy);
223
+
224
+ await fillIn(inputElement, '124');
225
+ expect(formElement.value).to.equal('124', '`value` property has value `124`');
226
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
227
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('124', '`change` event has value `124`');
228
+
229
+ await fillIn(inputElement, '');
230
+ expect(formElement.value).to.equal('', '`value` property has value ``');
231
+ expect(changeEventSpy.callCount).to.equal(2, '`change` event fired');
232
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('', '`change` event has value ``');
233
+
234
+ await formElement.updateComplete;
235
+ let validationMessage = shadowRoot.querySelector('.validation');
236
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
237
+ expect(validationMessage.textContent.trim()).to.equal('This field is required.', 'validation message has correct value');
238
+
239
+ await fillIn(inputElement, '56');
240
+ expect(formElement.value).to.equal('56', '`value` property has value `56`');
241
+ expect(changeEventSpy.callCount).to.equal(3, '`change` event fired');
242
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('56', '`change` event has value `56`');
243
+
244
+ await formElement.updateComplete;
245
+ validationMessage = shadowRoot.querySelector('.validation');
246
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
247
+ expect(validationMessage.textContent.trim()).to.equal('match the pattern.', 'validation message has correct value');
248
+
249
+ });
250
+
251
+ it('text custom type validation', async () => {
252
+ const formElement = await fixture(html`
253
+ <${tag} type="custom" validation=["isRequired"]>
254
+ <label slot="label">input label</label>
255
+ <input type="text" value=""/>
256
+ </${tag}>`);
257
+
258
+ await defaultChecks(formElement);
259
+
260
+ const shadowRoot = formElement.shadowRoot;
261
+ const inputElement = formElement.querySelector('input');
262
+
263
+ // eslint-disable-next-line no-unused-expressions
264
+ expect(inputElement).to.not.be.null;
265
+
266
+ const changeEventSpy = sinon.spy();
267
+ formElement.addEventListener('change', changeEventSpy);
268
+
269
+ await fillIn(inputElement, 'hello');
270
+ expect(formElement.value).to.equal('hello', '`value` property has value `hello`');
271
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
272
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('hello', '`change` event has value `hello`');
273
+
274
+ await fillIn(inputElement, '');
275
+ expect(formElement.value).to.equal('', '`value` property has value ``');
276
+ expect(changeEventSpy.callCount).to.equal(2, '`change` event fired');
277
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('', '`change` event has value ``');
278
+
279
+ await formElement.updateComplete;
280
+ const validationMessage = shadowRoot.querySelector('.validation');
281
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
282
+ const listMessage = validationMessage.querySelectorAll('ul > li > p');
283
+ expect(listMessage[0].textContent.trim()).to.equal('This field is required.', 'validation message has correct value');
284
+ });
285
+
286
+ it('radio validation', async () => {
287
+ const formElement = await fixture(html`
288
+ <${tag} heading="What is your heating source?" validation=["isRequired"]>
289
+ <input type="radio" id="question-gas" name="question" value="gas"></input>
290
+ <label for="question-gas">Gas</label>
291
+ <input type="radio" id="question-electricity" name="question" value="electricity"></input>
292
+ <label for="question-electricity">Electricity</label>
293
+ </${tag}>`);
294
+
295
+ await defaultChecks(formElement);
296
+
297
+ const shadowRoot = formElement.shadowRoot;
298
+ const inputElement = formElement.querySelector('input');
299
+
300
+ // eslint-disable-next-line no-unused-expressions
301
+ expect(inputElement).to.not.be.null;
302
+
303
+ // eslint-disable-next-line no-unused-expressions
304
+ expect(inputElement.checked).to.false;
305
+
306
+ await inputElement.focus();
307
+ await inputElement.blur();
308
+
309
+ await formElement.updateComplete;
310
+ const validationMessage = shadowRoot.querySelector('.validation');
311
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
312
+ expect(validationMessage.textContent.trim()).to.equal('This field is required.', 'validation message has correct value');
313
+ });
314
+
315
+ it('checkbox validation', async () => {
316
+ const formElement = await fixture(html`
317
+ <${tag} heading="What is your heating source?" validation=["isRequired"]>
318
+ <input type="checkbox" id="question-gas" name="question" value="gas" checked></input>
319
+ <label for="question-gas">Gas</label>
320
+ <input type="checkbox" id="question-electricity" name="question" value="electricity"></input>
321
+ <label for="question-electricity">Electricity</label>
322
+ </${tag}>`);
323
+
324
+ await defaultChecks(formElement);
325
+
326
+ const shadowRoot = formElement.shadowRoot;
327
+ const inputElement = formElement.querySelectorAll('input');
328
+
329
+ // eslint-disable-next-line no-unused-expressions
330
+ expect(inputElement).to.not.be.null;
331
+
332
+ const changeEventSpy = sinon.spy();
333
+ formElement.addEventListener('change', changeEventSpy);
334
+
335
+ // eslint-disable-next-line no-unused-expressions
336
+ expect(inputElement[0].checked).to.true;
337
+
338
+ await inputElement[0].click();
339
+ await formElement.updateComplete;
340
+
341
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
342
+ const validationMessage = shadowRoot.querySelector('.validation');
343
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
344
+ expect(validationMessage.textContent.trim()).to.equal('This field is required.', 'validation message has correct value');
345
+ });
346
+
347
+ it('select validation', async () => {
348
+ const formElement = await fixture(html`
349
+ <${tag} validation=["isRequired"]>
350
+ <label slot="label" for="select-input">What is your heating source?</label>
351
+ <select name="select" id="select-input">
352
+ <option value="">Please Select</option>
353
+ <option value="value1">One</option>
354
+ <option value="value2">Two</option>
355
+ <option value="value3">Three</option>
356
+ <option value="value4">Four</option>
357
+ </select>
358
+ </${tag}>`);
359
+
360
+ await defaultChecks(formElement);
361
+
362
+ const shadowRoot = formElement.shadowRoot;
363
+ const selectElement = formElement.querySelector('select');
364
+ // eslint-disable-next-line no-unused-expressions
365
+ expect(selectElement).to.not.be.null;
366
+
367
+ const changeEventSpy = sinon.spy();
368
+ formElement.addEventListener('change', changeEventSpy);
369
+
370
+ await selectEvent(selectElement, '');
371
+ await formElement.updateComplete;
372
+
373
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
374
+ const validationMessage = shadowRoot.querySelector('.validation');
375
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
376
+ expect(validationMessage.textContent.trim()).to.equal('This field is required.', 'validation message has correct value');
377
+ });
378
+
379
+ it('date validation', async () => {
380
+ const formElement = await fixture(html`
381
+ <${tag} validation=["isRequired","minDate('11/11/2021')"]>
382
+ <label slot="label">input label</label>
383
+ <input type="text" value="" />
384
+ </${tag}>`);
385
+
386
+ await defaultChecks(formElement);
387
+
388
+ const shadowRoot = formElement.shadowRoot;
389
+ const inputElement = formElement.querySelector('input');
390
+
391
+ // eslint-disable-next-line no-unused-expressions
392
+ expect(inputElement).to.not.be.null;
393
+
394
+ const changeEventSpy = sinon.spy();
395
+ formElement.addEventListener('change', changeEventSpy);
396
+
397
+ await fillIn(inputElement, '12/11/2021');
398
+ await formElement.updateComplete;
399
+ expect(formElement.value).to.equal('12/11/2021', '`value` property has value `12/11/2021`');
400
+ expect(changeEventSpy.callCount).to.equal(1, '`change` event fired');
401
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('12/11/2021', '`change` event has value `12/11/2021`');
402
+
403
+ await fillIn(inputElement, '');
404
+ await formElement.updateComplete;
405
+ expect(formElement.value).to.equal('', '`value` property has value ``');
406
+ expect(changeEventSpy.callCount).to.equal(2, '`change` event fired');
407
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('', '`change` event has value ``');
408
+
409
+ let validationMessage = shadowRoot.querySelector('.validation');
410
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
411
+ expect(validationMessage.textContent.trim()).to.equal('This field is required.', 'validation message has correct value');
412
+
413
+ await fillIn(inputElement, '10/11/2021');
414
+ await formElement.updateComplete;
415
+ expect(formElement.value).to.equal('10/11/2021', '`value` property has value `10/11/2021`');
416
+ expect(changeEventSpy.callCount).to.equal(3, '`change` event fired');
417
+ expect(changeEventSpy.lastCall.args[0].detail.value).to.equal('10/11/2021', '`change` event has value `10/11/2021`');
418
+
419
+ validationMessage = shadowRoot.querySelector('.validation');
420
+ expect(validationMessage).to.not.be.null; // eslint-disable-line no-unused-expressions
421
+ expect(validationMessage.textContent.trim()).to.equal('Date must be on or after 11/11/2021.', 'validation message has correct value');
422
+ });
423
+ });
@@ -0,0 +1,19 @@
1
+ export function checkRunSnapshots(run) {
2
+ return {
3
+ name: 'check-run-snapshots',
4
+
5
+ executeCommand({ command, session }) {
6
+ if (command === 'run-snapshots') {
7
+ if (typeof run === 'boolean') {
8
+ return { run, browser: session.browser.type};
9
+ } else if (session.browser.type === 'selenium') {
10
+ return { run: false, browser: session.browser.type };
11
+ } else if (session.browser.type === 'playwright') {
12
+ return { run: true, browser: session.browser.type };
13
+ }
14
+ }
15
+
16
+ return { run: false, browser: session.browser.type };
17
+ }
18
+ };
19
+ }
@@ -0,0 +1,26 @@
1
+ import { Card } from '@muonic/muon/components/card';
2
+
3
+ /**
4
+ * A fancier version of the card.
5
+ *
6
+ * @element card
7
+ *
8
+ */
9
+
10
+ export class FancyCard extends Card {
11
+
12
+ static get properties() {
13
+ return {
14
+ fancy: { type: Boolean }
15
+ };
16
+ }
17
+
18
+ get coolBean() {
19
+ return 'cool beans';
20
+ }
21
+
22
+ something() {
23
+ return 'doing something';
24
+ }
25
+
26
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "components": {
3
+ "included": ["inputter" ,"card","image"],
4
+ "dir": "tests/scripts/utils/*-component.js"
5
+ },
6
+ "tokens": {
7
+ "dir": ["tokens/*.json"],
8
+ "theme": "default"
9
+ },
10
+ "alias": {
11
+ "@muon/utils/validation": "./utils/validation"
12
+ }
13
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "components": {
3
+ "included": ["card"]
4
+ }
5
+ }
@@ -0,0 +1 @@
1
+ console.log('test runner function');