Skip to content

Commit

Permalink
have errors return empty objects, not nothing
Browse files Browse the repository at this point in the history
a few attributes the write json values swallow errors. these should return at least an empty
object, so its easier to see that the attribute was rendered but failed.

also add tests for all untested attributes
will-wow committed Mar 13, 2024
1 parent 3d141e4 commit f608a4d
Showing 13 changed files with 167 additions and 75 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
node_modules
coverage
task
.task
1 change: 0 additions & 1 deletion .task/checksum/examples-gen

This file was deleted.

2 changes: 1 addition & 1 deletion assets/badge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 0 additions & 2 deletions examples/web/activesearch/extempl/activesearch.templ
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@ import (
"github.com/will-wow/typed-htmx-go/examples/web/exprint"
"github.com/will-wow/typed-htmx-go/htmx"
"github.com/will-wow/typed-htmx-go/htmx/trigger"
"github.com/will-wow/typed-htmx-go/htmx/swap"
"time"
)

@@ -67,7 +66,6 @@ templ search() {
trigger.On("search"),
)... }
{ hx.Target("#search-results")... }
{ hx.Swap(swap.OuterHTML)... }
{ hx.Indicator(".htmx-indicator")... }
/>
<table>
13 changes: 4 additions & 9 deletions examples/web/activesearch/extempl/activesearch_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions htmx/config.go
Original file line number Diff line number Diff line change
@@ -22,8 +22,7 @@ func (hx *HX[T]) Config(config *hxconfig.Builder) T {
c := config.Build()
bytes, err := json.Marshal(c)
if err != nil {
var empty T
return empty
return hx.attr("content", "{}")
}
return hx.attr("content", string(bytes))
}
46 changes: 46 additions & 0 deletions htmx/gomponents_test.go
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ package htmx_test

