diff --git a/tests/ports/webassembly/basic.js b/tests/ports/webassembly/basic.js new file mode 100644 index 0000000000..19b1881faf --- /dev/null +++ b/tests/ports/webassembly/basic.js @@ -0,0 +1,8 @@ +import(process.argv[2]).then((mp) => { + mp.loadMicroPython().then((py) => { + py.runPython("1"); + py.runPython("print('hello')"); + py.runPython("import sys; print(f'hello from {sys.platform}')"); + py.runPython("import collections; print(collections.OrderedDict)"); + }); +}); diff --git a/tests/ports/webassembly/basic.js.exp b/tests/ports/webassembly/basic.js.exp new file mode 100644 index 0000000000..6459b2492c --- /dev/null +++ b/tests/ports/webassembly/basic.js.exp @@ -0,0 +1,3 @@ +hello +hello from webassembly + diff --git a/tests/ports/webassembly/filesystem.mjs b/tests/ports/webassembly/filesystem.mjs new file mode 100644 index 0000000000..e9e2920a16 --- /dev/null +++ b/tests/ports/webassembly/filesystem.mjs @@ -0,0 +1,9 @@ +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.FS.mkdir("/lib/"); +mp.FS.writeFile("/lib/testmod.py", "x = 1; print(__name__, x)"); +mp.runPython("import testmod"); + +mp.runPython("import sys; sys.modules.clear()"); +const testmod = mp.pyimport("testmod"); +console.log("testmod:", testmod, testmod.x); diff --git a/tests/ports/webassembly/filesystem.mjs.exp b/tests/ports/webassembly/filesystem.mjs.exp new file mode 100644 index 0000000000..25a48b1083 --- /dev/null +++ b/tests/ports/webassembly/filesystem.mjs.exp @@ -0,0 +1,3 @@ +testmod 1 +testmod 1 +testmod: PyProxy { _ref: 3 } 1 diff --git a/tests/ports/webassembly/float.mjs b/tests/ports/webassembly/float.mjs new file mode 100644 index 0000000000..53bb8b1c4d --- /dev/null +++ b/tests/ports/webassembly/float.mjs @@ -0,0 +1,43 @@ +// Test passing floats between JavaScript and Python. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +globalThis.a = 1 / 2; +globalThis.b = Infinity; +globalThis.c = NaN; + +mp.runPython(` +import js + +# Test retrieving floats from JS. +print(js.a) +print(js.b) +print(js.c) + +# Test calling JS which returns a float. +r = js.Math.random() +print(type(r), 0 < r < 1) + +x = 1 / 2 +y = float("inf") +z = float("nan") + +# Test passing floats to a JS function. +js.console.log(x) +js.console.log(x, y) +js.console.log(x, y, z) +`); + +// Test retrieving floats from Python. +console.log(mp.globals.get("x")); +console.log(mp.globals.get("y")); +console.log(mp.globals.get("z")); + +// Test passing floats to a Python function. +const mp_print = mp.pyimport("builtins").print; +mp_print(globalThis.a); +mp_print(globalThis.a, globalThis.b); +mp_print(globalThis.a, globalThis.b, globalThis.c); + +// Test calling Python which returns a float. +console.log(mp.pyimport("math").sqrt(0.16)); diff --git a/tests/ports/webassembly/float.mjs.exp b/tests/ports/webassembly/float.mjs.exp new file mode 100644 index 0000000000..57eff74acd --- /dev/null +++ b/tests/ports/webassembly/float.mjs.exp @@ -0,0 +1,14 @@ +0.5 +inf +nan + True +0.5 +0.5 Infinity +0.5 Infinity NaN +0.5 +Infinity +NaN +0.5 +0.5 inf +0.5 inf nan +0.4 diff --git a/tests/ports/webassembly/fun_call.mjs b/tests/ports/webassembly/fun_call.mjs new file mode 100644 index 0000000000..295745d2e2 --- /dev/null +++ b/tests/ports/webassembly/fun_call.mjs @@ -0,0 +1,17 @@ +// Test calling JavaScript functions from Python. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +globalThis.f = (a, b, c, d, e) => { + console.log(a, b, c, d, e); +}; +mp.runPython(` +import js +js.f() +js.f(1) +js.f(1, 2) +js.f(1, 2, 3) +js.f(1, 2, 3, 4) +js.f(1, 2, 3, 4, 5) +js.f(1, 2, 3, 4, 5, 6) +`); diff --git a/tests/ports/webassembly/fun_call.mjs.exp b/tests/ports/webassembly/fun_call.mjs.exp new file mode 100644 index 0000000000..e9ed5f6ddf --- /dev/null +++ b/tests/ports/webassembly/fun_call.mjs.exp @@ -0,0 +1,7 @@ +undefined undefined undefined undefined undefined +1 undefined undefined undefined undefined +1 2 undefined undefined undefined +1 2 3 undefined undefined +1 2 3 4 undefined +1 2 3 4 5 +1 2 3 4 5 diff --git a/tests/ports/webassembly/globals.mjs b/tests/ports/webassembly/globals.mjs new file mode 100644 index 0000000000..3d5ecb4167 --- /dev/null +++ b/tests/ports/webassembly/globals.mjs @@ -0,0 +1,13 @@ +// Test accessing Python globals dict via mp.globals. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.runPython("x = 1"); +console.log(mp.globals.get("x")); + +mp.globals.set("y", 2); +mp.runPython("print(y)"); + +mp.runPython("print('y' in globals())"); +mp.globals.delete("y"); +mp.runPython("print('y' in globals())"); diff --git a/tests/ports/webassembly/globals.mjs.exp b/tests/ports/webassembly/globals.mjs.exp new file mode 100644 index 0000000000..a118c13fec --- /dev/null +++ b/tests/ports/webassembly/globals.mjs.exp @@ -0,0 +1,4 @@ +1 +2 +True +False diff --git a/tests/ports/webassembly/heap_expand.mjs b/tests/ports/webassembly/heap_expand.mjs new file mode 100644 index 0000000000..2cf7c07b0b --- /dev/null +++ b/tests/ports/webassembly/heap_expand.mjs @@ -0,0 +1,15 @@ +// Test expanding the MicroPython GC heap. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.runPython(` +import gc +bs = [] +for i in range(24): + b = bytearray(1 << i) + bs.append(b) + gc.collect() + print(gc.mem_free()) +for b in bs: + print(len(b)) +`); diff --git a/tests/ports/webassembly/heap_expand.mjs.exp b/tests/ports/webassembly/heap_expand.mjs.exp new file mode 100644 index 0000000000..ee14908409 --- /dev/null +++ b/tests/ports/webassembly/heap_expand.mjs.exp @@ -0,0 +1,48 @@ +135241360 +135241328 +135241296 +135241264 +135241216 +135241168 +135241088 +135240944 +135240640 +135240112 +135239072 +135237008 +135232896 +135224688 +135208288 +135175504 +135109888 +134978800 +134716640 +135216848 +136217216 +138218032 +142219616 +150222864 +1 +2 +4 +8 +16 +32 +64 +128 +256 +512 +1024 +2048 +4096 +8192 +16384 +32768 +65536 +131072 +262144 +524288 +1048576 +2097152 +4194304 +8388608 diff --git a/tests/ports/webassembly/jsffi_create_proxy.mjs b/tests/ports/webassembly/jsffi_create_proxy.mjs new file mode 100644 index 0000000000..5f04bf44d7 --- /dev/null +++ b/tests/ports/webassembly/jsffi_create_proxy.mjs @@ -0,0 +1,15 @@ +// Test jsffi.create_proxy(). + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.runPython(` +import jsffi +x = jsffi.create_proxy(1) +print(x) +y = jsffi.create_proxy([2]) +print(y) +`); +console.log(mp.globals.get("x")); +console.log(mp.PyProxy.toJs(mp.globals.get("x"))); +console.log(mp.globals.get("y")); +console.log(mp.PyProxy.toJs(mp.globals.get("y"))); diff --git a/tests/ports/webassembly/jsffi_create_proxy.mjs.exp b/tests/ports/webassembly/jsffi_create_proxy.mjs.exp new file mode 100644 index 0000000000..a3b38a78b1 --- /dev/null +++ b/tests/ports/webassembly/jsffi_create_proxy.mjs.exp @@ -0,0 +1,6 @@ +1 + +1 +1 +PyProxy { _ref: 3 } +[ 2 ] diff --git a/tests/ports/webassembly/jsffi_to_js.mjs b/tests/ports/webassembly/jsffi_to_js.mjs new file mode 100644 index 0000000000..714af6b629 --- /dev/null +++ b/tests/ports/webassembly/jsffi_to_js.mjs @@ -0,0 +1,28 @@ +// Test jsffi.to_js(). + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.runPython(` +import jsffi +x = jsffi.to_js(1) +print(x) +y = jsffi.to_js([2]) +print(y) +z = jsffi.to_js({"three":3}) +print(z) +`); + +const x = mp.globals.get("x"); +const y = mp.globals.get("y"); +const z = mp.globals.get("z"); + +console.log(Array.isArray(x)); +console.log(x); + +console.log(Array.isArray(y)); +console.log(y); +console.log(Reflect.ownKeys(y)); + +console.log(Array.isArray(z)); +console.log(z); +console.log(Reflect.ownKeys(z)); diff --git a/tests/ports/webassembly/jsffi_to_js.mjs.exp b/tests/ports/webassembly/jsffi_to_js.mjs.exp new file mode 100644 index 0000000000..399dd0aa8c --- /dev/null +++ b/tests/ports/webassembly/jsffi_to_js.mjs.exp @@ -0,0 +1,11 @@ +1 + + +false +1 +true +[ 2 ] +[ '0', 'length' ] +false +{ three: 3 } +[ 'three' ] diff --git a/tests/ports/webassembly/override_new.mjs b/tests/ports/webassembly/override_new.mjs new file mode 100644 index 0000000000..f5d64d7d11 --- /dev/null +++ b/tests/ports/webassembly/override_new.mjs @@ -0,0 +1,33 @@ +// Test overriding .new() on a JavaScript class. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +globalThis.MyClass1 = class { + new() { + console.log("MyClass1 new"); + return 1; + } +}; + +globalThis.MyClass2 = class { + static new() { + console.log("MyClass2 static new"); + return 2; + } + new() { + console.log("MyClass2 new"); + return 3; + } +}; + +globalThis.myClass2Instance = new globalThis.MyClass2(); + +mp.runPython(` + import js + + print(type(js.MyClass1.new())) + print(js.MyClass1.new().new()) + + print(js.MyClass2.new()) + print(js.myClass2Instance.new()) +`); diff --git a/tests/ports/webassembly/override_new.mjs.exp b/tests/ports/webassembly/override_new.mjs.exp new file mode 100644 index 0000000000..2efb669714 --- /dev/null +++ b/tests/ports/webassembly/override_new.mjs.exp @@ -0,0 +1,7 @@ + +MyClass1 new +1 +MyClass2 static new +2 +MyClass2 new +3 diff --git a/tests/ports/webassembly/promise_with_resolvers.mjs b/tests/ports/webassembly/promise_with_resolvers.mjs new file mode 100644 index 0000000000..a2c6d509a6 --- /dev/null +++ b/tests/ports/webassembly/promise_with_resolvers.mjs @@ -0,0 +1,23 @@ +// Test polyfill of a method on a built-in. + +// Implement Promise.withResolvers, and make sure it has a unique name so +// the test below is guaranteed to use this version. +Promise.withResolversCustom = function withResolversCustom() { + let a; + let b; + const c = new this((resolve, reject) => { + a = resolve; + b = reject; + }); + return { resolve: a, reject: b, promise: c }; +}; + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.runPython(` + from js import Promise + + deferred = Promise.withResolversCustom() + deferred.promise.then(print) + deferred.resolve('OK') +`); diff --git a/tests/ports/webassembly/promise_with_resolvers.mjs.exp b/tests/ports/webassembly/promise_with_resolvers.mjs.exp new file mode 100644 index 0000000000..d86bac9de5 --- /dev/null +++ b/tests/ports/webassembly/promise_with_resolvers.mjs.exp @@ -0,0 +1 @@ +OK diff --git a/tests/ports/webassembly/py_proxy_delete.mjs b/tests/ports/webassembly/py_proxy_delete.mjs new file mode 100644 index 0000000000..2afea0b9f2 --- /dev/null +++ b/tests/ports/webassembly/py_proxy_delete.mjs @@ -0,0 +1,30 @@ +// Test `delete .` on the JavaScript side, which tests PyProxy.deleteProperty. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.runPython(` +class A: + pass +x = A() +x.foo = 1 +y = [] +`); + +const x = mp.globals.get("x"); +const y = mp.globals.get("y"); + +// Should pass. +// biome-ignore lint/performance/noDelete: test delete statement +delete x.foo; + +mp.runPython(` +print(hasattr(x, "foo")) +`); + +// Should fail, can't delete attributes on MicroPython lists. +try { + // biome-ignore lint/performance/noDelete: test delete statement + delete y.sort; +} catch (error) { + console.log(error.message); +} diff --git a/tests/ports/webassembly/py_proxy_delete.mjs.exp b/tests/ports/webassembly/py_proxy_delete.mjs.exp new file mode 100644 index 0000000000..8eb9ad1501 --- /dev/null +++ b/tests/ports/webassembly/py_proxy_delete.mjs.exp @@ -0,0 +1,2 @@ +False +'deleteProperty' on proxy: trap returned falsish for property 'sort' diff --git a/tests/ports/webassembly/py_proxy_dict.mjs b/tests/ports/webassembly/py_proxy_dict.mjs new file mode 100644 index 0000000000..201f179ef3 --- /dev/null +++ b/tests/ports/webassembly/py_proxy_dict.mjs @@ -0,0 +1,34 @@ +// Test passing a Python dict into JavaScript, it should act like a JS object. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.runPython(` +x = {"a": 1, "b": 2} +`); + +const x = mp.globals.get("x"); + +// Test has, get, keys/iteration. +console.log("a" in x, "b" in x, "c" in x); +console.log(x.a, x.b); +for (const k in x) { + console.log(k, x[k]); +} +console.log(Object.keys(x)); +console.log(Reflect.ownKeys(x)); + +// Test set. +x.c = 3; +console.log(Object.keys(x)); + +// Test delete. +// biome-ignore lint/performance/noDelete: test delete statement +delete x.b; +console.log(Object.keys(x)); + +// Make sure changes on the JavaScript side are reflected in Python. +mp.runPython(` +print(x["a"]) +print("b" in x) +print(x["c"]) +`); diff --git a/tests/ports/webassembly/py_proxy_dict.mjs.exp b/tests/ports/webassembly/py_proxy_dict.mjs.exp new file mode 100644 index 0000000000..f0e15034bd --- /dev/null +++ b/tests/ports/webassembly/py_proxy_dict.mjs.exp @@ -0,0 +1,11 @@ +true true false +1 2 +a 1 +b 2 +[ 'a', 'b' ] +[ 'a', 'b' ] +[ 'a', 'c', 'b' ] +[ 'a', 'c' ] +1 +False +3 diff --git a/tests/ports/webassembly/py_proxy_has.mjs b/tests/ports/webassembly/py_proxy_has.mjs new file mode 100644 index 0000000000..8881776fdb --- /dev/null +++ b/tests/ports/webassembly/py_proxy_has.mjs @@ -0,0 +1,11 @@ +// Test ` in ` on the JavaScript side, which tests PyProxy.has. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.runPython(` +x = [] +`); + +const x = mp.globals.get("x"); +console.log("no_exist" in x); +console.log("sort" in x); diff --git a/tests/ports/webassembly/py_proxy_has.mjs.exp b/tests/ports/webassembly/py_proxy_has.mjs.exp new file mode 100644 index 0000000000..1d474d5255 --- /dev/null +++ b/tests/ports/webassembly/py_proxy_has.mjs.exp @@ -0,0 +1,2 @@ +false +true diff --git a/tests/ports/webassembly/py_proxy_own_keys.mjs b/tests/ports/webassembly/py_proxy_own_keys.mjs new file mode 100644 index 0000000000..bbf5b4f01c --- /dev/null +++ b/tests/ports/webassembly/py_proxy_own_keys.mjs @@ -0,0 +1,11 @@ +// Test `Reflect.ownKeys()` on the JavaScript side, which tests PyProxy.ownKeys. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.runPython(` +x = [] +y = {"a": 1} +`); + +console.log(Reflect.ownKeys(mp.globals.get("x"))); +console.log(Reflect.ownKeys(mp.globals.get("y"))); diff --git a/tests/ports/webassembly/py_proxy_own_keys.mjs.exp b/tests/ports/webassembly/py_proxy_own_keys.mjs.exp new file mode 100644 index 0000000000..313d06d4d7 --- /dev/null +++ b/tests/ports/webassembly/py_proxy_own_keys.mjs.exp @@ -0,0 +1,9 @@ +[ + 'append', 'clear', + 'copy', 'count', + 'extend', 'index', + 'insert', 'pop', + 'remove', 'reverse', + 'sort' +] +[ 'a' ] diff --git a/tests/ports/webassembly/py_proxy_set.mjs b/tests/ports/webassembly/py_proxy_set.mjs new file mode 100644 index 0000000000..30360a847d --- /dev/null +++ b/tests/ports/webassembly/py_proxy_set.mjs @@ -0,0 +1,27 @@ +// Test `. = ` on the JavaScript side, which tests PyProxy.set. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.runPython(` +class A: + pass +x = A() +y = [] +`); + +const x = mp.globals.get("x"); +const y = mp.globals.get("y"); + +// Should pass. +x.foo = 1; + +mp.runPython(` +print(x.foo) +`); + +// Should fail, can't set attributes on MicroPython lists. +try { + y.bar = 1; +} catch (error) { + console.log(error.message); +} diff --git a/tests/ports/webassembly/py_proxy_set.mjs.exp b/tests/ports/webassembly/py_proxy_set.mjs.exp new file mode 100644 index 0000000000..e1d9951563 --- /dev/null +++ b/tests/ports/webassembly/py_proxy_set.mjs.exp @@ -0,0 +1,2 @@ +1 +'set' on proxy: trap returned falsish for property 'bar' diff --git a/tests/ports/webassembly/py_proxy_to_js.mjs b/tests/ports/webassembly/py_proxy_to_js.mjs new file mode 100644 index 0000000000..f9fce606f1 --- /dev/null +++ b/tests/ports/webassembly/py_proxy_to_js.mjs @@ -0,0 +1,20 @@ +// Test PyProxy.toJs(). + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.runPython(` +a = 1 +b = (1, 2, 3) +c = [None, True, 1.2] +d = {"one": 1, "tuple": b, "list": c} +`); + +const py_a = mp.globals.get("a"); +const py_b = mp.globals.get("b"); +const py_c = mp.globals.get("c"); +const py_d = mp.globals.get("d"); + +console.log(py_a instanceof mp.PyProxy, mp.PyProxy.toJs(py_a)); +console.log(py_b instanceof mp.PyProxy, mp.PyProxy.toJs(py_b)); +console.log(py_c instanceof mp.PyProxy, mp.PyProxy.toJs(py_c)); +console.log(py_d instanceof mp.PyProxy, mp.PyProxy.toJs(py_d)); diff --git a/tests/ports/webassembly/py_proxy_to_js.mjs.exp b/tests/ports/webassembly/py_proxy_to_js.mjs.exp new file mode 100644 index 0000000000..279df7bdfb --- /dev/null +++ b/tests/ports/webassembly/py_proxy_to_js.mjs.exp @@ -0,0 +1,4 @@ +false 1 +true [ 1, 2, 3 ] +true [ null, true, 1.2 ] +true { tuple: [ 1, 2, 3 ], one: 1, list: [ null, true, 1.2 ] } diff --git a/tests/ports/webassembly/register_js_module.js b/tests/ports/webassembly/register_js_module.js new file mode 100644 index 0000000000..b512f2c0dd --- /dev/null +++ b/tests/ports/webassembly/register_js_module.js @@ -0,0 +1,6 @@ +import(process.argv[2]).then((mp) => { + mp.loadMicroPython().then((py) => { + py.registerJsModule("js_module", { y: 2 }); + py.runPython("import js_module; print(js_module); print(js_module.y)"); + }); +}); diff --git a/tests/ports/webassembly/register_js_module.js.exp b/tests/ports/webassembly/register_js_module.js.exp new file mode 100644 index 0000000000..bb45f4ce00 --- /dev/null +++ b/tests/ports/webassembly/register_js_module.js.exp @@ -0,0 +1,2 @@ + +2 diff --git a/tests/ports/webassembly/run_python_async.mjs b/tests/ports/webassembly/run_python_async.mjs new file mode 100644 index 0000000000..44f2a90ab1 --- /dev/null +++ b/tests/ports/webassembly/run_python_async.mjs @@ -0,0 +1,115 @@ +// Test runPythonAsync() and top-level await in Python. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +/**********************************************************/ +// Using only promise objects, no await's. + +console.log("= TEST 1 =========="); + +globalThis.p = new Promise((resolve, reject) => { + resolve(123); +}); + +console.log(1); + +mp.runPython(` +import js +print(js.p) +print("py 1") +print(js.p.then(lambda x: print("resolved", x))) +print("py 2") +`); + +console.log(2); + +// Let the promise resolve. +await globalThis.p; + +console.log(3); + +/**********************************************************/ +// Using setTimeout to resolve the promise. + +console.log("= TEST 2 =========="); + +globalThis.p = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(123); + console.log("setTimeout resolved"); + }, 100); +}); + +console.log(1); + +mp.runPython(` +import js +print(js.p) +print("py 1") +print(js.p.then(lambda x: print("resolved", x))) +print("py 2") +`); + +console.log(2); + +// Let the promise resolve. +await globalThis.p; + +console.log(3); + +/**********************************************************/ +// Using setTimeout and await within Python. + +console.log("= TEST 3 =========="); + +globalThis.p = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(123); + console.log("setTimeout resolved"); + }, 100); +}); + +console.log(1); + +const ret3 = await mp.runPythonAsync(` +import js +print("py 1") +print("resolved value:", await js.p) +print("py 2") +`); + +console.log(2, ret3); + +/**********************************************************/ +// Multiple setTimeout's and await's within Python. + +console.log("= TEST 4 =========="); + +globalThis.p1 = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(123); + console.log("setTimeout A resolved"); + }, 100); +}); + +globalThis.p2 = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(456); + console.log("setTimeout B resolved"); + }, 200); +}); + +console.log(1); + +const ret4 = await mp.runPythonAsync(` +import js +print("py 1") +print("resolved value:", await js.p1) +print("py 2") +print("resolved value:", await js.p1) +print("py 3") +print("resolved value:", await js.p2) +print("py 4") +`); + +console.log(2, ret4); diff --git a/tests/ports/webassembly/run_python_async.mjs.exp b/tests/ports/webassembly/run_python_async.mjs.exp new file mode 100644 index 0000000000..f441bc5cf1 --- /dev/null +++ b/tests/ports/webassembly/run_python_async.mjs.exp @@ -0,0 +1,38 @@ += TEST 1 ========== +1 + +py 1 + +py 2 +2 +resolved 123 +3 += TEST 2 ========== +1 + +py 1 + +py 2 +2 +setTimeout resolved +resolved 123 +3 += TEST 3 ========== +1 +py 1 +setTimeout resolved +resolved value: 123 +py 2 +2 null += TEST 4 ========== +1 +py 1 +setTimeout A resolved +resolved value: 123 +py 2 +resolved value: 123 +py 3 +setTimeout B resolved +resolved value: 456 +py 4 +2 null diff --git a/tests/ports/webassembly/run_python_async2.mjs b/tests/ports/webassembly/run_python_async2.mjs new file mode 100644 index 0000000000..87067e6e8c --- /dev/null +++ b/tests/ports/webassembly/run_python_async2.mjs @@ -0,0 +1,42 @@ +// Test runPythonAsync() and top-level await in Python, with multi-level awaits. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +// simulate a 2-step resolution of the string "OK". +await mp.runPythonAsync(` +import js + +def _timeout(resolve, _): + js.setTimeout(resolve, 100) + +def _fetch(): + return js.Promise.new(_timeout) + +async def _text(promise): + if not promise._response: + print("_text await start") + await promise + print("_text awaited end") + ret = await promise._response.text() + return ret + +class _Response: + async def text(self): + print('_Response.text start') + await js.Promise.new(_timeout) + print('_Response.text end') + return "OK" + +def _response(promise): + promise._response = _Response() + return promise._response + +def fetch(url): + promise = _fetch().then(lambda *_: _response(promise)) + promise._response = None + promise.text = lambda: _text(promise) + return promise + +print(await fetch("config.json").text()) +print(await (await fetch("config.json")).text()) +`); diff --git a/tests/ports/webassembly/run_python_async2.mjs.exp b/tests/ports/webassembly/run_python_async2.mjs.exp new file mode 100644 index 0000000000..60d68c5d3b --- /dev/null +++ b/tests/ports/webassembly/run_python_async2.mjs.exp @@ -0,0 +1,8 @@ +_text await start +_text awaited end +_Response.text start +_Response.text end +OK +_Response.text start +_Response.text end +OK diff --git a/tests/ports/webassembly/this_behaviour.mjs b/tests/ports/webassembly/this_behaviour.mjs new file mode 100644 index 0000000000..6411b6ce63 --- /dev/null +++ b/tests/ports/webassembly/this_behaviour.mjs @@ -0,0 +1,24 @@ +// Test "this" behaviour. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +// "this" should be undefined. +globalThis.func0 = function () { + console.log("func0", this); +}; +mp.runPython("import js; js.func0()"); + +globalThis.func1 = function (a) { + console.log("func1", a, this); +}; +mp.runPython("import js; js.func1(123)"); + +globalThis.func2 = function (a, b) { + console.log("func2", a, b, this); +}; +mp.runPython("import js; js.func2(123, 456)"); + +globalThis.func3 = function (a, b, c) { + console.log("func3", a, b, c, this); +}; +mp.runPython("import js; js.func3(123, 456, 789)"); diff --git a/tests/ports/webassembly/this_behaviour.mjs.exp b/tests/ports/webassembly/this_behaviour.mjs.exp new file mode 100644 index 0000000000..4762026ab2 --- /dev/null +++ b/tests/ports/webassembly/this_behaviour.mjs.exp @@ -0,0 +1,4 @@ +func0 undefined +func1 123 undefined +func2 123 456 undefined +func3 123 456 789 undefined diff --git a/tests/ports/webassembly/various.js b/tests/ports/webassembly/various.js new file mode 100644 index 0000000000..e2fa9362c4 --- /dev/null +++ b/tests/ports/webassembly/various.js @@ -0,0 +1,38 @@ +import(process.argv[2]).then((mp) => { + mp.loadMicroPython().then((py) => { + globalThis.jsadd = (x, y) => { + return x + y; + }; + py.runPython("import js; print(js); print(js.jsadd(4, 9))"); + + py.runPython( + "def set_timeout_callback():\n print('set_timeout_callback')", + ); + py.runPython("import js; js.setTimeout(set_timeout_callback, 100)"); + + py.runPython("obj = js.Object(a=1)"); + console.log("main", py.pyimport("__main__").obj); + + console.log("======="); + py.runPython(` + from js import Array, Promise, Reflect + + def callback(resolve, reject): + resolve('OK1') + + p = Reflect.construct(Promise, Array(callback)) + p.then(print) + `); + + console.log("======="); + py.runPython(` + from js import Promise + + def callback(resolve, reject): + resolve('OK2') + + p = Promise.new(callback) + p.then(print) + `); + }); +}); diff --git a/tests/ports/webassembly/various.js.exp b/tests/ports/webassembly/various.js.exp new file mode 100644 index 0000000000..502ab2cccf --- /dev/null +++ b/tests/ports/webassembly/various.js.exp @@ -0,0 +1,8 @@ + +13 +main { a: 1 } +======= +======= +OK1 +OK2 +set_timeout_callback diff --git a/tests/run-tests.py b/tests/run-tests.py index 83af61c83d..4f55cdd398 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -1142,7 +1142,7 @@ the last matching regex is used: "ports/qemu-arm", ) elif args.target == "webassembly": - test_dirs += ("float",) + test_dirs += ("float", "ports/webassembly") else: # run tests from these directories test_dirs = args.test_dirs