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 { """) } - - func testKeySwap() 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 -
- - """) - } }