Files
kjol/bundler/compile_solid_test.go

117 lines
3.6 KiB
Go

package bundler
import "testing"
// parseOne parses a single JSX element starting at the first '<'.
func parseOne(t *testing.T, src string) jsxNode {
t.Helper()
i := 0
for i < len(src) && src[i] != '<' {
i++
}
node, next, err := parseJSX(src, i)
if err != nil {
t.Fatalf("parseJSX(%q): %v", src, err)
}
if next != len(src) {
t.Fatalf("parseJSX(%q): consumed to %d, want %d (trailing %q)", src, next, len(src), src[next:])
}
return node
}
func TestParseStaticElement(t *testing.T) {
n := parseOne(t, `<div class="x">hi</div>`)
if n.kind != jsxElement || n.tag != "div" {
t.Fatalf("kind/tag = %d/%q", n.kind, n.tag)
}
if len(n.attrs) != 1 || n.attrs[0].kind != attrStatic || n.attrs[0].name != "class" || n.attrs[0].value != "x" {
t.Fatalf("attrs = %+v", n.attrs)
}
if len(n.children) != 1 || n.children[0].kind != jsxText || n.children[0].text != "hi" {
t.Fatalf("children = %+v", n.children)
}
}
func TestParseComponent(t *testing.T) {
n := parseOne(t, `<Foo bar={1}>child</Foo>`)
if n.kind != jsxComponent || n.tag != "Foo" {
t.Fatalf("kind/tag = %d/%q", n.kind, n.tag)
}
if len(n.attrs) != 1 || n.attrs[0].kind != attrExpr || n.attrs[0].name != "bar" || n.attrs[0].expr != "1" {
t.Fatalf("attrs = %+v", n.attrs)
}
}
func TestParseNested(t *testing.T) {
n := parseOne(t, `<div><span>a</span><b>{x()}</b></div>`)
if len(n.children) != 2 {
t.Fatalf("want 2 element children, got %d: %+v", len(n.children), n.children)
}
if n.children[0].tag != "span" || n.children[1].tag != "b" {
t.Fatalf("child tags = %q, %q", n.children[0].tag, n.children[1].tag)
}
b := n.children[1]
if len(b.children) != 1 || b.children[0].kind != jsxExpr || b.children[0].expr != "x()" {
t.Fatalf("b children = %+v", b.children)
}
}
func TestParseFragment(t *testing.T) {
n := parseOne(t, `<>{a()}{b()}</>`)
if n.kind != jsxFragment || len(n.children) != 2 {
t.Fatalf("fragment: kind=%d children=%d", n.kind, len(n.children))
}
if n.children[0].expr != "a()" || n.children[1].expr != "b()" {
t.Fatalf("fragment children = %+v", n.children)
}
}
func TestParseSelfCloseAndBool(t *testing.T) {
n := parseOne(t, `<input disabled type="text" />`)
if n.tag != "input" || len(n.children) != 0 {
t.Fatalf("input: tag=%q children=%d", n.tag, len(n.children))
}
if len(n.attrs) != 2 || !n.attrs[0].boolt || n.attrs[0].name != "disabled" {
t.Fatalf("attrs = %+v", n.attrs)
}
if n.attrs[1].name != "type" || n.attrs[1].value != "text" {
t.Fatalf("type attr = %+v", n.attrs[1])
}
}
func TestParseSpread(t *testing.T) {
n := parseOne(t, `<div {...p} class="x">hi</div>`)
if len(n.attrs) != 2 || n.attrs[0].kind != attrSpread || n.attrs[0].expr != "p" {
t.Fatalf("attrs = %+v", n.attrs)
}
}
// The hardest case: an expression child containing nested JSX AND braces inside
// strings/templates. The parser must capture the whole expression opaquely.
func TestParseExprWithNestedJSX(t *testing.T) {
n := parseOne(t, "<ul>{items.map((x) => <li>{x}</li>)}</ul>")
if len(n.children) != 1 || n.children[0].kind != jsxExpr {
t.Fatalf("children = %+v", n.children)
}
if n.children[0].expr != "items.map((x) => <li>{x}</li>)" {
t.Fatalf("expr = %q", n.children[0].expr)
}
}
func TestCaptureBracesLexer(t *testing.T) {
cases := []struct{ in, want string }{
{`{a + "}" + b}`, `a + "}" + b`},
{"{`a${nested}b`}", "`a${nested}b`"},
{`{ {k: 1} }`, ` {k: 1} `},
{`{f(/[}]/)}`, `f(/[}]/)`},
{`{x} rest`, `x`},
}
for _, c := range cases {
got, next := captureBraces(c.in, 0)
if got != c.want {
t.Errorf("captureBraces(%q) = %q, want %q", c.in, got, c.want)
}
_ = next
}
}