diff --git a/package-lock.json b/package-lock.json index b11818400..5a2861815 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,9 +14,8 @@ }, "devDependencies": { "jest": "^26.0.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-test-renderer": "^18.2.0" + "react": "19.0.0-rc.1", + "react-dom": "19.0.0-rc.1" } }, "node_modules/@ampproject/remapping": { @@ -3802,17 +3801,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4143,15 +4131,6 @@ "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", "dev": true }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -4516,66 +4495,37 @@ "dev": true }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, + "version": "19.0.0-rc.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0-rc.1.tgz", + "integrity": "sha512-NZKln+uyPuyHchzP07I6GGYFxdAoaKhehgpCa3ltJGzwE31OYumLeshGaitA1R/fS5d9D2qpZVwTFAr6zCLM9w==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "19.0.0-rc.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0-rc.1.tgz", + "integrity": "sha512-k8MfDX+4G+eaa1cXXI9QF4d+pQtYol3nx8vauqRWUEOPqC7NQn2qmEqUsLoSd28rrZUL+R3T2VC+kZ2Hyx1geQ==", + "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "0.25.0-rc.1" }, "peerDependencies": { - "react": "^18.2.0" + "react": "19.0.0-rc.1" } }, + "node_modules/react-dom/node_modules/scheduler": { + "version": "0.25.0-rc.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-rc.1.tgz", + "integrity": "sha512-fVinv2lXqYpKConAMdergOl5owd0rY1O4P/QTe0aWKCqGtu7VsCt1iqQFxSJtqK4Lci/upVSBpGwVC7eWcuS9Q==", + "license": "MIT" + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, - "node_modules/react-shallow-renderer": { - "version": "16.15.0", - "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", - "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", - "dev": true, - "dependencies": { - "object-assign": "^4.1.1", - "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-test-renderer": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.2.0.tgz", - "integrity": "sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==", - "dev": true, - "dependencies": { - "react-is": "^18.2.0", - "react-shallow-renderer": "^16.15.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-test-renderer/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -5089,14 +5039,6 @@ "node": ">=10" } }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", diff --git a/package.json b/package.json index 6020ed48a..a9bd27f37 100644 --- a/package.json +++ b/package.json @@ -26,9 +26,8 @@ "homepage": "https://reasonml.github.io/reason-react/", "devDependencies": { "jest": "^26.0.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-test-renderer": "^18.2.0" + "react": "19.0.0-rc.1", + "react-dom": "19.0.0-rc.1" }, "jest": { "moduleDirectories": [ diff --git a/test/Form__test.re b/test/Form__test.re index 85593047b..2ea26d9c4 100644 --- a/test/Form__test.re +++ b/test/Form__test.re @@ -1,7 +1,4 @@ open Jest; -open Jest.Expect; -open ReactDOMTestUtils; -open Belt; module FormData = React.Experimental.FormData; @@ -25,7 +22,11 @@ module Thread = { let (optimisticMessages, addOptimisticMessage) = React.Experimental.useOptimistic(messages, (state, newMessage) => [ - {text: newMessage, sending: true, key: List.length(state) + 1}, + { + text: newMessage, + sending: true, + key: List.length(state) + 1, + }, ...state, ] ); @@ -49,24 +50,26 @@ module Thread = { }; }; <> - {{ - optimisticMessages->Belt.List.map(message => -
- {React.string(message.text)} - {message.sending - ? React.null - : {React.string("(Enviando...)")} } -
- ); - } - ->Belt.List.toArray - ->React.array} +
+ {{ + optimisticMessages->Belt.List.map(message => + + {React.string(message.text)} + {message.sending + ? React.null + : {React.string("(Enviando...)")} } + + ); + } + ->Belt.List.toArray + ->React.array} +
{React.cloneElement( ReactDOM.createElement( "form", ~props=ReactDOM.domProps(~ref=ReactDOM.Ref.domRef(formRef), ()), [| - , + , , |], ), @@ -84,7 +87,15 @@ module App = { [@react.component] let make = () => { let (messages, setMessages) = - React.useState(() => [{text: "¡Hola!", sending: false, key: 1}]); + React.useState(() => + [ + { + text: "Hola!", + sending: false, + key: 1, + }, + ] + ); let sendMessage = formData => { let formMessage = FormData.get("message", formData); @@ -95,7 +106,14 @@ module App = { | JSString(text) => let _ = setMessages(messages => - [{text, sending: true, key: 1}, ...messages] + [ + { + text, + sending: true, + key: 1, + }, + ...messages, + ] ); Js.Promise.resolve(); | _ => Js.Promise.resolve() @@ -108,46 +126,38 @@ module App = { }; }; -describe("Form with useOptimistic", () => { - let container = ref(None); - - beforeEach(prepareContainer(container)); - afterEach(cleanupContainer(container)); - - test("should render the form", () => { - let container = getContainer(container); - let root = ReactDOM.Client.createRoot(container); +let (let.await) = (p, f) => Js.Promise.then_(f, p); +let (let.catch) = (p, f) => Js.Promise.then_(f, p); - act(() => ReactDOM.Client.render(root, )); +let findByString = (text, container) => + ReactTestingLibrary.findByText(~matcher=`Str(text), container); - expect( - container - ->DOM.findBySelectorAndTextContent("button", "0") - ->Option.isSome, - ) - ->toBe(true); +let findByPlaceholderText = (text, container) => + ReactTestingLibrary.findByPlaceholderText(~matcher=`Str(text), container); - let button = container->DOM.findBySelector("button"); +describe("Form with useOptimistic", () => { + testPromise("should render the form", finish => { + let container = ReactTestingLibrary.render(); + + ReactTestingLibrary.actAsync(() => { + let.await _ = findByString("Hola!", container); + + let.await button = findByString("Enviar", container); + let.await input = findByPlaceholderText("message", container); + + FireEvent.change( + input, + ~eventInit={ + "target": { + "value": "Let's go!", + }, + }, + ); - act(() => { - switch (button) { - | Some(button) => Simulate.click(button) - | None => () - } + FireEvent.click(button); + let.await _newMessage = findByString("Let's go!", container); + /* If the promise resolve, means the node is found in the DOM */ + finish(); }); - - expect( - container - ->DOM.findBySelectorAndTextContent("button", "0") - ->Option.isSome, - ) - ->toBe(false); - - expect( - container - ->DOM.findBySelectorAndTextContent("button", "1") - ->Option.isSome, - ) - ->toBe(true); - }); + }) }); diff --git a/test/dune b/test/dune index fd66b7258..c444622f1 100644 --- a/test/dune +++ b/test/dune @@ -8,7 +8,7 @@ reason-react.node jest melange.belt - melange-testing-library.dom - melange-testing-library.react) + melange_testing_library_dom + melange_testing_library_react) (preprocess (pps melange.ppx reason-react-ppx))) diff --git a/test/jest/Jest.re b/test/jest/Jest.re index 3c9a6bc5f..fa3a29742 100644 --- a/test/jest/Jest.re +++ b/test/jest/Jest.re @@ -22,6 +22,25 @@ let testAsync: (~timeout: int=?, string, (unit => unit) => unit) => unit = (~timeout=?, name, f) => testAsyncU(name, callback => f(callback), timeout); +external testPromiseU: + ( + string, + (unit => Js.Promise.t(unit)) => Js.Promise.t(unit), + option(int) + ) => + unit = + "test"; + +let testPromise: + ( + ~timeout: int=?, + string, + (unit => Js.Promise.t(unit)) => Js.Promise.t(unit) + ) => + unit = + (~timeout=?, name, f) => + testPromiseU(name, callback => f(callback), timeout); + module Only = { [@mel.scope "describe"] external describeU: (string, (. unit) => unit) => unit = "only";