Skip to content

Commit 2587df3

Browse files
React 19 support (#3985)
* deprecate `IObserver` options and its properties in JSDoc * Preparing for React 19 - some tests fail * RTL hooks error * skipping legacy context tests * skipping propTypes and defaultProps forwarding tests * skipping class propTypes test * render time check * changed some assertions * added extra render * added todo * added warning for legacy context types in function components * added changeset --------- Co-authored-by: Michel Weststrate <[email protected]>
1 parent 9944edc commit 2587df3

16 files changed

+316
-203
lines changed

.changeset/unlucky-readers-nail.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"mobx-react-lite": minor
3+
"mobx-react": minor
4+
---
5+
6+
* Added React 19 support, fixes #3986

package.json

+3-4
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@
3535
"@changesets/cli": "^2.11.0",
3636
"@testing-library/dom": "^10.4.0",
3737
"@testing-library/jest-dom": "^5.16.4",
38-
"@testing-library/react": "^16.0.1",
39-
"@testing-library/react-hooks": "7.0.2",
38+
"@testing-library/react": "^16.1.0",
4039
"@types/jest": "^26.0.15",
4140
"@types/node": "18",
4241
"@types/prop-types": "^15.5.2",
@@ -62,8 +61,8 @@
6261
"prettier": "^2.8.4",
6362
"pretty-quick": "3.1.0",
6463
"prop-types": "15.6.2",
65-
"react": "^18.0.0",
66-
"react-dom": "^18.0.0",
64+
"react": "^19.0.0",
65+
"react-dom": "^19.0.0",
6766
"react-test-renderer": "^18.0.0",
6867
"serializr": "^2.0.3",
6968
"tape": "^5.0.1",

packages/mobx-react-lite/__tests__/observer.test.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function runTestSuite(mode: "observer" | "useObserver") {
4949
list: 0
5050
}
5151

52-
const TodoItem = obsComponent(({ todo }: { todo: typeof store.todos[0] }) => {
52+
const TodoItem = obsComponent(({ todo }: { todo: (typeof store.todos)[0] }) => {
5353
renderings.item++
5454
return <li>|{todo.title}</li>
5555
}, true)
@@ -997,7 +997,7 @@ it("dependencies should not become temporarily unobserved", async () => {
997997
expect(doubleDisposed).toBeCalledTimes(1)
998998
})
999999

1000-
it("Legacy context support", () => {
1000+
it.skip("Legacy context support", () => {
10011001
const contextKey = "key"
10021002
const contextValue = "value"
10031003

packages/mobx-react-lite/__tests__/useAsObservableSource.deprecated.test.tsx

+53-21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { act, cleanup, render } from "@testing-library/react"
2-
import { renderHook } from "@testing-library/react-hooks"
1+
import { act, cleanup, render, renderHook } from "@testing-library/react"
32
import { autorun, configure, observable } from "mobx"
43
import * as React from "react"
54
import { useEffect, useState } from "react"
@@ -81,7 +80,7 @@ describe("base useAsObservableSource should work", () => {
8180
})
8281
expect(container.querySelector("span")!.innerHTML).toBe("22")
8382
expect(counterRender).toBe(2)
84-
expect(observerRender).toBe(3)
83+
expect(observerRender).toBe(4)
8584
expect(consoleWarnMock).toMatchSnapshot()
8685
})
8786

@@ -288,29 +287,62 @@ describe("combining observer with props and stores", () => {
288287
describe("enforcing actions", () => {
289288
it("'never' should work", () => {
290289
configure({ enforceActions: "never" })
291-
const { result } = renderHook(() => {
292-
const [thing, setThing] = React.useState("world")
293-
useAsObservableSource({ hello: thing })
294-
useEffect(() => setThing("react"), [])
295-
})
296-
expect(result.error).not.toBeDefined()
290+
const onError = jest.fn()
291+
renderHook(
292+
() => {
293+
const [thing, setThing] = React.useState("world")
294+
useAsObservableSource({ hello: thing })
295+
useEffect(() => setThing("react"), [])
296+
},
297+
{
298+
wrapper: class extends React.Component<React.PropsWithChildren> {
299+
componentDidCatch = onError
300+
render() {
301+
return this.props.children
302+
}
303+
}
304+
}
305+
)
306+
expect(onError).not.toBeCalled()
297307
})
298308
it("only when 'observed' should work", () => {
299309
configure({ enforceActions: "observed" })
300-
const { result } = renderHook(() => {
301-
const [thing, setThing] = React.useState("world")
302-
useAsObservableSource({ hello: thing })
303-
useEffect(() => setThing("react"), [])
304-
})
305-
expect(result.error).not.toBeDefined()
310+
const onError = jest.fn()
311+
renderHook(
312+
() => {
313+
const [thing, setThing] = React.useState("world")
314+
useAsObservableSource({ hello: thing })
315+
useEffect(() => setThing("react"), [])
316+
},
317+
{
318+
wrapper: class extends React.Component<React.PropsWithChildren> {
319+
componentDidCatch = onError
320+
render() {
321+
return this.props.children
322+
}
323+
}
324+
}
325+
)
326+
expect(onError).not.toBeCalled()
306327
})
307328
it("'always' should work", () => {
308329
configure({ enforceActions: "always" })
309-
const { result } = renderHook(() => {
310-
const [thing, setThing] = React.useState("world")
311-
useAsObservableSource({ hello: thing })
312-
useEffect(() => setThing("react"), [])
313-
})
314-
expect(result.error).not.toBeDefined()
330+
const onError = jest.fn()
331+
renderHook(
332+
() => {
333+
const [thing, setThing] = React.useState("world")
334+
useAsObservableSource({ hello: thing })
335+
useEffect(() => setThing("react"), [])
336+
},
337+
{
338+
wrapper: class extends React.Component<React.PropsWithChildren> {
339+
componentDidCatch = onError
340+
render() {
341+
return this.props.children
342+
}
343+
}
344+
}
345+
)
346+
expect(onError).not.toBeCalled()
315347
})
316348
})

packages/mobx-react-lite/__tests__/useAsObservableSource.test.tsx

+52-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { act, cleanup, render } from "@testing-library/react"
2-
import { renderHook } from "@testing-library/react-hooks"
1+
import { act, cleanup, render, renderHook } from "@testing-library/react"
32
import mockConsole from "jest-mock-console"
43
import { autorun, configure, observable } from "mobx"
54
import * as React from "react"
@@ -351,30 +350,63 @@ describe("combining observer with props and stores", () => {
351350
describe("enforcing actions", () => {
352351
it("'never' should work", () => {
353352
configure({ enforceActions: "never" })
354-
const { result } = renderHook(() => {
355-
const [thing, setThing] = React.useState("world")
356-
useLocalObservable(() => ({ hello: thing }))
357-
useEffect(() => setThing("react"), [])
358-
})
359-
expect(result.error).not.toBeDefined()
353+
const onError = jest.fn()
354+
renderHook(
355+
() => {
356+
const [thing, setThing] = React.useState("world")
357+
useLocalObservable(() => ({ hello: thing }))
358+
useEffect(() => setThing("react"), [])
359+
},
360+
{
361+
wrapper: class extends React.Component<React.PropsWithChildren> {
362+
componentDidCatch = onError
363+
render() {
364+
return this.props.children
365+
}
366+
}
367+
}
368+
)
369+
expect(onError).not.toBeCalled()
360370
})
361371
it("only when 'observed' should work", () => {
362372
configure({ enforceActions: "observed" })
363-
const { result } = renderHook(() => {
364-
const [thing, setThing] = React.useState("world")
365-
useLocalObservable(() => ({ hello: thing }))
366-
useEffect(() => setThing("react"), [])
367-
})
368-
expect(result.error).not.toBeDefined()
373+
const onError = jest.fn()
374+
renderHook(
375+
() => {
376+
const [thing, setThing] = React.useState("world")
377+
useLocalObservable(() => ({ hello: thing }))
378+
useEffect(() => setThing("react"), [])
379+
},
380+
{
381+
wrapper: class extends React.Component<React.PropsWithChildren> {
382+
componentDidCatch = onError
383+
render() {
384+
return this.props.children
385+
}
386+
}
387+
}
388+
)
389+
expect(onError).not.toBeCalled()
369390
})
370391
it("'always' should work", () => {
371392
configure({ enforceActions: "always" })
372-
const { result } = renderHook(() => {
373-
const [thing, setThing] = React.useState("world")
374-
useLocalObservable(() => ({ hello: thing }))
375-
useEffect(() => setThing("react"), [])
376-
})
377-
expect(result.error).not.toBeDefined()
393+
const onError = jest.fn()
394+
renderHook(
395+
() => {
396+
const [thing, setThing] = React.useState("world")
397+
useLocalObservable(() => ({ hello: thing }))
398+
useEffect(() => setThing("react"), [])
399+
},
400+
{
401+
wrapper: class extends React.Component<React.PropsWithChildren> {
402+
componentDidCatch = onError
403+
render() {
404+
return this.props.children
405+
}
406+
}
407+
}
408+
)
409+
expect(onError).not.toBeCalled()
378410
})
379411
})
380412

0 commit comments

Comments
 (0)