-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* update cli exports * add additional react adapters * update system test infra to better cover react versions * use idiomatic cy.mount and cy.unmount * add additional test projects * update tests * add new modules * remove dead code, organize code more * add react 16 project * update webpack to resolve react correctly * add test for react 16 * update snaps * add react adapters * ignore cli/react files * use official rollup plugin to bundle npm/react * update yarn lock for webpack dev server tests * update vite dev server projects * update config * remove console.log * update tsconfig * fix tests * fix another test * update snaps * update snaps * fix build * remove react{16,17}, update tests * update build * add missing export * update test * fixing tests * fixing tests * update snaps * update snaps again * build artifacts on circle * dont try to update rollup plugin * update circle * update * add missing build step * update deps, remove old code * revert circle changes * do not hoist deps from react18 * remove deps
- Loading branch information
1 parent
60fd568
commit f0d3a48
Showing
73 changed files
with
7,933 additions
and
554 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,5 +17,5 @@ build | |
# the sync-exported-npm-with-cli.js script | ||
vue | ||
vue2 | ||
react | ||
react* | ||
mount-utils |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
import * as React from 'react' | ||
import ReactDOM from 'react-dom' | ||
import getDisplayName from './getDisplayName' | ||
import { | ||
injectStylesBeforeElement, | ||
getContainerEl, | ||
ROOT_SELECTOR, | ||
setupHooks, | ||
} from '@cypress/mount-utils' | ||
import type { InternalMountOptions, InternalUnmountOptions, MountOptions, MountReturn, UnmountArgs } from './types' | ||
|
||
/** | ||
* Inject custom style text or CSS file or 3rd party style resources | ||
*/ | ||
const injectStyles = (options: MountOptions) => { | ||
return (): HTMLElement => { | ||
const el = getContainerEl() | ||
|
||
return injectStylesBeforeElement(options, document, el) | ||
} | ||
} | ||
|
||
export let lastMountedReactDom: (typeof ReactDOM) | undefined | ||
|
||
/** | ||
* Create an `mount` function. Performs all the non-React-version specific | ||
* behavior related to mounting. The React-version-specific code | ||
* is injected. This helps us to maintain a consistent public API | ||
* and handle breaking changes in React's rendering API. | ||
* | ||
* This is designed to be consumed by `npm/react{16,17,18}`, and other React adapters, | ||
* or people writing adapters for third-party, custom adapters. | ||
*/ | ||
export const makeMountFn = ( | ||
type: 'mount' | 'rerender', | ||
jsx: React.ReactNode, | ||
options: MountOptions = {}, | ||
rerenderKey?: string, | ||
internalMountOptions?: InternalMountOptions, | ||
): globalThis.Cypress.Chainable<MountReturn> => { | ||
if (!internalMountOptions) { | ||
throw Error('internalMountOptions must be provided with `render` and `reactDom` parameters') | ||
} | ||
|
||
// Get the display name property via the component constructor | ||
// @ts-ignore FIXME | ||
const componentName = getDisplayName(jsx.type, options.alias) | ||
const displayName = options.alias || componentName | ||
|
||
const jsxComponentName = `<${componentName} ... />` | ||
|
||
const message = options.alias | ||
? `${jsxComponentName} as "${options.alias}"` | ||
: jsxComponentName | ||
|
||
return cy | ||
.then(injectStyles(options)) | ||
.then(() => { | ||
const reactDomToUse = internalMountOptions.reactDom | ||
|
||
lastMountedReactDom = reactDomToUse | ||
|
||
const el = getContainerEl() | ||
|
||
if (!el) { | ||
throw new Error( | ||
[ | ||
`[@cypress/react] 🔥 Hmm, cannot find root element to mount the component. Searched for ${ROOT_SELECTOR}`, | ||
].join(' '), | ||
) | ||
} | ||
|
||
const key = rerenderKey ?? | ||
// @ts-ignore provide unique key to the the wrapped component to make sure we are rerendering between tests | ||
(Cypress?.mocha?.getRunner()?.test?.title as string || '') + Math.random() | ||
const props = { | ||
key, | ||
} | ||
|
||
const reactComponent = React.createElement( | ||
options.strict ? React.StrictMode : React.Fragment, | ||
props, | ||
jsx, | ||
) | ||
// since we always surround the component with a fragment | ||
// let's get back the original component | ||
const userComponent = (reactComponent.props as { | ||
key: string | ||
children: React.ReactNode | ||
}).children | ||
|
||
internalMountOptions.render(reactComponent, el, reactDomToUse) | ||
|
||
if (options.log !== false) { | ||
Cypress.log({ | ||
name: type, | ||
type: 'parent', | ||
message: [message], | ||
// @ts-ignore | ||
$el: (el.children.item(0) as unknown) as JQuery<HTMLElement>, | ||
consoleProps: () => { | ||
return { | ||
// @ts-ignore protect the use of jsx functional components use ReactNode | ||
props: jsx.props, | ||
description: type === 'mount' ? 'Mounts React component' : 'Rerenders mounted React component', | ||
home: 'https://github.com/cypress-io/cypress', | ||
} | ||
}, | ||
}).snapshot('mounted').end() | ||
} | ||
|
||
return ( | ||
// Separate alias and returned value. Alias returns the component only, and the thenable returns the additional functions | ||
cy.wrap<React.ReactNode>(userComponent, { log: false }) | ||
.as(displayName) | ||
.then(() => { | ||
return cy.wrap<MountReturn>({ | ||
component: userComponent, | ||
rerender: (newComponent) => makeMountFn('rerender', newComponent, options, key, internalMountOptions), | ||
unmount: internalMountOptions.unmount, | ||
}, { log: false }) | ||
}) | ||
// by waiting, we delaying test execution for the next tick of event loop | ||
// and letting hooks and component lifecycle methods to execute mount | ||
// https://github.com/bahmutov/cypress-react-unit-test/issues/200 | ||
.wait(0, { log: false }) | ||
) | ||
// Bluebird types are terrible. I don't think the return type can be carried without this cast | ||
}) as unknown as globalThis.Cypress.Chainable<MountReturn> | ||
} | ||
|
||
/** | ||
* Create an `unmount` function. Performs all the non-React-version specific | ||
* behavior related to unmounting. | ||
* | ||
* This is designed to be consumed by `npm/react{16,17,18}`, and other React adapters, | ||
* or people writing adapters for third-party, custom adapters. | ||
*/ | ||
export const makeUnmountFn = (options: UnmountArgs, internalUnmountOptions: InternalUnmountOptions) => { | ||
return cy.then(() => { | ||
return cy.get(ROOT_SELECTOR, { log: false }).then(($el) => { | ||
if (lastMountedReactDom) { | ||
internalUnmountOptions.unmount($el[0]) | ||
const wasUnmounted = internalUnmountOptions.unmount($el[0]) | ||
|
||
if (wasUnmounted && options.log) { | ||
Cypress.log({ | ||
name: 'unmount', | ||
type: 'parent', | ||
message: [options.boundComponentMessage ?? 'Unmounted component'], | ||
consoleProps: () => { | ||
return { | ||
description: 'Unmounts React component', | ||
parent: $el[0], | ||
home: 'https://github.com/cypress-io/cypress', | ||
} | ||
}, | ||
}) | ||
} | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
// Cleanup before each run | ||
// NOTE: we cannot use unmount here because | ||
// we are not in the context of a test | ||
const preMountCleanup = () => { | ||
const el = getContainerEl() | ||
|
||
if (el && lastMountedReactDom) { | ||
lastMountedReactDom.unmountComponentAtNode(el) | ||
} | ||
} | ||
|
||
const _mount = (jsx: React.ReactNode, options: MountOptions = {}) => makeMountFn('mount', jsx, options) | ||
|
||
export const createMount = (defaultOptions: MountOptions) => { | ||
return ( | ||
element: React.ReactElement, | ||
options?: MountOptions, | ||
) => { | ||
return _mount(element, { ...defaultOptions, ...options }) | ||
} | ||
} | ||
|
||
/** @deprecated Should be removed in the next major version */ | ||
// TODO: Remove | ||
export default _mount | ||
|
||
export interface JSX extends Function { | ||
displayName: string | ||
} | ||
|
||
// Side effects from "import { mount } from '@cypress/<my-framework>'" are annoying, we should avoid doing this | ||
// by creating an explicit function/import that the user can register in their 'component.js' support file, | ||
// such as: | ||
// import 'cypress/<my-framework>/support' | ||
// or | ||
// import { registerCT } from 'cypress/<my-framework>' | ||
// registerCT() | ||
// Note: This would be a breaking change | ||
|
||
// it is required to unmount component in beforeEach hook in order to provide a clean state inside test | ||
// because `mount` can be called after some preparation that can side effect unmount | ||
// @see npm/react/cypress/component/advanced/set-timeout-example/loading-indicator-spec.js | ||
setupHooks(preMountCleanup) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
export * from './createMount' | ||
|
||
export * from './mount' | ||
|
||
export * from './mountHook' | ||
|
||
export * from './types' |
Oops, something went wrong.
f0d3a48
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Circle has built the
linux x64
version of the Test Runner.Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.
Run this command to install the pre-release locally:
f0d3a48
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Circle has built the
linux arm64
version of the Test Runner.Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.
Run this command to install the pre-release locally:
f0d3a48
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Circle has built the
darwin arm64
version of the Test Runner.Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.
Run this command to install the pre-release locally:
f0d3a48
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Circle has built the
darwin x64
version of the Test Runner.Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.
Run this command to install the pre-release locally:
f0d3a48
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Circle has built the
win32 x64
version of the Test Runner.Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.
Run this command to install the pre-release locally: