Skip to content

Commit 6630865

Browse files
authored
Merge pull request #1127 from japgolly/test_warnings_to_errors
Fixes for compile-time options
2 parents 53d95d7 + 868dc94 commit 6630865

File tree

16 files changed

+152
-143
lines changed

16 files changed

+152
-143
lines changed

doc/CONFIG.md

Lines changed: 14 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
* [`.component.names.all`](#componentnamesall)
77
* [`.component.names.implicit`](#componentnamesimplicit)
88
* [`.config.class` *(Scala 3 only)*](#configclass-scala-3-only)
9-
* [`.test.warnings.react`](#testwarningsreact)
109
* Runtime Settings *(development-mode only)*
1110
* [Usage](#runtime-settings-usage)
1211
* [`Reusability.disableGloballyInDev()`](#reusabilitydisablegloballyindev)
@@ -26,6 +25,16 @@ If this is important to you or your organisation, feel free to reach out and spo
2625

2726
# Compile-Time Settings: Usage
2827

28+
First add this to your sbt:
29+
30+
```scala
31+
scalacOptions ++= // Required since sbt 1.6.0
32+
sys.props.iterator
33+
.filter(_._1.contains("japgolly"))
34+
.map(x => s"-D${x._1}=${x._2}")
35+
.toSeq
36+
```
37+
2938
Currently, you have to specify compile-time settings to `sbt` directly when you start it.
3039

3140
Examples:
@@ -161,60 +170,6 @@ object CustomConfig extends ScalaJsReactConfig.Defaults {
161170
}
162171
```
163172

164-
165-
# `.test.warnings.react`
166-
167-
When using `LegacyReactTestUtils`, this setting can be used to catch React warnings and turn them into exceptions.
168-
169-
### Usage:
170-
171-
```
172-
sbt -Djapgolly.scalajs.react.test.warnings.react=warn|fatal
173-
```
174-
175-
| Setting | Outcome |
176-
| -- | -- |
177-
| `warn` (default) | Print warnings and move on |
178-
| `fatal` | Throw warnings as exceptions |
179-
180-
### Example:
181-
182-
```
183-
sbt -Djapgolly.scalajs.react.test.warnings.react=fatal
184-
```
185-
186-
```scala
187-
package com.example
188-
189-
import japgolly.scalajs.react._
190-
import japgolly.scalajs.react.test._
191-
import japgolly.scalajs.react.vdom.html_<^._
192-
import utest._
193-
194-
object ExampleTest extends TestSuite {
195-
196-
override def tests = Tests {
197-
"example" - {
198-
val comp = ScalaFnComponent[Int](i => <.p(<.td(s"i = $i")))
199-
LegacyReactTestUtils.withRenderedIntoBody(comp(123)).withParent { m =>
200-
val html = m.outerHTML
201-
assert(html == "<p><td>i = 123</td></p>")
202-
}
203-
}
204-
}
205-
}
206-
```
207-
208-
Running the above test will fail with this error message:
209-
210-
```
211-
scala.scalajs.js.JavaScriptException: Warning: validateDOMNesting(...): <td> cannot appear as a child of <p>.
212-
at td
213-
at p
214-
at $c_sjs_js_Any$.fromFunction1__F1__sjs_js_Function1
215-
```
216-
217-
218173
# Runtime Settings: Usage
219174

220175
Runtime settings are designed for use in development-mode only (`fastOptJS`).
@@ -241,7 +196,8 @@ object Main {
241196

242197
// Start app
243198
val container = dom.document.getElementById("root")
244-
MyApp().renderIntoDOM(container)
199+
val root = ReactDOMClient.createRoot(container)
200+
root.render(MyApp())
245201
}
246202
}
247203
```
@@ -293,7 +249,8 @@ object Main {
293249

294250
// Start app
295251
val container = dom.document.getElementById("root")
296-
MyApp().renderIntoDOM(container)
252+
val root = ReactDOMClient.createRoot(container)
253+
root.render(MyApp())
297254
}
298255
}
299256
```

doc/TESTING.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -290,10 +290,7 @@ for how to write tests for real-world scalajs-react applications.
290290

291291
# Fatal React warnings
292292

293-
The easiest way to make `LegacyReactTestUtils` to turn React warnings into runtime exceptions,
294-
is via a [config option](./CONFIG.md#testwarningsreact).
295-
296-
Alternatively, you can do any of the following...
293+
To turn React warnings into runtime exceptions, do any of the following...
297294

298295
- Wrapping a test
299296

@@ -304,7 +301,7 @@ Alternatively, you can do any of the following...
304301
}
305302
```
306303

307-
- Installing for all `LegacyReactTestUtils` usage
304+
- Installing for all `ReactTestUtils` usage
308305

309306
```scala
310307
import japgolly.scalajs.react.test.ReactTestUtilsConfig

doc/changelog/3.0.0.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
- Wrap router actions in `startTransition`, making the change of pages interruptible.
3636
- Allow creating custom `Route` instances outside the DSL model. A `Route` just wraps functions to turn a `Path` into a potential page and vice-versa.
3737

38+
- The ability to globally turn React warnings into errors via sbt system properties has been removed.
39+
It's test case had an error in it — it never worked as intended.
40+
3841
### Deprecated
3942

4043
- Anything deprecated by React 18 is now deprecated in Scala

downstream-tests/build.sbt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def scalacCommonFlags: Seq[String] = Seq(
2020
)
2121

2222
def scalac2Flags = Seq(
23+
"-Wconf:cat=lint-infer-any&msg=kind-polymorphic:s", // https://github.com/scala/bug/issues/13128
2324
"-Wunused:explicits", // Warn if an explicit parameter is unused.
2425
"-Wunused:implicits", // Warn if an implicit parameter is unused.
2526
"-Wunused:imports", // Warn if an import selector is not referenced.
@@ -63,6 +64,11 @@ def commonSettings: Project => Project = _
6364
case (2, _) => scalac2Flags
6465
case (3, _) => scalac3Flags
6566
}.value,
67+
scalacOptions ++= // Required since sbt 1.6.0
68+
sys.props.iterator
69+
.filter(_._1.matches("(downstream_tests|japgolly).*"))
70+
.map(x => s"-D${x._1}=${x._2}")
71+
.toSeq,
6672
dependencyOverrides ++= globalDependencyOverrides.value,
6773
)
6874

downstream-tests/js/src/test/scala/downstream/RuntimeTests.scala

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ import cats.effect.IO
44
import japgolly.microlibs.compiletime.CompileTimeInfo
55
import japgolly.microlibs.testutil.TestUtil._
66
import japgolly.scalajs.react._
7-
import japgolly.scalajs.react.vdom.html_<^._
87
import japgolly.scalajs.react.test.ReactTestUtils
98
import japgolly.scalajs.react.util.JsUtil
10-
import org.scalajs.dom.console
119
import scala.scalajs.js
1210
import scala.scalajs.LinkingInfo.developmentMode
1311
import scala.util.Try
@@ -16,10 +14,9 @@ import japgolly.scalajs.react.AsyncTestSuite
1614

1715
object RuntimeTests extends AsyncTestSuite {
1816

19-
val compNameAuto = CompileTimeInfo.sysProp("japgolly.scalajs.react.component.names.implicit")
20-
val compNameAll = CompileTimeInfo.sysProp("japgolly.scalajs.react.component.names.all")
21-
val configClass = CompileTimeInfo.sysProp("japgolly.scalajs.react.config.class")
22-
val testWarningsReact = CompileTimeInfo.sysProp("japgolly.scalajs.react.test.warnings.react")
17+
val compNameAuto = CompileTimeInfo.sysProp("japgolly.scalajs.react.component.names.implicit")
18+
val compNameAll = CompileTimeInfo.sysProp("japgolly.scalajs.react.component.names.all")
19+
val configClass = CompileTimeInfo.sysProp("japgolly.scalajs.react.config.class")
2320

2421
val dsCfg1 = configClass.contains("downstream.DownstreamConfig1")
2522
val dsCfg2 = configClass.contains("downstream.DownstreamConfig2")
@@ -91,26 +88,5 @@ object RuntimeTests extends AsyncTestSuite {
9188
} yield ()
9289
}
9390

94-
"testWarnings" - {
95-
96-
"react" - {
97-
val c = ScalaFnComponent[Int](i => <.p(<.td(s"i = $i")))
98-
ReactTestUtils.withRendered_(c(123))(_ => ()).attemptTry.map { t =>
99-
assertEq(t.isFailure, testWarningsReact.contains("react"))
100-
}
101-
}
102-
103-
"unlreated" - {
104-
val c = ScalaFnComponent[Int](i => <.p(s"i = $i"))
105-
ReactTestUtils.withRendered_(c(123)) { _ =>
106-
console.info(".")
107-
console.log(".")
108-
console.warn(".")
109-
console.error(".")
110-
}.attemptTry.map { t =>
111-
assertEq(t.isFailure, false)
112-
}
113-
}
114-
}
11591
}
11692
}

downstream-tests/run

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ skip2=skip2
66

77
# Tests
88
all_tests_values=(
9-
"-Ddownstream_tests.enableJSCE -Djapgolly.scalajs.react.test.warnings.react=fatal"
9+
"-Ddownstream_tests.enableJSCE"
1010
"-Djapgolly.scalajs.react.config.class=downstream.DownstreamConfig1 -Ddownstream_tests.reusability.dev=disable $skip2"
1111
"-Djapgolly.scalajs.react.component.names.implicit=blank -Djapgolly.scalajs.react.component.names.all=allow"
1212
"-Djapgolly.scalajs.react.component.names.implicit=short -Ddownstream_tests.reusability.dev=disable"

library/project/Build.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ object ScalaJsReact {
251251

252252
lazy val util = project
253253
.dependsOn(utilFallbacks % Provided)
254-
.configure(commonSettings, publicationSettings, hasNoTests, disableScalaDoc3, prohibitDefaultEffects)
254+
.configure(commonSettings, publicationSettings, utestSettings, disableScalaDoc3, prohibitDefaultEffects)
255255
.settings(
256256
libraryDependencies += Dep.scalaJsDom.value,
257257
)

library/testUtil/src/main/scala/japgolly/scalajs/react/test/LegacyReactTestUtils.scala

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import japgolly.scalajs.react._
44
import japgolly.scalajs.react.facade.{React => RawReact, ReactDOM => RawReactDOM}
55
import japgolly.scalajs.react.hooks.Hooks
66
import japgolly.scalajs.react.internal.CoreGeneral._
7-
import japgolly.scalajs.react.test.ReactTestUtilsConfig.aroundReact
87
import japgolly.scalajs.react.util.DefaultEffects.{Async => DA, Sync => DS}
98
import japgolly.scalajs.react.util.Effect._
109
import japgolly.scalajs.react.util.JsUtil
@@ -106,30 +105,13 @@ object LegacyReactTestUtils extends LegacyReactTestUtils {
106105

107106
def _withRenderedAsync[F[_], M, A](u: Unmounted[M], parent: Element, f: (M, Element) => F[A])
108107
(implicit F: Async[F]): F[A] =
109-
aroundReactAsync {
108+
ReactTestUtilsConfig.aroundReact.async {
110109
F.flatMap(F.delay(act(RawReactDOM.render(u.raw, parent)))) { c =>
111110
val m = u.mountRawOrNull(c)
112111
F.finallyRun(f(m, parent), F.delay(act(unmountRawComponent(c))))
113112
}
114113
}
115114

116-
def aroundReactAsync[F[_], A](body: F[A])(implicit F: Async[F]): F[A] = {
117-
val start = F.delay {
118-
val stop = aroundReact.start()
119-
F.delay(stop())
120-
}
121-
F.flatMap(start) { stop =>
122-
F.finallyRun(body, stop)
123-
}
124-
}
125-
126-
def aroundReactFuture[A](body: => Future[A])(implicit ec: ExecutionContext): Future[A] = {
127-
val stop = aroundReact.start()
128-
val f = body
129-
f.onComplete { _ => stop() }
130-
f
131-
}
132-
133115
} // Internals
134116
}
135117

@@ -279,7 +261,7 @@ trait LegacyReactTestUtils extends japgolly.scalajs.react.test.internal.ReactTes
279261
new WithRenderedDsl[M, Element] {
280262
override def apply[A](f: (M, Element) => A): A =
281263
withNewBodyElement { parent =>
282-
aroundReact.sync {
264+
ReactTestUtilsConfig.aroundReact.sync {
283265
val c = act(RawReactDOM.render(u.raw, parent))
284266
try
285267
f(u.mountRawOrNull(c), parent)
@@ -308,7 +290,7 @@ trait LegacyReactTestUtils extends japgolly.scalajs.react.test.internal.ReactTes
308290
*/
309291
def withRenderedIntoBodyFuture[M, A](u: Unmounted[M])(f: M => Future[A])(implicit ec: ExecutionContext): Future[A] =
310292
withNewBodyElementFuture { parent =>
311-
aroundReactFuture {
293+
ReactTestUtilsConfig.aroundReact.future {
312294
val c = act(RawReactDOM.render(u.raw, parent))
313295
val m = u.mountRawOrNull(c)
314296
attemptFuture(f(m)).andThen { case _ => act(unmountRawComponent(c)) }
@@ -357,7 +339,7 @@ trait LegacyReactTestUtils extends japgolly.scalajs.react.test.internal.ReactTes
357339
def withRenderedIntoDocument[M](u: Unmounted[M]): WithRenderedDsl[M, Element] =
358340
new WithRenderedDsl[M, Element] {
359341
override def apply[A](f: (M, Element) => A): A =
360-
aroundReact.sync {
342+
ReactTestUtilsConfig.aroundReact.sync {
361343
val c = act(raw.renderIntoDocument(u.raw))
362344
try {
363345
val p = parentElement(c)
@@ -377,7 +359,7 @@ trait LegacyReactTestUtils extends japgolly.scalajs.react.test.internal.ReactTes
377359
* and asynchronously waits for the Future to complete before unmounting.
378360
*/
379361
def withRenderedIntoDocumentFuture[M, A](u: Unmounted[M])(f: M => Future[A])(implicit ec: ExecutionContext): Future[A] =
380-
aroundReactFuture {
362+
ReactTestUtilsConfig.aroundReact.future {
381363
val c = act(raw.renderIntoDocument(u.raw))
382364
val m = u.mountRawOrNull(c)
383365
attemptFuture(f(m)).andThen { case _ => act(unmountRawComponent(c)) }

library/testUtil/src/main/scala/japgolly/scalajs/react/test/ReactTestUtils.scala

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,18 @@ trait ReactTestUtils extends japgolly.scalajs.react.test.internal.ReactTestUtilE
120120
Resource.make(Effect[F].delay(newElement()), e => Effect[F].delay(removeElement(e)))
121121

122122
val withReactRootSync: WithDsl[TestReactRoot, ImplicitUnit] =
123-
withElementSync.mapResource(TestReactRoot(_))(_.unmountSync())
124-
125-
def withReactRoot[F[_]: Async]: Resource[F, TestReactRoot] =
126-
withElement[F].flatMap{ e =>
127-
Resource.make_[F, TestReactRoot](TestReactRoot(e), _.unmount[F]())
123+
withElementSync
124+
.mapResource(e => {
125+
val stop = ReactTestUtilsConfig.aroundReact.start()
126+
(e, stop)
127+
})(_._2())
128+
.mapResource(x => TestReactRoot(x._1))(_.unmountSync())
129+
130+
def withReactRoot[F[_]](implicit F: Async[F]): Resource[F, TestReactRoot] =
131+
withElement[F].flatMap { e =>
132+
Resource.make_[F, () => Unit](ReactTestUtilsConfig.aroundReact.start(), stop => F.delay(stop())).flatMap { _ =>
133+
Resource.make_[F, TestReactRoot](TestReactRoot(e), _.unmount[F]())
134+
}
128135
}
129136

130137
def withRenderedSync[A](unmounted: A): WithDsl[TestDomWithRoot, Renderable[A]] =

library/testUtil/src/main/scala/japgolly/scalajs/react/test/ReactTestUtilsConfig.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package japgolly.scalajs.react.test
22

33
import japgolly.scalajs.react.test.internal._
4+
import japgolly.scalajs.react.util.Effect.Async
5+
import scala.concurrent.ExecutionContext
6+
import scala.concurrent.Future
47

58
object ReactTestUtilsConfig extends ReactTestUtilsConfigTypes {
69

@@ -20,5 +23,22 @@ object ReactTestUtilsConfig extends ReactTestUtilsConfigTypes {
2023

2124
override def start(): () => Unit =
2225
value.start()
26+
27+
def async[F[_], A](body: F[A])(implicit F: Async[F]): F[A] = {
28+
val start = F.delay {
29+
val stop = ReactTestUtilsConfig.aroundReact.start()
30+
F.delay(stop())
31+
}
32+
F.flatMap(start) { stop =>
33+
F.finallyRun(body, stop)
34+
}
35+
}
36+
37+
def future[A](body: => Future[A])(implicit ec: ExecutionContext): Future[A] = {
38+
val stop = ReactTestUtilsConfig.aroundReact.start()
39+
val f = body
40+
f.onComplete { _ => stop() }
41+
f
42+
}
2343
}
2444
}

0 commit comments

Comments
 (0)