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  }