cypress 10.10.0 → 11.0.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 (75) hide show
  1. package/angular/CHANGELOG.md +27 -0
  2. package/angular/dist/index.d.ts +124 -1
  3. package/angular/dist/index.js +59 -59
  4. package/lib/cli.js +15 -1
  5. package/lib/tasks/download.js +3 -7
  6. package/lib/util.js +2 -2
  7. package/mount-utils/CHANGELOG.md +7 -63
  8. package/mount-utils/README.md +5 -23
  9. package/mount-utils/dist/index.d.ts +25 -39
  10. package/mount-utils/dist/index.js +33 -112
  11. package/mount-utils/package.json +1 -0
  12. package/package.json +5 -4
  13. package/react/CHANGELOG.md +12 -55
  14. package/react/README.md +2 -22
  15. package/react/dist/cypress-react.cjs.js +92 -219
  16. package/react/dist/cypress-react.esm-bundler.js +92 -220
  17. package/react/dist/index.d.ts +111 -4
  18. package/react18/CHANGELOG.md +6 -106
  19. package/react18/dist/cypress-react.cjs.js +117 -180
  20. package/react18/dist/cypress-react.esm-bundler.js +103 -167
  21. package/react18/dist/index.d.ts +78 -6
  22. package/react18/package.json +1 -0
  23. package/svelte/CHANGELOG.md +20 -0
  24. package/svelte/dist/cypress-svelte.cjs.js +19 -114
  25. package/svelte/dist/cypress-svelte.esm-bundler.js +19 -114
  26. package/svelte/dist/index.d.ts +201 -1
  27. package/types/cypress-npm-api.d.ts +1 -1
  28. package/types/cypress.d.ts +43 -21
  29. package/vue/CHANGELOG.md +13 -101
  30. package/vue/README.md +4 -8
  31. package/vue/dist/cypress-vue.cjs.js +70 -153
  32. package/vue/dist/cypress-vue.esm-bundler.js +70 -153
  33. package/vue/dist/index.d.ts +1352 -104
  34. package/vue/package.json +1 -1
  35. package/vue2/CHANGELOG.md +15 -50
  36. package/vue2/README.md +3 -7
  37. package/vue2/dist/cypress-vue2.cjs.js +87 -211
  38. package/vue2/dist/cypress-vue2.esm-bundler.js +86 -210
  39. package/vue2/dist/index.d.ts +341 -172
  40. package/vue2/package.json +1 -3
  41. package/angular/dist/mount.d.ts +0 -112
  42. package/react/dist/createMount.d.ts +0 -31
  43. package/react/dist/getDisplayName.d.ts +0 -8
  44. package/react/dist/mount.d.ts +0 -8
  45. package/react/dist/mountHook.d.ts +0 -12
  46. package/react/dist/types.d.ts +0 -45
  47. package/svelte/dist/mount.d.ts +0 -30
  48. package/vue/dist/@vue/test-utils/baseWrapper.d.ts +0 -63
  49. package/vue/dist/@vue/test-utils/components/RouterLinkStub.d.ts +0 -21
  50. package/vue/dist/@vue/test-utils/config.d.ts +0 -30
  51. package/vue/dist/@vue/test-utils/constants/dom-events.d.ts +0 -900
  52. package/vue/dist/@vue/test-utils/createDomEvent.d.ts +0 -9
  53. package/vue/dist/@vue/test-utils/domWrapper.d.ts +0 -18
  54. package/vue/dist/@vue/test-utils/emit.d.ts +0 -5
  55. package/vue/dist/@vue/test-utils/errorWrapper.d.ts +0 -1
  56. package/vue/dist/@vue/test-utils/index.d.ts +0 -11
  57. package/vue/dist/@vue/test-utils/interfaces/wrapperLike.d.ts +0 -56
  58. package/vue/dist/@vue/test-utils/mount.d.ts +0 -35
  59. package/vue/dist/@vue/test-utils/stubs.d.ts +0 -22
  60. package/vue/dist/@vue/test-utils/types.d.ts +0 -125
  61. package/vue/dist/@vue/test-utils/utils/autoUnmount.d.ts +0 -5
  62. package/vue/dist/@vue/test-utils/utils/compileSlots.d.ts +0 -2
  63. package/vue/dist/@vue/test-utils/utils/componentName.d.ts +0 -4
  64. package/vue/dist/@vue/test-utils/utils/find.d.ts +0 -10
  65. package/vue/dist/@vue/test-utils/utils/flushPromises.d.ts +0 -1
  66. package/vue/dist/@vue/test-utils/utils/getRootNodes.d.ts +0 -2
  67. package/vue/dist/@vue/test-utils/utils/isElement.d.ts +0 -1
  68. package/vue/dist/@vue/test-utils/utils/isElementVisible.d.ts +0 -6
  69. package/vue/dist/@vue/test-utils/utils/matchName.d.ts +0 -1
  70. package/vue/dist/@vue/test-utils/utils/stringifyNode.d.ts +0 -1
  71. package/vue/dist/@vue/test-utils/utils/vueCompatSupport.d.ts +0 -8
  72. package/vue/dist/@vue/test-utils/utils/vueShared.d.ts +0 -3
  73. package/vue/dist/@vue/test-utils/utils.d.ts +0 -13
  74. package/vue/dist/@vue/test-utils/vueWrapper.d.ts +0 -35
  75. package/vue/dist/@vue/test-utils/wrapperFactory.d.ts +0 -14
