cypress 10.2.0 → 10.4.0

Sign up to get free protection for your applications and to get access to all the features.
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>>;