import (
"os"
"strings"
"testing"

g "github.com/maragudk/gomponents"
@@ -41,3 +42,48 @@ func ExampleNewGomponents() {
_ = component.Render(os.Stdout)
// Output: <form hx-boost="true" hx-post="/submit" hx-swap="outerHTML" id="form"><input name="firstName"><button type="submit">Submit</button></form>
}

func TestRender(t *testing.T) {
tests := []struct {
name string
node htmx.GomponentsAttrs
want string
}{
{
name: "string value",
node: gomHx.Boost(true),
want: ` hx-boost="true"`,
},
{
name: "bool value",
node: gomHx.Preserve(),
want: ` hx-preserve`,
},
{
name: "invalid value",
node: htmx.GomponentsAttrs{},
want: ``,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Check that render renders the expected value to a writer.
builder := strings.Builder{}
err := tt.node.Render(&builder)
if err != nil {
t.Errorf("got error %v, want %s", err, tt.want)
}
got := builder.String()
if got != tt.want {
t.Errorf("got %s, want %s", got, tt.want)
}
// Check that .String() returns the same expected value.
string := tt.node.String()
if string != tt.want {
t.Errorf("for String got %s, want %s", string, tt.want)
}
})
}

}
18 changes: 8 additions & 10 deletions htmx/htmx.go
Original file line number Diff line number Diff line change
@@ -543,8 +543,7 @@ func (hx *HX[T]) Vals(vals any) T {
json, err := json.Marshal(vals)
if err != nil {
// Silently ignore the value if there is an error, because there's not a good way to report an error when constructing templ attributes.
var empty T
return empty
return hx.attr(Vals, "{}")
}
return hx.attr(Vals, string(json))
}
@@ -810,9 +809,8 @@ func (hx *HX[T]) ExtIgnore(ext string) T {
func (hx *HX[T]) Headers(headers any) T {
json, err := json.Marshal(headers)
if err != nil {
// Silently ignore the value if there is an error, because there's not a good way to report an error when constructing templ attributes.
var empty T
return empty
// Silently ignore the value if there is an error, because there's not a good way to report an error when constructing attributes.
return hx.attr(Headers, "{}")
}
return hx.attr(Headers, string(json))
}
@@ -1070,10 +1068,10 @@ func (r RequestConfig) String() string {
opts = append(opts, fmt.Sprintf(`"timeout":%d`, r.Timeout.Milliseconds()))
}
if r.Credentials {
opts = append(opts, `"credentials": true`)
opts = append(opts, `"credentials":true`)
}
if r.NoHeaders {
opts = append(opts, `"noHeaders": true`)
opts = append(opts, `"noHeaders":true`)
}

return strings.Join(opts, ",")
@@ -1101,13 +1099,13 @@ func (r RequestConfigJS) String() string {
opts := []string{}

if r.Timeout != "" {
opts = append(opts, fmt.Sprintf(`"timeout":%s`, r.Timeout))
opts = append(opts, fmt.Sprintf(`timeout:%s`, r.Timeout))
}
if r.Credentials != "" {
opts = append(opts, fmt.Sprintf(`"credentials": %s`, r.Credentials))
opts = append(opts, fmt.Sprintf(`credentials:%s`, r.Credentials))
}
if r.NoHeaders != "" {
opts = append(opts, fmt.Sprintf(`"noHeaders": %s`, r.NoHeaders))
opts = append(opts, fmt.Sprintf(`noHeaders:%s`, r.NoHeaders))
}

value := strings.Join(opts, ",")
72 changes: 53 additions & 19 deletions htmx/htmx_test.go
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ import (
"fmt"
"time"

base "github.com/will-wow/typed-htmx-go/htmx"
"github.com/will-wow/typed-htmx-go/htmx"
"github.com/will-wow/typed-htmx-go/htmx/on"
"github.com/will-wow/typed-htmx-go/htmx/swap"
"github.com/will-wow/typed-htmx-go/htmx/trigger"
@@ -29,11 +29,11 @@ func (a Attrs) String() string {
return ""
}

var hx = base.NewHX(func(key base.Attribute, value any) Attrs {
var hx = htmx.NewHX(func(key htmx.Attribute, value any) Attrs {
return Attrs{string(key): value}
})

type HX = base.HX[Attrs]
type HX = htmx.HX[Attrs]

func ExampleHX_Boost() {
fmt.Println(hx.Boost(true))
@@ -81,8 +81,8 @@ func ExampleHX_SelectOOB() {

func ExampleHX_SelectOOBWithStrategy() {
fmt.Println(hx.SelectOOBWithStrategy(
base.SelectOOBStrategy{Selector: "#info-details", Strategy: swap.AfterBegin},
base.SelectOOBStrategy{Selector: "#other-details", Strategy: ""},
htmx.SelectOOBStrategy{Selector: "#info-details", Strategy: swap.AfterBegin},
htmx.SelectOOBStrategy{Selector: "#other-details", Strategy: ""},
))
// Output: hx-select-oob='#info-details:afterbegin,#other-details'
}
@@ -123,13 +123,13 @@ func ExampleHX_Target() {
}

func ExampleHX_Target_nonStandard() {
fmt.Println(hx.Target(base.TargetThis))
fmt.Println(hx.Target(htmx.TargetThis))
// Output: hx-target='this'
}

func ExampleHX_Target_relativeSelector() {
fmt.Println(hx.Target(
base.TargetRelative(base.Closest, "#example"),
htmx.TargetRelative(htmx.Closest, "#example"),
))
// Output: hx-target='closest #example'
}
@@ -158,6 +158,17 @@ func ExampleHX_Vals() {
// Output: hx-vals='{"one":1,"two":2}'
}

func ExampleHX_Vals_error() {
fmt.Println(hx.Vals(func() {}))
// Output: hx-vals='{}'
}

func ExampleHX_Vals_invalid() {
// You would expect this to be an error, but `Vals` doesn't check the type of the value for performance reasons.
fmt.Println(hx.Vals(0))
// Output: hx-vals='0'
}

func ExampleHX_ValsJS() {
fmt.Println(hx.ValsJS(map[string]string{"lastKey": "event.key"}))
// Output: hx-vals='js:{lastKey:event.key}'
@@ -190,18 +201,18 @@ func ExampleHX_DisabledElt() {

func ExampleHX_DisabledElt_relative() {
fmt.Println(hx.DisabledElt(
base.DisabledEltRelative(base.DisabledEltClosest, "#example"),
htmx.DisabledEltRelative(htmx.DisabledEltClosest, "#example"),
))
// Output: hx-disabled-elt='closest #example'
}

func ExampleHX_DisabledElt_this() {
fmt.Println(hx.DisabledElt(base.DisabledEltThis))
fmt.Println(hx.DisabledElt(htmx.DisabledEltThis))
// Output: hx-disabled-elt='this'
}

func ExampleHX_Disinherit() {
fmt.Println(hx.Disinherit(base.Get, base.Boost))
fmt.Println(hx.Disinherit(htmx.Get, htmx.Boost))
// Output: hx-disinherit='hx-get hx-boost'
}

@@ -211,7 +222,7 @@ func ExampleHX_DisinheritAll() {
}

func ExampleHX_Encoding() {
fmt.Println(hx.Encoding(base.EncodingMultipart))
fmt.Println(hx.Encoding(htmx.EncodingMultipart))
// Output: hx-encoding='multipart/form-data'
}

@@ -230,6 +241,11 @@ func ExampleHX_Headers() {
// Output: hx-headers='{"Content-Type":"application/json"}'
}

func ExampleHX_Headers_error() {
fmt.Println(hx.Headers(func() {}))
// Output: hx-headers='{}'
}

func ExampleHX_HeadersJS() {
fmt.Println(hx.HeadersJS(map[string]string{"Content-Type": "getContentType()"}))
// Output: hx-headers='js:{"Content-Type":getContentType()}'
@@ -256,13 +272,13 @@ func ExampleHX_Include() {
}

func ExampleHX_Include_this() {
fmt.Println(hx.Include(base.IncludeThis))
fmt.Println(hx.Include(htmx.IncludeThis))
// Output: hx-include='this'
}

func ExampleHX_Include_relative() {
fmt.Println(hx.Include(
base.IncludeRelative(base.Closest, "#example"),
htmx.IncludeRelative(htmx.Closest, "#example"),
))
// Output: hx-include='closest #example'
}
@@ -274,7 +290,7 @@ func ExampleHX_Indicator() {

func ExampleHX_Indicator_relative() {
fmt.Println(hx.Indicator(
base.IndicatorRelative(base.IndicatorClosest, "#example"),
htmx.IndicatorRelative(htmx.IndicatorClosest, "#example"),
))
// Output: hx-indicator='closest #example'
}
@@ -329,20 +345,38 @@ func ExampleHX_ReplaceURLWith() {
// Output: hx-replace-url='/example'
}

func ExampleHX_Request() {
fmt.Println(hx.Request(htmx.RequestConfig{
Timeout: time.Second,
Credentials: true,
NoHeaders: true,
}))
// Output: hx-request='"timeout":1000,"credentials":true,"noHeaders":true'
}

func ExampleHX_RequestJS() {
fmt.Println(hx.RequestJS(htmx.RequestConfigJS{
Timeout: "getTimeoutSetting()",
Credentials: "true",
NoHeaders: "noHeaders()",
}))
// Output: hx-request='js: timeout:getTimeoutSetting(),credentials:true,noHeaders:noHeaders()'
}

func ExampleHX_Sync() {
fmt.Println(hx.Sync(base.SyncThis))
fmt.Println(hx.Sync(htmx.SyncThis))
// Output: hx-sync='this'
}

func ExampleHX_SyncStrategy() {
fmt.Println(hx.SyncStrategy(base.SyncThis, base.SyncDrop))
fmt.Println(hx.SyncStrategy(htmx.SyncThis, htmx.SyncDrop))
// Output: hx-sync='this:drop'
}

func ExampleHX_SyncStrategy_relative() {
fmt.Println(hx.SyncStrategy(
base.SyncRelative(base.Closest, "#example"),
base.SyncDrop,
htmx.SyncRelative(htmx.Closest, "#example"),
htmx.SyncDrop,
))
// Output: hx-sync='closest #example:drop'
}
@@ -353,6 +387,6 @@ func ExampleHX_Validate() {
}

func ExampleHX_Unset() {
fmt.Println(hx.Unset(base.Boost))
fmt.Println(hx.Unset(htmx.Boost))
// Output: hx-boost='unset'
}
Loading

0 comments on commit f608a4d

Please sign in to comment.