github.com/goplusjs/gopherjs@v1.2.6-0.20211206034512-f187917453b8/tests/syscalljs/go113_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 // +build !go1.14 10 11 // To run these tests: 12 // 13 // - Install Node 14 // - Add /path/to/go/misc/wasm to your $PATH (so that "go test" can find 15 // "go_js_wasm_exec"). 16 // - GOOS=js GOARCH=wasm go test 17 // 18 // See -exec in "go help test", and "go help run" for details. 19 20 package js_test 21 22 import ( 23 "fmt" 24 "math" 25 "syscall/js" 26 "testing" 27 ) 28 29 func TestMain(m *testing.M) { 30 // Suppress the 'deadlock' error on GopherJS by goroutine 31 // (https://github.com/gopherjs/gopherjs/issues/826). 32 go func() { 33 m.Run() 34 }() 35 } 36 37 var dummys = js.Global().Call("eval", `({ 38 someBool: true, 39 someString: "abc\u1234", 40 someInt: 42, 41 someFloat: 42.123, 42 someArray: [41, 42, 43], 43 someDate: new Date(), 44 add: function(a, b) { 45 return a + b; 46 }, 47 zero: 0, 48 stringZero: "0", 49 NaN: NaN, 50 emptyObj: {}, 51 emptyArray: [], 52 Infinity: Infinity, 53 NegInfinity: -Infinity, 54 objNumber0: new Number(0), 55 objBooleanFalse: new Boolean(false), 56 })`) 57 58 func TestBool(t *testing.T) { 59 want := true 60 o := dummys.Get("someBool") 61 if got := o.Bool(); got != want { 62 t.Errorf("got %#v, want %#v", got, want) 63 } 64 dummys.Set("otherBool", want) 65 if got := dummys.Get("otherBool").Bool(); got != want { 66 t.Errorf("got %#v, want %#v", got, want) 67 } 68 if dummys.Get("someBool") != dummys.Get("someBool") { 69 t.Errorf("same value not equal") 70 } 71 } 72 73 func TestString(t *testing.T) { 74 want := "abc\u1234" 75 o := dummys.Get("someString") 76 if got := o.String(); got != want { 77 t.Errorf("got %#v, want %#v", got, want) 78 } 79 dummys.Set("otherString", want) 80 if got := dummys.Get("otherString").String(); got != want { 81 t.Errorf("got %#v, want %#v", got, want) 82 } 83 if dummys.Get("someString") != dummys.Get("someString") { 84 t.Errorf("same value not equal") 85 } 86 87 if got, want := js.Undefined().String(), "<undefined>"; got != want { 88 t.Errorf("got %#v, want %#v", got, want) 89 } 90 if got, want := js.Null().String(), "<null>"; got != want { 91 t.Errorf("got %#v, want %#v", got, want) 92 } 93 if got, want := js.ValueOf(true).String(), "<boolean: true>"; got != want { 94 t.Errorf("got %#v, want %#v", got, want) 95 } 96 if got, want := js.ValueOf(42.5).String(), "<number: 42.5>"; got != want { 97 t.Errorf("got %#v, want %#v", got, want) 98 } 99 if got, want := js.Global().Call("Symbol").String(), "<symbol>"; got != want { 100 t.Errorf("got %#v, want %#v", got, want) 101 } 102 if got, want := js.Global().String(), "<object>"; got != want { 103 t.Errorf("got %#v, want %#v", got, want) 104 } 105 if got, want := js.Global().Get("setTimeout").String(), "<function>"; got != want { 106 t.Errorf("got %#v, want %#v", got, want) 107 } 108 } 109 110 func TestInt(t *testing.T) { 111 want := 42 112 o := dummys.Get("someInt") 113 if got := o.Int(); got != want { 114 t.Errorf("got %#v, want %#v", got, want) 115 } 116 dummys.Set("otherInt", want) 117 if got := dummys.Get("otherInt").Int(); got != want { 118 t.Errorf("got %#v, want %#v", got, want) 119 } 120 if dummys.Get("someInt") != dummys.Get("someInt") { 121 t.Errorf("same value not equal") 122 } 123 if got := dummys.Get("zero").Int(); got != 0 { 124 t.Errorf("got %#v, want %#v", got, 0) 125 } 126 } 127 128 func TestIntConversion(t *testing.T) { 129 testIntConversion(t, 0) 130 testIntConversion(t, 1) 131 testIntConversion(t, -1) 132 testIntConversion(t, 1<<20) 133 testIntConversion(t, -1<<20) 134 135 // Skip too big integers. They cannot be compiled with 32bit environment, and GopherJS is one of them. 136 // testIntConversion(t, 1<<40) 137 // testIntConversion(t, -1<<40) 138 // testIntConversion(t, 1<<60) 139 // testIntConversion(t, -1<<60) 140 } 141 142 func testIntConversion(t *testing.T, want int) { 143 if got := js.ValueOf(want).Int(); got != want { 144 t.Errorf("got %#v, want %#v", got, want) 145 } 146 } 147 148 func TestFloat(t *testing.T) { 149 want := 42.123 150 o := dummys.Get("someFloat") 151 if got := o.Float(); got != want { 152 t.Errorf("got %#v, want %#v", got, want) 153 } 154 dummys.Set("otherFloat", want) 155 if got := dummys.Get("otherFloat").Float(); got != want { 156 t.Errorf("got %#v, want %#v", got, want) 157 } 158 if dummys.Get("someFloat") != dummys.Get("someFloat") { 159 t.Errorf("same value not equal") 160 } 161 } 162 163 func TestObject(t *testing.T) { 164 if dummys.Get("someArray") != dummys.Get("someArray") { 165 t.Errorf("same value not equal") 166 } 167 168 // An object and its prototype should not be equal. 169 proto := js.Global().Get("Object").Get("prototype") 170 o := js.Global().Call("eval", "new Object()") 171 if proto == o { 172 t.Errorf("object equals to its prototype") 173 } 174 } 175 176 func TestFrozenObject(t *testing.T) { 177 o := js.Global().Call("eval", "(function () { let o = new Object(); o.field = 5; Object.freeze(o); return o; })()") 178 want := 5 179 if got := o.Get("field").Int(); want != got { 180 t.Errorf("got %#v, want %#v", got, want) 181 } 182 } 183 184 func TestNaN(t *testing.T) { 185 t.Skip("NaN cannot be compared") 186 187 want := js.ValueOf(math.NaN()) 188 got := dummys.Get("NaN") 189 if got != want { 190 t.Errorf("got %#v, want %#v", got, want) 191 } 192 } 193 194 func TestUndefined(t *testing.T) { 195 dummys.Set("test", js.Undefined()) 196 if dummys == js.Undefined() || dummys.Get("test") != js.Undefined() || dummys.Get("xyz") != js.Undefined() { 197 t.Errorf("js.Undefined expected") 198 } 199 } 200 201 func TestNull(t *testing.T) { 202 dummys.Set("test1", nil) 203 dummys.Set("test2", js.Null()) 204 if dummys == js.Null() || dummys.Get("test1") != js.Null() || dummys.Get("test2") != js.Null() { 205 t.Errorf("js.Null expected") 206 } 207 } 208 209 func TestLength(t *testing.T) { 210 if got := dummys.Get("someArray").Length(); got != 3 { 211 t.Errorf("got %#v, want %#v", got, 3) 212 } 213 } 214 215 func TestGet(t *testing.T) { 216 // positive cases get tested per type 217 218 expectValueError(t, func() { 219 dummys.Get("zero").Get("badField") 220 }) 221 } 222 223 func TestSet(t *testing.T) { 224 // positive cases get tested per type 225 226 expectValueError(t, func() { 227 dummys.Get("zero").Set("badField", 42) 228 }) 229 } 230 231 func TestIndex(t *testing.T) { 232 if got := dummys.Get("someArray").Index(1).Int(); got != 42 { 233 t.Errorf("got %#v, want %#v", got, 42) 234 } 235 236 expectValueError(t, func() { 237 dummys.Get("zero").Index(1) 238 }) 239 } 240 241 func TestSetIndex(t *testing.T) { 242 dummys.Get("someArray").SetIndex(2, 99) 243 if got := dummys.Get("someArray").Index(2).Int(); got != 99 { 244 t.Errorf("got %#v, want %#v", got, 99) 245 } 246 247 expectValueError(t, func() { 248 dummys.Get("zero").SetIndex(2, 99) 249 }) 250 } 251 252 func TestCall(t *testing.T) { 253 var i int64 = 40 254 if got := dummys.Call("add", i, 2).Int(); got != 42 { 255 t.Errorf("got %#v, want %#v", got, 42) 256 } 257 if got := dummys.Call("add", js.Global().Call("eval", "40"), 2).Int(); got != 42 { 258 t.Errorf("got %#v, want %#v", got, 42) 259 } 260 261 expectPanic(t, func() { 262 dummys.Call("zero") 263 }) 264 expectValueError(t, func() { 265 dummys.Get("zero").Call("badMethod") 266 }) 267 } 268 269 func TestInvoke(t *testing.T) { 270 var i int64 = 40 271 if got := dummys.Get("add").Invoke(i, 2).Int(); got != 42 { 272 t.Errorf("got %#v, want %#v", got, 42) 273 } 274 275 expectValueError(t, func() { 276 dummys.Get("zero").Invoke() 277 }) 278 } 279 280 func TestNew(t *testing.T) { 281 if got := js.Global().Get("Array").New(42).Length(); got != 42 { 282 t.Errorf("got %#v, want %#v", got, 42) 283 } 284 285 expectValueError(t, func() { 286 dummys.Get("zero").New() 287 }) 288 } 289 290 func TestInstanceOf(t *testing.T) { 291 someArray := js.Global().Get("Array").New() 292 if got, want := someArray.InstanceOf(js.Global().Get("Array")), true; got != want { 293 t.Errorf("got %#v, want %#v", got, want) 294 } 295 if got, want := someArray.InstanceOf(js.Global().Get("Function")), false; got != want { 296 t.Errorf("got %#v, want %#v", got, want) 297 } 298 } 299 300 func TestType(t *testing.T) { 301 if got, want := js.Undefined().Type(), js.TypeUndefined; got != want { 302 t.Errorf("got %s, want %s", got, want) 303 } 304 if got, want := js.Null().Type(), js.TypeNull; got != want { 305 t.Errorf("got %s, want %s", got, want) 306 } 307 if got, want := js.ValueOf(true).Type(), js.TypeBoolean; got != want { 308 t.Errorf("got %s, want %s", got, want) 309 } 310 if got, want := js.ValueOf(0).Type(), js.TypeNumber; got != want { 311 t.Errorf("got %s, want %s", got, want) 312 } 313 if got, want := js.ValueOf(42).Type(), js.TypeNumber; got != want { 314 t.Errorf("got %s, want %s", got, want) 315 } 316 if got, want := js.ValueOf("test").Type(), js.TypeString; got != want { 317 t.Errorf("got %s, want %s", got, want) 318 } 319 if got, want := js.Global().Get("Symbol").Invoke("test").Type(), js.TypeSymbol; got != want { 320 t.Errorf("got %s, want %s", got, want) 321 } 322 if got, want := js.Global().Get("Array").New().Type(), js.TypeObject; got != want { 323 t.Errorf("got %s, want %s", got, want) 324 } 325 if got, want := js.Global().Get("Array").Type(), js.TypeFunction; got != want { 326 t.Errorf("got %s, want %s", got, want) 327 } 328 } 329 330 type object = map[string]interface{} 331 type array = []interface{} 332 333 func TestValueOf(t *testing.T) { 334 a := js.ValueOf(array{0, array{0, 42, 0}, 0}) 335 if got := a.Index(1).Index(1).Int(); got != 42 { 336 t.Errorf("got %v, want %v", got, 42) 337 } 338 339 o := js.ValueOf(object{"x": object{"y": 42}}) 340 if got := o.Get("x").Get("y").Int(); got != 42 { 341 t.Errorf("got %v, want %v", got, 42) 342 } 343 } 344 345 func TestZeroValue(t *testing.T) { 346 var v js.Value 347 if v != js.Undefined() { 348 t.Error("zero js.Value is not js.Undefined()") 349 } 350 } 351 352 func TestFuncOf(t *testing.T) { 353 c := make(chan struct{}) 354 cb := js.FuncOf(func(this js.Value, args []js.Value) interface{} { 355 if got := args[0].Int(); got != 42 { 356 t.Errorf("got %#v, want %#v", got, 42) 357 } 358 c <- struct{}{} 359 return nil 360 }) 361 defer cb.Release() 362 js.Global().Call("setTimeout", cb, 0, 42) 363 <-c 364 } 365 366 func TestInvokeFunction(t *testing.T) { 367 called := false 368 cb := js.FuncOf(func(this js.Value, args []js.Value) interface{} { 369 cb2 := js.FuncOf(func(this js.Value, args []js.Value) interface{} { 370 called = true 371 return 42 372 }) 373 defer cb2.Release() 374 return cb2.Invoke() 375 }) 376 defer cb.Release() 377 if got := cb.Invoke().Int(); got != 42 { 378 t.Errorf("got %#v, want %#v", got, 42) 379 } 380 if !called { 381 t.Error("function not called") 382 } 383 } 384 385 func ExampleFuncOf() { 386 var cb js.Func 387 cb = js.FuncOf(func(this js.Value, args []js.Value) interface{} { 388 fmt.Println("button clicked") 389 cb.Release() // release the function if the button will not be clicked again 390 return nil 391 }) 392 js.Global().Get("document").Call("getElementById", "myButton").Call("addEventListener", "click", cb) 393 } 394 395 // See 396 // - https://developer.mozilla.org/en-US/docs/Glossary/Truthy 397 // - https://stackoverflow.com/questions/19839952/all-falsey-values-in-javascript/19839953#19839953 398 // - http://www.ecma-international.org/ecma-262/5.1/#sec-9.2 399 func TestTruthy(t *testing.T) { 400 want := true 401 for _, key := range []string{ 402 "someBool", "someString", "someInt", "someFloat", "someArray", "someDate", 403 "stringZero", // "0" is truthy 404 "add", // functions are truthy 405 "emptyObj", "emptyArray", "Infinity", "NegInfinity", 406 // All objects are truthy, even if they're Number(0) or Boolean(false). 407 "objNumber0", "objBooleanFalse", 408 } { 409 if got := dummys.Get(key).Truthy(); got != want { 410 t.Errorf("%s: got %#v, want %#v", key, got, want) 411 } 412 } 413 414 want = false 415 if got := dummys.Get("zero").Truthy(); got != want { 416 t.Errorf("got %#v, want %#v", got, want) 417 } 418 if got := dummys.Get("NaN").Truthy(); got != want { 419 t.Errorf("got %#v, want %#v", got, want) 420 } 421 if got := js.ValueOf("").Truthy(); got != want { 422 t.Errorf("got %#v, want %#v", got, want) 423 } 424 if got := js.Null().Truthy(); got != want { 425 t.Errorf("got %#v, want %#v", got, want) 426 } 427 if got := js.Undefined().Truthy(); got != want { 428 t.Errorf("got %#v, want %#v", got, want) 429 } 430 } 431 432 func expectValueError(t *testing.T, fn func()) { 433 defer func() { 434 err := recover() 435 if _, ok := err.(*js.ValueError); !ok { 436 t.Errorf("expected *js.ValueError, got %T", err) 437 } 438 }() 439 fn() 440 } 441 442 func expectPanic(t *testing.T, fn func()) { 443 defer func() { 444 err := recover() 445 if err == nil { 446 t.Errorf("expected panic") 447 } 448 }() 449 fn() 450 } 451 452 var copyTests = []struct { 453 srcLen int 454 dstLen int 455 copyLen int 456 }{ 457 {5, 3, 3}, 458 {3, 5, 3}, 459 {0, 0, 0}, 460 } 461 462 func TestCopyBytesToGo(t *testing.T) { 463 for _, tt := range copyTests { 464 t.Run(fmt.Sprintf("%d-to-%d", tt.srcLen, tt.dstLen), func(t *testing.T) { 465 src := js.Global().Get("Uint8Array").New(tt.srcLen) 466 if tt.srcLen >= 2 { 467 src.SetIndex(1, 42) 468 } 469 dst := make([]byte, tt.dstLen) 470 471 if got, want := js.CopyBytesToGo(dst, src), tt.copyLen; got != want { 472 t.Errorf("copied %d, want %d", got, want) 473 } 474 if tt.dstLen >= 2 { 475 if got, want := int(dst[1]), 42; got != want { 476 t.Errorf("got %d, want %d", got, want) 477 } 478 } 479 }) 480 } 481 } 482 483 func TestCopyBytesToJS(t *testing.T) { 484 for _, tt := range copyTests { 485 t.Run(fmt.Sprintf("%d-to-%d", tt.srcLen, tt.dstLen), func(t *testing.T) { 486 src := make([]byte, tt.srcLen) 487 if tt.srcLen >= 2 { 488 src[1] = 42 489 } 490 dst := js.Global().Get("Uint8Array").New(tt.dstLen) 491 492 if got, want := js.CopyBytesToJS(dst, src), tt.copyLen; got != want { 493 t.Errorf("copied %d, want %d", got, want) 494 } 495 if tt.dstLen >= 2 { 496 if got, want := dst.Index(1).Int(), 42; got != want { 497 t.Errorf("got %d, want %d", got, want) 498 } 499 } 500 }) 501 } 502 }