cypress 10.11.0 → 11.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. package/angular/CHANGELOG.md +20 -0
  2. package/angular/README.md +2 -77
  3. package/angular/dist/index.d.ts +124 -1
  4. package/angular/dist/index.js +59 -59
  5. package/lib/cli.js +15 -1
  6. package/lib/tasks/download.js +3 -7
  7. package/lib/util.js +2 -2
  8. package/mount-utils/CHANGELOG.md +14 -0
  9. package/mount-utils/README.md +7 -24
  10. package/mount-utils/dist/index.d.ts +25 -39
  11. package/mount-utils/dist/index.js +33 -112
  12. package/mount-utils/package.json +1 -0
  13. package/package.json +3 -3
  14. package/react/CHANGELOG.md +27 -0
  15. package/react/README.md +2 -107
  16. package/react/dist/cypress-react.cjs.js +92 -219
  17. package/react/dist/cypress-react.esm-bundler.js +92 -220
  18. package/react/dist/index.d.ts +111 -4
  19. package/react18/CHANGELOG.md +13 -0
  20. package/react18/README.md +7 -0
  21. package/react18/dist/cypress-react.cjs.js +117 -180
  22. package/react18/dist/cypress-react.esm-bundler.js +103 -167
  23. package/react18/dist/index.d.ts +78 -6
  24. package/react18/package.json +1 -0
  25. package/svelte/CHANGELOG.md +20 -0
  26. package/svelte/README.md +1 -69
  27. package/svelte/dist/cypress-svelte.cjs.js +19 -114
  28. package/svelte/dist/cypress-svelte.esm-bundler.js +19 -114
  29. package/svelte/dist/index.d.ts +201 -1
  30. package/types/cypress.d.ts +18 -10
  31. package/vue/CHANGELOG.md +34 -0
  32. package/vue/README.md +2 -76
  33. package/vue/dist/cypress-vue.cjs.js +68 -151
  34. package/vue/dist/cypress-vue.esm-bundler.js +68 -151
  35. package/vue/dist/index.d.ts +1352 -104
  36. package/vue/package.json +1 -1
  37. package/vue2/CHANGELOG.md +27 -0
  38. package/vue2/README.md +2 -72
  39. package/vue2/dist/cypress-vue2.cjs.js +87 -211
  40. package/vue2/dist/cypress-vue2.esm-bundler.js +86 -210
  41. package/vue2/dist/index.d.ts +341 -172
  42. package/vue2/package.json +1 -3
  43. package/angular/dist/mount.d.ts +0 -112
  44. package/react/dist/createMount.d.ts +0 -31
  45. package/react/dist/getDisplayName.d.ts +0 -8
  46. package/react/dist/mount.d.ts +0 -8
  47. package/react/dist/mountHook.d.ts +0 -12
  48. package/react/dist/types.d.ts +0 -45
  49. package/svelte/dist/mount.d.ts +0 -30
  50. package/vue/dist/@vue/test-utils/baseWrapper.d.ts +0 -63
  51. package/vue/dist/@vue/test-utils/components/RouterLinkStub.d.ts +0 -21
  52. package/vue/dist/@vue/test-utils/config.d.ts +0 -30
  53. package/vue/dist/@vue/test-utils/constants/dom-events.d.ts +0 -900
  54. package/vue/dist/@vue/test-utils/createDomEvent.d.ts +0 -9
  55. package/vue/dist/@vue/test-utils/domWrapper.d.ts +0 -18
  56. package/vue/dist/@vue/test-utils/emit.d.ts +0 -5
  57. package/vue/dist/@vue/test-utils/errorWrapper.d.ts +0 -1
  58. package/vue/dist/@vue/test-utils/index.d.ts +0 -11
  59. package/vue/dist/@vue/test-utils/interfaces/wrapperLike.d.ts +0 -56
  60. package/vue/dist/@vue/test-utils/mount.d.ts +0 -35
  61. package/vue/dist/@vue/test-utils/stubs.d.ts +0 -22
  62. package/vue/dist/@vue/test-utils/types.d.ts +0 -125
  63. package/vue/dist/@vue/test-utils/utils/autoUnmount.d.ts +0 -5
  64. package/vue/dist/@vue/test-utils/utils/compileSlots.d.ts +0 -2
  65. package/vue/dist/@vue/test-utils/utils/componentName.d.ts +0 -4
  66. package/vue/dist/@vue/test-utils/utils/find.d.ts +0 -10
  67. package/vue/dist/@vue/test-utils/utils/flushPromises.d.ts +0 -1
  68. package/vue/dist/@vue/test-utils/utils/getRootNodes.d.ts +0 -2
  69. package/vue/dist/@vue/test-utils/utils/isElement.d.ts +0 -1
  70. package/vue/dist/@vue/test-utils/utils/isElementVisible.d.ts +0 -6
  71. package/vue/dist/@vue/test-utils/utils/matchName.d.ts +0 -1
  72. package/vue/dist/@vue/test-utils/utils/stringifyNode.d.ts +0 -1
  73. package/vue/dist/@vue/test-utils/utils/vueCompatSupport.d.ts +0 -8
  74. package/vue/dist/@vue/test-utils/utils/vueShared.d.ts +0 -3
  75. package/vue/dist/@vue/test-utils/utils.d.ts +0 -13
  76. package/vue/dist/@vue/test-utils/vueWrapper.d.ts +0 -35
  77. package/vue/dist/@vue/test-utils/wrapperFactory.d.ts +0 -14