@@ -36,17 +36,16 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
36
36
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
37
37
  var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
38
38
 
39
- const cachedDisplayNames = new WeakMap();
40
39
  /**
41
40
  * Gets the display name of the component when possible.
42
41
  * @param type {JSX} The type object returned from creating the react element.
43
42
  * @param fallbackName {string} The alias, or fallback name to use when the name cannot be derived.
44
43
  * @link https://github.com/facebook/react-devtools/blob/master/backend/getDisplayName.js
45
44
  */
46
- function getDisplayName(type, fallbackName = 'Unknown') {
47
- const nameFromCache = cachedDisplayNames.get(type);
48
- if (nameFromCache != null) {
49
- return nameFromCache;
45
+ function getDisplayName(node, fallbackName = 'Unknown') {
46
+ const type = node === null || node === void 0 ? void 0 : node.type;
47
+ if (!type) {
48
+ return fallbackName;
50
49
  }
51
50
  let displayName = null;
52
51
  // The displayName property is not guaranteed to be a string.
@@ -71,16 +70,15 @@ function getDisplayName(type, fallbackName = 'Unknown') {
71
70
  }
72
71
  }
73
72
  }
74
- try {
75
- cachedDisplayNames.set(type, displayName);
76
- }
77
- catch (e) {
78
- // do nothing
79
- }
80
73
  return displayName;
81
74
  }
82
75
 
83
76
  const ROOT_SELECTOR = '[data-cy-root]';
77
+ /**
78
+ * Gets the root element used to mount the component.
79
+ * @returns {HTMLElement} The root element
80
+ * @throws {Error} If the root element is not found
81
+ */
84
82
  const getContainerEl = () => {
85
83
  const el = document.querySelector(ROOT_SELECTOR);
86
84
  if (el) {
@@ -88,122 +86,19 @@ const getContainerEl = () => {
88
86
  }
89
87
  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
88
  };
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);
89
+ function checkForRemovedStyleOptions(mountingOptions) {
90
+ for (const key of ['cssFile', 'cssFiles', 'style', 'styles', 'stylesheet', 'stylesheets']) {
91
+ if (mountingOptions[key]) {
92
+ Cypress.utils.throwErrByPath('mount.removed_style_mounting_options', key);
101
93
  }
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
- });
94
+ }
149
95
  }
150
96
  /**
151
- * Injects custom style text or CSS file or 3rd party style resources
152
- * into the given document.
97
+ * Utility function to register CT side effects and run cleanup code during the "test:before:run" Cypress hook
98
+ * @param optionalCallback Callback to be called before the next test runs
153
99
  */
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
100
  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
101
+ // We don't want CT side effects to run when e2e
207
102
  // testing so we early return.
208
103
  // System test to verify CT side effects do not pollute e2e: system-tests/test/e2e_with_mount_import_spec.ts
