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.
- package/lib/exec/open.js +7 -2
- package/lib/exec/spawn.js +7 -2
- package/mount-utils/CHANGELOG.md +0 -1
- package/mount-utils/README.md +7 -0
- package/mount-utils/dist/index.js +8 -1
- package/mount-utils/package.json +1 -0
- package/package.json +20 -10
- package/react/CHANGELOG.md +0 -19
- package/react/README.md +28 -323
- package/react/dist/createMount.d.ts +30 -0
- package/react/dist/cypress-react.cjs.js +76 -80
- package/react/dist/cypress-react.esm-bundler.js +68 -76
- package/react/dist/getDisplayName.d.ts +1 -1
- package/react/dist/index.d.ts +2 -0
- package/react/dist/mount.d.ts +5 -141
- package/react/dist/types.d.ts +50 -0
- package/react/package.json +1 -5
- package/react18/dist/cypress-react.cjs.js +422 -0
- package/react18/dist/cypress-react.esm-bundler.js +394 -0
- package/react18/dist/index.d.ts +5 -0
- package/react18/package.json +59 -0
- package/types/cypress.d.ts +11 -2
- package/types/index.d.ts +1 -1
- package/types/{net-stubbing.ts → net-stubbing.d.ts} +0 -0
- package/vue/CHANGELOG.md +2 -17
- package/vue/README.md +17 -607
- package/vue/dist/@vue/test-utils/baseWrapper.d.ts +63 -0
- package/vue/dist/@vue/test-utils/components/RouterLinkStub.d.ts +21 -0
- package/vue/dist/@vue/test-utils/config.d.ts +30 -0
- package/vue/dist/@vue/test-utils/constants/dom-events.d.ts +900 -0
- package/vue/dist/@vue/test-utils/createDomEvent.d.ts +9 -0
- package/vue/dist/@vue/test-utils/domWrapper.d.ts +18 -0
- package/vue/dist/@vue/test-utils/emit.d.ts +5 -0
- package/vue/dist/@vue/test-utils/errorWrapper.d.ts +1 -0
- package/vue/dist/@vue/test-utils/index.d.ts +11 -0
- package/vue/dist/@vue/test-utils/interfaces/wrapperLike.d.ts +56 -0
- package/vue/dist/@vue/test-utils/mount.d.ts +35 -0
- package/vue/dist/@vue/test-utils/stubs.d.ts +22 -0
- package/vue/dist/@vue/test-utils/types.d.ts +125 -0
- package/vue/dist/@vue/test-utils/utils/autoUnmount.d.ts +5 -0
- package/vue/dist/@vue/test-utils/utils/compileSlots.d.ts +2 -0
- package/vue/dist/@vue/test-utils/utils/componentName.d.ts +4 -0
- package/vue/dist/@vue/test-utils/utils/find.d.ts +10 -0
- package/vue/dist/@vue/test-utils/utils/flushPromises.d.ts +1 -0
- package/vue/dist/@vue/test-utils/utils/getRootNodes.d.ts +2 -0
- package/vue/dist/@vue/test-utils/utils/isElement.d.ts +1 -0
- package/vue/dist/@vue/test-utils/utils/isElementVisible.d.ts +6 -0
- package/vue/dist/@vue/test-utils/utils/matchName.d.ts +1 -0
- package/vue/dist/@vue/test-utils/utils/stringifyNode.d.ts +1 -0
- package/vue/dist/@vue/test-utils/utils/vueCompatSupport.d.ts +8 -0
- package/vue/dist/@vue/test-utils/utils/vueShared.d.ts +3 -0
- package/vue/dist/@vue/test-utils/utils.d.ts +13 -0
- package/vue/dist/@vue/test-utils/vueWrapper.d.ts +35 -0
- package/vue/dist/@vue/test-utils/wrapperFactory.d.ts +14 -0
- package/vue/dist/cypress-vue.cjs.js +5583 -5209
- package/vue/dist/cypress-vue.esm-bundler.js +5584 -5211
- package/vue/dist/index.d.ts +35 -3
- package/vue/package.json +11 -7
- package/vue2/README.md +11 -627
- package/vue2/dist/cypress-vue2.browser.js +268 -262
- package/vue2/dist/cypress-vue2.cjs.js +267 -261
- package/vue2/dist/cypress-vue2.esm-bundler.js +265 -259
- package/vue2/package.json +1 -1
- 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
|
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
|
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
|
-
*
|
253
|
-
*
|
254
|
-
*
|
255
|
-
*
|
256
|
-
*
|
257
|
-
*
|
258
|
-
*
|
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
|
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 =
|
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
|
-
|
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
|
338
|
-
unmount:
|
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
|
-
*
|
350
|
-
*
|
351
|
-
*
|
352
|
-
*
|
353
|
-
*
|
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
|
-
|
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
|
-
|
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
|
-
|
404
|
-
|
405
|
-
|
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
|
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
|
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
|
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
|
-
*
|
252
|
-
*
|
253
|
-
*
|
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
|
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 =
|
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
|
-
|
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
|
313
|
-
unmount:
|
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
|
-
*
|
325
|
-
*
|
326
|
-
*
|
327
|
-
*
|
328
|
-
*
|
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
|
-
|
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
|
-
|
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
|
-
|
379
|
-
|
380
|
-
|
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
|
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 };
|
package/react/dist/index.d.ts
CHANGED
package/react/dist/mount.d.ts
CHANGED
@@ -1,143 +1,7 @@
|
|
1
1
|
/// <reference types="cypress" />
|
2
|
-
import
|
3
|
-
import
|
4
|
-
|
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
|
-
})
|
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>>;
|