cypress 10.2.0 → 10.4.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 (64) hide show
  1. package/lib/exec/open.js +7 -2
  2. package/lib/exec/spawn.js +7 -2
  3. package/mount-utils/CHANGELOG.md +0 -1
  4. package/mount-utils/README.md +7 -0
  5. package/mount-utils/dist/index.js +8 -1
  6. package/mount-utils/package.json +1 -0
  7. package/package.json +20 -10
  8. package/react/CHANGELOG.md +0 -19
  9. package/react/README.md +28 -323
  10. package/react/dist/createMount.d.ts +30 -0
  11. package/react/dist/cypress-react.cjs.js +76 -80
  12. package/react/dist/cypress-react.esm-bundler.js +68 -76
  13. package/react/dist/getDisplayName.d.ts +1 -1
  14. package/react/dist/index.d.ts +2 -0
  15. package/react/dist/mount.d.ts +5 -141
  16. package/react/dist/types.d.ts +50 -0
  17. package/react/package.json +1 -5
  18. package/react18/dist/cypress-react.cjs.js +422 -0
  19. package/react18/dist/cypress-react.esm-bundler.js +394 -0
  20. package/react18/dist/index.d.ts +5 -0
  21. package/react18/package.json +59 -0
  22. package/types/cypress.d.ts +11 -2
  23. package/types/index.d.ts +1 -1
  24. package/types/{net-stubbing.ts → net-stubbing.d.ts} +0 -0
  25. package/vue/CHANGELOG.md +2 -17
  26. package/vue/README.md +17 -607
  27. package/vue/dist/@vue/test-utils/baseWrapper.d.ts +63 -0
  28. package/vue/dist/@vue/test-utils/components/RouterLinkStub.d.ts +21 -0
  29. package/vue/dist/@vue/test-utils/config.d.ts +30 -0
  30. package/vue/dist/@vue/test-utils/constants/dom-events.d.ts +900 -0
  31. package/vue/dist/@vue/test-utils/createDomEvent.d.ts +9 -0
  32. package/vue/dist/@vue/test-utils/domWrapper.d.ts +18 -0
  33. package/vue/dist/@vue/test-utils/emit.d.ts +5 -0
  34. package/vue/dist/@vue/test-utils/errorWrapper.d.ts +1 -0
  35. package/vue/dist/@vue/test-utils/index.d.ts +11 -0
  36. package/vue/dist/@vue/test-utils/interfaces/wrapperLike.d.ts +56 -0
  37. package/vue/dist/@vue/test-utils/mount.d.ts +35 -0
  38. package/vue/dist/@vue/test-utils/stubs.d.ts +22 -0
  39. package/vue/dist/@vue/test-utils/types.d.ts +125 -0
  40. package/vue/dist/@vue/test-utils/utils/autoUnmount.d.ts +5 -0
  41. package/vue/dist/@vue/test-utils/utils/compileSlots.d.ts +2 -0
  42. package/vue/dist/@vue/test-utils/utils/componentName.d.ts +4 -0
  43. package/vue/dist/@vue/test-utils/utils/find.d.ts +10 -0
  44. package/vue/dist/@vue/test-utils/utils/flushPromises.d.ts +1 -0
  45. package/vue/dist/@vue/test-utils/utils/getRootNodes.d.ts +2 -0
  46. package/vue/dist/@vue/test-utils/utils/isElement.d.ts +1 -0
  47. package/vue/dist/@vue/test-utils/utils/isElementVisible.d.ts +6 -0
  48. package/vue/dist/@vue/test-utils/utils/matchName.d.ts +1 -0
  49. package/vue/dist/@vue/test-utils/utils/stringifyNode.d.ts +1 -0
  50. package/vue/dist/@vue/test-utils/utils/vueCompatSupport.d.ts +8 -0
  51. package/vue/dist/@vue/test-utils/utils/vueShared.d.ts +3 -0
  52. package/vue/dist/@vue/test-utils/utils.d.ts +13 -0
  53. package/vue/dist/@vue/test-utils/vueWrapper.d.ts +35 -0
  54. package/vue/dist/@vue/test-utils/wrapperFactory.d.ts +14 -0
  55. package/vue/dist/cypress-vue.cjs.js +5583 -5209
  56. package/vue/dist/cypress-vue.esm-bundler.js +5584 -5211
  57. package/vue/dist/index.d.ts +35 -3
  58. package/vue/package.json +11 -7
  59. package/vue2/README.md +11 -627
  60. package/vue2/dist/cypress-vue2.browser.js +268 -262
  61. package/vue2/dist/cypress-vue2.cjs.js +267 -261
  62. package/vue2/dist/cypress-vue2.esm-bundler.js +265 -259
  63. package/vue2/package.json +1 -1
  64. package/react/dist/cypress-react.browser.js +0 -497
