~repos /gromer

#golang#htmx#ssr

git clone https://pyrossh.dev/repos/gromer.git

gromer is a framework and cli to build multipage web apps in golang using htmx and alpinejs.


e218d833 pyros2097

4 years ago
reduce more deps
Files changed (11) hide show
  1. app_nowasm.go +1 -2
  2. app_wasm.go +1 -1
  3. js/js.go +7 -2
  4. js/js_nowasm.go +0 -12
  5. js/js_wasm.go +13 -18
  6. log.go +0 -48
  7. router.go +5 -28
  8. storage_wasm.go +1 -16
  9. testing.go +268 -268
  10. testing_test.go +38 -38
  11. utils.go +16 -0
app_nowasm.go CHANGED
@@ -3,7 +3,6 @@
3
3
  package app
4
4
 
5
5
  import (
6
- "fmt"
7
6
  "io"
8
7
  "net/http"
9
8
  "os"
@@ -19,7 +18,7 @@ func Run() {
19
18
  if !isLambda {
20
19
  wd, err := os.Getwd()
21
20
  if err != nil {
22
- fmt.Printf("could not get wd")
21
+ println("could not get wd")
23
22
  return
24
23
  }
25
24
  assetsFS := http.FileServer(pkger.Dir(filepath.Join(wd, "assets")))
app_wasm.go CHANGED
@@ -8,7 +8,7 @@ import (
8
8
  )
9
9
 
10
10
  func Run() {
11
- handle, _, _ := AppRouter.Lookup("GET", js.Window.URL().Path)
11
+ handle, _, _ := AppRouter.Lookup("GET", js.Window.Location().Pathname)
12
12
  if handle == nil {
13
13
  renderFunc = AppRouter.NotFound
14
14
  } else {
js/js.go CHANGED
@@ -2,7 +2,6 @@ package js
2
2
 
3
3
  import (
4
4
  "fmt"
5
- "net/url"
6
5
  )
7
6
 
8
7
  // Type represents the JavaScript type of a Value.
@@ -175,7 +174,7 @@ type BrowserWindow interface {
175
174
  Value
176
175
 
177
176
  // The window current url (window.location.href).
178
- URL() *url.URL
177
+ URL() string
179
178
 
180
179
  // The window size.
181
180
  Size() (w, h int)
@@ -250,3 +249,9 @@ func (h EventHandler) Equal(o EventHandler) bool {
250
249
  return h.Event == o.Event &&
251
250
  fmt.Sprintf("%p", h.Value) == fmt.Sprintf("%p", o.Value)
252
251
  }
252
+
253
+ type Location struct {
254
+ value Value
255
+ Href string
256
+ Pathname string
257
+ }
js/js_nowasm.go CHANGED
@@ -2,10 +2,6 @@
2
2
 
3
3
  package js
4
4
 
5
- import (
6
- "net/url"
7
- )
8
-
9
5
  var Window = &browserWindow{value: value{}}
10
6
 
11
7
  type value struct{}
@@ -106,10 +102,6 @@ type browserWindow struct {
106
102
  value
107
103
  }
108
104
 
109
- func (w browserWindow) URL() *url.URL {
110
- panic("wasm required")
111
- }
112
-
113
105
  func (w browserWindow) Size() (width, height int) {
114
106
  panic("wasm required")
115
107
  }
@@ -146,10 +138,6 @@ func copyBytesToJS(dst Value, src []byte) int {
146
138
  panic("wasm required")
147
139
  }
148
140
 
149
- type Location struct {
150
- value
151
- }
152
-
153
141
  func (l *Location) Reload() {
154
142
  panic("wasm required")
155
143
  }
js/js_wasm.go CHANGED
@@ -2,8 +2,6 @@
2
2
  package js
3
3
 
4
4
  import (
5
- "net/url"
6
- "reflect"
7
5
  "syscall/js"
8
6
  )
9
7
 
@@ -112,16 +110,6 @@ type browserWindow struct {
112
110
  cursorY int
113
111
  }
114
112
 
115
- func (w *browserWindow) URL() *url.URL {
116
- rawurl := w.
117
- Get("location").
118
- Get("href").
119
- String()
120
-
121
- u, _ := url.Parse(rawurl)
122
- return u
123
- }
124
-
125
113
  func (w *browserWindow) Size() (width int, height int) {
126
114
  getSize := func(axis string) int {
127
115
  size := w.Get("inner" + axis)
@@ -177,11 +165,17 @@ func (w *browserWindow) AddEventListener(event string, h EventHandler) func() {
177
165
  }
178
166
 
179
167
  func (w *browserWindow) Location() *Location {
168
+ return &Location{
180
- return &Location{value: Window.Get("location")}
169
+ value: w.Get("location"),
170
+ Href: w.
171
+ Get("location").
172
+ Get("href").
173
+ String(),
174
+ Pathname: w.
175
+ Get("location").
176
+ Get("pathname").
177
+ String(),
181
- }
178
+ }
182
-
183
- type Location struct {
184
- value Value
185
179
  }
186
180
 
187
181
  func (l *Location) Reload() {
@@ -207,7 +201,8 @@ func jsval(v Value) js.Value {
207
201
  return jsval(v.Value)
208
202
 
209
203
  default:
204
+ // + reflect.TypeOf(v).String()
210
- println("syscall/js value conversion failed type: " + reflect.TypeOf(v).String())
205
+ println("syscall/js value conversion failed type: ", v)
211
206
  return js.Undefined()
212
207
  }
213
208
  }
log.go DELETED
@@ -1,48 +0,0 @@
1
- package app
2
-
3
- import (
4
- "fmt"
5
- "runtime"
6
- )
7
-
8
- var (
9
- // DefaultLogger is the logger used to log info and errors.
10
- DefaultLogger func(format string, v ...interface{}) = log
11
-
12
- defaultColor string
13
- errorColor string
14
- infoColor string
15
- )
16
-
17
- func init() {
18
- switch runtime.GOARCH {
19
- case "wasm", "window":
20
- default:
21
- defaultColor = "\033[00m"
22
- errorColor = "\033[91m"
23
- infoColor = "\033[94m"
24
- }
25
- }
26
-
27
- // Log logs according to a format specifier using the default logger.
28
- func Log(format string, v ...interface{}) {
29
- DefaultLogger(format, v...)
30
- }
31
-
32
- func log(format string, v ...interface{}) {
33
- errorLevel := false
34
-
35
- for _, a := range v {
36
- if _, ok := a.(error); ok {
37
- errorLevel = true
38
- break
39
- }
40
- }
41
-
42
- if errorLevel {
43
- fmt.Printf(errorColor+"ERROR ‣ "+defaultColor+format+"\n", v...)
44
- return
45
- }
46
-
47
- fmt.Printf(infoColor+"INFO ‣ "+defaultColor+format+"\n", v...)
48
- }
router.go CHANGED
@@ -5,7 +5,6 @@ import (
5
5
  "context"
6
6
  "net/http"
7
7
  "strings"
8
- "sync"
9
8
  "unicode"
10
9
  "unicode/utf8"
11
10
 
@@ -719,9 +718,8 @@ func ParamsFromContext(ctx context.Context) Params {
719
718
  // Router is a http.Handler which can be used to dispatch requests to different
720
719
  // handler functions via configurable routes
721
720
  type Router struct {
722
- trees map[string]*node
721
+ trees map[string]*node
723
- paramsPool sync.Pool
724
- maxParams uint16
722
+ maxParams uint16
725
723
  // Enables automatic redirection if the current route can't be matched but a
726
724
  // handler for the path with (without) the trailing slash exists.
727
725
  // For example if /foo/ is requested but a route only exists for /foo, the
@@ -763,18 +761,6 @@ var AppRouter = &Router{
763
761
  },
764
762
  }
765
763
 
766
- func (r *Router) getParams() *Params {
767
- ps, _ := r.paramsPool.Get().(*Params)
768
- *ps = (*ps)[0:0] // reset slice
769
- return ps
770
- }
771
-
772
- func (r *Router) putParams(ps *Params) {
773
- if ps != nil {
774
- r.paramsPool.Put(ps)
775
- }
776
- }
777
-
778
764
  // GET is a shortcut for router.Handle(http.MethodGet, path, handle)
779
765
  func (r *Router) GET(path string, handle interface{}) {
780
766
  r.Handle(http.MethodGet, path, handle)
@@ -836,14 +822,6 @@ func (r *Router) Handle(method, path string, handle interface{}) {
836
822
  if paramsCount := countParams(path); paramsCount+varsCount > r.maxParams {
837
823
  r.maxParams = paramsCount + varsCount
838
824
  }
839
-
840
- // Lazy-init paramsPool alloc func
841
- if r.paramsPool.New == nil && r.maxParams > 0 {
842
- r.paramsPool.New = func() interface{} {
843
- ps := make(Params, 0, r.maxParams)
844
- return &ps
845
- }
846
- }
847
825
  }
848
826
 
849
827
  // Lookup allows the manual lookup of a method + path combo.
@@ -853,9 +831,8 @@ func (r *Router) Handle(method, path string, handle interface{}) {
853
831
  // the same path with an extra / without the trailing slash should be performed.
854
832
  func (r *Router) Lookup(method, path string) (interface{}, Params, bool) {
855
833
  if root := r.trees[method]; root != nil {
856
- handle, ps, tsr := root.getValue(path, r.getParams)
834
+ handle, ps, tsr := root.getValue(path, nil)
857
835
  if handle == nil {
858
- r.putParams(ps)
859
836
  return nil, nil, tsr
860
837
  }
861
838
  if ps == nil {
@@ -891,7 +868,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
891
868
 
892
869
  if root := r.trees[req.Method]; root != nil {
893
870
  // TODO: use _ ps save it to context for useParam()
894
- if handle, _, tsr := root.getValue(path, r.getParams); handle != nil {
871
+ if handle, _, tsr := root.getValue(path, nil); handle != nil {
895
872
  if render, ok := handle.(RenderFunc); ok {
896
873
  w.Header().Set("Content-Type", "text/html")
897
874
  w.WriteHeader(http.StatusOK)
@@ -957,7 +934,7 @@ func (r *Router) Lambda(ctx context.Context, e events.APIGatewayV2HTTPRequest) (
957
934
  println("route: " + e.RawPath)
958
935
  path := strings.Replace(e.RawPath, "/Prod/", "/", 1)
959
936
  if root := r.trees[e.RequestContext.HTTP.Method]; root != nil {
960
- if handle, _, _ := root.getValue(path, r.getParams); handle != nil {
937
+ if handle, _, _ := root.getValue(path, nil); handle != nil {
961
938
  res.Body = r.getPage(handle.(RenderFunc)(NewRenderContext()))
962
939
  return
963
940
  }
storage_wasm.go CHANGED
@@ -2,7 +2,6 @@ package app
2
2
 
3
3
  import (
4
4
  "encoding/json"
5
- "sync"
6
5
 
7
6
  "github.com/pyros2097/wapp/js"
8
7
  )
@@ -13,8 +12,7 @@ func init() {
13
12
  }
14
13
 
15
14
  type jsStorage struct {
16
- name string
15
+ name string
17
- mutex sync.RWMutex
18
16
  }
19
17
 
20
18
  func newJSStorage(name string) *jsStorage {
@@ -28,10 +26,6 @@ func (s *jsStorage) Set(k string, v interface{}) (err error) {
28
26
  panic("setting storage value failed storage-type: " + s.name + "key " + k)
29
27
  }
30
28
  }()
31
-
32
- s.mutex.Lock()
33
- defer s.mutex.Unlock()
34
-
35
29
  b, err := json.Marshal(v)
36
30
  if err != nil {
37
31
  return err
@@ -42,9 +36,6 @@ func (s *jsStorage) Set(k string, v interface{}) (err error) {
42
36
  }
43
37
 
44
38
  func (s *jsStorage) Get(k string, v interface{}) error {
45
- s.mutex.RLock()
46
- defer s.mutex.RUnlock()
47
-
48
39
  item := js.Window.Get(s.name).Call("getItem", k)
49
40
  if !item.Truthy() {
50
41
  return nil
@@ -54,15 +45,9 @@ func (s *jsStorage) Get(k string, v interface{}) error {
54
45
  }
55
46
 
56
47
  func (s *jsStorage) Del(k string) {
57
- s.mutex.Lock()
58
- defer s.mutex.Unlock()
59
-
60
48
  js.Window.Get(s.name).Call("removeItem", k)
61
49
  }
62
50
 
63
51
  func (s *jsStorage) Clear() {
64
- s.mutex.Lock()
65
- defer s.mutex.Unlock()
66
-
67
52
  js.Window.Get(s.name).Call("clear")
68
53
  }
testing.go CHANGED
@@ -1,283 +1,283 @@
1
1
  package app
2
2
 
3
- import (
4
- "fmt"
5
-
6
- "github.com/pyros2097/wapp/errors"
7
- )
8
-
9
- // TestUIDescriptor represents a descriptor that describes a UI element and its
10
- // location from its parents.
11
- type TestUIDescriptor struct {
12
- // The location of the node. It is used by the TestMatch to find the
13
- // element to test.
14
- //
15
- // If empty, the expected UI element is compared with the root of the tree.
16
- //
17
- // Otherwise, each integer represents the index of the element to traverse,
18
- // from the root's children to the element to compare
19
- Path []int
20
-
21
- // The element to compare with the element targeted by Path. Compare
22
- // behavior varies depending on the element kind.
23
- //
24
- // Simple text elements only have their text value compared.
25
- //
26
- // HTML elements have their attribute compared and check if their event
27
- // handlers are set.
28
- //
29
- // Components have their exported field values compared.
30
- Expected UI
31
- }
32
-
33
- // TestPath is a helper function that returns a path to use in a
34
- // TestUIDescriptor.
35
- func TestPath(p ...int) []int {
36
- return p
37
- }
38
-
39
- // TestMatch looks for the element targeted by the descriptor in the given tree
40
- // and reports whether it matches with the expected element.
41
- //
42
- // Eg:
43
- // tree := app.Div().Body(
44
- // app.H2().Body(
45
- // app.Text("foo"),
46
- // ),
47
- // app.P().Body(
48
- // app.Text("bar"),
49
- // ),
50
- // )
51
- //
52
- // // Testing root:
53
- // err := app.TestMatch(tree, app.TestUIDescriptor{
54
- // Path: TestPath(),
55
- // Expected: app.Div(),
56
- // })
57
- // // OK => err == nil
58
- //
59
- // // Testing h2:
60
- // err := app.TestMatch(tree, app.TestUIDescriptor{
61
- // Path: TestPath(0),
62
- // Expected: app.H3(),
63
- // })
64
- // // KO => err != nil because we ask h2 to match with h3
65
- //
66
- // // Testing text from p:
67
- // err = app.TestMatch(tree, app.TestUIDescriptor{
68
- // Path: TestPath(1, 0),
69
- // Expected: app.Text("bar"),
70
- // })
71
- // // OK => err == nil
72
- func TestMatch(tree UI, d TestUIDescriptor) error {
73
- if !tree.Mounted() {
74
- if err := mount(tree); err != nil {
75
- return err
76
- }
77
- }
78
-
79
- if d.Expected != nil {
80
- d.Expected.setSelf(d.Expected)
81
- }
82
-
83
- if len(d.Path) != 0 {
84
- idx := d.Path[0]
85
-
86
- if idx < 0 || idx >= len(tree.children()) {
87
- // Check that the element does not exists.
88
- if d.Expected == nil {
89
- return nil
90
- }
91
-
92
- return errors.New("ui element to match is out of range").
93
- Tag("name", d.Expected.name()).
94
- Tag("parent-name", tree.name()).
95
- Tag("parent-children-count", len(tree.children())).
96
- Tag("index", idx)
97
- }
98
-
99
- c := tree.children()[idx]
100
- p := c.parent()
101
-
102
- if p != tree {
103
- return errors.New("unexpected ui element parent").
104
- Tag("name", d.Expected.name()).
105
- Tag("parent-name", p.name()).
106
- Tag("parent-addr", fmt.Sprintf("%p", p)).
107
- Tag("expected-parent-name", tree.name()).
108
- Tag("expected-parent-addr", fmt.Sprintf("%p", tree))
109
- }
110
-
111
- d.Path = d.Path[1:]
112
- return TestMatch(c, d)
113
- }
114
-
115
- if d.Expected.name() != tree.name() {
116
- return errors.New("the UI element is not matching the descriptor").
117
- Tag("expected-name", d.Expected.name()).
118
- Tag("current-name", tree.name())
119
- }
120
-
121
- // switch d.Expected.Kind() {
122
- // case SimpleText:
123
- // return matchText(tree, d)
124
-
125
- // case HTML:
126
- // if err := matchHTMLElemAttrs(tree, d); err != nil {
127
- // return err
128
- // }
129
- // return matchHTMLElemEventHandlers(tree, d)
130
-
131
- // // case Component:
132
- // // return matchComponent(tree, d)
133
-
134
- // case RawHTML:
135
- // return matchRaw(tree, d)
136
-
137
- // default:
138
- // return errors.New("the UI element is not matching the descriptor").
139
- // Tag("reason", "unavailable matching for the kind").
140
- // Tag("kind", d.Expected.Kind())
141
- // }
142
- return nil
143
- }
144
-
145
- func matchText(n UI, d TestUIDescriptor) error {
146
- a := n.(*text)
147
- b := d.Expected.(*text)
148
-
149
- if a.value != b.value {
150
- return errors.New("the text element is not matching the descriptor").
151
- Tag("name", a.name()).
152
- Tag("reason", "unexpected text value").
153
- Tag("expected-value", b.value).
154
- Tag("current-value", a.value)
155
- }
156
- return nil
157
- }
158
-
159
- func matchHTMLElemAttrs(n UI, d TestUIDescriptor) error {
160
- aAttrs := n.attributes()
161
- bAttrs := d.Expected.attributes()
162
-
163
- if len(aAttrs) != len(bAttrs) {
164
- return errors.New("the html element is not matching the descriptor").
165
- Tag("name", n.name()).
166
- Tag("reason", "unexpected attributes length").
167
- Tag("expected-attributes-length", len(bAttrs)).
168
- Tag("current-attributes-length", len(aAttrs))
169
- }
170
-
171
- for k, b := range bAttrs {
172
- a, exists := aAttrs[k]
173
- if !exists {
174
- return errors.New("the html element is not matching the descriptor").
175
- Tag("name", n.name()).
176
- Tag("reason", "an attribute is missing").
177
- Tag("attribute", k)
178
- }
179
-
180
- if a != b {
181
- return errors.New("the html element is not matching the descriptor").
182
- Tag("name", n.name()).
183
- Tag("reason", "unexpected attribute value").
184
- Tag("attribute", k).
185
- Tag("expected-value", b).
186
- Tag("current-value", a)
187
- }
188
- }
189
-
190
- for k := range bAttrs {
191
- _, exists := bAttrs[k]
192
- if !exists {
193
- return errors.New("the html element is not matching the descriptor").
194
- Tag("name", n.name()).
195
- Tag("reason", "an unexpected attribute is present").
196
- Tag("attribute", k)
197
- }
198
- }
199
-
200
- return nil
201
- }
202
-
203
- func matchHTMLElemEventHandlers(n UI, d TestUIDescriptor) error {
204
- aevents := n.eventHandlers()
205
- bevents := d.Expected.eventHandlers()
206
-
207
- if len(aevents) != len(bevents) {
208
- return errors.New("the html element is not matching the descriptor").
209
- Tag("name", n.name()).
210
- Tag("reason", "unexpected event handlers length").
211
- Tag("expected-event-handlers-length", len(bevents)).
212
- Tag("current-event-handlers-length", len(aevents))
213
- }
214
-
215
- for k := range bevents {
216
- _, exists := aevents[k]
217
- if !exists {
218
- return errors.New("the html element is not matching the descriptor").
219
- Tag("name", n.name()).
220
- Tag("reason", "an event handler is missing").
221
- Tag("event-handler", k)
222
- }
223
- }
224
-
225
- for k := range bevents {
226
- _, exists := aevents[k]
227
- if !exists {
228
- return errors.New("the html element is not matching the descriptor").
229
- Tag("name", n.name()).
230
- Tag("reason", "an unexpected event handler is present").
231
- Tag("event-handler", k)
232
- }
233
- }
234
-
235
- return nil
236
-
237
- }
238
-
239
- // func matchComponent(n UI, d TestUIDescriptor) error {
240
- // aval := reflect.ValueOf(n).Elem()
241
- // bval := reflect.ValueOf(d.Expected).Elem()
242
-
243
- // compotype := reflect.TypeOf(Compo{})
244
-
245
- // for i := 0; i < bval.NumField(); i++ {
246
- // a := aval.Field(i)
247
- // b := bval.Field(i)
248
-
249
- // if a.Type() == compotype {
250
- // continue
3
+ // import (
4
+ // "fmt"
5
+
6
+ // "github.com/pyros2097/wapp/errors"
7
+ // )
8
+
9
+ // // TestUIDescriptor represents a descriptor that describes a UI element and its
10
+ // // location from its parents.
11
+ // type TestUIDescriptor struct {
12
+ // // The location of the node. It is used by the TestMatch to find the
13
+ // // element to test.
14
+ // //
15
+ // // If empty, the expected UI element is compared with the root of the tree.
16
+ // //
17
+ // // Otherwise, each integer represents the index of the element to traverse,
18
+ // // from the root's children to the element to compare
19
+ // Path []int
20
+
21
+ // // The element to compare with the element targeted by Path. Compare
22
+ // // behavior varies depending on the element kind.
23
+ // //
24
+ // // Simple text elements only have their text value compared.
25
+ // //
26
+ // // HTML elements have their attribute compared and check if their event
27
+ // // handlers are set.
28
+ // //
29
+ // // Components have their exported field values compared.
30
+ // Expected UI
31
+ // }
32
+
33
+ // // TestPath is a helper function that returns a path to use in a
34
+ // // TestUIDescriptor.
35
+ // func TestPath(p ...int) []int {
36
+ // return p
37
+ // }
38
+
39
+ // // TestMatch looks for the element targeted by the descriptor in the given tree
40
+ // // and reports whether it matches with the expected element.
41
+ // //
42
+ // // Eg:
43
+ // // tree := app.Div().Body(
44
+ // // app.H2().Body(
45
+ // // app.Text("foo"),
46
+ // // ),
47
+ // // app.P().Body(
48
+ // // app.Text("bar"),
49
+ // // ),
50
+ // // )
51
+ // //
52
+ // // // Testing root:
53
+ // // err := app.TestMatch(tree, app.TestUIDescriptor{
54
+ // // Path: TestPath(),
55
+ // // Expected: app.Div(),
56
+ // // })
57
+ // // // OK => err == nil
58
+ // //
59
+ // // // Testing h2:
60
+ // // err := app.TestMatch(tree, app.TestUIDescriptor{
61
+ // // Path: TestPath(0),
62
+ // // Expected: app.H3(),
63
+ // // })
64
+ // // // KO => err != nil because we ask h2 to match with h3
65
+ // //
66
+ // // // Testing text from p:
67
+ // // err = app.TestMatch(tree, app.TestUIDescriptor{
68
+ // // Path: TestPath(1, 0),
69
+ // // Expected: app.Text("bar"),
70
+ // // })
71
+ // // // OK => err == nil
72
+ // func TestMatch(tree UI, d TestUIDescriptor) error {
73
+ // if !tree.Mounted() {
74
+ // if err := mount(tree); err != nil {
75
+ // return err
76
+ // }
77
+ // }
78
+
79
+ // if d.Expected != nil {
80
+ // d.Expected.setSelf(d.Expected)
81
+ // }
82
+
83
+ // if len(d.Path) != 0 {
84
+ // idx := d.Path[0]
85
+
86
+ // if idx < 0 || idx >= len(tree.children()) {
87
+ // // Check that the element does not exists.
88
+ // if d.Expected == nil {
89
+ // return nil
90
+ // }
91
+
92
+ // return errors.New("ui element to match is out of range").
93
+ // Tag("name", d.Expected.name()).
94
+ // Tag("parent-name", tree.name()).
95
+ // Tag("parent-children-count", len(tree.children())).
96
+ // Tag("index", idx)
251
97
  // }
252
98
 
99
+ // c := tree.children()[idx]
100
+ // p := c.parent()
101
+
253
- // if !a.CanSet() {
102
+ // if p != tree {
103
+ // return errors.New("unexpected ui element parent").
104
+ // Tag("name", d.Expected.name()).
254
- // continue
105
+ // Tag("parent-name", p.name()).
106
+ // Tag("parent-addr", fmt.Sprintf("%p", p)).
107
+ // Tag("expected-parent-name", tree.name()).
108
+ // Tag("expected-parent-addr", fmt.Sprintf("%p", tree))
255
109
  // }
256
110
 
111
+ // d.Path = d.Path[1:]
112
+ // return TestMatch(c, d)
113
+ // }
114
+
257
- // if !reflect.DeepEqual(a.Interface(), b.Interface()) {
115
+ // if d.Expected.name() != tree.name() {
116
+ // return errors.New("the UI element is not matching the descriptor").
117
+ // Tag("expected-name", d.Expected.name()).
118
+ // Tag("current-name", tree.name())
119
+ // }
120
+
121
+ // // switch d.Expected.Kind() {
122
+ // // case SimpleText:
123
+ // // return matchText(tree, d)
124
+
125
+ // // case HTML:
126
+ // // if err := matchHTMLElemAttrs(tree, d); err != nil {
127
+ // // return err
128
+ // // }
129
+ // // return matchHTMLElemEventHandlers(tree, d)
130
+
131
+ // // // case Component:
132
+ // // // return matchComponent(tree, d)
133
+
134
+ // // case RawHTML:
135
+ // // return matchRaw(tree, d)
136
+
137
+ // // default:
138
+ // // return errors.New("the UI element is not matching the descriptor").
139
+ // // Tag("reason", "unavailable matching for the kind").
140
+ // // Tag("kind", d.Expected.Kind())
141
+ // // }
142
+ // return nil
143
+ // }
144
+
145
+ // func matchText(n UI, d TestUIDescriptor) error {
146
+ // a := n.(*text)
147
+ // b := d.Expected.(*text)
148
+
149
+ // if a.value != b.value {
150
+ // return errors.New("the text element is not matching the descriptor").
151
+ // Tag("name", a.name()).
152
+ // Tag("reason", "unexpected text value").
153
+ // Tag("expected-value", b.value).
154
+ // Tag("current-value", a.value)
155
+ // }
156
+ // return nil
157
+ // }
158
+
159
+ // func matchHTMLElemAttrs(n UI, d TestUIDescriptor) error {
160
+ // aAttrs := n.attributes()
161
+ // bAttrs := d.Expected.attributes()
162
+
163
+ // if len(aAttrs) != len(bAttrs) {
164
+ // return errors.New("the html element is not matching the descriptor").
165
+ // Tag("name", n.name()).
166
+ // Tag("reason", "unexpected attributes length").
167
+ // Tag("expected-attributes-length", len(bAttrs)).
168
+ // Tag("current-attributes-length", len(aAttrs))
169
+ // }
170
+
171
+ // for k, b := range bAttrs {
172
+ // a, exists := aAttrs[k]
173
+ // if !exists {
258
- // return errors.New("the component is not matching with the descriptor").
174
+ // return errors.New("the html element is not matching the descriptor").
175
+ // Tag("name", n.name()).
176
+ // Tag("reason", "an attribute is missing").
177
+ // Tag("attribute", k)
178
+ // }
179
+
180
+ // if a != b {
181
+ // return errors.New("the html element is not matching the descriptor").
182
+ // Tag("name", n.name()).
183
+ // Tag("reason", "unexpected attribute value").
184
+ // Tag("attribute", k).
185
+ // Tag("expected-value", b).
186
+ // Tag("current-value", a)
187
+ // }
188
+ // }
189
+
190
+ // for k := range bAttrs {
191
+ // _, exists := bAttrs[k]
192
+ // if !exists {
193
+ // return errors.New("the html element is not matching the descriptor").
259
194
  // Tag("name", n.name()).
260
- // Tag("reason", "unexpected field value").
195
+ // Tag("reason", "an unexpected attribute is present").
261
- // Tag("field", bval.Type().Field(i).Name).
262
- // Tag("expected-value", b.Interface()).
263
- // Tag("current-value", a.Interface())
196
+ // Tag("attribute", k)
264
197
  // }
265
198
  // }
266
199
 
267
200
  // return nil
268
201
  // }
269
202
 
270
- func matchRaw(n UI, d TestUIDescriptor) error {
203
+ // func matchHTMLElemEventHandlers(n UI, d TestUIDescriptor) error {
271
- a := n.(*raw)
204
+ // aevents := n.eventHandlers()
272
- b := d.Expected.(*raw)
205
+ // bevents := d.Expected.eventHandlers()
273
206
 
274
- if a.value != b.value {
207
+ // if len(aevents) != len(bevents) {
275
- return errors.New("the raw html element is not matching with the descriptor").
208
+ // return errors.New("the html element is not matching the descriptor").
276
- Tag("name", n.name()).
209
+ // Tag("name", n.name()).
277
- Tag("reason", "unexpected value").
210
+ // Tag("reason", "unexpected event handlers length").
278
- Tag("expected-value", b.value).
211
+ // Tag("expected-event-handlers-length", len(bevents)).
279
- Tag("current-value", a.value)
212
+ // Tag("current-event-handlers-length", len(aevents))
280
- }
213
+ // }
281
214
 
215
+ // for k := range bevents {
216
+ // _, exists := aevents[k]
217
+ // if !exists {
218
+ // return errors.New("the html element is not matching the descriptor").
219
+ // Tag("name", n.name()).
220
+ // Tag("reason", "an event handler is missing").
221
+ // Tag("event-handler", k)
222
+ // }
223
+ // }
224
+
225
+ // for k := range bevents {
226
+ // _, exists := aevents[k]
227
+ // if !exists {
228
+ // return errors.New("the html element is not matching the descriptor").
229
+ // Tag("name", n.name()).
230
+ // Tag("reason", "an unexpected event handler is present").
231
+ // Tag("event-handler", k)
232
+ // }
233
+ // }
234
+
282
- return nil
235
+ // return nil
236
+
283
- }
237
+ // }
238
+
239
+ // // func matchComponent(n UI, d TestUIDescriptor) error {
240
+ // // aval := reflect.ValueOf(n).Elem()
241
+ // // bval := reflect.ValueOf(d.Expected).Elem()
242
+
243
+ // // compotype := reflect.TypeOf(Compo{})
244
+
245
+ // // for i := 0; i < bval.NumField(); i++ {
246
+ // // a := aval.Field(i)
247
+ // // b := bval.Field(i)
248
+
249
+ // // if a.Type() == compotype {
250
+ // // continue
251
+ // // }
252
+
253
+ // // if !a.CanSet() {
254
+ // // continue
255
+ // // }
256
+
257
+ // // if !reflect.DeepEqual(a.Interface(), b.Interface()) {
258
+ // // return errors.New("the component is not matching with the descriptor").
259
+ // // Tag("name", n.name()).
260
+ // // Tag("reason", "unexpected field value").
261
+ // // Tag("field", bval.Type().Field(i).Name).
262
+ // // Tag("expected-value", b.Interface()).
263
+ // // Tag("current-value", a.Interface())
264
+ // // }
265
+ // // }
266
+
267
+ // // return nil
268
+ // // }
269
+
270
+ // func matchRaw(n UI, d TestUIDescriptor) error {
271
+ // a := n.(*raw)
272
+ // b := d.Expected.(*raw)
273
+
274
+ // if a.value != b.value {
275
+ // return errors.New("the raw html element is not matching with the descriptor").
276
+ // Tag("name", n.name()).
277
+ // Tag("reason", "unexpected value").
278
+ // Tag("expected-value", b.value).
279
+ // Tag("current-value", a.value)
280
+ // }
281
+
282
+ // return nil
283
+ // }
testing_test.go CHANGED
@@ -1,46 +1,46 @@
1
1
  package app
2
2
 
3
- import (
3
+ // import (
4
- "io/ioutil"
4
+ // "io/ioutil"
5
- "os"
5
+ // "os"
6
- "runtime"
6
+ // "runtime"
7
- "testing"
7
+ // "testing"
8
8
 
9
- "github.com/stretchr/testify/require"
9
+ // "github.com/stretchr/testify/require"
10
- )
10
+ // )
11
11
 
12
- func testSkipNonWasm(t *testing.T) {
12
+ // func testSkipNonWasm(t *testing.T) {
13
- if goarch := runtime.GOARCH; goarch != "wasm" {
13
+ // if goarch := runtime.GOARCH; goarch != "wasm" {
14
- t.Skip("skipping test")
15
- // t.Skip(logs.New("skipping test").
14
+ // t.Skip("skipping test")
15
+ // // t.Skip(logs.New("skipping test").
16
- // Tag("reason", "unsupported architecture").
16
+ // // Tag("reason", "unsupported architecture").
17
- // Tag("required-architecture", "wasm").
17
+ // // Tag("required-architecture", "wasm").
18
- // Tag("current-architecture", goarch),
18
+ // // Tag("current-architecture", goarch),
19
+ // // )
20
+ // }
19
- // )
21
+ // }
20
- }
21
- }
22
22
 
23
- func testSkipWasm(t *testing.T) {
23
+ // func testSkipWasm(t *testing.T) {
24
- if goarch := runtime.GOARCH; goarch == "wasm" {
24
+ // if goarch := runtime.GOARCH; goarch == "wasm" {
25
- t.Skip("skipping test")
26
- // t.Skip(logs.New("skipping test").
25
+ // t.Skip("skipping test")
26
+ // // t.Skip(logs.New("skipping test").
27
- // Tag("reason", "unsupported architecture").
27
+ // // Tag("reason", "unsupported architecture").
28
- // Tag("required-architecture", "!= than wasm").
28
+ // // Tag("required-architecture", "!= than wasm").
29
- // Tag("current-architecture", goarch),
29
+ // // Tag("current-architecture", goarch),
30
+ // // )
31
+ // }
30
- // )
32
+ // }
31
- }
32
- }
33
33
 
34
- func testCreateDir(t *testing.T, path string) func() {
34
+ // func testCreateDir(t *testing.T, path string) func() {
35
- err := os.MkdirAll(path, 0755)
35
+ // err := os.MkdirAll(path, 0755)
36
- require.NoError(t, err)
36
+ // require.NoError(t, err)
37
37
 
38
- return func() {
38
+ // return func() {
39
- os.RemoveAll(path)
39
+ // os.RemoveAll(path)
40
+ // }
40
- }
41
+ // }
41
- }
42
42
 
43
- func testCreateFile(t *testing.T, path, content string) {
43
+ // func testCreateFile(t *testing.T, path, content string) {
44
- err := ioutil.WriteFile(path, stob(content), 0666)
44
+ // err := ioutil.WriteFile(path, stob(content), 0666)
45
- require.NoError(t, err)
45
+ // require.NoError(t, err)
46
- }
46
+ // }
utils.go CHANGED
@@ -48,3 +48,19 @@ func btos(b []byte) string {
48
48
  func stob(s string) []byte {
49
49
  return *(*[]byte)(unsafe.Pointer(&s))
50
50
  }
51
+
52
+ var (
53
+ defaultColor = "\033[00m"
54
+ errorColor = "\033[91m"
55
+ infoColor = "\033[94m"
56
+ )
57
+
58
+ // Log logs according to a format specifier using the default logger.
59
+ func Log(format string, v ...interface{}) {
60
+ errorLevel := false
61
+ if errorLevel {
62
+ println(errorColor+"ERROR ‣ "+defaultColor+format+"\n", v)
63
+ return
64
+ }
65
+ println(infoColor+"INFO ‣ "+defaultColor+format+"\n", v)
66
+ }