Source file src/syscall/js/js_test.go

Documentation: syscall/js

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

View as plain text