fix(app): guard reentrant Solid cleanup (#39261)

Co-authored-by: Jack <jack@anoma.ly>
This commit is contained in:
opencode-agent[bot] 2026-07-28 19:07:19 +08:00 committed by GitHub
commit be93cec9ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 210 additions and 10 deletions

View file

@ -0,0 +1,64 @@
import { expect, test } from "bun:test"
import { MetaProvider, Title } from "@solidjs/meta"
import { MemoryRouter, Route, createMemoryHistory, useParams } from "@solidjs/router"
import { createMemo } from "solid-js"
import { createComponent, render } from "solid-js/web"
test("route cleanup cannot invalidate an owner list being disposed", async () => {
const host = document.createElement("div")
document.body.append(host)
const history = createMemoryHistory()
const RepoPage = () => {
const params = useParams<{ id?: string }>()
const title = createMemo(() => params.id ?? "")
const button = document.createElement("button")
button.textContent = "Back"
button.addEventListener("click", () => history.set({ value: "/", scroll: false, replace: false }))
return [
createComponent(Title, {
get children() {
return title()
},
}),
button,
]
}
const HomePage = () => {
const button = document.createElement("button")
button.textContent = "Go"
button.addEventListener("click", () => history.set({ value: "/project", scroll: false, replace: false }))
return button
}
const App = () =>
createComponent(MetaProvider, {
get children() {
return createComponent(MemoryRouter, {
history,
get children() {
return [
createComponent(Route, { path: "/", component: HomePage }),
createComponent(Route, { path: "/:id", component: RepoPage }),
]
},
})
},
})
const dispose = render(() => createComponent(App, {}), host)
const go = host.querySelector("button")
expect(go?.textContent).toBe("Go")
go?.click()
await new Promise((resolve) => setTimeout(resolve, 0))
const back = host.querySelector("button")
expect(back?.textContent).toBe("Back")
back?.click()
await new Promise((resolve) => setTimeout(resolve, 0))
expect(host.querySelector("button")?.textContent).toBe("Go")
dispose()
host.remove()
})