github.com/goplusjs/gopherjs@v1.2.6-0.20211206034512-f187917453b8/tests/syscalljs/js_test.go (about) 1 // This file is basically copied from $GOROOT/src/syscall/js/js_test.go 2 3 // Copyright 2018 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 // +build js 8 // +build !go1.13 9 10 // To run these tests: 11 // 12 // - Install Node 13 // - Add /path/to/go/misc/wasm to your $PATH (so that "go test" can find 14 // "go_js_wasm_exec"). 15 // - GOOS=js GOARCH=wasm go test 16 // 17 // See -exec in "go help test", and "go help run" for details. 18 19 package js_test 20 21 import ( 22 "fmt" 23 "math" 24 "syscall/js" 25 "testing" 26 ) 27 28 func TestMain(m *testing.M) { 29 // Suppress the 'deadlock' error on GopherJS by goroutine 30 // (https://github.com/gopherjs/gopherjs/issues/826). 31 go func() { 32 m.Run() 33 }() 34 } 35 36 var dummys = js.Global().Call("eval", `({ 37 someBool: true, 38 someString: "abc\u1234", 39 someInt: 42, 40 someFloat: 42.123, 41 someArray: [41, 42, 43], 42 someDate: new Date(), 43 add: function(a, b) { 44 return a + b; 45 }, 46 zero: 0, 47 stringZero: "0", 48 NaN: NaN, 49 emptyObj: {}, 50 emptyArray: [], 51 Infinity: Infinity, 52 NegInfinity: -Infinity, 53 objNumber0: new Number(0), 54 objBooleanFalse: new Boolean(false), 55 })`) 56 57 func TestBool(t *testing.T) { 58 want := true 59 o := dummys.Get("someBool") 60 if got := o.Bool(); got != want { 61 t.Errorf("got %#v, want %#v", got, want) 62 } 63 dummys.Set("otherBool", want) 64 if got := dummys.Get("otherBool").Bool(); got != want { 65 t.Errorf("got %#v, want %#v", got, want) 66 } 67 if dummys.Get("someBool") != dummys.Get("someBool") { 68 t.Errorf("same value not equal") 69 } 70 } 71 72 func TestString(t *testing.T) { 73 want := "abc\u1234" 74 o := dummys.Get("someString") 75 if got := o.String(); got != want { 76 t.Errorf("got %#v, want %#v", got, want) 77 } 78 dummys.Set("otherString", want) 79 if got := dummys.Get("otherString").String(); got != want { 80 t.Errorf("got %#v, want %#v", got, want) 81 } 82 if dummys.Get("someString") != dummys.Get("someString") { 83 t.Errorf("same value not equal") 84 } 85 86 wantInt := "42" 87 o = dummys.Get("someInt") 88 if got := o.String(); got != wantInt { 89 t.Errorf("got %#v, want %#v", got, wantInt) 90 } 91 } 92 93 func TestInt(t *testing.T) { 94 want := 42 95 o := dummys.Get("someInt") 96 if got := o.Int(); got != want { 97 t.Errorf("got %#v, want %#v", got, want) 98 } 99 dummys.Set("otherInt", want) 100 if got := dummys.Get("otherInt").Int(); got != want { 101 t.Errorf("got %#v, want %#v", got, want) 102 } 103 if dummys.Get("someInt") != dummys.Get("someInt") { 104 t.Errorf("same value not equal") 105 } 106 if got := dummys.Get("zero").Int(); got != 0 { 107 t.Errorf("got %#v, want %#v", got, 0) 108 } 109 } 110 111 func TestIntConversion(t *testing.T) { 112 testIntConversion(t, 0) 113 testIntConversion(t, 1) 114 testIntConversion(t, -1) 115 testIntConversion(t, 1<<20) 116 testIntConversion(t, -1<<20) 117 118 // Skip too big integers. They cannot be compiled with 32bit environment, and GopherJS is one of them. 119 // testIntConversion(t, 1<<40) 120 // testIntConversion(t, -1<<40) 121 // testIntConversion(t, 1<<60) 122 // testIntConversion(t, -1<<60) 123 } 124 125 func testIntConversion(t *testing.T, want int) { 126 if got := js.ValueOf(want).Int(); got != want { 127 t.Errorf("got %#v, want %#v", got, want) 128 } 129 } 130 131 func TestFloat(t *testing.T) { 132 want := 42.123 133 o := dummys.Get("someFloat") 134 if got := o.Float(); got != want { 135 t.Errorf("got %#v, want %#v", got, want) 136 } 137 dummys.Set("otherFloat", want) 138 if got := dummys.Get("otherFloat").Float(); got != want { 139 t.Errorf("got %#v, want %#v", got, want) 140 } 141 if dummys.Get("someFloat") != dummys.Get("someFloat") { 142 t.Errorf("same value not equal") 143 } 144 } 145 146 func TestObject(t *testing.T) { 147 if dummys.Get("someArray") != dummys.Get("someArray") { 148 t.Errorf("same value not equal") 149 } 150 151 // An object and its prototype should not be equal. 152 proto := js.Global().Get("Object").Get("prototype") 153 o := js.Global().Call("eval", "new Object()") 154 if proto == o { 155 t.Errorf("object equals to its prototype") 156 } 157 } 158 159 func TestFrozenObject(t *testing.T) { 160 o := js.Global().Call("eval", "(function () { let o = new Object(); o.field = 5; Object.freeze(o); return o; })()") 161 want := 5 162 if got := o.Get("field").Int(); want != got { 163 t.Errorf("got %#v, want %#v", got, want) 164 } 165 } 166 167 func TestTypedArrayOf(t *testing.T) { 168 testTypedArrayOf(t, "[]int8", []int8{0, -42, 0}, -42) 169 testTypedArrayOf(t, "[]int16", []int16{0, -42, 0}, -42) 170 testTypedArrayOf(t, "[]int32", []int32{0, -42, 0}, -42) 171 testTypedArrayOf(t, "[]uint8", []uint8{0, 42, 0}, 42) 172 testTypedArrayOf(t, "[]uint16", []uint16{0, 42, 0}, 42) 173 testTypedArrayOf(t, "[]uint32", []uint32{0, 42, 0}, 42) 174 testTypedArrayOf(t, "[]float32", []float32{0, -42.5, 0}, -42.5) 175 testTypedArrayOf(t, "[]float64", []float64{0, -42.5, 0}, -42.5) 176 } 177 178 func testTypedArrayOf(t *testing.T, name string, slice interface{}, want float64) { 179 t.Run(name, func(t *testing.T) { 180 a := js.TypedArrayOf(slice) 181 got := a.Index(1).Float() 182 a.Release() 183 if got != want { 184 t.Errorf("got %#v, want %#v", got, want) 185 } 186 }) 187 } 188 189 func TestNaN(t *testing.T) { 190 t.Skip("NaN cannot be compared") 191 192 want := js.ValueOf(math.NaN()) 193 got := dummys.Get("NaN") 194 if got != want { 195 t.Errorf("got %#v, want %#v", got, want) 196 } 197 } 198 199 func TestUndefined(t *testing.T) { 200 dummys.Set("test", js.Undefined()) 201 if dummys == js.Undefined() || dummys.Get("test") != js.Undefined() || dummys.Get("xyz") != js.Undefined() { 202 t.Errorf("js.Undefined expected") 203 } 204 } 205 206 func TestNull(t *testing.T) { 207 dummys.Set("test1", nil) 208 dummys.Set("test2", js.Null()) 209 if dummys == js.Null() || dummys.Get("test1") != js.Null() || dummys.Get("test2") != js.Null() { 210 t.Errorf("js.Null expected") 211 } 212 } 213 214 func TestLength(t *testing.T) { 215 if got := dummys.Get("someArray").Length(); got != 3 { 216 t.Errorf("got %#v, want %#v", got, 3) 217 } 218 } 219 220 func TestIndex(t *testing.T) { 221 if got := dummys.Get("someArray").Index(1).Int(); got != 42 { 222 t.Errorf("got %#v, want %#v", got, 42) 223 } 224 } 225 226 func TestSetIndex(t *testing.T) { 227 dummys.Get("someArray").SetIndex(2, 99) 228 if got := dummys.Get("someArray").Index(2).Int(); got != 99 { 229 t.Errorf("got %#v, want %#v", got, 99) 230 } 231 } 232 233 func TestCall(t *testing.T) { 234 var i int64 = 40 235 if got := dummys.Call("add", i, 2).Int(); got != 42 { 236 t.Errorf("got %#v, want %#v", got, 42) 237 } 238 if got := dummys.Call("add", js.Global().Call("eval", "40"), 2).Int(); got != 42 { 239 t.Errorf("got %#v, want %#v", got, 42) 240 } 241 } 242 243 func TestInvoke(t *testing.T) { 244 var i int64 = 40 245 if got := dummys.Get("add").Invoke(i, 2).Int(); got != 42 { 246 t.Errorf("got %#v, want %#v", got, 42) 247 } 248 } 249 250 func TestNew(t *testing.T) { 251 if got := js.Global().Get("Array").New(42).Length(); got != 42 { 252 t.Errorf("got %#v, want %#v", got, 42) 253 } 254 } 255 256 func TestInstanceOf(t *testing.T) { 257 someArray := js.Global().Get("Array").New() 258 if got, want := someArray.InstanceOf(js.Global().Get("Array")), true; got != want { 259 t.Errorf("got %#v, want %#v", got, want) 260 } 261 if got, want := someArray.InstanceOf(js.Global().Get("Function")), false; got != want { 262 t.Errorf("got %#v, want %#v", got, want) 263 } 264 } 265 266 func TestType(t *testing.T) { 267 if got, want := js.Undefined().Type(), js.TypeUndefined; got != want { 268 t.Errorf("got %s, want %s", got, want) 269 } 270 if got, want := js.Null().Type(), js.TypeNull; got != want { 271 t.Errorf("got %s, want %s", got, want) 272 } 273 if got, want := js.ValueOf(true).Type(), js.TypeBoolean; got != want { 274 t.Errorf("got %s, want %s", got, want) 275 } 276 if got, want := js.ValueOf(0).Type(), js.TypeNumber; got != want { 277 t.Errorf("got %s, want %s", got, want) 278 } 279 if got, want := js.ValueOf(42).Type(), js.TypeNumber; got != want { 280 t.Errorf("got %s, want %s", got, want) 281 } 282 if got, want := js.ValueOf("test").Type(), js.TypeString; got != want { 283 t.Errorf("got %s, want %s", got, want) 284 } 285 if got, want := js.Global().Get("Symbol").Invoke("test").Type(), js.TypeSymbol; got != want { 286 t.Errorf("got %s, want %s", got, want) 287 } 288 if got, want := js.Global().Get("Array").New().Type(), js.TypeObject; got != want { 289 t.Errorf("got %s, want %s", got, want) 290 } 291 if got, want := js.Global().Get("Array").Type(), js.TypeFunction; got != want { 292 t.Errorf("got %s, want %s", got, want) 293 } 294 } 295 296 type object = map[string]interface{} 297 type array = []interface{} 298 299 func TestValueOf(t *testing.T) { 300 a := js.ValueOf(array{0, array{0, 42, 0}, 0}) 301 if got := a.Index(1).Index(1).Int(); got != 42 { 302 t.Errorf("got %v, want %v", got, 42) 303 } 304 305 o := js.ValueOf(object{"x": object{"y": 42}}) 306 if got := o.Get("x").Get("y").Int(); got != 42 { 307 t.Errorf("got %v, want %v", got, 42) 308 } 309 } 310 311 func TestZeroValue(t *testing.T) { 312 var v js.Value 313 if v != js.Undefined() { 314 t.Error("zero js.Value is not js.Undefined()") 315 } 316 } 317 318 func TestFuncOf(t *testing.T) { 319 c := make(chan struct{}) 320 cb := js.FuncOf(func(this js.Value, args []js.Value) interface{} { 321 if got := args[0].Int(); got != 42 { 322 t.Errorf("got %#v, want %#v", got, 42) 323 } 324 c <- struct{}{} 325 return nil 326 }) 327 defer cb.Release() 328 js.Global().Call("setTimeout", cb, 0, 42) 329 <-c 330 } 331 332 func TestInvokeFunction(t *testing.T) { 333 called := false 334 cb := js.FuncOf(func(this js.Value, args []js.Value) interface{} { 335 cb2 := js.FuncOf(func(this js.Value, args []js.Value) interface{} { 336 called = true 337 return 42 338 }) 339 defer cb2.Release() 340 return cb2.Invoke() 341 }) 342 defer cb.Release() 343 if got := cb.Invoke().Int(); got != 42 { 344 t.Errorf("got %#v, want %#v", got, 42) 345 } 346 if !called { 347 t.Error("function not called") 348 } 349 } 350 351 func ExampleFuncOf() { 352 var cb js.Func 353 cb = js.FuncOf(func(this js.Value, args []js.Value) interface{} { 354 fmt.Println("button clicked") 355 cb.Release() // release the function if the button will not be clicked again 356 return nil 357 }) 358 js.Global().Get("document").Call("getElementById", "myButton").Call("addEventListener", "click", cb) 359 } 360 361 // See 362 // - https://developer.mozilla.org/en-US/docs/Glossary/Truthy 363 // - https://stackoverflow.com/questions/19839952/all-falsey-values-in-javascript/19839953#19839953 364 // - http://www.ecma-international.org/ecma-262/5.1/#sec-9.2 365 func TestTruthy(t *testing.T) { 366 want := true 367 for _, key := range []string{ 368 "someBool", "someString", "someInt", "someFloat", "someArray", "someDate", 369 "stringZero", // "0" is truthy 370 "add", // functions are truthy 371 "emptyObj", "emptyArray", "Infinity", "NegInfinity", 372 // All objects are truthy, even if they're Number(0) or Boolean(false). 373 "objNumber0", "objBooleanFalse", 374 } { 375 if got := dummys.Get(key).Truthy(); got != want { 376 t.Errorf("%s: got %#v, want %#v", key, got, want) 377 } 378 } 379 380 want = false 381 if got := dummys.Get("zero").Truthy(); got != want { 382 t.Errorf("got %#v, want %#v", got, want) 383 } 384 if got := dummys.Get("NaN").Truthy(); got != want { 385 t.Errorf("got %#v, want %#v", got, want) 386 } 387 if got := js.ValueOf("").Truthy(); got != want { 388 t.Errorf("got %#v, want %#v", got, want) 389 } 390 if got := js.Null().Truthy(); got != want { 391 t.Errorf("got %#v, want %#v", got, want) 392 } 393 if got := js.Undefined().Truthy(); got != want { 394 t.Errorf("got %#v, want %#v", got, want) 395 } 396 }