@mui/internal-test-utils 2.0.14 → 2.0.16

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 (212) hide show
  1. package/{src/chai.types.ts → chai.types.d.ts} +7 -40
  2. package/chai.types.js +5 -0
  3. package/chaiPlugin.d.ts +4 -0
  4. package/chaiPlugin.js +287 -0
  5. package/{build/components.d.ts → components.d.ts} +18 -19
  6. package/components.js +64 -0
  7. package/createDOM.d.ts +2 -0
  8. package/{src/createDOM.js → createDOM.js} +17 -35
  9. package/createDescribe.d.ts +7 -0
  10. package/createDescribe.js +26 -0
  11. package/createRenderer.d.ts +214 -0
  12. package/createRenderer.js +428 -0
  13. package/createRenderer.test.d.ts +1 -0
  14. package/describeConformance.d.ts +200 -0
  15. package/describeConformance.js +1038 -0
  16. package/env.d.ts +1 -0
  17. package/env.js +11 -0
  18. package/esm/chai.types.d.ts +74 -0
  19. package/esm/chai.types.js +3 -0
  20. package/esm/chaiPlugin.d.ts +4 -0
  21. package/esm/chaiPlugin.js +281 -0
  22. package/esm/components.d.ts +35 -0
  23. package/esm/components.js +56 -0
  24. package/esm/createDOM.d.ts +2 -0
  25. package/esm/createDOM.js +47 -0
  26. package/esm/createDescribe.d.ts +7 -0
  27. package/esm/createDescribe.js +19 -0
  28. package/esm/createRenderer.d.ts +214 -0
  29. package/esm/createRenderer.js +390 -0
  30. package/esm/createRenderer.test.d.ts +1 -0
  31. package/esm/describeConformance.d.ts +200 -0
  32. package/esm/describeConformance.js +1024 -0
  33. package/esm/env.d.ts +1 -0
  34. package/esm/env.js +5 -0
  35. package/{build → esm}/fireDiscreteEvent.d.ts +1 -2
  36. package/{src/fireDiscreteEvent.ts → esm/fireDiscreteEvent.js} +10 -18
  37. package/esm/flushMicrotasks.d.ts +1 -0
  38. package/{src/flushMicrotasks.ts → esm/flushMicrotasks.js} +2 -3
  39. package/{build → esm}/focusVisible.d.ts +1 -2
  40. package/{src/focusVisible.ts → esm/focusVisible.js} +10 -9
  41. package/esm/index.d.ts +18 -0
  42. package/esm/index.js +27 -0
  43. package/esm/init.d.ts +1 -0
  44. package/{src → esm}/init.js +4 -2
  45. package/esm/initMatchers.d.ts +1 -0
  46. package/esm/initMatchers.js +6 -0
  47. package/esm/initMatchers.test.d.ts +1 -0
  48. package/esm/initPlaywrightMatchers.d.ts +24 -0
  49. package/esm/initPlaywrightMatchers.js +40 -0
  50. package/esm/package.json +1 -0
  51. package/esm/reactMajor.d.ts +2 -0
  52. package/esm/reactMajor.js +2 -0
  53. package/esm/setup.d.ts +1 -0
  54. package/{src → esm}/setup.js +2 -4
  55. package/esm/setupVitest.d.ts +1 -0
  56. package/esm/setupVitest.js +28 -0
  57. package/esm/setupVitestBrowser.d.ts +1 -0
  58. package/esm/setupVitestBrowser.js +30 -0
  59. package/fireDiscreteEvent.d.ts +6 -0
  60. package/fireDiscreteEvent.js +79 -0
  61. package/flushMicrotasks.d.ts +1 -0
  62. package/flushMicrotasks.js +10 -0
  63. package/focusVisible.d.ts +7 -0
  64. package/focusVisible.js +44 -0
  65. package/index.d.ts +18 -0
  66. package/index.js +139 -0
  67. package/init.d.ts +1 -0
  68. package/init.js +15 -0
  69. package/initMatchers.d.ts +1 -0
  70. package/initMatchers.js +10 -0
  71. package/initMatchers.test.d.ts +1 -0
  72. package/initPlaywrightMatchers.d.ts +24 -0
  73. package/initPlaywrightMatchers.js +42 -0
  74. package/package.json +89 -46
  75. package/reactMajor.d.ts +2 -0
  76. package/reactMajor.js +9 -0
  77. package/setup.d.ts +1 -0
  78. package/setup.js +10 -0
  79. package/setupVitest.d.ts +1 -0
  80. package/setupVitest.js +32 -0
  81. package/setupVitestBrowser.d.ts +1 -0
  82. package/setupVitestBrowser.js +34 -0
  83. package/build/.tsbuildinfo +0 -1
  84. package/build/KarmaReporterReactProfiler.d.ts +0 -51
  85. package/build/KarmaReporterReactProfiler.d.ts.map +0 -1
  86. package/build/KarmaReporterReactProfiler.js +0 -66
  87. package/build/KarmaReporterReactProfiler.js.map +0 -1
  88. package/build/chai.types.d.ts +0 -75
  89. package/build/chai.types.d.ts.map +0 -1
  90. package/build/chai.types.js +0 -3
  91. package/build/chai.types.js.map +0 -1
  92. package/build/chaiPlugin.d.ts +0 -5
  93. package/build/chaiPlugin.d.ts.map +0 -1
  94. package/build/chaiPlugin.js +0 -417
  95. package/build/chaiPlugin.js.map +0 -1
  96. package/build/components.d.ts.map +0 -1
  97. package/build/components.js +0 -88
  98. package/build/components.js.map +0 -1
  99. package/build/createDOM.d.ts +0 -3
  100. package/build/createDOM.d.ts.map +0 -1
  101. package/build/createDOM.js +0 -60
  102. package/build/createDOM.js.map +0 -1
  103. package/build/createDescribe.d.ts +0 -8
  104. package/build/createDescribe.d.ts.map +0 -1
  105. package/build/createDescribe.js +0 -22
  106. package/build/createDescribe.js.map +0 -1
  107. package/build/createRenderer.d.ts +0 -215
  108. package/build/createRenderer.d.ts.map +0 -1
  109. package/build/createRenderer.js +0 -565
  110. package/build/createRenderer.js.map +0 -1
  111. package/build/createRenderer.test.d.ts +0 -2
  112. package/build/createRenderer.test.d.ts.map +0 -1
  113. package/build/createRenderer.test.js +0 -58
  114. package/build/createRenderer.test.js.map +0 -1
  115. package/build/describeConformance.d.ts +0 -201
  116. package/build/describeConformance.d.ts.map +0 -1
  117. package/build/describeConformance.js +0 -859
  118. package/build/describeConformance.js.map +0 -1
  119. package/build/describeSkipIf.d.ts +0 -4
  120. package/build/describeSkipIf.d.ts.map +0 -1
  121. package/build/describeSkipIf.js +0 -10
  122. package/build/describeSkipIf.js.map +0 -1
  123. package/build/fireDiscreteEvent.d.ts.map +0 -1
  124. package/build/fireDiscreteEvent.js +0 -77
  125. package/build/fireDiscreteEvent.js.map +0 -1
  126. package/build/flushMicrotasks.d.ts +0 -2
  127. package/build/flushMicrotasks.d.ts.map +0 -1
  128. package/build/flushMicrotasks.js +0 -8
  129. package/build/flushMicrotasks.js.map +0 -1
  130. package/build/focusVisible.d.ts.map +0 -1
  131. package/build/focusVisible.js +0 -38
  132. package/build/focusVisible.js.map +0 -1
  133. package/build/index.d.ts +0 -18
  134. package/build/index.d.ts.map +0 -1
  135. package/build/index.js +0 -68
  136. package/build/index.js.map +0 -1
  137. package/build/init.d.ts +0 -2
  138. package/build/init.d.ts.map +0 -1
  139. package/build/init.js +0 -46
  140. package/build/init.js.map +0 -1
  141. package/build/initMatchers.d.ts +0 -2
  142. package/build/initMatchers.d.ts.map +0 -1
  143. package/build/initMatchers.js +0 -45
  144. package/build/initMatchers.js.map +0 -1
  145. package/build/initMatchers.test.d.ts +0 -2
  146. package/build/initMatchers.test.d.ts.map +0 -1
  147. package/build/initMatchers.test.js +0 -101
  148. package/build/initMatchers.test.js.map +0 -1
  149. package/build/initPlaywrightMatchers.d.ts +0 -25
  150. package/build/initPlaywrightMatchers.d.ts.map +0 -1
  151. package/build/initPlaywrightMatchers.js +0 -73
  152. package/build/initPlaywrightMatchers.js.map +0 -1
  153. package/build/mochaHooks.d.ts +0 -24
  154. package/build/mochaHooks.d.ts.map +0 -1
  155. package/build/mochaHooks.js +0 -165
  156. package/build/mochaHooks.js.map +0 -1
  157. package/build/mochaHooks.test.d.ts +0 -2
  158. package/build/mochaHooks.test.d.ts.map +0 -1
  159. package/build/mochaHooks.test.js +0 -127
  160. package/build/mochaHooks.test.js.map +0 -1
  161. package/build/reactMajor.d.ts +0 -3
  162. package/build/reactMajor.d.ts.map +0 -1
  163. package/build/reactMajor.js +0 -38
  164. package/build/reactMajor.js.map +0 -1
  165. package/build/setup.d.ts +0 -2
  166. package/build/setup.d.ts.map +0 -1
  167. package/build/setup.js +0 -10
  168. package/build/setup.js.map +0 -1
  169. package/build/setupBabel.d.ts +0 -2
  170. package/build/setupBabel.d.ts.map +0 -1
  171. package/build/setupBabel.js +0 -5
  172. package/build/setupBabel.js.map +0 -1
  173. package/build/setupBabelPlaywright.d.ts +0 -2
  174. package/build/setupBabelPlaywright.d.ts.map +0 -1
  175. package/build/setupBabelPlaywright.js +0 -14
  176. package/build/setupBabelPlaywright.js.map +0 -1
  177. package/build/setupJSDOM.d.ts +0 -7
  178. package/build/setupJSDOM.d.ts.map +0 -1
  179. package/build/setupJSDOM.js +0 -17
  180. package/build/setupJSDOM.js.map +0 -1
  181. package/build/setupKarma.d.ts +0 -2
  182. package/build/setupKarma.d.ts.map +0 -1
  183. package/build/setupKarma.js +0 -56
  184. package/build/setupKarma.js.map +0 -1
  185. package/build/setupVitest.d.ts +0 -2
  186. package/build/setupVitest.d.ts.map +0 -1
  187. package/build/setupVitest.js +0 -131
  188. package/build/setupVitest.js.map +0 -1
  189. package/src/KarmaReporterReactProfiler.js +0 -82
  190. package/src/chai-augmentation.d.ts +0 -8
  191. package/src/chaiPlugin.ts +0 -516
  192. package/src/components.tsx +0 -61
  193. package/src/createDOM.d.ts +0 -9
  194. package/src/createDescribe.ts +0 -31
  195. package/src/createRenderer.test.js +0 -31
  196. package/src/createRenderer.tsx +0 -809
  197. package/src/describeConformance.tsx +0 -1257
  198. package/src/describeSkipIf.tsx +0 -11
  199. package/src/index.ts +0 -25
  200. package/src/initMatchers.test.js +0 -124
  201. package/src/initMatchers.ts +0 -7
  202. package/src/initPlaywrightMatchers.ts +0 -101
  203. package/src/mochaHooks.js +0 -200
  204. package/src/mochaHooks.test.js +0 -115
  205. package/src/reactMajor.ts +0 -3
  206. package/src/setupBabel.js +0 -3
  207. package/src/setupBabelPlaywright.js +0 -13
  208. package/src/setupJSDOM.js +0 -20
  209. package/src/setupKarma.js +0 -65
  210. package/src/setupVitest.ts +0 -117
  211. package/tsconfig.build.json +0 -16
  212. package/tsconfig.json +0 -17
