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  }