Newer
Older
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build js,wasm
// To run these tests:
//
// - Install Node
// - Add /path/to/go/misc/wasm to your $PATH (so that "go test" can find
// "go_js_wasm_exec").
// - GOOS=js GOARCH=wasm go test
//
// See -exec in "go help test", and "go help run" for details.
var dummys = js.Global().Call("eval", `({
someBool: true,
someString: "abc\u1234",
someInt: 42,
someFloat: 42.123,
someArray: [41, 42, 43],
emptyObj: {},
emptyArray: [],
Infinity: Infinity,
NegInfinity: -Infinity,
objNumber0: new Number(0),
objBooleanFalse: new Boolean(false),
})`)
func TestBool(t *testing.T) {
want := true
o := dummys.Get("someBool")
if got := o.Bool(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
dummys.Set("otherBool", want)
if got := dummys.Get("otherBool").Bool(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
if dummys.Get("someBool") != dummys.Get("someBool") {
t.Errorf("same value not equal")
}
}
func TestString(t *testing.T) {
want := "abc\u1234"
o := dummys.Get("someString")
if got := o.String(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
dummys.Set("otherString", want)
if got := dummys.Get("otherString").String(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
if dummys.Get("someString") != dummys.Get("someString") {
t.Errorf("same value not equal")
}
wantInt := "42"
o = dummys.Get("someInt")
if got := o.String(); got != wantInt {
t.Errorf("got %#v, want %#v", got, wantInt)
}
}
func TestInt(t *testing.T) {
want := 42
o := dummys.Get("someInt")
if got := o.Int(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
dummys.Set("otherInt", want)
if got := dummys.Get("otherInt").Int(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
if dummys.Get("someInt") != dummys.Get("someInt") {
t.Errorf("same value not equal")
}
if got := dummys.Get("zero").Int(); got != 0 {
t.Errorf("got %#v, want %#v", got, 0)
}
func TestIntConversion(t *testing.T) {
testIntConversion(t, 0)
testIntConversion(t, 1)
testIntConversion(t, -1)
testIntConversion(t, 1<<20)
testIntConversion(t, -1<<20)
testIntConversion(t, 1<<40)
testIntConversion(t, -1<<40)
testIntConversion(t, 1<<60)
testIntConversion(t, -1<<60)
}
func testIntConversion(t *testing.T, want int) {
if got := js.ValueOf(want).Int(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
}
func TestFloat(t *testing.T) {
want := 42.123
o := dummys.Get("someFloat")
if got := o.Float(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
dummys.Set("otherFloat", want)
if got := dummys.Get("otherFloat").Float(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
if dummys.Get("someFloat") != dummys.Get("someFloat") {
t.Errorf("same value not equal")
}
}
func TestObject(t *testing.T) {
if dummys.Get("someArray") != dummys.Get("someArray") {
t.Errorf("same value not equal")
}
// An object and its prototype should not be equal.
proto := js.Global().Get("Object").Get("prototype")
o := js.Global().Call("eval", "new Object()")
if proto == o {
t.Errorf("object equals to its prototype")
}
func TestFrozenObject(t *testing.T) {
o := js.Global().Call("eval", "(function () { let o = new Object(); o.field = 5; Object.freeze(o); return o; })()")
want := 5
if got := o.Get("field").Int(); want != got {
t.Errorf("got %#v, want %#v", got, want)
}
}
func TestTypedArrayOf(t *testing.T) {
testTypedArrayOf(t, "[]int8", []int8{0, -42, 0}, -42)
testTypedArrayOf(t, "[]int16", []int16{0, -42, 0}, -42)
testTypedArrayOf(t, "[]int32", []int32{0, -42, 0}, -42)
testTypedArrayOf(t, "[]uint8", []uint8{0, 42, 0}, 42)
testTypedArrayOf(t, "[]uint16", []uint16{0, 42, 0}, 42)
testTypedArrayOf(t, "[]uint32", []uint32{0, 42, 0}, 42)
testTypedArrayOf(t, "[]float32", []float32{0, -42.5, 0}, -42.5)
testTypedArrayOf(t, "[]float64", []float64{0, -42.5, 0}, -42.5)
}
func testTypedArrayOf(t *testing.T, name string, slice interface{}, want float64) {
t.Run(name, func(t *testing.T) {
a := js.TypedArrayOf(slice)
got := a.Index(1).Float()
a.Release()
if got != want {
t.Errorf("got %#v, want %#v", got, want)
}
})
}
func TestNaN(t *testing.T) {
want := js.ValueOf(math.NaN())
got := dummys.Get("NaN")
if got != want {
t.Errorf("got %#v, want %#v", got, want)
}
dummys.Set("test", js.Undefined())
if dummys == js.Undefined() || dummys.Get("test") != js.Undefined() || dummys.Get("xyz") != js.Undefined() {
t.Errorf("js.Undefined expected")
}
}
func TestNull(t *testing.T) {
dummys.Set("test1", nil)
dummys.Set("test2", js.Null())
if dummys == js.Null() || dummys.Get("test1") != js.Null() || dummys.Get("test2") != js.Null() {
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
t.Errorf("js.Null expected")
}
}
func TestLength(t *testing.T) {
if got := dummys.Get("someArray").Length(); got != 3 {
t.Errorf("got %#v, want %#v", got, 3)
}
}
func TestIndex(t *testing.T) {
if got := dummys.Get("someArray").Index(1).Int(); got != 42 {
t.Errorf("got %#v, want %#v", got, 42)
}
}
func TestSetIndex(t *testing.T) {
dummys.Get("someArray").SetIndex(2, 99)
if got := dummys.Get("someArray").Index(2).Int(); got != 99 {
t.Errorf("got %#v, want %#v", got, 99)
}
}
func TestCall(t *testing.T) {
var i int64 = 40
if got := dummys.Call("add", i, 2).Int(); got != 42 {
t.Errorf("got %#v, want %#v", got, 42)
}
if got := dummys.Call("add", js.Global().Call("eval", "40"), 2).Int(); got != 42 {
t.Errorf("got %#v, want %#v", got, 42)
}
}
func TestInvoke(t *testing.T) {
var i int64 = 40
if got := dummys.Get("add").Invoke(i, 2).Int(); got != 42 {
t.Errorf("got %#v, want %#v", got, 42)
}
}
func TestNew(t *testing.T) {
if got := js.Global().Get("Array").New(42).Length(); got != 42 {
t.Errorf("got %#v, want %#v", got, 42)
}
}
someArray := js.Global().Get("Array").New()
if got, want := someArray.InstanceOf(js.Global().Get("Array")), true; got != want {
t.Errorf("got %#v, want %#v", got, want)
}
if got, want := someArray.InstanceOf(js.Global().Get("Function")), false; got != want {
t.Errorf("got %#v, want %#v", got, want)
}
}
func TestType(t *testing.T) {
if got, want := js.Undefined().Type(), js.TypeUndefined; got != want {
t.Errorf("got %s, want %s", got, want)
}
if got, want := js.Null().Type(), js.TypeNull; got != want {
t.Errorf("got %s, want %s", got, want)
}
if got, want := js.ValueOf(true).Type(), js.TypeBoolean; got != want {
t.Errorf("got %s, want %s", got, want)
}
if got, want := js.ValueOf(0).Type(), js.TypeNumber; got != want {
t.Errorf("got %s, want %s", got, want)
}
if got, want := js.ValueOf(42).Type(), js.TypeNumber; got != want {
t.Errorf("got %s, want %s", got, want)
}
if got, want := js.ValueOf("test").Type(), js.TypeString; got != want {
t.Errorf("got %s, want %s", got, want)
}
if got, want := js.Global().Get("Symbol").Invoke("test").Type(), js.TypeSymbol; got != want {
t.Errorf("got %s, want %s", got, want)
}
if got, want := js.Global().Get("Array").New().Type(), js.TypeObject; got != want {
t.Errorf("got %s, want %s", got, want)
}
if got, want := js.Global().Get("Array").Type(), js.TypeFunction; got != want {
t.Errorf("got %s, want %s", got, want)
}
}
type object = map[string]interface{}
type array = []interface{}
func TestValueOf(t *testing.T) {
a := js.ValueOf(array{0, array{0, 42, 0}, 0})
if got := a.Index(1).Index(1).Int(); got != 42 {
t.Errorf("got %v, want %v", got, 42)
}
o := js.ValueOf(object{"x": object{"y": 42}})
if got := o.Get("x").Get("y").Int(); got != 42 {
t.Errorf("got %v, want %v", got, 42)
}
}
func TestZeroValue(t *testing.T) {
var v js.Value
if v != js.Undefined() {
t.Error("zero js.Value is not js.Undefined()")
}
}
func TestCallback(t *testing.T) {
c := make(chan struct{})
cb := js.NewCallback(func(args []js.Value) {
if got := args[0].Int(); got != 42 {
t.Errorf("got %#v, want %#v", got, 42)
}
c <- struct{}{}
})
defer cb.Release()
js.Global().Call("setTimeout", cb, 0, 42)
<-c
}
func TestEventCallback(t *testing.T) {
for _, name := range []string{"preventDefault", "stopPropagation", "stopImmediatePropagation"} {
c := make(chan struct{})
var flags js.EventCallbackFlag
switch name {
case "preventDefault":
flags = js.PreventDefault
case "stopPropagation":
flags = js.StopPropagation
case "stopImmediatePropagation":
flags = js.StopImmediatePropagation
}
cb := js.NewEventCallback(flags, func(event js.Value) {
c <- struct{}{}
})
defer cb.Release()
event := js.Global().Call("eval", fmt.Sprintf("({ called: false, %s: function() { this.called = true; } })", name))
cb.Invoke(event)
if !event.Get("called").Bool() {
t.Errorf("%s not called", name)
}
<-c
}
}
func ExampleNewCallback() {
var cb js.Callback
cb = js.NewCallback(func(args []js.Value) {
fmt.Println("button clicked")
cb.Release() // release the callback if the button will not be clicked again
js.Global().Get("document").Call("getElementById", "myButton").Call("addEventListener", "click", cb)
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
// See
// - https://developer.mozilla.org/en-US/docs/Glossary/Truthy
// - https://stackoverflow.com/questions/19839952/all-falsey-values-in-javascript/19839953#19839953
// - http://www.ecma-international.org/ecma-262/5.1/#sec-9.2
func TestTruthy(t *testing.T) {
want := true
for _, key := range []string{
"someBool", "someString", "someInt", "someFloat", "someArray", "someDate",
"stringZero", // "0" is truthy
"add", // functions are truthy
"emptyObj", "emptyArray", "Infinity", "NegInfinity",
// All objects are truthy, even if they're Number(0) or Boolean(false).
"objNumber0", "objBooleanFalse",
} {
if got := dummys.Get(key).Truthy(); got != want {
t.Errorf("%s: got %#v, want %#v", key, got, want)
}
}
want = false
if got := dummys.Get("zero").Truthy(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
if got := dummys.Get("NaN").Truthy(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
if got := js.ValueOf("").Truthy(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
if got := js.Null().Truthy(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
if got := js.Undefined().Truthy(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
}