209
104
  if (Cypress.testingType !== 'component') {
@@ -218,19 +113,9 @@ function setupHooks(optionalCallback) {
218
113
  // @ts-ignore
219
114
  Cypress.on('test:before:run', () => {
220
115
  optionalCallback === null || optionalCallback === void 0 ? void 0 : optionalCallback();
221
- cleanupStyles();
222
116
  });
223
117
  }
224
118
 
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
119
  let mountCleanup;
235
120
  /**
236
121
  * Create an `mount` function. Performs all the non-React-version specific
@@ -245,17 +130,14 @@ const makeMountFn = (type, jsx, options = {}, rerenderKey, internalMountOptions)
245
130
  if (!internalMountOptions) {
246
131
  throw Error('internalMountOptions must be provided with `render` and `reactDom` parameters');
247
132
  }
133
+ // @ts-expect-error - this is removed but we want to check if a user is passing it, and error if they are.
134
+ if (options.alias) {
135
+ // @ts-expect-error
136
+ Cypress.utils.throwErrByPath('mount.alias', options.alias);
137
+ }
138
+ checkForRemovedStyleOptions(options);
248
139
  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
140
  return cy
258
- .then(injectStyles(options))
259
141
  .then(() => {
260
142
  var _a, _b, _c;
261
143
  const reactDomToUse = internalMountOptions.reactDom;
@@ -276,38 +158,44 @@ const makeMountFn = (type, jsx, options = {}, rerenderKey, internalMountOptions)
276
158
  // let's get back the original component
277
159
  const userComponent = reactComponent.props.children;
278
160
  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)
161
+ return (cy.wrap(userComponent, { log: false })
300
162
  .then(() => {
301
163
  return cy.wrap({
302
164
  component: userComponent,
303
165
  rerender: (newComponent) => makeMountFn('rerender', newComponent, options, key, internalMountOptions),
304
- unmount: internalMountOptions.unmount,
166
+ unmount: () => {
167
+ // @ts-expect-error - undocumented API
168
+ Cypress.utils.throwErrByPath('mount.unmount');
169
+ },
305
170
  }, { log: false });
306
171
  })
307
172
  // by waiting, we delaying test execution for the next tick of event loop
308
173
  // and letting hooks and component lifecycle methods to execute mount
309
174
  // https://github.com/bahmutov/cypress-react-unit-test/issues/200
310
- .wait(0, { log: false }));
175
+ .wait(0, { log: false })
176
+ .then(() => {
177
+ if (options.log !== false) {
178
+ // Get the display name property via the component constructor
179
+ // @ts-ignore FIXME
180
+ const componentName = getDisplayName(jsx);
181
+ const jsxComponentName = `<${componentName} ... />`;
182
+ Cypress.log({
183
+ name: type,
184
+ type: 'parent',
185
+ message: [jsxComponentName],
186
+ // @ts-ignore
187
+ $el: el.children.item(0),
188
+ consoleProps: () => {
189
+ return {
190
+ // @ts-ignore protect the use of jsx functional components use ReactNode
191
+ props: jsx === null || jsx === void 0 ? void 0 : jsx.props,
192
+ description: type === 'mount' ? 'Mounts React component' : 'Rerenders mounted React component',
193
+ home: 'https://github.com/cypress-io/cypress',
194
+ };
195
+ },
196
+ });
197
+ }
198
+ }));
311
199
  // Bluebird types are terrible. I don't think the return type can be carried without this cast
312
200
  });
313
201
  };
@@ -317,6 +205,8 @@ const makeMountFn = (type, jsx, options = {}, rerenderKey, internalMountOptions)
317
205
  *
318
206
  * This is designed to be consumed by `npm/react{16,17,18}`, and other React adapters,
319
207
  * or people writing adapters for third-party, custom adapters.
208
+ *
209
+ * @param {UnmountArgs} options used during unmounting
320
210
  */
321
211
  const makeUnmountFn = (options) => {
322
212
  return cy.then(() => {
@@ -916,87 +806,70 @@ const cleanup = () => {
916
806
  }
917
807
  return false;
918
808
  };
809
+ /**
810
+ * Mounts a React component into the DOM.
811
+ * @param jsx {React.ReactNode} The React component to mount.
812
+ * @param options {MountOptions} [options={}] options to pass to the mount function.
813
+ * @param rerenderKey {string} [rerenderKey] A key to use to force a rerender.
814
+ * @see {@link https://on.cypress.io/mounting-react} for more details.
815
+ * @example
816
+ * import { mount } from '@cypress/react'
817
+ * import { Stepper } from './Stepper'
818
+ *
819
+ * it('mounts', () => {
820
+ * mount(<StepperComponent />)
821
+ * cy.get('[data-cy=increment]').click()
822
+ * cy.get('[data-cy=counter]').should('have.text', '1')
823
+ * }
824
+ */
919
825
  function mount(jsx, options = {}, rerenderKey) {
920
826
  if (major_1(React__default["default"].version) === 18) {
921
827
  const message = '[cypress/react]: You are using `cypress/react`, which is designed for React <= 17. Consider changing to `cypress/react18`, which is designed for React 18.';
922
828
  console.error(message);
923
829
  Cypress.log({ name: 'warning', message });
924
830
  }
831
+ // Remove last mounted component if cy.mount is called more than once in a test
832
+ cleanup();
925
833
  const internalOptions = {
926
834
  reactDom: ReactDOM__default["default"],
927
835
  render: (reactComponent, el, reactDomToUse) => {
928
836
  lastReactDom = (reactDomToUse || ReactDOM__default["default"]);
929
837
  return lastReactDom.render(reactComponent, el);
930
838
  },
931
- unmount,
839
+ unmount: internalUnmount,
932
840
  cleanup,
933
841
  };
934
842
  return makeMountFn('mount', jsx, Object.assign({ ReactDom: ReactDOM__default["default"] }, options), rerenderKey, internalOptions);
935
843
  }
936
- function unmount(options = { log: true }) {
844
+ /**
845
+ * Unmounts the component from the DOM.
846
+ * @internal
847
+ * @param options - Options for unmounting.
848
+ */
849
+ function internalUnmount(options = { log: true }) {
937
850
  return makeUnmountFn(options);
851
+ }
852
+ /**
853
+ * Removed as of Cypress 11.0.0.
854
+ * @see https://on.cypress.io/migration-11-0-0-component-testing-updates
855
+ */
856
+ function unmount(options = { log: true }) {
857
+ // @ts-expect-error - undocumented API
858
+ Cypress.utils.throwErrByPath('mount.unmount');
938
859
  }
939
860
 
940
- // mounting hooks inside a test component mostly copied from
941
- // https://github.com/testing-library/react-hooks-testing-library/blob/master/src/pure.js
942
- function resultContainer() {
943
- let value = null;
944
- let error = null;
945
- const resolvers = [];
946
- const result = {
947
- get current() {
948
- if (error) {
949
- throw error;
950
- }
951
- return value;
952
- },
953
- get error() {
954
- return error;
955
- },
956
- };
957
- const updateResult = (val, err = null) => {
958
- value = val;
959
- error = err;
960
- resolvers.splice(0, resolvers.length).forEach((resolve) => resolve());
961
- };
962
- return {
963
- result,
964
- addResolver: (resolver) => {
965
- resolvers.push(resolver);
966
- },
967
- setValue: (val) => updateResult(val),
968
- setError: (err) => updateResult(undefined, err),
969
- };
970
- }
971
- function TestHook({ callback, onError, children }) {
972
- try {
973
- children(callback());
974
- }
975
- catch (err) {
976
- if ('then' in err) {
977
- throw err;
978
- }
979
- else {
980
- onError(err);
981
- }
982
- }
983
- return null;
984
- }
985
861
  /**
986
862
  * Mounts a React hook function in a test component for testing.
987
- *
863
+ * Removed as of Cypress 11.0.0.
864
+ * @see https://on.cypress.io/migration-11-0-0-component-testing-updates
988
865
  */
989
866
  const mountHook = (hookFn) => {
990
- const { result, setValue, setError } = resultContainer();
991
- const componentTest = React__namespace.createElement(TestHook, {
992
- callback: hookFn,
993
- onError: setError,
994
- children: setValue,
995
- });
996
- return mount(componentTest).then(() => result);
867
+ // @ts-expect-error - internal API
868
+ Cypress.utils.throwErrByPath('mount.mount_hook');
997
869
  };
998
870
 
999
871
  exports.createMount = createMount;
872
+ exports.getContainerEl = getContainerEl;
1000
873
  exports.makeMountFn = makeMountFn;
1001
874
  exports.makeUnmountFn = makeUnmountFn;
1002
875
  exports.mount = mount;