From 4ad0c65b91d4ca5652207897acbf051cfe66c487 Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 4 May 2022 14:41:01 +1000 Subject: [PATCH 01/83] Upgrade to React 18.0.0 --- README.md | 2 +- bin/update_react_version | 8 ++++++-- doc/TESTING.md | 2 +- doc/USAGE.md | 10 +++++----- library/ghpages/html/dev2.html | 4 ++-- library/ghpages/html/dev3.html | 4 ++-- library/ghpages/html/prod.html | 4 ++-- library/project/Dependencies.scala | 2 +- 8 files changed, 20 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 94ac1ee97..c650e6743 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Includes a router, testing utils, performance utils, more. * [scastie](https://github.com/scalacenter/scastie) - An interactive playground for Scala [https://scastie.scala-lang.org](https://scastie.scala-lang.org) ##### Requirements: -* React ≥ 17 +* React ≥ 18 * Scala ≥ 2.13 * Scala.JS ≥ 1.10 diff --git a/bin/update_react_version b/bin/update_react_version index 42c330a2f..0e0322045 100755 --- a/bin/update_react_version +++ b/bin/update_react_version @@ -1,10 +1,14 @@ #!/bin/bash -cd "$(dirname "$0")/../library" || exit 1 +cd "$(dirname "$0")/.." || exit 1 [ $# -ne 1 ] && echo "Usage: $0 " && exit 1 ver="$1" perl -pi -e 's/(? "17.0.2", - "react-dom" -> "17.0.2") + "react" -> "18.0.0", + "react-dom" -> "18.0.0") ``` If you're using old-school `jsDependencies`, add something akin to: @@ -55,18 +55,18 @@ Setup // React JS itself (Note the filenames, adjust as needed, eg. to remove addons.) jsDependencies ++= Seq( - "org.webjars.npm" % "react" % "17.0.2" + "org.webjars.npm" % "react" % "18.0.0" / "umd/react.development.js" minified "umd/react.production.min.js" commonJSName "React", - "org.webjars.npm" % "react-dom" % "17.0.2" + "org.webjars.npm" % "react-dom" % "18.0.0" / "umd/react-dom.development.js" minified "umd/react-dom.production.min.js" dependsOn "umd/react.development.js" commonJSName "ReactDOM", - "org.webjars.npm" % "react-dom" % "17.0.2" + "org.webjars.npm" % "react-dom" % "18.0.0" / "umd/react-dom-server.browser.development.js" minified "umd/react-dom-server.browser.production.min.js" dependsOn "umd/react-dom.development.js" diff --git a/library/ghpages/html/dev2.html b/library/ghpages/html/dev2.html index 31ab646df..a4bff7bb9 100644 --- a/library/ghpages/html/dev2.html +++ b/library/ghpages/html/dev2.html @@ -3,8 +3,8 @@ - - + + diff --git a/library/ghpages/html/dev3.html b/library/ghpages/html/dev3.html index 719ecfd2e..0929b7f97 100644 --- a/library/ghpages/html/dev3.html +++ b/library/ghpages/html/dev3.html @@ -3,8 +3,8 @@ - - + + diff --git a/library/ghpages/html/prod.html b/library/ghpages/html/prod.html index e1605a900..6abfe4ade 100644 --- a/library/ghpages/html/prod.html +++ b/library/ghpages/html/prod.html @@ -3,8 +3,8 @@ - - + + diff --git a/library/project/Dependencies.scala b/library/project/Dependencies.scala index 46ab36677..e86de4be1 100644 --- a/library/project/Dependencies.scala +++ b/library/project/Dependencies.scala @@ -26,7 +26,7 @@ object Dependencies { val kindProjector = "0.13.2" val macrotaskExecutor = "1.0.0" val nyaya = "1.0.0" - val reactJs = "17.0.2" + val reactJs = "18.0.0" val scalaJsJavaTime = "1.0.0" val scalaJsSecureRandom = "1.0.0" val scalaTest = "3.2.11" From 3ecdcb648a17e4038178426ac45a0d0e60d63477 Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 4 May 2022 14:41:42 +1000 Subject: [PATCH 02/83] Upgrade Scalajs to 1.10.0 --- doc/changelog/2.2.0.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 doc/changelog/2.2.0.md diff --git a/doc/changelog/2.2.0.md b/doc/changelog/2.2.0.md new file mode 100644 index 000000000..a9e876d9f --- /dev/null +++ b/doc/changelog/2.2.0.md @@ -0,0 +1,3 @@ +# 2.2.0 + +* Scala.js upgraded to 1.10.0 From 0bde31a078f0be71262cb50bf2da3d1c665b2645 Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 4 May 2022 14:44:36 +1000 Subject: [PATCH 03/83] Upgrade microlibs to 4.1.0 Closes #1052 --- doc/changelog/2.2.0.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog/2.2.0.md b/doc/changelog/2.2.0.md index a9e876d9f..d4ffec1a4 100644 --- a/doc/changelog/2.2.0.md +++ b/doc/changelog/2.2.0.md @@ -1,3 +1,5 @@ # 2.2.0 + * Scala.js upgraded to 1.10.0 +* microlibs upgraded to 4.1.0 From b05183a9ace68753331e99d50b1ac2f9402371e6 Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 4 May 2022 14:48:14 +1000 Subject: [PATCH 04/83] Upgrade Scalafix and co --- library/scalafix.sbt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/scalafix.sbt b/library/scalafix.sbt index a1100c70c..fbe1c58c3 100644 --- a/library/scalafix.sbt +++ b/library/scalafix.sbt @@ -9,9 +9,3 @@ ThisBuild / semanticdbEnabled := true // NOTE: Upgrade downstream-tests/scalafix.sbt too! ThisBuild / semanticdbVersion := "4.5.9" - -ThisBuild / scalafixScalaBinaryVersion := "2.13" - -ThisBuild / scalafixDependencies ++= Seq( - "com.github.liancheng" %% "organize-imports" % "0.6.0" -) From 49eed7da8085cc20e0b2247da9691f749fb73573 Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 11 May 2022 10:26:47 +1000 Subject: [PATCH 05/83] Add a doc symlink for DX --- library/doc | 1 + 1 file changed, 1 insertion(+) create mode 120000 library/doc diff --git a/library/doc b/library/doc new file mode 120000 index 000000000..6af34c9a8 --- /dev/null +++ b/library/doc @@ -0,0 +1 @@ +../doc \ No newline at end of file From 4b813a70ae8a96892609e0369247ac6d46e8101c Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 11 May 2022 10:27:38 +1000 Subject: [PATCH 06/83] Add setting required to make React 18.0.0 work from sbt --- doc/USAGE.md | 7 +++++-- library/project/Dependencies.scala | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/USAGE.md b/doc/USAGE.md index a5a96462c..051b5aecd 100644 --- a/doc/USAGE.md +++ b/doc/USAGE.md @@ -49,7 +49,7 @@ Setup "react-dom" -> "18.0.0") ``` - If you're using old-school `jsDependencies`, add something akin to: + If you're using `jsDependencies`, add the following: ```scala // React JS itself (Note the filenames, adjust as needed, eg. to remove addons.) @@ -70,7 +70,10 @@ Setup / "umd/react-dom-server.browser.development.js" minified "umd/react-dom-server.browser.production.min.js" dependsOn "umd/react-dom.development.js" - commonJSName "ReactDOMServer"), + commonJSName "ReactDOMServer", + ), + + dependencyOverrides += "org.webjars.npm" % "scheduler" % "0.22.0", // Required for React 18.0.0 ``` [See here](IDE.md) for tips on configuring your IDE. diff --git a/library/project/Dependencies.scala b/library/project/Dependencies.scala index e86de4be1..d72bc5d2b 100644 --- a/library/project/Dependencies.scala +++ b/library/project/Dependencies.scala @@ -85,6 +85,7 @@ object Dependencies { Dep.scalaJsDom.value, Dep.univEq.value, Dep.univEqCats.value, + "org.webjars.npm" % "scheduler" % "0.22.0", // Required for React 18.0.0 )) def addReactJsDependencies(scope: Configuration): Project => Project = From 7c8203e07db1293a6ab5d730fcd20c83d851edf7 Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 11 May 2022 11:06:37 +1000 Subject: [PATCH 07/83] Upgrade `ReactDOM` for React 18 --- library/TODO.md | 6 ++ .../scalajs/react/vdom/VdomNode.scala | 1 + .../scalajs/react/vdom/VdomNode.scala | 1 + .../japgolly/scalajs/react/ReactDOM.scala | 101 +++++++++++++----- .../japgolly/scalajs/react/ReactOptions.scala | 40 +++++++ .../japgolly/scalajs/react/ReactRoot.scala | 18 ++++ .../scalajs/react/component/Generic.scala | 1 + .../scalajs/react/component/JsFn.scala | 1 + .../react/component/JsForwardRef.scala | 1 + .../scalajs/react/facade/React18.scala | 71 ++++++++++++ .../scalajs/react/facade/ReactDOM.scala | 13 ++- .../src/main/scala/ghpages/GhPages.scala | 3 +- 12 files changed, 224 insertions(+), 33 deletions(-) create mode 100644 library/TODO.md create mode 100644 library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactOptions.scala create mode 100644 library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactRoot.scala create mode 100644 library/facadeMain/src/main/scala/japgolly/scalajs/react/facade/React18.scala diff --git a/library/TODO.md b/library/TODO.md new file mode 100644 index 000000000..332d9895f --- /dev/null +++ b/library/TODO.md @@ -0,0 +1,6 @@ +* Test that `ReactRoot.render` works for: + * VdomNode + * VdomElement + * Generic + * JsFn + * JsForwardRef diff --git a/library/coreGeneric/src/main/scala-2/japgolly/scalajs/react/vdom/VdomNode.scala b/library/coreGeneric/src/main/scala-2/japgolly/scalajs/react/vdom/VdomNode.scala index c1dbdb8be..f3b0a946e 100644 --- a/library/coreGeneric/src/main/scala-2/japgolly/scalajs/react/vdom/VdomNode.scala +++ b/library/coreGeneric/src/main/scala-2/japgolly/scalajs/react/vdom/VdomNode.scala @@ -10,6 +10,7 @@ trait VdomNode extends TagMod { override def applyTo(b: VdomBuilder): Unit = b.appendChild(rawNode) + @deprecated("Use ReactDOM.createRoot and root.render instead", "2.2.0 / React v18") @inline final def renderIntoDOM(container: facade.ReactDOM.Container): facade.React.ComponentUntyped = facade.ReactDOM.render(rawNode, container) diff --git a/library/coreGeneric/src/main/scala-3/japgolly/scalajs/react/vdom/VdomNode.scala b/library/coreGeneric/src/main/scala-3/japgolly/scalajs/react/vdom/VdomNode.scala index 7938f5083..3c17b64bc 100644 --- a/library/coreGeneric/src/main/scala-3/japgolly/scalajs/react/vdom/VdomNode.scala +++ b/library/coreGeneric/src/main/scala-3/japgolly/scalajs/react/vdom/VdomNode.scala @@ -10,6 +10,7 @@ trait VdomNode extends TagMod { override def applyTo(b: VdomBuilder): Unit = b.appendChild(rawNode) + @deprecated("Use ReactDOM.createRoot and root.render instead", "2.2.0 / React v18") inline final def renderIntoDOM(container: facade.ReactDOM.Container): facade.React.ComponentUntyped = facade.ReactDOM.render(rawNode, container) diff --git a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactDOM.scala b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactDOM.scala index 8bf99a881..5577ecf19 100644 --- a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactDOM.scala +++ b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactDOM.scala @@ -1,5 +1,6 @@ package japgolly.scalajs.react +import japgolly.scalajs.react.facade.ReactDOM.Container import japgolly.scalajs.react.util.Effect._ import japgolly.scalajs.react.util.NotAllowed import japgolly.scalajs.react.vdom.VdomNode @@ -7,29 +8,52 @@ import org.scalajs.dom import scala.scalajs.js.| object ReactDOM { - def raw = facade.ReactDOM - def version = facade.ReactDOM.version + @inline def raw = facade.ReactDOM + @inline def version = facade.ReactDOM.version + + /** Create a React root for the supplied container and return the root. The root can be used to render a React element + * into the DOM with `.render`. + * + * @since v2.2.0 / React v18 + */ + def createRoot(container: Container): ReactRoot = + ReactRoot(raw.createRoot(container)) + + /** Create a React root for the supplied container and return the root. The root can be used to render a React element + * into the DOM with `.render`. + * + * @since v2.2.0 / React v18 + */ + def createRoot(container: Container, options: ReactOptions.CreateRoot): ReactRoot = + ReactRoot(raw.createRoot(container, options.raw())) /** For mounted components, use .getDOMNode */ def findDOMNode(componentOrElement: dom.Element | facade.React.ComponentUntyped): Option[ComponentDom.Mounted] = ComponentDom.findDOMNode(componentOrElement).mounted - def hydrate(element : VdomNode, - container: facade.ReactDOM.Container): facade.React.ComponentUntyped = - facade.ReactDOM.hydrate(element.rawNode, container) + def flushSync[F[_], A](fa: F[A])(implicit F: Sync[F]): F[A] = + F.delay(facade.ReactDOM.flushSync(F.toJsFn(fa))) def hydrate[G[_]](element : VdomNode, - container: facade.ReactDOM.Container, + container: Container, callback : => G[Unit])(implicit G: Dispatch[G]): facade.React.ComponentUntyped = facade.ReactDOM.hydrate(element.rawNode, container, G.dispatchFn(callback)) - /** Hydrate the container if is has children, else render into that container. */ - def hydrateOrRender(element : VdomNode, - container: dom.Element): facade.React.ComponentUntyped = - if (container.hasChildNodes()) - hydrate(element, container) - else - element.renderIntoDOM(container) + /** Same as [[createRoot()]], but is used to hydrate a container whose HTML contents were rendered by + * [[ReactDOMServer]]. React will attempt to attach event listeners to the existing markup. + * + * @since v2.2.0 / React v18 + */ + def hydrateRoot(container: Container, element: VdomNode): ReactRoot = + ReactRoot(raw.hydrateRoot(container, element.rawNode)) + + /** Same as [[createRoot()]], but is used to hydrate a container whose HTML contents were rendered by + * [[ReactDOMServer]]. React will attempt to attach event listeners to the existing markup. + * + * @since v2.2.0 / React v18 + */ + def hydrateRoot(container: Container, element: VdomNode, options: ReactOptions.HydrateRoot): ReactRoot = + ReactRoot(raw.hydrateRoot(container, element.rawNode, options.raw())) /** Hydrate the container if is has children, else render into that container. */ def hydrateOrRender[G[_]](element : VdomNode, @@ -40,25 +64,44 @@ object ReactDOM { else element.renderIntoDOM(container, callback) - def unmountComponentAtNode(container: dom.Node): Boolean = - raw.unmountComponentAtNode(container) - - // .hydrate is not here because currently, SSR with scalajs-react isn't directly supported. - // .raw.hydrate can be used if needed. + /** Hydrate the container if is has children, else render into that container. */ + def hydrateOrRenderIntoNewRoot(container : dom.Element, + element : VdomNode, + creationOptions : ReactOptions.CreateRoot = ReactOptions.CreateRoot(), + hydrationOptions: ReactOptions.HydrateRoot = ReactOptions.HydrateRoot(), + ): ReactRoot = + if (container.hasChildNodes()) + hydrateRoot(container, element, hydrationOptions) + else { + val root = createRoot(container, creationOptions) + root.render(element) + root + } - // There are three ways of providing this functionality: - // 1. ReactDOM.render here (problem: lose return type precision) - // 2. ReactDOM.render{Js,Scala,Vdom,etc} - // 3. Add .renderIntoDOM to mountable types (current solution) - @deprecated("Use .renderIntoDOM on unmounted components.", "") - def render(element : NotAllowed, - container: Any, - callback : Any = null) = element.result + // =================================================================================================================== + // Deprecated stuff @deprecated("Import vdom and use ReactPortal()", "") def createPortal(child: NotAllowed, container: Any) = child.result - def flushSync[F[_], A](fa: F[A])(implicit F: Sync[F]): F[A] = - F.delay(facade.ReactDOM.flushSync(F.toJsFn(fa))) + @deprecated("Use hydrateRoot instead", "2.2.0 / React v18") + def hydrate(element: VdomNode, container: Container): facade.React.ComponentUntyped = + facade.ReactDOM.hydrate(element.rawNode, container) -} \ No newline at end of file + /** Hydrate the container if is has children, else render into that container. */ + @deprecated("Use hydrateOrRenderIntoNewRoot instead", "2.2.0 / React v18") + def hydrateOrRender(element: VdomNode, container: dom.Element): facade.React.ComponentUntyped = + if (container.hasChildNodes()) + hydrate(element, container) + else + element.renderIntoDOM(container) + + @deprecated("Use createRoot and root.render instead", "2.2.0 / React v18") + def render(element : NotAllowed, + container: Any, + callback : Any = null) = element.result + + @deprecated("Use root.unmount() instead", "2.2.0 / React v18") + def unmountComponentAtNode(container: dom.Node): Boolean = + raw.unmountComponentAtNode(container) +} diff --git a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactOptions.scala b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactOptions.scala new file mode 100644 index 000000000..06d425791 --- /dev/null +++ b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactOptions.scala @@ -0,0 +1,40 @@ +package japgolly.scalajs.react + +import scala.scalajs.js + +/** Classes for specifying options for React. */ +object ReactOptions { + + /** Options for [[ReactDOM.createRoot()]]. */ + final case class CreateRoot(identifierPrefix : js.UndefOr[String ] = js.undefined, + onRecoverableError : js.UndefOr[Any => Unit] = js.undefined, + unstable_concurrentUpdatesByDefault: js.UndefOr[Boolean ] = js.undefined, + unstable_strictMode : js.UndefOr[Boolean ] = js.undefined, + ) { self => + def raw(): facade.CreateRootOptions = { + val o = js.Dynamic.literal().asInstanceOf[facade.CreateRootOptions] + o.identifierPrefix = self.identifierPrefix + o.onRecoverableError = self.onRecoverableError + o.unstable_concurrentUpdatesByDefault = self.unstable_concurrentUpdatesByDefault + o.unstable_strictMode = self.unstable_strictMode + o + } + } + + /** Options for [[ReactDOM.hydrateRoot()]]. */ + final case class HydrateRoot(identifierPrefix : js.UndefOr[String ] = js.undefined, + onRecoverableError : js.UndefOr[Any => Unit] = js.undefined, + unstable_concurrentUpdatesByDefault: js.UndefOr[Boolean ] = js.undefined, + unstable_strictMode : js.UndefOr[Boolean ] = js.undefined, + ) { self => + def raw(): facade.HydrateRootOptions = { + val o = js.Dynamic.literal().asInstanceOf[facade.HydrateRootOptions] + o.identifierPrefix = self.identifierPrefix + o.onRecoverableError = self.onRecoverableError + o.unstable_concurrentUpdatesByDefault = self.unstable_concurrentUpdatesByDefault + o.unstable_strictMode = self.unstable_strictMode + o + } + } + +} diff --git a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactRoot.scala b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactRoot.scala new file mode 100644 index 000000000..57eecfdd7 --- /dev/null +++ b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactRoot.scala @@ -0,0 +1,18 @@ +package japgolly.scalajs.react + +import japgolly.scalajs.react.vdom.VdomNode + +/** A location in the DOM into which React has initialised itself, and now manages. + * + * Can be used to render a React element into the DOM with `.render`. + * + * @since v2.2.0 / React 18 + */ +@inline final case class ReactRoot(raw: facade.RootType) { + + @inline def render(element: VdomNode): Unit = + raw.render(element.rawNode) + + @inline def unmount(): Unit = + raw.unmount() +} diff --git a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/component/Generic.scala b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/component/Generic.scala index 901a02552..055a31d97 100644 --- a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/component/Generic.scala +++ b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/component/Generic.scala @@ -95,6 +95,7 @@ object Generic { final def mountRawOrNull(c: facade.React.ComponentUntyped | Null): M = if (c == null) null.asInstanceOf[M] else mountRaw(JsUtil.notNull(c)) + @deprecated("Use ReactDOM.createRoot and root.render instead", "2.2.0 / React v18") def renderIntoDOM(container: facade.ReactDOM.Container): Mounted = mountRaw(facade.ReactDOM.render(raw, container)) diff --git a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/component/JsFn.scala b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/component/JsFn.scala index 94c44c62a..ce49218dc 100644 --- a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/component/JsFn.scala +++ b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/component/JsFn.scala @@ -118,6 +118,7 @@ object JsFn extends JsBaseComponentTemplate[facade.React.StatelessFunctionalComp override def mapUnmountedProps[P2](f: P => P2): UnmountedSimple[P2, M] override def mapMounted[M2](f: M => M2): UnmountedSimple[P, M2] + @deprecated("Use ReactDOM.createRoot and root.render instead", "2.2.0 / React v18") override final def renderIntoDOM(container: facade.ReactDOM.Container): this.Mounted = postRender(facade.ReactDOM.render(raw, container)) diff --git a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/component/JsForwardRef.scala b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/component/JsForwardRef.scala index d5e4db52a..a99962df9 100644 --- a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/component/JsForwardRef.scala +++ b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/component/JsForwardRef.scala @@ -140,6 +140,7 @@ object JsForwardRef { override def mapUnmountedProps[P2](f: P => P2): UnmountedSimple[P2, R, M] override def mapMounted[M2](f: M => M2): UnmountedSimple[P, R, M2] + @deprecated("Use ReactDOM.createRoot and root.render instead", "2.2.0 / React v18") override final def renderIntoDOM(container: facade.ReactDOM.Container): this.Mounted = postRender(facade.ReactDOM.render(raw, container)) diff --git a/library/facadeMain/src/main/scala/japgolly/scalajs/react/facade/React18.scala b/library/facadeMain/src/main/scala/japgolly/scalajs/react/facade/React18.scala new file mode 100644 index 000000000..7587e9369 --- /dev/null +++ b/library/facadeMain/src/main/scala/japgolly/scalajs/react/facade/React18.scala @@ -0,0 +1,71 @@ +package japgolly.scalajs.react.facade + +import scala.annotation.nowarn +import scala.scalajs.js + +@js.native +@nowarn("cat=unused") +trait ReactDOM18 extends js.Object { + + /** Create a React root for the supplied container and return the root. The root can be used to render a React element into the DOM with `.render`. */ + final def createRoot(container: ReactDOM.Container, options: CreateRootOptions = js.native): RootType = js.native + + /** Same as createRoot(), but is used to hydrate a container whose HTML contents were rendered by ReactDOMServer. React will attempt to attach event listeners to the existing markup. */ + final def hydrateRoot(container: ReactDOM.Container, element: React.Node, options: HydrateRootOptions = js.native): RootType = js.native +} + +@js.native +@nowarn("cat=unused") +trait RootType extends js.Object { + def render(element: React.Node): Unit = js.native + def unmount(): Unit = js.native +} + +@js.native +trait CreateRootOptions extends js.Object { + var identifierPrefix : js.UndefOr[String] + var onRecoverableError : js.UndefOr[Any => Unit] + var unstable_concurrentUpdatesByDefault: js.UndefOr[Boolean] + var unstable_strictMode : js.UndefOr[Boolean] + // var transitionCallbacks : js.UndefOr[TransitionTracingCallbacks] +} + +@js.native +trait HydrateRootOptions extends js.Object { + var identifierPrefix : js.UndefOr[String] + var onRecoverableError : js.UndefOr[Any => Unit] + var unstable_concurrentUpdatesByDefault: js.UndefOr[Boolean] + var unstable_strictMode : js.UndefOr[Boolean] + // var hydratedSources : js.UndefOr[Array[MutableSource[any]]] + // var onHydrated : js.UndefOr[Comment => Unit] + // var onDeleted : js.UndefOr[Comment => Unit] +} + +// @js.native +// trait RecoverableError extends js.Object { +// val message: String +// } + +// @js.native +// trait TransitionTracingCallbacks extends js.Object { +// var onMarkerComplete : js.UndefOr[(String, String, Double, Double) => Unit] +// var onMarkerIncomplete : js.UndefOr[(String, String, Double, Array[Deletions]) => Unit] +// var onMarkerProgress : js.UndefOr[(String, String, Double, Double, Array[HasName]) => Unit] +// var onTransitionComplete : js.UndefOr[(String, Double, Double) => Unit] +// var onTransitionIncomplete: js.UndefOr[(String, Double, Array[Deletions]) => Unit] +// var onTransitionProgress : js.UndefOr[(String, Double, Double, Array[HasName]) => Unit] +// var onTransitionStart : js.UndefOr[(String, Double) => Unit] +// } + +// @js.native +// trait HasName extends js.Object { +// val name: String +// } + +// @js.native +// trait Deletions extends js.Object { +// val `type`: String +// val name: js.UndefOr[String] +// val newName: js.UndefOr[String] +// val endTime: Double +// } diff --git a/library/facadeMain/src/main/scala/japgolly/scalajs/react/facade/ReactDOM.scala b/library/facadeMain/src/main/scala/japgolly/scalajs/react/facade/ReactDOM.scala index 613674bfe..a52540e92 100644 --- a/library/facadeMain/src/main/scala/japgolly/scalajs/react/facade/ReactDOM.scala +++ b/library/facadeMain/src/main/scala/japgolly/scalajs/react/facade/ReactDOM.scala @@ -12,20 +12,27 @@ object ReactDOM extends ReactDOM @js.native @nowarn("cat=unused") -trait ReactDOM extends js.Object { +trait ReactDOM extends ReactDOM18 { val version: String = js.native final type Container = dom.Element | dom.Document + @deprecated("Use createRoot instead", "2.2.0 / React v18") + final def render(element: React.Node, container: Container): React.ComponentUntyped = js.native + final def render(element : React.Node, container: Container, - callback : js.Function0[Any] = js.native): React.ComponentUntyped = js.native + callback : js.Function0[Any]): React.ComponentUntyped = js.native + + @deprecated("Use hydrateRoot instead", "2.2.0 / React v18") + final def hydrate(element: React.Node, container: Container): React.ComponentUntyped = js.native final def hydrate(element : React.Node, container: Container, - callback : js.Function0[Any] = js.native): React.ComponentUntyped = js.native + callback : js.Function0[Any]): React.ComponentUntyped = js.native + @deprecated("Use root.unmount() instead", "2.2.0 / React v18") final def unmountComponentAtNode(container: dom.Node): Boolean = js.native // ========================================================================== diff --git a/library/ghpages/src/main/scala/ghpages/GhPages.scala b/library/ghpages/src/main/scala/ghpages/GhPages.scala index 3ec113fe8..ae3cb7284 100644 --- a/library/ghpages/src/main/scala/ghpages/GhPages.scala +++ b/library/ghpages/src/main/scala/ghpages/GhPages.scala @@ -66,8 +66,9 @@ object GhPages { def main(args: Array[String]): Unit = { val container = dom.document.getElementById("root") + val root = ReactDOM.createRoot(container) dom.console.info("Router logging is enabled. Enjoy!") val router = Router(baseUrl, routerConfig.logToConsole) - router() renderIntoDOM container + root.render(router()) } } From ccd2b8a38cd09df790b8113dce3519a3a5894a0e Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 11 May 2022 12:06:04 +1000 Subject: [PATCH 08/83] Use `scalajs-java-securerandom` in tests --- library/project/Dependencies.scala | 52 +++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/library/project/Dependencies.scala b/library/project/Dependencies.scala index d72bc5d2b..18bcdf125 100644 --- a/library/project/Dependencies.scala +++ b/library/project/Dependencies.scala @@ -36,32 +36,32 @@ object Dependencies { } object Dep { - val cats = Def.setting("org.typelevel" %%% "cats-core" % Ver.cats) - val catsEffect = Def.setting("org.typelevel" %%% "cats-effect" % Ver.catsEffect) - val catsEffectLaws = Def.setting("org.typelevel" %%% "cats-effect-laws" % Ver.catsEffect) - val catsEffectTestkit = Def.setting("org.typelevel" %%% "cats-effect-testkit" % Ver.catsEffect) - val catsTestkit = Def.setting("org.typelevel" %%% "cats-testkit" % Ver.cats) - val catsTestkitScalaTest = Def.setting("org.typelevel" %%% "cats-testkit-scalatest" % Ver.catsTestkitScalaTest) - val disciplineScalaTest = Def.setting("org.typelevel" %%% "discipline-scalatest" % Ver.disciplineScalaTest) - val macrotaskExecutor = Def.setting("org.scala-js" %%% "scala-js-macrotask-executor" % Ver.macrotaskExecutor) - val microlibsCompileTime = Def.setting("com.github.japgolly.microlibs" %%% "compile-time" % Ver.microlibs) - val microlibsTestUtil = Def.setting("com.github.japgolly.microlibs" %%% "test-util" % Ver.microlibs) - val microlibsTypes = Def.setting("com.github.japgolly.microlibs" %%% "types" % Ver.microlibs) - val monocle2 = Def.setting("com.github.julien-truffaut" %%% "monocle-core" % Ver.monocle2 cross CrossVersion.for3Use2_13 excludeAll(ExclusionRule(organization = "org.typelevel"))) - val monocle3 = Def.setting("dev.optics" %%% "monocle-core" % Ver.monocle3) - val nyayaGen = Def.setting("com.github.japgolly.nyaya" %%% "nyaya-gen" % Ver.nyaya) - val nyayaProp = Def.setting("com.github.japgolly.nyaya" %%% "nyaya-prop" % Ver.nyaya) - val nyayaTest = Def.setting("com.github.japgolly.nyaya" %%% "nyaya-test" % Ver.nyaya) - val scalaCompiler = Def.setting("org.scala-lang" % "scala-compiler" % scalaVersion.value) - val scalaJsDom = Def.setting("org.scala-js" %%% "scalajs-dom" % Ver.scalaJsDom) - val scalaJsJavaTime = Def.setting("org.scala-js" %%% "scalajs-java-time" % Ver.scalaJsJavaTime cross CrossVersion.for3Use2_13) - val scalaJsSecureRandom = Def.setting("org.scala-js" %%% "scalajs-fake-insecure-java-securerandom" % Ver.scalaJsSecureRandom cross CrossVersion.for3Use2_13) - val scalaReflect = Def.setting("org.scala-lang" % "scala-reflect" % scalaVersion.value) - val scalaTest = Def.setting("org.scalatest" %%% "scalatest" % Ver.scalaTest) - val sourcecode = Def.setting("com.lihaoyi" %%% "sourcecode" % Ver.sourcecode) - val univEq = Def.setting("com.github.japgolly.univeq" %%% "univeq" % Ver.univEq) - val univEqCats = Def.setting("com.github.japgolly.univeq" %%% "univeq-cats" % Ver.univEq) - val utest = Def.setting("com.lihaoyi" %%% "utest" % Ver.utest) + val cats = Def.setting("org.typelevel" %%% "cats-core" % Ver.cats) + val catsEffect = Def.setting("org.typelevel" %%% "cats-effect" % Ver.catsEffect) + val catsEffectLaws = Def.setting("org.typelevel" %%% "cats-effect-laws" % Ver.catsEffect) + val catsEffectTestkit = Def.setting("org.typelevel" %%% "cats-effect-testkit" % Ver.catsEffect) + val catsTestkit = Def.setting("org.typelevel" %%% "cats-testkit" % Ver.cats) + val catsTestkitScalaTest = Def.setting("org.typelevel" %%% "cats-testkit-scalatest" % Ver.catsTestkitScalaTest) + val disciplineScalaTest = Def.setting("org.typelevel" %%% "discipline-scalatest" % Ver.disciplineScalaTest) + val macrotaskExecutor = Def.setting("org.scala-js" %%% "scala-js-macrotask-executor" % Ver.macrotaskExecutor) + val microlibsCompileTime = Def.setting("com.github.japgolly.microlibs" %%% "compile-time" % Ver.microlibs) + val microlibsTestUtil = Def.setting("com.github.japgolly.microlibs" %%% "test-util" % Ver.microlibs) + val microlibsTypes = Def.setting("com.github.japgolly.microlibs" %%% "types" % Ver.microlibs) + val monocle2 = Def.setting("com.github.julien-truffaut" %%% "monocle-core" % Ver.monocle2 cross CrossVersion.for3Use2_13 excludeAll(ExclusionRule(organization = "org.typelevel"))) + val monocle3 = Def.setting("dev.optics" %%% "monocle-core" % Ver.monocle3) + val nyayaGen = Def.setting("com.github.japgolly.nyaya" %%% "nyaya-gen" % Ver.nyaya) + val nyayaProp = Def.setting("com.github.japgolly.nyaya" %%% "nyaya-prop" % Ver.nyaya) + val nyayaTest = Def.setting("com.github.japgolly.nyaya" %%% "nyaya-test" % Ver.nyaya) + val scalaCompiler = Def.setting("org.scala-lang" % "scala-compiler" % scalaVersion.value) + val scalaJsDom = Def.setting("org.scala-js" %%% "scalajs-dom" % Ver.scalaJsDom) + val scalaJsJavaTime = Def.setting("org.scala-js" %%% "scalajs-java-time" % Ver.scalaJsJavaTime cross CrossVersion.for3Use2_13) + val scalaJsSecureRandom = Def.setting("org.scala-js" %%% "scalajs-java-securerandom" % Ver.scalaJsSecureRandom cross CrossVersion.for3Use2_13) + val scalaReflect = Def.setting("org.scala-lang" % "scala-reflect" % scalaVersion.value) + val scalaTest = Def.setting("org.scalatest" %%% "scalatest" % Ver.scalaTest) + val sourcecode = Def.setting("com.lihaoyi" %%% "sourcecode" % Ver.sourcecode) + val univEq = Def.setting("com.github.japgolly.univeq" %%% "univeq" % Ver.univEq) + val univEqCats = Def.setting("com.github.japgolly.univeq" %%% "univeq-cats" % Ver.univEq) + val utest = Def.setting("com.lihaoyi" %%% "utest" % Ver.utest) // Compiler plugins val betterMonadicFor = compilerPlugin("com.olegpy" %% "better-monadic-for" % Ver.betterMonadicFor) From 90f9fd4467a6c0ab2bd707a185c5beb96de32633 Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 11 May 2022 12:23:13 +1000 Subject: [PATCH 09/83] Upgrade Scala3 to 3.1.2 --- doc/changelog/2.2.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog/2.2.0.md b/doc/changelog/2.2.0.md index d4ffec1a4..fecf4dc3b 100644 --- a/doc/changelog/2.2.0.md +++ b/doc/changelog/2.2.0.md @@ -3,3 +3,4 @@ * Scala.js upgraded to 1.10.0 * microlibs upgraded to 4.1.0 +* Scala 3 upgraded to 3.1.2 From 29ef55f543f7a907529b0db7915e99d719c3b335 Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 11 May 2022 12:57:41 +1000 Subject: [PATCH 10/83] Add a new typeclass `Renderable` --- doc/changelog/2.2.0.md | 1 + library/TODO.md | 6 -- .../japgolly/scalajs/react/ReactDOM.scala | 42 ++++---- .../japgolly/scalajs/react/ReactRoot.scala | 6 +- .../japgolly/scalajs/react/Renderable.scala | 29 +++++ .../japgolly/scalajs/react/core/RefTest.scala | 12 ++- .../scalajs/react/core/RenderableTest.scala | 100 ++++++++++++++++++ 7 files changed, 160 insertions(+), 36 deletions(-) delete mode 100644 library/TODO.md create mode 100644 library/coreGeneric/src/main/scala/japgolly/scalajs/react/Renderable.scala create mode 100644 library/tests/src/test/scala/japgolly/scalajs/react/core/RenderableTest.scala diff --git a/doc/changelog/2.2.0.md b/doc/changelog/2.2.0.md index fecf4dc3b..6c65b35c6 100644 --- a/doc/changelog/2.2.0.md +++ b/doc/changelog/2.2.0.md @@ -1,5 +1,6 @@ # 2.2.0 +* Added a new typeclass `Renderable` * Scala.js upgraded to 1.10.0 * microlibs upgraded to 4.1.0 diff --git a/library/TODO.md b/library/TODO.md deleted file mode 100644 index 332d9895f..000000000 --- a/library/TODO.md +++ /dev/null @@ -1,6 +0,0 @@ -* Test that `ReactRoot.render` works for: - * VdomNode - * VdomElement - * Generic - * JsFn - * JsForwardRef diff --git a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactDOM.scala b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactDOM.scala index 5577ecf19..344b46fc2 100644 --- a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactDOM.scala +++ b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactDOM.scala @@ -3,7 +3,6 @@ package japgolly.scalajs.react import japgolly.scalajs.react.facade.ReactDOM.Container import japgolly.scalajs.react.util.Effect._ import japgolly.scalajs.react.util.NotAllowed -import japgolly.scalajs.react.vdom.VdomNode import org.scalajs.dom import scala.scalajs.js.| @@ -34,42 +33,41 @@ object ReactDOM { def flushSync[F[_], A](fa: F[A])(implicit F: Sync[F]): F[A] = F.delay(facade.ReactDOM.flushSync(F.toJsFn(fa))) - def hydrate[G[_]](element : VdomNode, - container: Container, - callback : => G[Unit])(implicit G: Dispatch[G]): facade.React.ComponentUntyped = - facade.ReactDOM.hydrate(element.rawNode, container, G.dispatchFn(callback)) + def hydrate[G[_], A](element: A, container: Container, callback : => G[Unit]) + (implicit G: Dispatch[G], r: Renderable[A]): facade.React.ComponentUntyped = + facade.ReactDOM.hydrate(r(element), container, G.dispatchFn(callback)) /** Same as [[createRoot()]], but is used to hydrate a container whose HTML contents were rendered by * [[ReactDOMServer]]. React will attempt to attach event listeners to the existing markup. * * @since v2.2.0 / React v18 */ - def hydrateRoot(container: Container, element: VdomNode): ReactRoot = - ReactRoot(raw.hydrateRoot(container, element.rawNode)) + def hydrateRoot[A](container: Container, element: A)(implicit r: Renderable[A]): ReactRoot = + ReactRoot(raw.hydrateRoot(container, r(element))) /** Same as [[createRoot()]], but is used to hydrate a container whose HTML contents were rendered by * [[ReactDOMServer]]. React will attempt to attach event listeners to the existing markup. * * @since v2.2.0 / React v18 */ - def hydrateRoot(container: Container, element: VdomNode, options: ReactOptions.HydrateRoot): ReactRoot = - ReactRoot(raw.hydrateRoot(container, element.rawNode, options.raw())) + def hydrateRoot[A](container: Container, element: A, options: ReactOptions.HydrateRoot) + (implicit r: Renderable[A]): ReactRoot = + ReactRoot(raw.hydrateRoot(container, r(element), options.raw())) /** Hydrate the container if is has children, else render into that container. */ - def hydrateOrRender[G[_]](element : VdomNode, - container: dom.Element, - callback : => G[Unit])(implicit G: Dispatch[G]): facade.React.ComponentUntyped = + def hydrateOrRender[G[_], A](element: A, container: dom.Element, callback: => G[Unit]) + (implicit G: Dispatch[G], r: Renderable[A]): facade.React.ComponentUntyped = if (container.hasChildNodes()) hydrate(element, container, callback) else - element.renderIntoDOM(container, callback) + raw.render(r(element), container, G.dispatchFn(callback)) /** Hydrate the container if is has children, else render into that container. */ - def hydrateOrRenderIntoNewRoot(container : dom.Element, - element : VdomNode, - creationOptions : ReactOptions.CreateRoot = ReactOptions.CreateRoot(), - hydrationOptions: ReactOptions.HydrateRoot = ReactOptions.HydrateRoot(), - ): ReactRoot = + def hydrateOrRenderIntoNewRoot[A](container : dom.Element, + element : A, + creationOptions : ReactOptions.CreateRoot = ReactOptions.CreateRoot(), + hydrationOptions: ReactOptions.HydrateRoot = ReactOptions.HydrateRoot(), + )(implicit r : Renderable[A]): ReactRoot = if (container.hasChildNodes()) hydrateRoot(container, element, hydrationOptions) else { @@ -85,16 +83,16 @@ object ReactDOM { def createPortal(child: NotAllowed, container: Any) = child.result @deprecated("Use hydrateRoot instead", "2.2.0 / React v18") - def hydrate(element: VdomNode, container: Container): facade.React.ComponentUntyped = - facade.ReactDOM.hydrate(element.rawNode, container) + def hydrate[A](element: A, container: Container)(implicit r: Renderable[A]): facade.React.ComponentUntyped = + facade.ReactDOM.hydrate(r(element), container) /** Hydrate the container if is has children, else render into that container. */ @deprecated("Use hydrateOrRenderIntoNewRoot instead", "2.2.0 / React v18") - def hydrateOrRender(element: VdomNode, container: dom.Element): facade.React.ComponentUntyped = + def hydrateOrRender[A](element: A, container: dom.Element)(implicit r: Renderable[A]): facade.React.ComponentUntyped = if (container.hasChildNodes()) hydrate(element, container) else - element.renderIntoDOM(container) + raw.render(r(element), container) @deprecated("Use createRoot and root.render instead", "2.2.0 / React v18") def render(element : NotAllowed, diff --git a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactRoot.scala b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactRoot.scala index 57eecfdd7..c7857313b 100644 --- a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactRoot.scala +++ b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/ReactRoot.scala @@ -1,7 +1,5 @@ package japgolly.scalajs.react -import japgolly.scalajs.react.vdom.VdomNode - /** A location in the DOM into which React has initialised itself, and now manages. * * Can be used to render a React element into the DOM with `.render`. @@ -10,8 +8,8 @@ import japgolly.scalajs.react.vdom.VdomNode */ @inline final case class ReactRoot(raw: facade.RootType) { - @inline def render(element: VdomNode): Unit = - raw.render(element.rawNode) + @inline def render[A](node: A)(implicit r: Renderable[A]): Unit = + raw.render(r(node)) @inline def unmount(): Unit = raw.unmount() diff --git a/library/coreGeneric/src/main/scala/japgolly/scalajs/react/Renderable.scala b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/Renderable.scala new file mode 100644 index 000000000..f3ad7af48 --- /dev/null +++ b/library/coreGeneric/src/main/scala/japgolly/scalajs/react/Renderable.scala @@ -0,0 +1,29 @@ +package japgolly.scalajs.react + +import japgolly.scalajs.react.component.Generic.{UnmountedRaw => Component} +import japgolly.scalajs.react.facade.React +import japgolly.scalajs.react.vdom.VdomNode + +/** Typeclass for anything that React can render. + * + * @since v2.2.0 / React 18 + */ +@inline final case class Renderable[-A](raw: A => React.Node) extends AnyVal { + @inline def apply(a: A): React.Node = + raw(a) +} + +object Renderable { + + @inline implicit def long: Renderable[Long] = + Renderable(_.toString) + + @inline implicit def raw[A](implicit ev: A => React.Node): Renderable[A] = + Renderable(ev) + + @inline implicit def vdom: Renderable[VdomNode] = + Renderable(_.rawNode) + + @inline implicit def component: Renderable[Component] = + Renderable(_.raw) +} diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/core/RefTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/core/RefTest.scala index f7e4ae650..862a7ad90 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/core/RefTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/core/RefTest.scala @@ -152,9 +152,11 @@ object RefTest extends TestSuite { @js.native private object RawComp extends js.Object - private val Forwarder = JsForwardRefComponent[Null, Children.Varargs, html.Button](RawComp) + val Forwarder = JsForwardRefComponent[Null, Children.Varargs, html.Button](RawComp) - def nullary() = assertRender(Forwarder(), "
") + def nullaryExpectation = "
" + + def nullary() = assertRender(Forwarder(), nullaryExpectation) def children() = assertRender(Forwarder(<.br, <.hr), "
") @@ -180,10 +182,12 @@ object RefTest extends TestSuite { object ScalaToVdom { - private val Forwarder = React.forwardRef.justChildren[html.Button]((c, r) => + val Forwarder = React.forwardRef.justChildren[html.Button]((c, r) => <.div(<.button.withOptionalRef(r)(^.cls := "fancy", c))) - def nullary() = assertRender(Forwarder(), "
") + def nullaryExpectation = "
" + + def nullary() = assertRender(Forwarder(), nullaryExpectation) def children() = assertRender(Forwarder(<.br, <.hr), "
") diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/core/RenderableTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/core/RenderableTest.scala new file mode 100644 index 000000000..f9e052a6f --- /dev/null +++ b/library/tests/src/test/scala/japgolly/scalajs/react/core/RenderableTest.scala @@ -0,0 +1,100 @@ +package japgolly.scalajs.react.core + +import japgolly.scalajs.react._ +import japgolly.scalajs.react.test.ReactTestUtils +import japgolly.scalajs.react.test.TestUtil._ +import japgolly.scalajs.react.vdom.VdomNode +import japgolly.scalajs.react.vdom.html_<^._ +import sourcecode.Line +import utest._ + +object RenderableTest extends TestSuite { + + private def test[A: Renderable](source: A, expectHtml: String)(implicit l: Line): Unit = { + ReactTestUtils.withNewBodyElement { container => + val root = ReactDOM.createRoot(container) + try { + root.render(source) + assertOuterHTML(container, expectHtml) + } finally { + root.unmount() + } + } + } + + override def tests = Tests { + + // TODO: Add undefined + + "text" - { + test("cool", "cool") + } + + "boolean" - { + test(true, "true") + } + + "short" - { + test(6.toShort, "6") + } + + "int" - { + test(3, "3") + } + + "double" - { + test(3.2, "3.2") + } + + "long" - { + test(500000000L, "500000000") + } + + "rawNode" - { + test(VdomNode("abc").rawNode, "abc") + } + + "rawElement" - { + test(<.div("oof").rawElement, "
oof
") + } + + "vdomNode" - { + test(VdomNode("hehe"), "hehe") + } + + "vdomElement" - { + test(<.div("ah"), "
ah
") + } + + "jsComponent" - { + import JsComponentEs6PTest._ + test(Component(JsProps("Nim")), "
Hello Nim
") + } + + "jsFnComponent" - { + import JsFnComponentTest._ + test(Component(JsProps("Aiden")), "
Hello Aiden
") + } + + "scalaComponent" - { + val ScalaComp = ScalaComponent.builder[Unit].render_(<.div("scala!")).build + test(ScalaComp(), "
scala!
") + } + + "scalaFnComponent" - { + val ScalaFnComp = ScalaFnComponent[Unit](_ => <.div("scala fn!")) + test(ScalaFnComp(), "
scala fn!
") + } + + "jsForwardRef" - { + import RefTest.TestRefForwarding.JsToVdom._ + test(Forwarder(), nullaryExpectation) + } + + "scalaForwardRef" - { + import RefTest.TestRefForwarding.ScalaToVdom._ + test(Forwarder(), nullaryExpectation) + } + } + +} From a62a566fdb79b1d1faf44eaf6c6f0c5e966e0210 Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 11 May 2022 14:30:35 +1000 Subject: [PATCH 11/83] Get React 18 working with `jsDependencies` --- doc/USAGE.md | 14 +++++++++----- doc/changelog/2.2.0.md | 31 ++++++++++++++++++++++++++++++ library/project/Build.scala | 3 ++- library/project/Dependencies.scala | 12 ++++++++++-- 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/doc/USAGE.md b/doc/USAGE.md index 051b5aecd..0e0fffbe8 100644 --- a/doc/USAGE.md +++ b/doc/USAGE.md @@ -52,12 +52,18 @@ Setup If you're using `jsDependencies`, add the following: ```scala - // React JS itself (Note the filenames, adjust as needed, eg. to remove addons.) + // Required for React 18.0.0 + dependencyOverrides += "org.webjars.npm" % "scheduler" % "0.22.0", + jsDependencies ++= Seq( + // Polyfill required for React 18.0.0 + "org.webjars.npm" % "fast-text-encoding" % "1.0.3" / "text.js" minified "text.min.js" + "org.webjars.npm" % "react" % "18.0.0" - / "umd/react.development.js" - minified "umd/react.production.min.js" + / "umd/react.development.js" + minified "umd/react.production.min.js" + dependsOn "text.js" // <-- Load the fast-text-encoding polyfill before loading React itself commonJSName "React", "org.webjars.npm" % "react-dom" % "18.0.0" @@ -72,8 +78,6 @@ Setup dependsOn "umd/react-dom.development.js" commonJSName "ReactDOMServer", ), - - dependencyOverrides += "org.webjars.npm" % "scheduler" % "0.22.0", // Required for React 18.0.0 ``` [See here](IDE.md) for tips on configuring your IDE. diff --git a/doc/changelog/2.2.0.md b/doc/changelog/2.2.0.md index 6c65b35c6..03744c15b 100644 --- a/doc/changelog/2.2.0.md +++ b/doc/changelog/2.2.0.md @@ -5,3 +5,34 @@ * Scala.js upgraded to 1.10.0 * microlibs upgraded to 4.1.0 * Scala 3 upgraded to 3.1.2 + +* To upgrade when using `jsDependencies`, make your sbt config look like this (comments for clarity) + + ```scala + // Required for React 18.0.0 + dependencyOverrides += "org.webjars.npm" % "scheduler" % "0.22.0", + + jsDependencies ++= Seq( + + // Polyfill required for React 18.0.0 + "org.webjars.npm" % "fast-text-encoding" % "1.0.3" / "text.js" minified "text.min.js" + + "org.webjars.npm" % "react" % "18.0.0" + / "umd/react.development.js" + minified "umd/react.production.min.js" + dependsOn "text.js" // <-- Load the fast-text-encoding polyfill before loading React itself + commonJSName "React", + + "org.webjars.npm" % "react-dom" % "18.0.0" + / "umd/react-dom.development.js" + minified "umd/react-dom.production.min.js" + dependsOn "umd/react.development.js" + commonJSName "ReactDOM", + + "org.webjars.npm" % "react-dom" % "18.0.0" + / "umd/react-dom-server.browser.development.js" + minified "umd/react-dom-server.browser.production.min.js" + dependsOn "umd/react-dom.development.js" + commonJSName "ReactDOMServer", + ), + ``` diff --git a/library/project/Build.scala b/library/project/Build.scala index 2647b2121..602c22099 100644 --- a/library/project/Build.scala +++ b/library/project/Build.scala @@ -226,11 +226,12 @@ object ScalaJsReact { Dep.scalaJsSecureRandom.value % Test, ), jsDependencies ++= Seq( + Dep.fastTextEncoding(Test).value, Dep.sizzleJs(Test).value, + (ProvidedJS / "polyfill.js") % Test, (ProvidedJS / "component-es6.js" dependsOn Dep.reactDom.dev) % Test, (ProvidedJS / "component-fn.js" dependsOn Dep.reactDom.dev) % Test, (ProvidedJS / "forward-ref.js" dependsOn Dep.reactDom.dev) % Test, - (ProvidedJS / "polyfill.js" dependsOn Dep.reactDom.dev) % Test, ), ) diff --git a/library/project/Dependencies.scala b/library/project/Dependencies.scala index 18bcdf125..34d7b8c06 100644 --- a/library/project/Dependencies.scala +++ b/library/project/Dependencies.scala @@ -23,6 +23,7 @@ object Dependencies { val betterMonadicFor = "0.3.1" val catsTestkitScalaTest = "2.1.5" val disciplineScalaTest = "2.1.5" + val fastTextEncoding = "1.0.3" val kindProjector = "0.13.2" val macrotaskExecutor = "1.0.0" val nyaya = "1.0.0" @@ -67,6 +68,10 @@ object Dependencies { val betterMonadicFor = compilerPlugin("com.olegpy" %% "better-monadic-for" % Ver.betterMonadicFor) val kindProjector = compilerPlugin("org.typelevel" %% "kind-projector" % Ver.kindProjector cross CrossVersion.full) + /** For testing React 18 */ + def fastTextEncoding(scope: Configuration) = + Def.setting("org.webjars.npm" % "fast-text-encoding" % Ver.fastTextEncoding % scope / fastTextEncodingJs minified "text.min.js") + def sizzleJs(scope: Configuration) = Def.setting("org.webjars.bower" % "sizzle" % Ver.sizzleJs % scope / "sizzle.min.js" commonJSName "Sizzle") @@ -76,6 +81,8 @@ object Dependencies { val reactDoutestUtils = ReactArtifact("react-dom-test-utils") } + def fastTextEncodingJs = "text.js" + final case class ReactArtifact(filename: String) { val dev = s"umd/$filename.development.js" val prod = s"umd/$filename.production.min.js" @@ -94,8 +101,9 @@ object Dependencies { jsDependencies ++= Seq( "org.webjars.npm" % "react" % Ver.reactJs % scope - / "umd/react.development.js" - minified "umd/react.production.min.js" + / "umd/react.development.js" + minified "umd/react.production.min.js" + dependsOn fastTextEncodingJs commonJSName "React", "org.webjars.npm" % "react-dom" % Ver.reactJs % scope From 6753226d9e5c23792014bb6273d00185c4343445 Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 11 May 2022 14:49:10 +1000 Subject: [PATCH 12/83] Upgrade to React 18.1.0 --- doc/TESTING.md | 2 +- doc/USAGE.md | 14 +++++++------- doc/changelog/2.2.0.md | 2 ++ library/ghpages/html/dev2.html | 4 ++-- library/ghpages/html/dev3.html | 4 ++-- library/ghpages/html/prod.html | 4 ++-- library/project/Dependencies.scala | 4 ++-- 7 files changed, 18 insertions(+), 16 deletions(-) diff --git a/doc/TESTING.md b/doc/TESTING.md index 1436c9535..89498e9a0 100644 --- a/doc/TESTING.md +++ b/doc/TESTING.md @@ -33,7 +33,7 @@ Setup // NOTE: Requires react-with-addons.js instead of just react.js jsDependencies += - "org.webjars.npm" % "react-dom" % "18.0.0" % Test + "org.webjars.npm" % "react-dom" % "18.1.0" % Test / "umd/react-dom-test-utils.development.js" minified "umd/react-dom-test-utils.production.min.js" dependsOn "umd/react-dom.development.js" diff --git a/doc/USAGE.md b/doc/USAGE.md index 0e0fffbe8..287a2e58f 100644 --- a/doc/USAGE.md +++ b/doc/USAGE.md @@ -45,34 +45,34 @@ Setup libraryDependencies += "com.github.japgolly.scalajs-react" %%% "core" % "2.1.1" Compile / npmDependencies ++= Seq( - "react" -> "18.0.0", - "react-dom" -> "18.0.0") + "react" -> "18.1.0", + "react-dom" -> "18.1.0") ``` If you're using `jsDependencies`, add the following: ```scala - // Required for React 18.0.0 + // Required for React 18.1.0 dependencyOverrides += "org.webjars.npm" % "scheduler" % "0.22.0", jsDependencies ++= Seq( - // Polyfill required for React 18.0.0 + // Polyfill required for React 18.1.0 "org.webjars.npm" % "fast-text-encoding" % "1.0.3" / "text.js" minified "text.min.js" - "org.webjars.npm" % "react" % "18.0.0" + "org.webjars.npm" % "react" % "18.1.0" / "umd/react.development.js" minified "umd/react.production.min.js" dependsOn "text.js" // <-- Load the fast-text-encoding polyfill before loading React itself commonJSName "React", - "org.webjars.npm" % "react-dom" % "18.0.0" + "org.webjars.npm" % "react-dom" % "18.1.0" / "umd/react-dom.development.js" minified "umd/react-dom.production.min.js" dependsOn "umd/react.development.js" commonJSName "ReactDOM", - "org.webjars.npm" % "react-dom" % "18.0.0" + "org.webjars.npm" % "react-dom" % "18.1.0" / "umd/react-dom-server.browser.development.js" minified "umd/react-dom-server.browser.production.min.js" dependsOn "umd/react-dom.development.js" diff --git a/doc/changelog/2.2.0.md b/doc/changelog/2.2.0.md index 03744c15b..d923dbde4 100644 --- a/doc/changelog/2.2.0.md +++ b/doc/changelog/2.2.0.md @@ -2,6 +2,8 @@ * Added a new typeclass `Renderable` +* Upgrade to React 18 + * Scala.js upgraded to 1.10.0 * microlibs upgraded to 4.1.0 * Scala 3 upgraded to 3.1.2 diff --git a/library/ghpages/html/dev2.html b/library/ghpages/html/dev2.html index a4bff7bb9..32da2b399 100644 --- a/library/ghpages/html/dev2.html +++ b/library/ghpages/html/dev2.html @@ -3,8 +3,8 @@ - - + + diff --git a/library/ghpages/html/dev3.html b/library/ghpages/html/dev3.html index 0929b7f97..969bdc09e 100644 --- a/library/ghpages/html/dev3.html +++ b/library/ghpages/html/dev3.html @@ -3,8 +3,8 @@ - - + + diff --git a/library/ghpages/html/prod.html b/library/ghpages/html/prod.html index 6abfe4ade..dfbff9527 100644 --- a/library/ghpages/html/prod.html +++ b/library/ghpages/html/prod.html @@ -3,8 +3,8 @@ - - + + diff --git a/library/project/Dependencies.scala b/library/project/Dependencies.scala index 34d7b8c06..7fc140ef6 100644 --- a/library/project/Dependencies.scala +++ b/library/project/Dependencies.scala @@ -27,7 +27,7 @@ object Dependencies { val kindProjector = "0.13.2" val macrotaskExecutor = "1.0.0" val nyaya = "1.0.0" - val reactJs = "18.0.0" + val reactJs = "18.1.0" val scalaJsJavaTime = "1.0.0" val scalaJsSecureRandom = "1.0.0" val scalaTest = "3.2.11" @@ -92,7 +92,7 @@ object Dependencies { Dep.scalaJsDom.value, Dep.univEq.value, Dep.univEqCats.value, - "org.webjars.npm" % "scheduler" % "0.22.0", // Required for React 18.0.0 + "org.webjars.npm" % "scheduler" % "0.22.0", // Required for React 18.1.0 )) def addReactJsDependencies(scope: Configuration): Project => Project = From d55efcd806a4df555fdc8b6e170754ddb60285bc Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 11 May 2022 14:50:23 +1000 Subject: [PATCH 13/83] Fix the output of assertOuterHTML when untitled --- .../src/test/scala/japgolly/scalajs/react/test/TestUtil.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/test/TestUtil.scala b/library/tests/src/test/scala/japgolly/scalajs/react/test/TestUtil.scala index f5b324b20..bafc6fe12 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/test/TestUtil.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/test/TestUtil.scala @@ -75,7 +75,7 @@ trait TestUtil assertOuterHTML(null, node, expect) def assertOuterHTML(name: => String, node: TopNode, expect: String)(implicit l: Line): Unit = - assertEq(name, scrubReactHtml(node.outerHTML), expect) + assertEqO(Option(name), scrubReactHtml(node.outerHTML), expect) private val reactRubbish = """\s+data-react\S*?\s*?=\s*?".*?"|""".r From e855a81859aa14596b844cc163bc1365817c659f Mon Sep 17 00:00:00 2001 From: David Barri Date: Wed, 11 May 2022 14:52:23 +1000 Subject: [PATCH 14/83] Add `assertInnerHTML` --- .../scalajs/react/test/TestUtil.scala | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/test/TestUtil.scala b/library/tests/src/test/scala/japgolly/scalajs/react/test/TestUtil.scala index bafc6fe12..8f6988a71 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/test/TestUtil.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/test/TestUtil.scala @@ -77,6 +77,31 @@ trait TestUtil def assertOuterHTML(name: => String, node: TopNode, expect: String)(implicit l: Line): Unit = assertEqO(Option(name), scrubReactHtml(node.outerHTML), expect) + def assertInnerHTMLMatches(node: TopNode, expectRegex: String)(implicit l: Line): Unit = + assertInnerHTMLMatches(null, node, Pattern.compile(expectRegex)) + + def assertInnerHTMLMatches(name: => String, node: TopNode, expectRegex: String)(implicit l: Line): Unit = + assertInnerHTMLMatches(name, node, Pattern.compile(expectRegex)) + + def assertInnerHTMLMatches(node: TopNode, expectPattern: Pattern)(implicit l: Line): Unit = + assertInnerHTMLMatches(null, node, expectPattern) + + def assertInnerHTMLMatches(name: => String, node: TopNode, expectPattern: Pattern)(implicit l: Line): Unit = { + import japgolly.microlibs.testutil.TestUtilInternals._ + val actual = scrubReactHtml(node.innerHTML) + if (!expectPattern.matcher(actual).matches()) { + val desc = Option(name) + printFail2(desc)("regexp", BOLD_BRIGHT_CYAN, expectPattern.pattern)("actual", BOLD_BRIGHT_RED, actual) + failMethod("assertInnerHTMLMatches", desc) + } + } + + def assertInnerHTML(node: TopNode, expect: String)(implicit l: Line): Unit = + assertInnerHTML(null, node, expect) + + def assertInnerHTML(name: => String, node: TopNode, expect: String)(implicit l: Line): Unit = + assertEqO(Option(name), scrubReactHtml(node.innerHTML), expect) + private val reactRubbish = """\s+data-react\S*?\s*?=\s*?".*?"|""".r def scrubReactHtml(html: String): String = From a03b5c532d932816a80521df8d5515aa639133fe Mon Sep 17 00:00:00 2001 From: David Barri Date: Fri, 20 May 2022 10:19:39 +1000 Subject: [PATCH 15/83] Add LegacyReactTestUtils --- doc/changelog/2.2.0.md | 2 + .../react/test/LegacyReactTestUtils.scala | 455 ++++++++++++++++++ 2 files changed, 457 insertions(+) create mode 100644 library/testUtil/src/main/scala/japgolly/scalajs/react/test/LegacyReactTestUtils.scala diff --git a/doc/changelog/2.2.0.md b/doc/changelog/2.2.0.md index d923dbde4..40d0c6462 100644 --- a/doc/changelog/2.2.0.md +++ b/doc/changelog/2.2.0.md @@ -4,6 +4,8 @@ * Upgrade to React 18 +* `LegacyReactTestUtils` + * Scala.js upgraded to 1.10.0 * microlibs upgraded to 4.1.0 * Scala 3 upgraded to 3.1.2 diff --git a/library/testUtil/src/main/scala/japgolly/scalajs/react/test/LegacyReactTestUtils.scala b/library/testUtil/src/main/scala/japgolly/scalajs/react/test/LegacyReactTestUtils.scala new file mode 100644 index 000000000..55eb59e14 --- /dev/null +++ b/library/testUtil/src/main/scala/japgolly/scalajs/react/test/LegacyReactTestUtils.scala @@ -0,0 +1,455 @@ +package japgolly.scalajs.react.test + +import japgolly.scalajs.react._ +import japgolly.scalajs.react.facade.{React => RawReact, ReactDOM => RawReactDOM} +import japgolly.scalajs.react.hooks.Hooks +import japgolly.scalajs.react.internal.CoreGeneral._ +import japgolly.scalajs.react.test.ReactTestUtilsConfig.aroundReact +import japgolly.scalajs.react.util.DefaultEffects.{Async => DA, Sync => DS} +import japgolly.scalajs.react.util.Effect._ +import japgolly.scalajs.react.util.JsUtil +import org.scalajs.dom +import org.scalajs.dom.html.Element +import org.scalajs.dom.{console, document} +import scala.annotation.nowarn +import scala.concurrent.{ExecutionContext, Future} +import scala.scalajs.js +import scala.scalajs.js.| + +@nowarn("cat=deprecation") +object LegacyReactTestUtils extends LegacyReactTestUtils { + @inline def raw = japgolly.scalajs.react.test.facade.ReactTestUtils + + @deprecated("Use .withNewDocumentElementAsync", "2.0.0") + def withNewDocumentElementAsyncCallback[F[_], A](use: Element => F[A])(implicit F: Async[F]): F[A] = + withNewDocumentElementAsync(use) + + @deprecated("Use .withRenderedIntoDocumentAsync", "2.0.0") + def withRenderedIntoDocumentAsyncCallback[M](u: Unmounted[M]): WithRenderedDslF[DA, M, Element] = + withRenderedIntoDocumentAsync(u) + + @deprecated("Use .withNewBodyElementAsync", "2.0.0") + def withNewBodyElementAsyncCallback[F[_], A](use: Element => F[A])(implicit F: Async[F]): F[A] = + withNewBodyElementAsync(use) + + @deprecated("Use .withRenderedIntoBodyAsync", "2.0.0") + def withRenderedIntoBodyAsyncCallback[M](u: Unmounted[M]): WithRenderedDslF[DA, M, Element] = + withRenderedIntoBodyAsync(u) + + @deprecated("Use .withRenderedAsync", "2.0.0") + def withRenderedAsyncCallback[M](u: Unmounted[M], intoBody: Boolean): WithRenderedDslF[DA, M, Element] = + withRenderedAsync(u, intoBody) + + trait WithRenderedDsl[M, R] { + def apply [A](f: (M, R) => A): A + def apply [A](f: M => A): A = apply((m, _) => f(m)) + def withParent[A](f: R => A): A = apply((_, r) => f(r)) + } + + trait WithRenderedDslF[F[_], M, R] { + def apply [A](f: (M, R) => F[A]): F[A] + def apply [A](f: M => F[A]): F[A] = apply((m, _) => f(m)) + def withParent[A](f: R => F[A]): F[A] = apply((_, r) => f(r)) + } + + private[LegacyReactTestUtils] object Internals { + + val reactDataAttrRegex = """\s+data-react\S*?\s*?=\s*?".*?"""".r + val reactTextCommentRegex = """""".r + + type RawM = japgolly.scalajs.react.facade.React.ComponentUntyped + + def wrapMO(r: RawM | Null): MountedOutput = + if (r == null) + null + else { + val r2 = JsUtil.notNull[RawM](r) // TODO: https://github.com/lampepfl/dotty/issues/12739 + val x = JsComponent.mounted(r2) + x.asInstanceOf[MountedOutput] + } + + def mountedElement(c: RawReact.ComponentUntyped | Null) = + if (c == null) null else ReactDOM.findDOMNode(c).get.asElement() + + def parentNode(c: RawReact.ComponentUntyped | Null) = { + val m = mountedElement(c) + if (m == null) null else m.parentNode + } + + def parentElement(c: RawReact.ComponentUntyped | Null) = { + val p = parentNode(c) + if (p == null) null else p.domCast[Element] + } + + def attemptFuture[A](f: => Future[A]): Future[A] = + try f catch { case err: Exception => Future.failed(err) } + + def warnOnError(prefix: String)(a: => Any): Unit = + try { + a + () + } catch { + case t: Throwable => + console.warn(s"$prefix: $t") + } + + def unmount(container: dom.Node): Unit = + warnOnError("Failed to unmount component") { + ReactDOM.unmountComponentAtNode(container) + } + + def _withNewElementAsync[F[_], A](create: => Element, + use : Element => F[A], + remove: Element => Unit, + )(implicit F: Async[F]): F[A] = + F.flatMap(F.delay(create))(e => + F.finallyRun(use(e), F.delay(act(remove(e))))) + + def _withRenderedAsync[F[_], M, A](u: Unmounted[M], parent: Element, f: (M, Element) => F[A]) + (implicit F: Async[F]): F[A] = + aroundReactAsync { + F.flatMap(F.delay(act(RawReactDOM.render(u.raw, parent)))) { c => + val m = u.mountRawOrNull(c) + F.finallyRun(f(m, parent), F.delay(act(unmountRawComponent(c)))) + } + } + + def aroundReactAsync[F[_], A](body: F[A])(implicit F: Async[F]): F[A] = { + val start = F.delay { + val stop = aroundReact.start() + F.delay(stop()) + } + F.flatMap(start) { stop => + F.finallyRun(body, stop) + } + } + + def aroundReactFuture[A](body: => Future[A])(implicit ec: ExecutionContext): Future[A] = { + val stop = aroundReact.start() + val f = body + f.onComplete { _ => stop() } + f + } + + } // Internals +} + +@nowarn("cat=deprecation") +trait LegacyReactTestUtils extends japgolly.scalajs.react.test.internal.ReactTestUtilExtensions { + import LegacyReactTestUtils._ + import LegacyReactTestUtils.Internals._ + + type Unmounted[M] = GenericComponent.Unmounted[_, M] + type Mounted = GenericComponent.MountedRaw + + type MountedOutput = JsComponent.Mounted[js.Object, js.Object] + + type CompType = GenericComponent.ComponentRaw {type Raw <: japgolly.scalajs.react.facade.React.ComponentClassUntyped } + + /** When writing UI tests, tasks like rendering, user events, or data fetching can be considered as "units" of + * interaction with a user interface. React provides a helper called act() that makes sure all updates related to + * these "units" have been processed and applied to the DOM before you make any assertions: + * + * {{{ + * act { + * // render components + * } + * // make assertions + * }}} + * + * This helps make your tests run closer to what real users would experience when using your application. + */ + def act[A](body: => A): A = { + var a = Option.empty[A] + raw.act(() => { a = Some(body) }) + a.getOrElse(throw new RuntimeException("React's TestUtils.act didn't seem to complete.")) + } + + /** When writing UI tests, tasks like rendering, user events, or data fetching can be considered as "units" of + * interaction with a user interface. React provides a helper called act() that makes sure all updates related to + * these "units" have been processed and applied to the DOM before you make any assertions: + * + * {{{ + * await act(async () => { + * // render components + * }); + * // make assertions + * }}} + * + * This helps make your tests run closer to what real users would experience when using your application. + */ + def actAsync[F[_], A](body: F[A])(implicit F: Async[F]): F[A] = { + F.flatMap(F.delay(new Hooks.Var(Option.empty[A]))) { ref => + def setAsync(a: A): F[Unit] = F.delay(DS.runSync(ref.set(Some(a)))) + val body2 = F.flatMap(body)(setAsync) + val body3 = F.fromJsPromise(raw.actAsync(F.toJsPromise(body2))) + F.map(body3)(_ => ref.value.getOrElse(throw new RuntimeException("React's TestUtils.act didn't seem to complete."))) + } + } + + /** Render a component into a detached DOM node in the document. This function requires a DOM. */ + def renderIntoDocument[M](unmounted: Unmounted[M]): M = { + val c = act(raw.renderIntoDocument(unmounted.raw)) + unmounted.mountRawOrNull(c) + } + + def renderIntoDocument(e: vdom.VdomElement): MountedOutput = + wrapMO(act(raw.renderIntoDocument(e.rawElement))) + + /** + * Traverse all components in tree and accumulate all components where test(component) is true. + * This is not that useful on its own, but it's used as a primitive for other test utils. + */ + def findAllInRenderedTree(tree: Mounted, test: MountedOutput => Boolean): Vector[MountedOutput] = + raw.findAllInRenderedTree(tree.raw, (m: RawM) => test(wrapMO(m))).iterator.map(wrapMO(_)).toVector + + /** + * Finds all instance of components in the rendered tree that are DOM components with the class name + * matching className. + */ + def scryRenderedDOMComponentsWithClass(tree: Mounted, className: String): Vector[MountedOutput] = + raw.scryRenderedDOMComponentsWithClass(tree.raw, className).iterator.map(wrapMO(_)).toVector + + /** + * Like [[scryRenderedDOMComponentsWithClass()]] but expects there to be one result, and returns that one result, or + * throws exception if there is any other number of matches besides one. + */ + def findRenderedDOMComponentWithClass(tree: Mounted, className: String): MountedOutput = + wrapMO(raw.findRenderedDOMComponentWithClass(tree.raw, className)) + + /** + * Finds all instance of components in the rendered tree that are DOM components with the tag name + * matching tagName. + */ + def scryRenderedDOMComponentsWithTag(tree: Mounted, tagName: String): Vector[MountedOutput] = + raw.scryRenderedDOMComponentsWithTag(tree.raw, tagName).iterator.map(wrapMO(_)).toVector + + /** + * Like [[scryRenderedDOMComponentsWithTag()]] but expects there to be one result, and returns that one result, or + * throws exception if there is any other number of matches besides one. + */ + def findRenderedDOMComponentWithTag(tree: Mounted, tagName: String): MountedOutput = + wrapMO(raw.findRenderedDOMComponentWithTag(tree.raw, tagName)) + + /** Finds all instances of components with type equal to componentClass. */ + def scryRenderedComponentsWithType(tree: Mounted, c: CompType): Vector[MountedOutput] = + raw.scryRenderedComponentsWithType(tree.raw, c.raw).iterator.map(wrapMO(_)).toVector + + /** + * Same as [[scryRenderedComponentsWithType()]] but expects there to be one result and returns that one result, or throws + * exception if there is any other number of matches besides one. + */ + def findRenderedComponentWithType(tree: Mounted, c: CompType): MountedOutput = + wrapMO(raw.findRenderedComponentWithType(tree.raw, c.raw)) + + def unmountRawComponent(c: RawReact.ComponentUntyped | Null): Unit = { + val p = parentNode(c) + if (p != null) + unmount(p) + } + + // =================================================================================================================== + // Render into body + + def newBodyElement(): Element = { + val cont = document.createElement("div").domAsHtml + document.body.appendChild(cont) + cont + } + + def removeNewBodyElement(e: Element): Unit = + warnOnError("Failed to unmount newBodyElement") { + ReactDOM unmountComponentAtNode e // Doesn't matter if no component mounted here + document.body.removeChild(e) + } + + def withNewBodyElement[A](use: Element => A): A = { + val e = newBodyElement() + try + use(e) + finally + act(removeNewBodyElement(e)) + } + + /** Renders a component into the document body via [[ReactDOM.render()]], + * then unmounts and cleans up after use. + * + * Unlike [[LegacyReactTestUtils.renderIntoDocument()]], this allows DOM focus to work. + */ + def withRenderedIntoBody[M](u: Unmounted[M]): WithRenderedDsl[M, Element] = + new WithRenderedDsl[M, Element] { + override def apply[A](f: (M, Element) => A): A = + withNewBodyElement { parent => + aroundReact { + val c = act(RawReactDOM.render(u.raw, parent)) + try + f(u.mountRawOrNull(c), parent) + finally + unmountRawComponent(c) + } + } + } + + /** Renders a component into the document body via [[ReactDOM.render()]]. + * + * Unlike [[LegacyReactTestUtils.renderIntoDocument()]], this allows DOM focus to work. + */ + def renderIntoBody[M](u: Unmounted[M]): M = { + val c = act(RawReactDOM.render(u.raw, newBodyElement())) + u.mountRawOrNull(c) + } + + def withNewBodyElementFuture[A](use: Element => Future[A])(implicit ec: ExecutionContext): Future[A] = { + val e = newBodyElement() + attemptFuture(use(e)).andThen { case _ => act(removeNewBodyElement(e)) } + } + + /** Renders a component into the document body via [[ReactDOM.render()]], + * and asynchronously waits for the Future to complete before unmounting. + */ + def withRenderedIntoBodyFuture[M, A](u: Unmounted[M])(f: M => Future[A])(implicit ec: ExecutionContext): Future[A] = + withNewBodyElementFuture { parent => + aroundReactFuture { + val c = act(RawReactDOM.render(u.raw, parent)) + val m = u.mountRawOrNull(c) + attemptFuture(f(m)).andThen { case _ => act(unmountRawComponent(c)) } + } + } + + def withNewBodyElementAsync[F[_], A](use: Element => F[A])(implicit F: Async[F]): F[A] = + _withNewElementAsync(newBodyElement(), use, removeNewBodyElement) + + /** Renders a component into the document body via [[ReactDOM.render()]], + * and asynchronously waits for the Async to complete before unmounting. + */ + def withRenderedIntoBodyAsync[M](u: Unmounted[M]): WithRenderedDslF[DA, M, Element] = + new WithRenderedDslF[DA, M, Element] { + override def apply[A](f: (M, Element) => DA[A]) = + withNewBodyElementAsync(_withRenderedAsync(u, _, f)) + } + + // =================================================================================================================== + // Render into document + + def newDocumentElement(): Element = + document.createElement("div").domAsHtml + + def removeNewDocumentElement(e: Element): Unit = + warnOnError("Failed to unmount newDocumentElement") { + // This DOM is detached so the best we can do (for memory) is remove its children + while (e.hasChildNodes()) { + val c = e.childNodes(0) + unmount(c) // Doesn't matter if no component mounted here + e.removeChild(c) + } + } + + def withNewDocumentElement[A](use: Element => A): A = { + val e = newDocumentElement() + try + use(e) + finally + act(removeNewDocumentElement(e)) + } + + /** Renders a component into detached DOM via [[LegacyReactTestUtils.renderIntoDocument()]], + * then unmounts and cleans up after use. + */ + def withRenderedIntoDocument[M](u: Unmounted[M]): WithRenderedDsl[M, Element] = + new WithRenderedDsl[M, Element] { + override def apply[A](f: (M, Element) => A): A = + aroundReact { + val c = act(raw.renderIntoDocument(u.raw)) + try { + val p = parentElement(c) + val m = u.mountRawOrNull(c) + f(m, p) + } finally + act(unmountRawComponent(c)) + } + } + + def withNewDocumentElementFuture[A](use: Element => Future[A])(implicit ec: ExecutionContext): Future[A] = { + val e = newDocumentElement() + attemptFuture(use(e)).andThen { case _ => act(removeNewDocumentElement(e)) } + } + + /** Renders a component into detached DOM via [[LegacyReactTestUtils.renderIntoDocument()]], + * and asynchronously waits for the Future to complete before unmounting. + */ + def withRenderedIntoDocumentFuture[M, A](u: Unmounted[M])(f: M => Future[A])(implicit ec: ExecutionContext): Future[A] = + aroundReactFuture { + val c = act(raw.renderIntoDocument(u.raw)) + val m = u.mountRawOrNull(c) + attemptFuture(f(m)).andThen { case _ => act(unmountRawComponent(c)) } + } + + def withNewDocumentElementAsync[F[_], A](use: Element => F[A])(implicit F: Async[F]): F[A] = + _withNewElementAsync(newDocumentElement(), use, removeNewDocumentElement) + + /** Renders a component into the document body via [[ReactDOM.render()]], + * and asynchronously waits for the Async to complete before unmounting. + */ + def withRenderedIntoDocumentAsync[M](u: Unmounted[M]): WithRenderedDslF[DA, M, Element] = + new WithRenderedDslF[DA, M, Element] { + override def apply[A](f: (M, Element) => DA[A]) = + withNewDocumentElementAsync(_withRenderedAsync(u, _, f)) + } + + // =================================================================================================================== + // Render into body/document + + /** Renders a component then unmounts and cleans up after use. + * + * @param intoBody Whether to use [[renderIntoBody()]] or [[LegacyReactTestUtils.renderIntoDocument()]]. + */ + def withRendered[M](u: Unmounted[M], intoBody: Boolean): WithRenderedDsl[M, Element] = + if (intoBody) + withRenderedIntoBody(u) + else + withRenderedIntoDocument(u) + + /** Renders a component then unmounts and cleans up after use. + * + * @param intoBody Whether to use [[renderIntoBodyFuture()]] or [[renderIntoDocumentFuture()]]. + */ + def withRenderedFuture[M, A](u: Unmounted[M], intoBody: Boolean)(f: M => Future[A])(implicit ec: ExecutionContext): Future[A] = + if (intoBody) + withRenderedIntoBodyFuture(u)(f) + else + withRenderedIntoDocumentFuture(u)(f) + + /** Renders a component then unmounts and cleans up after use. + * + * @param intoBody Whether to use [[renderIntoBodyAsync()]] or [[renderIntoDocumentAsync()]]. + */ + def withRenderedAsync[M](u: Unmounted[M], intoBody: Boolean): WithRenderedDslF[DA, M, Element] = + if (intoBody) + withRenderedIntoBodyAsync(u) + else + withRenderedIntoDocumentAsync(u) + + // =================================================================================================================== + + def modifyProps[P, U <: GenericComponent.Unmounted[P, M], M <: GenericComponent.MountedImpure[P, _]] + (c: GenericComponent[P, CtorType.Props, U], m: M)(f: P => P): M = { + val container = m.getDOMNode.asMounted().node.parentNode + val p2 = f(m.props) + act(c(p2).renderIntoDOM(container.domCast[org.scalajs.dom.Element])) + } + + def replaceProps[P, U <: GenericComponent.Unmounted[P, M], M <: GenericComponent.MountedImpure[P, _]] + (c: GenericComponent[P, CtorType.Props, U], m: M)(p: P): M = + modifyProps(c, m)(_ => p) + + /** + * Turn `<div data-reactroot="">hello</div>` + * into `<div>hello</div>` + */ + def removeReactInternals(html: String): String = + reactDataAttrRegex.replaceAllIn( + reactTextCommentRegex.replaceAllIn( + html, + ""), + "") +} From d49f00f3c44cd28fb611d497a20d585614e04d11 Mon Sep 17 00:00:00 2001 From: David Barri Date: Fri, 20 May 2022 10:21:40 +1000 Subject: [PATCH 16/83] Use LegacyReactTestUtils from tests for now --- .../japgolly/scalajs/react/MiscTest.scala | 12 ++-- .../scalajs/react/core/HooksTest.scala | 2 +- .../react/core/JsComponentEs6Test.scala | 22 ++++---- .../react/core/JsFnComponentTest.scala | 6 +- .../react/core/RawComponentEs6Test.scala | 14 ++--- .../japgolly/scalajs/react/core/RefTest.scala | 28 +++++----- .../scalajs/react/core/RenderableTest.scala | 4 +- .../scalajs/react/core/ReusabilityTest.scala | 4 +- .../react/core/ScalaComponentTest.scala | 24 ++++---- .../react/core/ScalaFnComponentTest.scala | 16 +++--- .../scalajs/react/core/vdom/VdomTest.scala | 12 ++-- .../scalajs/react/extra/BroadcasterTest.scala | 4 +- .../react/extra/EventListenerTest.scala | 4 +- .../scalajs/react/extra/OnUnmountTest.scala | 4 +- .../react/extra/StateSnapshotZoomTest.scala | 2 +- .../react/extra/TriStateCheckboxTest.scala | 2 +- .../react/extra/router/Router2Test.scala | 2 +- .../react/extra/router/RouterP2Test.scala | 2 +- .../react/extra/router/RouterTest.scala | 2 +- .../scalajs/react/test/DomTester.scala | 2 +- .../scalajs/react/test/ReactTestVarTest.scala | 2 +- .../scalajs/react/test/TestTest.scala | 56 +++++++++---------- .../scalajs/react/test/TestUtil.scala | 2 +- 23 files changed, 114 insertions(+), 114 deletions(-) diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/MiscTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/MiscTest.scala index fbcbee5ad..ba36e836c 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/MiscTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/MiscTest.scala @@ -70,7 +70,7 @@ object MiscTest extends TestSuite { <.option(^.value := "c")("c")) ).build - val c = ReactTestUtils.renderIntoDocument(s()) + val c = LegacyReactTestUtils.renderIntoDocument(s()) val sel = c.getDOMNode.asMounted().domCast[html.Select] val options = sel.options.asInstanceOf[js.Array[html.Option]] // https://github.com/scala-js/scala-js-dom/pull/107 val selectedOptions = options filter (_.selected) map (_.value) @@ -96,7 +96,7 @@ object MiscTest extends TestSuite { <.button(^.onClick --> (add1 >> add7)) } .build - val c = ReactTestUtils.renderIntoDocument(C()) + val c = LegacyReactTestUtils.renderIntoDocument(C()) assertEq(c.state, 3) Simulation.click run c assertEq(c.state, 11) @@ -112,7 +112,7 @@ object MiscTest extends TestSuite { <.button(^.onClick --> (add1 >> add7)) } .build - val c = ReactTestUtils.renderIntoDocument(C()) + val c = LegacyReactTestUtils.renderIntoDocument(C()) assertEq(c.state, StrInt("yay", 3)) Simulation.click run c assertEq(c.state, StrInt("yay", 11)) @@ -131,7 +131,7 @@ object MiscTest extends TestSuite { <.button(^.onClick --> (add1 >> add7)) } .build - val c = ReactTestUtils.renderIntoDocument(C()) + val c = LegacyReactTestUtils.renderIntoDocument(C()) assertEq(c.state, StrInt("yay", 3)) Simulation.click run c assertEq(c.state, StrInt("yay", 11)) @@ -150,7 +150,7 @@ object MiscTest extends TestSuite { <.button(^.onClick --> (add1 >> add7)) } .build - val c = ReactTestUtils.renderIntoDocument(C()) + val c = LegacyReactTestUtils.renderIntoDocument(C()) assertEq(c.state, StrIntWrap(StrInt("yay", 3))) Simulation.click run c assertEq(c.state, StrIntWrap(StrInt("yay", 11))) @@ -198,7 +198,7 @@ object MiscTest extends TestSuite { ) ).build React.Profiler.unstable_trace("poop") { - ReactTestUtils.withRenderedIntoDocument(comp(234)) { mounted => + LegacyReactTestUtils.withRenderedIntoDocument(comp(234)) { mounted => assertOuterHTML(mounted.getDOMNode.toHtml.get, "
i = 234
") } } diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/core/HooksTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/core/HooksTest.scala index bcf224b22..65a713b0a 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/core/HooksTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/core/HooksTest.scala @@ -4,7 +4,7 @@ import japgolly.scalajs.react.Hooks.UseEffectArg import japgolly.scalajs.react._ import japgolly.scalajs.react.extra._ import japgolly.scalajs.react.test.DomTester -import japgolly.scalajs.react.test.ReactTestUtils._ +import japgolly.scalajs.react.test.LegacyReactTestUtils._ import japgolly.scalajs.react.test.TestUtil._ import japgolly.scalajs.react.vdom.html_<^._ import org.scalajs.dom.html.Input diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/core/JsComponentEs6Test.scala b/library/tests/src/test/scala/japgolly/scalajs/react/core/JsComponentEs6Test.scala index ad69b9c18..7219391d3 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/core/JsComponentEs6Test.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/core/JsComponentEs6Test.scala @@ -1,7 +1,7 @@ package japgolly.scalajs.react.core import japgolly.scalajs.react._ -import japgolly.scalajs.react.test.ReactTestUtils +import japgolly.scalajs.react.test.LegacyReactTestUtils import japgolly.scalajs.react.test.TestUtil._ import japgolly.scalajs.react.vdom.ImplicitsFromRaw._ import scala.annotation.nowarn @@ -37,7 +37,7 @@ object JsComponentEs6PTest extends JsComponentTest { def p = JsProps("Bob") "c" - assertEq(Component.displayName, n) "u" - assertEq(Component(p).displayName, n) - "m" - assertEq(ReactTestUtils.withRenderedIntoDocument(Component(p))(_.displayName), n) + "m" - assertEq(LegacyReactTestUtils.withRenderedIntoDocument(Component(p))(_.displayName), n) } "noChildren" - { @@ -48,7 +48,7 @@ object JsComponentEs6PTest extends JsComponentTest { assertEq(unmounted.propsChildren.isEmpty, true) assertEq(unmounted.key, None) assertEq(unmounted.ref, None) - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = unmounted.renderIntoDOM(mountNode) val n = mounted.getDOMNode.asMounted().asElement() assertOuterHTML(n, "
Hello Bob
") @@ -67,7 +67,7 @@ object JsComponentEs6PTest extends JsComponentTest { assertEq(unmounted.propsChildren.isEmpty, true) assertEq(unmounted.key, Some("hehe": Key)) assertEq(unmounted.ref, None) - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = unmounted.renderIntoDOM(mountNode) val n = mounted.getDOMNode.asMounted().asElement() assertOuterHTML(n, "
Hello Bob
") @@ -106,7 +106,7 @@ object JsComponentEs6PTest extends JsComponentTest { assertEq(unmounted.propsChildren.isEmpty, false) assertEq(unmounted.key, None) assertEq(unmounted.ref, None) - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = unmounted.renderIntoDOM(mountNode) val n = mounted.getDOMNode.asMounted().asElement() assertOuterHTML(n, "
Hello X

Huge

") @@ -119,7 +119,7 @@ object JsComponentEs6PTest extends JsComponentTest { } "withKey" - { - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val n = C.withKey("k")(JsProps("X"))(H1).renderIntoDOM(mountNode).getDOMNode.asMounted().asElement() assertOuterHTML(n, "
Hello X

Huge

") } @@ -159,7 +159,7 @@ object JsComponentEs6STest extends JsComponentTest { def n = "Statey" "c" - assertEq(Component.displayName, n) "u" - assertEq(Component().displayName, n) - "m" - assertEq(ReactTestUtils.withRenderedIntoDocument(Component())(_.displayName), n) + "m" - assertEq(LegacyReactTestUtils.withRenderedIntoDocument(Component())(_.displayName), n) } "noChildren" - { @@ -172,7 +172,7 @@ object JsComponentEs6STest extends JsComponentTest { assertEq(unmounted.propsChildren.isEmpty, true) assertEq(unmounted.key, None) assertEq(unmounted.ref, None) - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = unmounted.renderIntoDOM(mountNode) val n = mounted.getDOMNode.asMounted().asElement() var s = JsState(123, 500) @@ -231,7 +231,7 @@ object JsComponentEs6STest extends JsComponentTest { assert(Component() eq Component()) "withKey" - { - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val n = Component.withKey("k")().renderIntoDOM(mountNode).getDOMNode.asMounted().asElement() assertOuterHTML(n, "
State = 123 + 500
") } @@ -260,7 +260,7 @@ object JsComponentEs6STest extends JsComponentTest { assertEq(unmounted.propsChildren.isEmpty, false) assertEq(unmounted.key, None) assertEq(unmounted.ref, None) - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = unmounted.renderIntoDOM(mountNode) val n = mounted.getDOMNode.asMounted().asElement() @@ -274,7 +274,7 @@ object JsComponentEs6STest extends JsComponentTest { } "withKey" - { - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val n = C.withKey("k")(H1).renderIntoDOM(mountNode).getDOMNode.asMounted().asElement() assertOuterHTML(n, "
State = 123 + 500

Huge

") } diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/core/JsFnComponentTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/core/JsFnComponentTest.scala index b206aef6a..139837793 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/core/JsFnComponentTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/core/JsFnComponentTest.scala @@ -1,7 +1,7 @@ package japgolly.scalajs.react.core import japgolly.scalajs.react._ -import japgolly.scalajs.react.test.ReactTestUtils +import japgolly.scalajs.react.test.LegacyReactTestUtils import japgolly.scalajs.react.test.TestUtil._ import japgolly.scalajs.react.vdom.html_<^._ import scala.scalajs.js @@ -38,7 +38,7 @@ object JsFnComponentTest extends TestSuite { assertEq(unmounted.propsChildren.isEmpty, true) assertEq(unmounted.key, None) // assertEq(unmounted.ref, None) - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => unmounted.renderIntoDOM(mountNode) val n = mountNode assertOuterHTML(n, "
Hello Bob
") @@ -57,7 +57,7 @@ object JsFnComponentTest extends TestSuite { assertEq(unmounted.propsChildren.isEmpty, true) assertEq(unmounted.key, Some("hehe": Key)) // assertEq(unmounted.ref, None) - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => unmounted.renderIntoDOM(mountNode) val n = mountNode assertOuterHTML(n, "
Hello Bob
") diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/core/RawComponentEs6Test.scala b/library/tests/src/test/scala/japgolly/scalajs/react/core/RawComponentEs6Test.scala index b56732c45..8275d4892 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/core/RawComponentEs6Test.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/core/RawComponentEs6Test.scala @@ -3,7 +3,7 @@ package japgolly.scalajs.react.core import japgolly.scalajs.react._ import japgolly.scalajs.react.internal.Box import japgolly.scalajs.react.test.TestUtil._ -import japgolly.scalajs.react.test.{InferenceHelpers, ReactTestUtils} +import japgolly.scalajs.react.test.{InferenceHelpers, LegacyReactTestUtils} import japgolly.scalajs.react.vdom.ImplicitsFromRaw._ import scala.annotation.nowarn import scala.scalajs.js @@ -32,7 +32,7 @@ object RawComponentEs6PTest extends TestSuite { "displayName" - { assertEq(BasicComponent.displayName, "HelloRaw6") -// ReactTestUtils.withRenderedIntoDocument(BasicComponent(BasicProps("X"))) { m => +// LegacyReactTestUtils.withRenderedIntoDocument(BasicComponent(BasicProps("X"))) { m => // println(inspectObject(m.raw)) // assertEq(m.raw.displayName, "HelloRaw6") // } @@ -52,7 +52,7 @@ object RawComponentEs6PTest extends TestSuite { assertEq(unmounted.propsChildren.isEmpty, true) assertEq(unmounted.key, None) assertEq(unmounted.ref, None) - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = unmounted.renderIntoDOM(mountNode) val n = mounted.getDOMNode.asMounted().asElement() assertOuterHTML(n, "
Hello Bob
") @@ -66,7 +66,7 @@ object RawComponentEs6PTest extends TestSuite { } "withKey" - { - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val u = BasicComponent.withKey("k")(BasicProps("Bob")) assertEq(u.key, Option[Key]("k")) val m = u.renderIntoDOM(mountNode) @@ -81,7 +81,7 @@ object RawComponentEs6PTest extends TestSuite { val c2 = BasicComponent.mapCtorType(_ withProps BasicProps("hello!")) val unmounted = c2() assertEq(unmounted.props.name, "hello!") - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = unmounted.renderIntoDOM(mountNode) val n = mounted.getDOMNode.asMounted().asElement() assertOuterHTML(n, "
Hello hello!
") @@ -150,7 +150,7 @@ object RawComponentEs6PTest extends TestSuite { .componentWillReceiveProps(x => x.backend.receive(x.currentProps, x.nextProps)) .build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => assertMountCount(0) var mounted = Comp(Props(1, 2, 3)).renderIntoDOM(mountNode) @@ -211,7 +211,7 @@ object RawComponentEs6STest extends TestSuite { assert(unmounted.propsChildren.isEmpty) assertEq(unmounted.key, None) assertEq(unmounted.ref, None) - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = unmounted.renderIntoDOM(mountNode) val n = mounted.getDOMNode.asMounted().asElement() diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/core/RefTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/core/RefTest.scala index 862a7ad90..bd218d7fc 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/core/RefTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/core/RefTest.scala @@ -1,7 +1,7 @@ package japgolly.scalajs.react.core import japgolly.scalajs.react._ -import japgolly.scalajs.react.test.ReactTestUtils +import japgolly.scalajs.react.test.LegacyReactTestUtils import japgolly.scalajs.react.test.TestUtil._ import japgolly.scalajs.react.vdom.html_<^._ import org.scalajs.dom.{html, svg} @@ -22,7 +22,7 @@ object RefTest extends TestSuite { def render = renderFn(ref) } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) assertRendered(mounted.getDOMNode.asMounted().asHtml(), expectedHtml(expectedRefHtml)) assertEq(refHtml(mounted.backend.ref), expectedRefHtml) @@ -41,7 +41,7 @@ object RefTest extends TestSuite { def render = <.div(<.input.text(^.defaultValue := "2").withRef(input)) } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].componentDidMount(_.backend.addDataAttr).build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) assertEq(mounted.getDOMNode.asMounted().asElement().querySelector("input").getAttribute(attr), V) } @@ -55,7 +55,7 @@ object RefTest extends TestSuite { def render = <.svg(<.circle().withRef(circle)) } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].componentDidMount(_.backend.addDataAttr).build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) assertEq(mounted.getDOMNode.asMounted().asElement().querySelector("circle").getAttribute(attr), V) } @@ -73,7 +73,7 @@ object RefTest extends TestSuite { def render = <.div(ref.component(123)) } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) assertEq(mounted.backend.ref.unsafeGet().backend.secret, 666) } @@ -85,7 +85,7 @@ object RefTest extends TestSuite { def render = <.div(InnerScala.C.withRef(ref)(123)) } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) assertEq(mounted.backend.ref.unsafeGet().backend.secret, 666) } @@ -97,7 +97,7 @@ object RefTest extends TestSuite { def render = <.div(ref.component.withKey(555555555)(123)) } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) assertEq(mounted.backend.ref.unsafeGet().backend.secret, 666) } @@ -113,7 +113,7 @@ object RefTest extends TestSuite { def render = <.div(ref.component()) } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) mounted.backend.ref.unsafeGet().raw.inc() // compilation and evaluation without error is test enough } @@ -125,7 +125,7 @@ object RefTest extends TestSuite { def render = <.div(InnerJs.withRef(ref)()) } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) mounted.backend.ref.unsafeGet().raw.inc() // compilation and evaluation without error is test enough } @@ -137,7 +137,7 @@ object RefTest extends TestSuite { def render = <.div(ref.component.withKey(555555555)()) } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) mounted.backend.ref.unsafeGet().raw.inc() // compilation and evaluation without error is test enough } @@ -248,7 +248,7 @@ object RefTest extends TestSuite { def render = Forwarder.withRef(ref)("noice") } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) assertRendered(mounted.getDOMNode.asMounted().asHtml(), "
noice

Scala123

") assertEq(mounted.backend.ref.get.runNow().map(_.backend.gimmeHtmlNow()), Some("

Scala123

")) @@ -261,7 +261,7 @@ object RefTest extends TestSuite { def render = Forwarder.withRef(ref)("noice") } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) assertRendered(mounted.getDOMNode.asMounted().asHtml(), "
noice

Scala123

") assertEq(mounted.backend.ref.get.runNow().map(_.backend.gimmeHtmlNow()), Some("

Scala123

")) @@ -274,7 +274,7 @@ object RefTest extends TestSuite { def render = Forwarder.withRef(ref)("noice") } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) assertRendered(mounted.getDOMNode.asMounted().asHtml(), "
noice

Scala123

") assertEq(mounted.backend.ref.get.runNow(), Some("

Scala123

")) @@ -309,7 +309,7 @@ object RefTest extends TestSuite { def render = Forwarder.withRef(ref)("noice") } val C = ScalaComponent.builder[Unit]("X").renderBackend[Backend].build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = C().renderIntoDOM(mountNode) assertRendered(mounted.getDOMNode.asMounted().asHtml(), "
noice
State = 123 + 500
") val r = mounted.backend.ref.get.runNow().get diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/core/RenderableTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/core/RenderableTest.scala index f9e052a6f..c3818e758 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/core/RenderableTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/core/RenderableTest.scala @@ -1,7 +1,7 @@ package japgolly.scalajs.react.core import japgolly.scalajs.react._ -import japgolly.scalajs.react.test.ReactTestUtils +import japgolly.scalajs.react.test.LegacyReactTestUtils import japgolly.scalajs.react.test.TestUtil._ import japgolly.scalajs.react.vdom.VdomNode import japgolly.scalajs.react.vdom.html_<^._ @@ -11,7 +11,7 @@ import utest._ object RenderableTest extends TestSuite { private def test[A: Renderable](source: A, expectHtml: String)(implicit l: Line): Unit = { - ReactTestUtils.withNewBodyElement { container => + LegacyReactTestUtils.withNewBodyElement { container => val root = ReactDOM.createRoot(container) try { root.render(source) diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/core/ReusabilityTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/core/ReusabilityTest.scala index 01b5e8e48..31d51b2cb 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/core/ReusabilityTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/core/ReusabilityTest.scala @@ -313,7 +313,7 @@ object ReusabilityTest extends TestSuite { val pic1b = Picture(1, "eqwrg", "seafr") val pic2 = Picture(2, "asdf", "qer") - val c = ReactTestUtils renderIntoDocument component(Props("n", None, pic1a)) + val c = LegacyReactTestUtils renderIntoDocument component(Props("n", None, pic1a)) def test(expectDelta: Int, s: Props): Unit = { val a = renderCount c.setState(s) @@ -337,7 +337,7 @@ object ReusabilityTest extends TestSuite { import SampleComponent2._ val data1: M = Map(1 -> "One", 2 -> "Two", 3 -> "Three") val data2: M = Map(1 -> "One", 2 -> "Two", 3 -> "33333") - val c = ReactTestUtils renderIntoDocument outerComponent(data1) + val c = LegacyReactTestUtils renderIntoDocument outerComponent(data1) assertEq((outerRenderCount, innerRenderCount), (1, 3)) // println() // println(">>> c.forceUpdate") diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/core/ScalaComponentTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/core/ScalaComponentTest.scala index 49852cc8f..12a13597f 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/core/ScalaComponentTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/core/ScalaComponentTest.scala @@ -2,7 +2,7 @@ package japgolly.scalajs.react.core import japgolly.scalajs.react._ import japgolly.scalajs.react.test.TestUtil._ -import japgolly.scalajs.react.test.{InferenceHelpers, ReactTestUtils, Simulate} +import japgolly.scalajs.react.test.{InferenceHelpers, LegacyReactTestUtils, Simulate} import japgolly.scalajs.react.vdom.ImplicitsFromRaw._ import scala.annotation.nowarn import utest._ @@ -23,7 +23,7 @@ object ScalaComponentPTest extends TestSuite { "displayName" - { assertEq(BasicComponent.displayName, "HelloMessage") -// ReactTestUtils.withRenderedIntoDocument(BasicComponent(BasicProps("X"))) { m => +// LegacyReactTestUtils.withRenderedIntoDocument(BasicComponent(BasicProps("X"))) { m => // println(inspectObject(m.raw)) // assertEq(m.raw.displayName, "HelloMessage") // } @@ -43,7 +43,7 @@ object ScalaComponentPTest extends TestSuite { assertEq(unmounted.propsChildren.isEmpty, true) assertEq(unmounted.key, None) assertEq(unmounted.ref, None) - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = unmounted.renderIntoDOM(mountNode) val n = mounted.getDOMNode.asMounted().asElement() assertOuterHTML(n, "
Hello Bob
") @@ -56,7 +56,7 @@ object ScalaComponentPTest extends TestSuite { } "withKey" - { - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val u = BasicComponent.withKey("k")(BasicProps("Bob")) assertEq(u.key, Option[Key]("k")) val m = u.renderIntoDOM(mountNode) @@ -71,7 +71,7 @@ object ScalaComponentPTest extends TestSuite { val c2 = BasicComponent.mapCtorType(_ withProps BasicProps("hello!")) val unmounted = c2() assertEq(unmounted.props.name, "hello!") - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = unmounted.renderIntoDOM(mountNode) val n = mounted.getDOMNode.asMounted().asElement() assertOuterHTML(n, "
Hello hello!
") @@ -149,7 +149,7 @@ object ScalaComponentPTest extends TestSuite { .componentDidCatch($ => $.setState(Some($.error.message.replaceFirst("'.+' *", "")))) .build - val staleDomNodeCallback = ReactTestUtils.withNewBodyElement { mountNode => + val staleDomNodeCallback = LegacyReactTestUtils.withNewBodyElement { mountNode => assertMountCount(0) var mounted = Comp(Props(1, 2, 3)).renderIntoDOM(mountNode) @@ -194,7 +194,7 @@ object ScalaComponentPTest extends TestSuite { .componentDidUpdate($ => Callback(snapshots :+= $.snapshot)) .build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => var mounted = Comp(10).renderIntoDOM(mountNode) assertOuterHTML(mounted.getDOMNode.asMounted().asElement(), "
p=10 s=110
") assertEq(snapshots, Vector()) @@ -216,7 +216,7 @@ object ScalaComponentPTest extends TestSuite { .getDerivedStateFromPropsOption((_, s) => if ((s & 1) == 0) Some(s >> 1) else None) .build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => var mounted = Comp(108).renderIntoDOM(mountNode) assertOuterHTML(mounted.getDOMNode.asMounted().asElement(), "
p=108 s=4
") @@ -240,7 +240,7 @@ object ScalaComponentPTest extends TestSuite { .getDerivedStateFromPropsOption((_, s) => if ((s & 1) == 0) Some(s >> 1) else None) .build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => var mounted = Comp(-108).renderIntoDOM(mountNode) assertOuterHTML(mounted.getDOMNode.asMounted().asElement(), "
p=-108 s=4
") @@ -264,7 +264,7 @@ object ScalaComponentPTest extends TestSuite { .getDerivedStateFromPropsOption((_, s) => if ((s & 1) == 0) Some(s >> 1) else None) .build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => var mounted = Comp(-108).renderIntoDOM(mountNode) assertOuterHTML(mounted.getDOMNode.asMounted().asElement(), "
p=-108 s=4
") @@ -302,7 +302,7 @@ object ScalaComponentPTest extends TestSuite { .renderBackend[Backend] .build - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = Component().renderIntoDOM(mountNode) assertEq(results, Vector()) @@ -344,7 +344,7 @@ object ScalaComponentSTest extends TestSuite { assert(unmounted.propsChildren.isEmpty) assertEq(unmounted.key, None) assertEq(unmounted.ref, None) - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = unmounted.renderIntoDOM(mountNode) val n = mounted.getDOMNode.asMounted().asElement() val b = mounted.backend diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/core/ScalaFnComponentTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/core/ScalaFnComponentTest.scala index c1a8a1e89..fbe49f42f 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/core/ScalaFnComponentTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/core/ScalaFnComponentTest.scala @@ -1,7 +1,7 @@ package japgolly.scalajs.react.core import japgolly.scalajs.react._ -import japgolly.scalajs.react.test.ReactTestUtils +import japgolly.scalajs.react.test.LegacyReactTestUtils import japgolly.scalajs.react.test.TestUtil._ import japgolly.scalajs.react.vdom.html_<^._ import sourcecode.Line @@ -41,7 +41,7 @@ object ScalaFnComponentTest extends TestSuite { <.br }) val w = ScalaComponent.builder[Unit]("").initialState(Add(1, 1)).render_S(c(_)).build - ReactTestUtils.withRenderedIntoDocument(w()) { m => + LegacyReactTestUtils.withRenderedIntoDocument(w()) { m => assert(rendered == 1) m.setState(Add(1, 2)) assert(rendered == 1) @@ -63,16 +63,16 @@ object ScalaFnComponentTest extends TestSuite { <.span(p) } val C = ScalaComponent.builder[Int].render_P(F(_)).build - ReactTestUtils.withRenderedIntoBody(C(7)) { (m, p) => + LegacyReactTestUtils.withRenderedIntoBody(C(7)) { (m, p) => def test(expectedRenders: Int, expectedHtml: Int)(implicit q: Line): Unit = { val a = (renders, p.innerHTML.trim) val e = (expectedRenders, s"$expectedHtml") assertEq(a, e) } test(1, 7) - ReactTestUtils.replaceProps(C, m)(7) + LegacyReactTestUtils.replaceProps(C, m)(7) test(1, 7) - ReactTestUtils.replaceProps(C, m)(6) + LegacyReactTestUtils.replaceProps(C, m)(6) test(2, 6) } } @@ -86,16 +86,16 @@ object ScalaFnComponentTest extends TestSuite { <.span(p) } val C = ScalaComponent.builder[Int].render_P(F(_)).build - ReactTestUtils.withRenderedIntoBody(C(7)) { (m, p) => + LegacyReactTestUtils.withRenderedIntoBody(C(7)) { (m, p) => def test(expectedRenders: Int, expectedHtml: Int)(implicit q: Line): Unit = { val a = (renders, p.innerHTML.trim) val e = (expectedRenders, s"$expectedHtml") assertEq(a, e) } test(1, 7) - ReactTestUtils.replaceProps(C, m)(7) + LegacyReactTestUtils.replaceProps(C, m)(7) test(2, 7) - ReactTestUtils.replaceProps(C, m)(6) + LegacyReactTestUtils.replaceProps(C, m)(6) test(3, 6) } } diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/core/vdom/VdomTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/core/vdom/VdomTest.scala index 9c839d8c4..44b200876 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/core/vdom/VdomTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/core/vdom/VdomTest.scala @@ -69,13 +69,13 @@ object VdomTest extends TestSuite { } "portal" - { - ReactTestUtils.withNewBodyElement { portalTarget => + LegacyReactTestUtils.withNewBodyElement { portalTarget => val comp = ScalaComponent.static("tmp")( <.div("Here we go...", ReactPortal(<.div("NICE"), portalTarget))) - ReactTestUtils.withRenderedIntoBody(comp()) { m => + LegacyReactTestUtils.withRenderedIntoBody(comp()) { m => val compHtml = m.outerHtmlScrubbed() - val portalHtml = ReactTestUtils.removeReactInternals(portalTarget.innerHTML) + val portalHtml = LegacyReactTestUtils.removeReactInternals(portalTarget.innerHTML) assertEq((compHtml, portalHtml), ("
Here we go...
", "
NICE
")) } } @@ -101,7 +101,7 @@ object VdomTest extends TestSuite { ^.value := s) } .build - ReactTestUtils.withRenderedIntoBody(c()) { m => + LegacyReactTestUtils.withRenderedIntoBody(c()) { m => def txt() = m.getDOMNode.asMounted().domCast[html.Input].value SimEvent.Keyboard.Enter.simulateKeyDown(m) assertEq(txt(), "enter!") @@ -125,7 +125,7 @@ object VdomTest extends TestSuite { } .build - ReactTestUtils.withRenderedIntoBody(c()) { _ => + LegacyReactTestUtils.withRenderedIntoBody(c()) { _ => assert(value.isInstanceOf[html.Input]) } assert(value eq null) @@ -145,7 +145,7 @@ object VdomTest extends TestSuite { } .build - ReactTestUtils.withRenderedIntoBody(c()) { _ => + LegacyReactTestUtils.withRenderedIntoBody(c()) { _ => val x = ref.get.runNow() assert(x.isDefined) } diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/extra/BroadcasterTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/extra/BroadcasterTest.scala index 81130d77d..89565a83f 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/extra/BroadcasterTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/extra/BroadcasterTest.scala @@ -1,7 +1,7 @@ package japgolly.scalajs.react.extra import japgolly.scalajs.react._ -import japgolly.scalajs.react.test.ReactTestUtils +import japgolly.scalajs.react.test.LegacyReactTestUtils import japgolly.scalajs.react.vdom.html_<^._ import utest._ @@ -23,7 +23,7 @@ object BroadcasterTest extends TestSuite { val b = new B "component" - { - val c = ReactTestUtils.renderIntoDocument(C(b)) + val c = LegacyReactTestUtils.renderIntoDocument(C(b)) assert(c.state == Vector()) b.broadcast(2).runNow() assert(c.state == Vector(2)) diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/extra/EventListenerTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/extra/EventListenerTest.scala index 0c183ec24..84f576400 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/extra/EventListenerTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/extra/EventListenerTest.scala @@ -1,7 +1,7 @@ package japgolly.scalajs.react.extra import japgolly.scalajs.react._ -import japgolly.scalajs.react.test.ReactTestUtils +import japgolly.scalajs.react.test.LegacyReactTestUtils import japgolly.scalajs.react.test.TestUtil._ import japgolly.scalajs.react.vdom.html_<^._ import org.scalajs.dom._ @@ -17,7 +17,7 @@ object EventListenerTest extends TestSuite { .build override def tests = Tests { - val c = ReactTestUtils.renderIntoDocument(C()) + val c = LegacyReactTestUtils.renderIntoDocument(C()) def dispatch(name: String) = { val args: EventInit = new EventInit{} diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/extra/OnUnmountTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/extra/OnUnmountTest.scala index b2f5073ed..90ee3387f 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/extra/OnUnmountTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/extra/OnUnmountTest.scala @@ -1,7 +1,7 @@ package japgolly.scalajs.react.extra import japgolly.scalajs.react._ -import japgolly.scalajs.react.test.ReactTestUtils +import japgolly.scalajs.react.test.LegacyReactTestUtils import japgolly.scalajs.react.vdom.html_<^._ import utest._ @@ -26,7 +26,7 @@ object OnUnmountTest extends TestSuite { .build override def tests = Tests { - val c = ReactTestUtils.renderIntoDocument(Outer()) + val c = LegacyReactTestUtils.renderIntoDocument(Outer()) assert(i == 1) c.setState(false) assert(i == 0) diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/extra/StateSnapshotZoomTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/extra/StateSnapshotZoomTest.scala index c4a5b1864..5e79f1e00 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/extra/StateSnapshotZoomTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/extra/StateSnapshotZoomTest.scala @@ -110,7 +110,7 @@ object StateSnapshotZoomTest extends TestSuite { def counts() = (Middle.renders, intRenders, strRenders) - ReactTestUtils.withNewBodyElement { mountNode => + LegacyReactTestUtils.withNewBodyElement { mountNode => val mounted = Top.Comp().renderIntoDOM(mountNode) def dom() = mounted.getDOMNode.asMounted().asElement() def intDom() = dom().querySelector("span") diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/extra/TriStateCheckboxTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/extra/TriStateCheckboxTest.scala index d27d6656c..225215460 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/extra/TriStateCheckboxTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/extra/TriStateCheckboxTest.scala @@ -2,7 +2,7 @@ package japgolly.scalajs.react.extra import japgolly.scalajs.react._ import japgolly.scalajs.react.extra.components.TriStateCheckbox -import japgolly.scalajs.react.test.ReactTestUtils._ +import japgolly.scalajs.react.test.LegacyReactTestUtils._ import japgolly.scalajs.react.test.TestUtil._ import japgolly.scalajs.react.test._ import japgolly.scalajs.react.vdom.html_<^._ diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/extra/router/Router2Test.scala b/library/tests/src/test/scala/japgolly/scalajs/react/extra/router/Router2Test.scala index 549cac593..90a1a234e 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/extra/router/Router2Test.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/extra/router/Router2Test.scala @@ -159,7 +159,7 @@ object Router2Test extends TestSuite { val ctl = lgc.ctl val sim = SimHistory(base.abs) - val r = ReactTestUtils.renderIntoDocument(router()) + val r = LegacyReactTestUtils.renderIntoDocument(router()) def html = r.getDOMNode.asMounted().asElement().outerHTML def currentPage(): Option[MyPage2] = lgc.parseUrl(AbsUrl(dom.window.location.href)).flatMap(config.rules.parse(_).runNow().toOption) isUserLoggedIn = false diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/extra/router/RouterP2Test.scala b/library/tests/src/test/scala/japgolly/scalajs/react/extra/router/RouterP2Test.scala index 1765cb377..db395c6dd 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/extra/router/RouterP2Test.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/extra/router/RouterP2Test.scala @@ -163,7 +163,7 @@ object RouterP2Test extends TestSuite { val ctx = new Ctx(42) val sim = SimHistory(base.abs) - val r = ReactTestUtils.renderIntoDocument(router(ctx)) + val r = LegacyReactTestUtils.renderIntoDocument(router(ctx)) def html = r.getDOMNode.asMounted().asElement().outerHTML def currentPage(): Option[MyPage2] = lgc.parseUrl(AbsUrl(dom.window.location.href)).flatMap(config.rules.parse(_).runNow().toOption) isUserLoggedIn = false diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/extra/router/RouterTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/extra/router/RouterTest.scala index f4ce48bbd..59022f22e 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/extra/router/RouterTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/extra/router/RouterTest.scala @@ -91,7 +91,7 @@ object RouterTest extends TestSuite { import MyPage.{Root, Hello, Greet, QueryParamPage} val base = RouterTestHelp.localBaseUrl_/ val router = Router(base, MyPage.config.logToConsole) - val c = ReactTestUtils.renderIntoDocument(router()) + val c = LegacyReactTestUtils.renderIntoDocument(router()) def node = c.getDOMNode.asMounted().asElement() def html = node.outerHTML diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/test/DomTester.scala b/library/tests/src/test/scala/japgolly/scalajs/react/test/DomTester.scala index a9a417ca9..cc396183c 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/test/DomTester.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/test/DomTester.scala @@ -2,7 +2,7 @@ package japgolly.scalajs.react.test import japgolly.microlibs.testutil.TestUtil._ import japgolly.scalajs.react._ -import japgolly.scalajs.react.test.ReactTestUtils._ +import japgolly.scalajs.react.test.LegacyReactTestUtils._ import japgolly.scalajs.react.test._ import org.scalajs.dom.html.{Button, Element, Input} import sourcecode.Line diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/test/ReactTestVarTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/test/ReactTestVarTest.scala index 7ad29c241..aefe66c0f 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/test/ReactTestVarTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/test/ReactTestVarTest.scala @@ -75,7 +75,7 @@ object ReactTestVarTest extends TestSuite { .render_P(parent => <.div(parent.state.runNow(), ^.onClick --> parent.modState(_ + 1))) .build val v = ReactTestVar(1) - ReactTestUtils.withRenderedIntoDocument(c(v.stateAccess)) { m => + LegacyReactTestUtils.withRenderedIntoDocument(c(v.stateAccess)) { m => v.onUpdate(m.forceUpdate) assertRendered(m.getDOMNode.asMounted().asElement(), "
1
") Simulate.click(m.getDOMNode.asMounted().asElement()) diff --git a/library/tests/src/test/scala/japgolly/scalajs/react/test/TestTest.scala b/library/tests/src/test/scala/japgolly/scalajs/react/test/TestTest.scala index 88149adf8..d51140aca 100644 --- a/library/tests/src/test/scala/japgolly/scalajs/react/test/TestTest.scala +++ b/library/tests/src/test/scala/japgolly/scalajs/react/test/TestTest.scala @@ -16,7 +16,7 @@ object TestTest extends TestSuite { lazy val A = ScalaComponent.builder[Unit]("A").render_C(c => <.p(^.cls := "AA", c)).build lazy val B = ScalaComponent.builder[Unit]("B").renderStatic(<.p(^.cls := "BB", "hehehe")).build - lazy val rab = ReactTestUtils.renderIntoDocument(A(B())) + lazy val rab = LegacyReactTestUtils.renderIntoDocument(A(B())) val inputRef = Ref[HTMLInputElement] @@ -47,13 +47,13 @@ object TestTest extends TestSuite { val tests = Tests { "findRenderedDOMComponentWithClass" - { - val x = ReactTestUtils.findRenderedDOMComponentWithClass(rab, "BB") + val x = LegacyReactTestUtils.findRenderedDOMComponentWithClass(rab, "BB") val n = x.getDOMNode.asMounted().asElement() assert(n.matchesBy[HTMLElement](_.className == "BB")) } "findRenderedComponentWithType" - { - val n = ReactTestUtils.findRenderedComponentWithType(rab, B).getDOMNode.asMounted().asElement() + val n = LegacyReactTestUtils.findRenderedComponentWithType(rab, B).getDOMNode.asMounted().asElement() assert(n.matchesBy[HTMLElement](_.className == "BB")) } @@ -63,20 +63,20 @@ object TestTest extends TestSuite { "plainElement" - { val re: VdomElement = <.div("Good") - val c = ReactTestUtils.renderIntoDocument(re) + val c = LegacyReactTestUtils.renderIntoDocument(re) test(c, """
Good
""") } "scalaComponent" - { - val c = ReactTestUtils.renderIntoDocument(B()) + val c = LegacyReactTestUtils.renderIntoDocument(B()) test(c, """

hehehe

""") } } "Simulate" - { "click" - { - val c = ReactTestUtils.renderIntoDocument(IC()) - val s = ReactTestUtils.findRenderedDOMComponentWithTag(c, "span") + val c = LegacyReactTestUtils.renderIntoDocument(IC()) + val s = LegacyReactTestUtils.findRenderedDOMComponentWithTag(c, "span") val a = s.getDOMNode.asMounted().asElement().innerHTML Simulate.click(inputRef.unsafeGet()) val b = s.getDOMNode.asMounted().asElement().innerHTML @@ -93,8 +93,8 @@ object TestTest extends TestSuite { ) }).build - val c = ReactTestUtils.renderIntoDocument(IDC()) - val s = ReactTestUtils.findRenderedDOMComponentWithTag(c, "span") + val c = LegacyReactTestUtils.renderIntoDocument(IDC()) + val s = LegacyReactTestUtils.findRenderedDOMComponentWithTag(c, "span") val a = s.getDOMNode.asMounted().asElement().innerHTML simF(inputRef.unsafeGet()) @@ -182,14 +182,14 @@ object TestTest extends TestSuite { } <.div(^.onClick ==> onClick) }.build - ReactTestUtils.withRenderedIntoDocument(c()) { m => + LegacyReactTestUtils.withRenderedIntoDocument(c()) { m => Simulate.click(m) } assertEq(ok, true) } "change" - { - val c = ReactTestUtils.renderIntoDocument(IT()) + val c = LegacyReactTestUtils.renderIntoDocument(IT()) SimEvent.Change("hehe").simulate(c) val t = c.getDOMNode.asMounted().domCast[HTMLInputElement].value assertEq(t, "HEHE") @@ -203,13 +203,13 @@ object TestTest extends TestSuite { e("change") >> T.setState(ev.target.value) <.input.text(^.value := T.state, ^.onFocus --> e("focus"), ^.onChange ==> chg, ^.onBlur --> e("blur")).withRef(inputRef) }).build - ReactTestUtils.renderIntoDocument(C()) + LegacyReactTestUtils.renderIntoDocument(C()) Simulation.focusChangeBlur("good") run inputRef.unsafeGet() assertEq(events, Vector("focus", "change", "blur")) assertEq(inputRef.unsafeGet().value, "good") } "targetByName" - { - val c = ReactTestUtils.renderIntoDocument(IC()) + val c = LegacyReactTestUtils.renderIntoDocument(IC()) var count = 0 def tgt = { count += 1 @@ -222,10 +222,10 @@ object TestTest extends TestSuite { "withRenderedIntoDocument" - { var m: ScalaComponent.MountedImpure[Unit, Boolean, Unit] = null - ReactTestUtils.withRenderedIntoDocument(IC()) { mm => + LegacyReactTestUtils.withRenderedIntoDocument(IC()) { mm => m = mm val n = m.getDOMNode.asMounted().asElement() - assert(ReactTestUtils.removeReactInternals(n.outerHTML) startsWith "