@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,30 @@
1
+ <% _.forIn(properties && properties.asset && properties.asset.font, function(font) {
2
+ var fileFormatArr = [];
3
+ if (font.eot) {
4
+ fileFormatArr.push("url('" + font.eot.value + "');\n\tsrc: url('" + font.eot.value + "?#iefix') format('embedded-opentype')");
5
+ }
6
+ if (font.otf) {
7
+ fileFormatArr.push("url('" + font.otf.value + "') format('otf')");
8
+ }
9
+ if (font.ttf) {
10
+ fileFormatArr.push("url('" + font.ttf.value + "') format('truetype')");
11
+ }
12
+ if (font.svg) {
13
+ fileFormatArr.push("url('" + font.svg.value + "#" + font.name.value.replace(/ /g,'%20') + "') format('svg')");
14
+ }
15
+ if (font.woff) {
16
+ fileFormatArr.push("url('" + font.woff.value + "') format('woff')");
17
+ }
18
+ if (font.woff2) {
19
+ fileFormatArr.push("url('" + font.woff2.value + "') format('woff2')");
20
+ }
21
+ %>
22
+ @font-face {
23
+ font-family: "<%= font.name.value %>";
24
+ font-display: fallback;<% if (font.unicodeRange) { %>
25
+ unicode-range: <%= font.unicodeRange.value %>;<% } %>
26
+ src: <%= fileFormatArr.join(',\n\t\t') %>;<% if (font.style) { %>
27
+ font-style: <%= font.style.value %>;<% } if (font.weight) { %>
28
+ font-weight: <%= font.weight.value %>;<% } %>
29
+ }
30
+ <% }); %>
@@ -0,0 +1,27 @@
1
+ const chroma = require('chroma-js');
2
+
3
+ const colorTransform = (token) => {
4
+ const { value, modify = [] } = token;
5
+ let color = chroma(value);
6
+ // iterate over the modify array (see tokens/color.json)
7
+ // and apply each modification in order
8
+ modify.forEach(({ type, amount }) => {
9
+ // modifier type must match a method name in chromajs
10
+ // https://gka.github.io/chroma.js/
11
+ // chroma methods can be chained, so each time we override the color variable
12
+ // we can still call other chroma methods, similar to
13
+ // chroma(value).brighten(1).darken(1).hex();
14
+ color = color[type](amount);
15
+
16
+ });
17
+
18
+ return color.hex();
19
+ };
20
+
21
+ module.exports = {
22
+ name: 'color/css',
23
+ type: 'value',
24
+ transitive: true,
25
+ matcher: (token) => token.modify,
26
+ transformer: colorTransform
27
+ };
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ name: 'string/css',
3
+ type: 'value',
4
+ matcher: (token) => token.type === 'string',
5
+ transformer: (token) => `"${token.value}"`
6
+ };
@@ -0,0 +1,76 @@
1
+ {
2
+ "validation": {
3
+ "isRequired": {
4
+ "message": {
5
+ "description": "Display message for isRequired validation function",
6
+ "value": "This field is required"
7
+ }
8
+ },
9
+ "isNumber": {
10
+ "message": {
11
+ "description": "Display message for isNumber validation function",
12
+ "value": "Needs to be a number"
13
+ }
14
+ },
15
+ "isInteger": {
16
+ "message": {
17
+ "description": "Display message for isInteger validation function",
18
+ "value": "Needs to be a whole number"
19
+ }
20
+ },
21
+ "isEmail": {
22
+ "message": {
23
+ "description": "Display message for isEmail validation function",
24
+ "value": "Your email does not look right"
25
+ }
26
+ },
27
+ "minLength": {
28
+ "message": {
29
+ "description": "Display message for minLength validation function",
30
+ "value": "Length must be at least $min characters"
31
+ }
32
+ },
33
+ "maxLength": {
34
+ "message": {
35
+ "description": "Display message for maxLength validation function",
36
+ "value": "Length must be no longer than $max characters"
37
+ }
38
+ },
39
+ "isBetween": {
40
+ "message": {
41
+ "description": "Display message for isBetween validation function",
42
+ "value": "Length must be between $min and $max characters"
43
+ }
44
+ },
45
+ "isDate": {
46
+ "message": {
47
+ "description": "Display message for isDate validation function",
48
+ "value": "Your date does not look right"
49
+ }
50
+ },
51
+ "minDate": {
52
+ "message": {
53
+ "description": "Display message for minDate validation function",
54
+ "value": "Date must be on or after $minDate"
55
+ }
56
+ },
57
+ "maxDate": {
58
+ "message": {
59
+ "description": "Display message for maxDate validation function",
60
+ "value": "Date must be on or before $maxDate"
61
+ }
62
+ },
63
+ "hasNumbers": {
64
+ "message": {
65
+ "description": "Display message for hasNumbers validation function",
66
+ "value": "Must include at least one number"
67
+ }
68
+ },
69
+ "hasLetters": {
70
+ "message": {
71
+ "description": "Display message for hasLetters validation function",
72
+ "value": "Must include at least one letter"
73
+ }
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,31 @@
1
+ export default ({
2
+ element, // the element to scroll to
3
+ focusOn = element // optional element that gets focus
4
+ } = {}) => {
5
+ const motionQuery = window.matchMedia('(prefers-reduced-motion)');
6
+
7
+ setTimeout(function () { // Firefox needs this in order to allow the event queue to clear before scrolling
8
+ if (!motionQuery.matches) {
9
+ element.scrollIntoView({
10
+ behavior: 'smooth'
11
+ });
12
+ }
13
+ }, 0);
14
+
15
+ focusOn.focus({
16
+ preventScroll: !motionQuery.matches
17
+ });
18
+
19
+ // https://css-tricks.com/smooth-scrolling-accessibility/
20
+ // "In order for this to work on non-focusable target elements (section, div, span, h1-6, ect),
21
+ // we have to set tabindex="-1" on them"
22
+
23
+ if (focusOn !== document.activeElement) { // Checking if the target was focused
24
+ const tabIndex = focusOn.getAttribute('tabindex');
25
+ focusOn.setAttribute('tabindex', '-1'); // Adding tabindex for elements not focusable
26
+ focusOn.focus({
27
+ preventScroll: !motionQuery.matches
28
+ }); // Setting focus
29
+ focusOn.setAttribute('tabindex', tabIndex); //resetting tabindex
30
+ }
31
+ };
@@ -0,0 +1,205 @@
1
+ import {
2
+ VALIDATION_IS_REQUIRED_MESSAGE,
3
+ VALIDATION_IS_NUMBER_MESSAGE,
4
+ VALIDATION_IS_INTEGER_MESSAGE,
5
+ VALIDATION_IS_EMAIL_MESSAGE,
6
+ VALIDATION_MIN_LENGTH_MESSAGE,
7
+ VALIDATION_MAX_LENGTH_MESSAGE,
8
+ VALIDATION_IS_BETWEEN_MESSAGE,
9
+ VALIDATION_IS_DATE_MESSAGE,
10
+ VALIDATION_MIN_DATE_MESSAGE,
11
+ VALIDATION_MAX_DATE_MESSAGE,
12
+ VALIDATION_HAS_NUMBERS_MESSAGE,
13
+ VALIDATION_HAS_LETTERS_MESSAGE
14
+ } from '@muon/tokens';
15
+
16
+ const regularExpressions = {
17
+ // eslint-disable-next-line no-useless-escape
18
+ email: /^[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i
19
+ };
20
+
21
+ const withoutChar = (value, separator) => {
22
+ return value.split(separator).join('');
23
+ };
24
+
25
+ const convertIsoDate = (isoDate) => {
26
+ return isoDate.split('-').reverse().join('/');
27
+ };
28
+
29
+ const isRequired = (inputter, value) => {
30
+ return (value === undefined || value.length === 0) && VALIDATION_IS_REQUIRED_MESSAGE;
31
+ };
32
+
33
+ const isNumber = (inputter, value) => {
34
+ const number = inputter.separator ? withoutChar(value, inputter.separator) : value;
35
+ const val = Number(number);
36
+ const isNum = typeof val === 'number' && !isNaN(val);
37
+ return value.length > 0 && !isNum && VALIDATION_IS_NUMBER_MESSAGE;
38
+ };
39
+
40
+ const isInteger = (inputter, value) => {
41
+ const number = inputter.separator ? withoutChar(value, inputter.separator) : value;
42
+ const val = Number(number);
43
+ const isInt = typeof val === 'number' && isFinite(val) && Math.floor(val) === val;
44
+
45
+ return value.length > 0 && !isInt && VALIDATION_IS_INTEGER_MESSAGE;
46
+ };
47
+
48
+ const isEmail = (inputter, value) => {
49
+ const emailRegexp = new RegExp(regularExpressions.email, 'i');
50
+ return value.length > 0 && !emailRegexp.test(value) && VALIDATION_IS_EMAIL_MESSAGE;
51
+ };
52
+
53
+ const minLength = (inputter, value, min) => {
54
+ const str = inputter.separator ? withoutChar(value, inputter.separator) : value;
55
+ return value.length > 0 && str.length < min && VALIDATION_MIN_LENGTH_MESSAGE.replace('$min', min);
56
+ };
57
+
58
+ const maxLength = (inputter, value, max) => {
59
+ const str = inputter.separator ? withoutChar(value, inputter.separator) : value;
60
+ return value.length > 0 && str.length > max && VALIDATION_MAX_LENGTH_MESSAGE.replace('$max', max);
61
+ };
62
+
63
+ const isBetween = (inputter, value, min, max) => {
64
+ const str = inputter.separator ? withoutChar(value, inputter.separator) : value;
65
+ return value.length > 0 && (str.length < min || str.length > max) && VALIDATION_IS_BETWEEN_MESSAGE.replace('$min', min).replace('$max', max);
66
+ };
67
+
68
+ const stringToDate = (dateString) => {
69
+ const arr = dateString.indexOf('/') !== -1 ? dateString.split('/') : dateString.split('-');
70
+
71
+ let dayString;
72
+ let monthString;
73
+ let yearString;
74
+
75
+ if (dateString.indexOf('/') !== -1) {
76
+ dayString = arr[0];
77
+ monthString = arr[1];
78
+ yearString = arr[2];
79
+ } else {
80
+ dayString = arr[2];
81
+ monthString = arr[1];
82
+ yearString = arr[0];
83
+ }
84
+
85
+ const day = parseInt(dayString, 10);
86
+ const month = parseInt(monthString, 10) - 1;
87
+ const year = parseInt(yearString, 10);
88
+ const date = new Date(year, month, day);
89
+ return date;
90
+ };
91
+
92
+ const isDate = (inputter, dateString) => {
93
+ const isValid = (string, length, a, b) => {
94
+ return string && string.length === length && isNumeric(string) && a === b;
95
+ };
96
+
97
+ const arr = dateString.indexOf('/') !== -1 ? dateString.split('/') : dateString.split('-');
98
+
99
+ let dayString;
100
+ let monthString;
101
+ let yearString;
102
+
103
+ if (dateString.indexOf('/') !== -1) {
104
+ dayString = arr[0];
105
+ monthString = arr[1];
106
+ yearString = arr[2];
107
+ } else {
108
+ dayString = arr[2];
109
+ monthString = arr[1];
110
+ yearString = arr[0];
111
+ }
112
+
113
+ const day = parseInt(dayString, 10);
114
+ const month = parseInt(monthString, 10) - 1;
115
+ const year = parseInt(yearString, 10);
116
+
117
+ // Check formatting first
118
+ const formatValid =
119
+ dateString.length === 10 && isNumeric(dayString) && isNumeric(monthString) && isNumeric(yearString);
120
+
121
+ if (dateString.length > 0 && !formatValid) {
122
+ return VALIDATION_IS_DATE_MESSAGE;
123
+ }
124
+
125
+ // Check date is a valid date
126
+ const date = new Date(year, month, day);
127
+ const dayValid = isValid(dayString, 2, date.getDate(), day);
128
+ const monthValid = isValid(monthString, 2, date.getMonth(), month);
129
+ const yearValid = isValid(yearString, 4, date.getFullYear(), year);
130
+ const valid = dayValid && monthValid && yearValid;
131
+
132
+ return dateString.length > 0 && !valid ? VALIDATION_IS_DATE_MESSAGE : '';
133
+ };
134
+
135
+ const minDate = (inputter, value, min) => {
136
+ if (isDate(inputter, value) === '') {
137
+ const minDate = stringToDate(min);
138
+ const date = stringToDate(value);
139
+ const displayDate = convertIsoDate(min);
140
+
141
+ if (value.length > 0 && date < minDate) {
142
+ return VALIDATION_MIN_DATE_MESSAGE.replace('$minDate', displayDate);
143
+ }
144
+ }
145
+
146
+ return '';
147
+ };
148
+
149
+ const maxDate = (inputter, value, max) => {
150
+ if (isDate(inputter, value) === '') {
151
+ const maxDate = stringToDate(max);
152
+ const date = stringToDate(value);
153
+ const displayDate = convertIsoDate(max);
154
+
155
+ if (value.length > 0 && date > maxDate) {
156
+ return VALIDATION_MAX_DATE_MESSAGE.replace('$maxDate', displayDate);
157
+ }
158
+ }
159
+
160
+ return '';
161
+ };
162
+
163
+ /**
164
+ * A function to check whether the value is numeric or not.
165
+ *
166
+ * @function
167
+ * @param {string} value - value to check.
168
+ * @returns {boolean} - True or false.
169
+ * @example
170
+ * // returns false
171
+ * isNumeric('abcd');
172
+ * @example
173
+ * // returns true
174
+ * isNumeric('374');
175
+ */
176
+ function isNumeric(value) {
177
+ const regex = /[^0-9]/g;
178
+ return value && !value.match(regex);
179
+ }
180
+
181
+ const hasNumbers = (inputter, value) => {
182
+ return value.length > 0 && !/\d/.test(value) ? VALIDATION_HAS_NUMBERS_MESSAGE : '';
183
+ };
184
+
185
+ const hasLetters = (inputter, value) => {
186
+ const regExp = /[a-zA-Z]/g;
187
+ return value.length > 0 && !regExp.test(value) ? VALIDATION_HAS_LETTERS_MESSAGE : '';
188
+ };
189
+
190
+ const validations = {
191
+ isRequired,
192
+ isNumber,
193
+ isInteger,
194
+ isEmail,
195
+ minDate,
196
+ maxDate,
197
+ minLength,
198
+ maxLength,
199
+ isBetween,
200
+ isDate,
201
+ hasNumbers,
202
+ hasLetters
203
+ };
204
+
205
+ export { validations as default };
@@ -0,0 +1,123 @@
1
+ import { browserstackLauncher } from '@web/test-runner-browserstack';
2
+
3
+ import { serverPlugins } from '@muonic/muon/scripts/rollup-plugins.mjs';
4
+ import { checkRunSnapshots } from './tests/runner/commands.mjs';
5
+
6
+ // options shared between all browsers
7
+ const sharedCapabilities = {
8
+ // your username and key for browserstack, you can get this from your browserstack account
9
+ // it's recommended to store these as environment variables
10
+ 'browserstack.user': process.env.BROWSER_STACK_USERNAME,
11
+ 'browserstack.key': process.env.BROWSER_STACK_ACCESS_KEY,
12
+
13
+ project: 'Muon',
14
+ name: 'CI tests',
15
+ // if you are running tests in a CI, the build id might be available as an
16
+ // environment variable. this is useful for identifying test runs
17
+ // this is for example the name for github actions
18
+ build: `Muon ${process.env.GITHUB_RUN_NUMBER || 'unknown'}`,
19
+ };
20
+
21
+ export default {
22
+ testRunnerHtml: (testFramework) =>
23
+ `<html>
24
+ <head>
25
+ <script type="module">
26
+ import '@webcomponents/scoped-custom-element-registry';
27
+ </script>
28
+ </head>
29
+ <body>
30
+ <script>window.process = { env: { NODE_ENV: "development" } }</script>
31
+ <script type="module" src="${testFramework}"></script>
32
+ </body>
33
+ </html>`,
34
+ nodeResolve: true,
35
+ mimeTypes: {
36
+ '**/*.css': 'js'
37
+ },
38
+ plugins: [
39
+ ...serverPlugins,
40
+ checkRunSnapshots(false)
41
+ ],
42
+ // how many browsers to run concurrently in browserstack. increasing this significantly
43
+ // reduces testing time, but your subscription might limit concurrent connections
44
+ concurrentBrowsers: 2,
45
+ // amount of test files to execute concurrently in a browser. the default value is based
46
+ // on amount of available CPUs locally which is irrelevant when testing remotely
47
+ concurrency: 3,
48
+ browsers: [
49
+ // create a browser launcher per browser you want to test
50
+ // you can get the browser capabilities from the browserstack website
51
+ browserstackLauncher({
52
+ capabilities: {
53
+ ...sharedCapabilities,
54
+ browserName: 'Chrome',
55
+ os: 'Windows',
56
+ os_version: '10',
57
+ },
58
+ }),
59
+ browserstackLauncher({
60
+ capabilities: {
61
+ ...sharedCapabilities,
62
+ browserName: 'Firefox',
63
+ os: 'Windows',
64
+ os_version: '10',
65
+ },
66
+ }),
67
+ browserstackLauncher({
68
+ capabilities: {
69
+ ...sharedCapabilities,
70
+ browserName: 'Edge',
71
+ os: 'Windows',
72
+ os_version: '10',
73
+ },
74
+ }),
75
+ browserstackLauncher({
76
+ capabilities: {
77
+ ...sharedCapabilities,
78
+ browserName: 'Safari',
79
+ os: 'OS X',
80
+ os_version: 'Big Sur',
81
+ },
82
+ }),
83
+ browserstackLauncher({
84
+ capabilities: {
85
+ ...sharedCapabilities,
86
+ realMobile: true,
87
+ device: 'Google Pixel 5',
88
+ os_version: '12.0',
89
+ browserName: 'Android',
90
+ },
91
+ }),
92
+ browserstackLauncher({
93
+ capabilities: {
94
+ ...sharedCapabilities,
95
+ realMobile: true,
96
+ device: 'Samsung Galaxy S20',
97
+ os_version: '10.0',
98
+ browserName: 'Android',
99
+ },
100
+ }),
101
+ // browserstackLauncher({
102
+ // capabilities: {
103
+ // ...sharedCapabilities,
104
+ // realMobile: true,
105
+ // device: 'iPhone 13 Pro',
106
+ // os_version: '15.6',
107
+ // browserName: 'iPhone',
108
+ // },
109
+ // }),
110
+ // browserstackLauncher({
111
+ // capabilities: {
112
+ // ...sharedCapabilities,
113
+ // realMobile: true,
114
+ // device: 'iPhone SE 2020',
115
+ // os_version: '13',
116
+ // browserName: 'iPhone',
117
+ // },
118
+ // }),
119
+ ],
120
+ browserStartTimeout: 60000,
121
+ testsStartTimeout: 60000,
122
+ testsFinishTimeout: 120000,
123
+ };
@@ -0,0 +1,44 @@
1
+ import { playwrightLauncher } from '@web/test-runner-playwright';
2
+ import { serverPlugins } from '@muonic/muon/scripts/rollup-plugins.mjs';
3
+ import { checkRunSnapshots } from './tests/runner/commands.mjs';
4
+
5
+ export default {
6
+ testRunnerHtml: (testFramework) =>
7
+ `<html>
8
+ <head>
9
+ <script type="module">
10
+ import '@webcomponents/scoped-custom-element-registry';
11
+ </script>
12
+ </head>
13
+ <body>
14
+ <script>window.process = { env: { NODE_ENV: "development" } }</script>
15
+ <script type="module" src="${testFramework}"></script>
16
+ </body>
17
+ </html>`,
18
+ nodeResolve: true,
19
+ mimeTypes: {
20
+ '**/*.css': 'js'
21
+ },
22
+ browsers: [
23
+ playwrightLauncher({ product: 'chromium' }),
24
+ playwrightLauncher({ product: 'firefox' }),
25
+ playwrightLauncher({ product: 'webkit' })
26
+ ],
27
+ browserStartTimeout: 30000, // default 30000
28
+ testsStartTimeout: 20000, // default 10000
29
+ testsFinishTimeout: 60000, // default 20000
30
+ concurrentBrowsers: 2,
31
+ concurrency: 2,
32
+ plugins: [
33
+ ...serverPlugins,
34
+ checkRunSnapshots()
35
+ ],
36
+ coverageConfig: {
37
+ threshold: {
38
+ statements: 99,
39
+ branches: 99,
40
+ functions: 99,
41
+ lines: 99
42
+ }
43
+ }
44
+ };