cypress 10.10.0 → 11.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -9,17 +9,30 @@ import ReactDOM from 'react-dom/client';
9
9
  import * as React from 'react';
10
10
  import 'react-dom';
11
11
 
12
- const cachedDisplayNames = new WeakMap();
12
+ const ROOT_SELECTOR$1 = '[data-cy-root]';
13
+ /**
14
+ * Gets the root element used to mount the component.
15
+ * @returns {HTMLElement} The root element
16
+ * @throws {Error} If the root element is not found
17
+ */
18
+ const getContainerEl$1 = () => {
19
+ const el = document.querySelector(ROOT_SELECTOR$1);
20
+ if (el) {
21
+ return el;
22
+ }
23
+ 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.`);
24
+ };
25
+
13
26
  /**
14
27
  * Gets the display name of the component when possible.
15
28
  * @param type {JSX} The type object returned from creating the react element.
16
29
  * @param fallbackName {string} The alias, or fallback name to use when the name cannot be derived.
17
30
  * @link https://github.com/facebook/react-devtools/blob/master/backend/getDisplayName.js
18
31
  */
19
- function getDisplayName(type, fallbackName = 'Unknown') {
20
- const nameFromCache = cachedDisplayNames.get(type);
21
- if (nameFromCache != null) {
22
- return nameFromCache;
32
+ function getDisplayName(node, fallbackName = 'Unknown') {
33
+ const type = node === null || node === void 0 ? void 0 : node.type;
34
+ if (!type) {
35
+ return fallbackName;
23
36
  }
24
37
  let displayName = null;
25
38
  // The displayName property is not guaranteed to be a string.
@@ -44,16 +57,15 @@ function getDisplayName(type, fallbackName = 'Unknown') {
44
57
  }
45
58
  }
46
59
  }
47
- try {
48
- cachedDisplayNames.set(type, displayName);
49
- }
50
- catch (e) {
51
- // do nothing
52
- }
53
60
  return displayName;
54
61
  }
55
62
 
56
63
  const ROOT_SELECTOR = '[data-cy-root]';
64
+ /**
65
+ * Gets the root element used to mount the component.
66
+ * @returns {HTMLElement} The root element
67
+ * @throws {Error} If the root element is not found
68
+ */
57
69
  const getContainerEl = () => {
58
70
  const el = document.querySelector(ROOT_SELECTOR);
59
71
  if (el) {
@@ -61,122 +73,19 @@ const getContainerEl = () => {
61
73
  }
62
74
  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.`);
63
75
  };