@@ -0,0 +1,30 @@
1
+ /// <reference types="cypress" />
2
+ import * as React from 'react';
3
+ import ReactDOM from 'react-dom';
4
+ import type { InternalMountOptions, InternalUnmountOptions, MountOptions, MountReturn, UnmountArgs } from './types';
5
+ export declare let lastMountedReactDom: (typeof ReactDOM) | undefined;
6
+ /**
7
+ * Create an `mount` function. Performs all the non-React-version specific
8
+ * behavior related to mounting. The React-version-specific code
9
+ * is injected. This helps us to maintain a consistent public API
10
+ * and handle breaking changes in React's rendering API.
11
+ *
12
+ * This is designed to be consumed by `npm/react{16,17,18}`, and other React adapters,
13
+ * or people writing adapters for third-party, custom adapters.
14
+ */
15
+ export declare const makeMountFn: (type: 'mount' | 'rerender', jsx: React.ReactNode, options?: MountOptions, rerenderKey?: string | undefined, internalMountOptions?: InternalMountOptions | undefined) => globalThis.Cypress.Chainable<MountReturn>;
16
+ /**
17
+ * Create an `unmount` function. Performs all the non-React-version specific
18
+ * behavior related to unmounting.
19
+ *
20
+ * This is designed to be consumed by `npm/react{16,17,18}`, and other React adapters,
21
+ * or people writing adapters for third-party, custom adapters.
22
+ */
23
+ export declare const makeUnmountFn: (options: UnmountArgs, internalUnmountOptions: InternalUnmountOptions) => Cypress.Chainable<JQuery<HTMLElement>>;
24
+ declare const _mount: (jsx: React.ReactNode, options?: MountOptions) => Cypress.Chainable<MountReturn>;
25
+ export declare const createMount: (defaultOptions: MountOptions) => (element: React.ReactElement, options?: Partial<import("@cypress/mount-utils").StyleOptions & import("./types").MountReactComponentOptions> | undefined) => Cypress.Chainable<MountReturn>;
26
+ /** @deprecated Should be removed in the next major version */
27
+ export default _mount;
28
+ export interface JSX extends Function {
29
+ displayName: string;
30
+ }
@@ -12,6 +12,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
12
12
  var React = require('react');
13
13
  var ReactDOM = require('react-dom');
14
14
 
