mirror of
https://github.com/cypress-io/cypress.git
synced 2025-12-30 11:09:49 -06:00
breaking: remove support for React 16 and 17 for Cypress Component Testing. Additionally, remove the cypress/react18 testing harness and merge it upstream with cypress/react (#30590)
* breaking: remove support for react 16 and 17 for component testing and move cypress/react18 upstream into cypress/react [run ci] * update tests / suggestions from code review [run ci]
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
# Bump this version to force CI to re-create the cache from scratch.
|
||||
|
||||
11-07-24-vue-cli-service-removal
|
||||
11-07-24-react-16-17-removal
|
||||
|
||||
@@ -30,7 +30,7 @@ mainBuildFilters: &mainBuildFilters
|
||||
- /^release\/\d+\.\d+\.\d+$/
|
||||
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
|
||||
- 'update-v8-snapshot-cache-on-develop'
|
||||
- 'breaking/remove_vue_cli_service'
|
||||
- 'breaking/remove_react_16_17_merge_react18_harness_upstream'
|
||||
- 'publish-binary'
|
||||
|
||||
# usually we don't build Mac app - it takes a long time
|
||||
@@ -42,7 +42,7 @@ macWorkflowFilters: &darwin-workflow-filters
|
||||
- equal: [ develop, << pipeline.git.branch >> ]
|
||||
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
|
||||
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
|
||||
- equal: [ 'breaking/remove_vue_cli_service', << pipeline.git.branch >> ]
|
||||
- equal: [ 'breaking/remove_react_16_17_merge_react18_harness_upstream', << pipeline.git.branch >> ]
|
||||
- matches:
|
||||
pattern: /^release\/\d+\.\d+\.\d+$/
|
||||
value: << pipeline.git.branch >>
|
||||
@@ -53,7 +53,7 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters
|
||||
- equal: [ develop, << pipeline.git.branch >> ]
|
||||
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
|
||||
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
|
||||
- equal: [ 'breaking/remove_vue_cli_service', << pipeline.git.branch >> ]
|
||||
- equal: [ 'breaking/remove_react_16_17_merge_react18_harness_upstream', << pipeline.git.branch >> ]
|
||||
- matches:
|
||||
pattern: /^release\/\d+\.\d+\.\d+$/
|
||||
value: << pipeline.git.branch >>
|
||||
@@ -76,7 +76,7 @@ windowsWorkflowFilters: &windows-workflow-filters
|
||||
- equal: [ develop, << pipeline.git.branch >> ]
|
||||
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
|
||||
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
|
||||
- equal: [ 'breaking/remove_vue_cli_service', << pipeline.git.branch >> ]
|
||||
- equal: [ 'breaking/remove_react_16_17_merge_react18_harness_upstream', << pipeline.git.branch >> ]
|
||||
- matches:
|
||||
pattern: /^release\/\d+\.\d+\.\d+$/
|
||||
value: << pipeline.git.branch >>
|
||||
@@ -152,7 +152,7 @@ commands:
|
||||
name: Set environment variable to determine whether or not to persist artifacts
|
||||
command: |
|
||||
echo "Setting SHOULD_PERSIST_ARTIFACTS variable"
|
||||
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "breaking/remove_vue_cli_service" ]]; then
|
||||
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "breaking/remove_react_16_17_merge_react18_harness_upstream" ]]; then
|
||||
export SHOULD_PERSIST_ARTIFACTS=true
|
||||
fi' >> "$BASH_ENV"
|
||||
# You must run `setup_should_persist_artifacts` command and be using bash before running this command
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
- [`@cypress/eslint-plugin-dev`](https://github.com/cypress-io/cypress/blob/develop/npm/eslint-plugin-dev/CHANGELOG.md)
|
||||
- [`@cypress/mount-utils`](https://github.com/cypress-io/cypress/blob/develop/npm/mount-utils/CHANGELOG.md)
|
||||
- [`@cypress/react`](https://github.com/cypress-io/cypress/blob/develop/npm/react/CHANGELOG.md)
|
||||
- [`@cypress/react18`](https://github.com/cypress-io/cypress/blob/develop/npm/react18/CHANGELOG.md)
|
||||
- [`@cypress/svelte`](https://github.com/cypress-io/cypress/blob/develop/npm/svelte/CHANGELOG.md)
|
||||
- [`@cypress/vite-dev-server`](https://github.com/cypress-io/cypress/blob/develop/npm/vite-dev-server/CHANGELOG.md)
|
||||
- [`@cypress/vue`](https://github.com/cypress-io/cypress/blob/develop/npm/vue/CHANGELOG.md)
|
||||
|
||||
@@ -186,7 +186,6 @@ Here is a list of the npm packages in this repository:
|
||||
| [grep](./npm/grep) | `@cypress/grep` | Filter tests using substring |
|
||||
| [mount-utils](./npm/mount-utils) | `@cypress/mount-utils` | Common functionality for Vue/React/Angular adapters. |
|
||||
| [react](./npm/react) | `@cypress/react` | Cypress component testing for React. |
|
||||
| [react18](./npm/react18) | `@cypress/react18` | Cypress component testing for React 18. |
|
||||
| [schematic](./npm/cypress-schematic) | `@cypress/schematic` | Official Angular Schematic and Builder for the Angular CLI.|
|
||||
| [svelte](./npm/svelte) | `@cypress/svelte` | Cypress component testing for Svelte. |
|
||||
| [vite-dev-server](./npm/vite-dev-server) | `@cypress/vite-dev-server` | Vite powered dev server for Component Testing. |
|
||||
|
||||
@@ -11,7 +11,6 @@ package.json
|
||||
# these are all copied from dist'd builds from the individual libs
|
||||
/angular
|
||||
/react
|
||||
/react18
|
||||
/vue
|
||||
/svelte
|
||||
/mount-utils
|
||||
@@ -17,11 +17,13 @@ _Released 12/3/2024 (PENDING)_
|
||||
- It is no longer possible to make a `fetch` or `XMLHttpRequest` request from the `about:blank` page in Electron (i.e. `cy.window().then((win) => win.fetch('<some-url>')`). You must use `cy.request` instead or perform some form of initial navigation via `cy.visit()`. Addressed in [#29547](https://github.com/cypress-io/cypress/pull/30394).
|
||||
- `@cypress/webpack-dev-server` no longer supports `webpack-dev-server` version 3. Additionally, `@cypress/webpack-dev-server` now ships with `webpack-dev-server` version 5 by default. `webpack-dev-server` version 4 will need to be installed along side Cypress if you are still using `webpack` version 4. Addresses [#29308](https://github.com/cypress-io/cypress/issues/29308), [#30347](https://github.com/cypress-io/cypress/issues/30347), and [#30141](https://github.com/cypress-io/cypress/issues/30141).
|
||||
- `@cypress/vite-dev-server` no longer supports `vite` versions 2 and 3. Addresses [#29377](https://github.com/cypress-io/cypress/issues/29377) and [#29378](https://github.com/cypress-io/cypress/issues/29378).
|
||||
- Cypress Component Testing no longer supports `Nuxt.js` version 2. Addresses [#30468](https://github.com/cypress-io/cypress/issues/30468).
|
||||
- Cypress Component Testing no longer supports `Vue` version 2. Addresses [#30295](https://github.com/cypress-io/cypress/issues/30295).
|
||||
- Cypress Component Testing no longer supports `React` versions 16 and 17. Addresses [#29607](https://github.com/cypress-io/cypress/issues/29607).
|
||||
- Cypress Component Testing no longer supports `Next.js` versions 10, 11, 12, and 13. Addresses [#29583](https://github.com/cypress-io/cypress/issues/29583).
|
||||
- Cypress Component Testing no longer supports `Vue` version 2. Addresses [#30295](https://github.com/cypress-io/cypress/issues/30295).
|
||||
- Cypress Component Testing no longer supports `Nuxt.js` version 2. Addresses [#30468](https://github.com/cypress-io/cypress/issues/30468).
|
||||
- Cypress Component Testing no longer supports `Angular` versions 13, 14, 15, and 16. The minimum supported version is now `17.2.0` in order to fully support Angular [signals](https://angular.dev/guide/signals). Addresses [#29582](https://github.com/cypress-io/cypress/issues/29582). Addressed in [#30539](https://github.com/cypress-io/cypress/pull/30539).
|
||||
- Cypress Component Testing no longer supports `Svelte` version 3. Addresses [#30492](https://github.com/cypress-io/cypress/issues/30492).
|
||||
- The `cypress/react18` test harness is no longer included in the Cypress binary. Instead, React 18 support is now shipped with `cypress/react`! Addresses [#29607](https://github.com/cypress-io/cypress/issues/29607).
|
||||
- The `cypress/angular-signals` test harness is no longer included in the Cypress binary. Instead, signals support is now shipped with `cypress/angular`! This requires `rxjs` to be installed as a `peerDependency`. Addresses [#29606](https://github.com/cypress-io/cypress/issues/29606).
|
||||
- Cypress Component Testing no longer supports `create-react-app`. Addresses [#30028](https://github.com/cypress-io/cypress/issues/30028).
|
||||
- Cypress Component Testing no longer supports `@vue/cli-service`. Addresses [#30481](https://github.com/cypress-io/cypress/issues/30481).
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
"@cypress/grep": "0.0.0-development",
|
||||
"@cypress/mount-utils": "0.0.0-development",
|
||||
"@cypress/react": "0.0.0-development",
|
||||
"@cypress/react18": "0.0.0-development",
|
||||
"@cypress/sinon-chai": "2.9.1",
|
||||
"@cypress/svelte": "0.0.0-development",
|
||||
"@cypress/vue": "0.0.0-development",
|
||||
@@ -114,7 +113,6 @@
|
||||
"mount-utils",
|
||||
"vue",
|
||||
"react",
|
||||
"react18",
|
||||
"angular",
|
||||
"svelte"
|
||||
],
|
||||
@@ -145,11 +143,6 @@
|
||||
"import": "./react/dist/cypress-react.esm-bundler.js",
|
||||
"require": "./react/dist/cypress-react.cjs.js"
|
||||
},
|
||||
"./react18": {
|
||||
"types": "./react18/dist/index.d.ts",
|
||||
"import": "./react18/dist/cypress-react.esm-bundler.js",
|
||||
"require": "./react18/dist/cypress-react.cjs.js"
|
||||
},
|
||||
"./mount-utils": {
|
||||
"types": "./mount-utils/dist/index.d.ts",
|
||||
"require": "./mount-utils/dist/index.js"
|
||||
|
||||
@@ -9,7 +9,6 @@ shell.set('-e') // any error is fatal
|
||||
const npmModulesToCopy = [
|
||||
'mount-utils',
|
||||
'react',
|
||||
'react18',
|
||||
'vue',
|
||||
'angular',
|
||||
'svelte',
|
||||
|
||||
@@ -20,15 +20,13 @@ describe('Counter with access', () => {
|
||||
// the window.counter was set from the Counter's constructor
|
||||
cy.window()
|
||||
.should('have.property', 'counter')
|
||||
.its('state')
|
||||
.should('deep.equal', { count: 0 })
|
||||
.its('count')
|
||||
.should('equal', 0)
|
||||
|
||||
// let's change the state of the component
|
||||
cy.window()
|
||||
.its('counter')
|
||||
.invoke('setState', {
|
||||
count: 101,
|
||||
})
|
||||
.invoke('setCount', 101)
|
||||
|
||||
// the UI should update to reflect the new count
|
||||
cy.contains('count: 101').should('be.visible')
|
||||
|
||||
@@ -1,34 +1,28 @@
|
||||
import React from 'react'
|
||||
import React, { useState } from 'react'
|
||||
|
||||
export class Counter extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
count: 0,
|
||||
}
|
||||
|
||||
if (window.Cypress) {
|
||||
// if this component is mounted from inside Cypress Test Runner
|
||||
// then expose the reference to this instance
|
||||
// to allow controlling it from tests
|
||||
console.log(
|
||||
'set window.counter to this component in window',
|
||||
window.location.pathname,
|
||||
)
|
||||
|
||||
window.counter = this
|
||||
} else {
|
||||
console.log('running outside Cypress')
|
||||
export function Counter () {
|
||||
const [count, setCount] = useState(0)
|
||||
|
||||
if (window.Cypress) {
|
||||
// if this component is mounted from inside Cypress Test Runner
|
||||
// then expose the reference to this instance
|
||||
// to allow controlling it from tests
|
||||
console.log(
|
||||
'set window.counter to this component in window',
|
||||
window.location.pathname,
|
||||
)
|
||||
|
||||
window.counter = {
|
||||
count,
|
||||
setCount,
|
||||
}
|
||||
} else {
|
||||
console.log('running outside Cypress')
|
||||
}
|
||||
|
||||
click = () => {
|
||||
this.setState({
|
||||
count: this.state.count + 1,
|
||||
})
|
||||
function click () {
|
||||
setCount(count + 1)
|
||||
}
|
||||
|
||||
render () {
|
||||
return <p onClick={this.click}>count: {this.state.count}</p>
|
||||
}
|
||||
return <p onClick={click}>count: {count}</p>
|
||||
}
|
||||
|
||||
@@ -2,15 +2,13 @@ import React from 'react'
|
||||
import { ThemeContext } from './context'
|
||||
import { Toolbar } from './Toolbar.jsx'
|
||||
|
||||
export default class App extends React.Component {
|
||||
render () {
|
||||
// Use a Provider to pass the current theme to the tree below.
|
||||
// Any component can read it, no matter how deep it is.
|
||||
// In this example, we're passing "dark" as the current value.
|
||||
return (
|
||||
<ThemeContext.Provider value="dark">
|
||||
<Toolbar />
|
||||
</ThemeContext.Provider>
|
||||
)
|
||||
}
|
||||
export default function App () {
|
||||
// Use a Provider to pass the current theme to the tree below.
|
||||
// Any component can read it, no matter how deep it is.
|
||||
// In this example, we're passing "dark" as the current value.
|
||||
return (
|
||||
<ThemeContext.Provider value="dark">
|
||||
<Toolbar />
|
||||
</ThemeContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ export default function Counter2WithHooks () {
|
||||
|
||||
useEffect(() => {
|
||||
document.title = `You clicked ${count} times`
|
||||
})
|
||||
}, [count])
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -1,36 +1,28 @@
|
||||
import React from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
// import the entire axios module
|
||||
// later we can use axios.get to make requests
|
||||
import axios from 'axios'
|
||||
|
||||
export class Users extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
users: [],
|
||||
}
|
||||
export function Users () {
|
||||
const [users, setUsers] = useState([])
|
||||
|
||||
const getUsers = async () => {
|
||||
const response = await axios.get('https://jsonplaceholder.cypress.io/users?_limit=3')
|
||||
|
||||
setUsers(response.data)
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
axios
|
||||
.get('https://jsonplaceholder.cypress.io/users?_limit=3')
|
||||
.then((response) => {
|
||||
// JSON responses are automatically parsed.
|
||||
this.setState({
|
||||
users: response.data,
|
||||
})
|
||||
})
|
||||
}
|
||||
useEffect(() => {
|
||||
getUsers()
|
||||
}, [])
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
{this.state.users.map((user) => (
|
||||
<li key={user.id}>
|
||||
<strong>{user.id}</strong> - {user.name}
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
{users.map((user) => (
|
||||
<li key={user.id}>
|
||||
<strong>{user.id}</strong> - {user.name}
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// <reference types="cypress" />
|
||||
import React from 'react'
|
||||
import { mount } from '@cypress/react'
|
||||
import { Users } from './3-users-api.jsx'
|
||||
import * as axios from './axios-api'
|
||||
import { Users } from './2-users-api.jsx'
|
||||
import * as axios from './axios-api.jsx'
|
||||
|
||||
describe('Mocking wrapped Axios', () => {
|
||||
it('shows real users', () => {
|
||||
@@ -0,0 +1,28 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
// import wrapped Axios method
|
||||
import axiosApi from './axios-api.jsx'
|
||||
|
||||
export function Users () {
|
||||
const [users, setUsers] = useState([])
|
||||
|
||||
const getUsers = async () => {
|
||||
console.log({ axiosApi })
|
||||
const response = await axiosApi.get('https://jsonplaceholder.cypress.io/users?_limit=3')
|
||||
|
||||
setUsers(response.data)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getUsers()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>
|
||||
{users.map((user) => (
|
||||
<li key={user.id}>
|
||||
<strong>{user.id}</strong> - {user.name}
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
import React from 'react'
|
||||
import { mount } from '@cypress/react'
|
||||
import { Users } from './2-users-named.jsx'
|
||||
import axios from 'axios'
|
||||
|
||||
describe('Mocking Axios named import get', () => {
|
||||
it('shows real users', () => {
|
||||
mount(<Users />)
|
||||
cy.get('li').should('have.length', 3)
|
||||
})
|
||||
|
||||
// TODO: Support stubbing ES Modules
|
||||
it.skip('mocks get', () => {
|
||||
cy.stub(axios, 'get')
|
||||
.resolves({
|
||||
data: [
|
||||
{
|
||||
id: 101,
|
||||
name: 'Test User',
|
||||
},
|
||||
],
|
||||
})
|
||||
.as('get')
|
||||
|
||||
mount(<Users />)
|
||||
// only the test user should be shown
|
||||
cy.get('li').should('have.length', 1)
|
||||
cy.get('@get').should('have.been.called')
|
||||
})
|
||||
|
||||
it('restores the original method', () => {
|
||||
mount(<Users />)
|
||||
cy.get('li').should('have.length', 3)
|
||||
})
|
||||
})
|
||||
@@ -1,33 +0,0 @@
|
||||
import React from 'react'
|
||||
// use named import "get" from the module
|
||||
import { get } from 'axios'
|
||||
|
||||
export class Users extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
users: [],
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
get('https://jsonplaceholder.cypress.io/users?_limit=3').then((response) => {
|
||||
// JSON responses are automatically parsed.
|
||||
this.setState({
|
||||
users: response.data,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
{this.state.users.map((user) => (
|
||||
<li key={user.id}>
|
||||
<strong>{user.id}</strong> - {user.name}
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import React from 'react'
|
||||
// import wrapped Axios method
|
||||
import axiosApi from './axios-api'
|
||||
|
||||
export class Users extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
users: [],
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
console.log({ axiosApi })
|
||||
axiosApi.get('https://jsonplaceholder.cypress.io/users?_limit=3').then((response) => {
|
||||
// JSON responses are automatically parsed.
|
||||
this.setState({
|
||||
users: response.data,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
{this.state.users.map((user) => (
|
||||
<li key={user.id}>
|
||||
<strong>{user.id}</strong> - {user.name}
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,52 +1,44 @@
|
||||
// https://medium.com/@pierrehedkvist/renderless-components-in-react-8d663746314c
|
||||
import React from 'react'
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
export default class MouseMovement extends React.Component {
|
||||
constructor (props) {
|
||||
console.log('MouseMovement constructor')
|
||||
super(props)
|
||||
this.state = {
|
||||
timer: undefined,
|
||||
}
|
||||
export default function MouseMovement ({ onMoved }) {
|
||||
const [timer, setTimer] = useState(undefined)
|
||||
|
||||
this.timeout = this.timeout.bind(this)
|
||||
this.onMouseMove = this.onMouseMove.bind(this)
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
console.log('MouseMovement componentWillMount')
|
||||
document.addEventListener('mousemove', this.onMouseMove)
|
||||
const timer = setTimeout(this.timeout, 4000)
|
||||
|
||||
this.setState({ timer })
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
console.log('MouseMovement componentWillUnmount')
|
||||
document.removeEventListener('mousemove', this.onMouseMove)
|
||||
clearTimeout(this.state.timer)
|
||||
this.setState({ timer: undefined })
|
||||
}
|
||||
|
||||
onMouseMove () {
|
||||
function onMouseMove () {
|
||||
console.log('MouseMovement onMouseMove')
|
||||
clearTimeout(this.state.timer)
|
||||
const timer = setTimeout(this.timeout, 4000)
|
||||
clearTimeout(timer)
|
||||
const timerNew = setTimeout(timeout, 4000)
|
||||
|
||||
this.setState({ timer })
|
||||
this.props.onMoved(true)
|
||||
setTimer(timerNew)
|
||||
onMoved(true)
|
||||
}
|
||||
|
||||
timeout () {
|
||||
function timeout () {
|
||||
console.log('timeout')
|
||||
clearTimeout(this.state.timer)
|
||||
this.props.onMoved(false)
|
||||
clearTimeout(timer)
|
||||
onMoved(false)
|
||||
}
|
||||
|
||||
render () {
|
||||
return null
|
||||
}
|
||||
useEffect(() => {
|
||||
// Anything in here is fired on component mount.
|
||||
console.log('MouseMovement componentWillMount')
|
||||
document.addEventListener('mousemove', onMouseMove)
|
||||
const timerNew = setTimeout(timeout, 4000)
|
||||
|
||||
setTimer(timerNew)
|
||||
|
||||
return () => {
|
||||
// Anything in here is fired on component unmount.
|
||||
console.log('MouseMovement componentWillUnmount')
|
||||
document.removeEventListener('mousemove', onMouseMove)
|
||||
clearTimeout(timer)
|
||||
setTimer(undefined)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
MouseMovement.propTypes = {
|
||||
|
||||
@@ -5,14 +5,6 @@ import MouseMovement from './mouse-movement'
|
||||
|
||||
describe('Renderless component', () => {
|
||||
it('works', () => {
|
||||
// let's also spy on "console.log" calls
|
||||
// to make sure the entire sequence of calls happens
|
||||
cy.window()
|
||||
.its('console')
|
||||
.then((console) => {
|
||||
cy.spy(console, 'log').as('log')
|
||||
})
|
||||
|
||||
const onMoved = cy.stub()
|
||||
|
||||
mount(<MouseMovement onMoved={onMoved} />)
|
||||
@@ -23,27 +15,7 @@ describe('Renderless component', () => {
|
||||
expect(onMoved).to.have.been.calledWith(true)
|
||||
})
|
||||
|
||||
// mount something else to trigger unmount
|
||||
// mount something else to trigger unmount and stop log flow
|
||||
mount(<div>Test Component</div>)
|
||||
|
||||
cy.get('@log')
|
||||
.its('callCount')
|
||||
.should('equal', 4)
|
||||
|
||||
cy.get('@log')
|
||||
.invoke('getCalls')
|
||||
.then((calls) => {
|
||||
return calls.map((call) => {
|
||||
console.log('one', call.args[0])
|
||||
|
||||
return call.args[0]
|
||||
})
|
||||
})
|
||||
.should('deep.equal', [
|
||||
'MouseMovement constructor',
|
||||
'MouseMovement componentWillMount',
|
||||
'MouseMovement onMouseMove',
|
||||
'MouseMovement componentWillUnmount',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,35 +1,31 @@
|
||||
import React, { Component } from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import './App.css'
|
||||
import logo from './logo.svg'
|
||||
import LoadingIndicator from './LoadingIndicator'
|
||||
|
||||
class App extends Component {
|
||||
state = {
|
||||
isLoading: true,
|
||||
}
|
||||
function App () {
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
componentDidMount () {
|
||||
this._timer = setTimeout(() => this.setState({ isLoading: false }), 2000)
|
||||
}
|
||||
useEffect(() => {
|
||||
const _timer = setTimeout(() => setIsLoading(false), 2000)
|
||||
|
||||
componentWillUnmount () {
|
||||
clearTimeout(this._timer)
|
||||
}
|
||||
return () => {
|
||||
clearTimeout(_timer)
|
||||
}
|
||||
}, [])
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<img src={logo} className="App-logo" alt="logo" />
|
||||
<h1 className="App-title">Welcome to React</h1>
|
||||
</header>
|
||||
<pre>isLoading: {String(this.state.isLoading)}</pre>
|
||||
<LoadingIndicator isLoading={this.state.isLoading}>
|
||||
<div>ahoy!</div>
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<img src={logo} className="App-logo" alt="logo" />
|
||||
<h1 className="App-title">Welcome to React</h1>
|
||||
</header>
|
||||
<pre>isLoading: {String(isLoading)}</pre>
|
||||
<LoadingIndicator isLoading={isLoading}>
|
||||
<div>ahoy!</div>
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
|
||||
@@ -1,37 +1,26 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
|
||||
export default class LoadingIndicator extends Component {
|
||||
static propTypes = {
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
}
|
||||
export default function LoadingIndicator ({ isLoading, children }) {
|
||||
const [isPastDelay, setIsPastDelay] = useState(false)
|
||||
|
||||
state = {
|
||||
isPastDelay: false,
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
console.log('component did mount')
|
||||
this._delayTimer = setTimeout(() => {
|
||||
useEffect(() => {
|
||||
const _delayTimer = setTimeout(() => {
|
||||
console.log('2000ms passed')
|
||||
this.setState({ isPastDelay: true })
|
||||
setIsPastDelay(true)
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
console.log('componentWillUnmount')
|
||||
clearTimeout(this._delayTimer)
|
||||
}
|
||||
return () => {
|
||||
clearTimeout(_delayTimer)
|
||||
}
|
||||
}, [])
|
||||
|
||||
render () {
|
||||
if (this.props.isLoading) {
|
||||
if (!this.state.isPastDelay) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <div>loading...</div>
|
||||
if (isLoading) {
|
||||
if (!isPastDelay) {
|
||||
return null
|
||||
}
|
||||
|
||||
return this.props.children
|
||||
return <div>loading...</div>
|
||||
}
|
||||
|
||||
return children
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { Component } from 'react'
|
||||
|
||||
// Class components will be removed in a future release of React 18+. Until then, this example will serve as a class component example
|
||||
export default class Card extends Component {
|
||||
componentDidMount () {
|
||||
this._timeoutID = setTimeout(() => {
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import React from 'react'
|
||||
|
||||
export default class ShoppingList extends React.Component {
|
||||
render () {
|
||||
return (
|
||||
<div className="shopping-list">
|
||||
<h1>Shopping List for {this.props.name}</h1>
|
||||
<ul>
|
||||
<li>Instagram</li>
|
||||
<li>WhatsApp</li>
|
||||
<li>Oculus</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default function ShoppingList ({ name }) {
|
||||
return (
|
||||
<div className="shopping-list">
|
||||
<h1>Shopping List for {name}</h1>
|
||||
<ul>
|
||||
<li>Instagram</li>
|
||||
<li>WhatsApp</li>
|
||||
<li>Oculus</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,27 +1,17 @@
|
||||
/// <reference types="cypress" />
|
||||
import React from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import { mount } from '@cypress/react'
|
||||
import './tic-tac-toe.css'
|
||||
|
||||
// let's put React component right in the spec file
|
||||
class Square extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
value: null,
|
||||
}
|
||||
}
|
||||
export default function Square ({ value: valueAsProp }) {
|
||||
const [valueAsState, setValueAsState] = useState(null)
|
||||
|
||||
render () {
|
||||
return (
|
||||
<button
|
||||
className="square"
|
||||
onClick={() => this.setState({ value: this.props.value })}
|
||||
>
|
||||
{this.state.value}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<button className="square" onClick={() => setValueAsState(valueAsProp)}>
|
||||
{valueAsState}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
describe('Square', () => {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <reference types="cypress" />
|
||||
import React from 'react'
|
||||
import { mount } from '@cypress/react'
|
||||
import { Game } from './tic-tac-toe.jsx'
|
||||
import Game from './tic-tac-toe.jsx'
|
||||
import './tic-tac-toe.css'
|
||||
|
||||
describe('Tic Tac Toe', () => {
|
||||
|
||||
@@ -1,6 +1,105 @@
|
||||
// entire game from the tutorial inside the spec for simplicity
|
||||
// the code taken from https://codepen.io/gaearon/pen/LyyXgK
|
||||
import React from 'react'
|
||||
import React, { useState } from 'react'
|
||||
|
||||
function Square ({ value, onSquareClick }) {
|
||||
return (
|
||||
<button className="square" onClick={onSquareClick}>
|
||||
{value}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export function Board ({ xIsNext, squares, onPlay }) {
|
||||
function handleClick (i) {
|
||||
if (calculateWinner(squares) || squares[i]) {
|
||||
return
|
||||
}
|
||||
|
||||
const nextSquares = squares.slice()
|
||||
|
||||
if (xIsNext) {
|
||||
nextSquares[i] = 'X'
|
||||
} else {
|
||||
nextSquares[i] = 'O'
|
||||
}
|
||||
|
||||
onPlay(nextSquares)
|
||||
}
|
||||
|
||||
const winner = calculateWinner(squares)
|
||||
let status
|
||||
|
||||
if (winner) {
|
||||
status = `Winner: ${ winner}`
|
||||
} else {
|
||||
status = `Next player: ${ xIsNext ? 'X' : 'O'}`
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="status">{status}</div>
|
||||
<div className="board-row">
|
||||
<Square value={squares[0]} onSquareClick={() => handleClick(0)} />
|
||||
<Square value={squares[1]} onSquareClick={() => handleClick(1)} />
|
||||
<Square value={squares[2]} onSquareClick={() => handleClick(2)} />
|
||||
</div>
|
||||
<div className="board-row">
|
||||
<Square value={squares[3]} onSquareClick={() => handleClick(3)} />
|
||||
<Square value={squares[4]} onSquareClick={() => handleClick(4)} />
|
||||
<Square value={squares[5]} onSquareClick={() => handleClick(5)} />
|
||||
</div>
|
||||
<div className="board-row">
|
||||
<Square value={squares[6]} onSquareClick={() => handleClick(6)} />
|
||||
<Square value={squares[7]} onSquareClick={() => handleClick(7)} />
|
||||
<Square value={squares[8]} onSquareClick={() => handleClick(8)} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Game () {
|
||||
const [history, setHistory] = useState([Array(9).fill(null)])
|
||||
const [currentMove, setCurrentMove] = useState(0)
|
||||
const xIsNext = currentMove % 2 === 0
|
||||
const currentSquares = history[currentMove]
|
||||
|
||||
function handlePlay (nextSquares) {
|
||||
const nextHistory = [...history.slice(0, currentMove + 1), nextSquares]
|
||||
|
||||
setHistory(nextHistory)
|
||||
setCurrentMove(nextHistory.length - 1)
|
||||
}
|
||||
|
||||
function jumpTo (nextMove) {
|
||||
setCurrentMove(nextMove)
|
||||
}
|
||||
|
||||
const moves = history.map((squares, move) => {
|
||||
let description
|
||||
|
||||
if (move > 0) {
|
||||
description = `Go to move #${ move}`
|
||||
} else {
|
||||
description = 'Go to game start'
|
||||
}
|
||||
|
||||
return (
|
||||
<li key={move}>
|
||||
<button onClick={() => jumpTo(move)}>{description}</button>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="game">
|
||||
<div className="game-board">
|
||||
<Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />
|
||||
</div>
|
||||
<div className="game-info">
|
||||
<ol>{moves}</ol>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function calculateWinner (squares) {
|
||||
const lines = [
|
||||
@@ -24,92 +123,3 @@ export function calculateWinner (squares) {
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function Square (props) {
|
||||
return (
|
||||
<button className="square" onClick={props.onClick}>
|
||||
{props.value}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export class Board extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
squares: Array(9).fill(null),
|
||||
xIsNext: true,
|
||||
}
|
||||
}
|
||||
|
||||
handleClick (i) {
|
||||
const squares = this.state.squares.slice()
|
||||
|
||||
if (calculateWinner(squares) || squares[i]) {
|
||||
return
|
||||
}
|
||||
|
||||
squares[i] = this.state.xIsNext ? 'X' : 'O'
|
||||
this.setState({
|
||||
squares,
|
||||
xIsNext: !this.state.xIsNext,
|
||||
})
|
||||
}
|
||||
|
||||
renderSquare (i) {
|
||||
return (
|
||||
<Square
|
||||
value={this.state.squares[i]}
|
||||
onClick={() => this.handleClick(i)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
const winner = calculateWinner(this.state.squares)
|
||||
let status
|
||||
|
||||
if (winner) {
|
||||
status = `Winner: ${winner}`
|
||||
} else {
|
||||
status = `Next player: ${this.state.xIsNext ? 'X' : 'O'}`
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="status">{status}</div>
|
||||
<div className="board-row">
|
||||
{this.renderSquare(0)}
|
||||
{this.renderSquare(1)}
|
||||
{this.renderSquare(2)}
|
||||
</div>
|
||||
<div className="board-row">
|
||||
{this.renderSquare(3)}
|
||||
{this.renderSquare(4)}
|
||||
{this.renderSquare(5)}
|
||||
</div>
|
||||
<div className="board-row">
|
||||
{this.renderSquare(6)}
|
||||
{this.renderSquare(7)}
|
||||
{this.renderSquare(8)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class Game extends React.Component {
|
||||
render () {
|
||||
return (
|
||||
<div className="game">
|
||||
<div className="game-board">
|
||||
<Board />
|
||||
</div>
|
||||
<div className="game-info">
|
||||
<div>{/* status */}</div>
|
||||
<ol>{/* TODO */}</ol>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
import React from 'react'
|
||||
import './Button.css'
|
||||
|
||||
export class Button extends React.Component {
|
||||
handleClick () {
|
||||
this.props.clickHandler(this.props.name)
|
||||
export function Button ({ name, orange, wide, clickHandler }) {
|
||||
const className = [
|
||||
'component-button',
|
||||
orange ? 'orange' : '',
|
||||
wide ? 'wide' : '',
|
||||
]
|
||||
|
||||
function handleClick () {
|
||||
clickHandler(name)
|
||||
}
|
||||
|
||||
render () {
|
||||
const className = [
|
||||
'component-button',
|
||||
this.props.orange ? 'orange' : '',
|
||||
this.props.wide ? 'wide' : '',
|
||||
]
|
||||
|
||||
return (
|
||||
<div className={className.join(' ').trim()}>
|
||||
<button onClick={this.handleClick.bind(this)}>{this.props.name}</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className={className.join(' ').trim()}>
|
||||
<button onClick={handleClick.bind(this)}>{name}</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
# Enzyme examples
|
||||
|
||||
This folder shows several examples from [Enzyme docs](https://enzymejs.github.io/enzyme/).
|
||||
|
||||
In general if you are migrating from Enzyme to `@cypress/react`:
|
||||
|
||||
- there is no shallow mounting, only the full mounting. Thus `@cypress/react` has `mount` which is similar to the Enzyme's `render`. It renders the full HTML and CSS output of your component.
|
||||
- you can mock [children components](https://github.com/bahmutov/cypress-react-unit-test/tree/main/cypress/component/advanced/mocking-component) if you want to avoid running "expensive" components during tests
|
||||
- the test is running as a "mini" web application. Thus if you want to set a context around component, then set the [context around the component](https://github.com/bahmutov/cypress-react-unit-test/tree/main/cypress/component/advanced/context)
|
||||
|
||||
## setState
|
||||
|
||||
If you want to change the component's internal state, use the component reference. You can get it by using the special property `ref` when mounting.
|
||||
|
||||
```js
|
||||
// get the component reference using "ref" prop
|
||||
// and place it into the object for Cypress to "wait" for it
|
||||
let c = {}
|
||||
mount(<Foo id="foo" foo="initial" ref={i => (c.instance = i)} />)
|
||||
cy.wrap(c)
|
||||
.its('instance')
|
||||
.invoke('setState', { count: 10 })
|
||||
```
|
||||
|
||||
See [state-spec.js](state-spec.js) file.
|
||||
|
||||
## setProps
|
||||
|
||||
There is no direct implementation of `setProps`. If you want to see how the component behaves with different props:
|
||||
|
||||
```js
|
||||
it('mounts component with new props', () => {
|
||||
mount(<Foo id="foo" foo="initial" />)
|
||||
cy.contains('initial').should('be.visible')
|
||||
|
||||
mount(<Foo id="foo" foo="second" />)
|
||||
cy.contains('second').should('be.visible')
|
||||
})
|
||||
```
|
||||
|
||||
If you want to reuse properties, you can even clone the component
|
||||
|
||||
```js
|
||||
it('mounts cloned component', () => {
|
||||
const cmp = <Foo id="foo" foo="initial" />
|
||||
mount(cmp)
|
||||
cy.contains('initial').should('be.visible')
|
||||
|
||||
const cloned = Cypress._.cloneDeep(cmp)
|
||||
// change a property, leaving the rest unchanged
|
||||
cloned.props.foo = 'second'
|
||||
mount(cloned)
|
||||
cy.contains('.foo', 'second').should('be.visible')
|
||||
})
|
||||
```
|
||||
|
||||
See [props-spec.js](props-spec.js) file.
|
||||
|
||||
## context
|
||||
|
||||
Enzyme's `mount` method allows passing the [React context](https://reactjs.org/docs/context.html) as the second argument to the JSX component like `SimpleComponent` below.
|
||||
|
||||
```js
|
||||
function SimpleComponent(props, context) {
|
||||
const { name } = context
|
||||
return <div>{name || 'not set'}</div>
|
||||
}
|
||||
```
|
||||
|
||||
Since the above syntax is [deprecated](https://reactjs.org/docs/legacy-context.html), `@cypress/react` does not support it. Instead use `createContext` and `Context.Provider` to surround the mounted component, just like you would do in a regular application code.
|
||||
|
||||
```js
|
||||
mount(
|
||||
<SimpleContext.Provider value={{ name: 'test context' }}>
|
||||
<SimpleComponent />
|
||||
</SimpleContext.Provider>,
|
||||
)
|
||||
```
|
||||
|
||||
Instead of setting a new context, mount the same component but surround it with a different context provider
|
||||
|
||||
```js
|
||||
const cmp = <SimpleComponent id="0x123" />
|
||||
mount(
|
||||
<SimpleContext.Provider value={{ name: 'first context' }}>
|
||||
{cmp}
|
||||
</SimpleContext.Provider>,
|
||||
)
|
||||
|
||||
// same component, different provider
|
||||
mount(
|
||||
<SimpleContext.Provider value={{ name: 'second context' }}>
|
||||
{cmp}
|
||||
</SimpleContext.Provider>,
|
||||
)
|
||||
```
|
||||
|
||||
See [context-spec.js](context-spec.js) for more examples.
|
||||
@@ -1,53 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
import React from 'react'
|
||||
import { mount } from '@cypress/react'
|
||||
import { SimpleContext } from './simple-context'
|
||||
import { SimpleComponent } from './simple-component.jsx'
|
||||
|
||||
// testing components that use Context React API
|
||||
// https://reactjs.org/docs/context.html
|
||||
describe('Enzyme', () => {
|
||||
context('setContext', () => {
|
||||
it('does not provide the context', () => {
|
||||
mount(<SimpleComponent />)
|
||||
cy.contains('context not set').should('be.visible')
|
||||
})
|
||||
|
||||
it('provides the context', () => {
|
||||
// surround the component with the real provider but
|
||||
// set the value prop to whatever the test requires
|
||||
mount(
|
||||
<SimpleContext.Provider value={{ name: 'test context' }}>
|
||||
<SimpleComponent />
|
||||
</SimpleContext.Provider>,
|
||||
)
|
||||
|
||||
cy.contains('test context').should('be.visible')
|
||||
})
|
||||
|
||||
it('mounts new context', () => {
|
||||
// instead of setting the context from the test
|
||||
// just mount the component again with a different provider around it
|
||||
const cmp = <SimpleComponent id="0x123" />
|
||||
|
||||
mount(
|
||||
<SimpleContext.Provider value={{ name: 'first context' }}>
|
||||
{cmp}
|
||||
</SimpleContext.Provider>,
|
||||
)
|
||||
|
||||
cy.contains('first context').should('be.visible')
|
||||
cy.contains('.id', '0x123').should('be.visible')
|
||||
|
||||
// same component, different provider
|
||||
mount(
|
||||
<SimpleContext.Provider value={{ name: 'second context' }}>
|
||||
{cmp}
|
||||
</SimpleContext.Provider>,
|
||||
)
|
||||
|
||||
cy.contains('second context').should('be.visible')
|
||||
cy.contains('.id', '0x123').should('be.visible')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,82 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
import React from 'react'
|
||||
import { mount } from '@cypress/react'
|
||||
|
||||
class Foo extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
console.log('componentDidMount called')
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
console.log('componentDidUpdate called')
|
||||
}
|
||||
|
||||
render () {
|
||||
const { id, foo } = this.props
|
||||
|
||||
return (
|
||||
<div className={id}>
|
||||
{foo} count {this.state.count}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
describe('Enzyme', () => {
|
||||
// example test copied from
|
||||
// https://github.com/enzymejs/enzyme/blob/master/packages/enzyme-test-suite/test/shared/methods/setProps.jsx
|
||||
|
||||
context('setProps', () => {
|
||||
it('gets props from the component', () => {
|
||||
mount(<Foo id="foo" foo="initial" />).as('Foo')
|
||||
cy.contains('initial').should('be.visible')
|
||||
|
||||
cy.get('@Foo')
|
||||
.its('component')
|
||||
.its('props')
|
||||
.then((props) => {
|
||||
console.log('current props', props)
|
||||
expect(props).to.deep.equal({
|
||||
id: 'foo',
|
||||
foo: 'initial',
|
||||
})
|
||||
|
||||
// you can get current props of the component
|
||||
// but not change them - they are read-only
|
||||
expect(() => {
|
||||
props.foo = 'change 1'
|
||||
}).to.throw()
|
||||
})
|
||||
})
|
||||
|
||||
it('mounts component with new props', () => {
|
||||
mount(<Foo id="foo" foo="initial" />)
|
||||
cy.contains('initial').should('be.visible')
|
||||
|
||||
mount(<Foo id="foo" foo="second" />)
|
||||
cy.contains('second').should('be.visible')
|
||||
})
|
||||
|
||||
it('mounts cloned component', () => {
|
||||
const cmp = <Foo id="foo" foo="initial" />
|
||||
|
||||
mount(cmp)
|
||||
cy.contains('initial').should('be.visible')
|
||||
|
||||
const cloned = Cypress._.cloneDeep(cmp)
|
||||
|
||||
// change a property, leaving the rest unchanged
|
||||
cloned.props.foo = 'second'
|
||||
mount(cloned)
|
||||
cy.contains('.foo', 'second').should('be.visible')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,24 +0,0 @@
|
||||
import React from 'react'
|
||||
import { SimpleContext } from './simple-context'
|
||||
|
||||
export class SimpleComponent extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
id: props.id || 'unknown id',
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
console.log('context %o', this.context)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>{this.context.name || 'context not set'}</div>
|
||||
<div className="id">{this.state.id}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SimpleComponent.contextType = SimpleContext
|
||||
@@ -1,4 +0,0 @@
|
||||
// https://reactjs.org/docs/context.html
|
||||
import { createContext } from 'react'
|
||||
|
||||
export const SimpleContext = createContext({ name: '' })
|
||||
@@ -1,60 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
import React from 'react'
|
||||
import { mount } from '@cypress/react'
|
||||
|
||||
class Foo extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
console.log('componentDidMount called')
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
console.log('componentDidUpdate called')
|
||||
}
|
||||
|
||||
render () {
|
||||
const { id, foo } = this.props
|
||||
|
||||
return (
|
||||
<div className={id}>
|
||||
{foo} count {this.state.count}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
describe('Enzyme', () => {
|
||||
context('setState', () => {
|
||||
it('sets component state', () => {
|
||||
// get the component reference using "ref" prop
|
||||
// and place it into the object for Cypress to "wait" for it
|
||||
let c = {}
|
||||
|
||||
mount(<Foo id="foo" foo="initial" ref={(i) => (c.instance = i)} />)
|
||||
cy.contains('initial').should('be.visible')
|
||||
|
||||
cy.log('**check state**')
|
||||
cy.wrap(c)
|
||||
.its('instance.state')
|
||||
.should('deep.equal', { count: 0 })
|
||||
|
||||
cy.log('**setState**')
|
||||
cy.wrap(c)
|
||||
.its('instance')
|
||||
.invoke('setState', { count: 10 })
|
||||
|
||||
cy.wrap(c)
|
||||
.its('instance.state')
|
||||
.should('deep.equal', { count: 10 })
|
||||
|
||||
cy.contains('initial count 10')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,34 +1,26 @@
|
||||
import React from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import axios from 'axios'
|
||||
|
||||
export class Users extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
users: [],
|
||||
}
|
||||
export function Users () {
|
||||
const [users, setUsers] = useState([])
|
||||
|
||||
const getUsers = async () => {
|
||||
const response = await axios.get('https://jsonplaceholder.cypress.io/users?_limit=3')
|
||||
|
||||
setUsers(response.data)
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
axios
|
||||
.get('https://jsonplaceholder.cypress.io/users?_limit=3')
|
||||
.then((response) => {
|
||||
// JSON responses are automatically parsed.
|
||||
this.setState({
|
||||
users: response.data,
|
||||
})
|
||||
})
|
||||
}
|
||||
useEffect(() => {
|
||||
getUsers()
|
||||
}, [])
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
{this.state.users.map((user) => (
|
||||
<li key={user.id}>
|
||||
<strong>{user.id}</strong> - {user.name}
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
{users.map((user) => (
|
||||
<li key={user.id}>
|
||||
<strong>{user.id}</strong> - {user.name}
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,34 +1,26 @@
|
||||
import React from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
|
||||
export class Users extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
users: [],
|
||||
}
|
||||
export function Users () {
|
||||
const [users, setUsers] = useState([])
|
||||
|
||||
const getUsers = async () => {
|
||||
const response = await fetch('https://jsonplaceholder.cypress.io/users?_limit=3')
|
||||
const list = await response.json()
|
||||
|
||||
setUsers(list)
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
fetch('https://jsonplaceholder.cypress.io/users?_limit=3')
|
||||
.then((response) => {
|
||||
return response.json()
|
||||
})
|
||||
.then((list) => {
|
||||
this.setState({
|
||||
users: list,
|
||||
})
|
||||
})
|
||||
}
|
||||
useEffect(() => {
|
||||
getUsers()
|
||||
}, [])
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
{this.state.users.map((user) => (
|
||||
<li key={user.id}>
|
||||
<strong>{user.id}</strong> - {user.name}
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
{users.map((user) => (
|
||||
<li key={user.id}>
|
||||
<strong>{user.id}</strong> - {user.name}
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ import { mount } from '@cypress/react'
|
||||
import './tic-tac-toe.css'
|
||||
|
||||
// for now need a constructor, otherwise getting "Weak map" key
|
||||
const BoardWrap = ({ squares, onClick }) => {
|
||||
const BoardWrap = ({ squares, onPlay }) => {
|
||||
return (
|
||||
<div className="game">
|
||||
<div className="game-board">
|
||||
<Board squares={squares} onClick={onClick} />
|
||||
<Board squares={squares} onPlay={onPlay} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -21,16 +21,16 @@ beforeEach(() => {
|
||||
|
||||
it('renders empty Board', () => {
|
||||
const squares = Array(9).fill(null)
|
||||
const onClick = cy.stub()
|
||||
const onPlay = cy.stub()
|
||||
|
||||
mount(<BoardWrap squares={squares} onClick={onClick} />)
|
||||
mount(<BoardWrap squares={squares} onPlay={onPlay} />)
|
||||
cy.get('.board-row')
|
||||
.eq(0)
|
||||
.find('.square')
|
||||
.eq(0)
|
||||
.click()
|
||||
.then(() => {
|
||||
expect(onClick).to.have.been.calledWith(0)
|
||||
expect(onPlay).to.have.been.called
|
||||
})
|
||||
})
|
||||
|
||||
@@ -55,7 +55,7 @@ it('renders Board with a few squares filled', () => {
|
||||
|
||||
it('plays the game', () => {
|
||||
mount(<Game />)
|
||||
cy.contains('.game-info', 'Next player: X').should('be.visible')
|
||||
cy.contains('.game-board > .status', 'Next player: X').should('be.visible')
|
||||
cy.get('.board-row')
|
||||
.eq(0)
|
||||
.find('.square')
|
||||
@@ -87,7 +87,7 @@ it('plays the game', () => {
|
||||
.eq(2)
|
||||
.click()
|
||||
|
||||
cy.contains('.game-info', 'Winner: X').should('be.visible')
|
||||
cy.contains('.game-board > .status', 'Winner: X').should('be.visible')
|
||||
// history of moves
|
||||
cy.get('ol li')
|
||||
.should('have.length', 6)
|
||||
|
||||
@@ -1,130 +1,106 @@
|
||||
// from https://codepen.io/gaearon/pen/gWWZgR
|
||||
import React from 'react'
|
||||
import React, { useState } from 'react'
|
||||
|
||||
function Square (props) {
|
||||
function Square ({ value, onSquareClick }) {
|
||||
return (
|
||||
<button className="square" onClick={props.onClick}>
|
||||
{props.value}
|
||||
<button className="square" onClick={onSquareClick}>
|
||||
{value}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export class Board extends React.Component {
|
||||
renderSquare (i) {
|
||||
return (
|
||||
<Square
|
||||
value={this.props.squares[i]}
|
||||
onClick={() => this.props.onClick(i)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
<div className="board-row">
|
||||
{this.renderSquare(0)}
|
||||
{this.renderSquare(1)}
|
||||
{this.renderSquare(2)}
|
||||
</div>
|
||||
<div className="board-row">
|
||||
{this.renderSquare(3)}
|
||||
{this.renderSquare(4)}
|
||||
{this.renderSquare(5)}
|
||||
</div>
|
||||
<div className="board-row">
|
||||
{this.renderSquare(6)}
|
||||
{this.renderSquare(7)}
|
||||
{this.renderSquare(8)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default class Game extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
history: [
|
||||
{
|
||||
squares: Array(9).fill(null),
|
||||
},
|
||||
],
|
||||
stepNumber: 0,
|
||||
xIsNext: true,
|
||||
}
|
||||
}
|
||||
|
||||
handleClick (i) {
|
||||
const history = this.state.history.slice(0, this.state.stepNumber + 1)
|
||||
const current = history[history.length - 1]
|
||||
const squares = current.squares.slice()
|
||||
|
||||
export function Board ({ xIsNext, squares, onPlay }) {
|
||||
function handleClick (i) {
|
||||
if (calculateWinner(squares) || squares[i]) {
|
||||
return
|
||||
}
|
||||
|
||||
squares[i] = this.state.xIsNext ? 'X' : 'O'
|
||||
this.setState({
|
||||
history: history.concat([
|
||||
{
|
||||
squares,
|
||||
},
|
||||
]),
|
||||
stepNumber: history.length,
|
||||
xIsNext: !this.state.xIsNext,
|
||||
})
|
||||
}
|
||||
const nextSquares = squares.slice()
|
||||
|
||||
jumpTo (step) {
|
||||
this.setState({
|
||||
stepNumber: step,
|
||||
xIsNext: step % 2 === 0,
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
const history = this.state.history
|
||||
const current = history[this.state.stepNumber]
|
||||
const winner = calculateWinner(current.squares)
|
||||
|
||||
const moves = history.map((step, move) => {
|
||||
const desc = move ? `Go to move #${move}` : 'Go to game start'
|
||||
|
||||
return (
|
||||
<li key={move}>
|
||||
<button onClick={() => this.jumpTo(move)}>{desc}</button>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
|
||||
let status
|
||||
|
||||
if (winner) {
|
||||
status = `Winner: ${winner}`
|
||||
if (xIsNext) {
|
||||
nextSquares[i] = 'X'
|
||||
} else {
|
||||
status = `Next player: ${this.state.xIsNext ? 'X' : 'O'}`
|
||||
nextSquares[i] = 'O'
|
||||
}
|
||||
|
||||
onPlay(nextSquares)
|
||||
}
|
||||
|
||||
const winner = calculateWinner(squares)
|
||||
let status
|
||||
|
||||
if (winner) {
|
||||
status = `Winner: ${ winner}`
|
||||
} else {
|
||||
status = `Next player: ${ xIsNext ? 'X' : 'O'}`
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="status">{status}</div>
|
||||
<div className="board-row">
|
||||
<Square value={squares[0]} onSquareClick={() => handleClick(0)} />
|
||||
<Square value={squares[1]} onSquareClick={() => handleClick(1)} />
|
||||
<Square value={squares[2]} onSquareClick={() => handleClick(2)} />
|
||||
</div>
|
||||
<div className="board-row">
|
||||
<Square value={squares[3]} onSquareClick={() => handleClick(3)} />
|
||||
<Square value={squares[4]} onSquareClick={() => handleClick(4)} />
|
||||
<Square value={squares[5]} onSquareClick={() => handleClick(5)} />
|
||||
</div>
|
||||
<div className="board-row">
|
||||
<Square value={squares[6]} onSquareClick={() => handleClick(6)} />
|
||||
<Square value={squares[7]} onSquareClick={() => handleClick(7)} />
|
||||
<Square value={squares[8]} onSquareClick={() => handleClick(8)} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Game () {
|
||||
const [history, setHistory] = useState([Array(9).fill(null)])
|
||||
const [currentMove, setCurrentMove] = useState(0)
|
||||
const xIsNext = currentMove % 2 === 0
|
||||
const currentSquares = history[currentMove]
|
||||
|
||||
function handlePlay (nextSquares) {
|
||||
const nextHistory = [...history.slice(0, currentMove + 1), nextSquares]
|
||||
|
||||
setHistory(nextHistory)
|
||||
setCurrentMove(nextHistory.length - 1)
|
||||
}
|
||||
|
||||
function jumpTo (nextMove) {
|
||||
setCurrentMove(nextMove)
|
||||
}
|
||||
|
||||
const moves = history.map((squares, move) => {
|
||||
let description
|
||||
|
||||
if (move > 0) {
|
||||
description = `Go to move #${ move}`
|
||||
} else {
|
||||
description = 'Go to game start'
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="game">
|
||||
<div className="game-board">
|
||||
<Board squares={current.squares} onClick={(i) => this.handleClick(i)} />
|
||||
</div>
|
||||
<div className="game-info">
|
||||
<div>{status}</div>
|
||||
<ol>{moves}</ol>
|
||||
</div>
|
||||
</div>
|
||||
<li key={move}>
|
||||
<button onClick={() => jumpTo(move)}>{description}</button>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="game">
|
||||
<div className="game-board">
|
||||
<Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />
|
||||
</div>
|
||||
<div className="game-info">
|
||||
<ol>{moves}</ol>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// ========================================
|
||||
|
||||
// ReactDOM.render(<Game />, document.getElementById('root'))
|
||||
|
||||
export function calculateWinner (squares) {
|
||||
const lines = [
|
||||
[0, 1, 2],
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import React from 'react'
|
||||
|
||||
export default class ShoppingList extends React.Component {
|
||||
render () {
|
||||
return (
|
||||
<div className="shopping-list">
|
||||
<h1>Shopping List for {this.props.name}</h1>
|
||||
<ul>
|
||||
<li>Instagram</li>
|
||||
<li>WhatsApp</li>
|
||||
<li>Oculus</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default function ShoppingList ({ name }) {
|
||||
return (
|
||||
<div className="shopping-list">
|
||||
<h1>Shopping List for {name}</h1>
|
||||
<ul>
|
||||
<li>Instagram</li>
|
||||
<li>WhatsApp</li>
|
||||
<li>Oculus</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Example usage: <ShoppingList name="Mark" />
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import React from 'react'
|
||||
|
||||
export default class Square extends React.Component {
|
||||
render () {
|
||||
return (
|
||||
<button className="square" onClick={() => alert('click')}>
|
||||
{this.props.value}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
export default function Square ({ value }) {
|
||||
return (
|
||||
<button className="square" onClick={() => alert('click')}>
|
||||
{value}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
import React from 'react'
|
||||
|
||||
export default class Square extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
value: null,
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<button className="square" onClick={() => alert('click')}>
|
||||
{this.props.value}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
export default function Square ({ value }) {
|
||||
return (
|
||||
<button className="square" onClick={() => alert('click')}>
|
||||
{value || null}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
import React from 'react'
|
||||
import React, { useState } from 'react'
|
||||
|
||||
export default class Square extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
value: null,
|
||||
}
|
||||
}
|
||||
export default function Square () {
|
||||
const [value, setValue] = useState(null)
|
||||
|
||||
render () {
|
||||
return (
|
||||
<button className="square" onClick={() => this.setState({ value: 'X' })}>
|
||||
{this.state.value}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<button className="square" onClick={() => setValue('X')}>
|
||||
{value}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function Square (props) {
|
||||
export default function Square ({ value, onClick }) {
|
||||
return (
|
||||
<button className="square" onClick={props.onClick}>
|
||||
{props.value}
|
||||
<button className="square" onClick={onClick}>
|
||||
{value}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/// <reference types="cypress" />
|
||||
import React, { useLayoutEffect, useEffect } from 'react'
|
||||
import ReactDom from 'react-dom'
|
||||
import { mount, getContainerEl } from '@cypress/react'
|
||||
import { mount } from '@cypress/react'
|
||||
|
||||
it('should not run unmount effect cleanup when rerendering', () => {
|
||||
const layoutEffectCleanup = cy.stub()
|
||||
@@ -60,8 +59,8 @@ it('should run unmount effect cleanup when unmounting', () => {
|
||||
expect(effectCleanup).to.have.been.callCount(0)
|
||||
})
|
||||
|
||||
cy
|
||||
.then(() => ReactDom.unmountComponentAtNode(getContainerEl()))
|
||||
// mount something else to trigger an unmount event
|
||||
cy.mount(<div>Hello </div>)
|
||||
.then(async () => {
|
||||
// does not call useEffect in react 17 unmount synchronously.
|
||||
// @see https://github.com/facebook/react/issues/20263
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/// <reference types="cypress" />
|
||||
import Comp from './comp.jsx'
|
||||
import { Comp } from './comp.jsx'
|
||||
import React from 'react'
|
||||
import { mount, unmount } from '@cypress/react'
|
||||
|
||||
@@ -11,7 +11,6 @@ it('calls callbacks on mount and unmount', () => {
|
||||
mount(<Comp onMount={onMount} onUnmount={onUnmount} />)
|
||||
cy.then(() => {
|
||||
expect(onMount).to.have.been.calledOnce
|
||||
expect(onUnmount).to.have.not.been.called
|
||||
})
|
||||
|
||||
cy.contains('Component with').should('be.visible')
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import React, { Component } from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
|
||||
export default class Comp extends Component {
|
||||
componentDidMount () {
|
||||
this.props.onMount()
|
||||
}
|
||||
export const Comp = ({ onMount }) => {
|
||||
useEffect(() => {
|
||||
onMount()
|
||||
}, [])
|
||||
|
||||
componentWillUnmount () {
|
||||
this.props.onUnmount()
|
||||
}
|
||||
|
||||
render () {
|
||||
return <div>Component with mount and unmount calls</div>
|
||||
}
|
||||
return <div>Component with mount and unmount calls</div>
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
import React, { Component } from 'react'
|
||||
import { getContainerEl } from '@cypress/mount-utils'
|
||||
import ReactDom from 'react-dom'
|
||||
import { mount } from '@cypress/react'
|
||||
|
||||
class Comp extends Component {
|
||||
componentWillUnmount () {
|
||||
// simply calls the prop
|
||||
this.props.onUnmount()
|
||||
}
|
||||
|
||||
render () {
|
||||
return <div>My component</div>
|
||||
}
|
||||
}
|
||||
|
||||
describe('Comp with componentWillUnmount', () => {
|
||||
it('calls the prop', () => {
|
||||
mount(<Comp onUnmount={cy.stub().as('onUnmount')} />)
|
||||
cy.contains('My component')
|
||||
|
||||
// after we have confirmed the component exists let's remove it
|
||||
// unmount() command is automatically enqueued
|
||||
cy.then(() => ReactDom.unmountComponentAtNode(getContainerEl()))
|
||||
|
||||
// the component is gone from the DOM
|
||||
cy.contains('My component').should('not.exist')
|
||||
// the component has called the prop on unmount
|
||||
cy.get('@onUnmount').should('have.been.calledOnce')
|
||||
})
|
||||
|
||||
it('can be called using then', () => {
|
||||
mount(<Comp onUnmount={cy.stub().as('onUnmount')} />)
|
||||
cy.contains('My component')
|
||||
|
||||
// still works, should probably be removed in v5
|
||||
cy.then(() => ReactDom.unmountComponentAtNode(getContainerEl()))
|
||||
|
||||
// the component is gone from the DOM
|
||||
cy.contains('My component').should('not.exist')
|
||||
// the component has called the prop on unmount
|
||||
cy.get('@onUnmount').should('have.been.calledOnce')
|
||||
})
|
||||
})
|
||||
@@ -1,10 +1,7 @@
|
||||
import React from 'react'
|
||||
|
||||
class MyComponent extends React.Component {
|
||||
state = {}
|
||||
render () {
|
||||
return <div>Hello</div>
|
||||
}
|
||||
export function MyComponent () {
|
||||
return <div>Hello</div>
|
||||
}
|
||||
|
||||
export default MyComponent
|
||||
|
||||
@@ -17,25 +17,26 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/mount-utils": "0.0.0-development",
|
||||
"@types/semver": "7.5.0",
|
||||
"@vitejs/plugin-react": "4.3.0",
|
||||
"axios": "0.21.2",
|
||||
"@types/semver": "7.5.8",
|
||||
"@vitejs/plugin-react": "4.3.3",
|
||||
"axios": "1.7.7",
|
||||
"cypress": "0.0.0-development",
|
||||
"prop-types": "15.7.2",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-router": "6.10.0",
|
||||
"react-router-dom": "6.10.0",
|
||||
"prop-types": "15.8.1",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"react-router": "6.28.0",
|
||||
"react-router-dom": "6.28.0",
|
||||
"semver": "^7.5.3",
|
||||
"typescript": "~5.4.5",
|
||||
"vite": "5.2.11",
|
||||
"vite": "5.4.10",
|
||||
"vite-plugin-require-transform": "1.0.12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.9.16 || ^17.0.0",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"cypress": "*",
|
||||
"react": "^=16.x || ^=17.x",
|
||||
"react-dom": "^=16.x || ^=17.x"
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
@@ -90,9 +91,6 @@
|
||||
"nx": {
|
||||
"targets": {
|
||||
"build": {
|
||||
"dependsOn": [
|
||||
"!@cypress/react18:build"
|
||||
],
|
||||
"outputs": [
|
||||
"{workspaceRoot}/cli/react",
|
||||
"{projectRoot}/dist"
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import { getContainerEl } from '@cypress/mount-utils'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import major from 'semver/functions/major'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import { getContainerEl } from '@cypress/mount-utils'
|
||||
import {
|
||||
makeMountFn,
|
||||
makeUnmountFn,
|
||||
} from './createMount'
|
||||
} from './index'
|
||||
import type {
|
||||
MountOptions,
|
||||
InternalMountOptions,
|
||||
} from './types'
|
||||
UnmountArgs,
|
||||
} from './index'
|
||||
|
||||
let lastReactDom: typeof ReactDOM
|
||||
let root: ReactDOM.Root | null
|
||||
|
||||
const cleanup = () => {
|
||||
if (lastReactDom) {
|
||||
const root = getContainerEl()
|
||||
if (root) {
|
||||
root.unmount()
|
||||
|
||||
lastReactDom.unmountComponentAtNode(root)
|
||||
root = null
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -27,10 +27,10 @@ const cleanup = () => {
|
||||
|
||||
/**
|
||||
* Mounts a React component into the DOM.
|
||||
* @param jsx {React.ReactNode} The React component to mount.
|
||||
* @param options {MountOptions} [options={}] options to pass to the mount function.
|
||||
* @param rerenderKey {string} [rerenderKey] A key to use to force a rerender.
|
||||
* @see {@link https://on.cypress.io/mounting-react} for more details.
|
||||
* @param {import('react').JSX.Element} jsx The React component to mount.
|
||||
* @param {MountOptions} options Options to pass to the mount function.
|
||||
* @param {string} rerenderKey A key to use to force a rerender.
|
||||
*
|
||||
* @example
|
||||
* import { mount } from '@cypress/react'
|
||||
* import { Stepper } from './Stepper'
|
||||
@@ -40,24 +40,24 @@ const cleanup = () => {
|
||||
* cy.get('[data-cy=increment]').click()
|
||||
* cy.get('[data-cy=counter]').should('have.text', '1')
|
||||
* }
|
||||
*
|
||||
* @see {@link https://on.cypress.io/mounting-react} for more details.
|
||||
*
|
||||
* @returns {Cypress.Chainable<MountReturn>} The mounted component.
|
||||
*/
|
||||
export function mount (jsx: React.ReactNode, options: MountOptions = {}, rerenderKey?: string) {
|
||||
if (major(React.version) === 18) {
|
||||
const message = '[cypress/react]: You are using `cypress/react`, which is designed for React <= 17. Consider changing to `cypress/react18`, which is designed for React 18.'
|
||||
|
||||
console.error(message)
|
||||
Cypress.log({ name: 'warning', message })
|
||||
}
|
||||
|
||||
// Remove last mounted component if cy.mount is called more than once in a test
|
||||
// React by default removes the last component when calling render, but we should remove the root
|
||||
// to wipe away any state
|
||||
cleanup()
|
||||
|
||||
const internalOptions: InternalMountOptions = {
|
||||
reactDom: ReactDOM,
|
||||
render: (reactComponent: ReturnType<typeof React.createElement>, el: HTMLElement, reactDomToUse: typeof ReactDOM) => {
|
||||
lastReactDom = (reactDomToUse || ReactDOM)
|
||||
render: (reactComponent: ReturnType<typeof React.createElement>, el: HTMLElement) => {
|
||||
if (!root) {
|
||||
root = ReactDOM.createRoot(el)
|
||||
}
|
||||
|
||||
return lastReactDom.render(reactComponent, el)
|
||||
return root.render(reactComponent)
|
||||
},
|
||||
unmount: internalUnmount,
|
||||
cleanup,
|
||||
@@ -66,20 +66,14 @@ export function mount (jsx: React.ReactNode, options: MountOptions = {}, rerende
|
||||
return makeMountFn('mount', jsx, { ReactDom: ReactDOM, ...options }, rerenderKey, internalOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmounts the component from the DOM.
|
||||
* @internal
|
||||
* @param options - Options for unmounting.
|
||||
*/
|
||||
function internalUnmount (options = { log: true }) {
|
||||
return makeUnmountFn(options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removed as of Cypress 11.0.0.
|
||||
* @see https://on.cypress.io/migration-11-0-0-component-testing-updates
|
||||
*/
|
||||
export function unmount (options = { log: true }) {
|
||||
export function unmount (options: UnmountArgs = { log: true }) {
|
||||
// @ts-expect-error - undocumented API
|
||||
Cypress.utils.throwErrByPath('mount.unmount')
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export interface UnmountArgs {
|
||||
export type MountOptions = Partial<MountReactComponentOptions>
|
||||
|
||||
export interface MountReactComponentOptions {
|
||||
ReactDom: typeof import('react-dom')
|
||||
ReactDom: typeof import('react-dom/client')
|
||||
/**
|
||||
* Log the mounting command into Cypress Command Log,
|
||||
* true by default.
|
||||
@@ -22,11 +22,11 @@ export interface MountReactComponentOptions {
|
||||
}
|
||||
|
||||
export interface InternalMountOptions {
|
||||
reactDom: typeof import('react-dom')
|
||||
reactDom: typeof import('react-dom/client')
|
||||
render: (
|
||||
reactComponent: ReturnType<typeof React.createElement>,
|
||||
el: HTMLElement,
|
||||
reactDomToUse: typeof import('react-dom')
|
||||
reactDomToUse: typeof import('react-dom/client')
|
||||
) => void
|
||||
unmount: (options: UnmountArgs) => void
|
||||
cleanup: () => boolean
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
**/dist
|
||||
**/*.d.ts
|
||||
**/package-lock.json
|
||||
**/tsconfig.json
|
||||
**/cypress/fixtures
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
...require('../../.releaserc'),
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
# [@cypress/react18-v2.0.1](https://github.com/cypress-io/cypress/compare/@cypress/react18-v2.0.0...@cypress/react18-v2.0.1) (2024-06-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update cypress to Typescript 5 ([#29568](https://github.com/cypress-io/cypress/issues/29568)) ([f3b6766](https://github.com/cypress-io/cypress/commit/f3b67666a5db0438594339c379cf27e1fd1e4abc))
|
||||
|
||||
# [@cypress/react18-v2.0.0](https://github.com/cypress-io/cypress/compare/@cypress/react18-v1.1.1...@cypress/react18-v2.0.0) (2022-11-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove last mounted component upon subsequent mount calls ([#24470](https://github.com/cypress-io/cypress/issues/24470)) ([f39eb1c](https://github.com/cypress-io/cypress/commit/f39eb1c19e0923bda7ae263168fc6448da942d54))
|
||||
* remove some CT functions and props ([#24419](https://github.com/cypress-io/cypress/issues/24419)) ([294985f](https://github.com/cypress-io/cypress/commit/294985f8b3e0fa00ed66d25f88c8814603766074))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* remove last mounted component upon subsequent mount calls of mount
|
||||
|
||||
# [@cypress/react18-v1.1.1](https://github.com/cypress-io/cypress/compare/@cypress/react18-v1.1.0...@cypress/react18-v1.1.1) (2022-10-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* cypress/react18 rerender ([#23360](https://github.com/cypress-io/cypress/issues/23360)) ([8b8f20e](https://github.com/cypress-io/cypress/commit/8b8f20eec77d4c0a704aee7f7077dc92dbafb93f))
|
||||
|
||||
# [@cypress/react18-v1.1.0](https://github.com/cypress-io/cypress/compare/@cypress/react18-v1.0.1...@cypress/react18-v1.1.0) (2022-08-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adding svelte component testing support ([#23553](https://github.com/cypress-io/cypress/issues/23553)) ([f6eaad4](https://github.com/cypress-io/cypress/commit/f6eaad40e1836fa9db87c60defa5ae6f390c8fd8))
|
||||
|
||||
# [@cypress/react18-v1.0.1](https://github.com/cypress-io/cypress/compare/@cypress/react18-v1.0.0...@cypress/react18-v1.0.1) (2022-08-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **react18:** unmount component with react18 API ([#23204](https://github.com/cypress-io/cypress/issues/23204)) ([eab950b](https://github.com/cypress-io/cypress/commit/eab950bec013f9caf5836e3fa58670fde25e2684))
|
||||
|
||||
# @cypress/react18-v1.0.0 (2022-08-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* React 18 support ([#22876](https://github.com/cypress-io/cypress/issues/22876)) ([f0d3a48](https://github.com/cypress-io/cypress/commit/f0d3a4867907bf6e60468510daa883ccc8dcfb63))
|
||||
@@ -1,7 +0,0 @@
|
||||
# @cypress/react18
|
||||
|
||||
Mount React 18 components in the open source [Cypress.io](https://www.cypress.io/) test runner
|
||||
|
||||
> **Note:** This package is bundled with the `cypress` package and should not need to be installed separately. See the [React Component Testing Docs](https://docs.cypress.io/guides/component-testing/react/overview) for mounting React components. Installing and importing `mount` from `@cypress/react18` should only be done for advanced use-cases.
|
||||
|
||||
## [Changelog](./CHANGELOG.md)
|
||||
@@ -1,71 +0,0 @@
|
||||
{
|
||||
"name": "@cypress/react18",
|
||||
"version": "0.0.0-development",
|
||||
"description": "Test React components using Cypress",
|
||||
"main": "dist/cypress-react.cjs.js",
|
||||
"scripts": {
|
||||
"build": "rimraf dist && rollup -c rollup.config.mjs",
|
||||
"postbuild": "node ../../scripts/sync-exported-npm-with-cli.js",
|
||||
"check-ts": "tsc --noEmit",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json, .",
|
||||
"watch": "yarn build --watch --watch.exclude ./dist/**/*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/mount-utils": "0.0.0-development",
|
||||
"@cypress/react": "0.0.0-development",
|
||||
"@rollup/plugin-commonjs": "^17.1.0",
|
||||
"@rollup/plugin-node-resolve": "^11.1.1",
|
||||
"@types/react": "17.0.83",
|
||||
"@types/react-dom": "17.0.25",
|
||||
"cypress": "0.0.0-development",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"rollup": "3.7.3",
|
||||
"rollup-plugin-typescript2": "^0.29.0",
|
||||
"typescript": "~5.4.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"cypress": "*",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"types": "dist/index.d.ts",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cypress-io/cypress.git"
|
||||
},
|
||||
"homepage": "https://github.com/cypress-io/cypress/blob/develop/npm/react18/#readme",
|
||||
"bugs": "https://github.com/cypress-io/cypress/issues/new?assignees=&labels=npm%3A%20%40cypress%2Freact18&template=1-bug-report.md&title=",
|
||||
"keywords": [
|
||||
"react",
|
||||
"cypress",
|
||||
"cypress-io",
|
||||
"test",
|
||||
"testing"
|
||||
],
|
||||
"module": "dist/cypress-react.esm-bundler.js",
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"nx": {
|
||||
"targets": {
|
||||
"build": {
|
||||
"outputs": [
|
||||
"{workspaceRoot}/cli/react18",
|
||||
"{projectRoot}/dist"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import rollupConfig from '@cypress/react/rollup.config.mjs'
|
||||
|
||||
export default rollupConfig
|
||||
@@ -1,92 +0,0 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import { getContainerEl } from '@cypress/mount-utils'
|
||||
import {
|
||||
makeMountFn,
|
||||
makeUnmountFn,
|
||||
} from '@cypress/react'
|
||||
import type {
|
||||
MountOptions,
|
||||
MountReturn,
|
||||
InternalMountOptions,
|
||||
UnmountArgs,
|
||||
} from '@cypress/react'
|
||||
|
||||
let root: ReactDOM.Root | null
|
||||
|
||||
const cleanup = () => {
|
||||
if (root) {
|
||||
root.unmount()
|
||||
|
||||
root = null
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Mounts a React component into the DOM.
|
||||
* @param {import('react').JSX.Element} jsx The React component to mount.
|
||||
* @param {MountOptions} options Options to pass to the mount function.
|
||||
* @param {string} rerenderKey A key to use to force a rerender.
|
||||
*
|
||||
* @example
|
||||
* import { mount } from '@cypress/react'
|
||||
* import { Stepper } from './Stepper'
|
||||
*
|
||||
* it('mounts', () => {
|
||||
* mount(<StepperComponent />)
|
||||
* cy.get('[data-cy=increment]').click()
|
||||
* cy.get('[data-cy=counter]').should('have.text', '1')
|
||||
* }
|
||||
*
|
||||
* @see {@link https://on.cypress.io/mounting-react} for more details.
|
||||
*
|
||||
* @returns {Cypress.Chainable<MountReturn>} The mounted component.
|
||||
*/
|
||||
export function mount (jsx: React.ReactNode, options: MountOptions = {}, rerenderKey?: string) {
|
||||
// Remove last mounted component if cy.mount is called more than once in a test
|
||||
// React by default removes the last component when calling render, but we should remove the root
|
||||
// to wipe away any state
|
||||
cleanup()
|
||||
const internalOptions: InternalMountOptions = {
|
||||
// @ts-expect-error
|
||||
reactDom: ReactDOM,
|
||||
render: (reactComponent: ReturnType<typeof React.createElement>, el: HTMLElement) => {
|
||||
if (!root) {
|
||||
root = ReactDOM.createRoot(el)
|
||||
}
|
||||
|
||||
return root.render(reactComponent)
|
||||
},
|
||||
unmount: internalUnmount,
|
||||
cleanup,
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
return makeMountFn('mount', jsx, { ReactDom: ReactDOM, ...options }, rerenderKey, internalOptions)
|
||||
}
|
||||
|
||||
function internalUnmount (options = { log: true }) {
|
||||
return makeUnmountFn(options)
|
||||
}
|
||||
/**
|
||||
* Removed as of Cypress 11.0.0.
|
||||
* @see https://on.cypress.io/migration-11-0-0-component-testing-updates
|
||||
*/
|
||||
export function unmount (options: UnmountArgs = { log: true }) {
|
||||
// @ts-expect-error - undocumented API
|
||||
Cypress.utils.throwErrByPath('mount.unmount')
|
||||
}
|
||||
|
||||
// Re-export this to help with migrating away from `unmount`
|
||||
export {
|
||||
getContainerEl,
|
||||
}
|
||||
|
||||
export type {
|
||||
MountOptions,
|
||||
MountReturn,
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"lib": [
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"types": [
|
||||
"cypress"
|
||||
],
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": false
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
@@ -19,7 +19,7 @@ describe('Config options', () => {
|
||||
await ctx.actions.file.writeFileInProject(
|
||||
'src/App.cy.jsx', `
|
||||
import React from 'react'
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
export const App = () => {
|
||||
return (
|
||||
|
||||
@@ -10,8 +10,8 @@ Run Cypress with `DEBUG=cypress:vite-plugin-cypress-esm`. You will get logs in t
|
||||
## Compatibility
|
||||
|
||||
| @cypress/vite-plugin-cypress-esm | cypress |
|
||||
| ------------------------ | ------- |
|
||||
| >= v1 | >= v12 |
|
||||
| -------------------------------- | ------- |
|
||||
| >= v1 | >= v12 |
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -80,6 +80,14 @@ CypressEsm({
|
||||
})
|
||||
```
|
||||
|
||||
If using the `@cypress/react` test harness, you may need to ignore the `react-dom/client` module by configuring as such:
|
||||
|
||||
```ts
|
||||
CypressEsm({
|
||||
ignoreImportList: ['**/react-dom/client']
|
||||
})
|
||||
```
|
||||
|
||||
## Known Issues
|
||||
|
||||
### Import Syntax
|
||||
|
||||
@@ -13,12 +13,11 @@ export default defineConfig({
|
||||
viteConfig: () => {
|
||||
return {
|
||||
plugins: [
|
||||
react({
|
||||
jsxRuntime: 'classic',
|
||||
}),
|
||||
react(),
|
||||
CypressEsm({
|
||||
ignoreModuleList: ['**/ignoreModuleList.cy.ts', '*MyAsync*'],
|
||||
ignoreImportList: ['**/ImmutableModuleB*'],
|
||||
// For `cypress/react` on react 18+, we need to ignore transforming the react-dom/client library
|
||||
ignoreImportList: ['**/ImmutableModuleB*', '**/react-dom/client'],
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
"devDependencies": {
|
||||
"@tanstack/react-query": "4.36.1",
|
||||
"@types/picomatch": "2.3.0",
|
||||
"@vitejs/plugin-react": "4.3.0",
|
||||
"react": "16.8.6",
|
||||
"react-dom": "16.8.6",
|
||||
"react-router": "6.10.0",
|
||||
"react-router-dom": "6.10.0",
|
||||
"@vitejs/plugin-react": "4.3.3",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"react-router": "6.28.0",
|
||||
"react-router-dom": "6.28.0",
|
||||
"vite": "5.2.11"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -82,9 +82,6 @@
|
||||
"nx": {
|
||||
"targets": {
|
||||
"build": {
|
||||
"dependsOn": [
|
||||
"!@cypress/react18:build"
|
||||
],
|
||||
"outputs": [
|
||||
"{workspaceRoot}/cli/vue",
|
||||
"{projectRoot}/dist"
|
||||
|
||||
@@ -70,9 +70,6 @@
|
||||
"nx": {
|
||||
"targets": {
|
||||
"build": {
|
||||
"dependsOn": [
|
||||
"!@cypress/react18:build"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/dist"
|
||||
]
|
||||
|
||||
@@ -203,8 +203,8 @@ describe('component testing dependency warnings', () => {
|
||||
cy.get('[data-cy="warning-alert"]', { timeout: 12000 }).should('exist')
|
||||
.should('contain.text', 'Warning: Component Testing Mismatched Dependencies')
|
||||
.should('contain.text', 'vite. Expected ^4.0.0 || ^5.0.0, found 3.2.11')
|
||||
.should('contain.text', 'react. Expected ^16.0.0 || ^17.0.0 || ^18.0.0, found 15.6.2.')
|
||||
.should('contain.text', 'react-dom. Expected ^16.0.0 || ^17.0.0 || ^18.0.0 but dependency was not found.')
|
||||
.should('contain.text', 'react. Expected ^18.0.0, found 15.6.2.')
|
||||
.should('contain.text', 'react-dom. Expected ^18.0.0 but dependency was not found.')
|
||||
|
||||
cy.get('.warning-markdown').find('li').should('have.length', 3)
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
import 'cypress-real-events/support'
|
||||
import { installCustomPercyCommand } from '@packages/frontend-shared/cypress/support/customPercyCommand'
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ export const WIZARD_DEPENDENCY_REACT = {
|
||||
package: 'react',
|
||||
installer: 'react',
|
||||
description: 'A JavaScript library for building user interfaces',
|
||||
minVersion: '^16.0.0 || ^17.0.0 || ^18.0.0',
|
||||
minVersion: '^18.0.0',
|
||||
} as const
|
||||
|
||||
export const WIZARD_DEPENDENCY_REACT_DOM = {
|
||||
@@ -31,7 +31,7 @@ export const WIZARD_DEPENDENCY_REACT_DOM = {
|
||||
package: 'react-dom',
|
||||
installer: 'react-dom',
|
||||
description: 'This package serves as the entry point to the DOM and server renderers for React',
|
||||
minVersion: '^16.0.0 || ^17.0.0 || ^18.0.0',
|
||||
minVersion: '^18.0.0',
|
||||
} as const
|
||||
|
||||
export const WIZARD_DEPENDENCY_TYPESCRIPT = {
|
||||
|
||||
@@ -101,16 +101,6 @@ export function getBundler (bundler: WizardBundler['type']): WizardBundler {
|
||||
|
||||
const mountModule = <T extends string>(mountModule: T) => (projectPath: string) => Promise.resolve(mountModule)
|
||||
|
||||
const reactMountModule = async (projectPath: string) => {
|
||||
const reactPkg = await isDependencyInstalled(dependencies.WIZARD_DEPENDENCY_REACT, projectPath)
|
||||
|
||||
if (!reactPkg.detectedVersion || !semver.valid(reactPkg.detectedVersion)) {
|
||||
return 'cypress/react'
|
||||
}
|
||||
|
||||
return semver.major(reactPkg.detectedVersion) === 18 ? 'cypress/react18' : 'cypress/react'
|
||||
}
|
||||
|
||||
export const SUPPORT_STATUSES: Readonly<Cypress.ResolvedComponentFrameworkDefinition['supportStatus'][]> = ['alpha', 'beta', 'full', 'community'] as const
|
||||
|
||||
export const CT_FRAMEWORKS: Cypress.ComponentFrameworkDefinition[] = [
|
||||
@@ -130,7 +120,7 @@ export const CT_FRAMEWORKS: Cypress.ComponentFrameworkDefinition[] = [
|
||||
},
|
||||
codeGenFramework: 'react',
|
||||
glob: '*.{js,jsx,tsx}',
|
||||
mountModule: reactMountModule,
|
||||
mountModule: mountModule('cypress/react'),
|
||||
supportStatus: 'full',
|
||||
/**
|
||||
* Next.js uses style-loader to inject CSS and requires this element to exist in the HTML.
|
||||
@@ -176,7 +166,7 @@ export const CT_FRAMEWORKS: Cypress.ComponentFrameworkDefinition[] = [
|
||||
},
|
||||
codeGenFramework: 'react',
|
||||
glob: '*.{js,jsx,tsx}',
|
||||
mountModule: reactMountModule,
|
||||
mountModule: mountModule('cypress/react'),
|
||||
supportStatus: 'full',
|
||||
componentIndexHtml: componentIndexHtmlGenerator(),
|
||||
},
|
||||
|
||||
@@ -4,11 +4,12 @@ import { expect } from 'chai'
|
||||
|
||||
describe('supportFileComponent', () => {
|
||||
context('react', () => {
|
||||
for (const mountModule of ['cypress/react', 'cypress/react18'] as const) {
|
||||
it(`handles ${mountModule} and JS`, () => {
|
||||
const actual = supportFileComponent('js', mountModule)
|
||||
const mountModule = 'cypress/react'
|
||||
|
||||
expect(actual).to.eq(dedent`
|
||||
it(`handles ${mountModule} and JS`, () => {
|
||||
const actual = supportFileComponent('js', mountModule)
|
||||
|
||||
expect(actual).to.eq(dedent`
|
||||
// ***********************************************************
|
||||
// This example support/component.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
@@ -37,12 +38,12 @@ describe('supportFileComponent', () => {
|
||||
// Example use:
|
||||
// cy.mount(<MyComponent />)
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
it(`handles ${mountModule} and TS`, () => {
|
||||
const actual = supportFileComponent('ts', mountModule)
|
||||
it(`handles ${mountModule} and TS`, () => {
|
||||
const actual = supportFileComponent('ts', mountModule)
|
||||
|
||||
expect(actual).to.eq(dedent`
|
||||
expect(actual).to.eq(dedent`
|
||||
// ***********************************************************
|
||||
// This example support/component.ts is processed and
|
||||
// loaded automatically before your test files.
|
||||
@@ -83,8 +84,7 @@ describe('supportFileComponent', () => {
|
||||
// Example use:
|
||||
// cy.mount(<MyComponent />)
|
||||
`)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
context('vue', () => {
|
||||
|
||||
@@ -7,16 +7,14 @@ exports['React major versions with Webpack executes all of the tests for React v
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Cypress: 1.2.3 │
|
||||
│ Browser: FooBrowser 88 │
|
||||
│ Specs: 5 found (App.cy.jsx, Unmount.cy.jsx, UsingLegacyMount.cy.jsx, Rerendering.cy.jsx, │
|
||||
│ mount.cy.jsx) │
|
||||
│ Searched: src/App.cy.jsx, src/Unmount.cy.jsx, src/UsingLegacyMount.cy.jsx, src/Rerendering.c │
|
||||
│ y.jsx, src/mount.cy.jsx │
|
||||
│ Specs: 4 found (App.cy.jsx, Unmount.cy.jsx, Rerendering.cy.jsx, mount.cy.jsx) │
|
||||
│ Searched: src/App.cy.jsx, src/Unmount.cy.jsx, src/Rerendering.cy.jsx, src/mount.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: App.cy.jsx (1 of 5)
|
||||
Running: App.cy.jsx (1 of 4)
|
||||
|
||||
|
||||
✓ renders hello world
|
||||
@@ -42,7 +40,7 @@ exports['React major versions with Webpack executes all of the tests for React v
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: Unmount.cy.jsx (2 of 5)
|
||||
Running: Unmount.cy.jsx (2 of 4)
|
||||
|
||||
|
||||
Comp with componentWillUnmount
|
||||
@@ -73,34 +71,7 @@ exports['React major versions with Webpack executes all of the tests for React v
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: UsingLegacyMount.cy.jsx (3 of 5)
|
||||
|
||||
|
||||
using legacy mount
|
||||
✓ issues a warning encouraging user to update
|
||||
|
||||
|
||||
1 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 1 │
|
||||
│ Passing: 1 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: UsingLegacyMount.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: Rerendering.cy.jsx (4 of 5)
|
||||
Running: Rerendering.cy.jsx (3 of 4)
|
||||
|
||||
|
||||
re-render
|
||||
@@ -127,7 +98,7 @@ exports['React major versions with Webpack executes all of the tests for React v
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: mount.cy.jsx (5 of 5)
|
||||
Running: mount.cy.jsx (4 of 4)
|
||||
|
||||
|
||||
mount
|
||||
@@ -166,372 +137,11 @@ exports['React major versions with Webpack executes all of the tests for React v
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ Unmount.cy.jsx XX:XX 3 3 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ UsingLegacyMount.cy.jsx XX:XX 1 1 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ Rerendering.cy.jsx XX:XX 1 1 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ mount.cy.jsx XX:XX 3 3 - - - │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
✔ All specs passed! XX:XX 10 10 - - -
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['React major versions with Webpack executes all of the tests for React v17 with Webpack 1'] = `
|
||||
|
||||
====================================================================================================
|
||||
|
||||
(Run Starting)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Cypress: 1.2.3 │
|
||||
│ Browser: FooBrowser 88 │
|
||||
│ Specs: 5 found (App.cy.jsx, Unmount.cy.jsx, UsingLegacyMount.cy.jsx, Rerendering.cy.jsx, │
|
||||
│ mount.cy.jsx) │
|
||||
│ Searched: src/App.cy.jsx, src/Unmount.cy.jsx, src/UsingLegacyMount.cy.jsx, src/Rerendering.c │
|
||||
│ y.jsx, src/mount.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: App.cy.jsx (1 of 5)
|
||||
50 modules
|
||||
|
||||
|
||||
✓ renders hello world
|
||||
✓ renders background
|
||||
|
||||
2 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 2 │
|
||||
│ Passing: 2 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: App.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: Unmount.cy.jsx (2 of 5)
|
||||
|
||||
|
||||
Comp with componentWillUnmount
|
||||
✓ calls the prop
|
||||
|
||||
mount cleanup
|
||||
✓ mount 1
|
||||
✓ mount 2
|
||||
|
||||
|
||||
3 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 3 │
|
||||
│ Passing: 3 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: Unmount.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: UsingLegacyMount.cy.jsx (3 of 5)
|
||||
|
||||
|
||||
using legacy mount
|
||||
✓ does not warning or log
|
||||
|
||||
|
||||
1 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 1 │
|
||||
│ Passing: 1 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: UsingLegacyMount.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: Rerendering.cy.jsx (4 of 5)
|
||||
|
||||
|
||||
re-render
|
||||
✓ maintains component state across re-renders
|
||||
|
||||
|
||||
1 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 1 │
|
||||
│ Passing: 1 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: Rerendering.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: mount.cy.jsx (5 of 5)
|
||||
|
||||
|
||||
mount
|
||||
✓ does not error when rendering primitives
|
||||
teardown
|
||||
✓ should mount
|
||||
✓ should remove previous mounted component
|
||||
|
||||
|
||||
3 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 3 │
|
||||
│ Passing: 3 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: mount.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
====================================================================================================
|
||||
|
||||
(Run Finished)
|
||||
|
||||
|
||||
Spec Tests Passing Failing Pending Skipped
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ ✔ App.cy.jsx XX:XX 2 2 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ Unmount.cy.jsx XX:XX 3 3 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ UsingLegacyMount.cy.jsx XX:XX 1 1 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ Rerendering.cy.jsx XX:XX 1 1 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ mount.cy.jsx XX:XX 3 3 - - - │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
✔ All specs passed! XX:XX 10 10 - - -
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['React major versions with Vite executes all of the tests for React v17 with Vite 1'] = `
|
||||
|
||||
====================================================================================================
|
||||
|
||||
(Run Starting)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Cypress: 1.2.3 │
|
||||
│ Browser: FooBrowser 88 │
|
||||
│ Specs: 5 found (App.cy.jsx, Unmount.cy.jsx, UsingLegacyMount.cy.jsx, Rerendering.cy.jsx, │
|
||||
│ mount.cy.jsx) │
|
||||
│ Searched: src/App.cy.jsx, src/Unmount.cy.jsx, src/UsingLegacyMount.cy.jsx, src/Rerendering.c │
|
||||
│ y.jsx, src/mount.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: App.cy.jsx (1 of 5)
|
||||
|
||||
|
||||
✓ renders hello world
|
||||
✓ renders background
|
||||
|
||||
2 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 2 │
|
||||
│ Passing: 2 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: App.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: Unmount.cy.jsx (2 of 5)
|
||||
|
||||
|
||||
Comp with componentWillUnmount
|
||||
✓ calls the prop
|
||||
|
||||
mount cleanup
|
||||
✓ mount 1
|
||||
✓ mount 2
|
||||
|
||||
|
||||
3 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 3 │
|
||||
│ Passing: 3 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: Unmount.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: UsingLegacyMount.cy.jsx (3 of 5)
|
||||
|
||||
|
||||
using legacy mount
|
||||
✓ does not warning or log
|
||||
|
||||
|
||||
1 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 1 │
|
||||
│ Passing: 1 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: UsingLegacyMount.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: Rerendering.cy.jsx (4 of 5)
|
||||
|
||||
|
||||
re-render
|
||||
✓ maintains component state across re-renders
|
||||
|
||||
|
||||
1 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 1 │
|
||||
│ Passing: 1 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: Rerendering.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: mount.cy.jsx (5 of 5)
|
||||
|
||||
|
||||
mount
|
||||
✓ does not error when rendering primitives
|
||||
teardown
|
||||
✓ should mount
|
||||
✓ should remove previous mounted component
|
||||
|
||||
|
||||
3 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 3 │
|
||||
│ Passing: 3 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: mount.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
====================================================================================================
|
||||
|
||||
(Run Finished)
|
||||
|
||||
|
||||
Spec Tests Passing Failing Pending Skipped
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ ✔ App.cy.jsx XX:XX 2 2 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ Unmount.cy.jsx XX:XX 3 3 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ UsingLegacyMount.cy.jsx XX:XX 1 1 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ Rerendering.cy.jsx XX:XX 1 1 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ mount.cy.jsx XX:XX 3 3 - - - │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
✔ All specs passed! XX:XX 10 10 - - -
|
||||
✔ All specs passed! XX:XX 9 9 - - -
|
||||
|
||||
|
||||
`
|
||||
@@ -545,16 +155,14 @@ exports['React major versions with Vite executes all of the tests for React v18
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Cypress: 1.2.3 │
|
||||
│ Browser: FooBrowser 88 │
|
||||
│ Specs: 5 found (App.cy.jsx, Unmount.cy.jsx, UsingLegacyMount.cy.jsx, Rerendering.cy.jsx, │
|
||||
│ mount.cy.jsx) │
|
||||
│ Searched: src/App.cy.jsx, src/Unmount.cy.jsx, src/UsingLegacyMount.cy.jsx, src/Rerendering.c │
|
||||
│ y.jsx, src/mount.cy.jsx │
|
||||
│ Specs: 4 found (App.cy.jsx, Unmount.cy.jsx, Rerendering.cy.jsx, mount.cy.jsx) │
|
||||
│ Searched: src/App.cy.jsx, src/Unmount.cy.jsx, src/Rerendering.cy.jsx, src/mount.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: App.cy.jsx (1 of 5)
|
||||
Running: App.cy.jsx (1 of 4)
|
||||
|
||||
|
||||
✓ renders hello world
|
||||
@@ -580,7 +188,7 @@ exports['React major versions with Vite executes all of the tests for React v18
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: Unmount.cy.jsx (2 of 5)
|
||||
Running: Unmount.cy.jsx (2 of 4)
|
||||
|
||||
|
||||
Comp with componentWillUnmount
|
||||
@@ -611,34 +219,7 @@ exports['React major versions with Vite executes all of the tests for React v18
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: UsingLegacyMount.cy.jsx (3 of 5)
|
||||
|
||||
|
||||
using legacy mount
|
||||
✓ issues a warning encouraging user to update
|
||||
|
||||
|
||||
1 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 1 │
|
||||
│ Passing: 1 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: UsingLegacyMount.cy.jsx │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: Rerendering.cy.jsx (4 of 5)
|
||||
Running: Rerendering.cy.jsx (3 of 4)
|
||||
|
||||
|
||||
re-render
|
||||
@@ -665,7 +246,7 @@ exports['React major versions with Vite executes all of the tests for React v18
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: mount.cy.jsx (5 of 5)
|
||||
Running: mount.cy.jsx (4 of 4)
|
||||
|
||||
|
||||
mount
|
||||
@@ -704,13 +285,11 @@ exports['React major versions with Vite executes all of the tests for React v18
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ Unmount.cy.jsx XX:XX 3 3 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ UsingLegacyMount.cy.jsx XX:XX 1 1 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ Rerendering.cy.jsx XX:XX 1 1 - - - │
|
||||
├────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ ✔ mount.cy.jsx XX:XX 3 3 - - - │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
✔ All specs passed! XX:XX 10 10 - - -
|
||||
✔ All specs passed! XX:XX 9 9 - - -
|
||||
|
||||
|
||||
`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
import './backgroundColor.css'
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
Cypress.Commands.add('mount', mount)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
describe('NewComponent', () => {
|
||||
it('renders the new component', () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
describe('TestComponent', () => {
|
||||
it('renders the test component', () => {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
Cypress.Commands.add('mount', mount)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
Cypress.Commands.add('mount', mount)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'tailwindcss/tailwind.css'
|
||||
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
declare global {
|
||||
namespace Cypress {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
import { Button } from './button'
|
||||
|
||||
it('works', () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
import { Button } from './button'
|
||||
|
||||
it('works', () => {
|
||||
|
||||
@@ -19,7 +19,7 @@ import './commands'
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
Cypress.Commands.add('mount', mount)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
// Augment the Cypress namespace to include type definitions for
|
||||
// your custom command.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
import App from './App.tsx'
|
||||
|
||||
it('works', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
import './backgroundColor.css'
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import React from 'react'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
function App () {
|
||||
return <h1>Hello world</h1>
|
||||
}
|
||||
|
||||
describe('using legacy mount', () => {
|
||||
it('issues a warning encouraging user to update', () => {
|
||||
// dont log else we create an endless loop!
|
||||
const log = cy.spy(Cypress, 'log').log(false)
|
||||
const err = cy.spy(console, 'error')
|
||||
|
||||
mount(<App />).get('h1').contains('Hello world')
|
||||
.then(() => {
|
||||
const msg = '[cypress/react]: You are using `cypress/react`, which is designed for React <= 17. Consider changing to `cypress/react18`, which is designed for React 18.'
|
||||
const warning = log.getCalls().find((call) => call.args[0].name === 'warning')
|
||||
|
||||
expect(warning.lastArg.message).to.eq(msg)
|
||||
expect(err).to.have.been.calledWith(msg)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
export const App = () => {
|
||||
return (
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
Cypress.Commands.add('mount', mount)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
describe('webpack-dev-server', () => {
|
||||
it('image with relative path should load', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import { App } from './App'
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
it('renders hello world', () => {
|
||||
mount(<App />)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import { App } from './App'
|
||||
import { mount } from 'cypress/react18'
|
||||
import { mount } from 'cypress/react'
|
||||
|
||||
it('renders hello world', () => {
|
||||
mount(<App />)
|
||||
|
||||
@@ -47,7 +47,7 @@ describe(`React major versions with Vite`, function () {
|
||||
return systemTests.exec(this, {
|
||||
project: `react${majorVersion}`,
|
||||
configFile: 'cypress-vite-default.config.ts',
|
||||
spec: 'src/App.cy.jsx,src/Unmount.cy.jsx,src/UsingLegacyMount.cy.jsx,src/Rerendering.cy.jsx,src/mount.cy.jsx',
|
||||
spec: 'src/App.cy.jsx,src/Unmount.cy.jsx,src/Rerendering.cy.jsx,src/mount.cy.jsx',
|
||||
testingType: 'component',
|
||||
browser: 'chrome',
|
||||
snapshot: true,
|
||||
@@ -65,7 +65,7 @@ describe(`React major versions with Webpack`, function () {
|
||||
return systemTests.exec(this, {
|
||||
project: `react${majorVersion}`,
|
||||
configFile: 'cypress-webpack.config.ts',
|
||||
spec: 'src/App.cy.jsx,src/Unmount.cy.jsx,src/UsingLegacyMount.cy.jsx,src/Rerendering.cy.jsx,src/mount.cy.jsx',
|
||||
spec: 'src/App.cy.jsx,src/Unmount.cy.jsx,src/Rerendering.cy.jsx,src/mount.cy.jsx',
|
||||
testingType: 'component',
|
||||
browser: 'chrome',
|
||||
snapshot: true,
|
||||
|
||||
217
yarn.lock
217
yarn.lock
@@ -1562,10 +1562,10 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.6", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878"
|
||||
integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==
|
||||
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz#9cbdd63a9443a2c92a725cca7ebca12cc8dd9f46"
|
||||
integrity sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==
|
||||
|
||||
"@babel/helper-remap-async-to-generator@^7.24.7", "@babel/helper-remap-async-to-generator@^7.25.0":
|
||||
version "7.25.0"
|
||||
@@ -2229,19 +2229,19 @@
|
||||
dependencies:
|
||||
"@babel/plugin-transform-react-jsx" "^7.24.7"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-self@^7.24.5":
|
||||
version "7.24.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.6.tgz#4fa4870d594d6840d724d2006d0f98b19be6f502"
|
||||
integrity sha512-FfZfHXtQ5jYPQsCRyLpOv2GeLIIJhs8aydpNh39vRDjhD411XcfWDni5i7OjP/Rs8GAtTn7sWFFELJSHqkIxYg==
|
||||
"@babel/plugin-transform-react-jsx-self@^7.24.7":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz#c0b6cae9c1b73967f7f9eb2fca9536ba2fad2858"
|
||||
integrity sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.24.6"
|
||||
"@babel/helper-plugin-utils" "^7.25.9"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-source@^7.24.1":
|
||||
version "7.24.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.6.tgz#4e1503f24ca5fccb1fc7f20c57426899d5ce5c1f"
|
||||
integrity sha512-BQTBCXmFRreU3oTUXcGKuPOfXAGb1liNY4AvvFKsOBAJ89RKcTsIrSsnMYkj59fNa66OFKnSa4AJZfy5Y4B9WA==
|
||||
"@babel/plugin-transform-react-jsx-source@^7.24.7":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz#4c6b8daa520b5f155b5fb55547d7c9fa91417503"
|
||||
integrity sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.24.6"
|
||||
"@babel/helper-plugin-utils" "^7.25.9"
|
||||
|
||||
"@babel/plugin-transform-react-jsx@^7.0.0", "@babel/plugin-transform-react-jsx@^7.24.7":
|
||||
version "7.25.2"
|
||||
@@ -6231,10 +6231,10 @@
|
||||
tslib "^2.0.0"
|
||||
warning "^4.0.3"
|
||||
|
||||
"@remix-run/router@1.5.0":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.5.0.tgz#57618e57942a5f0131374a9fdb0167e25a117fdc"
|
||||
integrity sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==
|
||||
"@remix-run/router@1.21.0":
|
||||
version "1.21.0"
|
||||
resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.21.0.tgz#c65ae4262bdcfe415dbd4f64ec87676e4a56e2b5"
|
||||
integrity sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==
|
||||
|
||||
"@rollup/plugin-commonjs@^17.1.0":
|
||||
version "17.1.0"
|
||||
@@ -8195,13 +8195,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
|
||||
integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
|
||||
|
||||
"@types/react-dom@17.0.25":
|
||||
version "17.0.25"
|
||||
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.25.tgz#e0e5b3571e1069625b3a3da2b279379aa33a0cb5"
|
||||
integrity sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==
|
||||
dependencies:
|
||||
"@types/react" "^17"
|
||||
|
||||
"@types/react-dom@18.3.1":
|
||||
version "18.3.1"
|
||||
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz#1e4654c08a9cdcfb6594c780ac59b55aad42fe07"
|
||||
@@ -8217,15 +8210,6 @@
|
||||
"@types/prop-types" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/react@17.0.83", "@types/react@^17":
|
||||
version "17.0.83"
|
||||
resolved "https://registry.npmjs.org/@types/react/-/react-17.0.83.tgz#b477c56387b74279281149dcf5ba2a1e2216d131"
|
||||
integrity sha512-l0m4ArKJvmFtR4e8UmKrj1pB4tUgOhJITf+mADyF/p69Ts1YAR/E+G9XEM0mHXKVRa1dQNHseyyDNzeuAXfXQw==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "^0.16"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/react@^16":
|
||||
version "16.14.62"
|
||||
resolved "https://registry.npmjs.org/@types/react/-/react-16.14.62.tgz#449e4e81caaf132d0c2c390644e577702db1dd9e"
|
||||
@@ -8295,12 +8279,7 @@
|
||||
resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff"
|
||||
integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==
|
||||
|
||||
"@types/semver@7.5.0":
|
||||
version "7.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a"
|
||||
integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==
|
||||
|
||||
"@types/semver@^7.5.0":
|
||||
"@types/semver@7.5.8", "@types/semver@^7.5.0":
|
||||
version "7.5.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
|
||||
integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
|
||||
@@ -8770,14 +8749,14 @@
|
||||
regenerator-runtime "^0.14.1"
|
||||
systemjs "^6.15.1"
|
||||
|
||||
"@vitejs/plugin-react@4.3.0":
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.0.tgz#f20ec2369a92d8abaaefa60da8b7157819d20481"
|
||||
integrity sha512-KcEbMsn4Dpk+LIbHMj7gDPRKaTMStxxWRkRmxsg/jVdFdJCZWt1SchZcf0M4t8lIKdwwMsEyzhrcOXRrDPtOBw==
|
||||
"@vitejs/plugin-react@4.3.3":
|
||||
version "4.3.3"
|
||||
resolved "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.3.tgz#28301ac6d7aaf20b73a418ee5c65b05519b4836c"
|
||||
integrity sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==
|
||||
dependencies:
|
||||
"@babel/core" "^7.24.5"
|
||||
"@babel/plugin-transform-react-jsx-self" "^7.24.5"
|
||||
"@babel/plugin-transform-react-jsx-source" "^7.24.1"
|
||||
"@babel/core" "^7.25.2"
|
||||
"@babel/plugin-transform-react-jsx-self" "^7.24.7"
|
||||
"@babel/plugin-transform-react-jsx-source" "^7.24.7"
|
||||
"@types/babel__core" "^7.20.5"
|
||||
react-refresh "^0.14.2"
|
||||
|
||||
@@ -10624,7 +10603,7 @@ axios@0.21.2:
|
||||
dependencies:
|
||||
follow-redirects "^1.14.0"
|
||||
|
||||
axios@^1.7.4:
|
||||
axios@1.7.7, axios@^1.7.4:
|
||||
version "1.7.7"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f"
|
||||
integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==
|
||||
@@ -22513,7 +22492,7 @@ mobx@6.13.5:
|
||||
resolved "https://registry.npmjs.org/mobx/-/mobx-6.13.5.tgz#957d9df88c7f8b4baa7c6f8bdcb6d68b432a6ed5"
|
||||
integrity sha512-/HTWzW2s8J1Gqt+WmUj5Y0mddZk+LInejADc79NJadrWla3rHzmRHki/mnEUH1AvOmbNTZ1BRbKxr8DSgfdjMA==
|
||||
|
||||
"mocha-7.0.1@npm:mocha@7.0.1":
|
||||
"mocha-7.0.1@npm:mocha@7.0.1", mocha@7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.0.1.tgz#276186d35a4852f6249808c6dd4a1376cbf6c6ce"
|
||||
integrity sha512-9eWmWTdHLXh72rGrdZjNbG3aa1/3NRPpul1z0D979QpEnFdCG0Q5tv834N+94QEN2cysfV72YocQ3fn87s70fg==
|
||||
@@ -22630,36 +22609,6 @@ mocha@6.2.2:
|
||||
yargs-parser "13.1.1"
|
||||
yargs-unparser "1.6.0"
|
||||
|
||||
mocha@7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.0.1.tgz#276186d35a4852f6249808c6dd4a1376cbf6c6ce"
|
||||
integrity sha512-9eWmWTdHLXh72rGrdZjNbG3aa1/3NRPpul1z0D979QpEnFdCG0Q5tv834N+94QEN2cysfV72YocQ3fn87s70fg==
|
||||
dependencies:
|
||||
ansi-colors "3.2.3"
|
||||
browser-stdout "1.3.1"
|
||||
chokidar "3.3.0"
|
||||
debug "3.2.6"
|
||||
diff "3.5.0"
|
||||
escape-string-regexp "1.0.5"
|
||||
find-up "3.0.0"
|
||||
glob "7.1.3"
|
||||
growl "1.10.5"
|
||||
he "1.2.0"
|
||||
js-yaml "3.13.1"
|
||||
log-symbols "2.2.0"
|
||||
minimatch "3.0.4"
|
||||
mkdirp "0.5.1"
|
||||
ms "2.1.1"
|
||||
node-environment-flags "1.0.6"
|
||||
object.assign "4.1.0"
|
||||
strip-json-comments "2.0.1"
|
||||
supports-color "6.0.0"
|
||||
which "1.3.1"
|
||||
wide-align "1.1.3"
|
||||
yargs "13.3.0"
|
||||
yargs-parser "13.1.1"
|
||||
yargs-unparser "1.6.0"
|
||||
|
||||
mocha@7.1.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.1.0.tgz#c784f579ad0904d29229ad6cb1e2514e4db7d249"
|
||||
@@ -25908,7 +25857,7 @@ prop-types@15.7.2:
|
||||
object-assign "^4.1.1"
|
||||
react-is "^16.8.1"
|
||||
|
||||
prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
prop-types@15.8.1, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@@ -26335,25 +26284,6 @@ react-docgen@6.0.4:
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-dom@16.8.6:
|
||||
version "16.8.6"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f"
|
||||
integrity sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.2"
|
||||
scheduler "^0.13.6"
|
||||
|
||||
react-dom@17.0.2, react-dom@^17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
|
||||
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
scheduler "^0.20.2"
|
||||
|
||||
react-dom@18.3.1:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
|
||||
@@ -26423,20 +26353,20 @@ react-remove-scroll@^2.3.0:
|
||||
use-callback-ref "^1.2.3"
|
||||
use-sidecar "^1.0.1"
|
||||
|
||||
react-router-dom@6.10.0:
|
||||
version "6.10.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.10.0.tgz#090ddc5c84dc41b583ce08468c4007c84245f61f"
|
||||
integrity sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==
|
||||
react-router-dom@6.28.0:
|
||||
version "6.28.0"
|
||||
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.28.0.tgz#f73ebb3490e59ac9f299377062ad1d10a9f579e6"
|
||||
integrity sha512-kQ7Unsl5YdyOltsPGl31zOjLrDv+m2VcIEcIHqYYD3Lp0UppLjrzcfJqDJwXxFw3TH/yvapbnUvPlAj7Kx5nbg==
|
||||
dependencies:
|
||||
"@remix-run/router" "1.5.0"
|
||||
react-router "6.10.0"
|
||||
"@remix-run/router" "1.21.0"
|
||||
react-router "6.28.0"
|
||||
|
||||
react-router@6.10.0:
|
||||
version "6.10.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.10.0.tgz#230f824fde9dd0270781b5cb497912de32c0a971"
|
||||
integrity sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==
|
||||
react-router@6.28.0:
|
||||
version "6.28.0"
|
||||
resolved "https://registry.npmjs.org/react-router/-/react-router-6.28.0.tgz#29247c86d7ba901d7e5a13aa79a96723c3e59d0d"
|
||||
integrity sha512-HrYdIFqdrnhDw0PqG/AKjAqEqM7AvxCz0DQ4h2W8k6nqmc5uRBYDag0SBxx9iYz5G8gnuNVLzUe13wl9eAsXXg==
|
||||
dependencies:
|
||||
"@remix-run/router" "1.5.0"
|
||||
"@remix-run/router" "1.21.0"
|
||||
|
||||
react-style-singleton@^2.1.0:
|
||||
version "2.1.1"
|
||||
@@ -26457,24 +26387,6 @@ react-test-renderer@^16.0.0-0:
|
||||
react-is "^16.8.6"
|
||||
scheduler "^0.19.1"
|
||||
|
||||
react@16.8.6:
|
||||
version "16.8.6"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"
|
||||
integrity sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.2"
|
||||
scheduler "^0.13.6"
|
||||
|
||||
react@17.0.2, react@^17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
|
||||
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
react@18.3.1:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
|
||||
@@ -27597,14 +27509,6 @@ sax@>=0.6.0, sax@^1.2.4:
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
scheduler@^0.13.6:
|
||||
version "0.13.6"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.6.tgz#466a4ec332467b31a91b9bf74e5347072e4cd889"
|
||||
integrity sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
scheduler@^0.19.1:
|
||||
version "0.19.1"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
|
||||
@@ -27613,14 +27517,6 @@ scheduler@^0.19.1:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
scheduler@^0.20.2:
|
||||
version "0.20.2"
|
||||
resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
|
||||
integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
scheduler@^0.23.2:
|
||||
version "0.23.2"
|
||||
resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
|
||||
@@ -29282,7 +29178,7 @@ string-template@~0.2.1:
|
||||
resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add"
|
||||
integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@@ -29308,15 +29204,6 @@ string-width@^1.0.1, string-width@^1.0.2:
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^3.0.0, string-width@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
|
||||
@@ -29427,7 +29314,7 @@ stringify-object@^3.0.0, stringify-object@^3.3.0:
|
||||
is-obj "^1.0.1"
|
||||
is-regexp "^1.0.0"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
@@ -29448,13 +29335,6 @@ strip-ansi@5.2.0, strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
|
||||
dependencies:
|
||||
ansi-regex "^4.1.0"
|
||||
|
||||
strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
|
||||
@@ -31785,7 +31665,7 @@ vite@5.2.11:
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.3"
|
||||
|
||||
vite@^5.0.0:
|
||||
vite@5.4.10, vite@^5.0.0:
|
||||
version "5.4.10"
|
||||
resolved "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz#d358a7bd8beda6cf0f3b7a450a8c7693a4f80c18"
|
||||
integrity sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==
|
||||
@@ -32459,7 +32339,7 @@ workerpool@6.2.0:
|
||||
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b"
|
||||
integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==
|
||||
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
@@ -32502,15 +32382,6 @@ wrap-ansi@^6.2.0:
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
dependencies:
|
||||
ansi-styles "^4.0.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^8.0.1, wrap-ansi@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
||||
|
||||
Reference in New Issue
Block a user