64
- /**
65
- * Remove any style or extra link elements from the iframe placeholder
66
- * left from any previous test
67
- *
68
- */
69
- function cleanupStyles() {
70
- const styles = document.body.querySelectorAll('[data-cy=injected-style-tag]');
71
- styles.forEach((styleElement) => {
72
- if (styleElement.parentElement) {
73
- styleElement.parentElement.removeChild(styleElement);
74
- }
75
- });
76
- const links = document.body.querySelectorAll('[data-cy=injected-stylesheet]');
77
- links.forEach((link) => {
78
- if (link.parentElement) {
79
- link.parentElement.removeChild(link);
76
+ function checkForRemovedStyleOptions(mountingOptions) {
77
+ for (const key of ['cssFile', 'cssFiles', 'style', 'styles', 'stylesheet', 'stylesheets']) {
78
+ if (mountingOptions[key]) {
79
+ Cypress.utils.throwErrByPath('mount.removed_style_mounting_options', key);
80
80
  }
81
- });
82
- }
83
- /**
84
- * Insert links to external style resources.
85
- */
86
- function insertStylesheets(stylesheets, document, el) {
87
- stylesheets.forEach((href) => {
88
- const link = document.createElement('link');
89
- link.type = 'text/css';
90
- link.rel = 'stylesheet';
91
- link.href = href;
92
- link.dataset.cy = 'injected-stylesheet';
93
- document.body.insertBefore(link, el);
94
- });
95
- }
96
- /**
97
- * Inserts a single stylesheet element
98
- */
99
- function insertStyles(styles, document, el) {
100
- styles.forEach((style) => {
101
- const styleElement = document.createElement('style');
102
- styleElement.dataset.cy = 'injected-style-tag';
103
- styleElement.appendChild(document.createTextNode(style));
104
- document.body.insertBefore(styleElement, el);
105
- });
106
- }
107
- function insertSingleCssFile(cssFilename, document, el, log) {
108
- return cy.readFile(cssFilename, { log }).then((css) => {
109
- const style = document.createElement('style');
110
- style.appendChild(document.createTextNode(css));
111
- document.body.insertBefore(style, el);
112
- });
113
- }
114
- /**
115
- * Reads the given CSS file from local file system
116
- * and adds the loaded style text as an element.
117
- */
118
- function insertLocalCssFiles(cssFilenames, document, el, log) {
119
- return Cypress.Promise.mapSeries(cssFilenames, (cssFilename) => {
120
- return insertSingleCssFile(cssFilename, document, el, log);
121
- });
81
+ }
122
82
  }
123
83
  /**
124
- * Injects custom style text or CSS file or 3rd party style resources
125
- * into the given document.
84
+ * Utility function to register CT side effects and run cleanup code during the "test:before:run" Cypress hook
85
+ * @param optionalCallback Callback to be called before the next test runs
126
86
  */
127
- const injectStylesBeforeElement = (options, document, el) => {
128
- if (!el)
129
- return;
130
- // first insert all stylesheets as Link elements
131
- let stylesheets = [];
132
- if (typeof options.stylesheet === 'string') {
133
- stylesheets.push(options.stylesheet);
134
- }
135
- else if (Array.isArray(options.stylesheet)) {
136
- stylesheets = stylesheets.concat(options.stylesheet);
137
- }
138
- if (typeof options.stylesheets === 'string') {
139
- options.stylesheets = [options.stylesheets];
140
- }
141
- if (options.stylesheets) {
142
- stylesheets = stylesheets.concat(options.stylesheets);
143
- }
144
- insertStylesheets(stylesheets, document, el);
145
- // insert any styles as <style>...</style> elements
146
- let styles = [];
147
- if (typeof options.style === 'string') {
148
- styles.push(options.style);
149
- }
150
- else if (Array.isArray(options.style)) {
151
- styles = styles.concat(options.style);
152
- }
153
- if (typeof options.styles === 'string') {
154
- styles.push(options.styles);
155
- }
156
- else if (Array.isArray(options.styles)) {
157
- styles = styles.concat(options.styles);
158
- }
159
- insertStyles(styles, document, el);
160
- // now load any css files by path and add their content
161
- // as <style>...</style> elements
162
- let cssFiles = [];
163
- if (typeof options.cssFile === 'string') {
164
- cssFiles.push(options.cssFile);
165
- }
166
- else if (Array.isArray(options.cssFile)) {
167
- cssFiles = cssFiles.concat(options.cssFile);
168
- }
169
- if (typeof options.cssFiles === 'string') {
170
- cssFiles.push(options.cssFiles);
171
- }
172
- else if (Array.isArray(options.cssFiles)) {
173
- cssFiles = cssFiles.concat(options.cssFiles);
174
- }
175
- return insertLocalCssFiles(cssFiles, document, el, options.log);
176
- };
177
87
  function setupHooks(optionalCallback) {
178
- // Consumed by the framework "mount" libs. A user might register their own mount in the scaffolded 'commands.js'
179
- // file that is imported by e2e and component support files by default. We don't want CT side effects to run when e2e
88
+ // We don't want CT side effects to run when e2e
180
89
  // testing so we early return.
181
90
  // System test to verify CT side effects do not pollute e2e: system-tests/test/e2e_with_mount_import_spec.ts
182
91
  if (Cypress.testingType !== 'component') {
@@ -191,19 +100,9 @@ function setupHooks(optionalCallback) {
191
100
  // @ts-ignore
192
101
  Cypress.on('test:before:run', () => {
193
102
  optionalCallback === null || optionalCallback === void 0 ? void 0 : optionalCallback();
194
- cleanupStyles();
195
103
  });
196
104
  }
197
105
 
198
- /**
199
- * Inject custom style text or CSS file or 3rd party style resources
200
- */
201
- const injectStyles = (options) => {
202
- return () => {
203
- const el = getContainerEl();
204
- return injectStylesBeforeElement(options, document, el);
205
- };
206
- };
207
106
  let mountCleanup;
208
107
  /**
209
108
  * Create an `mount` function. Performs all the non-React-version specific
@@ -218,17 +117,14 @@ const makeMountFn = (type, jsx, options = {}, rerenderKey, internalMountOptions)
218
117
  if (!internalMountOptions) {
219
118
  throw Error('internalMountOptions must be provided with `render` and `reactDom` parameters');
220
119
  }
120
+ // @ts-expect-error - this is removed but we want to check if a user is passing it, and error if they are.
121
+ if (options.alias) {
122
+ // @ts-expect-error
123
+ Cypress.utils.throwErrByPath('mount.alias', options.alias);
124
+ }
125
+ checkForRemovedStyleOptions(options);
221
126
  mountCleanup = internalMountOptions.cleanup;
222
- // Get the display name property via the component constructor
223
- // @ts-ignore FIXME
224
- const componentName = getDisplayName(jsx.type, options.alias);
225
- const displayName = options.alias || componentName;
226
- const jsxComponentName = `<${componentName} ... />`;
227
- const message = options.alias
228
- ? `${jsxComponentName} as "${options.alias}"`
229
- : jsxComponentName;
230
127
  return cy
231
- .then(injectStyles(options))
232
128
  .then(() => {
233
129
  var _a, _b, _c;
234
130
  const reactDomToUse = internalMountOptions.reactDom;
@@ -249,38 +145,44 @@ const makeMountFn = (type, jsx, options = {}, rerenderKey, internalMountOptions)
249
145
  // let's get back the original component
250
146
  const userComponent = reactComponent.props.children;
251
147
  internalMountOptions.render(reactComponent, el, reactDomToUse);
252
- if (options.log !== false) {
253
- Cypress.log({
254
- name: type,
255
- type: 'parent',
256
- message: [message],
257
- // @ts-ignore
258
- $el: el.children.item(0),
259
- consoleProps: () => {
260
- return {
261
- // @ts-ignore protect the use of jsx functional components use ReactNode
262
- props: jsx.props,
263
- description: type === 'mount' ? 'Mounts React component' : 'Rerenders mounted React component',
264
- home: 'https://github.com/cypress-io/cypress',
265
- };
266
- },
267
- }).snapshot('mounted').end();
268
- }
269
- return (
270
- // Separate alias and returned value. Alias returns the component only, and the thenable returns the additional functions
271
- cy.wrap(userComponent, { log: false })
272
- .as(displayName)
148
+ return (cy.wrap(userComponent, { log: false })
273
149
  .then(() => {
274
150
  return cy.wrap({
275
151
  component: userComponent,
276
152
  rerender: (newComponent) => makeMountFn('rerender', newComponent, options, key, internalMountOptions),
277
- unmount: internalMountOptions.unmount,
153
+ unmount: () => {
154
+ // @ts-expect-error - undocumented API
155
+ Cypress.utils.throwErrByPath('mount.unmount');
156
+ },
278
157
  }, { log: false });
279
158
  })
280
159
  // by waiting, we delaying test execution for the next tick of event loop
281
160
  // and letting hooks and component lifecycle methods to execute mount
282
161
  // https://github.com/bahmutov/cypress-react-unit-test/issues/200
283
- .wait(0, { log: false }));
162
+ .wait(0, { log: false })
163
+ .then(() => {
164
+ if (options.log !== false) {
165
+ // Get the display name property via the component constructor
166
+ // @ts-ignore FIXME
167
+ const componentName = getDisplayName(jsx);
168
+ const jsxComponentName = `<${componentName} ... />`;
169
+ Cypress.log({
170
+ name: type,
171
+ type: 'parent',
172
+ message: [jsxComponentName],
173
+ // @ts-ignore
174
+ $el: el.children.item(0),
175
+ consoleProps: () => {
176
+ return {
177
+ // @ts-ignore protect the use of jsx functional components use ReactNode
178
+ props: jsx === null || jsx === void 0 ? void 0 : jsx.props,
179
+ description: type === 'mount' ? 'Mounts React component' : 'Rerenders mounted React component',
180
+ home: 'https://github.com/cypress-io/cypress',
181
+ };
182
+ },
183
+ });
184
+ }
185
+ }));
284
186
  // Bluebird types are terrible. I don't think the return type can be carried without this cast
285
187
  });
286
188
  };
@@ -290,6 +192,8 @@ const makeMountFn = (type, jsx, options = {}, rerenderKey, internalMountOptions)
290
192
  *
291
193
  * This is designed to be consumed by `npm/react{16,17,18}`, and other React adapters,
292
194
  * or people writing adapters for third-party, custom adapters.
195
+ *
196
+ * @param {UnmountArgs} options used during unmounting
293
197
  */
294
198
  const makeUnmountFn = (options) => {
295
199
  return cy.then(() => {
@@ -558,7 +462,31 @@ const cleanup = () => {
558
462
  }
559
463
  return false;
560
464
  };
465
+ /**
466
+ * Mounts a React component into the DOM.
467
+ * @param {import('react').JSX.Element} jsx The React component to mount.
468
+ * @param {MountOptions} options Options to pass to the mount function.
469
+ * @param {string} rerenderKey A key to use to force a rerender.
470
+ *
471
+ * @example
472
+ * import { mount } from '@cypress/react'
473
+ * import { Stepper } from './Stepper'
474
+ *
475
+ * it('mounts', () => {
476
+ * mount(<StepperComponent />)
477
+ * cy.get('[data-cy=increment]').click()
478
+ * cy.get('[data-cy=counter]').should('have.text', '1')
479
+ * }
480
+ *
481
+ * @see {@link https://on.cypress.io/mounting-react} for more details.
482
+ *
483
+ * @returns {Cypress.Chainable<MountReturn>} The mounted component.
484
+ */
561
485
  function mount(jsx, options = {}, rerenderKey) {
486
+ // Remove last mounted component if cy.mount is called more than once in a test
487
+ // React by default removes the last component when calling render, but we should remove the root
488
+ // to wipe away any state
489
+ cleanup();
562
490
  const internalOptions = {
563
491
  reactDom: ReactDOM,
564
492
  render: (reactComponent, el) => {
@@ -567,13 +495,21 @@ function mount(jsx, options = {}, rerenderKey) {
567
495
  }
568
496
  return root.render(reactComponent);
569
497
  },
570
- unmount,
498
+ unmount: internalUnmount,
571
499
  cleanup,
572
500
  };
573
501
  return makeMountFn('mount', jsx, Object.assign({ ReactDom: ReactDOM }, options), rerenderKey, internalOptions);
574
502
  }
575
- function unmount(options = { log: true }) {
503
+ function internalUnmount(options = { log: true }) {
576
504
  return makeUnmountFn(options);
505
+ }
506
+ /**
507
+ * Removed as of Cypress 11.0.0.
508
+ * @see https://on.cypress.io/migration-11-0-0-component-testing-updates
509
+ */
510
+ function unmount(options = { log: true }) {
511
+ // @ts-expect-error - undocumented API
512
+ Cypress.utils.throwErrByPath('mount.unmount');
577
513
  }
578
514
 
579
- export { mount, unmount };
515
+ export { getContainerEl$1 as getContainerEl, mount, unmount };
@@ -1,6 +1,78 @@
1
- /// <reference types="cypress" />
2
- /// <reference types="cypress" />
3
- import React from 'react';
4
- import type { MountOptions, UnmountArgs } from '@cypress/react';
5
- export declare function mount(jsx: React.ReactNode, options?: MountOptions, rerenderKey?: string): Cypress.Chainable<import("@cypress/react").MountReturn>;
6
- export declare function unmount(options?: UnmountArgs): Cypress.Chainable<undefined>;
1
+ /// <reference types="cypress" />
2
+
3
+ /// <reference types="cypress" />
4
+ import React__default from 'react';
5
+ import * as react_dom from 'react-dom';
6
+
7
+ interface UnmountArgs {
8
+ log: boolean;
9
+ boundComponentMessage?: string;
10
+ }
11
+ declare type MountOptions = Partial<MountReactComponentOptions>;
12
+ interface MountReactComponentOptions {
13
+ ReactDom: typeof react_dom;
14
+ /**
15
+ * Log the mounting command into Cypress Command Log,
16
+ * true by default.
17
+ */
18
+ log: boolean;
19
+ /**
20
+ * Render component in React [strict mode](https://reactjs.org/docs/strict-mode.html)
21
+ * It activates additional checks and warnings for child components.
22
+ */
23
+ strict: boolean;
24
+ }
25
+ interface MountReturn {
26
+ /**
27
+ * The component that was rendered.
28
+ */
29
+ component: React__default.ReactNode;
30
+ /**
31
+ * Rerenders the specified component with new props. This allows testing of components that store state (`setState`)
32
+ * or have asynchronous updates (`useEffect`, `useLayoutEffect`).
33
+ */
34
+ rerender: (component: React__default.ReactNode) => globalThis.Cypress.Chainable<MountReturn>;
35
+ /**
36
+ * Removes the mounted component.
37
+ *
38
+ * Removed as of Cypress 11.0.0.
39
+ * @see https://on.cypress.io/migration-11-0-0-component-testing-updates
40
+ */
41
+ unmount: (payload: UnmountArgs) => void;
42
+ }
43
+
44
+ /**
45
+ * Gets the root element used to mount the component.
46
+ * @returns {HTMLElement} The root element
47
+ * @throws {Error} If the root element is not found
48
+ */
49
+ declare const getContainerEl: () => HTMLElement;
50
+
51
+ /**
52
+ * Mounts a React component into the DOM.
53
+ * @param {import('react').JSX.Element} jsx The React component to mount.
54
+ * @param {MountOptions} options Options to pass to the mount function.
55
+ * @param {string} rerenderKey A key to use to force a rerender.
56
+ *
57
+ * @example
58
+ * import { mount } from '@cypress/react'
59
+ * import { Stepper } from './Stepper'
60
+ *
61
+ * it('mounts', () => {
62
+ * mount(<StepperComponent />)
63
+ * cy.get('[data-cy=increment]').click()
64
+ * cy.get('[data-cy=counter]').should('have.text', '1')
65
+ * }
66
+ *
67
+ * @see {@link https://on.cypress.io/mounting-react} for more details.
68
+ *
69
+ * @returns {Cypress.Chainable<MountReturn>} The mounted component.
70
+ */
71
+ declare function mount(jsx: React__default.ReactNode, options?: MountOptions, rerenderKey?: string): Cypress.Chainable<MountReturn>;
72
+ /**
73
+ * Removed as of Cypress 11.0.0.
74
+ * @see https://on.cypress.io/migration-11-0-0-component-testing-updates
75
+ */
76
+ declare function unmount(options?: UnmountArgs): void;
77
+
78
+ export { getContainerEl, mount, unmount };
@@ -10,6 +10,7 @@
10
10
  "watch": "yarn build --watch --watch.exclude ./dist/**/*"
11
11
  },
12
12
  "devDependencies": {
13
+ "@cypress/mount-utils": "0.0.0-development",
13
14
  "@cypress/react": "0.0.0-development",
14
15
  "@rollup/plugin-commonjs": "^17.1.0",
15
16
  "@rollup/plugin-node-resolve": "^11.1.1",
@@ -1,3 +1,23 @@
1
+ # [@cypress/svelte-v2.0.0](https://github.com/cypress-io/cypress/compare/@cypress/svelte-v1.0.2...@cypress/svelte-v2.0.0) (2022-11-07)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * remove last mounted component upon subsequent mount calls ([#24470](https://github.com/cypress-io/cypress/issues/24470)) ([f39eb1c](https://github.com/cypress-io/cypress/commit/f39eb1c19e0923bda7ae263168fc6448da942d54))
7
+ * remove some CT functions and props ([#24419](https://github.com/cypress-io/cypress/issues/24419)) ([294985f](https://github.com/cypress-io/cypress/commit/294985f8b3e0fa00ed66d25f88c8814603766074))
8
+
9
+
10
+ ### BREAKING CHANGES
11
+
12
+ * remove last mounted component upon subsequent mount calls of mount
13
+
14
+ # [@cypress/svelte-v1.0.2](https://github.com/cypress-io/cypress/compare/@cypress/svelte-v1.0.1...@cypress/svelte-v1.0.2) (2022-11-01)
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * Hovering over mount in command log does not show component in AUT ([#24346](https://github.com/cypress-io/cypress/issues/24346)) ([355d210](https://github.com/cypress-io/cypress/commit/355d2101d38ea4d1e93b9c571cf77babab2bbbfc))
20
+
1
21
  # [@cypress/svelte-v1.0.1](https://github.com/cypress-io/cypress/compare/@cypress/svelte-v1.0.0...@cypress/svelte-v1.0.1) (2022-09-29)
2
22
 
3
23
 
@@ -10,6 +10,11 @@
10
10
  Object.defineProperty(exports, '__esModule', { value: true });
11
11
 
12
12
  const ROOT_SELECTOR = '[data-cy-root]';
13
+ /**
14
+ * Gets the root element used to mount the component.
15
+ * @returns {HTMLElement} The root element
16
+ * @throws {Error} If the root element is not found
17
+ */
13
18
  const getContainerEl = () => {
14
19
  const el = document.querySelector(ROOT_SELECTOR);
15
20
  if (el) {
@@ -17,122 +22,19 @@ const getContainerEl = () => {
17
22
  }
18
23
  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.`);
19
24
  };
20
- /**
21
- * Remove any style or extra link elements from the iframe placeholder
22
- * left from any previous test
23
- *
24
- */
25
- function cleanupStyles() {
26
- const styles = document.body.querySelectorAll('[data-cy=injected-style-tag]');
27
- styles.forEach((styleElement) => {
28
- if (styleElement.parentElement) {
29
- styleElement.parentElement.removeChild(styleElement);
30
- }
31
- });
32
- const links = document.body.querySelectorAll('[data-cy=injected-stylesheet]');
33
- links.forEach((link) => {
34
- if (link.parentElement) {
35
- link.parentElement.removeChild(link);
25
+ function checkForRemovedStyleOptions(mountingOptions) {
26
+ for (const key of ['cssFile', 'cssFiles', 'style', 'styles', 'stylesheet', 'stylesheets']) {
27
+ if (mountingOptions[key]) {
28
+ Cypress.utils.throwErrByPath('mount.removed_style_mounting_options', key);
36
29
  }
37
- });
38
- }
39
- /**
40
- * Insert links to external style resources.
41
- */
42
- function insertStylesheets(stylesheets, document, el) {
43
- stylesheets.forEach((href) => {
44
- const link = document.createElement('link');
45
- link.type = 'text/css';
46
- link.rel = 'stylesheet';
47
- link.href = href;
48
- link.dataset.cy = 'injected-stylesheet';
49
- document.body.insertBefore(link, el);
50
- });
51
- }
52
- /**
53
- * Inserts a single stylesheet element
54
- */
55
- function insertStyles(styles, document, el) {
56
- styles.forEach((style) => {
57
- const styleElement = document.createElement('style');
58
- styleElement.dataset.cy = 'injected-style-tag';
59
- styleElement.appendChild(document.createTextNode(style));
60
- document.body.insertBefore(styleElement, el);
61
- });
62
- }
63
- function insertSingleCssFile(cssFilename, document, el, log) {
64
- return cy.readFile(cssFilename, { log }).then((css) => {
65
- const style = document.createElement('style');
66
- style.appendChild(document.createTextNode(css));
67
- document.body.insertBefore(style, el);
68
- });
69
- }
70
- /**
71
- * Reads the given CSS file from local file system
72
- * and adds the loaded style text as an element.
73
- */
74
- function insertLocalCssFiles(cssFilenames, document, el, log) {
75
- return Cypress.Promise.mapSeries(cssFilenames, (cssFilename) => {
76
- return insertSingleCssFile(cssFilename, document, el, log);
77
- });
30
+ }
78
31
  }
79
32
  /**
80
- * Injects custom style text or CSS file or 3rd party style resources
81
- * into the given document.
33
+ * Utility function to register CT side effects and run cleanup code during the "test:before:run" Cypress hook
34
+ * @param optionalCallback Callback to be called before the next test runs
82
35
  */
83
- const injectStylesBeforeElement = (options, document, el) => {
84
- if (!el)
85
- return;
86
- // first insert all stylesheets as Link elements
87
- let stylesheets = [];
88
- if (typeof options.stylesheet === 'string') {
89
- stylesheets.push(options.stylesheet);
90
- }
91
- else if (Array.isArray(options.stylesheet)) {
92
- stylesheets = stylesheets.concat(options.stylesheet);
93
- }
94
- if (typeof options.stylesheets === 'string') {
95
- options.stylesheets = [options.stylesheets];
96
- }
97
- if (options.stylesheets) {
98
- stylesheets = stylesheets.concat(options.stylesheets);
99
- }
100
- insertStylesheets(stylesheets, document, el);
101
- // insert any styles as <style>...</style> elements
102
- let styles = [];
103
- if (typeof options.style === 'string') {
104
- styles.push(options.style);
105
- }
106
- else if (Array.isArray(options.style)) {
107
- styles = styles.concat(options.style);
108
- }
109
- if (typeof options.styles === 'string') {
110
- styles.push(options.styles);
111
- }
112
- else if (Array.isArray(options.styles)) {
113
- styles = styles.concat(options.styles);
114
- }
115
- insertStyles(styles, document, el);
116
- // now load any css files by path and add their content
117
- // as <style>...</style> elements
118
- let cssFiles = [];
119
- if (typeof options.cssFile === 'string') {
120
- cssFiles.push(options.cssFile);
121
- }
122
- else if (Array.isArray(options.cssFile)) {
123
- cssFiles = cssFiles.concat(options.cssFile);
124
- }
125
- if (typeof options.cssFiles === 'string') {
126
- cssFiles.push(options.cssFiles);
127
- }
128
- else if (Array.isArray(options.cssFiles)) {
129
- cssFiles = cssFiles.concat(options.cssFiles);
130
- }
131
- return insertLocalCssFiles(cssFiles, document, el, options.log);
132
- };
133
36
  function setupHooks(optionalCallback) {
134
- // Consumed by the framework "mount" libs. A user might register their own mount in the scaffolded 'commands.js'
135
- // file that is imported by e2e and component support files by default. We don't want CT side effects to run when e2e
37
+ // We don't want CT side effects to run when e2e
136
38
  // testing so we early return.
137
39
  // System test to verify CT side effects do not pollute e2e: system-tests/test/e2e_with_mount_import_spec.ts
138
40
  if (Cypress.testingType !== 'component') {
@@ -147,7 +49,6 @@ function setupHooks(optionalCallback) {
147
49
  // @ts-ignore
148
50
  Cypress.on('test:before:run', () => {
149
51
  optionalCallback === null || optionalCallback === void 0 ? void 0 : optionalCallback();
150
- cleanupStyles();
151
52
  });
152
53
  }
153
54
 
@@ -179,11 +80,15 @@ const getComponentDisplayName = (Component) => {
179
80
  * mount(Counter, { props: { count: 42 } })
180
81
  * cy.get('button').contains(42)
181
82
  * })
83
+ *
84
+ * @see {@link https://on.cypress.io/mounting-svelte} for more details.
182
85
  */
183
86
  function mount(Component, options = {}) {
87
+ checkForRemovedStyleOptions(options);
184
88
  return cy.then(() => {
89
+ // Remove last mounted component if cy.mount is called more than once in a test
90
+ cleanup();
185
91
  const target = getContainerEl();
186
- injectStylesBeforeElement(options, document, target);
187
92
  const ComponentConstructor = (Component.default || Component);
188
93
  componentInstance = new ComponentConstructor(Object.assign({ target }, options));
189
94
  // by waiting, we are delaying test execution for the next tick of event loop
@@ -194,7 +99,7 @@ function mount(Component, options = {}) {
194
99
  Cypress.log({
195
100
  name: 'mount',
196
101
  message: [mountMessage],
197
- }).snapshot('mounted').end();
102
+ });
198
103
  }
199
104
  })
200
105
  .wrap({ component: componentInstance }, { log: false });