summary refs log tree commit diff stats
path: root/tests/js
diff options
context:
space:
mode:
Diffstat (limited to 'tests/js')
-rw-r--r--tests/js/readme.md5
-rw-r--r--tests/js/t11166.nim18
-rw-r--r--tests/js/t11354.nim20
-rw-r--r--tests/js/t11697.nim5
-rw-r--r--tests/js/t12303.nim16
-rw-r--r--tests/js/t12672.nim12
-rw-r--r--tests/js/t14153.nim22
-rw-r--r--tests/js/t14570.nim11
-rw-r--r--tests/js/t17177.nim10
-rw-r--r--tests/js/t20233.nim7
-rw-r--r--tests/js/t20235.nim11
-rw-r--r--tests/js/t21209.nim6
-rw-r--r--tests/js/t21209.nims1
-rw-r--r--tests/js/t21247.nim15
-rw-r--r--tests/js/t21439.nim11
-rw-r--r--tests/js/t7109.nim8
-rw-r--r--tests/js/t7127.nim2
-rw-r--r--tests/js/t7224.nim9
-rw-r--r--tests/js/t8231.nim3
-rw-r--r--tests/js/t8821.nim9
-rw-r--r--tests/js/t9410.nim4
-rw-r--r--tests/js/taddr.nim79
-rw-r--r--tests/js/tarrayboundscheck.nim6
-rw-r--r--tests/js/tasync.nim33
-rw-r--r--tests/js/tasyncjs.nim107
-rw-r--r--tests/js/tasyncjs_bad.nim22
-rw-r--r--tests/js/tasyncjs_pragma.nim (renamed from tests/js/tasync_pragma.nim)2
-rw-r--r--tests/js/tbasics.nim2
-rw-r--r--tests/js/tbigint_backend.nim57
-rw-r--r--tests/js/tbyvar.nim15
-rw-r--r--tests/js/tclosures.nim2
-rw-r--r--tests/js/tcodegendeclproc.nim2
-rw-r--r--tests/js/tconsole.nim1
-rw-r--r--tests/js/tcsymbol.nim6
-rw-r--r--tests/js/tdanger.nim17
-rw-r--r--tests/js/tdiscard.nim3
-rw-r--r--tests/js/tdollar_float.nim62
-rw-r--r--tests/js/temptyseq.nim8
-rw-r--r--tests/js/tfieldchecks.nim6
-rw-r--r--tests/js/tglobal.nim30
-rw-r--r--tests/js/tindexdefect.nim9
-rw-r--r--tests/js/tjsffi.nim447
-rw-r--r--tests/js/tjsffi_old.nim9
-rw-r--r--tests/js/tjshello.nim2
-rw-r--r--tests/js/tjshello_stacktrace.nim9
-rw-r--r--tests/js/tjsnimscombined.nim1
-rw-r--r--tests/js/tjsnimscombined.nims1
-rw-r--r--tests/js/tlent.nim33
-rw-r--r--tests/js/tmangle.nim4
-rw-r--r--tests/js/tmodify_cstring.nim6
-rw-r--r--tests/js/tnativeexc.nim2
-rw-r--r--tests/js/tneginthash.nim21
-rw-r--r--tests/js/tnilstrs.nim10
-rw-r--r--tests/js/tos.nim21
-rw-r--r--tests/js/trepr.nim93
-rw-r--r--tests/js/treprinifexpr.nim18
-rw-r--r--tests/js/tseqops.nim21
-rw-r--r--tests/js/tsourcemap.nim96
-rw-r--r--tests/js/tstdlib_imports.nim80
-rw-r--r--tests/js/tstdlib_various.nim174
-rw-r--r--tests/js/tstreams.nim22
-rw-r--r--tests/js/ttempgen.nim79
-rw-r--r--tests/js/ttypedarray.nim26
-rw-r--r--tests/js/tunion.nim7
-rw-r--r--tests/js/tunittest_error.nim24
-rw-r--r--tests/js/tunittest_error2.nim16
-rw-r--r--tests/js/tunittests.nim11
-rw-r--r--tests/js/twritestacktrace.nim12
68 files changed, 1448 insertions, 471 deletions
diff --git a/tests/js/readme.md b/tests/js/readme.md
new file mode 100644
index 000000000..7fcc722fa
--- /dev/null
+++ b/tests/js/readme.md
@@ -0,0 +1,5 @@
+## notes
+Prefer moving tests to a non-js directory so that they get tested across all backends automatically.
+Ideally, tests/js should be reserved to code that only makes sense in js.
+
+Note also that tests for a js specific module (e.g.: `std/jsbigints`) belong to `tests/stdlib`, (e.g.: `tests/stdlib/tjsbigints.nim`)
diff --git a/tests/js/t11166.nim b/tests/js/t11166.nim
index 8dd77925c..e98ccda10 100644
--- a/tests/js/t11166.nim
+++ b/tests/js/t11166.nim
@@ -1,4 +1,20 @@
+discard """
+  output: '''
+test1
+test2
+'''
+"""
+
 import jsffi
 
+type
+  C = object
+    props: int
+
+var c: C
+
 when compiles(c.props):
-  echo "test"
+  echo "test1"
+
+when not compiles(d.props):
+  echo "test2"
diff --git a/tests/js/t11354.nim b/tests/js/t11354.nim
new file mode 100644
index 000000000..8dee90de0
--- /dev/null
+++ b/tests/js/t11354.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''
+0
+@[@[0, 1]]
+'''
+"""
+
+type
+  TrackySeq[T] = object
+    s: seq[T]
+    pos: int
+
+proc foobar(ls: var TrackySeq[seq[int]], i: int): var seq[int] =
+  echo ls.pos  # removing this, or making the return explicit works
+  ls.s[i]
+
+var foo: TrackySeq[seq[int]]
+foo.s.add(@[0])
+foo.foobar(0).add(1)
+echo foo.s
\ No newline at end of file
diff --git a/tests/js/t11697.nim b/tests/js/t11697.nim
new file mode 100644
index 000000000..967752586
--- /dev/null
+++ b/tests/js/t11697.nim
@@ -0,0 +1,5 @@
+import tables
+
+var xs: Table[int, Table[int, int]]
+
+doAssertRaises(KeyError): reset xs[0]
diff --git a/tests/js/t12303.nim b/tests/js/t12303.nim
new file mode 100644
index 000000000..270d82ced
--- /dev/null
+++ b/tests/js/t12303.nim
@@ -0,0 +1,16 @@
+discard """
+  output: "{ b: 2 }"
+"""
+
+import jsconsole, jsffi
+
+type
+  A = ref object
+   b: B
+
+  B = object
+    b: int
+
+var a = cast[A](js{})
+a.b = B(b: 2)
+console.log a.b
diff --git a/tests/js/t12672.nim b/tests/js/t12672.nim
new file mode 100644
index 000000000..a658fbcbe
--- /dev/null
+++ b/tests/js/t12672.nim
@@ -0,0 +1,12 @@
+discard """
+  output: ""
+"""
+
+proc foo =
+  var x: seq[seq[int]]
+  for row in x.mitems:
+    let i = 1
+    echo row
+    inc row[i-1]
+
+foo()
diff --git a/tests/js/t14153.nim b/tests/js/t14153.nim
new file mode 100644
index 000000000..350bbd83b
--- /dev/null
+++ b/tests/js/t14153.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''
+index 5 not in 0 .. 2
+index 5 not in 0 .. 2
+'''
+"""
+
+var x = @[1, 2, 3]
+
+try:
+  echo x[5]
+except IndexError:
+  echo getCurrentExceptionMsg()
+except:
+  doAssert false
+
+try:
+  x[5] = 8
+except IndexError:
+  echo getCurrentExceptionMsg()
+except:
+  doAssert false
diff --git a/tests/js/t14570.nim b/tests/js/t14570.nim
new file mode 100644
index 000000000..100c2651d
--- /dev/null
+++ b/tests/js/t14570.nim
@@ -0,0 +1,11 @@
+discard """
+  output: '''
+18
+'''
+"""
+
+type A = range[15 .. 30]
+
+let a: A = 18
+
+echo ord(a)
diff --git a/tests/js/t17177.nim b/tests/js/t17177.nim
new file mode 100644
index 000000000..fc362cec1
--- /dev/null
+++ b/tests/js/t17177.nim
@@ -0,0 +1,10 @@
+import std/asyncjs
+
+proc fn1(n: int): Future[int] {.async.} = return n
+proc main2() =
+  proc fn2(n: int): Future[int] {.async.} = return n
+proc main3(a: auto) =
+  proc fn3(n: int): Future[int] {.async.} = return n
+proc main4() {.async.} =
+  proc fn4(n: int): Future[int] {.async.} = return n
+  discard
diff --git a/tests/js/t20233.nim b/tests/js/t20233.nim
new file mode 100644
index 000000000..401d14122
--- /dev/null
+++ b/tests/js/t20233.nim
@@ -0,0 +1,7 @@
+discard """
+  output: "yes"
+"""
+case 1.0
+of 1.0..2.0, 4.0: echo "yes"
+of 3.0: discard
+else: echo "no"
\ No newline at end of file
diff --git a/tests/js/t20235.nim b/tests/js/t20235.nim
new file mode 100644
index 000000000..3a69c2bd6
--- /dev/null
+++ b/tests/js/t20235.nim
@@ -0,0 +1,11 @@
+discard """
+  action: "run"
+  output: "0 4"
+"""
+
+proc main =
+  var s = ""
+  s.setLen(4)
+  echo s[0].ord, " ", s.len
+
+main()
diff --git a/tests/js/t21209.nim b/tests/js/t21209.nim
new file mode 100644
index 000000000..4de34f035
--- /dev/null
+++ b/tests/js/t21209.nim
@@ -0,0 +1,6 @@
+discard """
+  action: "compile"
+  cmd: "nim check --warning[UnusedImport]:off $file"
+"""
+
+import std/times
diff --git a/tests/js/t21209.nims b/tests/js/t21209.nims
new file mode 100644
index 000000000..318e28f97
--- /dev/null
+++ b/tests/js/t21209.nims
@@ -0,0 +1 @@
+--b:js
\ No newline at end of file
diff --git a/tests/js/t21247.nim b/tests/js/t21247.nim
new file mode 100644
index 000000000..5b38787b3
--- /dev/null
+++ b/tests/js/t21247.nim
@@ -0,0 +1,15 @@
+import std/typetraits
+
+type
+  QueryParams* = distinct seq[(string, string)]
+
+converter toBase*(params: var QueryParams): var seq[(string, string)] =
+  params.distinctBase
+
+proc foo(): QueryParams =
+  # Issue was that the implicit converter call didn't say that it took the
+  # address of the parameter it was converting. This led to the parameter not being
+  # passed as a fat pointer which toBase expected
+  result.add(("hello", "world"))
+
+assert foo().distinctBase() == @[("hello", "world")]
diff --git a/tests/js/t21439.nim b/tests/js/t21439.nim
new file mode 100644
index 000000000..3caeb090a
--- /dev/null
+++ b/tests/js/t21439.nim
@@ -0,0 +1,11 @@
+proc test(a: openArray[string]): proc =
+  let a = @a
+  result = proc =
+    for i in a:
+      discard i
+
+
+const a = ["t1", "t2"]
+
+discard test(a)
+
diff --git a/tests/js/t7109.nim b/tests/js/t7109.nim
new file mode 100644
index 000000000..a1a3b718e
--- /dev/null
+++ b/tests/js/t7109.nim
@@ -0,0 +1,8 @@
+iterator iter*(): int {.closure.} =
+  yield 3
+
+var x = iter
+doAssert x() == 3
+
+let fIt = iterator(): int = yield 70
+doAssert fIt() == 70
diff --git a/tests/js/t7127.nim b/tests/js/t7127.nim
new file mode 100644
index 000000000..364aedd4a
--- /dev/null
+++ b/tests/js/t7127.nim
@@ -0,0 +1,2 @@
+doAssertRaises(DivByZeroDefect): discard 1 mod 0
+doAssertRaises(DivByZeroDefect): discard 1 div 0
\ No newline at end of file
diff --git a/tests/js/t7224.nim b/tests/js/t7224.nim
index be9d0ae9c..77fef10a7 100644
--- a/tests/js/t7224.nim
+++ b/tests/js/t7224.nim
@@ -1,10 +1,11 @@
 discard """
   cmd: "nim $target $options --stackTrace:on --lineTrace:on $file"
   outputsub: '''
-t7224.aaa, line: 21
-t7224.bbb, line: 18
-t7224.ccc, line: 15
-t7224.ddd, line: 12
+t7224.nim(25) at module t7224
+t7224.nim(22) at t7224.aaa
+t7224.nim(19) at t7224.bbb
+t7224.nim(16) at t7224.ccc
+t7224.nim(13) at t7224.ddd
 '''
 """
 
diff --git a/tests/js/t8231.nim b/tests/js/t8231.nim
new file mode 100644
index 000000000..b0625a621
--- /dev/null
+++ b/tests/js/t8231.nim
@@ -0,0 +1,3 @@
+import strutils
+
+doAssert formatSize(2462056448, '.', bpIEC, false) == "2.293GiB"
\ No newline at end of file
diff --git a/tests/js/t8821.nim b/tests/js/t8821.nim
new file mode 100644
index 000000000..38c88efa8
--- /dev/null
+++ b/tests/js/t8821.nim
@@ -0,0 +1,9 @@
+
+proc isInt32(i: int): bool =
+  case i 
+  of 1 .. 70000:
+    return true
+  else:
+    return false
+
+doAssert isInt32(1) == true
\ No newline at end of file
diff --git a/tests/js/t9410.nim b/tests/js/t9410.nim
index 78c329a24..042520dc5 100644
--- a/tests/js/t9410.nim
+++ b/tests/js/t9410.nim
@@ -447,10 +447,10 @@ template tests =
       doAssert seqOfSeqs == @[@[10, 2], @[30, 4]]
 
   when false:
-    block: # openarray
+    block: # openArray
           # Error: internal error: genAddr: nkStmtListExpr
       var calls = 0
-      proc getvarint(x: var openarray[int]): var int =
+      proc getvarint(x: var openArray[int]): var int =
         calls += 1
         if true:
           x[1]
diff --git a/tests/js/taddr.nim b/tests/js/taddr.nim
deleted file mode 100644
index d8ff4c11b..000000000
--- a/tests/js/taddr.nim
+++ /dev/null
@@ -1,79 +0,0 @@
-discard """
-  action: run
-"""
-
-type T = object
-  x: int
-  s: string
-
-var obj: T
-var fieldAddr = addr(obj.x)
-var objAddr = addr(obj)
-
-# Integer tests
-var field = fieldAddr[]
-doAssert field == 0
-
-var objDeref = objAddr[]
-doAssert objDeref.x == 0
-
-# Change value
-obj.x = 42
-
-doAssert field == 0
-doAssert objDeref.x == 0
-
-field = fieldAddr[]
-objDeref = objAddr[]
-
-doAssert field == 42
-doAssert objDeref.x == 42
-
-# String tests
-obj.s = "lorem ipsum dolor sit amet"
-var indexAddr = addr(obj.s[2])
-
-doAssert indexAddr[] == 'r'
-
-indexAddr[] = 'd'
-
-doAssert indexAddr[] == 'd'
-
-doAssert obj.s == "lodem ipsum dolor sit amet"
-
-# Bug #2148
-var x: array[2, int]
-var y = addr x[1]
-
-y[] = 12
-doAssert(x[1] == 12)
-
-type
-  Foo = object
-    bar: int
-
-var foo: array[2, Foo]
-var z = addr foo[1]
-
-z[].bar = 12345
-doAssert(foo[1].bar == 12345)
-
-var t : tuple[a, b: int]
-var pt = addr t[1]
-pt[] = 123
-doAssert(t.b == 123)
-
-#block: # Test "untyped" pointer.
-proc testPtr(p: pointer, a: int) =
-  doAssert(a == 5)
-  (cast[ptr int](p))[] = 124
-var i = 123
-testPtr(addr i, 5)
-doAssert(i == 124)
-
-var someGlobal = 5
-proc getSomeGlobalPtr(): ptr int = addr someGlobal
-let someGlobalPtr = getSomeGlobalPtr()
-doAssert(someGlobalPtr[] == 5)
-someGlobalPtr[] = 10
-doAssert(someGlobal == 10)
diff --git a/tests/js/tarrayboundscheck.nim b/tests/js/tarrayboundscheck.nim
index f0eaeb89d..d8bf8de97 100644
--- a/tests/js/tarrayboundscheck.nim
+++ b/tests/js/tarrayboundscheck.nim
@@ -39,6 +39,12 @@ proc test_arrayboundscheck() =
         echo "month out of bounds: ", idx
     except:
       echo "idx out of bounds: ", i
+  
+  # #13966
+  var negativeIndexed: array[-2..2, int] = [0, 1, 2, 3, 4]
+  negativeIndexed[-1] = 2
+  negativeIndexed[1] = 2
+  doAssert negativeIndexed == [0, 2, 2, 2, 4]
 
 test_arrayboundscheck()
 {.pop.}
\ No newline at end of file
diff --git a/tests/js/tasync.nim b/tests/js/tasync.nim
deleted file mode 100644
index 318237651..000000000
--- a/tests/js/tasync.nim
+++ /dev/null
@@ -1,33 +0,0 @@
-discard """
-  output: '''
-x
-e
-'''
-"""
-
-import asyncjs
-
-# demonstrate forward definition
-# for js
-proc y(e: int): Future[string] {.async.}
-
-proc e: int {.discardable.} =
-  echo "e"
-  return 2
-
-proc x(e: int): Future[void] {.async.} =
-  var s = await y(e)
-  if e > 2:
-    return
-  echo s
-  e()
-
-proc y(e: int): Future[string] {.async.} =
-  if e > 0:
-    return await y(0)
-  else:
-    return "x"
-
-
-discard x(2)
-
diff --git a/tests/js/tasyncjs.nim b/tests/js/tasyncjs.nim
new file mode 100644
index 000000000..f3b273c44
--- /dev/null
+++ b/tests/js/tasyncjs.nim
@@ -0,0 +1,107 @@
+discard """
+  output: '''
+x
+e
+done
+'''
+"""
+
+#[
+xxx move this to tests/stdlib/tasyncjs.nim
+]#
+
+import std/asyncjs
+
+block:
+  # demonstrate forward definition for js
+  proc y(e: int): Future[string] {.async.}
+
+  proc e: int {.discardable.} =
+    echo "e"
+    return 2
+
+  proc x(e: int): Future[void] {.async.} =
+    var s = await y(e)
+    if e > 2:
+      return
+    echo s
+    e()
+
+  proc y(e: int): Future[string] {.async.} =
+    if e > 0:
+      return await y(0)
+    else:
+      return "x"
+
+  discard x(2)
+
+import std/sugar
+from std/strutils import contains
+
+var witness: seq[string]
+
+proc fn(n: int): Future[int] {.async.} =
+  if n >= 7:
+    raise newException(ValueError, "foobar: " & $n)
+  if n > 0:
+    var ret = 1 + await fn(n-1)
+    witness.add $(n, ret)
+    return ret
+  else:
+    return 10
+
+proc asyncFact(n: int): Future[int] {.async.} =
+  if n > 0: result = n * await asyncFact(n-1)
+  else: result = 1
+
+proc asyncIdentity(n: int): Future[int] {.async.} =
+  if n > 0: result = 1 + await asyncIdentity(n-1)
+  else: result = 0
+
+proc main() {.async.} =
+  block: # then
+    let x = await fn(4)
+      .then((a: int) => a.float)
+      .then((a: float) => $a)
+    doAssert x == "14.0"
+    doAssert witness == @["(1, 11)", "(2, 12)", "(3, 13)", "(4, 14)"]
+
+    doAssert (await fn(2)) == 12
+
+    let x2 = await fn(4).then((a: int) => (discard)).then(() => 13)
+    doAssert x2 == 13
+
+    let x4 = await asyncFact(3).then(asyncIdentity).then(asyncIdentity).then((a:int) => a * 7).then(asyncIdentity)
+    doAssert x4 == 3 * 2 * 7
+
+    block: # bug #17177
+      proc asyncIdentityNested(n: int): Future[int] {.async.} = return n
+      let x5 = await asyncFact(3).then(asyncIdentityNested)
+      doAssert x5 == 3 * 2
+
+    when false: # xxx pending bug #17254
+      let x6 = await asyncFact(3).then((a:int) {.async.} => a * 11)
+      doAssert x6 == 3 * 2 * 11
+
+  block: # catch
+    var reason: Error
+    await fn(6).then((a: int) => (witness.add $a)).catch((r: Error) => (reason = r))
+    doAssert reason == nil
+
+    await fn(7).then((a: int) => (discard)).catch((r: Error) => (reason = r))
+    doAssert reason != nil
+    doAssert reason.name == "Error"
+    doAssert "foobar: 7" in $reason.message
+  echo "done" # justified here to make sure we're running this, since it's inside `async`
+
+block asyncPragmaInType:
+  type Handler = proc () {.async.}
+  proc foo() {.async.} = discard
+  var x: Handler = foo
+
+block: # 13341
+  proc f {.async.} =
+    proc g: int =
+      result = 123
+
+discard main()
diff --git a/tests/js/tasyncjs_bad.nim b/tests/js/tasyncjs_bad.nim
new file mode 100644
index 000000000..b1e5a7bc3
--- /dev/null
+++ b/tests/js/tasyncjs_bad.nim
@@ -0,0 +1,22 @@
+discard """
+  exitCode: 1
+ outputsub: "Error: unhandled exception: foobar: 13"
+"""
+
+# note: this needs `--unhandled-rejections=strict`, see D20210217T215950
+
+import std/asyncjs
+from std/sugar import `=>`
+
+proc fn(n: int): Future[int] {.async.} =
+  if n >= 7: raise newException(ValueError, "foobar: " & $n)
+  else: result = n
+
+proc main() {.async.} =
+  let x1 = await fn(6)
+  doAssert x1 == 6
+  await fn(7).catch((a: Error) => (discard))
+  let x3 = await fn(13)
+  doAssert false # shouldn't go here, should fail before
+
+discard main()
diff --git a/tests/js/tasync_pragma.nim b/tests/js/tasyncjs_pragma.nim
index 916769fad..2b6f32e92 100644
--- a/tests/js/tasync_pragma.nim
+++ b/tests/js/tasyncjs_pragma.nim
@@ -5,6 +5,8 @@ t
 '''
 """
 
+# xxx merge into tasyncjs.nim
+
 import asyncjs, macros
 
 macro f*(a: untyped): untyped =
diff --git a/tests/js/tbasics.nim b/tests/js/tbasics.nim
index b297bb037..ef84f8bb5 100644
--- a/tests/js/tbasics.nim
+++ b/tests/js/tbasics.nim
@@ -54,7 +54,7 @@ for x in someGlobal: doAssert(x == 0)
 proc tdefault =
   var x = default(int)
   doAssert(x == 0)
-  proc inner(v: openarray[string]) =
+  proc inner(v: openArray[string]) =
     doAssert(v.len == 0)
 
   inner(default(seq[string]))
diff --git a/tests/js/tbigint_backend.nim b/tests/js/tbigint_backend.nim
new file mode 100644
index 000000000..8f2f6c4f4
--- /dev/null
+++ b/tests/js/tbigint_backend.nim
@@ -0,0 +1,57 @@
+import std/private/jsutils
+
+
+type JsBigIntImpl {.importc: "bigint".} = int
+type JsBigInt = distinct JsBigIntImpl
+
+doAssert JsBigInt isnot int
+func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".}
+func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".}
+func `<=`*(x, y: JsBigInt): bool {.importjs: "(# $1 #)".}
+func `==`*(x, y: JsBigInt): bool {.importjs: "(# === #)".}
+func inc*(x: var JsBigInt) {.importjs: "[#][0][0]++".}
+func inc2*(x: var JsBigInt) {.importjs: "#++".}
+func toCstring*(this: JsBigInt): cstring {.importjs: "#.toString()".}
+func `$`*(this: JsBigInt): string =
+  $toCstring(this)
+
+block:
+  doAssert defined(nimHasJsBigIntBackend)
+  let z1 = big"10"
+  let z2 = big"15"
+  doAssert z1 == big"10"
+  doAssert z1 == z1
+  doAssert z1 != z2
+  var s: seq[cstring]
+  for i in z1 .. z2:
+    s.add $i
+  doAssert s == @["10".cstring, "11", "12", "13", "14", "15"]
+  block:
+    var a=big"3"
+    a.inc
+    doAssert a == big"4"
+  block:
+    var z: JsBigInt
+    doAssert $z == "0"
+    doAssert z.jsTypeOf == "bigint" # would fail without codegen change
+    doAssert z != big(1)
+    doAssert z == big"0" # ditto
+
+  # ditto below
+  block:
+    let z: JsBigInt = big"1"
+    doAssert $z == "1"
+    doAssert z.jsTypeOf == "bigint"
+    doAssert z == big"1"
+
+  block:
+    let z = JsBigInt.default
+    doAssert $z == "0"
+    doAssert z.jsTypeOf == "bigint"
+    doAssert z == big"0"
+
+  block:
+    var a: seq[JsBigInt]
+    a.setLen 3
+    doAssert a[^1].jsTypeOf == "bigint"
+    doAssert a[^1] == big"0"
diff --git a/tests/js/tbyvar.nim b/tests/js/tbyvar.nim
index 705d62574..93724a2f1 100644
--- a/tests/js/tbyvar.nim
+++ b/tests/js/tbyvar.nim
@@ -1,15 +1,16 @@
 discard """
-  output: '''foo 12
+  output: '''
+foo 12
 bar 12
 2
 foo 12
 bar 12
 2
 12.5
-(nums: @[5, 5, 10, 5, 5, 5, 5, 5, 5, 5])
-(nums: @[5, 5, 50, 5, 5, 5, 5, 5, 5, 5])
-(nums: @[5, 5, 45, 5, 5, 5, 5, 5, 5, 5])
-(nums: @[5, 5, 9, 5, 5, 5, 5, 5, 5, 5])
+(nums: @[5.0, 5.0, 10.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0])
+(nums: @[5.0, 5.0, 50.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0])
+(nums: @[5.0, 5.0, 45.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0])
+(nums: @[5.0, 5.0, 9.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0])
 asd
 '''
 """
@@ -38,9 +39,9 @@ proc main =
 
 main()
 
-# Test: pass var seq to var openarray
+# Test: pass var seq to var openArray
 var s = @[2, 1]
-proc foo(a: var openarray[int]) = a[0] = 123
+proc foo(a: var openArray[int]) = a[0] = 123
 
 proc bar(s: var seq[int], a: int) =
   doAssert(a == 5)
diff --git a/tests/js/tclosures.nim b/tests/js/tclosures.nim
index 3137123bf..4f1c28de3 100644
--- a/tests/js/tclosures.nim
+++ b/tests/js/tclosures.nim
@@ -22,7 +22,7 @@ asm """
     function print (text) { console.log (text); }
 """
 
-proc consoleprint (str:cstring): void {.importc: "print", noDecl.}
+proc consoleprint (str:cstring): void {.importc: "print", nodecl.}
 proc print* (a: varargs[string, `$`]) = consoleprint "$1: $2" % [consolePrefix, join(a, " ")]
 
 type CallbackProc {.importc.} = proc () : cstring
diff --git a/tests/js/tcodegendeclproc.nim b/tests/js/tcodegendeclproc.nim
index 3acf0bc13..33064bdf1 100644
--- a/tests/js/tcodegendeclproc.nim
+++ b/tests/js/tcodegendeclproc.nim
@@ -3,7 +3,7 @@ discard """
 -1
 8
 '''
-  ccodecheck: "'console.log(-1); function fac_' \\d+ '(n_' \\d+ ')'"
+  ccodecheck: "'console.log(-1); function fac__tcodegendeclproc_u1(n_p0)'"
 """
 proc fac(n: int): int {.codegenDecl: "console.log(-1); function $2($3)".} =
   return n
diff --git a/tests/js/tconsole.nim b/tests/js/tconsole.nim
index b2eecc656..88c71ea18 100644
--- a/tests/js/tconsole.nim
+++ b/tests/js/tconsole.nim
@@ -3,7 +3,6 @@ discard """
 Hello, console
 1 2 3
 '''
-  disabled: "freebsd"
 """
 
 # This file tests the JavaScript console
diff --git a/tests/js/tcsymbol.nim b/tests/js/tcsymbol.nim
new file mode 100644
index 000000000..07e52b9b6
--- /dev/null
+++ b/tests/js/tcsymbol.nim
@@ -0,0 +1,6 @@
+discard """
+  matrix: "--cc:gcc; --cc:tcc"
+"""
+
+doAssert not defined(gcc)
+doAssert not defined(tcc)
\ No newline at end of file
diff --git a/tests/js/tdanger.nim b/tests/js/tdanger.nim
new file mode 100644
index 000000000..9088859a8
--- /dev/null
+++ b/tests/js/tdanger.nim
@@ -0,0 +1,17 @@
+discard """
+  matrix: ";--d:danger"
+"""
+
+block:
+  proc foo() =
+    var name = int64(12)
+    var x = uint32(name)
+    var m = x + 12
+
+    var y = int32(name)
+    var n = y + 1
+
+    doAssert m == uint32(n + 11)
+
+
+  foo()
diff --git a/tests/js/tdiscard.nim b/tests/js/tdiscard.nim
new file mode 100644
index 000000000..9aa6ea1b1
--- /dev/null
+++ b/tests/js/tdiscard.nim
@@ -0,0 +1,3 @@
+import dom
+
+discard Node()
\ No newline at end of file
diff --git a/tests/js/tdollar_float.nim b/tests/js/tdollar_float.nim
new file mode 100644
index 000000000..4fd8e3cba
--- /dev/null
+++ b/tests/js/tdollar_float.nim
@@ -0,0 +1,62 @@
+#[
+merge into tests/system/tdollars.nim once https://github.com/nim-lang/Nim/pull/14122
+is merged
+]#
+
+import unittest
+
+block: # https://github.com/timotheecour/Nim/issues/133
+  # simple test
+  var a: float = 2
+  check $a == "2.0"
+
+  # systematic tests
+  template fun(a2: static float) =
+    const a: float = a2 # needed pending https://github.com/timotheecour/Nim/issues/132
+    var b = a
+    check $b == $a
+
+  fun 2
+  fun 2.0
+  fun 2.1
+  fun 1_000
+  fun 1_000.1
+  fun 1_000_000_000.1
+  fun 1_000_000_000_000.1
+
+  # negatives
+  fun -2.0
+  fun -2.1
+
+  # 0
+  fun 0
+  fun -0
+  fun 0.0
+
+  block:
+    var a = -0.0
+    check $a in ["-0.0", "0.0"]
+
+  # exponents
+  block:
+    var a = 5e20
+    check $a in ["5e20", "500000000000000000000.0"]
+
+  fun 3.4e1'f32
+  fun 3.4e-1'f32
+  fun -3.4e-1'f32
+  fun 3.4e-1'f32
+  fun 3e-1'f32
+
+  block:
+    var a = 3.4e38'f32
+    check $a in ["3.4e+38", "3.4e+038"]
+      # on windows, printf (used in VM) prints as 3.4e+038
+      # but js prints as 3.4e+38
+      # on osx, both print as 3.4e+38
+      # see https://github.com/timotheecour/Nim/issues/138
+
+  when false: # edge cases
+    fun -0.0 # see https://github.com/timotheecour/Nim/issues/136
+    fun 5e20
+    fun 3.4e38'f32
diff --git a/tests/js/temptyseq.nim b/tests/js/temptyseq.nim
new file mode 100644
index 000000000..6489cf817
--- /dev/null
+++ b/tests/js/temptyseq.nim
@@ -0,0 +1,8 @@
+# #12671
+
+proc foo =
+  var x: seq[int]
+  doAssertRaises(IndexDefect):
+    inc x[0]
+
+foo()
diff --git a/tests/js/tfieldchecks.nim b/tests/js/tfieldchecks.nim
index 77759a75a..a0679a349 100644
--- a/tests/js/tfieldchecks.nim
+++ b/tests/js/tfieldchecks.nim
@@ -24,15 +24,15 @@ var obj = X(f0: "foo", f1: C, f3: 3.14)
 block:
   echo obj.f0
   echo obj.f1