15
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
16
+
15
17
  function _interopNamespace(e) {
16
18
  if (e && e.__esModule) return e;
17
19
  var n = Object.create(null);
@@ -31,9 +33,9 @@ function _interopNamespace(e) {
31
33
  }
32
34
 
33
35
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
34
- var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
36
+ var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
35
37
 
36
- /*! *****************************************************************************
38
+ /******************************************************************************
37
39
  Copyright (c) Microsoft Corporation.
38
40
 
39
41
  Permission to use, copy, modify, and/or distribute this software for any
@@ -110,7 +112,7 @@ const getContainerEl = () => {
110
112
  if (el) {
111
113
  return el;
112
114
  }
113
- throw Error(`No element found that matches selector ${ROOT_SELECTOR}. Please use the mount utils to mount it properly`);
115
+ 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.`);
114
116
  };
115
117
  /**
116
118
  * Remove any style or extra link elements from the iframe placeholder
@@ -226,6 +228,13 @@ const injectStylesBeforeElement = (options, document, el) => {
226
228
  return insertLocalCssFiles(cssFiles, document, el, options.log);
227
229
  };
228
230
  function setupHooks(optionalCallback) {
231
+ // Consumed by the framework "mount" libs. A user might register their own mount in the scaffolded 'commands.js'
232
+ // file that is imported by e2e and component support files by default. We don't want CT side effects to run when e2e
233
+ // testing so we early return.
234
+ // System test to verify CT side effects do not pollute e2e: system-tests/test/e2e_with_mount_import_spec.ts
235
+ if (Cypress.testingType !== 'component') {
236
+ return;
237
+ }
229
238
  // When running component specs, we cannot allow "cy.visit"
230
239
  // because it will wipe out our preparation work, and does not make much sense
231
240
  // thus we overwrite "cy.visit" to throw an error
@@ -248,37 +257,21 @@ var injectStyles = function (options) {
248
257
  return injectStylesBeforeElement(options, document, el);
249
258
  };
250
259
  };
260
+ exports.lastMountedReactDom = void 0;
251
261
  /**
252
- * Mount a React component in a blank document; register it as an alias
253
- * To access: use an alias or original component reference
254
- * @function mount
255
- * @param {React.ReactElement} jsx - component to mount
256
- * @param {MountOptions} [options] - options, like alias, styles
257
- * @see https://github.com/bahmutov/@cypress/react
258
- * @see https://glebbahmutov.com/blog/my-vision-for-component-tests/
259
- * @example
260
- ```
261
- import Hello from './hello.jsx'
262
- import { mount } from '@cypress/react'
263
- it('works', () => {
264
- mount(<Hello onClick={cy.stub()} />)
265
- // use Cypress commands
266
- cy.contains('Hello').click()
267
- })
268
- ```
269
- **/
270
- var mount = function (jsx, options) {
271
- if (options === void 0) { options = {}; }
272
- return _mount('mount', jsx, options);
273
- };
274
- var lastMountedReactDom;
275
- /**
276
- * @see `mount`
277
- * @param type The type of mount executed
278
- * @param rerenderKey If specified, use the provided key rather than generating a new one
262
+ * Create an `mount` function. Performs all the non-React-version specific
263
+ * behavior related to mounting. The React-version-specific code
264
+ * is injected. This helps us to maintain a consistent public API
265
+ * and handle breaking changes in React's rendering API.
266
+ *
267
+ * This is designed to be consumed by `npm/react{16,17,18}`, and other React adapters,
268
+ * or people writing adapters for third-party, custom adapters.
279
269
  */
280
- var _mount = function (type, jsx, options, rerenderKey) {
270
+ var makeMountFn = function (type, jsx, options, rerenderKey, internalMountOptions) {
281
271
  if (options === void 0) { options = {}; }
272
+ if (!internalMountOptions) {
273
+ throw Error('internalMountOptions must be provided with `render` and `reactDom` parameters');
274
+ }
282
275
  // Get the display name property via the component constructor
283
276
  // @ts-ignore FIXME
284
277
  var componentName = getDisplayName(jsx.type, options.alias);
@@ -291,8 +284,8 @@ var _mount = function (type, jsx, options, rerenderKey) {
291
284
  .then(injectStyles(options))
292
285
  .then(function () {
293
286
  var _a, _b, _c;
294
- var reactDomToUse = options.ReactDom || ReactDOM__namespace;
295
- lastMountedReactDom = reactDomToUse;
287
+ var reactDomToUse = internalMountOptions.reactDom;
288
+ exports.lastMountedReactDom = reactDomToUse;
296
289
  var el = getContainerEl();
297
290
  if (!el) {
298
291
  throw new Error([
@@ -309,7 +302,7 @@ var _mount = function (type, jsx, options, rerenderKey) {
309
302
  // since we always surround the component with a fragment
310
303
  // let's get back the original component
311
304
  var userComponent = reactComponent.props.children;
312
- reactDomToUse.render(reactComponent, el);
305
+ internalMountOptions.render(reactComponent, el, reactDomToUse);
313
306
  if (options.log !== false) {
314
307
  Cypress.log({
315
308
  name: type,
@@ -334,8 +327,8 @@ var _mount = function (type, jsx, options, rerenderKey) {
334
327
  .then(function () {
335
328
  return cy.wrap({
336
329
  component: userComponent,
337
- rerender: function (newComponent) { return _mount('rerender', newComponent, options, key); },
338
- unmount: function () { return _unmount({ boundComponentMessage: jsxComponentName, log: true }); },
330
+ rerender: function (newComponent) { return makeMountFn('rerender', newComponent, options, key, internalMountOptions); },
331
+ unmount: internalMountOptions.unmount,
339
332
  }, { log: false });
340
333
  })
341
334
  // by waiting, we delaying test execution for the next tick of event loop
@@ -346,32 +339,19 @@ var _mount = function (type, jsx, options, rerenderKey) {
346
339
  });
347
340
  };
348
341
  /**
349
- * Removes the mounted component. Notice this command automatically
350
- * queues up the `unmount` into Cypress chain, thus you don't need `.then`
351
- * to call it.
352
- * @see https://github.com/cypress-io/cypress/tree/develop/npm/react/cypress/component/basic/unmount
353
- * @example
354
- ```
355
- import { mount, unmount } from '@cypress/react'
356
- it('works', () => {
357
- mount(...)
358
- // interact with the component using Cypress commands
359
- // whenever you want to unmount
360
- unmount()
361
- })
362
- ```
342
+ * Create an `unmount` function. Performs all the non-React-version specific
343
+ * behavior related to unmounting.
344
+ *
345
+ * This is designed to be consumed by `npm/react{16,17,18}`, and other React adapters,
346
+ * or people writing adapters for third-party, custom adapters.
363
347
  */
364
- // @ts-ignore
365
- var unmount = function (options) {
366
- if (options === void 0) { options = { log: true }; }
367
- return _unmount(options);
368
- };
369
- var _unmount = function (options) {
348
+ var makeUnmountFn = function (options, internalUnmountOptions) {
370
349
  return cy.then(function () {
371
350
  return cy.get(ROOT_SELECTOR, { log: false }).then(function ($el) {
372
351
  var _a;
373
- if (lastMountedReactDom) {
374
- var wasUnmounted = lastMountedReactDom.unmountComponentAtNode($el[0]);
352
+ if (exports.lastMountedReactDom) {
353
+ internalUnmountOptions.unmount($el[0]);
354
+ var wasUnmounted = internalUnmountOptions.unmount($el[0]);
375
355
  if (wasUnmounted && options.log) {
376
356
  Cypress.log({
377
357
  name: 'unmount',
@@ -395,39 +375,53 @@ var _unmount = function (options) {
395
375
  // we are not in the context of a test
396
376
  var preMountCleanup = function () {
397
377
  var el = getContainerEl();
398
- if (el && lastMountedReactDom) {
399
- lastMountedReactDom.unmountComponentAtNode(el);
378
+ if (el && exports.lastMountedReactDom) {
379
+ exports.lastMountedReactDom.unmountComponentAtNode(el);
400
380
  }
401
381
  };
402
- /**
403
- * Creates new instance of `mount` function with default options
404
- * @function createMount
405
- * @param {MountOptions} [defaultOptions] - defaultOptions for returned `mount` function
406
- * @returns new instance of `mount` with assigned options
407
- * @example
408
- * ```
409
- * import Hello from './hello.jsx'
410
- * import { createMount } from '@cypress/react'
411
- *
412
- * const mount = createMount({ strict: true, cssFile: 'path/to/any/css/file.css' })
413
- *
414
- * it('works', () => {
415
- * mount(<Hello />)
416
- * // use Cypress commands
417
- * cy.get('button').should('have.css', 'color', 'rgb(124, 12, 109)')
418
- * })
419
- ```
420
- **/
382
+ var _mount = function (jsx, options) {
383
+ if (options === void 0) { options = {}; }
384
+ return makeMountFn('mount', jsx, options);
385
+ };
421
386
  var createMount = function (defaultOptions) {
422
387
  return function (element, options) {
423
- return mount(element, __assign(__assign({}, defaultOptions), options));
388
+ return _mount(element, __assign(__assign({}, defaultOptions), options));
424
389
  };
425
390
  };
391
+ // Side effects from "import { mount } from '@cypress/<my-framework>'" are annoying, we should avoid doing this
392
+ // by creating an explicit function/import that the user can register in their 'component.js' support file,
393
+ // such as:
394
+ // import 'cypress/<my-framework>/support'
395
+ // or
396
+ // import { registerCT } from 'cypress/<my-framework>'
397
+ // registerCT()
398
+ // Note: This would be a breaking change
426
399
  // it is required to unmount component in beforeEach hook in order to provide a clean state inside test
427
400
  // because `mount` can be called after some preparation that can side effect unmount
428
401
  // @see npm/react/cypress/component/advanced/set-timeout-example/loading-indicator-spec.js
429
402
  setupHooks(preMountCleanup);
430
403
 
404
+ function mount(jsx, options, rerenderKey) {
405
+ if (options === void 0) { options = {}; }
406
+ var internalOptions = {
407
+ reactDom: ReactDOM__default["default"],
408
+ render: function (reactComponent, el, reactDomToUse) {
409
+ return (reactDomToUse || ReactDOM__default["default"]).render(reactComponent, el);
410
+ },
411
+ unmount: unmount,
412
+ };
413
+ return makeMountFn('mount', jsx, __assign({ ReactDom: ReactDOM__default["default"] }, options), rerenderKey, internalOptions);
414
+ }
415
+ function unmount(options) {
416
+ if (options === void 0) { options = { log: true }; }
417
+ var internalOptions = {
418
+ unmount: function (el) {
419
+ return (exports.lastMountedReactDom || ReactDOM__default["default"]).unmountComponentAtNode(el);
420
+ },
421
+ };
422
+ return makeUnmountFn(options, internalOptions);
423
+ }
424
+
431
425
  // mounting hooks inside a test component mostly copied from
432
426
  // https://github.com/testing-library/react-hooks-testing-library/blob/master/src/pure.js
433
427
  function resultContainer() {
@@ -490,6 +484,8 @@ var mountHook = function (hookFn) {
490
484
  };
491
485
 
492
486
  exports.createMount = createMount;
487
+ exports.makeMountFn = makeMountFn;
488
+ exports.makeUnmountFn = makeUnmountFn;
493
489
  exports.mount = mount;
494
490
  exports.mountHook = mountHook;
495
491
  exports.unmount = unmount;
@@ -6,9 +6,9 @@
6
6
  */
7
7
 
8
8
  import * as React from 'react';
9
- import * as ReactDOM from 'react-dom';
9
+ import ReactDOM from 'react-dom';
10
10
 
11
- /*! *****************************************************************************
11
+ /******************************************************************************
12
12
  Copyright (c) Microsoft Corporation.
13
13
 
14
14
  Permission to use, copy, modify, and/or distribute this software for any
@@ -85,7 +85,7 @@ const getContainerEl = () => {
85
85
  if (el) {
86
86
  return el;
87
87
  }
88
- throw Error(`No element found that matches selector ${ROOT_SELECTOR}. Please use the mount utils to mount it properly`);
88
+ 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.`);
89
89
  };
90
90
  /**
91
91
  * Remove any style or extra link elements from the iframe placeholder
@@ -201,6 +201,13 @@ const injectStylesBeforeElement = (options, document, el) => {
201
201
  return insertLocalCssFiles(cssFiles, document, el, options.log);
202
202
  };
203
203
  function setupHooks(optionalCallback) {
204
+ // Consumed by the framework "mount" libs. A user might register their own mount in the scaffolded 'commands.js'
205
+ // file that is imported by e2e and component support files by default. We don't want CT side effects to run when e2e
206
+ // testing so we early return.
207
+ // System test to verify CT side effects do not pollute e2e: system-tests/test/e2e_with_mount_import_spec.ts
208
+ if (Cypress.testingType !== 'component') {
209
+ return;
210
+ }
204
211
  // When running component specs, we cannot allow "cy.visit"
205
212
  // because it will wipe out our preparation work, and does not make much sense
206
213
  // thus we overwrite "cy.visit" to throw an error
@@ -223,37 +230,21 @@ var injectStyles = function (options) {
223
230
  return injectStylesBeforeElement(options, document, el);
224
231
  };
225
232
  };
226
- /**
227
- * Mount a React component in a blank document; register it as an alias
228
- * To access: use an alias or original component reference
229
- * @function mount
230
- * @param {React.ReactElement} jsx - component to mount
231
- * @param {MountOptions} [options] - options, like alias, styles
232
- * @see https://github.com/bahmutov/@cypress/react
233
- * @see https://glebbahmutov.com/blog/my-vision-for-component-tests/
234
- * @example
235
- ```
236
- import Hello from './hello.jsx'
237
- import { mount } from '@cypress/react'
238
- it('works', () => {
239
- mount(<Hello onClick={cy.stub()} />)
240
- // use Cypress commands
241
- cy.contains('Hello').click()
242
- })
243
- ```
244
- **/
245
- var mount = function (jsx, options) {
246
- if (options === void 0) { options = {}; }
247
- return _mount('mount', jsx, options);
248
- };
249
233
  var lastMountedReactDom;
250
234
  /**
251
- * @see `mount`
252
- * @param type The type of mount executed
253
- * @param rerenderKey If specified, use the provided key rather than generating a new one
235
+ * Create an `mount` function. Performs all the non-React-version specific
236
+ * behavior related to mounting. The React-version-specific code
237
+ * is injected. This helps us to maintain a consistent public API
238
+ * and handle breaking changes in React's rendering API.
239
+ *
240
+ * This is designed to be consumed by `npm/react{16,17,18}`, and other React adapters,
241
+ * or people writing adapters for third-party, custom adapters.
254
242
  */
255
- var _mount = function (type, jsx, options, rerenderKey) {
243
+ var makeMountFn = function (type, jsx, options, rerenderKey, internalMountOptions) {
256
244
  if (options === void 0) { options = {}; }
245
+ if (!internalMountOptions) {
246
+ throw Error('internalMountOptions must be provided with `render` and `reactDom` parameters');
247
+ }
257
248
  // Get the display name property via the component constructor
258
249
  // @ts-ignore FIXME
259
250
  var componentName = getDisplayName(jsx.type, options.alias);
@@ -266,7 +257,7 @@ var _mount = function (type, jsx, options, rerenderKey) {
266
257
  .then(injectStyles(options))
267
258
  .then(function () {
268
259
  var _a, _b, _c;
269
- var reactDomToUse = options.ReactDom || ReactDOM;
260
+ var reactDomToUse = internalMountOptions.reactDom;
270
261
  lastMountedReactDom = reactDomToUse;
271
262
  var el = getContainerEl();
272
263
  if (!el) {
@@ -284,7 +275,7 @@ var _mount = function (type, jsx, options, rerenderKey) {
284
275
  // since we always surround the component with a fragment
285
276
  // let's get back the original component
286
277
  var userComponent = reactComponent.props.children;
287
- reactDomToUse.render(reactComponent, el);
278
+ internalMountOptions.render(reactComponent, el, reactDomToUse);
288
279
  if (options.log !== false) {
289
280
  Cypress.log({
290
281
  name: type,
@@ -309,8 +300,8 @@ var _mount = function (type, jsx, options, rerenderKey) {
309
300
  .then(function () {
310
301
  return cy.wrap({
311
302
  component: userComponent,
312
- rerender: function (newComponent) { return _mount('rerender', newComponent, options, key); },
313
- unmount: function () { return _unmount({ boundComponentMessage: jsxComponentName, log: true }); },
303
+ rerender: function (newComponent) { return makeMountFn('rerender', newComponent, options, key, internalMountOptions); },
304
+ unmount: internalMountOptions.unmount,
314
305
  }, { log: false });
315
306
  })
316
307
  // by waiting, we delaying test execution for the next tick of event loop
@@ -321,32 +312,19 @@ var _mount = function (type, jsx, options, rerenderKey) {
321
312
  });
322
313
  };
323
314
  /**
324
- * Removes the mounted component. Notice this command automatically
325
- * queues up the `unmount` into Cypress chain, thus you don't need `.then`
326
- * to call it.
327
- * @see https://github.com/cypress-io/cypress/tree/develop/npm/react/cypress/component/basic/unmount
328
- * @example
329
- ```
330
- import { mount, unmount } from '@cypress/react'
331
- it('works', () => {
332
- mount(...)
333
- // interact with the component using Cypress commands
334
- // whenever you want to unmount
335
- unmount()
336
- })
337
- ```
315
+ * Create an `unmount` function. Performs all the non-React-version specific
316
+ * behavior related to unmounting.
317
+ *
318
+ * This is designed to be consumed by `npm/react{16,17,18}`, and other React adapters,
319
+ * or people writing adapters for third-party, custom adapters.
338
320
  */
339
- // @ts-ignore
340
- var unmount = function (options) {
341
- if (options === void 0) { options = { log: true }; }
342
- return _unmount(options);
343
- };
344
- var _unmount = function (options) {
321
+ var makeUnmountFn = function (options, internalUnmountOptions) {
345
322
  return cy.then(function () {
346
323
  return cy.get(ROOT_SELECTOR, { log: false }).then(function ($el) {
347
324
  var _a;
348
325
  if (lastMountedReactDom) {
349
- var wasUnmounted = lastMountedReactDom.unmountComponentAtNode($el[0]);
326
+ internalUnmountOptions.unmount($el[0]);
327
+ var wasUnmounted = internalUnmountOptions.unmount($el[0]);
350
328
  if (wasUnmounted && options.log) {
351
329
  Cypress.log({
352
330
  name: 'unmount',
@@ -374,35 +352,49 @@ var preMountCleanup = function () {
374
352
  lastMountedReactDom.unmountComponentAtNode(el);
375
353
  }
376
354
  };
377
- /**
378
- * Creates new instance of `mount` function with default options
379
- * @function createMount
380
- * @param {MountOptions} [defaultOptions] - defaultOptions for returned `mount` function
381
- * @returns new instance of `mount` with assigned options
382
- * @example
383
- * ```
384
- * import Hello from './hello.jsx'
385
- * import { createMount } from '@cypress/react'
386
- *
387
- * const mount = createMount({ strict: true, cssFile: 'path/to/any/css/file.css' })
388
- *
389
- * it('works', () => {
390
- * mount(<Hello />)
391
- * // use Cypress commands
392
- * cy.get('button').should('have.css', 'color', 'rgb(124, 12, 109)')
393
- * })
394
- ```
395
- **/
355
+ var _mount = function (jsx, options) {
356
+ if (options === void 0) { options = {}; }
357
+ return makeMountFn('mount', jsx, options);
358
+ };
396
359
  var createMount = function (defaultOptions) {
397
360
  return function (element, options) {
398
- return mount(element, __assign(__assign({}, defaultOptions), options));
361
+ return _mount(element, __assign(__assign({}, defaultOptions), options));
399
362
  };
400
363
  };
364
+ // Side effects from "import { mount } from '@cypress/<my-framework>'" are annoying, we should avoid doing this
365
+ // by creating an explicit function/import that the user can register in their 'component.js' support file,
366
+ // such as:
367
+ // import 'cypress/<my-framework>/support'
368
+ // or
369
+ // import { registerCT } from 'cypress/<my-framework>'
370
+ // registerCT()
371
+ // Note: This would be a breaking change
401
372
  // it is required to unmount component in beforeEach hook in order to provide a clean state inside test
402
373
  // because `mount` can be called after some preparation that can side effect unmount
403
374
  // @see npm/react/cypress/component/advanced/set-timeout-example/loading-indicator-spec.js
404
375
  setupHooks(preMountCleanup);
405
376
 
377
+ function mount(jsx, options, rerenderKey) {
378
+ if (options === void 0) { options = {}; }
379
+ var internalOptions = {
380
+ reactDom: ReactDOM,
381
+ render: function (reactComponent, el, reactDomToUse) {
382
+ return (reactDomToUse || ReactDOM).render(reactComponent, el);
383
+ },
384
+ unmount: unmount,
385
+ };
386
+ return makeMountFn('mount', jsx, __assign({ ReactDom: ReactDOM }, options), rerenderKey, internalOptions);
387
+ }
388
+ function unmount(options) {
389
+ if (options === void 0) { options = { log: true }; }
390
+ var internalOptions = {
391
+ unmount: function (el) {
392
+ return (lastMountedReactDom || ReactDOM).unmountComponentAtNode(el);
393
+ },
394
+ };
395
+ return makeUnmountFn(options, internalOptions);
396
+ }
397
+
406
398
  // mounting hooks inside a test component mostly copied from
407
399
  // https://github.com/testing-library/react-hooks-testing-library/blob/master/src/pure.js
408
400
  function resultContainer() {
@@ -464,4 +456,4 @@ var mountHook = function (hookFn) {
464
456
  return mount(componentTest).then(function () { return result; });
465
457
  };
466
458
 
467
- export { createMount, mount, mountHook, unmount };
459
+ export { createMount, lastMountedReactDom, makeMountFn, makeUnmountFn, mount, mountHook, unmount };
@@ -1,4 +1,4 @@
1
- import { JSX } from './mount';
1
+ import { JSX } from './createMount';
2
2
  /**
3
3
  * Gets the display name of the component when possible.
4
4
  * @param type {JSX} The type object returned from creating the react element.
@@ -1,2 +1,4 @@
1
+ export * from './createMount';
1
2
  export * from './mount';
2
3
  export * from './mountHook';
4
+ export * from './types';
@@ -1,143 +1,7 @@
1
1
  /// <reference types="cypress" />
2
- import * as React from 'react';
3
- import * as ReactDOM from 'react-dom';
4
- import { StyleOptions } from '@cypress/mount-utils';
5
- /**
6
- * Mount a React component in a blank document; register it as an alias
7
- * To access: use an alias or original component reference
8
- * @function mount
9
- * @param {React.ReactElement} jsx - component to mount
10
- * @param {MountOptions} [options] - options, like alias, styles
11
- * @see https://github.com/bahmutov/@cypress/react
12
- * @see https://glebbahmutov.com/blog/my-vision-for-component-tests/
13
- * @example
14
- ```
15
- import Hello from './hello.jsx'
16
- import { mount } from '@cypress/react'
17
- it('works', () => {
18
- mount(<Hello onClick={cy.stub()} />)
19
- // use Cypress commands
20
- cy.contains('Hello').click()
21
- })
22
- ```
23
- **/
24
- export declare const mount: (jsx: React.ReactNode, options?: MountOptions) => globalThis.Cypress.Chainable<MountReturn>;
25
- /**
26
- * Removes the mounted component. Notice this command automatically
27
- * queues up the `unmount` into Cypress chain, thus you don't need `.then`
28
- * to call it.
29
- * @see https://github.com/cypress-io/cypress/tree/develop/npm/react/cypress/component/basic/unmount
30
- * @example
31
- ```
32
- import { mount, unmount } from '@cypress/react'
33
- it('works', () => {
34
- mount(...)
35
- // interact with the component using Cypress commands
36
- // whenever you want to unmount
37
- unmount()
38
- })
39
- ```
40
- */
41
- export declare const unmount: (options?: {
2
+ import React from 'react';
3
+ import type { MountOptions } from './types';
4
+ export declare function mount(jsx: React.ReactNode, options?: MountOptions, rerenderKey?: string): Cypress.Chainable<import("./types").MountReturn>;
5
+ export declare function unmount(options?: {
42
6
  log: boolean;
43
- }) => globalThis.Cypress.Chainable<JQuery<HTMLElement>>;
44
- /**
45
- * Creates new instance of `mount` function with default options
46
- * @function createMount
47
- * @param {MountOptions} [defaultOptions] - defaultOptions for returned `mount` function
48
- * @returns new instance of `mount` with assigned options
49
- * @example
50
- * ```
51
- * import Hello from './hello.jsx'
52
- * import { createMount } from '@cypress/react'
53
- *
54
- * const mount = createMount({ strict: true, cssFile: 'path/to/any/css/file.css' })
55
- *
56
- * it('works', () => {
57
- * mount(<Hello />)
58
- * // use Cypress commands
59
- * cy.get('button').should('have.css', 'color', 'rgb(124, 12, 109)')
60
- * })
61
- ```
62
- **/
63
- export declare const createMount: (defaultOptions: MountOptions) => (element: React.ReactElement, options?: Partial<StyleOptions & MountReactComponentOptions> | undefined) => globalThis.Cypress.Chainable<MountReturn>;
64
- /** @deprecated Should be removed in the next major version */
65
- export default mount;
66
- export interface ReactModule {
67
- name: string;
68
- type: string;
69
- location: string;
70
- source: string;
71
- }
72
- export interface MountReactComponentOptions {
73
- alias: string;
74
- ReactDom: typeof ReactDOM;
75
- /**
76
- * Log the mounting command into Cypress Command Log,
77
- * true by default.
78
- */
79
- log: boolean;
80
- /**
81
- * Render component in React [strict mode](https://reactjs.org/docs/strict-mode.html)
82
- * It activates additional checks and warnings for child components.
83
- */
84
- strict: boolean;
85
- }
86
- export declare type MountOptions = Partial<StyleOptions & MountReactComponentOptions>;
87
- export interface MountReturn {
88
- /**
89
- * The component that was rendered.
90
- */
91
- component: React.ReactNode;
92
- /**
93
- * Rerenders the specified component with new props. This allows testing of components that store state (`setState`)
94
- * or have asynchronous updates (`useEffect`, `useLayoutEffect`).
95
- */
96
- rerender: (component: React.ReactNode) => globalThis.Cypress.Chainable<MountReturn>;
97
- /**
98
- * Removes the mounted component.
99
- * @see `unmount`
100
- */
101
- unmount: () => globalThis.Cypress.Chainable<JQuery<HTMLElement>>;
102
- }
103
- /**
104
- * The `type` property from the transpiled JSX object.
105
- * @example
106
- * const { type } = React.createElement('div', null, 'Hello')
107
- * const { type } = <div>Hello</div>
108
- */
109
- export interface JSX extends Function {
110
- displayName: string;
111
- }
112
- export declare namespace Cypress {
113
- interface Cypress {
114
- stylesCache: any;
115
- React: string;
116
- ReactDOM: string;
117
- Styles: string;
118
- modules: ReactModule[];
119
- }
120
- interface Chainable<Subject> {
121
- state: (key: string) => any;
122
- /**
123
- * Mount a React component in a blank document; register it as an alias
124
- * To access: use an alias or original component reference
125
- * @function cy.mount
126
- * @param {Object} jsx - component to mount
127
- * @param {string} [Component] - alias to use later
128
- * @example
129
- ```
130
- import Hello from './hello.jsx'
131
- // mount and access by alias
132
- cy.mount(<Hello />, 'Hello')
133
- // using default alias
134
- cy.get('@Component')
135
- // using specified alias
136
- cy.get('@Hello').its('state').should(...)
137
- // using original component
138
- cy.get(Hello)
139
- ```
140
- **/
141
- get<S = any>(alias: string | symbol | Function, options?: Partial<any>): Chainable<any>;
142
- }
143
- }
7
+ }): Cypress.Chainable<JQuery<HTMLElement>>;