-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDomBehaviorTests.cs
More file actions
119 lines (98 loc) · 4.44 KB
/
DomBehaviorTests.cs
File metadata and controls
119 lines (98 loc) · 4.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
using Xunit;
using Abies.DOM;
using System.Linq;
using System.Collections.Generic;
using DOMAttribute = Abies.DOM.Attribute;
namespace Abies.Tests;
public class DomBehaviorTests
{
private record DummyMessage() : Message;
[Fact]
public void AddRoot_ShouldRenderCorrectly()
{
var newDom = new Element("1", "div", System.Array.Empty<DOMAttribute>(),
new Text("2", "Hello"));
var patches = Operations.Diff(null, newDom);
var result = ApplyPatches(null, patches, null);
Assert.Equal(Render.Html(newDom), Render.Html(result!));
}
[Fact]
public void ReplaceChild_ShouldUpdateTree()
{
var oldDom = new Element("1", "div", System.Array.Empty<DOMAttribute>(),
new Element("2", "span", System.Array.Empty<DOMAttribute>(), new Text("3", "Old")));
var newDom = new Element("1", "div", System.Array.Empty<DOMAttribute>(),
new Element("4", "p", System.Array.Empty<DOMAttribute>(), new Text("5", "New")));
var patches = Operations.Diff(oldDom, newDom);
var result = ApplyPatches(oldDom, patches, oldDom);
Assert.Equal(Render.Html(newDom), Render.Html(result));
}
[Fact]
public void AttributeChanges_ShouldReflectInResult()
{
var oldDom = new Element("1", "button",
new DOMAttribute[] { new DOMAttribute("a1", "class", "btn") },
System.Array.Empty<Node>());
var newDom = new Element("1", "button",
new DOMAttribute[]
{
new DOMAttribute("a1", "class", "btn-primary"),
new Handler("click", "cmd1", new DummyMessage(), "h1")
},
System.Array.Empty<Node>());
var patches = Operations.Diff(oldDom, newDom);
var result = ApplyPatches(oldDom, patches, oldDom);
Assert.Equal(Render.Html(newDom), Render.Html(result));
}
private static Node? ApplyPatches(Node? root, IEnumerable<Patch> patches, Node? initialRoot)
{
var current = root;
foreach (var patch in patches)
{
current = ApplyPatch(current, patch, initialRoot);
}
return current;
}
private static Node? ApplyPatch(Node? root, Patch patch, Node? initialRoot)
{
return patch switch
{
AddRoot ar => ar.Element,
ReplaceChild rc => ReplaceNode(root!, rc.OldElement, rc.NewElement),
AddChild ac => UpdateElement(root!, ac.Parent.Id, e => e with { Children = e.Children.Append(ac.Child).ToArray() }),
RemoveChild rc => UpdateElement(root!, rc.Parent.Id, e => e with { Children = e.Children.Where(c => c.Id != rc.Child.Id).ToArray() }),
UpdateAttribute ua => UpdateElement(root!, ua.Element.Id, e => e with { Attributes = e.Attributes.Select(a => a.Id == ua.Attribute.Id ? ua.Attribute with { Value = ua.Value } : a).ToArray() }),
AddAttribute aa => UpdateElement(root!, aa.Element.Id, e => e with { Attributes = e.Attributes.Append(aa.Attribute).ToArray() }),
RemoveAttribute ra => UpdateElement(root!, ra.Element.Id, e => e with { Attributes = e.Attributes.Where(a => a.Id != ra.Attribute.Id).ToArray() }),
AddHandler ah => UpdateElement(root!, ah.Element.Id, e => e with { Attributes = e.Attributes.Append(ah.Handler).ToArray() }),
RemoveHandler rh => UpdateElement(root!, rh.Element.Id, e => e with { Attributes = e.Attributes.Where(a => a.Id != rh.Handler.Id).ToArray() }),
UpdateText ut => ReplaceNode(root!, ut.Node, new Text(ut.Node.Id, ut.Text)),
_ => root
};
}
private static Node ReplaceNode(Node node, Node target, Node newNode)
{
if (ReferenceEquals(node, target) || node.Id == target.Id)
return newNode;
if (node is Element el)
{
var newChildren = el.Children.Select(c => ReplaceNode(c, target, newNode)).ToArray();
return el with { Children = newChildren };
}
return node;
}
private static Node UpdateElement(Node node, string targetId, System.Func<Element, Element> update)
{
if (node is Element el)
{
if (el.Id == targetId)
{
var updated = update(el);
return updated;
}
var newChildren = el.Children.Select(c => UpdateElement(c, targetId, update)).ToArray();
return el with { Children = newChildren };
}
return node;
}
}