-  doAssertRaises(FieldError): echo obj.f2
+  doAssertRaises(FieldDefect): echo obj.f2
   echo obj.f3
 
 block:
   let a0 = addr(obj.f0)
   echo a0[]
-  # let a1 = unsafeAddr(obj.f1)
+  # let a1 = addr(obj.f1)
   # echo a1[]
-  doAssertRaises(FieldError):
+  doAssertRaises(FieldDefect):
     let a2 = addr(obj.f2)
     echo a2[]
   let a3 = addr(obj.f3)
diff --git a/tests/js/tglobal.nim b/tests/js/tglobal.nim
new file mode 100644
index 000000000..38f5eec34
--- /dev/null
+++ b/tests/js/tglobal.nim
@@ -0,0 +1,30 @@
+block global:
+  proc getState(): int =
+    var state0 {.global.}: int
+    inc state0
+    result = state0
+
+  for i in 0 ..< 3:
+    doAssert getState() == i + 1
+
+  for i in 0 ..< 3:
+    once:
+      doAssert i == 0
+
+
+block threadvar:
+  proc getThreadState0(): int =
+    var state0 {.threadvar.}: int
+    inc state0
+    result = state0
+
+  for i in 0 ..< 3:
+    doAssert getThreadState0() == i + 1
+
+  proc getThreadState1(): int =
+    var state1 {.threadvar.}: int
+    inc state1
+    result = state1
+
+  for i in 0 ..< 3:
+    doAssert getThreadState1() == i + 1
diff --git a/tests/js/tindexdefect.nim b/tests/js/tindexdefect.nim
new file mode 100644
index 000000000..37994ec2e
--- /dev/null
+++ b/tests/js/tindexdefect.nim
@@ -0,0 +1,9 @@
+discard """
+  outputsub: "unhandled exception: index 10000 not in 0 .. 0 [IndexDefect]"
+  exitcode: 1
+  joinable: false
+"""
+
+var s = ['a']
+let z = s[10000] == 'a'
+echo z
\ No newline at end of file
diff --git a/tests/js/tjsffi.nim b/tests/js/tjsffi.nim
index af33cee8a..f27ea5546 100644
--- a/tests/js/tjsffi.nim
+++ b/tests/js/tjsffi.nim
@@ -1,291 +1,197 @@
 discard """
+matrix: "--legacy:jsnolambdalifting;"
 output: '''
-true
-true
-true
-true
-true
-true
-true
-true
-true
-true
-true
-true
-true
-true
-true
-true
 3
 2
 12
 Event { name: 'click: test' }
 Event { name: 'reloaded: test' }
 Event { name: 'updates: test' }
-true
-true
-true
-true
-true
-true
-true
 '''
 """
 
 import jsffi, jsconsole
 
 # Tests for JsObject
-# Test JsObject []= and []
-block:
-  proc test(): bool =
-    let obj = newJsObject()
-    var working = true
-    obj["a"] = 11
-    obj["b"] = "test"
-    obj["c"] = "test".cstring
-    working = working and obj["a"].to(int) == 11
-    working = working and obj["c"].to(cstring) == "test".cstring
-    working
-  echo test()
+block: # Test JsObject []= and []
+  let obj = newJsObject()
+  obj["a"] = 11
+  obj["b"] = "test"
+  obj["c"] = "test".cstring
+  doAssert obj["a"].to(int) == 11
+  doAssert obj["c"].to(cstring) == "test".cstring
 
-# Test JsObject .= and .
-block:
-  proc test(): bool =
-    let obj = newJsObject()
-    var working = true
-    obj.a = 11
-    obj.b = "test"
-    obj.c = "test".cstring
-    obj.`$!&` = 42
-    obj.`while` = 99
-    working = working and obj.a.to(int) == 11
-    working = working and obj.b.to(string) == "test"
-    working = working and obj.c.to(cstring) == "test".cstring
-    working = working and obj.`$!&`.to(int) == 42
-    working = working and obj.`while`.to(int) == 99
-    working
-  echo test()
+block: # Test JsObject .= and .
+  let obj = newJsObject()
+  obj.a = 11
+  obj.b = "test"
+  obj.c = "test".cstring
+  obj.`$!&` = 42
+  obj.`while` = 99
+  doAssert obj.a.to(int) == 11
+  doAssert obj.b.to(string) == "test"
+  doAssert obj.c.to(cstring) == "test".cstring
+  doAssert obj.`$!&`.to(int) == 42
+  doAssert obj.`while`.to(int) == 99
 
-# Test JsObject .()
-block:
-  proc test(): bool =
-    let obj = newJsObject()
-    obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z)
-    obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == cstring"Result is: 6"
-  echo test()
+block: # Test JsObject .()
+  let obj = newJsObject()
+  obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z)
+  doAssert obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == cstring"Result is: 6"
 
-# Test JsObject []()
-block:
-  proc test(): bool =
-    let obj = newJsObject()
-    obj.a = proc(x, y, z: int, t: string): string = t & $(x + y + z)
-    let call = obj["a"].to(proc(x, y, z: int, t: string): string)
-    call(1, 2, 3, "Result is: ") == "Result is: 6"
-  echo test()
+block: # Test JsObject []()
+  let obj = newJsObject()
+  obj.a = proc(x, y, z: int, t: string): string = t & $(x + y + z)
+  let call = obj["a"].to(proc(x, y, z: int, t: string): string)
+  doAssert call(1, 2, 3, "Result is: ") == "Result is: 6"
 
 # Test JsObject Iterators
-block:
-  proc testPairs(): bool =
-    let obj = newJsObject()
-    var working = true
-    obj.a = 10
-    obj.b = 20
-    obj.c = 30
-    for k, v in obj.pairs:
-      case $k
-      of "a":
-        working = working and v.to(int) == 10
-      of "b":
-        working = working and v.to(int) == 20
-      of "c":
-        working = working and v.to(int) == 30
-      else:
-        return false
-    working
-  proc testItems(): bool =
-    let obj = newJsObject()
-    var working = true
-    obj.a = 10
-    obj.b = 20
-    obj.c = 30
-    for v in obj.items:
-      working = working and v.to(int) in [10, 20, 30]
-    working
-  proc testKeys(): bool =
-    let obj = newJsObject()
-    var working = true
-    obj.a = 10
-    obj.b = 20
-    obj.c = 30
-    for v in obj.keys:
-      working = working and $v in ["a", "b", "c"]
-    working
-  proc test(): bool = testPairs() and testItems() and testKeys()
-  echo test()
+block: # testPairs
+  let obj = newJsObject()
+  obj.a = 10
+  obj.b = 20
+  obj.c = 30
+  for k, v in obj.pairs:
+    case $k
+    of "a":
+      doAssert v.to(int) == 10
+    of "b":
+      doAssert v.to(int) == 20
+    of "c":
+      doAssert v.to(int) == 30
+    else:
+      doAssert false
+block: # testItems
+  let obj = newJsObject()
+  obj.a = 10
+  obj.b = 20
+  obj.c = 30
+  for v in obj.items:
+    doAssert v.to(int) in [10, 20, 30]
+block: # testKeys
+  let obj = newJsObject()
+  obj.a = 10
+  obj.b = 20
+  obj.c = 30
+  for v in obj.keys:
+    doAssert $v in ["a", "b", "c"]
 
-# Test JsObject equality
-block:
-  proc test(): bool =
-    {. emit: "var comparison = {a: 22, b: 'test'};" .}
-    var comparison {. importjs, nodecl .}: JsObject
-    let obj = newJsObject()
-    obj.a = 22
-    obj.b = "test".cstring
-    obj.a == comparison.a and obj.b == comparison.b
-  echo test()
+block: # Test JsObject equality
+  {. emit: "var comparison = {a: 22, b: 'test'};" .}
+  var comparison {. importjs, nodecl .}: JsObject
+  let obj = newJsObject()
+  obj.a = 22
+  obj.b = "test".cstring
+  doAssert obj.a == comparison.a and obj.b == comparison.b
 
-# Test JsObject literal
-block:
-  proc test(): bool =
-    {. emit: "var comparison = {a: 22, b: 'test'};" .}
-    var comparison {. importjs, nodecl .}: JsObject
-    let obj = JsObject{ a: 22, b: "test".cstring }
-    obj.a == comparison.a and obj.b == comparison.b
-  echo test()
+block: # Test JsObject literal
+  {. emit: "var comparison = {a: 22, b: 'test'};" .}
+  var comparison {. importjs, nodecl .}: JsObject
+  let obj = JsObject{ a: 22, b: "test".cstring }
+  doAssert obj.a == comparison.a and obj.b == comparison.b
 
 # Tests for JsAssoc
-# Test JsAssoc []= and []
-block:
-  proc test(): bool =
-    let obj = newJsAssoc[int, int]()
-    var working = true
-    obj[1] = 11
-    working = working and not compiles(obj["a"] = 11)
-    working = working and not compiles(obj["a"])
-    working = working and not compiles(obj[2] = "test")
-    working = working and not compiles(obj[3] = "test".cstring)
-    working = working and obj[1] == 11
-    working
-  echo test()
+block: # Test JsAssoc []= and []
+  let obj = newJsAssoc[int, int]()
+  obj[1] = 11
+  doAssert not compiles(obj["a"] = 11)
+  doAssert not compiles(obj["a"])
+  doAssert not compiles(obj[2] = "test")
+  doAssert not compiles(obj[3] = "test".cstring)
+  doAssert obj[1] == 11
 
-# Test JsAssoc .= and .
-block:
-  proc test(): bool =
-    let obj = newJsAssoc[cstring, int]()
-    var working = true
-    obj.a = 11
-    obj.`$!&` = 42
-    working = working and not compiles(obj.b = "test")
-    working = working and not compiles(obj.c = "test".cstring)
-    working = working and obj.a == 11
-    working = working and obj.`$!&` == 42
-    working
-  echo test()
+block: # Test JsAssoc .= and .
+  let obj = newJsAssoc[cstring, int]()
+  var working = true
+  obj.a = 11
+  obj.`$!&` = 42
+  doAssert not compiles(obj.b = "test")
+  doAssert not compiles(obj.c = "test".cstring)
+  doAssert obj.a == 11
+  doAssert obj.`$!&` == 42
 
-# Test JsAssoc .()
-block:
-  proc test(): bool =
-    let obj = newJsAssoc[cstring, proc(e: int): int]()
-    obj.a = proc(e: int): int = e * e
-    obj.a(10) == 100
-  echo test()
+block: # Test JsAssoc .()
+  let obj = newJsAssoc[cstring, proc(e: int): int]()
+  obj.a = proc(e: int): int = e * e
+  doAssert obj.a(10) == 100
 