@@ -16,37 +16,50 @@ require('react-dom');
16
16
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
17
17
 
18
18
  function _interopNamespace(e) {
19
- if (e && e.__esModule) return e;
20
- var n = Object.create(null);
21
- if (e) {
22
- Object.keys(e).forEach(function (k) {
23
- if (k !== 'default') {
24
- var d = Object.getOwnPropertyDescriptor(e, k);
25
- Object.defineProperty(n, k, d.get ? d : {
26
- enumerable: true,
27
- get: function () { return e[k]; }
19
+ if (e && e.__esModule) return e;
20
+ var n = Object.create(null);
21
+ if (e) {
22
+ Object.keys(e).forEach(function (k) {
23
+ if (k !== 'default') {
24
+ var d = Object.getOwnPropertyDescriptor(e, k);
25
+ Object.defineProperty(n, k, d.get ? d : {
26
+ enumerable: true,
27
+ get: function () { return e[k]; }
28
+ });
29
+ }
28
30
  });
29
- }
30
- });
31
- }
32
- n["default"] = e;
33
- return Object.freeze(n);
31
+ }
32
+ n["default"] = e;
33
+ return Object.freeze(n);
34
34
  }
35
35
 
36
36
  var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
37
37
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
38
38
 
39
- const cachedDisplayNames = new WeakMap();
39
+ const ROOT_SELECTOR$1 = '[data-cy-root]';
40
+ /**
41
+ * Gets the root element used to mount the component.
42
+ * @returns {HTMLElement} The root element
43
+ * @throws {Error} If the root element is not found
44
+ */
45
+ const getContainerEl$1 = () => {
46
+ const el = document.querySelector(ROOT_SELECTOR$1);
47
+ if (el) {
48
+ return el;
49
+ }
50
+ throw Error(`No element found that matches selector ${ROOT_SELECTOR$1}. Please add a root element with data-cy-root attribute to your "component-index.html" file so that Cypress can attach your component to the DOM.`);
51
+ };
52
+
40
53
  /**
41
54
  * Gets the display name of the component when possible.
42
55
  * @param type {JSX} The type object returned from creating the react element.
43
56
  * @param fallbackName {string} The alias, or fallback name to use when the name cannot be derived.
44
57
  * @link https://github.com/facebook/react-devtools/blob/master/backend/getDisplayName.js
45
58
  */
46
- function getDisplayName(type, fallbackName = 'Unknown') {
47
- const nameFromCache = cachedDisplayNames.get(type);
48
- if (nameFromCache != null) {
49
- return nameFromCache;
59
+ function getDisplayName(node, fallbackName = 'Unknown') {
60
+ const type = node === null || node === void 0 ? void 0 : node.type;
61
+ if (!type) {
62
+ return fallbackName;
50
63
  }
51
64
  let displayName = null;
52
65
  // The displayName property is not guaranteed to be a string.
@@ -71,16 +84,15 @@ function getDisplayName(type, fallbackName = 'Unknown') {
71
84
  }
72
85
  }
73
86
  }
74
- try {
75
- cachedDisplayNames.set(type, displayName);
76
- }
77
- catch (e) {
78
- // do nothing
79
- }
80
87
  return displayName;
81
88
  }
82
89
 
83
90
  const ROOT_SELECTOR = '[data-cy-root]';
91
+ /**
92
+ * Gets the root element used to mount the component.
93
+ * @returns {HTMLElement} The root element
94
+ * @throws {Error} If the root element is not found
95
+ */
84
96
  const getContainerEl = () => {
85
97
  const el = document.querySelector(ROOT_SELECTOR);
86
98
  if (el) {
@@ -88,122 +100,19 @@ const getContainerEl = () => {
88
100
  }
89
101
  throw Error(`No element found that matches selector ${ROOT_SELECTOR}. Please add a root element with data-cy-root attribute to your "component-index.html" file so that Cypress can attach your component to the DOM.`);
90
102
  };
91
- /**
92
- * Remove any style or extra link elements from the iframe placeholder
93
- * left from any previous test
94
- *
95
- */
96
- function cleanupStyles() {
97
- const styles = document.body.querySelectorAll('[data-cy=injected-style-tag]');
98
- styles.forEach((styleElement) => {
99
- if (styleElement.parentElement) {
100
- styleElement.parentElement.removeChild(styleElement);
103
+ function checkForRemovedStyleOptions(mountingOptions) {
104
+ for (const key of ['cssFile', 'cssFiles', 'style', 'styles', 'stylesheet', 'stylesheets']) {
105
+ if (mountingOptions[key]) {
106
+ Cypress.utils.throwErrByPath('mount.removed_style_mounting_options', key);
101
107
  }
102
- });
103
- const links = document.body.querySelectorAll('[data-cy=injected-stylesheet]');
104
- links.forEach((link) => {
105
- if (link.parentElement) {
106
- link.parentElement.removeChild(link);
107
- }
108
- });
109
- }
110
- /**
111
- * Insert links to external style resources.
112
- */
113
- function insertStylesheets(stylesheets, document, el) {
114
- stylesheets.forEach((href) => {
115
- const link = document.createElement('link');
116
- link.type = 'text/css';
117
- link.rel = 'stylesheet';
118
- link.href = href;
119
- link.dataset.cy = 'injected-stylesheet';
120
- document.body.insertBefore(link, el);
121
- });
122
- }
123
- /**
124
- * Inserts a single stylesheet element
125
- */
126
- function insertStyles(styles, document, el) {
127
- styles.forEach((style) => {
128
- const styleElement = document.createElement('style');
129
- styleElement.dataset.cy = 'injected-style-tag';
130
- styleElement.appendChild(document.createTextNode(style));
131
- document.body.insertBefore(styleElement, el);
132
- });
133
- }
134
- function insertSingleCssFile(cssFilename, document, el, log) {
135
- return cy.readFile(cssFilename, { log }).then((css) => {
136
- const style = document.createElement('style');
137
- style.appendChild(document.createTextNode(css));
138
- document.body.insertBefore(style, el);
139
- });
140
- }
141
- /**
142
- * Reads the given CSS file from local file system
143
- * and adds the loaded style text as an element.
144
- */
145
- function insertLocalCssFiles(cssFilenames, document, el, log) {
146
- return Cypress.Promise.mapSeries(cssFilenames, (cssFilename) => {
147
- return insertSingleCssFile(cssFilename, document, el, log);
148
- });
108
+ }
149
109
  }
150
110
  /**
151
- * Injects custom style text or CSS file or 3rd party style resources
152
- * into the given document.
111
+ * Utility function to register CT side effects and run cleanup code during the "test:before:run" Cypress hook
112
+ * @param optionalCallback Callback to be called before the next test runs
153
113
  */
154
- const injectStylesBeforeElement = (options, document, el) => {
155
- if (!el)
156
- return;
157
- // first insert all stylesheets as Link elements
158
- let stylesheets = [];
159
- if (typeof options.stylesheet === 'string') {
160
- stylesheets.push(options.stylesheet);
161
- }
162
- else if (Array.isArray(options.stylesheet)) {
163
- stylesheets = stylesheets.concat(options.stylesheet);
164
- }
165
- if (typeof options.stylesheets === 'string') {
166
- options.stylesheets = [options.stylesheets];
167
- }
168
- if (options.stylesheets) {
169
- stylesheets = stylesheets.concat(options.stylesheets);
170
- }
171
- insertStylesheets(stylesheets, document, el);
172
- // insert any styles as <style>...</style> elements
173
- let styles = [];
174
- if (typeof options.style === 'string') {
175
- styles.push(options.style);
176
- }
177
- else if (Array.isArray(options.style)) {
178
- styles = styles.concat(options.style);
179
- }
180
- if (typeof options.styles === 'string') {
181
- styles.push(options.styles);
182
- }
183
- else if (Array.isArray(options.styles)) {
184
- styles = styles.concat(options.styles);
185
- }
186
- insertStyles(styles, document, el);
187
- // now load any css files by path and add their content
188
- // as <style>...</style> elements
189
- let cssFiles = [];
190
- if (typeof options.cssFile === 'string') {
191
- cssFiles.push(options.cssFile);
192
- }
193
- else if (Array.isArray(options.cssFile)) {
194
- cssFiles = cssFiles.concat(options.cssFile);
195
- }
196
- if (typeof options.cssFiles === 'string') {
197
- cssFiles.push(options.cssFiles);
198
- }
199
- else if (Array.isArray(options.cssFiles)) {
200
- cssFiles = cssFiles.concat(options.cssFiles);
201
- }
202
- return insertLocalCssFiles(cssFiles, document, el, options.log);
203
- };
204
114
  function setupHooks(optionalCallback) {
205
- // Consumed by the framework "mount" libs. A user might register their own mount in the scaffolded 'commands.js'
206
- // file that is imported by e2e and component support files by default. We don't want CT side effects to run when e2e
115
+ // We don't want CT side effects to run when e2e
207
116
  // testing so we early return.
208
117
  // System test to verify CT side effects do not pollute e2e: system-tests/test/e2e_with_mount_import_spec.ts
209
118
  if (Cypress.testingType !== 'component') {
@@ -218,19 +127,9 @@ function setupHooks(optionalCallback) {
218
127
  // @ts-ignore
219
128
  Cypress.on('test:before:run', () => {
220
129
  optionalCallback === null || optionalCallback === void 0 ? void 0 : optionalCallback();
221
- cleanupStyles();
222
130
  });
223
131
  }
224
132
 
225
- /**
226
- * Inject custom style text or CSS file or 3rd party style resources
227
- */
228
- const injectStyles = (options) => {
229
- return () => {
230
- const el = getContainerEl();
231
- return injectStylesBeforeElement(options, document, el);
232
- };
233
- };
234
133
  let mountCleanup;
235
134
  /**
236
135
  * Create an `mount` function. Performs all the non-React-version specific
@@ -245,17 +144,14 @@ const makeMountFn = (type, jsx, options = {}, rerenderKey, internalMountOptions)
245
144
  if (!internalMountOptions) {
246
145
  throw Error('internalMountOptions must be provided with `render` and `reactDom` parameters');
247
146
  }
147
+ // @ts-expect-error - this is removed but we want to check if a user is passing it, and error if they are.
148
+ if (options.alias) {
149
+ // @ts-expect-error
150
+ Cypress.utils.throwErrByPath('mount.alias', options.alias);
151
+ }
152
+ checkForRemovedStyleOptions(options);
248
153
  mountCleanup = internalMountOptions.cleanup;
249
- // Get the display name property via the component constructor
250
- // @ts-ignore FIXME
251
- const componentName = getDisplayName(jsx.type, options.alias);
252
- const displayName = options.alias || componentName;
253
- const jsxComponentName = `<${componentName} ... />`;
254
- const message = options.alias
255
- ? `${jsxComponentName} as "${options.alias}"`
256
- : jsxComponentName;
257
154
  return cy
258
- .then(injectStyles(options))
259
155
  .then(() => {
260
156
  var _a, _b, _c;
261
157
  const reactDomToUse = internalMountOptions.reactDom;
@@ -276,38 +172,44 @@ const makeMountFn = (type, jsx, options = {}, rerenderKey, internalMountOptions)
276
172
  // let's get back the original component
277
173
  const userComponent = reactComponent.props.children;
278
174
  internalMountOptions.render(reactComponent, el, reactDomToUse);
279
- if (options.log !== false) {
280
- Cypress.log({
281
- name: type,
282
- type: 'parent',
283
- message: [message],
284
- // @ts-ignore
285
- $el: el.children.item(0),
286
- consoleProps: () => {
287
- return {
288
- // @ts-ignore protect the use of jsx functional components use ReactNode
289
- props: jsx.props,
290
- description: type === 'mount' ? 'Mounts React component' : 'Rerenders mounted React component',
291
- home: 'https://github.com/cypress-io/cypress',
292
- };
293
- },
294
- }).snapshot('mounted').end();
295
- }
296
- return (
297
- // Separate alias and returned value. Alias returns the component only, and the thenable returns the additional functions
298
- cy.wrap(userComponent, { log: false })
299
- .as(displayName)
175
+ return (cy.wrap(userComponent, { log: false })
300
176
  .then(() => {
301
177
  return cy.wrap({
302
178
  component: userComponent,
303
179
  rerender: (newComponent) => makeMountFn('rerender', newComponent, options, key, internalMountOptions),
304
- unmount: internalMountOptions.unmount,
180
+ unmount: () => {
181
+ // @ts-expect-error - undocumented API
182
+ Cypress.utils.throwErrByPath('mount.unmount');
183
+ },
305
184
  }, { log: false });
306
185
  })
307
186
  // by waiting, we delaying test execution for the next tick of event loop
308
187
  // and letting hooks and component lifecycle methods to execute mount
309
188
  // https://github.com/bahmutov/cypress-react-unit-test/issues/200
310
- .wait(0, { log: false }));
189
+ .wait(0, { log: false })
190
+ .then(() => {
191
+ if (options.log !== false) {
192
+ // Get the display name property via the component constructor
193
+ // @ts-ignore FIXME
194
+ const componentName = getDisplayName(jsx);
195
+ const jsxComponentName = `<${componentName} ... />`;
196
+ Cypress.log({
197
+ name: type,
198
+ type: 'parent',
199
+ message: [jsxComponentName],
200
+ // @ts-ignore
201
+ $el: el.children.item(0),
202
+ consoleProps: () => {
203
+ return {
204
+ // @ts-ignore protect the use of jsx functional components use ReactNode
205
+ props: jsx === null || jsx === void 0 ? void 0 : jsx.props,
206
+ description: type === 'mount' ? 'Mounts React component' : 'Rerenders mounted React component',
207
+ home: 'https://github.com/cypress-io/cypress',
208
+ };
209
+ },
210
+ });
211
+ }
212
+ }));
311
213
  // Bluebird types are terrible. I don't think the return type can be carried without this cast
312
214
  });
313
215
  };
@@ -317,6 +219,8 @@ const makeMountFn = (type, jsx, options = {}, rerenderKey, internalMountOptions)
317
219
  *
318
220
  * This is designed to be consumed by `npm/react{16,17,18}`, and other React adapters,
319
221
  * or people writing adapters for third-party, custom adapters.
222
+ *
223
+ * @param {UnmountArgs} options used during unmounting
320
224
  */
321
225
  const makeUnmountFn = (options) => {
322
226
  return cy.then(() => {
@@ -585,7 +489,31 @@ const cleanup = () => {
585
489
  }
586
490
  return false;
587
491
  };
492
+ /**
493
+ * Mounts a React component into the DOM.
494
+ * @param {import('react').JSX.Element} jsx The React component to mount.
495
+ * @param {MountOptions} options Options to pass to the mount function.
496
+ * @param {string} rerenderKey A key to use to force a rerender.
497
+ *
498
+ * @example
499
+ * import { mount } from '@cypress/react'
500
+ * import { Stepper } from './Stepper'
501
+ *
502
+ * it('mounts', () => {
503
+ * mount(<StepperComponent />)
504
+ * cy.get('[data-cy=increment]').click()
505
+ * cy.get('[data-cy=counter]').should('have.text', '1')
506
+ * }
507
+ *
508
+ * @see {@link https://on.cypress.io/mounting-react} for more details.
509
+ *
510
+ * @returns {Cypress.Chainable<MountReturn>} The mounted component.
511
+ */
588
512
  function mount(jsx, options = {}, rerenderKey) {
513
+ // Remove last mounted component if cy.mount is called more than once in a test
514
+ // React by default removes the last component when calling render, but we should remove the root
515
+ // to wipe away any state
516
+ cleanup();
589
517
  const internalOptions = {
590
518
  reactDom: ReactDOM__default["default"],
591
519
  render: (reactComponent, el) => {
@@ -594,14 +522,23 @@ function mount(jsx, options = {}, rerenderKey) {
594
522
  }
595
523
  return root.render(reactComponent);
596
524
  },
597
- unmount,
525
+ unmount: internalUnmount,
598
526
  cleanup,
599
527
  };
600
528
  return makeMountFn('mount', jsx, Object.assign({ ReactDom: ReactDOM__default["default"] }, options), rerenderKey, internalOptions);
601
529
  }
602
- function unmount(options = { log: true }) {
530
+ function internalUnmount(options = { log: true }) {
603
531
  return makeUnmountFn(options);
532
+ }
533
+ /**
534
+ * Removed as of Cypress 11.0.0.
535
+ * @see https://on.cypress.io/migration-11-0-0-component-testing-updates
536
+ */
537
+ function unmount(options = { log: true }) {
538
+ // @ts-expect-error - undocumented API
539
+ Cypress.utils.throwErrByPath('mount.unmount');
604
540
  }
605
541
 
542
+ exports.getContainerEl = getContainerEl$1;
606
543
  exports.mount = mount;
607
544
  exports.unmount = unmount;