cypress 9.6.0 → 10.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. package/index.mjs +15 -0
  2. package/lib/cli.js +72 -23
  3. package/lib/errors.js +16 -1
  4. package/lib/exec/open.js +45 -10
  5. package/lib/exec/run.js +17 -10
  6. package/lib/exec/shared.js +30 -9
  7. package/lib/exec/spawn.js +4 -0
  8. package/lib/exec/xvfb.js +1 -0
  9. package/lib/util.js +10 -3
  10. package/mount-utils/CHANGELOG.md +20 -0
  11. package/mount-utils/README.md +14 -0
  12. package/mount-utils/dist/index.d.ts +54 -0
  13. package/mount-utils/dist/index.js +134 -0
  14. package/mount-utils/package.json +31 -0
  15. package/package.json +39 -4
  16. package/react/CHANGELOG.md +373 -0
  17. package/react/README.md +414 -0
  18. package/react/dist/cypress-react.browser.js +497 -0
  19. package/react/dist/cypress-react.cjs.js +495 -0
  20. package/react/dist/cypress-react.esm-bundler.js +467 -0
  21. package/react/dist/getDisplayName.d.ts +8 -0
  22. package/react/dist/index.d.ts +2 -0
  23. package/react/dist/mount.d.ts +143 -0
  24. package/react/dist/mountHook.d.ts +11 -0
  25. package/react/package.json +105 -0
  26. package/types/bluebird/index.d.ts +18 -4
  27. package/types/cypress-eventemitter.d.ts +1 -1
  28. package/types/cypress-global-vars.d.ts +2 -2
  29. package/types/cypress-npm-api.d.ts +4 -10
  30. package/types/cypress.d.ts +180 -120
  31. package/types/minimatch/index.d.ts +15 -5
  32. package/vue/CHANGELOG.md +380 -0
  33. package/vue/README.md +678 -0
  34. package/vue/dist/cypress-vue.cjs.js +13535 -0
  35. package/vue/dist/cypress-vue.esm-bundler.js +13511 -0
  36. package/vue/dist/index.d.ts +56 -0
  37. package/vue/package.json +86 -0
  38. package/vue2/CHANGELOG.md +5 -0
  39. package/vue2/README.md +693 -0
  40. package/vue2/dist/cypress-vue2.browser.js +20191 -0
  41. package/vue2/dist/cypress-vue2.cjs.js +20188 -0
  42. package/vue2/dist/cypress-vue2.esm-bundler.js +20179 -0
  43. package/vue2/dist/index.d.ts +171 -0
  44. package/vue2/package.json +59 -0