package/src/chaiPlugin.ts DELETED
@@ -1,516 +0,0 @@
1
- import { isInaccessible } from '@testing-library/dom';
2
- import { prettyDOM } from '@testing-library/react/pure';
3
- import * as chai from 'chai';
4
- import { computeAccessibleDescription, computeAccessibleName } from 'dom-accessibility-api';
5
- import formatUtil from 'format-util';
6
- // avoid loading whole lodash, it takes ~50ms to initialize
7
- import kebabCase from 'lodash.kebabcase';
8
- import './chai.types';
9
-
10
- const isKarma = Boolean(process.env.KARMA);
11
-
12
- function isInJSDOM() {
13
- return window.navigator.userAgent.includes('jsdom');
14
- }
15
-
16
- // chai#utils.elToString that looks like stringified elements in testing-library
17
- function elementToString(element: Element | null | undefined) {
18
- if (typeof element?.nodeType === 'number') {
19
- return prettyDOM(element, undefined, { highlight: !isKarma, maxDepth: 1 });
20
- }
21
- return String(element);
22
- }
23
-
24
- const chaiPlugin: Parameters<typeof chai.use>[0] = (chaiAPI, utils) => {
25
- const blockElements = new Set([
26
- 'html',
27
- 'address',
28
- 'blockquote',
29
- 'body',
30
- 'dd',
31
- 'div',
32
- 'dl',
33
- 'dt',
34
- 'fieldset',
35
- 'form',
36
- 'frame',
37
- 'frameset',
38
- 'h1',
39
- 'h2',
40
- 'h3',
41
- 'h4',
42
- 'h5',
43
- 'h6',
44
- 'noframes',
45
- 'ol',
46
- 'p',
47
- 'ul',
48
- 'center',
49
- 'dir',
50
- 'hr',
51
- 'menu',
52
- 'pre',
53
- ]);
54
-
55
- function pretendVisibleGetComputedStyle(element: Element): CSSStyleDeclaration {
56
- // `CSSStyleDeclaration` is not constructable
57
- // https://stackoverflow.com/a/52732909/3406963
58
- // this is not equivalent to the declaration from `getComputedStyle`
59
- // for example `getComputedStyle` would return a readonly declaration
60
- // let's hope this doesn't get passed around until it's no longer clear where it comes from
61
- const declaration = document.createElement('span').style;
62
-
63
- // initial values
64
- declaration.content = '';
65
- // technically it's `inline`. We partially apply the default user agent sheet (chrome) here
66
- // we're only interested in elements that use block
67
- declaration.display = blockElements.has(element.tagName) ? 'block' : 'inline';
68
- declaration.visibility = 'visible';
69
-
70
- return declaration;
71
- }
72
-
73
- // better diff view for expect(element).to.equal(document.activeElement)
74
- chaiAPI.Assertion.addMethod('toHaveFocus', function elementIsFocused() {
75
- const element = utils.flag(this, 'object');
76
-
77
- this.assert(
78
- element === document.activeElement,
79
- // karma does not show the diff like mocha does
80
- `expected element to have focus${isKarma ? '\nexpected #{exp}\nactual: #{act}' : ''}`,
81
- `expected element to NOT have focus \n${elementToString(element)}`,
82
- elementToString(element),
83
- elementToString(document.activeElement),
84
- );
85
- });
86
-
87
- chaiAPI.Assertion.addMethod('toHaveVirtualFocus', function elementIsVirtuallyFocused() {
88
- const element = utils.flag(this, 'object');
89
- const id = element.getAttribute('id');
90
-
91
- const virtuallyFocusedElementId = document.activeElement!.getAttribute('aria-activedescendant');
92
-
93
- this.assert(
94
- virtuallyFocusedElementId === id,
95
- `expected element to be virtually focused\nexpected id #{exp}\n${
96
- virtuallyFocusedElementId === null
97
- ? `activeElement: ${elementToString(document.activeElement)}`
98
- : 'actual id: #{act}'
99
- }`,
100
- 'expected element to NOT to be virtually focused',
101
- id,
102
- virtuallyFocusedElementId,
103
- virtuallyFocusedElementId !== null,
104
- );
105
- });
106
-
107
- chaiAPI.Assertion.addMethod('toBeInaccessible', function elementIsAccessible() {
108
- const element = utils.flag(this, 'object');
109
-
110
- const inaccessible = isInaccessible(element);
111
-
112
- this.assert(
113
- inaccessible === true,
114
- `expected \n${elementToString(element)} to be inaccessible but it was accessible`,
115
- `expected \n${elementToString(element)} to be accessible but it was inaccessible`,
116
- // Not interested in a diff but the typings require the 4th parameter.
117
- undefined,
118
- );
119
- });
120
-
121
- chaiAPI.Assertion.addMethod('toHaveAccessibleName', function hasAccessibleName(expectedName) {
122
- const root = utils.flag(this, 'object');
123
- // make sure it's an Element
124
- new chaiAPI.Assertion(root.nodeType, `Expected an Element but got '${String(root)}'`).to.equal(
125
- 1,
126
- );
127
-
128
- const actualName = computeAccessibleName(root, {
129
- computedStyleSupportsPseudoElements: !isInJSDOM(),
130
- // in local development we pretend to be visible. full getComputedStyle is
131
- // expensive and reserved for CI
132
- getComputedStyle: process.env.CI ? undefined : pretendVisibleGetComputedStyle,
133
- });
134
-
135
- this.assert(
136
- actualName === expectedName,
137
- `expected \n${elementToString(root)} to have accessible name #{exp} but got #{act} instead.`,
138
- `expected \n${elementToString(root)} not to have accessible name #{exp}.`,
139
- expectedName,
140
- actualName,
141
- );
142
- });
143
-
144
- chaiAPI.Assertion.addMethod(
145
- 'toHaveAccessibleDescription',
146
- function hasAccessibleDescription(expectedDescription) {
147
- const root = utils.flag(this, 'object');
148
- // make sure it's an Element
149
- new chaiAPI.Assertion(
150
- root.nodeType,
151
- `Expected an Element but got '${String(root)}'`,
152
- ).to.equal(1);
153
-
154
- const actualDescription = computeAccessibleDescription(root, {
155
- // in local development we pretend to be visible. full getComputedStyle is
156
- // expensive and reserved for CI
157
- getComputedStyle: process.env.CI ? undefined : pretendVisibleGetComputedStyle,
158
- });
159
-
160
- const possibleDescriptionComputationMessage = root.hasAttribute('title')
161
- ? ' computeAccessibleDescription can be misleading when a `title` attribute is used. This might be a bug in `dom-accessibility-api`.'
162
- : '';
163
- this.assert(
164
- actualDescription === expectedDescription,
165
- `expected \n${elementToString(
166
- root,
167
- )} to have accessible description #{exp} but got #{act} instead.${possibleDescriptionComputationMessage}`,
168
- `expected \n${elementToString(
169
- root,
170
- )} not to have accessible description #{exp}.${possibleDescriptionComputationMessage}`,
171
- expectedDescription,
172
- actualDescription,
173
- );
174
- },
175
- );
176
-
177
- /**
178
- * Correct name for `to.be.visible`
179
- */
180
- chaiAPI.Assertion.addMethod('toBeVisible', function toBeVisible() {
181
- // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-unused-expressions
182
- new chaiAPI.Assertion(this._obj).to.be.visible;
183
- });
184
-
185
- /**
186
- * Correct name for `not.to.be.visible`
187
- */
188
- chaiAPI.Assertion.addMethod('toBeHidden', function toBeHidden() {
189
- // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-unused-expressions
190
- new chaiAPI.Assertion(this._obj).not.to.be.visible;
191
- });
192
-
193
- function assertMatchingStyles(
194
- this: Chai.AssertionStatic,
195
- actualStyleDeclaration: CSSStyleDeclaration,
196
- expectedStyleUnnormalized: Record<string, string>,
197
- options: { styleTypeHint: string },
198
- ): void {
199
- const { styleTypeHint } = options;
200
-
201
- // Compare objects using hyphen case.
202
- // This is closer to actual CSS and required for getPropertyValue anyway.
203
- const expectedStyle: Record<string, string> = {};
204
- Object.keys(expectedStyleUnnormalized).forEach((cssProperty) => {
205
- const hyphenCasedPropertyName = kebabCase(cssProperty);
206
- const isVendorPrefixed = /^(moz|ms|o|webkit)-/.test(hyphenCasedPropertyName);
207
- const propertyName = isVendorPrefixed
208
- ? `-${hyphenCasedPropertyName}`
209
- : hyphenCasedPropertyName;
210
- expectedStyle[propertyName] = expectedStyleUnnormalized[cssProperty];
211
- });
212
-
213
- const shorthandProperties = new Set([
214
- 'all',
215
- 'animation',
216
- 'background',
217
- 'border',
218
- 'border-block-end',
219
- 'border-block-start',
220
- 'border-bottom',
221
- 'border-color',
222
- 'border-image',
223
- 'border-inline-end',
224
- 'border-inline-start',
225
- 'border-left',
226
- 'border-radius',
227
- 'border-right',
228
- 'border-style',
229
- 'border-top',
230
- 'border-width',
231
- 'column-rule',
232
- 'columns',
233
- 'flex',
234
- 'flex-flow',
235
- 'font',
236
- 'gap',
237
- 'grid',
238
- 'grid-area',
239
- 'grid-column',
240
- 'grid-row',
241
- 'grid-template',
242
- 'list-style',
243
- 'margin',
244
- 'mask',
245
- 'offset',
246
- 'outline',
247
- 'overflow',
248
- 'padding',
249
- 'place-content',
250
- 'place-items',
251
- 'place-self',
252
- 'scroll-margin',
253
- 'scroll-padding',
254
- 'text-decoration',
255
- 'text-emphasis',
256
- 'transition',
257
- ]);
258
- const usedShorthandProperties = Object.keys(expectedStyle).filter((cssProperty) => {
259
- return shorthandProperties.has(cssProperty);
260
- });
261
- if (usedShorthandProperties.length > 0) {
262
- throw new Error(
263
- [
264
- `Shorthand properties are not supported in ${styleTypeHint} styles matchers since browsers can compute them differently. `,
265
- 'Use longhand properties instead for the follow shorthand properties:\n',
266
- usedShorthandProperties
267
- .map((cssProperty) => {
268
- return `- https://developer.mozilla.org/en-US/docs/Web/CSS/${cssProperty}#constituent_properties`;
269
- })
270
- .join('\n'),
271
- ].join(''),
272
- );
273
- }
274
-
275
- const actualStyle: Record<string, string> = {};
276
- Object.keys(expectedStyle).forEach((cssProperty) => {
277
- actualStyle[cssProperty] = actualStyleDeclaration.getPropertyValue(cssProperty);
278
- });
279
-
280
- const jsdomHint =
281
- 'Styles in JSDOM e.g. from `test:unit` are often misleading since JSDOM does not implement the Cascade nor actual CSS property value computation. ' +
282
- 'If results differ between real browsers and JSDOM, skip the test in JSDOM e.g. `if (window.navigator.userAgent.includes("jsdom")) this.skip();`';
283
- const shorthandHint =
284
- 'Browsers can compute shorthand properties differently. Prefer longhand properties e.g. `borderTopColor`, `borderRightColor` etc. instead of `border` or `border-color`.';
285
- const messageHint = `${jsdomHint}\n${shorthandHint}`;
286
-
287
- if (isKarma) {
288
- // `#{exp}` and `#{act}` placeholders escape the newlines
289
- const expected = JSON.stringify(expectedStyle, null, 2);
290
- const actual = JSON.stringify(actualStyle, null, 2);
291
- // karma's `dots` reporter does not support diffs
292
- this.assert(
293
- // TODO Fix upstream docs/types
294
- (utils as any).eql(actualStyle, expectedStyle),
295
- `expected ${styleTypeHint} style of #{this} did not match\nExpected:\n${expected}\nActual:\n${actual}\n\n\n${messageHint}`,
296
- `expected #{this} to not have ${styleTypeHint} style\n${expected}\n\n\n${messageHint}`,
297
- expectedStyle,
298
- actualStyle,
299
- );
300
- } else {
301
- this.assert(
302
- // TODO Fix upstream docs/types
303
- (utils as any).eql(actualStyle, expectedStyle),
304
- `expected #{this} to have ${styleTypeHint} style #{exp} \n\n${messageHint}`,
305
- `expected #{this} not to have ${styleTypeHint} style #{exp}${messageHint}`,
306
- expectedStyle,
307
- actualStyle,
308
- true,
309
- );
310
- }
311
- }
312
-
313
- chaiAPI.Assertion.addMethod(
314
- 'toHaveInlineStyle',
315
- function toHaveInlineStyle(expectedStyleUnnormalized: Record<string, string>) {
316
- const element = utils.flag(this, 'object') as HTMLElement;
317
- if (element?.nodeType !== 1) {
318
- // Same pre-condition for negated and unnegated assertion
319
- throw new chai.AssertionError(`Expected an Element but got ${String(element)}`);
320
- }
321
-
322
- assertMatchingStyles.call(this, element.style, expectedStyleUnnormalized, {
323
- styleTypeHint: 'inline',
324
- });
325
- },
326
- );
327
-
328
- chaiAPI.Assertion.addMethod(
329
- 'toHaveComputedStyle',
330
- function toHaveComputedStyle(expectedStyleUnnormalized: Record<string, string>) {
331
- const element = utils.flag(this, 'object') as HTMLElement;
332
- if (element?.nodeType !== 1) {
333
- // Same pre-condition for negated and unnegated assertion
334
- throw new chai.AssertionError(`Expected an Element but got ${String(element)}`);
335
- }
336
- const computedStyle = element.ownerDocument.defaultView!.getComputedStyle(element);
337
-
338
- assertMatchingStyles.call(this, computedStyle, expectedStyleUnnormalized, {
339
- styleTypeHint: 'computed',
340
- });
341
- },
342
- );
343
-
344
- chaiAPI.Assertion.addMethod('toThrowMinified', function toThrowMinified(expectedDevMessage) {
345
- // TODO: Investigate if `as any` can be removed after https://github.com/DefinitelyTyped/DefinitelyTyped/issues/48634 is resolved.
346
- if (process.env.NODE_ENV !== 'production') {
347
- (this as any).to.throw(expectedDevMessage);
348
- } else {
349
- utils.flag(
350
- this,
351
- 'message',
352
- "Looks like the error was not minified. This can happen if the error code hasn't been generated yet. Run `pnpm extract-error-codes` and try again.",
353
- );
354
- // TODO: Investigate if `as any` can be removed after https://github.com/DefinitelyTyped/DefinitelyTyped/issues/48634 is resolved.
355
- (this as any).to.throw('Minified MUI error', 'helper');
356
- }
357
- });
358
-
359
- function addConsoleMatcher(matcherName: string, methodName: 'error' | 'warn') {
360
- /**
361
- * @param {string[]} expectedMessages
362
- */
363
- function matcher(this: Chai.AssertionStatic, expectedMessagesInput = []) {
364
- // documented pattern to get the actual value of the assertion
365
- // eslint-disable-next-line no-underscore-dangle
366
- const callback = this._obj;
367
-
368
- if (process.env.NODE_ENV !== 'production') {
369
- const expectedMessages =
370
- typeof expectedMessagesInput === 'string'
371
- ? [expectedMessagesInput]
372
- : expectedMessagesInput.slice();
373
- const unexpectedMessages: Error[] = [];
374
- // TODO Remove type once MUI X enables noImplicitAny
375
- let caughtError: unknown | null = null;
376
-
377
- this.assert(
378
- expectedMessages.length > 0,
379
- `Expected to call console.${methodName} but didn't provide messages. ` +
380
- `If you don't expect any messages prefer \`expect().not.${matcherName}();\`.`,
381
- `Expected no call to console.${methodName} while also expecting messages.` +
382
- 'Expected no call to console.error but provided messages. ' +
383
- "If you want to make sure a certain message isn't logged prefer the positive. " +
384
- 'By expecting certain messages you automatically expect that no other messages are logged',
385
- // Not interested in a diff but the typings require the 4th parameter.
386
- undefined,
387
- );
388
-
389
- // Ignore skipped messages in e.g. `[condition && 'foo']`
390
- const remainingMessages = expectedMessages.filter((messageOrFalse) => {
391
- return messageOrFalse !== false;
392
- });
393
-
394
- // eslint-disable-next-line no-console
395
- const originalMethod = console[methodName];
396
-
397
- let messagesMatched = 0;
398
- const consoleMatcher = (format: string, ...args: readonly unknown[]) => {
399
- // Ignore legacy root deprecation warnings
400
- // TODO: Remove once we no longer use legacy roots.
401
- if (
402
- format.includes('Use createRoot instead.') ||
403
- format.includes('Use hydrateRoot instead.')
404
- ) {
405
- return;
406
- }
407
- const actualMessage = formatUtil(format, ...args);
408
- const expectedMessage = remainingMessages.shift();
409
- messagesMatched += 1;
410
-
411
- // TODO Remove type once MUI X enables noImplicitAny
412
- let message: string | null = null;
413
- if (expectedMessage === undefined) {
414
- message = `Expected no more error messages but got:\n"${actualMessage}"`;
415
- } else if (!actualMessage.includes(expectedMessage)) {
416
- message = `Expected #${messagesMatched} "${expectedMessage}" to be included in \n"${actualMessage}"`;
417
- }
418
-
419
- if (message !== null) {
420
- const error = new Error(message);
421
-
422
- const { stack: fullStack } = error;
423
- const fullStacktrace = fullStack!.replace(`Error: ${message}\n`, '').split('\n');
424
-
425
- const usefulStacktrace = fullStacktrace
426
- //
427
- // first line points to this frame which is irrelevant for the tester
428
- .slice(1);
429
- const usefulStack = `${message}\n${usefulStacktrace.join('\n')}`;
430
-
431
- error.stack = usefulStack;
432
- unexpectedMessages.push(error);
433
- }
434
- };
435
- // eslint-disable-next-line no-console
436
- console[methodName] = consoleMatcher;
437
-
438
- try {
439
- callback();
440
- } catch (error) {
441
- caughtError = error;
442
- } finally {
443
- // eslint-disable-next-line no-console
444
- console[methodName] = originalMethod;
445
-
446
- // unexpected thrown error takes precedence over unexpected console call
447
- if (caughtError !== null) {
448
- // not the same pattern as described in the block because we don't rethrow in the catch
449
- // eslint-disable-next-line no-unsafe-finally
450
- throw caughtError;
451
- }
452
-
453
- const formatMessages = (messages: ReadonlyArray<Error | string>) => {
454
- const formattedMessages = messages.map((message) => {
455
- if (typeof message === 'string') {
456
- return `"${message}"`;
457
- }
458
- // full Error
459
- return `${message.stack}`;
460
- });
461
- return `\n\n - ${formattedMessages.join('\n\n- ')}`;
462
- };
463
-
464
- const shouldHaveWarned = utils.flag(this, 'negate') !== true;
465
-
466
- // unreachable from expect().not.toWarnDev(messages)
467
- if (unexpectedMessages.length > 0) {
468
- const unexpectedMessageRecordedMessage = `Recorded unexpected console.${methodName} calls: ${formatMessages(
469
- unexpectedMessages,
470
- )}`;
471
- // chai will duplicate the stack frames from the unexpected calls in their assertion error
472
- // it's not ideal but the test failure is located the second to last stack frame
473
- // and the origin of the call is the second stackframe in the stack
474
- this.assert(
475
- // force chai to always trigger an assertion error
476
- !shouldHaveWarned,
477
- unexpectedMessageRecordedMessage,
478
- unexpectedMessageRecordedMessage,
479
- // Not interested in a diff but the typings require the 4th parameter.
480
- undefined,
481
- );
482
- }
483
-
484
- if (shouldHaveWarned) {
485
- this.assert(
486
- remainingMessages.length === 0,
487
- `Could not match the following console.${methodName} calls. ` +
488
- `Make sure previous actions didn't call console.${methodName} by wrapping them in expect(() => {}).not.${matcherName}(): ${formatMessages(
489
- remainingMessages,
490
- )}`,
491
- `Impossible state reached in \`expect().${matcherName}()\`. ` +
492
- `This is a bug in the matcher.`,
493
- // Not interested in a diff but the typings require the 4th parameter.
494
- undefined,
495
- );
496
- }
497
- }
498
- } else {
499
- // nothing to do in prod
500
- // If there are still console calls than our test setup throws.
501
- callback();
502
- }
503
- }
504
-
505
- chaiAPI.Assertion.addMethod(matcherName, matcher);
506
- }
507
-
508
- /**
509
- * @example expect(() => render()).toWarnDev('single message')
510
- * @example expect(() => render()).toWarnDev(['first warning', 'then the second'])
511
- */
512
- addConsoleMatcher('toWarnDev', 'warn');
513
- addConsoleMatcher('toErrorDev', 'error');
514
- };
515
-
516
- export default chaiPlugin;
@@ -1,61 +0,0 @@
1
- import * as React from 'react';
2
- import PropTypes from 'prop-types';
3
-
4
- /**
5
- * A basic error boundary that can be used to assert thrown errors in render.
6
- * @example <ErrorBoundary ref={errorRef}><MyComponent /></ErrorBoundary>;
7
- * expect(errorRef.current.errors).to.have.length(0);
8
- */
9
- export class ErrorBoundary extends React.Component<{ children: React.ReactNode }> {
10
- static propTypes = {
11
- children: PropTypes.node.isRequired,
12
- };
13
-
14
- state = {
15
- error: null,
16
- };
17
-
18
- /**
19
- * @public
20
- */
21
- errors: unknown[] = [];
22
-
23
- static getDerivedStateFromError(error: unknown) {
24
- return { error };
25
- }
26
-
27
- componentDidCatch(error: unknown) {
28
- this.errors.push(error);
29
- }
30
-
31
- render() {
32
- if (this.state.error) {
33
- return null;
34
- }
35
- return this.props.children;
36
- }
37
- }
38
-
39
- /**
40
- * Allows counting how many times the owner of `RenderCounter` rendered or
41
- * a component within the RenderCounter tree "commits" an update.
42
- * @example <RenderCounter ref={getRenderCountRef}>...</RenderCounter>
43
- * getRenderCountRef.current() === 2
44
- */
45
- export const RenderCounter = React.forwardRef<() => number, { children: React.ReactNode }>(
46
- function RenderCounter({ children }, ref) {
47
- const getRenderCountRef = React.useRef(0);
48
- React.useImperativeHandle(ref, () => () => getRenderCountRef.current);
49
-
50
- return (
51
- <React.Profiler
52
- id="render-counter"
53
- onRender={() => {
54
- getRenderCountRef.current += 1;
55
- }}
56
- >
57
- {children}
58
- </React.Profiler>
59
- );
60
- },
61
- );
@@ -1,9 +0,0 @@
1
- // there's probably a broader solution e.g. levering DOMWindow from 'jsdom'
2
- // interface Window extends DOMWindow doesn't work because jsdom typings use
3
- // triple slash directives. Technical dom.lib.d.ts should already have these properties
4
- interface Window {
5
- DragEvent: typeof DragEvent;
6
- Event: typeof Event;
7
- HTMLButtonElement: HTMLButtonElement;
8
- HTMLParagraphElement: HTMLParagraphElement;
9
- }
@@ -1,31 +0,0 @@
1
- /* eslint-env mocha */
2
-
3
- type MUIDescribe<P extends any[]> = {
4
- (...args: P): void;
5
-
6
- skip: (...args: P) => void;
7
- only: (...args: P) => void;
8
- };
9
- export default <P extends any[]>(
10
- message: string,
11
- callback: (...args: P) => void,
12
- ): MUIDescribe<P> => {
13
- const muiDescribe = (...args: P) => {
14
- describe(message, () => {
15
- callback(...args);
16
- });
17
- };
18
-
19
- muiDescribe.skip = (...args: P) => {
20
- describe.skip(message, () => {
21
- callback(...args);
22
- });
23
- };
24
- muiDescribe.only = (...args: P) => {
25
- describe.only(message, () => {
26
- callback(...args);
27
- });
28
- };
29
-
30
- return muiDescribe;
31
- };
@@ -1,31 +0,0 @@
1
- import { expect } from 'chai';
2
- import * as React from 'react';
3
- import * as ReactDOM from 'react-dom';
4
- import { createRenderer } from './createRenderer';
5
-
6
- describe('createRenderer', () => {
7
- const { render } = createRenderer();
8
-
9
- it('allows querying descriptions', () => {
10
- function Component() {
11
- return (
12
- <React.Fragment>
13
- <div id="target" aria-describedby="r:1 r:2 r:3">
14
- I have a description.
15
- </div>
16
- {ReactDOM.createPortal(<div id="r:1">Description 1</div>, document.body)}
17
- {/* The ID format is important here. It would fail `querySelectorAll('#r:2')` and ensures we use `getElementById` */}
18
- <div id="r:2">Description 2</div>
19
- <div id="r:3">Description 3</div>
20
- </React.Fragment>
21
- );
22
- }
23
- const { getAllDescriptionsOf } = render(<Component />);
24
-
25
- const descriptions = getAllDescriptionsOf(document.getElementById('target'));
26
- expect(descriptions).to.have.length(3);
27
- expect(descriptions[0]).to.have.property('id', 'r:1');
28
- expect(descriptions[1]).to.have.property('id', 'r:2');
29
- expect(descriptions[2]).to.have.property('id', 'r:3');
30
- });
31
- });