From 7c254b6c614c81254843ccf9d26e4e72d227ae41 Mon Sep 17 00:00:00 2001
From: omochimetaru
Date: Mon, 15 Apr 2024 22:30:52 +0900
Subject: [PATCH] key match test by effect #28
---
.../React/Hooks/Context/ContextValue.swift | 6 +
Tests/ReactTests/KeyMatchTests.swift | 243 ++++++++++++++++++
Tests/ReactTests/RenderPlanTests.swift | 99 -------
Tests/ReactTests/RenderTests.swift | 51 ----
4 files changed, 249 insertions(+), 150 deletions(-)
create mode 100644 Tests/ReactTests/KeyMatchTests.swift
diff --git a/Sources/React/Hooks/Context/ContextValue.swift b/Sources/React/Hooks/Context/ContextValue.swift
index 8785c59..b788483 100644
--- a/Sources/React/Hooks/Context/ContextValue.swift
+++ b/Sources/React/Hooks/Context/ContextValue.swift
@@ -1,3 +1,9 @@
public protocol ContextValue: Hashable {
static var defaultValue: Self { get }
}
+
+extension ContextValue {
+ public static func undefinedDefault() -> Self {
+ fatalError("default value is undefined")
+ }
+}
diff --git a/Tests/ReactTests/KeyMatchTests.swift b/Tests/ReactTests/KeyMatchTests.swift
new file mode 100644
index 0000000..a2b1ae0
--- /dev/null
+++ b/Tests/ReactTests/KeyMatchTests.swift
@@ -0,0 +1,243 @@
+import XCTest
+import SRTTestSupport
+import SRTDOM
+import React
+
+final class KeyMatchTests: XCTestCase {
+ override func setUp() {
+ WebWindow.initializeJavaScriptKit()
+ document = JSWindow.global.document
+ }
+
+ var document: JSDocument!
+
+ func testTwinKeySwap() throws {
+ struct Section: Component {
+ var key: AnyHashable?
+
+ var id: Int
+
+ var deps: Deps? { [key, id] }
+
+ func render() -> Node {
+ return div {
+ "\(id)"
+ }
+ }
+ }
+
+ struct Content: Component {
+ var ids: [Int]
+
+ func render() -> Node {
+ ids.map { (id) in
+ Section(key: id, id: id)
+ }
+ }
+ }
+
+ let body = try document.createElement("body")
+ let root = ReactRoot(element: body)
+ root.render(node: Content(ids: [1, 2]))
+ XCTAssertPrint(root.dom, """
+
+
+ 1
+
+
+ 2
+
+
+ """)
+ root.render(node: Content(ids: [2, 1]))
+ XCTAssertPrint(root.dom, """
+
+
+ 2
+
+
+ 1
+
+
+ """)
+ }
+
+ func testMultiKeyMatchRender() throws {
+ struct Section: Component {
+ var key: AnyHashable?
+
+ var id: Int
+
+ var deps: Deps? { [key, id] }
+
+ func render() -> Node {
+ return div {
+ "\(id)"
+ }
+ }
+ }
+
+ struct Content: Component {
+ var ids: [Int]
+
+ func render() -> Node {
+ div {
+ ids.map { (id) in
+ Section(key: id, id: id)
+ }
+ }
+ }
+ }
+
+ var evs: [Int] = []
+
+ let body = try document.createElement("body")
+ let root = ReactRoot(element: body)
+ root.willComponentRender = { (c) in
+ switch c {
+ case let c as Section:
+ evs.append(c.id)
+ default: break
+ }
+ }
+ root.render(node: Content(ids: [1, 2, 3]))
+ XCTAssertPrint(root.dom, """
+
+
+
+ 1
+
+
+ 2
+
+
+ 3
+
+
+
+ """)
+ XCTAssertEqual(evs, [1, 2, 3])
+ evs = []
+
+ root.render(node: Content(ids: [2, 3, 4]))
+ XCTAssertEqual(evs, [4])
+ XCTAssertPrint(root.dom, """
+
+
+
+ 2
+
+
+ 3
+
+
+ 4
+
+
+
+ """)
+ evs = []
+
+ root.render(node: Content(ids: [5, 4, 3, 2]))
+ XCTAssertEqual(evs, [5])
+ XCTAssertPrint(root.dom, """
+
+
+
+ 5
+
+
+ 4
+
+
+ 3
+
+
+ 2
+
+
+
+ """)
+ evs = []
+ }
+
+ func testMultiKeyMatchEffect() throws {
+ struct Prove: ContextValue {
+ static var defaultValue: Prove = .undefinedDefault()
+
+ var onRender: Function
+ }
+
+ struct Section: Component {
+ var key: AnyHashable?
+
+ var id: Int
+
+ var deps: Deps? { [key, id] }
+
+ @Context var prove: Prove
+ @Effect var effect
+
+ func render() -> Node {
+ $effect {
+ prove.onRender("s\(id)")
+ return nil
+ }
+
+ return div {
+ "\(id)"
+ }
+ }
+ }
+
+ struct Content: Component {
+ var prove: Prove
+
+ var ids: [Int]
+
+ func render() -> Node {
+ Prove.Provider(value: prove) {
+ ids.map { (id) in
+ Section(key: id, id: id)
+ }
+ }
+ }
+ }
+
+ let body = try document.createElement("body")
+ let root = ReactRoot(element: body)
+ var evs: [String] = []
+ let prove = Prove(
+ onRender: Function {
+ evs.append($0)
+ }
+ )
+ root.render(
+ node: Content(
+ prove: prove,
+ ids: [1, 2, 3]
+ )
+ )
+ XCTAssertEqual(evs, ["s1", "s2", "s3"])
+ evs = []
+
+ root.render(
+ node: Content(
+ prove: prove,
+ ids: [1, 2, 3, 4]
+ )
+ )
+ XCTAssertEqual(evs, ["s4"])
+ evs = []
+
+ root.render(
+ node: Content(
+ prove: prove,
+ ids: [5, 4, 3]
+ )
+ )
+ XCTAssertEqual(evs, ["s5"])
+ evs = []
+ }
+}
+
diff --git a/Tests/ReactTests/RenderPlanTests.swift b/Tests/ReactTests/RenderPlanTests.swift
index 7e8120e..9ee73c1 100644
--- a/Tests/ReactTests/RenderPlanTests.swift
+++ b/Tests/ReactTests/RenderPlanTests.swift
@@ -293,103 +293,4 @@ final class RenderPlanTests: XCTestCase {
root.render(node: content)
XCTAssertEqual(renderCount, 1)
}
-
- func testKeySwapRender() throws {
- struct Section: Component {
- var key: AnyHashable?
-
- var id: Int
-
- var deps: Deps? { [key, id] }
-
- func render() -> Node {
- return div {
- "\(id)"
- }
- }
- }
-
- struct Content: Component {
- var ids: [Int]
-
- func render() -> Node {
- div {
- ids.map { (id) in
- Section(key: id, id: id)
- }
- }
- }
- }
-
- var evs: [Int] = []
-
- let body = try document.createElement("body")
- let root = ReactRoot(element: body)
- root.willComponentRender = { (c) in
- switch c {
- case let c as Section:
- evs.append(c.id)
- default: break
- }
- }
- root.render(node: Content(ids: [1, 2, 3]))
- XCTAssertPrint(root.dom, """
-
-
-
- 1
-
-
- 2
-
-
- 3
-
-
-
- """)
- XCTAssertEqual(evs, [1, 2, 3])
- evs = []
-
- root.render(node: Content(ids: [2, 3, 4]))
- XCTAssertEqual(evs, [4])
- XCTAssertPrint(root.dom, """
-
-
-
- 2
-
-
- 3
-
-
- 4
-
-
-
- """)
- evs = []
-
- root.render(node: Content(ids: [5, 4, 3, 2]))
- XCTAssertEqual(evs, [5])
- XCTAssertPrint(root.dom, """
-
-
-
- 5
-
-
- 4
-
-
- 3
-
-
- 2
-
-
-
- """)
- evs = []
- }
}
diff --git a/Tests/ReactTests/RenderTests.swift b/Tests/ReactTests/RenderTests.swift
index 2f0519d..e82d872 100644
--- a/Tests/ReactTests/RenderTests.swift
+++ b/Tests/ReactTests/RenderTests.swift
@@ -463,55 +463,4 @@ final class RenderTests: XCTestCase {
-
- 1
-
-
- 2
-
-
-
- 2
-
-
- 1
-
-