waveterm/pkg/vdom/vdom_test.go
Mike Sawka 91c293e4be
VDom 8 (#1202)
* new vdomevents to support click, change, keydown, etc. easier type
signature
* can now pass a prop type instead of always converting to
map[string]any
* implement DefineComponent to allow easier vdom creation using a
component function directly
* separate vdomclient Make from Connect
* lots of bug fixes to get everything working again
* PStyle and special "style" attribute handling
2024-11-04 12:52:36 -08:00

186 lines
4.3 KiB
Go

package vdom
import (
"context"
"encoding/json"
"fmt"
"log"
"reflect"
"testing"
"github.com/wavetermdev/waveterm/pkg/util/utilfn"
)
type renderContextKeyType struct{}
var renderContextKey = renderContextKeyType{}
type TestContext struct {
ButtonId string
}
func Page(ctx context.Context, props map[string]any) any {
clicked, setClicked := UseState(ctx, false)
var clickedDiv *VDomElem
if clicked {
clickedDiv = Bind(`<div>clicked</div>`, nil)
}
clickFn := func() {
log.Printf("run clickFn\n")
setClicked(true)
}
return Bind(
`
<div>
<h1>hello world</h1>
<Button onClick="#param:clickFn">hello</Button>
<bindparam key="clickedDiv"/>
</div>
`,
map[string]any{"clickFn": clickFn, "clickedDiv": clickedDiv},
)
}
func Button(ctx context.Context, props map[string]any) any {
ref := UseVDomRef(ctx)
clName, setClName := UseState(ctx, "button")
UseEffect(ctx, func() func() {
fmt.Printf("Button useEffect\n")
setClName("button mounted")
return nil
}, nil)
compId := UseId(ctx)
testContext := getTestContext(ctx)
if testContext != nil {
testContext.ButtonId = compId
}
return Bind(`
<div className="#param:clName" ref="#param:ref" onClick="#param:onClick">
<bindparam key="children"/>
</div>
`, map[string]any{"clName": clName, "ref": ref, "onClick": props["onClick"], "children": props["children"]})
}
func printVDom(root *RootElem) {
vd := root.MakeVDom()
jsonBytes, _ := json.MarshalIndent(vd, "", " ")
fmt.Printf("%s\n", string(jsonBytes))
}
func getTestContext(ctx context.Context) *TestContext {
val := ctx.Value(renderContextKey)
if val == nil {
return nil
}
return val.(*TestContext)
}
func Test1(t *testing.T) {
log.Printf("hello!\n")
testContext := &TestContext{ButtonId: ""}
ctx := context.WithValue(context.Background(), renderContextKey, testContext)
root := MakeRoot()
root.SetOuterCtx(ctx)
root.RegisterComponent("Page", Page)
root.RegisterComponent("Button", Button)
root.Render(E("Page"))
if root.Root == nil {
t.Fatalf("root.Root is nil")
}
printVDom(root)
root.RunWork()
printVDom(root)
root.Event(testContext.ButtonId, "onClick", VDomEvent{EventType: "onClick"})
root.RunWork()
printVDom(root)
}
func TestBind(t *testing.T) {
elem := Bind(`<div>clicked</div>`, nil)
jsonBytes, _ := json.MarshalIndent(elem, "", " ")
log.Printf("%s\n", string(jsonBytes))
elem = Bind(`
<div>
clicked
</div>`, nil)
jsonBytes, _ = json.MarshalIndent(elem, "", " ")
log.Printf("%s\n", string(jsonBytes))
elem = Bind(`<Button>foo</Button>`, nil)
jsonBytes, _ = json.MarshalIndent(elem, "", " ")
log.Printf("%s\n", string(jsonBytes))
elem = Bind(`
<div>
<h1>hello world</h1>
<Button onClick="#param:clickFn">hello</Button>
<bindparam key="clickedDiv"/>
</div>
`, nil)
jsonBytes, _ = json.MarshalIndent(elem, "", " ")
log.Printf("%s\n", string(jsonBytes))
}
func TestJsonBind(t *testing.T) {
elem := Bind(`<div data1={5} data2={[1,2,3]} data3={{"a": 1}}/>`, nil)
if elem == nil {
t.Fatalf("elem is nil")
}
if elem.Tag != "div" {
t.Fatalf("elem.Tag: %s (expected 'div')\n", elem.Tag)
}
if elem.Props == nil || len(elem.Props) != 3 {
t.Fatalf("elem.Props: %v\n", elem.Props)
}
data1Val, ok := elem.Props["data1"]
if !ok {
t.Fatalf("data1 not found\n")
}
_, ok = data1Val.(float64)
if !ok {
t.Fatalf("data1: %T\n", data1Val)
}
data1Int, ok := utilfn.ToInt(data1Val)
if !ok || data1Int != 5 {
t.Fatalf("data1: %v\n", data1Val)
}
data2Val, ok := elem.Props["data2"]
if !ok {
t.Fatalf("data2 not found\n")
}
d2type := reflect.TypeOf(data2Val)
if d2type.Kind() != reflect.Slice {
t.Fatalf("data2: %T\n", data2Val)
}
data2Arr := data2Val.([]any)
if len(data2Arr) != 3 {
t.Fatalf("data2: %v\n", data2Val)
}
d2v2, ok := data2Arr[1].(float64)
if !ok || d2v2 != 2 {
t.Fatalf("data2: %v\n", data2Val)
}
data3Val, ok := elem.Props["data3"]
if !ok || data3Val == nil {
t.Fatalf("data3 not found\n")
}
d3type := reflect.TypeOf(data3Val)
if d3type.Kind() != reflect.Map {
t.Fatalf("data3: %T\n", data3Val)
}
data3Map := data3Val.(map[string]any)
if len(data3Map) != 1 {
t.Fatalf("data3: %v\n", data3Val)
}
d3v1, ok := data3Map["a"]
if !ok {
t.Fatalf("data3: %v\n", data3Val)
}
mval, ok := utilfn.ToInt(d3v1)
if !ok || mval != 1 {
t.Fatalf("data3: %v\n", data3Val)
}
log.Printf("elem: %v\n", elem)
}