@@ -0,0 +1,495 @@
1
+
2
+ /**
3
+ * @cypress/react v0.0.0-development
4
+ * (c) 2022 Cypress.io
5
+ * Released under the MIT License
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ Object.defineProperty(exports, '__esModule', { value: true });
11
+
12
+ var React = require('react');
13
+ var ReactDOM = require('react-dom');
14
+
15
+ function _interopNamespace(e) {
16
+ if (e && e.__esModule) return e;
17
+ var n = Object.create(null);
18
+ if (e) {
19
+ Object.keys(e).forEach(function (k) {
20
+ if (k !== 'default') {
21
+ var d = Object.getOwnPropertyDescriptor(e, k);
22
+ Object.defineProperty(n, k, d.get ? d : {
23
+ enumerable: true,
24
+ get: function () { return e[k]; }
25
+ });
26
+ }
27
+ });
28
+ }
29
+ n["default"] = e;
30
+ return Object.freeze(n);
31
+ }
32
+
33
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
34
+ var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
35
+
36
+ /*! *****************************************************************************
37
+ Copyright (c) Microsoft Corporation.
38
+
39
+ Permission to use, copy, modify, and/or distribute this software for any
40
+ purpose with or without fee is hereby granted.
41
+
42
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
43
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
44
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
45
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
46
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
47
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
48
+ PERFORMANCE OF THIS SOFTWARE.
49
+ ***************************************************************************** */
50
+
51
+ var __assign = function() {
52
+ __assign = Object.assign || function __assign(t) {
53
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
54
+ s = arguments[i];
55
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
56
+ }
57
+ return t;
58
+ };
59
+ return __assign.apply(this, arguments);
60
+ };
61
+
62
+ var cachedDisplayNames = new WeakMap();
63
+ /**
64
+ * Gets the display name of the component when possible.
65
+ * @param type {JSX} The type object returned from creating the react element.
66
+ * @param fallbackName {string} The alias, or fallback name to use when the name cannot be derived.
67
+ * @link https://github.com/facebook/react-devtools/blob/master/backend/getDisplayName.js
68
+ */
69
+ function getDisplayName(type, fallbackName) {
70
+ if (fallbackName === void 0) { fallbackName = 'Unknown'; }
71
+ var nameFromCache = cachedDisplayNames.get(type);
72
+ if (nameFromCache != null) {
73
+ return nameFromCache;
74
+ }
75
+ var displayName = null;
76
+ // The displayName property is not guaranteed to be a string.
77
+ // It's only safe to use for our purposes if it's a string.
78
+ // github.com/facebook/react-devtools/issues/803
79
+ if (typeof type.displayName === 'string') {
80
+ displayName = type.displayName;
81
+ }
82
+ if (!displayName) {
83
+ displayName = type.name || fallbackName;
84
+ }
85
+ // Facebook-specific hack to turn "Image [from Image.react]" into just "Image".
86
+ // We need displayName with module name for error reports but it clutters the DevTools.
87
+ var match = displayName.match(/^(.*) \[from (.*)\]$/);
88
+ if (match) {
89
+ var componentName = match[1];
90
+ var moduleName = match[2];
91
+ if (componentName && moduleName) {
92
+ if (moduleName === componentName ||
93
+ moduleName.startsWith(componentName + ".")) {
94
+ displayName = componentName;
95
+ }
96
+ }
97
+ }
98
+ try {
99
+ cachedDisplayNames.set(type, displayName);
100
+ }
101
+ catch (e) {
102
+ // do nothing
103
+ }
104
+ return displayName;
105
+ }
106
+
107
+ const ROOT_SELECTOR = '[data-cy-root]';
108
+ const getContainerEl = () => {
109
+ const el = document.querySelector(ROOT_SELECTOR);
110
+ if (el) {
111
+ return el;
112
+ }
113
+ throw Error(`No element found that matches selector ${ROOT_SELECTOR}. Please use the mount utils to mount it properly`);
114
+ };
115
+ /**
116
+ * Remove any style or extra link elements from the iframe placeholder
117
+ * left from any previous test
118
+ *
119
+ */
120
+ function cleanupStyles() {
121
+ const styles = document.body.querySelectorAll('[data-cy=injected-style-tag]');
122
+ styles.forEach((styleElement) => {
123
+ if (styleElement.parentElement) {
124
+ styleElement.parentElement.removeChild(styleElement);
125
+ }
126
+ });
127
+ const links = document.body.querySelectorAll('[data-cy=injected-stylesheet]');
128
+ links.forEach((link) => {
129
+ if (link.parentElement) {
130
+ link.parentElement.removeChild(link);
131
+ }
132
+ });
133
+ }
134
+ /**
135
+ * Insert links to external style resources.
136
+ */
137
+ function insertStylesheets(stylesheets, document, el) {
138
+ stylesheets.forEach((href) => {
139
+ const link = document.createElement('link');
140
+ link.type = 'text/css';
141
+ link.rel = 'stylesheet';
142
+ link.href = href;
143
+ link.dataset.cy = 'injected-stylesheet';
144
+ document.body.insertBefore(link, el);
145
+ });
146
+ }
147
+ /**
148
+ * Inserts a single stylesheet element
149
+ */
150
+ function insertStyles(styles, document, el) {
151
+ styles.forEach((style) => {
152
+ const styleElement = document.createElement('style');
153
+ styleElement.dataset.cy = 'injected-style-tag';
154
+ styleElement.appendChild(document.createTextNode(style));
155
+ document.body.insertBefore(styleElement, el);
156
+ });
157
+ }
158
+ function insertSingleCssFile(cssFilename, document, el, log) {
159
+ return cy.readFile(cssFilename, { log }).then((css) => {
160
+ const style = document.createElement('style');
161
+ style.appendChild(document.createTextNode(css));
162
+ document.body.insertBefore(style, el);
163
+ });
164
+ }
165
+ /**
166
+ * Reads the given CSS file from local file system
167
+ * and adds the loaded style text as an element.
168
+ */
169
+ function insertLocalCssFiles(cssFilenames, document, el, log) {
170
+ return Cypress.Promise.mapSeries(cssFilenames, (cssFilename) => {
171
+ return insertSingleCssFile(cssFilename, document, el, log);
172
+ });
173
+ }
174
+ /**
175
+ * Injects custom style text or CSS file or 3rd party style resources
176
+ * into the given document.
177
+ */
178
+ const injectStylesBeforeElement = (options, document, el) => {
179
+ if (!el)
180
+ return;
181
+ // first insert all stylesheets as Link elements
182
+ let stylesheets = [];
183
+ if (typeof options.stylesheet === 'string') {
184
+ stylesheets.push(options.stylesheet);
185
+ }
186
+ else if (Array.isArray(options.stylesheet)) {
187
+ stylesheets = stylesheets.concat(options.stylesheet);
188
+ }
189
+ if (typeof options.stylesheets === 'string') {
190
+ options.stylesheets = [options.stylesheets];
191
+ }
192
+ if (options.stylesheets) {
193
+ stylesheets = stylesheets.concat(options.stylesheets);
194
+ }
195
+ insertStylesheets(stylesheets, document, el);
196
+ // insert any styles as <style>...</style> elements
197
+ let styles = [];
198
+ if (typeof options.style === 'string') {
199
+ styles.push(options.style);
200
+ }
201
+ else if (Array.isArray(options.style)) {
202
+ styles = styles.concat(options.style);
203
+ }
204
+ if (typeof options.styles === 'string') {
205
+ styles.push(options.styles);
206
+ }
207
+ else if (Array.isArray(options.styles)) {
208
+ styles = styles.concat(options.styles);
209
+ }
210
+ insertStyles(styles, document, el);
211
+ // now load any css files by path and add their content
212
+ // as <style>...</style> elements
213
+ let cssFiles = [];
214
+ if (typeof options.cssFile === 'string') {
215
+ cssFiles.push(options.cssFile);
216
+ }
217
+ else if (Array.isArray(options.cssFile)) {
218
+ cssFiles = cssFiles.concat(options.cssFile);
219
+ }
220
+ if (typeof options.cssFiles === 'string') {
221
+ cssFiles.push(options.cssFiles);
222
+ }
223
+ else if (Array.isArray(options.cssFiles)) {
224
+ cssFiles = cssFiles.concat(options.cssFiles);
225
+ }
226
+ return insertLocalCssFiles(cssFiles, document, el, options.log);
227
+ };
228
+ function setupHooks(optionalCallback) {
229
+ // When running component specs, we cannot allow "cy.visit"
230
+ // because it will wipe out our preparation work, and does not make much sense
231
+ // thus we overwrite "cy.visit" to throw an error
232
+ Cypress.Commands.overwrite('visit', () => {
233
+ throw new Error('cy.visit from a component spec is not allowed');
234
+ });
235
+ // @ts-ignore
236
+ Cypress.on('test:before:run', () => {
237
+ optionalCallback === null || optionalCallback === void 0 ? void 0 : optionalCallback();
238
+ cleanupStyles();
239
+ });
240
+ }
241
+
242
+ /**
243
+ * Inject custom style text or CSS file or 3rd party style resources
244
+ */
245
+ var injectStyles = function (options) {
246
+ return function () {
247
+ var el = getContainerEl();
248
+ return injectStylesBeforeElement(options, document, el);
249
+ };
250
+ };
251
+ /**
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
279
+ */
280
+ var _mount = function (type, jsx, options, rerenderKey) {
281
+ if (options === void 0) { options = {}; }
282
+ // Get the display name property via the component constructor
283
+ // @ts-ignore FIXME
284
+ var componentName = getDisplayName(jsx.type, options.alias);
285
+ var displayName = options.alias || componentName;
286
+ var jsxComponentName = "<" + componentName + " ... />";
287
+ var message = options.alias
288
+ ? jsxComponentName + " as \"" + options.alias + "\""
289
+ : jsxComponentName;
290
+ return cy
291
+ .then(injectStyles(options))
292
+ .then(function () {
293
+ var _a, _b, _c;
294
+ var reactDomToUse = options.ReactDom || ReactDOM__namespace;
295
+ lastMountedReactDom = reactDomToUse;
296
+ var el = getContainerEl();
297
+ if (!el) {
298
+ throw new Error([
299
+ "[@cypress/react] \uD83D\uDD25 Hmm, cannot find root element to mount the component. Searched for " + ROOT_SELECTOR,
300
+ ].join(' '));
301
+ }
302
+ var key = rerenderKey !== null && rerenderKey !== void 0 ? rerenderKey :
303
+ // @ts-ignore provide unique key to the the wrapped component to make sure we are rerendering between tests
304
+ (((_c = (_b = (_a = Cypress === null || Cypress === void 0 ? void 0 : Cypress.mocha) === null || _a === void 0 ? void 0 : _a.getRunner()) === null || _b === void 0 ? void 0 : _b.test) === null || _c === void 0 ? void 0 : _c.title) || '') + Math.random();
305
+ var props = {
306
+ key: key,
307
+ };
308
+ var reactComponent = React__namespace.createElement(options.strict ? React__namespace.StrictMode : React__namespace.Fragment, props, jsx);
309
+ // since we always surround the component with a fragment
310
+ // let's get back the original component
311
+ var userComponent = reactComponent.props.children;
312
+ reactDomToUse.render(reactComponent, el);
313
+ if (options.log !== false) {
314
+ Cypress.log({
315
+ name: type,
316
+ type: 'parent',
317
+ message: [message],
318
+ // @ts-ignore
319
+ $el: el.children.item(0),
320
+ consoleProps: function () {
321
+ return {
322
+ // @ts-ignore protect the use of jsx functional components use ReactNode
323
+ props: jsx.props,
324
+ description: type === 'mount' ? 'Mounts React component' : 'Rerenders mounted React component',
325
+ home: 'https://github.com/cypress-io/cypress',
326
+ };
327
+ },
328
+ }).snapshot('mounted').end();
329
+ }
330
+ return (
331
+ // Separate alias and returned value. Alias returns the component only, and the thenable returns the additional functions
332
+ cy.wrap(userComponent, { log: false })
333
+ .as(displayName)
334
+ .then(function () {
335
+ return cy.wrap({
336
+ component: userComponent,
337
+ rerender: function (newComponent) { return _mount('rerender', newComponent, options, key); },
338
+ unmount: function () { return _unmount({ boundComponentMessage: jsxComponentName, log: true }); },
339
+ }, { log: false });
340
+ })
341
+ // by waiting, we delaying test execution for the next tick of event loop
342
+ // and letting hooks and component lifecycle methods to execute mount
343
+ // https://github.com/bahmutov/cypress-react-unit-test/issues/200
344
+ .wait(0, { log: false }));
345
+ // Bluebird types are terrible. I don't think the return type can be carried without this cast
346
+ });
347
+ };
348
+ /**
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
+ ```
363
+ */
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) {
370
+ return cy.then(function () {
371
+ return cy.get(ROOT_SELECTOR, { log: false }).then(function ($el) {
372
+ var _a;
373
+ if (lastMountedReactDom) {
374
+ var wasUnmounted = lastMountedReactDom.unmountComponentAtNode($el[0]);
375
+ if (wasUnmounted && options.log) {
376
+ Cypress.log({
377
+ name: 'unmount',
378
+ type: 'parent',
379
+ message: [(_a = options.boundComponentMessage) !== null && _a !== void 0 ? _a : 'Unmounted component'],
380
+ consoleProps: function () {
381
+ return {
382
+ description: 'Unmounts React component',
383
+ parent: $el[0],
384
+ home: 'https://github.com/cypress-io/cypress',
385
+ };
386
+ },
387
+ });
388
+ }
389
+ }
390
+ });
391
+ });
392
+ };
393
+ // Cleanup before each run
394
+ // NOTE: we cannot use unmount here because
395
+ // we are not in the context of a test
396
+ var preMountCleanup = function () {
397
+ var el = getContainerEl();
398
+ if (el && lastMountedReactDom) {
399
+ lastMountedReactDom.unmountComponentAtNode(el);
400
+ }
401
+ };
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
+ **/
421
+ var createMount = function (defaultOptions) {
422
+ return function (element, options) {
423
+ return mount(element, __assign(__assign({}, defaultOptions), options));
424
+ };
425
+ };
426
+ // it is required to unmount component in beforeEach hook in order to provide a clean state inside test
427
+ // because `mount` can be called after some preparation that can side effect unmount
428
+ // @see npm/react/cypress/component/advanced/set-timeout-example/loading-indicator-spec.js
429
+ setupHooks(preMountCleanup);
430
+
431
+ // mounting hooks inside a test component mostly copied from
432
+ // https://github.com/testing-library/react-hooks-testing-library/blob/master/src/pure.js
433
+ function resultContainer() {
434
+ var value = null;
435
+ var error = null;
436
+ var resolvers = [];
437
+ var result = {
438
+ get current() {
439
+ if (error) {
440
+ throw error;
441
+ }
442
+ return value;
443
+ },
444
+ get error() {
445
+ return error;
446
+ },
447
+ };
448
+ var updateResult = function (val, err) {
449
+ if (err === void 0) { err = null; }
450
+ value = val;
451
+ error = err;
452
+ resolvers.splice(0, resolvers.length).forEach(function (resolve) { return resolve(); });
453
+ };
454
+ return {
455
+ result: result,
456
+ addResolver: function (resolver) {
457
+ resolvers.push(resolver);
458
+ },
459
+ setValue: function (val) { return updateResult(val); },
460
+ setError: function (err) { return updateResult(undefined, err); },
461
+ };
462
+ }
463
+ function TestHook(_a) {
464
+ var callback = _a.callback, onError = _a.onError, children = _a.children;
465
+ try {
466
+ children(callback());
467
+ }
468
+ catch (err) {
469
+ if ('then' in err) {
470
+ throw err;
471
+ }
472
+ else {
473
+ onError(err);
474
+ }
475
+ }
476
+ return null;
477
+ }
478
+ /**
479
+ * Mounts a React hook function in a test component for testing.
480
+ *
481
+ */
482
+ var mountHook = function (hookFn) {
483
+ var _a = resultContainer(), result = _a.result, setValue = _a.setValue, setError = _a.setError;
484
+ var componentTest = React__namespace.createElement(TestHook, {
485
+ callback: hookFn,
486
+ onError: setError,
487
+ children: setValue,
488
+ });
489
+ return mount(componentTest).then(function () { return result; });
490
+ };
491
+
492
+ exports.createMount = createMount;
493
+ exports.mount = mount;
494
+ exports.mountHook = mountHook;
495
+ exports.unmount = unmount;