Skip to content

Commit bd629d3

Browse files
author
Barthélémy Ledoux
authored
fix: avoid unmounting React components twice (#16280)
1 parent cd41077 commit bd629d3

File tree

2 files changed

+27
-21
lines changed

2 files changed

+27
-21
lines changed

npm/mount-utils/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ export function setupHooks (optionalCallback?: Function) {
200200
})
201201

202202
// @ts-ignore
203-
beforeEach(() => {
203+
Cypress.on('test:before:run', () => {
204204
optionalCallback?.()
205205
cleanupStyles()
206206
})

npm/react/src/mount.ts

+26-20
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ const injectStyles = (options: MountOptions) => {
4040
**/
4141
export const mount = (jsx: React.ReactNode, options: MountOptions = {}) => _mount('mount', jsx, options)
4242

43+
let lastMountedReactDom: (typeof ReactDOM) | undefined
44+
4345
/**
4446
* @see `mount`
4547
* @param type The type of mount executed
@@ -62,6 +64,8 @@ const _mount = (type: 'mount' | 'rerender', jsx: React.ReactNode, options: Mount
6264
.then(() => {
6365
const reactDomToUse = options.ReactDom || ReactDOM
6466

67+
lastMountedReactDom = reactDomToUse
68+
6569
const el = document.getElementById(ROOT_ID)
6670

6771
if (!el) {
@@ -153,21 +157,23 @@ const _unmount = (options: { boundComponentMessage?: string, log: boolean }) =>
153157
const selector = `#${ROOT_ID}`
154158

155159
return cy.get(selector, { log: false }).then(($el) => {
156-
const wasUnmounted = ReactDOM.unmountComponentAtNode($el[0])
157-
158-
if (wasUnmounted && options.log) {
159-
Cypress.log({
160-
name: 'unmount',
161-
type: 'parent',
162-
message: [options.boundComponentMessage ?? 'Unmounted component'],
163-
consoleProps: () => {
164-
return {
165-
description: 'Unmounts React component',
166-
parent: $el[0],
167-
home: 'https://github.com/cypress-io/cypress',
168-
}
169-
},
170-
})
160+
if (lastMountedReactDom) {
161+
const wasUnmounted = lastMountedReactDom.unmountComponentAtNode($el[0])
162+
163+
if (wasUnmounted && options.log) {
164+
Cypress.log({
165+
name: 'unmount',
166+
type: 'parent',
167+
message: [options.boundComponentMessage ?? 'Unmounted component'],
168+
consoleProps: () => {
169+
return {
170+
description: 'Unmounts React component',
171+
parent: $el[0],
172+
home: 'https://github.com/cypress-io/cypress',
173+
}
174+
},
175+
})
176+
}
171177
}
172178
})
173179
})
@@ -176,13 +182,13 @@ const _unmount = (options: { boundComponentMessage?: string, log: boolean }) =>
176182
// Cleanup before each run
177183
// NOTE: we cannot use unmount here because
178184
// we are not in the context of a test
179-
Cypress.on('test:before:run', () => {
185+
const preMountCleanup = () => {
180186
const el = document.getElementById(ROOT_ID)
181187

182-
if (el) {
183-
ReactDOM.unmountComponentAtNode(el)
188+
if (el && lastMountedReactDom) {
189+
lastMountedReactDom.unmountComponentAtNode(el)
184190
}
185-
})
191+
}
186192

187193
/**
188194
* Creates new instance of `mount` function with default options
@@ -317,4 +323,4 @@ export declare namespace Cypress {
317323
// it is required to unmount component in beforeEach hook in order to provide a clean state inside test
318324
// because `mount` can be called after some preparation that can side effect unmount
319325
// @see npm/react/cypress/component/advanced/set-timeout-example/loading-indicator-spec.js
320-
setupHooks(unmount)
326+
setupHooks(preMountCleanup)

0 commit comments

Comments
 (0)