-# Test JsAssoc []()
-block:
-  proc test(): bool =
-    let obj = newJsAssoc[cstring, proc(e: int): int]()
-    obj.a = proc(e: int): int = e * e
-    let call = obj["a"]
-    call(10) == 100
-  echo test()
+block: # Test JsAssoc []()
+  let obj = newJsAssoc[cstring, proc(e: int): int]()
+  obj.a = proc(e: int): int = e * e
+  let call = obj["a"]
+  doAssert call(10) == 100
 
 # Test JsAssoc Iterators
-block:
-  proc testPairs(): bool =
-    let obj = newJsAssoc[cstring, int]()
-    var working = true
-    obj.a = 10
-    obj.b = 20
-    obj.c = 30
-    for k, v in obj.pairs:
-      case $k
-      of "a":
-        working = working and v == 10
-      of "b":
-        working = working and v == 20
-      of "c":
-        working = working and v == 30
-      else:
-        return false
-    working
-  proc testItems(): bool =
-    let obj = newJsAssoc[cstring, int]()
-    var working = true
-    obj.a = 10
-    obj.b = 20
-    obj.c = 30
-    for v in obj.items:
-      working = working and v in [10, 20, 30]
-    working
-  proc testKeys(): bool =
-    let obj = newJsAssoc[cstring, int]()
-    var working = true
-    obj.a = 10
-    obj.b = 20
-    obj.c = 30
-    for v in obj.keys:
-      working = working and v in [cstring"a", cstring"b", cstring"c"]
-    working
-  proc test(): bool = testPairs() and testItems() and testKeys()
-  echo test()
+block: # testPairs
+  let obj = newJsAssoc[cstring, int]()
+  obj.a = 10
+  obj.b = 20
+  obj.c = 30
+  for k, v in obj.pairs:
+    case $k
+    of "a":
+      doAssert v == 10
+    of "b":
+      doAssert v == 20
+    of "c":
+      doAssert v == 30
+    else:
+      doAssert false
+block: # testItems
+  let obj = newJsAssoc[cstring, int]()
+  obj.a = 10
+  obj.b = 20
+  obj.c = 30
+  for v in obj.items:
+    doAssert v in [10, 20, 30]
+block: # testKeys
+  let obj = newJsAssoc[cstring, int]()
+  obj.a = 10
+  obj.b = 20
+  obj.c = 30
+  for v in obj.keys:
+    doAssert v in [cstring"a", cstring"b", cstring"c"]
 
-# Test JsAssoc equality
-block:
-  proc test(): bool =
-    {. emit: "var comparison = {a: 22, b: 55};" .}
-    var comparison {. importjs, nodecl .}: JsAssoc[cstring, int]
-    let obj = newJsAssoc[cstring, int]()
-    obj.a = 22
-    obj.b = 55
-    obj.a == comparison.a and obj.b == comparison.b
-  echo test()
+block: # Test JsAssoc equality
+  {. emit: "var comparison = {a: 22, b: 55};" .}
+  var comparison {. importjs, nodecl .}: JsAssoc[cstring, int]
+  let obj = newJsAssoc[cstring, int]()
+  obj.a = 22
+  obj.b = 55
+  doAssert obj.a == comparison.a and obj.b == comparison.b
 
-# Test JsAssoc literal
-block:
-  proc test(): bool =
-    {. emit: "var comparison = {a: 22, b: 55};" .}
-    var comparison {. importjs, nodecl .}: JsAssoc[cstring, int]
-    let obj = JsAssoc[cstring, int]{ a: 22, b: 55 }
-    var working = true
-    working = working and
-      compiles(JsAssoc[int, int]{ 1: 22, 2: 55 })
-    working = working and
-      comparison.a == obj.a and comparison.b == obj.b
-    working = working and
-      not compiles(JsAssoc[cstring, int]{ a: "test" })
-    working
-  echo test()
+block: # Test JsAssoc literal
+  {. emit: "var comparison = {a: 22, b: 55};" .}
+  var comparison {. importjs, nodecl .}: JsAssoc[cstring, int]
+  let obj = JsAssoc[cstring, int]{ a: 22, b: 55 }
+  doAssert compiles(JsAssoc[int, int]{ 1: 22, 2: 55 })
+  doAssert comparison.a == obj.a and comparison.b == obj.b
+  doAssert not compiles(JsAssoc[cstring, int]{ a: "test" })
 
 # Tests for macros on non-JsRoot objects
-# Test lit
-block:
+block: # Test lit
   type TestObject = object
     a: int
     b: cstring
-  proc test(): bool =
-    {. emit: "var comparison = {a: 1};" .}
-    var comparison {. importjs, nodecl .}: TestObject
-    let obj = TestObject{ a: 1 }
-    obj == comparison
-  echo test()
+  {. emit: "var comparison = {a: 1};" .}
+  var comparison {. importjs, nodecl .}: TestObject
+  let obj = TestObject{ a: 1 }
+  doAssert obj == comparison
 
-# Test bindMethod
-block:
+block: # Test bindMethod
   type TestObject = object
     a: int
-    onWhatever: proc(e: int): int
+    onWhatever: proc(e: int): int {.nimcall.}
   proc handleWhatever(this: TestObject, e: int): int =
     e + this.a
-  proc test(): bool =
+  block:
     let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever))
-    obj.onWhatever(1) == 10
-  echo test()
+    doAssert obj.onWhatever(1) == 10
 
 block:
   {.emit: "function jsProc(n) { return n; }" .}
   proc jsProc(x: int32): JsObject {.importjs: "jsProc(#)".}
-
-  proc test() =
+  block:
     var x = jsProc(1)
     var y = jsProc(2)
     console.log x + y
@@ -294,8 +200,6 @@ block:
     x += jsProc(10)
     console.log x
 
