Skip to content

Commit 15c0396

Browse files
fix: (cy.prompt) ensure that we do not attach a vue ref to the react root in the cy.prompt modals (#32011)
* fix: (studio) ensure that we do not attach a vue ref to the react root in the studio panel * fix test
1 parent b8e0982 commit 15c0396

File tree

3 files changed

+41
-15
lines changed

3 files changed

+41
-15
lines changed

packages/app/src/prompt/PromptGetCodeModal.vue

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ const closeModal = () => {
4646
const container = ref<HTMLDivElement | null>(null)
4747
const error = ref<string | null>(null)
4848
const ReactGetCodeModalContents = ref<GetCodeModalContentsShape | null>(null)
49-
const reactRoot = ref<Root | null>(null)
49+
const containerReactRootMap = new WeakMap<HTMLElement, Root>()
5050
const promptStore = usePromptStore()
5151
5252
const maybeRenderReactComponent = () => {
53-
if (!ReactGetCodeModalContents.value || !!error.value) {
53+
if (!ReactGetCodeModalContents.value || !!error.value || !container.value) {
5454
return
5555
}
5656
@@ -63,19 +63,32 @@ const maybeRenderReactComponent = () => {
6363
},
6464
})
6565
66-
if (!reactRoot.value) {
67-
reactRoot.value = window.UnifiedRunner.ReactDOM.createRoot(container.value)
66+
// Store the react root in a weak map keyed by the container. We do this so that we have a reference
67+
// to it that's tied to the container value but absolutely do not want to use vue to do the tracking.
68+
// If vue tracks it (e.g. using a ref) it creates proxies that do not play nicely with React in
69+
// production
70+
let reactRoot = containerReactRootMap.get(container.value)
71+
72+
if (!reactRoot) {
73+
reactRoot = window.UnifiedRunner.ReactDOM.createRoot(container.value) as Root
74+
containerReactRootMap.set(container.value, reactRoot)
6875
}
6976
70-
reactRoot.value?.render(panel)
77+
reactRoot.render(panel)
7178
}
7279
7380
const unmountReactComponent = () => {
7481
if (!ReactGetCodeModalContents.value || !container.value) {
7582
return
7683
}
7784
78-
reactRoot.value?.unmount()
85+
const reactRoot = containerReactRootMap.get(container.value)
86+
87+
if (!reactRoot) {
88+
return
89+
}
90+
91+
reactRoot.unmount()
7992
}
8093
8194
onMounted(maybeRenderReactComponent)

packages/app/src/prompt/PromptMoreInfoNeededModal.vue

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ const closeModal = () => {
4646
const container = ref<HTMLDivElement | null>(null)
4747
const error = ref<string | null>(null)
4848
const ReactMoreInfoNeededModalContents = ref<MoreInfoNeededModalContentsShape | null>(null)
49-
const reactRoot = ref<Root | null>(null)
49+
const containerReactRootMap = new WeakMap<HTMLElement, Root>()
5050
const promptStore = usePromptStore()
5151
5252
const maybeRenderReactComponent = () => {
53-
if (!ReactMoreInfoNeededModalContents.value || !!error.value) {
53+
if (!ReactMoreInfoNeededModalContents.value || !!error.value || !container.value) {
5454
return
5555
}
5656
@@ -65,19 +65,32 @@ const maybeRenderReactComponent = () => {
6565
},
6666
})
6767
68-
if (!reactRoot.value) {
69-
reactRoot.value = window.UnifiedRunner.ReactDOM.createRoot(container.value)
68+
// Store the react root in a weak map keyed by the container. We do this so that we have a reference
69+
// to it that's tied to the container value but absolutely do not want to use vue to do the tracking.
70+
// If vue tracks it (e.g. using a ref) it creates proxies that do not play nicely with React in
71+
// production
72+
let reactRoot = containerReactRootMap.get(container.value)
73+
74+
if (!reactRoot) {
75+
reactRoot = window.UnifiedRunner.ReactDOM.createRoot(container.value) as Root
76+
containerReactRootMap.set(container.value, reactRoot)
7077
}
7178
72-
reactRoot.value?.render(panel)
79+
reactRoot.render(panel)
7380
}
7481
7582
const unmountReactComponent = () => {
7683
if (!ReactMoreInfoNeededModalContents.value || !container.value) {
7784
return
7885
}
7986
80-
reactRoot.value?.unmount()
87+
const reactRoot = containerReactRootMap.get(container.value)
88+
89+
if (!reactRoot) {
90+
return
91+
}
92+
93+
reactRoot.unmount()
8194
}
8295
8396
onMounted(maybeRenderReactComponent)

packages/driver/cypress/e2e/commands/prompt/prompt.cy.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ describe('src/cy/commands/prompt', () => {
1212
// TODO: add more tests when cy.prompt is built out, but for now this just
1313
// verifies that the command executes without throwing an error
1414
// @ts-expect-error - this will not error when we actually release the experimentalPromptCommand flag
15-
cy.prompt('Hello, world!')
15+
cy.prompt(['Hello, world!'])
1616

1717
cy.visit('http://www.barbaz.com:3500/fixtures/dom.html')
1818

1919
cy.origin('http://www.barbaz.com:3500', () => {
2020
// @ts-expect-error - this will not error when we actually release the experimentalPromptCommand flag
21-
cy.prompt('Hello, world!')
21+
cy.prompt(['Hello, world!'])
2222
})
2323
})
2424

@@ -37,6 +37,6 @@ describe('src/cy/commands/prompt', () => {
3737

3838
cy.visit('http://www.foobar.com:3500/fixtures/dom.html')
3939
// @ts-expect-error - this will not error when we actually release the experimentalPromptCommand flag
40-
cy.prompt('Hello, world!')
40+
cy.prompt(['Hello, world!'])
4141
})
4242
})

0 commit comments

Comments
 (0)