cypress 10.11.0 → 11.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. package/angular/CHANGELOG.md +20 -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 +14 -0
  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 +3 -3
  13. package/react/CHANGELOG.md +27 -0
  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 +13 -0
  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.d.ts +18 -10
  28. package/vue/CHANGELOG.md +34 -0
  29. package/vue/README.md +4 -8
  30. package/vue/dist/cypress-vue.cjs.js +68 -151
  31. package/vue/dist/cypress-vue.esm-bundler.js +68 -151
  32. package/vue/dist/index.d.ts +1352 -104
  33. package/vue/package.json +1 -1
  34. package/vue2/CHANGELOG.md +27 -0
  35. package/vue2/README.md +3 -7
  36. package/vue2/dist/cypress-vue2.cjs.js +87 -211
  37. package/vue2/dist/cypress-vue2.esm-bundler.js +86 -210
  38. package/vue2/dist/index.d.ts +341 -172
  39. package/vue2/package.json +1 -3
  40. package/angular/dist/mount.d.ts +0 -112
  41. package/react/dist/createMount.d.ts +0 -31
  42. package/react/dist/getDisplayName.d.ts +0 -8
  43. package/react/dist/mount.d.ts +0 -8
  44. package/react/dist/mountHook.d.ts +0 -12
  45. package/react/dist/types.d.ts +0 -45
  46. package/svelte/dist/mount.d.ts +0 -30
  47. package/vue/dist/@vue/test-utils/baseWrapper.d.ts +0 -63
  48. package/vue/dist/@vue/test-utils/components/RouterLinkStub.d.ts +0 -21
  49. package/vue/dist/@vue/test-utils/config.d.ts +0 -30
  50. package/vue/dist/@vue/test-utils/constants/dom-events.d.ts +0 -900
  51. package/vue/dist/@vue/test-utils/createDomEvent.d.ts +0 -9
  52. package/vue/dist/@vue/test-utils/domWrapper.d.ts +0 -18
  53. package/vue/dist/@vue/test-utils/emit.d.ts +0 -5
  54. package/vue/dist/@vue/test-utils/errorWrapper.d.ts +0 -1
  55. package/vue/dist/@vue/test-utils/index.d.ts +0 -11
  56. package/vue/dist/@vue/test-utils/interfaces/wrapperLike.d.ts +0 -56
  57. package/vue/dist/@vue/test-utils/mount.d.ts +0 -35
  58. package/vue/dist/@vue/test-utils/stubs.d.ts +0 -22
  59. package/vue/dist/@vue/test-utils/types.d.ts +0 -125
  60. package/vue/dist/@vue/test-utils/utils/autoUnmount.d.ts +0 -5
  61. package/vue/dist/@vue/test-utils/utils/compileSlots.d.ts +0 -2
  62. package/vue/dist/@vue/test-utils/utils/componentName.d.ts +0 -4
  63. package/vue/dist/@vue/test-utils/utils/find.d.ts +0 -10
  64. package/vue/dist/@vue/test-utils/utils/flushPromises.d.ts +0 -1
  65. package/vue/dist/@vue/test-utils/utils/getRootNodes.d.ts +0 -2
  66. package/vue/dist/@vue/test-utils/utils/isElement.d.ts +0 -1
  67. package/vue/dist/@vue/test-utils/utils/isElementVisible.d.ts +0 -6
  68. package/vue/dist/@vue/test-utils/utils/matchName.d.ts +0 -1
  69. package/vue/dist/@vue/test-utils/utils/stringifyNode.d.ts +0 -1
  70. package/vue/dist/@vue/test-utils/utils/vueCompatSupport.d.ts +0 -8
  71. package/vue/dist/@vue/test-utils/utils/vueShared.d.ts +0 -3
  72. package/vue/dist/@vue/test-utils/utils.d.ts +0 -13
  73. package/vue/dist/@vue/test-utils/vueWrapper.d.ts +0 -35
  74. 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;