-  test()
-
 block:
   {.emit:
   """
@@ -314,7 +218,7 @@ block:
   on("click") do (e: Event):
     console.log e
 
-  jslib.on("reloaded") do:
+  jslib.on("reloaded") do ():
     console.log jsarguments[0]
 
   # this test case is different from the above, because
@@ -323,11 +227,48 @@ block:
     console.log jsarguments[0]
 
 block:
+  doAssert jsUndefined == jsNull
+  doAssert jsUndefined == nil
+  doAssert jsNull == nil
+  doAssert jsUndefined.isNil
+  doAssert jsNull.isNil
+  doAssert jsNull.isNull
+  doAssert jsUndefined.isUndefined
+
+block: # test **
+  var a = toJs(0)
+  var b = toJs(0)
+  doAssert to(a ** b, int) == 1
+  a = toJs(1)
+  b = toJs(1)
+  doAssert to(a ** b, int) == 1
+  a = toJs(-1)
+  b = toJs(-1)
+  doAssert to(a ** b, int) == -1
+  a = toJs(6)
+  b = toJs(6)
+  doAssert to(a ** b, int) == 46656
+  a = toJs(5.5)
+  b = toJs(3)
+  doAssert to(a ** b, float) == 166.375
+  a = toJs(5)
+  b = toJs(3.0)
+  doAssert to(a ** b, float) == 125.0
+  a = toJs(7.0)
+  b = toJS(6.0)
+  doAssert to(a ** b, float) == 117649.0
+  a = toJs(8)
+  b = toJS(-2)
+  doAssert to(a ** b, float) == 0.015625
+
+  a = toJs(1)
+  b = toJs(1)
+  doAssert to(`**`(a + a, b), int) == 2
+
+  doAssert to(`**`(toJs(1) + toJs(1), toJs(2)), int) == 4
 
-  echo jsUndefined == jsNull
-  echo jsUndefined == nil
-  echo jsNull == nil
-  echo jsUndefined.isNil
-  echo jsNull.isNil
-  echo jsNull.isNull
-  echo jsUndefined.isUndefined
+block: # issue #21208
+  type MyEnum = enum baz
+  var obj: JsObject
+  {.emit: "`obj` = {bar: {baz: 123}};".}
+  discard obj.bar.baz
diff --git a/tests/js/tjsffi_old.nim b/tests/js/tjsffi_old.nim
index 1f149694b..378003f4e 100644
--- a/tests/js/tjsffi_old.nim
+++ b/tests/js/tjsffi_old.nim
@@ -35,6 +35,9 @@ true
 ## same as tjsffi, but this test uses the old names: importc and
 ## importcpp. This test is for backwards compatibility.
 
+# xxx instead of maintaining this near-duplicate test file, just have tests
+# that check that importc, importcpp, importjs work and remove this file.
+
 import jsffi, jsconsole
 
 # Tests for JsObject
@@ -276,8 +279,8 @@ block:
 block:
   type TestObject = object
     a: int
-    onWhatever: proc(e: int): int
-  proc handleWhatever(this: TestObject, e: int): int =
+    onWhatever: proc(e: int): int {.nimcall.}
+  proc handleWhatever(this: TestObject, e: int): int {.nimcall.} =
     e + this.a
   proc test(): bool =
     let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever))
@@ -318,7 +321,7 @@ block:
   on("click") do (e: Event):
     console.log e
 
-  jslib.on("reloaded") do:
+  jslib.on("reloaded") do ():
     console.log jsarguments[0]
 
   # this test case is different from the above, because
diff --git a/tests/js/tjshello.nim b/tests/js/tjshello.nim
index 19e0b90ae..8e090b3d2 100644
--- a/tests/js/tjshello.nim
+++ b/tests/js/tjshello.nim
@@ -1,4 +1,5 @@
 discard """
+  cmd: "nim $target $options --stackTrace:off --lineTrace:off $file"
   output: "Hello World"
   maxcodesize: 1000
   ccodecheck: "!@'function'"
@@ -7,4 +8,3 @@ discard """
 import jsconsole
 
 console.log "Hello World"
-
diff --git a/tests/js/tjshello_stacktrace.nim b/tests/js/tjshello_stacktrace.nim
new file mode 100644
index 000000000..d5e1c36eb
--- /dev/null
+++ b/tests/js/tjshello_stacktrace.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "Hello World"
+  maxcodesize: 4500
+  ccodecheck: "!@'function'"
+"""
+
+import jsconsole
+
+console.log "Hello World"
diff --git a/tests/js/tjsnimscombined.nim b/tests/js/tjsnimscombined.nim
new file mode 100644
index 000000000..4d3e6c453
--- /dev/null
+++ b/tests/js/tjsnimscombined.nim
@@ -0,0 +1 @@
+import std/jsffi
diff --git a/tests/js/tjsnimscombined.nims b/tests/js/tjsnimscombined.nims
new file mode 100644
index 000000000..01b93d3fa
--- /dev/null
+++ b/tests/js/tjsnimscombined.nims
@@ -0,0 +1 @@
+# test the condition where both `js` and `nimscript` are defined (nimscript receives priority)
diff --git a/tests/js/tlent.nim b/tests/js/tlent.nim
new file mode 100644
index 000000000..2546e5b1d
--- /dev/null
+++ b/tests/js/tlent.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''
+hmm
+100
+hmm
+100
+'''
+"""
+
+# #16800
+
+type A = object
+  b: int
+var t = A(b: 100)
+block:
+  proc getValues: lent int =
+    echo "hmm"
+    result = t.b
+  echo getValues()
+block:
+  proc getValues: lent int =
+    echo "hmm"
+    t.b
+  echo getValues()
+
+when false: # still an issue, #16908
+  template main =
+    iterator fn[T](a:T): lent T = yield a
+    let a = @[10]
+    for b in fn(a): echo b
+
+  static: main()
+  main()
diff --git a/tests/js/tmangle.nim b/tests/js/tmangle.nim
index c97bf7029..caaa15fa1 100644
--- a/tests/js/tmangle.nim
+++ b/tests/js/tmangle.nim
@@ -62,8 +62,8 @@ block:
     result = result and obj1.`&&`.addr[] == "bar".cstring
     result = result and obj2.`if` == 0
     result = result and obj2.`for` == 0
-    result = result and obj2.`==`.isNil()
-    result = result and obj2.`&&`.isNil()
+    result = result and obj2.`==`.isNil
+    result = result and obj2.`&&`.isNil
   echo test()
 
 # Test codegen for fields with uppercase letters:
diff --git a/tests/js/tmodify_cstring.nim b/tests/js/tmodify_cstring.nim
new file mode 100644
index 000000000..82f8ccb23
--- /dev/null
+++ b/tests/js/tmodify_cstring.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "cstring doesn't support `[]=` operator"
+"""
+
+var x = cstring"abcd"
+x[0] = 'x'
diff --git a/tests/js/tnativeexc.nim b/tests/js/tnativeexc.nim
index ea371c1cd..8b2b43e8f 100644
--- a/tests/js/tnativeexc.nim
+++ b/tests/js/tnativeexc.nim
@@ -18,7 +18,7 @@ try:
 except JsEvalError:
   doAssert false
 except JsSyntaxError as se:
-  doAssert se.message == "Unexpected token ; in JSON at position 0"
+  doAssert se.message == "Unexpected token ';', \";;\" is not valid JSON"
 except JsError as e:
   doAssert false
 
diff --git a/tests/js/tneginthash.nim b/tests/js/tneginthash.nim
new file mode 100644
index 000000000..c082405c9
--- /dev/null
+++ b/tests/js/tneginthash.nim
@@ -0,0 +1,21 @@
+# issue #19929
+
+import std/[tables, hashes]
+
+type Foo = object
+  a: int
+
+proc hash(f: Foo): Hash =
+  var h: Hash = 0
+  h = h !& hash(f.a)
+  result = !$h
+
+proc transpose[T, S](data: array[T, S]): Table[S, T] =
+  for i, x in data:
+    result[x] = i
+
+const xs = [Foo(a: 5), Foo(a: -5)]
+const x = transpose(xs)
+
+doAssert x[Foo(a: -5)] == 1
+doAssert x[Foo(a: 5)] == 0
diff --git a/tests/js/tnilstrs.nim b/tests/js/tnilstrs.nim
index c0048cb24..6c1e4e401 100644
--- a/tests/js/tnilstrs.nim
+++ b/tests/js/tnilstrs.nim
@@ -14,4 +14,12 @@ block:
   var x = "foo".cstring
   var y: string
   add(y, x)
-  doAssert y == "foo"
\ No newline at end of file
+  doAssert y == "foo"
+
+block:
+  type Foo = object
+    a: string
+  var foo = Foo(a: "foo")
+  var y = move foo.a
+  doAssert foo.a.len == 0
+  doAssert y == "foo"
diff --git a/tests/js/tos.nim b/tests/js/tos.nim
new file mode 100644
index 000000000..40fb52bcf
--- /dev/null
+++ b/tests/js/tos.nim
@@ -0,0 +1,21 @@
+# xxx consider merging this in tests/stdlib/tos.nim for increased coverage (with selecting disabling)
+
+static: doAssert defined(nodejs)
+
+import os
+
+block:
+  doAssert "./foo//./bar/".normalizedPath == "foo/bar"
+  doAssert relativePath(".//foo/bar", "foo") == "bar"
+  doAssert "/".isAbsolute
+  doAssert not "".isAbsolute
+  doAssert not ".".isAbsolute
+  doAssert not "foo".isAbsolute
+  doAssert relativePath("", "bar") == ""
+  doAssert normalizedPath(".///foo//./") == "foo"
+
+  when nimvm: discard
+  else:
+    let cwd = getCurrentDir()
+    doAssert cwd.isAbsolute
+    doAssert relativePath(getCurrentDir() / "foo", "bar") == ".." / "foo"
diff --git a/tests/js/trepr.nim b/tests/js/trepr.nim
index 366d247c5..a562ad63b 100644
--- a/tests/js/trepr.nim
+++ b/tests/js/trepr.nim
@@ -1,6 +1,4 @@
-discard """
-  action: run
-"""
+# xxx consider merging with `tests/stdlib/trepr.nim` to increase overall test coverage
 
 block ints:
   let
@@ -137,15 +135,13 @@ block tuples:
   when defined js:
     doAssert(repr(ot) == """
 [Field0 = true,
-Field1 = 120]
-""")
+Field1 = 120]""")
     doAssert(repr(t) == """
 [Field0 = 42,
 Field1 = 12.34,
 Field2 = "tuple",
 Field3 = [Field0 = true,
-Field1 = 120]]
-""")
+Field1 = 120]]""")
 
 block objects:
   type
@@ -162,14 +158,12 @@ block objects:
 
   doAssert(repr(oo) == """
 [a = true,
-b = 120]
-""")
+b = 120]""")
   doAssert(repr(o) == """
 [a = 42,
 b = 12.34,
 c = [a = true,
-b = 120]]
-""")
+b = 120]]""")
 
 block arrays:
   type
@@ -183,15 +177,14 @@ block arrays:
     c = [o, o, o]
     d = ["hi", "array", "!"]
 
-  doAssert(repr(a) == "[0.0, 1.0, 2.0]\n")
-  doAssert(repr(b) == "[[0.0, 1.0, 2.0], [0.0, 1.0, 2.0], [0.0, 1.0, 2.0]]\n")
+  doAssert(repr(a) == "[0.0, 1.0, 2.0]")
+  doAssert(repr(b) == "[[0.0, 1.0, 2.0], [0.0, 1.0, 2.0], [0.0, 1.0, 2.0]]")
   doAssert(repr(c) == """
 [[x = 42,
 y = [0.0, 1.0, 2.0]], [x = 42,
 y = [0.0, 1.0, 2.0]], [x = 42,
-y = [0.0, 1.0, 2.0]]]
-""")
-  doAssert(repr(d) == "[\"hi\", \"array\", \"!\"]\n")
+y = [0.0, 1.0, 2.0]]]""")
+  doAssert(repr(d) == "[\"hi\", \"array\", \"!\"]")
 
 block seqs:
   type
@@ -205,15 +198,14 @@ block seqs:
     c = @[o, o, o]
     d = @["hi", "array", "!"]
 
-  doAssert(repr(a) == "@[0.0, 1.0, 2.0]\n")
-  doAssert(repr(b) == "@[@[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0]]\n")
+  doAssert(repr(a) == "@[0.0, 1.0, 2.0]")
+  doAssert(repr(b) == "@[@[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0]]")
   doAssert(repr(c) == """
 @[[x = 42,
 y = @[0.0, 1.0, 2.0]], [x = 42,
 y = @[0.0, 1.0, 2.0]], [x = 42,
-y = @[0.0, 1.0, 2.0]]]
-""")
-  doAssert(repr(d) == "@[\"hi\", \"array\", \"!\"]\n")
+y = @[0.0, 1.0, 2.0]]]""")
+  doAssert(repr(d) == "@[\"hi\", \"array\", \"!\"]")
 
 block ptrs:
   type
@@ -226,13 +218,12 @@ block ptrs:
     c = addr a[2]
     d = AObj()
 
-  doAssert(repr(a) == "[12.0, 13.0, 14.0]\n")
-  doAssert(repr(b) == "ref 0 --> 12.0\n")
-  doAssert(repr(c) == "ref 2 --> 14.0\n")
+  doAssert(repr(a) == "[12.0, 13.0, 14.0]")
+  doAssert(repr(b) == "ref 0 --> 12.0")
+  doAssert(repr(c) == "ref 2 --> 14.0")
   doAssert(repr(d) == """
 [x = nil,
-y = 0]
-""")
+y = 0]""")
 
 block ptrs:
   type
@@ -248,8 +239,7 @@ block ptrs:
 [x = ref 0 --> [[x = nil,
 y = 0], [x = nil,
 y = 0]],
-y = 0]
-""")
+y = 0]""")
 
 block procs:
   proc test(): int =
@@ -258,9 +248,9 @@ block procs:
     ptest = test
     nilproc: proc(): int
 
-  doAssert(repr(test) == "0\n")
-  doAssert(repr(ptest) == "0\n")
-  doAssert(repr(nilproc) == "nil\n")
+  doAssert(repr(test) == "0")
+  doAssert(repr(ptest) == "0")
+  doAssert(repr(nilproc) == "nil")
 
 block bunch:
   type
@@ -293,7 +283,7 @@ block bunch:
     result[] = b
 
   var
-    aa: A
+    aa = default(A)
     bb: B = B(a: "inner", b: @['o', 'b', 'j'])
     cc: A = A(a: 12, b: 1, c: 1.2, d: '\0', e: eC,
                 f: "hello", g: {'A'}, h: {2'i16},
@@ -308,22 +298,21 @@ b = 0,
 c = 0.0,
 d = '\0',
 e = eA,
-f = nil,
+f = "",
 g = {},
 h = {},
-i = [nil, nil, nil],
-j = nil,
-k = 0,
-l = [a = nil,
-b = nil],
+i = ["", "", ""],
+j = @[],
+k = -12,
+l = [a = "",
+b = @[]],
 m = nil,
 n = nil,
-o = [Field0 = [a = nil,
-b = nil],
-Field1 = nil],
+o = [Field0 = [a = "",
+b = @[]],
+Field1 = ""],
 p = nil,
-q = nil]
-""")
+q = nil]""")
   doAssert(repr(cc) == """
 [a = 12,
 b = 1,
@@ -346,8 +335,7 @@ o = [Field0 = [a = "inner",
 b = @['o', 'b', 'j']],
 Field1 = "tuple!"],
 p = 0,
-q = "cstringtest"]
-""")
+q = "cstringtest"]""")
 
 block another:
   type
@@ -358,9 +346,9 @@ block another:
     Size3 = enum
       s3e=0, s3f=2000000000
 
-  doAssert(repr([s1a, s1b]) == "[s1a, s1b]\n")
-  doAssert(repr([s2c, s2d]) == "[s2c, s2d]\n")
-  doAssert(repr([s3e, s3f]) == "[s3e, s3f]\n")
+  doAssert(repr([s1a, s1b]) == "[s1a, s1b]")
+  doAssert(repr([s2c, s2d]) == "[s2c, s2d]")
+  doAssert(repr([s3e, s3f]) == "[s3e, s3f]")
 
 block another2:
 
@@ -395,15 +383,13 @@ block another2:
 y = 13,
 z = 45,
 s = ["abc", "xyz"],
-e = en6]
-""")
+e = en6]""")
   doAssert(repr(q) == """
 ref 0 --> [x = 0,
 y = 13,
 z = 45,
 s = ["abc", "xyz"],
-e = en6]
-""")
+e = en6]""")
   doAssert(repr(s) == """
 @[ref 0 --> [x = 0,
 y = 13,
@@ -421,8 +407,7 @@ e = en6], ref 3 --> [x = 0,
 y = 13,
 z = 45,
 s = ["abc", "xyz"],
-e = en6]]
-""")
+e = en6]]""")
   doAssert(repr(en4) == "en4")
 
   doAssert(repr({'a'..'p'}) == "{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'}")
diff --git a/tests/js/treprinifexpr.nim b/tests/js/treprinifexpr.nim
new file mode 100644
index 000000000..09ded18b9
--- /dev/null
+++ b/tests/js/treprinifexpr.nim
@@ -0,0 +1,18 @@
+type
+  Enum = enum A
+
+let
+  enumVal = A
+  tmp = if true: $enumVal else: $enumVal
+
+let
+  intVal = 12
+  tmp2 = if true: repr(intVal) else: $enumVal
+
+let
+  strVal = "123"
+  tmp3 = if true: repr(strVal) else: $strVal
+
+let
+  floatVal = 12.4
+  tmp4 = if true: repr(floatVal) else: $floatVal
\ No newline at end of file
diff --git a/tests/js/tseqops.nim b/tests/js/tseqops.nim
index af664222c..8cfb50886 100644
--- a/tests/js/tseqops.nim
+++ b/tests/js/tseqops.nim
@@ -1,11 +1,3 @@
-discard """
-  output: '''(x: 0, y: 0)
-(x: 5, y: 0)
-@[(x: "2", y: 4), (x: "4", y: 5), (x: "4", y: 5)]
-@[(a: "3", b: 3), (a: "1", b: 1), (a: "2", b: 2)]
-'''
-"""
-
 # bug #4139
 
 type
@@ -17,8 +9,8 @@ proc onLoad() =
   var foo = TestO(x: 0, y: 0)
   test.add(foo)
   foo.x = 5
-  echo(test[0])
-  echo foo
+  doAssert $test[0] == "(x: 0, y: 0)"
+  doAssert $foo == "(x: 5, y: 0)"
 
 onLoad()
 
@@ -34,7 +26,7 @@ proc foo(x: var seq[MyObj]) =
 
 var s = @[MyObj(x: "2", y: 4), MyObj(x: "4", y: 5)]
 foo(s)
-echo s
+doAssert $s == """@[(x: "2", y: 4), (x: "4", y: 5), (x: "4", y: 5)]"""
 
 # bug  #5933
 import sequtils
@@ -48,4 +40,9 @@ var test = @[Test(a: "1", b: 1), Test(a: "2", b: 2)]
 
 test.insert(@[Test(a: "3", b: 3)], 0)
 
-echo test
+doAssert $test == """@[(a: "3", b: 3), (a: "1", b: 1), (a: "2", b: 2)]"""
+
+proc hello(): array[5, int] = discard
+var x = @(hello())
+x.add(2)
+doAssert x == @[0, 0, 0, 0, 0, 2]
diff --git a/tests/js/tsourcemap.nim b/tests/js/tsourcemap.nim
new file mode 100644
index 000000000..d358e4a57
--- /dev/null
+++ b/tests/js/tsourcemap.nim
@@ -0,0 +1,96 @@
+discard """
+  action: "run"
+  targets: "js"
+  cmd: "nim js -r -d:nodejs $options --sourceMap:on $file"
+"""
+import std/[os, json, strutils, sequtils, algorithm, assertions, paths, compilesettings]
+
+# Implements a very basic sourcemap parser and then runs it on itself.
+# Allows to check for basic problems such as bad counts and lines missing (e.g. issue #21052)
+
+type
+  SourceMap = object
+    version:   int
+    sources:   seq[string]
+    names:     seq[string]
+    mappings:  string
+    file:      string
+
+  Line = object
+    line, column: int
+    file: string
+
+const
+  flag = 1 shl 5
+  signBit = 0b1
+  fourBits = 0b1111
+  fiveBits = 0b11111
+  mask = (1 shl 5) - 1
+  alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+
+var b64Table: seq[int] = 0.repeat(max(alphabet.mapIt(it.ord)) + 1)
+for i, b in alphabet.pairs:
+  b64Table[b.ord] = i
+
+# From https://github.com/juancarlospaco/nodejs/blob/main/src/nodejs/jsfs.nim
+proc importFs*() {.importjs: "var fs = require(\"fs\");".}
+proc readFileSync*(path: cstring): cstring {.importjs: "(fs.$1(#).toString())".}
+importFS()
+# Read in needed files
+let
+  jsFileName = string(querySetting(outDir).Path / "tsourcemap.js".Path)
+  mapFileName = jsFileName & ".map"
+
+  data = parseJson($mapFileName.cstring.readFileSync()).to(SourceMap)
+  jsFile = $readFileSync(jsFileName.cstring)
+
+proc decodeVLQ(inp: string): seq[int] =
+  var
+    shift, value: int
+  for v in inp.mapIt(b64Table[it.ord]):
+    value += (v and mask) shl shift
+    if (v and flag) > 0:
+      shift += 5
+      continue
+    result &= (value shr 1) * (if (value and 1) > 0: -1 else: 1)
+    shift = 0
+    value = 0
+
+
+# Keep track of state
+var
+  line = 0
+  source = 0
+  name = 0
+  column = 0
+  jsLine = 1
+  lines: seq[Line]
+
+for gline in data.mappings.split(';'):
+  jsLine += 1
+  var jsColumn = 0
+  for item in gline.strip().split(','):
+    let value = item.decodeVLQ()
+    doAssert value.len in [0, 1, 4, 5]
+    if value.len == 0:
+      continue
+    jsColumn += value[0]
+    if value.len >= 4:
+      source += value[1]
+      line += value[2]
+      column += value[3]
+      lines &= Line(line: line, column: column, file: data.sources[source])
+
+let jsLines = jsFile.splitLines().len
+# There needs to be a mapping for every line in the JS
+# If there isn't then the JS lines wont match up with Nim lines.
+# Except we don't care about the final line since that doesn't need to line up
+doAssert data.mappings.count(';') == jsLines - 1
+
+# Check we can find this file somewhere in the source map
+var foundSelf = false
+for line in lines:
+  if "tsourcemap.nim" in line.file:
+    foundSelf = true
+    doAssert line.line in 0..<jsLines, "Lines is out of bounds for file"
+doAssert foundSelf, "Couldn't find tsourcemap.nim in source map"
diff --git a/tests/js/tstdlib_imports.nim b/tests/js/tstdlib_imports.nim
new file mode 100644
index 000000000..db851ba28
--- /dev/null
+++ b/tests/js/tstdlib_imports.nim
@@ -0,0 +1,80 @@
+discard """
+  action: compile
+"""
+
+{.warning[UnusedImport]: off.}
+
+when defined(nimPreviewSlimSystem):
+  import std/[
+    syncio, assertions, formatfloat, objectdollar, widestrs
+  ]
+
+import std/[
+  # Core:
+  bitops, typetraits, lenientops, macros, volatile, typeinfo,
+  # fails due to FFI: rlocks
+  # fails due to cstring cast/copyMem: endians
+  # works but uses FFI: cpuinfo, locks
+
+  # Algorithms:
+  algorithm, enumutils, sequtils, setutils,
+  
+  # Collections:
+  critbits, deques, heapqueue, intsets, lists, options, sets,
+  tables, packedsets,
+
+  # Strings:
+  cstrutils, editdistance, wordwrap, parseutils, ropes,
+  pegs, strformat, strmisc, strscans, strtabs,
+  strutils, unicode, unidecode,
+  # fails due to FFI: encodings
+
+  # Time handling:
+  monotimes, times,
+
+  # Generic operator system services:
+  os, streams,
+  # fails intentionally: dynlib, marshal, memfiles
+  # fails due to FFI: osproc, terminal
+  # fails due to osproc import: distros
+
+  # Math libraries:
+  complex, math, random, rationals, stats, sums, sysrand,
+  # works but uses FFI: fenv
+
+  # Internet protocols:
+  cookies, httpcore, mimetypes, uri,
+  # fails due to FFI: asyncdispatch, asyncfile, asyncftpclient, asynchttpserver,
+  # asyncnet, cgi, httpclient, nativesockets, net, selectors
+  # works but no need to test: asyncstreams, asyncfutures
+  
+  # Threading:
+  # fails due to FFI: threadpool
+
+  # Parsers:
+  htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml,
+  parseopt, jsonutils,
+
+  # XML processing:
+  xmltree, xmlparser,
+
+  # Generators:
+  htmlgen,
+
+  # Hashing:
+  base64, hashes,
+  # fails due to cstring cast/endians import: oids
+  # fails due to copyMem/endians import: sha1
+
+  # Miscellaneous:
+  colors, logging, sugar, unittest, varints, enumerate, with,
+  # fails due to FFI: browsers, coro
+  # works but uses FFI: segfaults
+
+  # Modules for JS backend:
+  asyncjs, dom, jsconsole, jscore, jsffi, jsbigints,
+
+  # Unlisted in lib.html:
+  decls, compilesettings, wrapnils, exitprocs, effecttraits,
+  genasts, importutils, isolation, jsfetch, jsformdata, jsheaders
+]
diff --git a/tests/js/tstdlib_various.nim b/tests/js/tstdlib_various.nim
new file mode 100644
index 000000000..1e584f735
--- /dev/null
+++ b/tests/js/tstdlib_various.nim
@@ -0,0 +1,174 @@
+discard """
+output: '''
+abc
+def
+definition
+prefix
+xyz
+def
+definition
+Hi Andreas! How do you feel, Rumpf?
+
+@[0, 2, 1]
+@[1, 0, 2]
+@[1, 2, 0]
+@[2, 0, 1]
+@[2, 1, 0]
+@[2, 0, 1]
+@[1, 2, 0]
+@[1, 0, 2]
+@[0, 2, 1]
+@[0, 1, 2]
+[5]
+[4, 5]
+[3, 4, 5]
+[2, 3, 4, 5]
+[2, 3, 4, 5, 6]
+[1, 2, 3, 4, 5, 6]
+'''
+"""
+
+import
+  critbits, sets, strutils, tables, random, algorithm, ropes,
+  lists, htmlgen, xmltree, strtabs
+
+
+block tcritbits:
+  var r: CritBitTree[void]
+  r.incl "abc"
+  r.incl "xyz"
+  r.incl "def"
+  r.incl "definition"
+  r.incl "prefix"
+  doAssert r.contains"def"
+  #r.del "def"
+
+  for w in r.items:
+    echo w
+  for w in r.itemsWithPrefix("de"):
+    echo w
+
+
+
+block testequivalence:
+  doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "equivalent or subset")
+  doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3]), "equivalent or subset")
+  doAssert((not(toHashSet(@[1,2,3]) <= toHashSet(@[1,2]))), "equivalent or subset")
+  doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "strict subset")
+  doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2,3]))), "strict subset")
+  doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2]))), "strict subset")
+  doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3,4]))), "==")
+  doAssert(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3]), "==")
+  doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2]))), "==")
+
+
+
+block tformat:
+  echo("Hi $1! How do you feel, $2?\n" % ["Andreas", "Rumpf"])
+
+
+
+block tnilecho:
+  var x = @["1", "", "3"]
+  doAssert $x == """@["1", "", "3"]"""
+
+
+
+block torderedtable:
+  var t = initOrderedTable[int,string]()
+
+  # this tests issue #5917
+  var data = newSeq[int]()
+  for i in 0..<1000:
+    var x = rand(1000)
+    if x notin t: data.add(x)
+    t[x] = "meh"
+
+  # this checks that keys are re-inserted
+  # in order when table is enlarged.
+  var i = 0
+  for k, v in t:
+    doAssert(k == data[i])
+    doAssert(v == "meh")
+    inc(i)
+
+
+
+block tpermutations:
+  var v = @[0, 1, 2]
+  while v.nextPermutation():
+    echo v
+  while v.prevPermutation():
+    echo v
+
+
+block tropes:
+  var
+    r1 = rope("")
+    r2 = rope("123")
+  doAssert r1.len == 0
+  doAssert r2.len == 3
+  doAssert $r1 == ""
+  doAssert $r2 == "123"
+
+  r1.add("123")
+  r2.add("456")
+  doAssert r1.len == 3
+  doAssert r2.len == 6
+  doAssert $r1 == "123"
+  doAssert $r2 == "123456"
+  doAssert $r1[1] == "2"
+  doAssert $r2[2] == "3"
+
+
+block tsinglylinkedring:
+  var r = initSinglyLinkedRing[int]()
+  r.prepend(5)
+  echo r
+  r.prepend(4)
+  echo r
+  r.prepend(3)
+  echo r
+  r.prepend(2)
+  echo r
+  r.append(6)
+  echo r
+  r.prepend(1)
+  echo r
+
+block tsplit:
+  var s = ""
+  for w in split("|abc|xy|z", {'|'}):
+    s.add("#")
+    s.add(w)
+
+  doAssert s == "##abc#xy#z"
+
+block tsplit2:
+  var s = ""
+  for w in split("|abc|xy|z", {'|'}):
+    s.add("#")
+    s.add(w)
+
+  doAssert "true".split("") == @["true"]
+
+block txmlgen:
+  var nim = "Nim"
+  doAssert h1(a(href="http://force7.de/nim", nim)) ==
+    "<h1><a href=\"http://force7.de/nim\">Nim</a></h1>"
+
+block txmltree:
+  var x = <>a(href="nim.de", newText("www.nim-test.de"))
+
+  doAssert($x == "<a href=\"nim.de\">www.nim-test.de</a>")
+  doAssert(newText("foo").innerText == "foo")
+  doAssert(newEntity("bar").innerText == "bar")
+  doAssert(newComment("baz").innerText == "")
+
+  let y = newXmlTree("x", [
+    newText("foo"),
+    newXmlTree("y", [
+      newText("bar")
+    ])
+  ])
+  doAssert(y.innerText == "foobar")
diff --git a/tests/js/tstreams.nim b/tests/js/tstreams.nim
new file mode 100644
index 000000000..43c26e01a
--- /dev/null
+++ b/tests/js/tstreams.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''
+I
+AM
+GROOT
+'''
+"""
+
+import streams
+
+var s = newStringStream("I\nAM\nGROOT")
+doAssert s.peekStr(1) == "I"
+doAssert s.peekChar() == 'I'
+for line in s.lines:
+  echo line
+s.close
+
+var s2 = newStringStream("abc")
+doAssert s2.readAll == "abc"
+s2.write("def")
+doAssert s2.data == "abcdef"
+s2.close
diff --git a/tests/js/ttempgen.nim b/tests/js/ttempgen.nim
new file mode 100644
index 000000000..badc66c1b
--- /dev/null
+++ b/tests/js/ttempgen.nim
@@ -0,0 +1,79 @@
+discard """
+  output: '''
+foo
+'''
+"""
+
+block: # #12672
+  var a = @[1]
+  let i = 1
+  inc a[i-1]
+
+  var b: seq[int]
+  doAssertRaises(IndexDefect): inc b[0]
+  doAssertRaises(IndexDefect): inc b[i-1]
+
+  var x: seq[seq[int]]
+  doAssertRaises(IndexDefect): # not TypeError
+    inc x[0][i-1]
+
+block: # #14087
+  type Obj = object
+    str: string
+
+  var s = @[Obj(str: "abc"), Obj(str: "def")]
+  s[1].str.add("ghi")
+  s[s.len - 1].str.add("jkl")
+  s[^1].str.add("mno")
+  s[s.high].str.add("pqr")
+
+  let slen = s.len
+  s[slen - 1].str.add("stu")
+
+  let shigh = s.high
+  s[shigh].str.add("vwx")
+
+  proc foo(): int =
+    echo "foo"
+    shigh
+  s[foo()].str.add("yz")
+  doAssert s[1].str == "defghijklmnopqrstuvwxyz"
+
+block: # #14117
+  type
+    A = object
+      case kind: bool
+      of true:
+        sons: seq[int]
+      else: discard
+
+  var a = A(kind: true)
+  doAssert a.sons.len == 0
+  a.sons.add(1)
+  doAssert a.sons.len == 1
+
+import tables
+
+block: # #13966
+  var t: Table[int8, array[int8, seq[tuple[]]]]
+
+  t[0] = default(array[int8, seq[tuple[]]])
+  t[0][0].add ()
+
+block: # #11783
+  proc fun(): string =
+    discard
+
+  var ret: string
+  ret.add fun()
+  doAssert ret == ""
+
+block: # #12256
+  var x: bool
+
+  doAssert x == false
+
+  reset x
+
+  doAssert x == false
+  doAssert x != true
diff --git a/tests/js/ttypedarray.nim b/tests/js/ttypedarray.nim
new file mode 100644
index 000000000..4807cb103
--- /dev/null
+++ b/tests/js/ttypedarray.nim
@@ -0,0 +1,26 @@
+discard """
+  matrix: "--jsbigint64:off -d:nimStringHash2; --jsbigint64:on"
+"""
+
+import std/private/jsutils
+
+proc main()=
+  template fn(a): untyped = jsConstructorName(a)
+  doAssert fn(array[2, int8].default) == "Int8Array"
+  doAssert fn(array[2, uint8].default) == "Uint8Array"
+  doAssert fn(array[2, byte].default) == "Uint8Array"
+  doAssert fn(array[2, char].default) == "Uint8Array"
+  whenJsNoBigInt64: discard
+  do:
+    doAssert fn(array[2, uint64].default) == "BigUint64Array"
+  doAssert fn([1'u8]) == "Uint8Array"
+  doAssert fn([1'u16]) == "Uint16Array"
+  doAssert fn([byte(1)]) == "Uint8Array"
+  doAssert fn([1.0'f32]) == "Float32Array"
+  doAssert fn(array[2, float32].default) == "Float32Array"
+  doAssert fn(array[2, float].default) == "Float64Array"
+  doAssert fn(array[2, float64].default) == "Float64Array"
+  doAssert fn([1.0]) == "Float64Array"
+  doAssert fn([1.0'f64]) == "Float64Array"
+
+main()
diff --git a/tests/js/tunion.nim b/tests/js/tunion.nim
new file mode 100644
index 000000000..e185495ad
--- /dev/null
+++ b/tests/js/tunion.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "`{.union.}` is not implemented for js backend."
+"""
+
+type Foo {.union.} = object
+  as_bytes: array[8, int8]
+  data: int64
diff --git a/tests/js/tunittest_error.nim b/tests/js/tunittest_error.nim
new file mode 100644
index 000000000..781e34338
--- /dev/null
+++ b/tests/js/tunittest_error.nim
@@ -0,0 +1,24 @@
+discard """
+  exitcode: 1
+  outputsub: "[FAILED] with exception"
+"""
+
+# see also: `tests/stdlib/tunittest_error.nim`
+
+import unittest
+
+proc ddd() =
+  raise newException(IOError, "didn't do stuff")
+
+proc ccc() =
+  ddd()
+
+proc bbb() =
+  ccc()
+
+proc aaa() =
+  bbb()
+
+test "with exception":
+  check 3 == 3
+  aaa()
diff --git a/tests/js/tunittest_error2.nim b/tests/js/tunittest_error2.nim
new file mode 100644
index 000000000..9c5af7529
--- /dev/null
+++ b/tests/js/tunittest_error2.nim
@@ -0,0 +1,16 @@
+discard """
+  exitcode: 1
+  outputsub: '''
+[<foreign exception>]
+[FAILED] Bad test
+  '''
+  matrix: "-d:nodejs"
+  targets: "js"
+  joinable: false
+"""
+
+# bug #16978
+import unittest
+test "Bad test":
+  var x: cstring = nil
+  let y = x[0]
diff --git a/tests/js/tunittests.nim b/tests/js/tunittests.nim
deleted file mode 100644
index 7c2e70563..000000000
--- a/tests/js/tunittests.nim
+++ /dev/null
@@ -1,11 +0,0 @@
-discard """
-  output: '''
-[Suite] Bacon
-  [OK] >:)'''
-"""
-
-import unittest
-
-suite "Bacon":
-  test ">:)":
-    check(true == true)
diff --git a/tests/js/twritestacktrace.nim b/tests/js/twritestacktrace.nim
new file mode 100644
index 000000000..2fe2b1987
--- /dev/null
+++ b/tests/js/twritestacktrace.nim
@@ -0,0 +1,12 @@
+discard """
+  cmd: "nim js --panics:on $file"
+  output: '''Traceback (most recent call last)
+twritestacktrace.nim(12) at module twritestacktrace
+twritestacktrace.nim(10) at twritestacktrace.hello
+'''
+"""
+
+proc hello() =
+  writeStackTrace()
+
+hello()