mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-23 12:12:59 -05:00
* Fix #2114 - Cleanup the test folder + automation * Merged both test and tests into a single folder
This commit is contained in:
committed by
GitHub
parent
f4c4edeb29
commit
9f46234f71
19
pyscript.core/tests/config/ambiguous-config.html
Normal file
19
pyscript.core/tests/config/ambiguous-config.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Next</title>
|
||||
<script>
|
||||
addEventListener("error", ({ message }) => {
|
||||
document.body.innerHTML += `<p>${message}</p>`;
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<py-config>name = "first"</py-config>
|
||||
<script type="py" config="second.toml"></script>
|
||||
</body>
|
||||
</html>
|
||||
16
pyscript.core/tests/config/index.html
Normal file
16
pyscript.core/tests/config/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
<li><a href="./ambiguous-config.html">ambiguous py-config VS config attribute</a></li>
|
||||
<li><a href="./too-many-config.html">too many config attributes</a></li>
|
||||
<li><a href="./too-many-py-config.html">too many <py-config></a></li>
|
||||
<li><a href="./same-config.html">same config attributes</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
20
pyscript.core/tests/config/same-config.html
Normal file
20
pyscript.core/tests/config/same-config.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Next</title>
|
||||
<script>
|
||||
addEventListener("error", ({ message }) => {
|
||||
document.body.innerHTML += `<p>${message}</p>`;
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
OK
|
||||
<script type="py" config='{"name":"OK"}'></script>
|
||||
<script type="py" config='{"name":"OK"}'></script>
|
||||
</body>
|
||||
</html>
|
||||
19
pyscript.core/tests/config/too-many-config.html
Normal file
19
pyscript.core/tests/config/too-many-config.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Next</title>
|
||||
<script>
|
||||
addEventListener("error", ({ message }) => {
|
||||
document.body.innerHTML += `<p>${message}</p>`;
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py" config="first.toml"></script>
|
||||
<script type="py" config="second.toml"></script>
|
||||
</body>
|
||||
</html>
|
||||
19
pyscript.core/tests/config/too-many-py-config.html
Normal file
19
pyscript.core/tests/config/too-many-py-config.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Next</title>
|
||||
<script>
|
||||
addEventListener("error", ({ message }) => {
|
||||
document.body.innerHTML += `<p>${message}</p>`;
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<py-config>name = "first"</py-config>
|
||||
<py-config>name = "second"</py-config>
|
||||
</body>
|
||||
</html>
|
||||
18
pyscript.core/tests/index.html
Normal file
18
pyscript.core/tests/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PyScript tests</title>
|
||||
<style>
|
||||
body { font-family: sans-serif; }
|
||||
a {
|
||||
display: block;
|
||||
transition: opacity .3s;
|
||||
}
|
||||
a, span { opacity: .7; }
|
||||
a:hover { opacity: 1; }
|
||||
</style>
|
||||
</head>
|
||||
<body><ul><li><strong><a href="./config/index.html">config</a></strong><ul><li><a href="./config/ambiguous-config.html">ambiguous-config<small>.html</small></a></li><li><a href="./config/same-config.html">same-config<small>.html</small></a></li><li><a href="./config/too-many-config.html">too-many-config<small>.html</small></a></li><li><a href="./config/too-many-py-config.html">too-many-py-config<small>.html</small></a></li></ul></li><li><strong><a href="./issue-7015/index.html">issue-7015</a></strong></li><li><strong><span>js-integration</span></strong><ul><li><a href="./js-integration/config-url.html">config-url<small>.html</small></a></li><li><strong><a href="./js-integration/fetch/index.html">fetch</a></strong></li><li><a href="./js-integration/ffi.html">ffi<small>.html</small></a></li><li><a href="./js-integration/hooks.html">hooks<small>.html</small></a></li><li><strong><a href="./js-integration/issue-2093/index.html">issue-2093</a></strong></li><li><a href="./js-integration/js_modules.html">js_modules<small>.html</small></a></li><li><a href="./js-integration/mpy.html">mpy<small>.html</small></a></li><li><a href="./js-integration/py-terminal-main.html">py-terminal-main<small>.html</small></a></li><li><a href="./js-integration/py-terminal-worker.html">py-terminal-worker<small>.html</small></a></li><li><a href="./js-integration/py-terminal.html">py-terminal<small>.html</small></a></li><li><a href="./js-integration/py-terminals.html">py-terminals<small>.html</small></a></li><li><strong><a href="./js-integration/pyscript_dom/index.html">pyscript_dom</a></strong></li><li><a href="./js-integration/storage.html">storage<small>.html</small></a></li><li><strong><a href="./js-integration/workers/index.html">workers</a></strong><ul><li><a href="./js-integration/workers/named.html">named<small>.html</small></a></li></ul></li></ul></li><li><strong><a href="./manual/index.html">manual</a></strong><ul><li><a href="./manual/all-done.html">all-done<small>.html</small></a></li><li><a href="./manual/async.html">async<small>.html</small></a></li><li><a href="./manual/camera.html">camera<small>.html</small></a></li><li><a href="./manual/click.html">click<small>.html</small></a></li><li><a href="./manual/code-a-part.html">code-a-part<small>.html</small></a></li><li><a href="./manual/combo.html">combo<small>.html</small></a></li><li><a href="./manual/config.html">config<small>.html</small></a></li><li><a href="./manual/create-element.html">create-element<small>.html</small></a></li><li><a href="./manual/dialog.html">dialog<small>.html</small></a></li><li><a href="./manual/display.html">display<small>.html</small></a></li><li><a href="./manual/error.html">error<small>.html</small></a></li><li><a href="./manual/html-decode.html">html-decode<small>.html</small></a></li><li><a href="./manual/input.html">input<small>.html</small></a></li><li><a href="./manual/multi.html">multi<small>.html</small></a></li><li><a href="./manual/multiple-editors.html">multiple-editors<small>.html</small></a></li><li><a href="./manual/no-error.html">no-error<small>.html</small></a></li><li><a href="./manual/py-editor.html">py-editor<small>.html</small></a></li><li><a href="./manual/py_modules.html">py_modules<small>.html</small></a></li><li><a href="./manual/split-config.html">split-config<small>.html</small></a></li><li><a href="./manual/target.html">target<small>.html</small></a></li><li><a href="./manual/test_display_HTML.html">test_display_HTML<small>.html</small></a></li><li><a href="./manual/test_when.html">test_when<small>.html</small></a></li><li><a href="./manual/worker.html">worker<small>.html</small></a></li></ul></li><li><strong><a href="./no_sab/index.html">no_sab</a></strong></li><li><strong><a href="./piratical/index.html">piratical</a></strong></li><li><strong><a href="./py-editor/index.html">py-editor</a></strong><ul><li><a href="./py-editor/issue-2056.html">issue-2056<small>.html</small></a></li><li><a href="./py-editor/service-worker.html">service-worker<small>.html</small></a></li></ul></li><li><strong><a href="./py-terminals/index.html">py-terminals</a></strong><ul><li><a href="./py-terminals/no-repl.html">no-repl<small>.html</small></a></li><li><a href="./py-terminals/repl.html">repl<small>.html</small></a></li></ul></li><li><strong><a href="./service-worker/index.html">service-worker</a></strong></li><li><strong><a href="./ui/index.html">ui</a></strong><ul><li><a href="./ui/gallery.html">gallery<small>.html</small></a></li></ul></li></ul></body>
|
||||
</html>
|
||||
99
pyscript.core/tests/integration.spec.js
Normal file
99
pyscript.core/tests/integration.spec.js
Normal file
@@ -0,0 +1,99 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('MicroPython display', async ({ page }) => {
|
||||
await page.goto('http://localhost:8080/tests/js-integration/mpy.html');
|
||||
await page.waitForSelector('html.done.worker');
|
||||
const body = await page.evaluate(() => document.body.innerText);
|
||||
await expect(body.trim()).toBe([
|
||||
'M-PyScript Main 1',
|
||||
'M-PyScript Main 2',
|
||||
'M-PyScript Worker',
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
test('MicroPython hooks', async ({ page }) => {
|
||||
const logs = [];
|
||||
page.on('console', msg => {
|
||||
const text = msg.text();
|
||||
if (!text.startsWith('['))
|
||||
logs.push(text);
|
||||
});
|
||||
await page.goto('http://localhost:8080/tests/js-integration/hooks.html');
|
||||
await page.waitForSelector('html.done.worker');
|
||||
await expect(logs.join('\n')).toBe([
|
||||
'main onReady',
|
||||
'main onBeforeRun',
|
||||
'main codeBeforeRun',
|
||||
'actual code in main',
|
||||
'main codeAfterRun',
|
||||
'main onAfterRun',
|
||||
'worker onReady',
|
||||
'worker onBeforeRun',
|
||||
'worker codeBeforeRun',
|
||||
'actual code in worker',
|
||||
'worker codeAfterRun',
|
||||
'worker onAfterRun',
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
test('MicroPython + Pyodide js_modules', async ({ page }) => {
|
||||
const logs = [];
|
||||
page.on('console', msg => {
|
||||
const text = msg.text();
|
||||
if (!text.startsWith('['))
|
||||
logs.push(text);
|
||||
});
|
||||
await page.goto('http://localhost:8080/tests/js-integration/js_modules.html');
|
||||
await page.waitForSelector('html.done');
|
||||
await expect(logs.length).toBe(6);
|
||||
await expect(logs[0]).toBe(logs[1]);
|
||||
await expect(logs[1]).toBe(logs[2]);
|
||||
await expect(logs[3]).toBe(logs[4]);
|
||||
await expect(logs[4]).toBe(logs[5]);
|
||||
});
|
||||
|
||||
test('MicroPython + configURL', async ({ page }) => {
|
||||
await page.goto('http://localhost:8080/tests/js-integration/config-url.html');
|
||||
await page.waitForSelector('html.main.worker');
|
||||
});
|
||||
|
||||
test('Pyodide + terminal on Main', async ({ page }) => {
|
||||
await page.goto('http://localhost:8080/tests/js-integration/py-terminal-main.html');
|
||||
await page.waitForSelector('html.ok');
|
||||
});
|
||||
|
||||
|
||||
test('Pyodide + terminal on Worker', async ({ page }) => {
|
||||
await page.goto('http://localhost:8080/tests/js-integration/py-terminal-worker.html');
|
||||
await page.waitForSelector('html.ok');
|
||||
});
|
||||
|
||||
test('Pyodide + multiple terminals via Worker', async ({ page }) => {
|
||||
await page.goto('http://localhost:8080/tests/js-integration/py-terminals.html');
|
||||
await page.waitForSelector('html.first.second');
|
||||
});
|
||||
|
||||
test('MicroPython + Pyodide fetch', async ({ page }) => {
|
||||
await page.goto('http://localhost:8080/tests/js-integration/fetch/index.html');
|
||||
await page.waitForSelector('html.mpy.py');
|
||||
});
|
||||
|
||||
test('MicroPython + Pyodide ffi', async ({ page }) => {
|
||||
await page.goto('http://localhost:8080/tests/js-integration/ffi.html');
|
||||
await page.waitForSelector('html.mpy.py');
|
||||
});
|
||||
|
||||
test('MicroPython + Storage', async ({ page }) => {
|
||||
await page.goto('http://localhost:8080/tests/js-integration/storage.html');
|
||||
await page.waitForSelector('html.ok');
|
||||
});
|
||||
|
||||
test('MicroPython + workers', async ({ page }) => {
|
||||
await page.goto('http://localhost:8080/tests/js-integration/workers/index.html');
|
||||
await page.waitForSelector('html.mpy.py');
|
||||
});
|
||||
|
||||
test('MicroPython Editor setup error', async ({ page }) => {
|
||||
await page.goto('http://localhost:8080/tests/js-integration/issue-2093/index.html');
|
||||
await page.waitForSelector('html.errored');
|
||||
});
|
||||
@@ -17,7 +17,7 @@ from playwright.sync_api import Error as PlaywrightError
|
||||
|
||||
ROOT = py.path.local(__file__).dirpath("..", "..", "..")
|
||||
BUILD = ROOT.join("pyscript.core").join("dist")
|
||||
TEST = ROOT.join("pyscript.core").join("test")
|
||||
TEST = ROOT.join("pyscript.core").join("tests")
|
||||
|
||||
|
||||
def params_with_marks(params):
|
||||
@@ -212,7 +212,7 @@ class PyScriptTest:
|
||||
tmpdir.join("dist").mksymlinkto(BUILD)
|
||||
# create a symlink to TEST inside tmpdir so we can run tests in that
|
||||
# manual test folder
|
||||
tmpdir.join("test").mksymlinkto(TEST)
|
||||
tmpdir.join("tests").mksymlinkto(TEST)
|
||||
|
||||
# create a symlink to the favicon, so that we can use it in the HTML
|
||||
self.tmpdir.chdir()
|
||||
|
||||
@@ -5,7 +5,6 @@ from .support import PyScriptTest, with_execution_thread
|
||||
class TestSmokeTests(PyScriptTest):
|
||||
"""
|
||||
Each example requires the same three tests:
|
||||
|
||||
- Test that the initial markup loads properly (currently done by
|
||||
testing the <title> tag's content)
|
||||
- Testing that pyscript is loading properly
|
||||
@@ -14,7 +13,7 @@ class TestSmokeTests(PyScriptTest):
|
||||
|
||||
def test_pydom(self):
|
||||
# Test the full pydom test suite by running it in the browser
|
||||
self.goto("test/pyscript_dom/index.html?-v&-s")
|
||||
self.goto("tests/pyscript_dom/index.html?-v&-s")
|
||||
assert self.page.title() == "PyDom Test Suite"
|
||||
|
||||
# wait for the test suite to finish
|
||||
|
||||
4
pyscript.core/tests/issue-7015/config.toml
Normal file
4
pyscript.core/tests/issue-7015/config.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
packages = [
|
||||
"https://cdn.holoviz.org/panel/wheels/bokeh-3.5.0-py3-none-any.whl",
|
||||
"https://cdn.holoviz.org/panel/1.5.0-b.2/dist/wheels/panel-1.5.0b2-py3-none-any.whl"
|
||||
]
|
||||
17
pyscript.core/tests/issue-7015/index.html
Normal file
17
pyscript.core/tests/issue-7015/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-3.5.0.js"></script>
|
||||
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.5.0.min.js"></script>
|
||||
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.5.0.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@holoviz/panel@1.5.0-b.2/dist/panel.min.js"></script>
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py" src="main.py" config="config.toml" worker></script>
|
||||
<div id="simple_app"></div>
|
||||
</body>
|
||||
</html>
|
||||
12
pyscript.core/tests/issue-7015/main.py
Normal file
12
pyscript.core/tests/issue-7015/main.py
Normal file
@@ -0,0 +1,12 @@
|
||||
import panel as pn
|
||||
|
||||
pn.extension(sizing_mode="stretch_width")
|
||||
|
||||
slider = pn.widgets.FloatSlider(start=0, end=10, name="amplitude")
|
||||
|
||||
|
||||
def callback(new):
|
||||
return f"Amplitude is: {new}"
|
||||
|
||||
|
||||
pn.Row(slider, pn.bind(callback, slider)).servable(target="simple_app")
|
||||
25
pyscript.core/tests/js-integration/config-url.html
Normal file
25
pyscript.core/tests/js-integration/config-url.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PyScript Next Plugin</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<mpy-config src="config-url/config.json"></mpy-config>
|
||||
<script type="mpy">
|
||||
from pyscript import config
|
||||
if config["files"]["{TO}"] != "./runtime":
|
||||
raise Exception("wrong config tree")
|
||||
|
||||
from runtime import test
|
||||
</script>
|
||||
<script type="mpy" worker>
|
||||
from pyscript import config
|
||||
if config["files"]["{TO}"] != "./runtime":
|
||||
raise Exception("wrong config tree")
|
||||
|
||||
from runtime import test
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"files":{
|
||||
"{FROM}": "./src",
|
||||
"{TO}": "./runtime",
|
||||
"{FROM}/test.py": "{TO}/test.py"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
from pyscript import RUNNING_IN_WORKER, document
|
||||
|
||||
classList = document.documentElement.classList
|
||||
|
||||
if RUNNING_IN_WORKER:
|
||||
classList.add("worker")
|
||||
else:
|
||||
classList.add("main")
|
||||
1
pyscript.core/tests/js-integration/fetch/a.py
Normal file
1
pyscript.core/tests/js-integration/fetch/a.py
Normal file
@@ -0,0 +1 @@
|
||||
print("a")
|
||||
5
pyscript.core/tests/js-integration/fetch/config.json
Normal file
5
pyscript.core/tests/js-integration/fetch/config.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"fetch": [{
|
||||
"files": ["./a.py"]
|
||||
}]
|
||||
}
|
||||
95
pyscript.core/tests/js-integration/fetch/index.html
Normal file
95
pyscript.core/tests/js-integration/fetch/index.html
Normal file
@@ -0,0 +1,95 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="../../../dist/core.css">
|
||||
</head>
|
||||
<body>
|
||||
<script type="module">
|
||||
import fetch from 'https://esm.run/@webreflection/fetch';
|
||||
|
||||
globalThis.fetch_text = await fetch("config.json").text();
|
||||
globalThis.fetch_json = JSON.stringify(await fetch("config.json").json());
|
||||
globalThis.fetch_buffer = new Uint8Array((await fetch("config.json").arrayBuffer())).length;
|
||||
|
||||
document.head.appendChild(
|
||||
Object.assign(
|
||||
document.createElement('script'),
|
||||
{
|
||||
type: 'module',
|
||||
src: '../../../dist/core.js'
|
||||
}
|
||||
)
|
||||
);
|
||||
</script>
|
||||
<script type="mpy" async>
|
||||
import js, json
|
||||
from pyscript import document, fetch
|
||||
|
||||
fetch_text = await (await fetch("config.json")).text()
|
||||
if (fetch_text != js.fetch_text):
|
||||
raise Exception("fetch_text")
|
||||
|
||||
fetch_text = await fetch("config.json").text()
|
||||
if (fetch_text != js.fetch_text):
|
||||
raise Exception("fetch_text")
|
||||
|
||||
fetch_json = await (await fetch("config.json")).json()
|
||||
if (json.dumps(fetch_json).replace(" ", "") != js.fetch_json):
|
||||
raise Exception("fetch_json")
|
||||
|
||||
fetch_json = await fetch("config.json").json()
|
||||
if (json.dumps(fetch_json).replace(" ", "") != js.fetch_json):
|
||||
raise Exception("fetch_json")
|
||||
|
||||
fetch_buffer = await (await fetch("config.json")).arrayBuffer()
|
||||
if (len(fetch_buffer) != js.fetch_buffer):
|
||||
raise Exception("fetch_buffer")
|
||||
|
||||
fetch_buffer = await fetch("config.json").arrayBuffer()
|
||||
if (len(fetch_buffer) != js.fetch_buffer):
|
||||
raise Exception("fetch_buffer")
|
||||
|
||||
print(await (await fetch("config.json")).bytearray())
|
||||
print(await (await fetch("config.json")).blob())
|
||||
|
||||
if (await fetch("shenanigans.nope")).ok == False:
|
||||
document.documentElement.classList.add('mpy')
|
||||
</script>
|
||||
<script type="py" async>
|
||||
import js, json
|
||||
from pyscript import document, fetch
|
||||
|
||||
fetch_text = await (await fetch("config.json")).text()
|
||||
if (fetch_text != js.fetch_text):
|
||||
raise Exception("fetch_text")
|
||||
|
||||
fetch_text = await fetch("config.json").text()
|
||||
if (fetch_text != js.fetch_text):
|
||||
raise Exception("fetch_text")
|
||||
|
||||
fetch_json = await (await fetch("config.json")).json()
|
||||
if (json.dumps(fetch_json).replace(" ", "") != js.fetch_json):
|
||||
raise Exception("fetch_json")
|
||||
|
||||
fetch_json = await fetch("config.json").json()
|
||||
if (json.dumps(fetch_json).replace(" ", "") != js.fetch_json):
|
||||
raise Exception("fetch_json")
|
||||
|
||||
fetch_buffer = await (await fetch("config.json")).arrayBuffer()
|
||||
if (len(fetch_buffer) != js.fetch_buffer):
|
||||
raise Exception("fetch_buffer")
|
||||
|
||||
fetch_buffer = await fetch("config.json").arrayBuffer()
|
||||
if (len(fetch_buffer) != js.fetch_buffer):
|
||||
raise Exception("fetch_buffer")
|
||||
|
||||
print(await (await fetch("config.json")).bytearray())
|
||||
print(await (await fetch("config.json")).blob())
|
||||
|
||||
if (await fetch("shenanigans.nope")).ok == False:
|
||||
document.documentElement.classList.add('py')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
26
pyscript.core/tests/js-integration/ffi.html
Normal file
26
pyscript.core/tests/js-integration/ffi.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript FFI</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy">
|
||||
from pyscript import document
|
||||
from pyscript.ffi import to_js
|
||||
document.documentElement.classList.add(
|
||||
to_js({"ok": "mpy"}).ok
|
||||
)
|
||||
</script>
|
||||
<script type="py">
|
||||
from pyscript import document
|
||||
from pyscript.ffi import to_js
|
||||
document.documentElement.classList.add(
|
||||
to_js({"ok": "py"}).ok
|
||||
)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
60
pyscript.core/tests/js-integration/hooks.html
Normal file
60
pyscript.core/tests/js-integration/hooks.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PyScript Next Plugin Bug?</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module">
|
||||
addEventListener('mpy:done', () => {
|
||||
document.documentElement.classList.add('done');
|
||||
});
|
||||
|
||||
import { hooks } from "../../dist/core.js";
|
||||
|
||||
// Main
|
||||
hooks.main.onReady.add((wrap, element) => {
|
||||
console.log("main", "onReady");
|
||||
if (location.search === '?debug') {
|
||||
console.debug("main", "wrap", wrap);
|
||||
console.debug("main", "element", element);
|
||||
}
|
||||
});
|
||||
hooks.main.onBeforeRun.add(() => {
|
||||
console.log("main", "onBeforeRun");
|
||||
});
|
||||
hooks.main.codeBeforeRun.add('print("main", "codeBeforeRun")');
|
||||
hooks.main.codeAfterRun.add('print("main", "codeAfterRun")');
|
||||
hooks.main.onAfterRun.add(() => {
|
||||
console.log("main", "onAfterRun");
|
||||
});
|
||||
|
||||
// Worker
|
||||
hooks.worker.onReady.add((wrap, xworker) => {
|
||||
console.log("worker", "onReady");
|
||||
if (location.search === '?debug') {
|
||||
console.debug("worker", "wrap", wrap);
|
||||
console.debug("worker", "xworker", xworker);
|
||||
}
|
||||
});
|
||||
hooks.worker.onBeforeRun.add(() => {
|
||||
console.log("worker", "onBeforeRun");
|
||||
});
|
||||
hooks.worker.codeBeforeRun.add('print("worker", "codeBeforeRun")');
|
||||
hooks.worker.codeAfterRun.add('print("worker", "codeAfterRun")');
|
||||
hooks.worker.onAfterRun.add(() => {
|
||||
console.log("worker", "onAfterRun");
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy" async="false" worker>
|
||||
from pyscript import document
|
||||
print("actual code in worker")
|
||||
document.documentElement.classList.add('worker')
|
||||
</script>
|
||||
<script type="mpy" async="false">
|
||||
print("actual code in main")
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
6
pyscript.core/tests/js-integration/issue-2093/error.js
Normal file
6
pyscript.core/tests/js-integration/issue-2093/error.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const { error } = console;
|
||||
|
||||
console.error = (...args) => {
|
||||
error(...args);
|
||||
document.documentElement.classList.add('errored');
|
||||
};
|
||||
16
pyscript.core/tests/js-integration/issue-2093/index.html
Normal file
16
pyscript.core/tests/js-integration/issue-2093/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="../../../dist/core.css">
|
||||
<script type="module" src="./error.js"></script>
|
||||
<script type="module" src="../../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy-editor" setup>
|
||||
print("Hello Editor")
|
||||
raise Exception("failure")
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
39
pyscript.core/tests/js-integration/js_modules.html
Normal file
39
pyscript.core/tests/js-integration/js_modules.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<mpy-config>
|
||||
[js_modules.main]
|
||||
"./js_modules.js" = "random_js"
|
||||
</mpy-config>
|
||||
<mpy-script>
|
||||
from pyscript.js_modules.random_js import default as value
|
||||
from pyscript.js_modules import random_js
|
||||
from pyscript import js_modules
|
||||
|
||||
print("mpy", value)
|
||||
print("mpy", random_js.default)
|
||||
print("mpy", js_modules.random_js.default)
|
||||
</mpy-script>
|
||||
<py-config>
|
||||
[js_modules.main]
|
||||
"./js_modules.js" = "random_js"
|
||||
</py-config>
|
||||
<py-script>
|
||||
from pyscript.js_modules.random_js import default as value
|
||||
from pyscript.js_modules import random_js
|
||||
from pyscript import js_modules, document
|
||||
|
||||
print("py", value)
|
||||
print("py", random_js.default)
|
||||
print("py", js_modules.random_js.default)
|
||||
|
||||
document.documentElement.classList.add('done')
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
1
pyscript.core/tests/js-integration/js_modules.js
Normal file
1
pyscript.core/tests/js-integration/js_modules.js
Normal file
@@ -0,0 +1 @@
|
||||
export default Math.random();
|
||||
30
pyscript.core/tests/js-integration/mpy.html
Normal file
30
pyscript.core/tests/js-integration/mpy.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Next</title>
|
||||
<script>
|
||||
addEventListener('mpy:done', () => {
|
||||
document.documentElement.classList.add('done');
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy">
|
||||
from pyscript import display
|
||||
display("Hello", "M-PyScript Main 1", append=False)
|
||||
</script>
|
||||
<mpy-script>
|
||||
from pyscript import display
|
||||
display("Hello", "M-PyScript Main 2", append=False)
|
||||
</mpy-script>
|
||||
<mpy-script worker>
|
||||
from pyscript import display, document
|
||||
display("Hello", "M-PyScript Worker", append=False)
|
||||
document.documentElement.classList.add('worker')
|
||||
</mpy-script>
|
||||
</body>
|
||||
</html>
|
||||
14
pyscript.core/tests/js-integration/py-terminal-main.html
Normal file
14
pyscript.core/tests/js-integration/py-terminal-main.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyTerminal Main</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<style>.xterm { padding: .5rem; }</style>
|
||||
</head>
|
||||
<body>
|
||||
<py-script src="terminal.py" terminal></py-script>
|
||||
</body>
|
||||
</html>
|
||||
15
pyscript.core/tests/js-integration/py-terminal-worker.html
Normal file
15
pyscript.core/tests/js-integration/py-terminal-worker.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyTerminal Main</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<style>.xterm { padding: .5rem; }</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py" src="terminal.py" worker terminal></script>
|
||||
<script type="mpy" src="terminal.py" worker terminal></script>
|
||||
</body>
|
||||
</html>
|
||||
18
pyscript.core/tests/js-integration/py-terminal.html
Normal file
18
pyscript.core/tests/js-integration/py-terminal.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyTerminal</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<style>.xterm { padding: .5rem; }</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy" worker terminal>
|
||||
print("µpython")
|
||||
import code
|
||||
code.interact()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
27
pyscript.core/tests/js-integration/py-terminals.html
Normal file
27
pyscript.core/tests/js-integration/py-terminals.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyTerminal Main</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<style>.xterm { padding: .5rem; }</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy" worker terminal>
|
||||
from pyscript import document
|
||||
document.documentElement.classList.add("first")
|
||||
|
||||
import code
|
||||
code.interact()
|
||||
</script>
|
||||
<script type="py" worker terminal>
|
||||
from pyscript import document
|
||||
document.documentElement.classList.add("second")
|
||||
|
||||
import code
|
||||
code.interact()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
46
pyscript.core/tests/js-integration/storage.html
Normal file
46
pyscript.core/tests/js-integration/storage.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@pyscript/core storage</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy" async>
|
||||
from random import random
|
||||
from pyscript import storage
|
||||
|
||||
store = await storage(name="test")
|
||||
|
||||
print("before", len(store))
|
||||
for k in store:
|
||||
if isinstance(store[k], memoryview):
|
||||
print(f" {k}: {store[k].hex()} as hex()")
|
||||
else:
|
||||
print(f" {k}: {store[k]}")
|
||||
|
||||
store["ba"] = bytearray([0, 1, 2, 3, 4])
|
||||
store["mv"] = memoryview(bytearray([5, 6, 7, 8, 9]))
|
||||
store["random"] = ("some", random(), True)
|
||||
store["key"] = "value"
|
||||
|
||||
print("now", len(store))
|
||||
for k in store:
|
||||
print(f" {k}: {store[k]}")
|
||||
|
||||
del store["key"]
|
||||
# store.clear()
|
||||
|
||||
print("after", len(store))
|
||||
for k in store:
|
||||
print(f" {k}: {store[k]}")
|
||||
|
||||
await store.sync()
|
||||
|
||||
import js
|
||||
js.document.documentElement.classList.add("ok")
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
8
pyscript.core/tests/js-integration/terminal.py
Normal file
8
pyscript.core/tests/js-integration/terminal.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from pyscript import document
|
||||
|
||||
classList = document.documentElement.classList
|
||||
|
||||
if not __terminal__:
|
||||
classList.add("error")
|
||||
else:
|
||||
classList.add("ok")
|
||||
2
pyscript.core/tests/js-integration/workers/config.toml
Normal file
2
pyscript.core/tests/js-integration/workers/config.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[files]
|
||||
"./test.py" = "./test.py"
|
||||
30
pyscript.core/tests/js-integration/workers/index.html
Normal file
30
pyscript.core/tests/js-integration/workers/index.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<script type="module" src="../../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy" async>
|
||||
from pyscript import create_named_worker
|
||||
|
||||
await create_named_worker("./worker.py", name="micropython_version", type="mpy")
|
||||
</script>
|
||||
<script type="mpy" config="./config.toml" async>
|
||||
from test import test
|
||||
await test("mpy")
|
||||
</script>
|
||||
<script type="py" config="./config.toml" async>
|
||||
from test import test
|
||||
await test("py")
|
||||
</script>
|
||||
<script type="py" name="pyodide_version" worker>
|
||||
def pyodide_version():
|
||||
import sys
|
||||
return sys.version
|
||||
|
||||
__export__ = ['pyodide_version']
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
29
pyscript.core/tests/js-integration/workers/named.html
Normal file
29
pyscript.core/tests/js-integration/workers/named.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||
<title>named workers</title>
|
||||
<script type="module" src="../../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy" async>
|
||||
from pyscript import workers
|
||||
|
||||
await (await workers["mpy"]).greetings()
|
||||
await (await workers["py"]).greetings()
|
||||
</script>
|
||||
<script type="mpy" worker name="mpy">
|
||||
def greetings():
|
||||
print("micropython")
|
||||
|
||||
__export__ = ['greetings']
|
||||
</script>
|
||||
<script type="py" worker name="py">
|
||||
def greetings():
|
||||
print("pyodide")
|
||||
|
||||
__export__ = ['greetings']
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
19
pyscript.core/tests/js-integration/workers/test.py
Normal file
19
pyscript.core/tests/js-integration/workers/test.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from pyscript import document, workers
|
||||
|
||||
|
||||
async def test(interpreter):
|
||||
# accessed as item
|
||||
named = await workers.micropython_version
|
||||
|
||||
version = await named.micropython_version()
|
||||
document.body.append(version)
|
||||
document.body.append(document.createElement("hr"))
|
||||
|
||||
# accessed as attribute
|
||||
named = await workers["pyodide_version"]
|
||||
|
||||
version = await named.pyodide_version()
|
||||
document.body.append(version)
|
||||
document.body.append(document.createElement("hr"))
|
||||
|
||||
document.documentElement.classList.add(interpreter)
|
||||
7
pyscript.core/tests/js-integration/workers/worker.py
Normal file
7
pyscript.core/tests/js-integration/workers/worker.py
Normal file
@@ -0,0 +1,7 @@
|
||||
def micropython_version():
|
||||
import sys
|
||||
|
||||
return sys.version
|
||||
|
||||
|
||||
__export__ = ["micropython_version"]
|
||||
1
pyscript.core/tests/manual/a.py
Normal file
1
pyscript.core/tests/manual/a.py
Normal file
@@ -0,0 +1 @@
|
||||
print("a")
|
||||
39
pyscript.core/tests/manual/all-done.html
Normal file
39
pyscript.core/tests/manual/all-done.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module">
|
||||
import '../../dist/core.js';
|
||||
|
||||
document.body.append('loading ...', document.createElement('br'));
|
||||
|
||||
addEventListener(
|
||||
'py:all-done',
|
||||
() => {
|
||||
document.body.append('all executed');
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py">
|
||||
print(1)
|
||||
</script>
|
||||
<py-script>
|
||||
print(2)
|
||||
</py-script>
|
||||
<py-script async>
|
||||
print(3)
|
||||
</py-script>
|
||||
<script type="py" worker>
|
||||
print(4)
|
||||
</script>
|
||||
<py-script async worker>
|
||||
print(5)
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
21
pyscript.core/tests/manual/async.html
Normal file
21
pyscript.core/tests/manual/async.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<py-script>
|
||||
import asyncio
|
||||
print('py-script sleep')
|
||||
await asyncio.sleep(1)
|
||||
print('py-script done')
|
||||
</py-script>
|
||||
<script type="py">
|
||||
import asyncio
|
||||
print('script-py sleep')
|
||||
await asyncio.sleep(1)
|
||||
print('script-py done')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1
pyscript.core/tests/manual/bad.toml
Normal file
1
pyscript.core/tests/manual/bad.toml
Normal file
@@ -0,0 +1 @@
|
||||
files = [
|
||||
24
pyscript.core/tests/manual/camera.html
Normal file
24
pyscript.core/tests/manual/camera.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PyScript Media Example</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py" src="camera.py" async></script>
|
||||
|
||||
<label for="cars">Choose a device:</label>
|
||||
|
||||
<select name="devices" id="devices"></select>
|
||||
|
||||
<button id="pick-device">Select the device</button>
|
||||
<button id="snap">Snap</button>
|
||||
|
||||
<div id="result"></div>
|
||||
|
||||
<video id="video" width="600" height="400" autoplay></video>
|
||||
</body>
|
||||
</html>
|
||||
32
pyscript.core/tests/manual/camera.py
Normal file
32
pyscript.core/tests/manual/camera.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from pyodide.ffi import create_proxy
|
||||
from pyscript import display, document, when, window
|
||||
from pyweb import media, pydom
|
||||
|
||||
devicesSelect = pydom["#devices"][0]
|
||||
video = pydom["video"][0]
|
||||
devices = {}
|
||||
|
||||
|
||||
async def list_media_devices(event=None):
|
||||
"""List the available media devices."""
|
||||
global devices
|
||||
for i, device in enumerate(await media.list_devices()):
|
||||
devices[device.id] = device
|
||||
label = f"{i} - ({device.kind}) {device.label} [{device.id}]"
|
||||
devicesSelect.options.add(value=device.id, html=label)
|
||||
|
||||
|
||||
@when("click", "#pick-device")
|
||||
async def connect_to_device(e):
|
||||
"""Connect to the selected device."""
|
||||
device = devices[devicesSelect.value]
|
||||
video._js.srcObject = await device.get_stream()
|
||||
|
||||
|
||||
@when("click", "#snap")
|
||||
async def camera_click(e):
|
||||
"""Take a picture and download it."""
|
||||
video.snap().download()
|
||||
|
||||
|
||||
await list_media_devices()
|
||||
29
pyscript.core/tests/manual/click.html
Normal file
29
pyscript.core/tests/manual/click.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PyScript Next Plugin Bug?</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py">
|
||||
from pyscript import display, document
|
||||
from datetime import datetime as dt
|
||||
from pyodide.ffi.wrappers import add_event_listener
|
||||
|
||||
element = document.querySelector("#just-a-button")
|
||||
|
||||
def on_click(event):
|
||||
print(f"Hello from Python! {dt.now()}")
|
||||
display(f"Hello from Python! {dt.now()}", append=False, target='result')
|
||||
|
||||
add_event_listener(element, "click", on_click)
|
||||
</script>
|
||||
|
||||
<button id="just-a-button">click and check the console</button>
|
||||
|
||||
<div id="result"></div>
|
||||
</body>
|
||||
</html>
|
||||
19
pyscript.core/tests/manual/code-a-part.html
Normal file
19
pyscript.core/tests/manual/code-a-part.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module">
|
||||
import { hooks } from "../../dist/core.js";
|
||||
hooks.main.codeBeforeRun.add('print(0)');
|
||||
hooks.main.codeAfterRun.add('print(2)');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py">
|
||||
# raise an error instead to see it on line 1
|
||||
print(1)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
17
pyscript.core/tests/manual/combo.html
Normal file
17
pyscript.core/tests/manual/combo.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Error</title>
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<py-config>
|
||||
[[fetch]]
|
||||
files = ["./a.py"]
|
||||
</py-config>
|
||||
<script type="py" worker>
|
||||
import a
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
13
pyscript.core/tests/manual/config.html
Normal file
13
pyscript.core/tests/manual/config.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PyScript Next Plugin</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<py-config>
|
||||
files = [
|
||||
</py-config>
|
||||
</head>
|
||||
</html>
|
||||
36
pyscript.core/tests/manual/create-element.html
Normal file
36
pyscript.core/tests/manual/create-element.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<script type="module">
|
||||
customElements.whenDefined('py-script').then(PyScript => {
|
||||
const textContent = `
|
||||
from pyscript import display
|
||||
|
||||
display("Hello World")
|
||||
`;
|
||||
|
||||
document.body.append(
|
||||
// test <script type="py">
|
||||
Object.assign(
|
||||
document.createElement('script'),
|
||||
{ type: "py", textContent }
|
||||
),
|
||||
|
||||
// test <py-script>
|
||||
Object.assign(
|
||||
document.createElement('py-script'),
|
||||
{ textContent }
|
||||
),
|
||||
|
||||
// test PyScript class
|
||||
Object.assign(
|
||||
new PyScript(),
|
||||
{ textContent }
|
||||
)
|
||||
);
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
31
pyscript.core/tests/manual/dialog.html
Normal file
31
pyscript.core/tests/manual/dialog.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Next</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<script type="module">
|
||||
const loader = document.querySelector('#loader');
|
||||
loader.showModal();
|
||||
addEventListener(
|
||||
'py:all-done',
|
||||
() => {
|
||||
loader.close();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
</script>
|
||||
<script type="py">
|
||||
from pyscript import document
|
||||
|
||||
document.body.textContent = "PyScript Ready";
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<dialog id="loader">
|
||||
Loading PyScript ...
|
||||
</dialog>
|
||||
</body>
|
||||
</html>
|
||||
30
pyscript.core/tests/manual/display.html
Normal file
30
pyscript.core/tests/manual/display.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Next</title>
|
||||
<script>
|
||||
addEventListener("py:all-done", ({ type }) => console.log(type));
|
||||
</script>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py" worker async>
|
||||
from pyscript import display
|
||||
display('hello 1')
|
||||
|
||||
import js
|
||||
import time
|
||||
js.console.log('sleeping...')
|
||||
time.sleep(2)
|
||||
js.console.log('...done')
|
||||
</script>
|
||||
<p>hello 2</p>
|
||||
<script type="py" worker async>
|
||||
from pyscript import display
|
||||
display('hello 3')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
23
pyscript.core/tests/manual/error.html
Normal file
23
pyscript.core/tests/manual/error.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PyScript Next Plugin</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<script type="py">
|
||||
print(1, 2, 3)
|
||||
first()
|
||||
</script>
|
||||
<py-script>
|
||||
print(4, 5, 6)
|
||||
second()
|
||||
</py-script>
|
||||
<py-script src="whatever.py">
|
||||
print(4, 5, 6)
|
||||
second()
|
||||
</py-script>
|
||||
<py-script src="main.py" worker="worker.py"></py-script>
|
||||
</head>
|
||||
</html>
|
||||
35
pyscript.core/tests/manual/html-decode.html
Normal file
35
pyscript.core/tests/manual/html-decode.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<body>
|
||||
<py-script>import js; js.console.log(1<2, 1>2)</py-script>
|
||||
<py-script>import js; js.console.log("<div></div>")</py-script>
|
||||
<script type="py">
|
||||
import js
|
||||
js.console.log("A", 1<2, 1>2)
|
||||
js.console.log("B <div></div>")
|
||||
</script>
|
||||
<py-script>
|
||||
import js
|
||||
js.console.log("C", 1<2, 1>2)
|
||||
js.console.log("D <div></div>")
|
||||
</py-script>
|
||||
<py-script worker>import js; js.console.log(1<2, 1>2)</py-script>
|
||||
<py-script worker>import js; js.console.log("<div></div>")</py-script>
|
||||
<script type="py" worker>
|
||||
import js
|
||||
js.console.log("A", 1<2, 1>2)
|
||||
js.console.log("B <div></div>")
|
||||
</script>
|
||||
<py-script worker>
|
||||
import js
|
||||
js.console.log("C", 1<2, 1>2)
|
||||
js.console.log("D <div></div>")
|
||||
</py-script>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
19
pyscript.core/tests/manual/index.html
Normal file
19
pyscript.core/tests/manual/index.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Next</title>
|
||||
<script>
|
||||
addEventListener("py:ready", console.log);
|
||||
</script>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py">
|
||||
from pyscript import display
|
||||
display("Hello", "PyScript Next", append=False)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
21
pyscript.core/tests/manual/input.html
Normal file
21
pyscript.core/tests/manual/input.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Next</title>
|
||||
<script>
|
||||
addEventListener("py:ready", console.log);
|
||||
</script>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<py-script>
|
||||
input("what's your name?")
|
||||
</py-script>
|
||||
<mpy-script>
|
||||
input("what's your name?")
|
||||
</mpy-script>
|
||||
</body>
|
||||
</html>
|
||||
20
pyscript.core/tests/manual/multi.html
Normal file
20
pyscript.core/tests/manual/multi.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy">
|
||||
from pyscript import document
|
||||
import sys
|
||||
document.body.append(sys.version)
|
||||
</script>
|
||||
<script type="py">
|
||||
from pyscript import document
|
||||
import sys
|
||||
document.body.append(sys.version)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
31
pyscript.core/tests/manual/multiple-editors.html
Normal file
31
pyscript.core/tests/manual/multiple-editors.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>PyScript Test</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py-editor">
|
||||
0
|
||||
</script>
|
||||
<script type="py-editor">
|
||||
1
|
||||
</script>
|
||||
<script type="py-editor">
|
||||
2
|
||||
</script>
|
||||
<script type="py-editor">
|
||||
3
|
||||
</script>
|
||||
<script type="py-editor">
|
||||
4
|
||||
</script>
|
||||
<script type="py-editor">
|
||||
5
|
||||
</script>
|
||||
<!-- more... -->
|
||||
</body>
|
||||
</html>
|
||||
23
pyscript.core/tests/manual/no-error.html
Normal file
23
pyscript.core/tests/manual/no-error.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PyScript Next No Plugin</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<py-config>plugins = ['!error']</py-config>
|
||||
<script type="py">
|
||||
print(1, 2, 3)
|
||||
first()
|
||||
</script>
|
||||
<py-script>
|
||||
print(4, 5, 6)
|
||||
second()
|
||||
</py-script>
|
||||
<py-script src="whatever.py">
|
||||
print(4, 5, 6)
|
||||
second()
|
||||
</py-script>
|
||||
</head>
|
||||
</html>
|
||||
33
pyscript.core/tests/manual/py-editor.html
Normal file
33
pyscript.core/tests/manual/py-editor.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyTerminal</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py-editor">
|
||||
import sys
|
||||
print(sys.version)
|
||||
</script>
|
||||
<script type="mpy-editor">
|
||||
import sys
|
||||
print(sys.version)
|
||||
a = 42
|
||||
print(a)
|
||||
</script>
|
||||
<script type="mpy-editor" env="shared">
|
||||
if not 'a' in globals():
|
||||
a = 1
|
||||
else:
|
||||
a += 1
|
||||
print(a)
|
||||
</script>
|
||||
<script type="mpy-editor" env="shared">
|
||||
# doubled a
|
||||
print(a * 2)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
27
pyscript.core/tests/manual/py_modules.html
Normal file
27
pyscript.core/tests/manual/py_modules.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py" async>
|
||||
from pyscript import py_import, js_import, window
|
||||
|
||||
window.console.time("first")
|
||||
matplotlib, regex, = await py_import("matplotlib", "regex")
|
||||
window.console.timeEnd("first")
|
||||
|
||||
window.console.time("second")
|
||||
matplotlib, regex, = await py_import("matplotlib", "regex")
|
||||
window.console.timeEnd("second")
|
||||
|
||||
print(matplotlib, regex)
|
||||
|
||||
escaper, = await js_import("https://esm.run/html-escaper")
|
||||
window.console.log(escaper)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
20
pyscript.core/tests/manual/split-config.html
Normal file
20
pyscript.core/tests/manual/split-config.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Config</title>
|
||||
<script type="module">
|
||||
import { config } from "../../dist/core.js";
|
||||
console.log(config.mpy);
|
||||
</script>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<mpy-config>
|
||||
[[fetch]]
|
||||
files = ["./a.py"]
|
||||
</mpy-config>
|
||||
<script type="mpy">
|
||||
import a
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
37
pyscript.core/tests/manual/target.html
Normal file
37
pyscript.core/tests/manual/target.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@pyscript/core</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<py-script id="first">
|
||||
import pyscript
|
||||
from pyscript import display
|
||||
display("Hello", append=True) # Appears in a DIV that is a child of this py-script tag
|
||||
pyscript.display("same", append=True) # Appears in another DIV that is a child of this py-script tag
|
||||
</py-script>
|
||||
<py-script id="second">
|
||||
# Appears in a DIV that is a child of this py-script tag, no need to re-import
|
||||
display("World", append=True)
|
||||
</py-script>
|
||||
<py-script id="third">
|
||||
# Appears in a DIV that is a child of this py-script tag
|
||||
# Re-importing has no effect in the essential behavior
|
||||
from pyscript import display
|
||||
display("A part", append=True)
|
||||
</py-script>
|
||||
<py-script id="fourth">
|
||||
# Use the 'target' element to specify the ID of an element in the DOM to write the content to
|
||||
display("!", target="first", append=True)
|
||||
</py-script>
|
||||
<py-script worker>
|
||||
# Appears in a DIV that is a child of this py-script tag, even with the code running in a worker
|
||||
from pyscript import display
|
||||
display("worker", append=True)
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
16
pyscript.core/tests/manual/test_display_HTML.html
Normal file
16
pyscript.core/tests/manual/test_display_HTML.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Next: Display HTML</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<py-script>
|
||||
from pyscript import display, HTML
|
||||
display(HTML('<p><label style="color: red;">hello</label> world</p>'))
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
24
pyscript.core/tests/manual/test_when.html
Normal file
24
pyscript.core/tests/manual/test_when.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Next: When Decorator</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Click for a hi!</p>
|
||||
|
||||
<py-script>
|
||||
from pyscript import window, when
|
||||
@when("click", selector="#say-hi")
|
||||
|
||||
def say_hi(event):
|
||||
window.alert("Hi! 🤗")
|
||||
</py-script>
|
||||
|
||||
<button id="say-hi">Click Me</button>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
39
pyscript.core/tests/manual/worker.html
Normal file
39
pyscript.core/tests/manual/worker.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyScript Next</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
|
||||
<!-- the PyWorker approach -->
|
||||
<script type="module">
|
||||
import { PyWorker, whenDefined } from '../../dist/core.js';
|
||||
whenDefined('py').then(() => {
|
||||
PyWorker('./worker.py', {config: {fetch: [{files: ['./a.py']}]}});
|
||||
});
|
||||
// the type is overwritten as "pyodide" in PyScript as the module
|
||||
// lives in that env too
|
||||
</script>
|
||||
|
||||
<!-- the worker attribute -->
|
||||
<script type="py" src="./worker.py" config="./config.json" worker></script>
|
||||
|
||||
<!-- this is only to test the non-blocking behavior -->
|
||||
<script>
|
||||
addEventListener('DOMContentLoaded', () => {
|
||||
const div = document.body.appendChild(
|
||||
document.createElement('div')
|
||||
);
|
||||
(function monitor() {
|
||||
const date = new Date;
|
||||
div.textContent = `${date.getSeconds()}.${date.getMilliseconds()}`;
|
||||
requestAnimationFrame(monitor);
|
||||
}());
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="test"></div>
|
||||
</body>
|
||||
</html>
|
||||
13
pyscript.core/tests/manual/worker.py
Normal file
13
pyscript.core/tests/manual/worker.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import js
|
||||
|
||||
js.document.body.append("document patch ")
|
||||
|
||||
import a
|
||||
from pyscript import RUNNING_IN_WORKER, display, sync
|
||||
|
||||
display("Hello World", target="test", append=True)
|
||||
|
||||
print(RUNNING_IN_WORKER)
|
||||
print("sleeping")
|
||||
sync.sleep(1)
|
||||
print("awake")
|
||||
23
pyscript.core/tests/no_sab/index.html
Normal file
23
pyscript.core/tests/no_sab/index.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module">
|
||||
import { PyWorker } from '../../dist/core.js';
|
||||
const { sync } = await PyWorker(
|
||||
'./worker.py',
|
||||
{
|
||||
config: {
|
||||
sync_main_only: true
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
document.documentElement.classList.add(
|
||||
await sync.get_class()
|
||||
);
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
3
pyscript.core/tests/no_sab/worker.py
Normal file
3
pyscript.core/tests/no_sab/worker.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from pyscript import sync
|
||||
|
||||
sync.get_class = lambda: "ok"
|
||||
18
pyscript.core/tests/piratical/index.html
Normal file
18
pyscript.core/tests/piratical/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Arrr - Piratical PyScript</title>
|
||||
<link rel="stylesheet" href="../../dist/core.css" />
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Arrr</h1>
|
||||
<p>Translate English into Pirate speak...</p>
|
||||
<input type="text" id="english" placeholder="Type English here..." />
|
||||
<button py-click="translate_english">Translate</button>
|
||||
<div id="output"></div>
|
||||
<script type="py" src="./piratical.py" config="./piratical.toml"></script>
|
||||
</body>
|
||||
</html>
|
||||
9
pyscript.core/tests/piratical/piratical.py
Normal file
9
pyscript.core/tests/piratical/piratical.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import arrr
|
||||
from js import document
|
||||
|
||||
|
||||
def translate_english(event):
|
||||
input_text = document.querySelector("#english")
|
||||
english = input_text.value
|
||||
output_div = document.querySelector("#output")
|
||||
output_div.innerText = arrr.translate(english)
|
||||
1
pyscript.core/tests/piratical/piratical.toml
Normal file
1
pyscript.core/tests/piratical/piratical.toml
Normal file
@@ -0,0 +1 @@
|
||||
packages = ["arrr"]
|
||||
2
pyscript.core/tests/py-editor/config.toml
Normal file
2
pyscript.core/tests/py-editor/config.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[js_modules.worker]
|
||||
"https://cdn.jsdelivr.net/npm/html-escaper/+esm" = "html_escaper"
|
||||
55
pyscript.core/tests/py-editor/index.html
Normal file
55
pyscript.core/tests/py-editor/index.html
Normal file
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module">
|
||||
import '../../dist/core.js';
|
||||
|
||||
addEventListener('mpy-editor', async ({ target }) => {
|
||||
if (target.hasAttribute('setup')) {
|
||||
await target.process([
|
||||
'from pyscript import document',
|
||||
// adds class="a-1" to the <html> element
|
||||
'document.documentElement.classList.add(f"a-{a}")',
|
||||
'from js import console',
|
||||
'console.log("Hello JS")',
|
||||
].join('\n'));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- a setup node with a config for an env -->
|
||||
<script type="mpy-editor" src="task1.py" config="./config.toml" env="task1" setup></script>
|
||||
<script type="mpy-editor" env="task1">
|
||||
from pyscript.js_modules.html_escaper import escape, unescape
|
||||
print(unescape(escape("<OK>")))
|
||||
a = 1
|
||||
</script>
|
||||
<!-- a share-nothing micropython editor -->
|
||||
<script type="mpy-editor" config='{"js_modules":{"worker":{"https://cdn.jsdelivr.net/npm/html-escaper/+esm":"html_escaper"}}}'>
|
||||
from pyscript.js_modules.html_escaper import escape, unescape
|
||||
print(unescape(escape("<OK>")))
|
||||
b = 2
|
||||
try:
|
||||
print(a)
|
||||
except:
|
||||
print("all good")
|
||||
</script>
|
||||
<!-- a config once micropython env -->
|
||||
<script type="mpy-editor" env="task2" config="./config.toml">
|
||||
from pyscript.js_modules.html_escaper import escape, unescape
|
||||
print(unescape(escape("<OK>")))
|
||||
c = 3
|
||||
try:
|
||||
print(b)
|
||||
except:
|
||||
print("all good")
|
||||
</script>
|
||||
<script type="mpy-editor" env="task2">
|
||||
print(c)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
17
pyscript.core/tests/py-editor/issue-2056.html
Normal file
17
pyscript.core/tests/py-editor/issue-2056.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py-editor">
|
||||
print("Hello!")
|
||||
</script>
|
||||
<script type="mpy-editor">
|
||||
print("Hello!")
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
16
pyscript.core/tests/py-editor/service-worker.html
Normal file
16
pyscript.core/tests/py-editor/service-worker.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy-editor" service-worker="./sw.js">
|
||||
from pyscript import document
|
||||
|
||||
document.body.append("OK")
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1
pyscript.core/tests/py-editor/sw.js
Normal file
1
pyscript.core/tests/py-editor/sw.js
Normal file
@@ -0,0 +1 @@
|
||||
const{isArray:e}=Array,t=new Map,s=e=>{e.stopImmediatePropagation(),e.preventDefault()};var n=Object.freeze({__proto__:null,activate:e=>e.waitUntil(clients.claim()),fetch:e=>{const{request:n}=e;"POST"===n.method&&n.url===`${location.href}?sabayon`&&(s(e),e.respondWith(n.json().then((async e=>{const{promise:s,resolve:o}=Promise.withResolvers(),a=e.join(",");t.set(a,o);for(const t of await clients.matchAll())t.postMessage(e);return s.then((e=>new Response(`[${e.join(",")}]`,n.headers)))}))))},install:()=>skipWaiting(),message:n=>{const{data:o}=n;if(e(o)&&4===o.length){const[e,a,i,r]=o,l=[e,a,i].join(",");t.has(l)&&(s(n),t.get(l)(r),t.delete(l))}}});for(const e in n)addEventListener(e,n[e]);
|
||||
5
pyscript.core/tests/py-editor/task1.py
Normal file
5
pyscript.core/tests/py-editor/task1.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from pyscript import window
|
||||
|
||||
window.console.log("OK")
|
||||
|
||||
a = 1
|
||||
18
pyscript.core/tests/py-terminals/index.html
Normal file
18
pyscript.core/tests/py-terminals/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="./no-repl.html">Prompt: NO REPL</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="./repl.html">Prompt: REPL</a>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
20
pyscript.core/tests/py-terminals/no-repl.html
Normal file
20
pyscript.core/tests/py-terminals/no-repl.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyTerminal Prompt: NO REPL</title>
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<style>.xterm { padding: .5rem; }</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy" worker terminal>
|
||||
prompt = input("Say something: ")
|
||||
print("You said, ", prompt)
|
||||
</script>
|
||||
<script type="py" worker terminal>
|
||||
prompt = input("Say something: ")
|
||||
print("You said, ", prompt)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
28
pyscript.core/tests/py-terminals/repl.html
Normal file
28
pyscript.core/tests/py-terminals/repl.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PyTerminal Prompt: REPL</title>
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
<style>.xterm { padding: .5rem; }</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy" worker terminal>
|
||||
import code
|
||||
code.interact()
|
||||
|
||||
prompt = input("Say something: ")
|
||||
print("You said, ", prompt)
|
||||
</script>
|
||||
<script type="py" worker terminal>
|
||||
import code
|
||||
code.interact()
|
||||
|
||||
# Pyodide won't execute this ... ever
|
||||
# this should be tested manually
|
||||
prompt = input("Say something: ")
|
||||
print("You said, ", prompt)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
130
pyscript.core/tests/pyscript_dom/index.html
Normal file
130
pyscript.core/tests/pyscript_dom/index.html
Normal file
@@ -0,0 +1,130 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>PyDom Test Suite</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
|
||||
<style>
|
||||
@import url("https://fonts.googleapis.com/css?family=Roboto:100,400");
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
*:before, *:after {
|
||||
box-sizing: inherit;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace;
|
||||
font-size: 14px; font-style: normal; font-variant: normal; font-weight: 400; line-height: 20px;
|
||||
}
|
||||
|
||||
h1 { font-size: 24px; font-weight: 700; line-height: 26.4px; }
|
||||
h2 { font-size: 14px; font-weight: 700; line-height: 15.4px; }
|
||||
|
||||
#tests-terminal{
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py" src="run_tests.py" config="tests.toml"></script>
|
||||
|
||||
<h1>pyscript.dom Tests</h1>
|
||||
<p>You can pass test parameters to this test suite by passing them as query params on the url.
|
||||
For instance, to pass "-v -s --pdb" to pytest, you would use the following url:
|
||||
<label style="color: blue">?-v&-s&--pdb</label>
|
||||
</p>
|
||||
<div id="tests-terminal"></div>
|
||||
|
||||
<template id="test_card_with_element_template">
|
||||
<p>This is a test. {foo}</p>
|
||||
</template>
|
||||
|
||||
<div id="test_id_selector" style="visibility: hidden;">You found test_id_selector</div>
|
||||
<div id="test_class_selector" class="a-test-class" style="visibility: hidden;">You found test_class_selector</div>
|
||||
<div id="test_selector_w_children" class="a-test-class" style="visibility: hidden;">
|
||||
<div id="test_selector_w_children_child_1" class="a-test-class" style="visibility: hidden;">Child 1</div>
|
||||
<div id="test_selector_w_children_child_2" style="visibility: hidden;">Child 2</div>
|
||||
</div>
|
||||
|
||||
<div id="div-no-classes"></div>
|
||||
|
||||
<div style="visibility: hidden;">
|
||||
<h2>Test Read and Write</h2>
|
||||
<div id="test_rr_div">Content test_rr_div</div>
|
||||
<h3 id="test_rr_h3">Content test_rr_h3</h3>
|
||||
|
||||
<div id="multi-elem-div" class="multi-elems">Content multi-elem-div</div>
|
||||
<p id="multi-elem-p" class="multi-elems">Content multi-elem-p</p>
|
||||
<h2 id="multi-elem-h2" class="multi-elems">Content multi-elem-h2</h2>
|
||||
|
||||
<form>
|
||||
<input id="test_rr_input_text" type="text" value="Content test_rr_input_text">
|
||||
<input id="test_rr_input_button" type="button" value="Content test_rr_input_button">
|
||||
<input id="test_rr_input_email" type="email" value="Content test_rr_input_email">
|
||||
<input id="test_rr_input_password" type="password" value="Content test_rr_input_password">
|
||||
</form>
|
||||
|
||||
<select id="test_select_element"></select>
|
||||
<select id="test_select_element_w_options">
|
||||
<option value="1">Option 1</option>
|
||||
<option value="2" selected="selected">Option 2</option>
|
||||
</select>
|
||||
<select id="test_select_element_to_clear">
|
||||
<option value="1">Option 1</option>
|
||||
<option value="2">Option 2</option>
|
||||
<option value="4">Option 4</option>
|
||||
</select>
|
||||
|
||||
<select id="test_select_element_to_remove">
|
||||
<option value="1">Option 1</option>
|
||||
<option value="2">Option 2</option>
|
||||
<option value="3">Option 3</option>
|
||||
<option value="4">Option 4</option>
|
||||
</select>
|
||||
|
||||
<div id="element-creation-test"></div>
|
||||
|
||||
<button id="a-test-button">I'm a button to be clicked</button>
|
||||
<button>I'm another button you can click</button>
|
||||
<button id="a-third-button">2 is better than 3 :)</button>
|
||||
|
||||
<div id="element-append-tests"></div>
|
||||
<p class="collection"></p>
|
||||
<div class="collection"></div>
|
||||
<h3 class="collection"></h3>
|
||||
|
||||
<div id="element_attribute_tests"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<script defer>
|
||||
console.log("remapping console.log")
|
||||
const terminalDiv = document.getElementById("tests-terminal");
|
||||
const log = console.log.bind(console)
|
||||
let testsStarted = false;
|
||||
console.log = (...args) => {
|
||||
let txt = args.join(" ");
|
||||
let token = "<br>";
|
||||
if (txt.endsWith("FAILED"))
|
||||
token = " ❌<br>";
|
||||
else if (txt.endsWith("PASSED"))
|
||||
token = " ✅<br>";
|
||||
if (testsStarted)
|
||||
terminalDiv.innerHTML += args.join(" ") + token;
|
||||
|
||||
log(...args)
|
||||
|
||||
// if we got the flag that tests are starting, then we can start logging
|
||||
if (args.join(" ") == "tests starting")
|
||||
testsStarted = true;
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
7
pyscript.core/tests/pyscript_dom/run_tests.py
Normal file
7
pyscript.core/tests/pyscript_dom/run_tests.py
Normal file
@@ -0,0 +1,7 @@
|
||||
print("tests starting")
|
||||
import pytest
|
||||
from pyscript import window
|
||||
|
||||
args = window.location.search.replace("?", "").split("&")
|
||||
|
||||
pytest.main(args)
|
||||
8
pyscript.core/tests/pyscript_dom/tests.toml
Normal file
8
pyscript.core/tests/pyscript_dom/tests.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
packages = [
|
||||
"pytest"
|
||||
]
|
||||
|
||||
[[fetch]]
|
||||
from = "tests/"
|
||||
files = ["__init__.py", "conftest.py", "test_dom.py"]
|
||||
to_folder = "tests"
|
||||
0
pyscript.core/tests/pyscript_dom/tests/__init__.py
Normal file
0
pyscript.core/tests/pyscript_dom/tests/__init__.py
Normal file
15
pyscript.core/tests/pyscript_dom/tests/conftest.py
Normal file
15
pyscript.core/tests/pyscript_dom/tests/conftest.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import pytest
|
||||
from js import document, localStorage
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def before_tests():
|
||||
"""
|
||||
Ensure browser storage is always reset to empty. Remove the app
|
||||
placeholder. Reset the page title.
|
||||
"""
|
||||
localStorage.clear()
|
||||
# app_placeholder = document.querySelector("pyper-app")
|
||||
# if app_placeholder:
|
||||
# app_placeholder.remove()
|
||||
document.querySelector("title").innerText = "Web API PyTest Suite"
|
||||
460
pyscript.core/tests/pyscript_dom/tests/test_dom.py
Normal file
460
pyscript.core/tests/pyscript_dom/tests/test_dom.py
Normal file
@@ -0,0 +1,460 @@
|
||||
from pyscript import document, when
|
||||
from pyscript.web import Element, ElementCollection, div, p, page
|
||||
|
||||
|
||||
class TestDocument:
|
||||
def test__element(self):
|
||||
assert page.body._dom_element == document.body
|
||||
assert page.head._dom_element == document.head
|
||||
|
||||
|
||||
def test_getitem_by_id():
|
||||
# GIVEN an existing element on the page with a known text content
|
||||
id_ = "test_id_selector"
|
||||
txt = "You found test_id_selector"
|
||||
selector = f"#{id_}"
|
||||
# EXPECT the element to be found by id
|
||||
result = page.find(selector)
|
||||
div = result[0]
|
||||
# EXPECT the element text value to match what we expect and what
|
||||
# the JS document.querySelector API would return
|
||||
assert document.querySelector(selector).innerHTML == div.innerHTML == txt
|
||||
# EXPECT the results to be of the right types
|
||||
assert isinstance(div, Element)
|
||||
assert isinstance(result, ElementCollection)
|
||||
|
||||
|
||||
def test_getitem_by_class():
|
||||
ids = [
|
||||
"test_class_selector",
|
||||
"test_selector_w_children",
|
||||
"test_selector_w_children_child_1",
|
||||
]
|
||||
expected_class = "a-test-class"
|
||||
result = page.find(f".{expected_class}")
|
||||
|
||||
# EXPECT to find exact number of elements with the class in the page (== 3)
|
||||
assert len(result) == 3
|
||||
|
||||
# EXPECT that all element ids are in the expected list
|
||||
assert [el.id for el in result] == ids
|
||||
|
||||
|
||||
def test_read_n_write_collection_elements():
|
||||
elements = page.find(".multi-elems")
|
||||
|
||||
for element in elements:
|
||||
assert element.innerHTML == f"Content {element.id.replace('#', '')}"
|
||||
|
||||
new_content = "New Content"
|
||||
elements.innerHTML = new_content
|
||||
for element in elements:
|
||||
assert element.innerHTML == new_content
|
||||
|
||||
|
||||
class TestElement:
|
||||
def test_query(self):
|
||||
# GIVEN an existing element on the page, with at least 1 child element
|
||||
id_ = "test_selector_w_children"
|
||||
parent_div = page.find(f"#{id_}")[0]
|
||||
|
||||
# EXPECT it to be able to query for the first child element
|
||||
div = parent_div.find("div")[0]
|
||||
|
||||
# EXPECT the new element to be associated with the parent
|
||||
assert div.parent == parent_div
|
||||
# EXPECT the new element to be an Element
|
||||
assert isinstance(div, Element)
|
||||
# EXPECT the div attributes to be == to how they are configured in the page
|
||||
assert div.innerHTML == "Child 1"
|
||||
assert div.id == "test_selector_w_children_child_1"
|
||||
|
||||
def test_equality(self):
|
||||
# GIVEN 2 different Elements pointing to the same underlying element
|
||||
id_ = "test_id_selector"
|
||||
selector = f"#{id_}"
|
||||
div = page.find(selector)[0]
|
||||
div2 = page.find(selector)[0]
|
||||
|
||||
# EXPECT them to be equal
|
||||
assert div == div2
|
||||
# EXPECT them to be different objects
|
||||
assert div is not div2
|
||||
|
||||
# EXPECT their value to always be equal
|
||||
assert div.innerHTML == div2.innerHTML
|
||||
div.innerHTML = "some value"
|
||||
|
||||
assert div.innerHTML == div2.innerHTML == "some value"
|
||||
|
||||
def test_append_element(self):
|
||||
id_ = "element-append-tests"
|
||||
div = page.find(f"#{id_}")[0]
|
||||
len_children_before = len(div.children)
|
||||
new_el = p("new element")
|
||||
div.append(new_el)
|
||||
assert len(div.children) == len_children_before + 1
|
||||
assert div.children[-1] == new_el
|
||||
|
||||
def test_append_dom_element_element(self):
|
||||
id_ = "element-append-tests"
|
||||
div = page.find(f"#{id_}")[0]
|
||||
len_children_before = len(div.children)
|
||||
new_el = p("new element")
|
||||
div.append(new_el._dom_element)
|
||||
assert len(div.children) == len_children_before + 1
|
||||
assert div.children[-1] == new_el
|
||||
|
||||
def test_append_collection(self):
|
||||
id_ = "element-append-tests"
|
||||
div = page.find(f"#{id_}")[0]
|
||||
len_children_before = len(div.children)
|
||||
collection = page.find(".collection")
|
||||
div.append(collection)
|
||||
assert len(div.children) == len_children_before + len(collection)
|
||||
|
||||
for i in range(len(collection)):
|
||||
assert div.children[-1 - i] == collection[-1 - i]
|
||||
|
||||
def test_read_classes(self):
|
||||
id_ = "test_class_selector"
|
||||
expected_class = "a-test-class"
|
||||
div = page.find(f"#{id_}")[0]
|
||||
assert div.classes == [expected_class]
|
||||
|
||||
def test_add_remove_class(self):
|
||||
id_ = "div-no-classes"
|
||||
classname = "tester-class"
|
||||
div = page.find(f"#{id_}")[0]
|
||||
assert not div.classes
|
||||
div.classes.add(classname)
|
||||
same_div = page.find(f"#{id_}")[0]
|
||||
assert div.classes == [classname] == same_div.classes
|
||||
div.classes.remove(classname)
|
||||
assert div.classes == [] == same_div.classes
|
||||
|
||||
def test_when_decorator(self):
|
||||
called = False
|
||||
|
||||
just_a_button = page.find("#a-test-button")[0]
|
||||
|
||||
@when("click", just_a_button)
|
||||
def on_click(event):
|
||||
nonlocal called
|
||||
called = True
|
||||
|
||||
# Now let's simulate a click on the button (using the low level JS API)
|
||||
# so we don't risk dom getting in the way
|
||||
assert not called
|
||||
just_a_button._dom_element.click()
|
||||
|
||||
assert called
|
||||
|
||||
def test_inner_html_attribute(self):
|
||||
# GIVEN an existing element on the page with a known empty text content
|
||||
div = page.find("#element_attribute_tests")[0]
|
||||
|
||||
# WHEN we set the html attribute
|
||||
div.innerHTML = "<b>New Content</b>"
|
||||
|
||||
# EXPECT the element html and underlying JS Element innerHTML property
|
||||
# to match what we expect and what
|
||||
assert div.innerHTML == div._dom_element.innerHTML == "<b>New Content</b>"
|
||||
assert div.textContent == div._dom_element.textContent == "New Content"
|
||||
|
||||
def test_text_attribute(self):
|
||||
# GIVEN an existing element on the page with a known empty text content
|
||||
div = page.find("#element_attribute_tests")[0]
|
||||
|
||||
# WHEN we set the html attribute
|
||||
div.textContent = "<b>New Content</b>"
|
||||
|
||||
# EXPECT the element html and underlying JS Element innerHTML property
|
||||
# to match what we expect and what
|
||||
assert (
|
||||
div.innerHTML
|
||||
== div._dom_element.innerHTML
|
||||
== "<b>New Content</b>"
|
||||
)
|
||||
assert div.textContent == div._dom_element.textContent == "<b>New Content</b>"
|
||||
|
||||
|
||||
class TestCollection:
|
||||
def test_iter_eq_children(self):
|
||||
elements = page.find(".multi-elems")
|
||||
assert [el for el in elements] == [el for el in elements.elements]
|
||||
assert len(elements) == 3
|
||||
|
||||
def test_slices(self):
|
||||
elements = page.find(".multi-elems")
|
||||
assert elements[0]
|
||||
_slice = elements[:2]
|
||||
assert len(_slice) == 2
|
||||
for i, el in enumerate(_slice):
|
||||
assert el == elements[i]
|
||||
assert elements[:] == elements
|
||||
|
||||
def test_style_rule(self):
|
||||
selector = ".multi-elems"
|
||||
elements = page.find(selector)
|
||||
for el in elements:
|
||||
assert el.style["background-color"] != "red"
|
||||
|
||||
elements.style["background-color"] = "red"
|
||||
|
||||
for i, el in enumerate(page.find(selector)):
|
||||
assert elements[i].style["background-color"] == "red"
|
||||
assert el.style["background-color"] == "red"
|
||||
|
||||
elements.style.remove("background-color")
|
||||
|
||||
for i, el in enumerate(page.find(selector)):
|
||||
assert el.style["background-color"] != "red"
|
||||
assert elements[i].style["background-color"] != "red"
|
||||
|
||||
def test_when_decorator(self):
|
||||
called = False
|
||||
|
||||
buttons_collection = page.find("button")
|
||||
|
||||
@when("click", buttons_collection)
|
||||
def on_click(event):
|
||||
nonlocal called
|
||||
called = True
|
||||
|
||||
# Now let's simulate a click on the button (using the low level JS API)
|
||||
# so we don't risk dom getting in the way
|
||||
assert not called
|
||||
for button in buttons_collection:
|
||||
button._dom_element.click()
|
||||
assert called
|
||||
called = False
|
||||
|
||||
|
||||
class TestCreation:
|
||||
def test_create_document_element(self):
|
||||
# TODO: This test should probably be removed since it's testing the elements
|
||||
# module.
|
||||
new_el = div("new element")
|
||||
new_el.id = "new_el_id"
|
||||
assert isinstance(new_el, Element)
|
||||
assert new_el._dom_element.tagName == "DIV"
|
||||
# EXPECT the new element to be associated with the document
|
||||
assert new_el.parent is None
|
||||
page.body.append(new_el)
|
||||
|
||||
assert page.find("#new_el_id")[0].parent == page.body
|
||||
|
||||
def test_create_element_child(self):
|
||||
selector = "#element-creation-test"
|
||||
parent_div = page.find(selector)[0]
|
||||
|
||||
# Creating an element from another element automatically creates that element
|
||||
# as a child of the original element
|
||||
new_el = p("a div", classes=["code-description"], innerHTML="Ciao PyScripters!")
|
||||
parent_div.append(new_el)
|
||||
|
||||
assert isinstance(new_el, Element)
|
||||
assert new_el._dom_element.tagName == "P"
|
||||
|
||||
# EXPECT the new element to be associated with the document
|
||||
assert new_el.parent == parent_div
|
||||
assert page.find(selector)[0].children[0] == new_el
|
||||
|
||||
|
||||
class TestInput:
|
||||
input_ids = [
|
||||
"test_rr_input_text",
|
||||
"test_rr_input_button",
|
||||
"test_rr_input_email",
|
||||
"test_rr_input_password",
|
||||
]
|
||||
|
||||
def test_value(self):
|
||||
for id_ in self.input_ids:
|
||||
expected_type = id_.split("_")[-1]
|
||||
result = page.find(f"#{id_}")
|
||||
input_el = result[0]
|
||||
assert input_el._dom_element.type == expected_type
|
||||
assert input_el.value == f"Content {id_}" == input_el._dom_element.value
|
||||
|
||||
# Check that we can set the value
|
||||
new_value = f"New Value {expected_type}"
|
||||
input_el.value = new_value
|
||||
assert input_el.value == new_value
|
||||
|
||||
# Check that we can set the value back to the original using
|
||||
# the collection
|
||||
new_value = f"Content {id_}"
|
||||
result.value = new_value
|
||||
assert input_el.value == new_value
|
||||
|
||||
def test_set_value_collection(self):
|
||||
for id_ in self.input_ids:
|
||||
input_el = page.find(f"#{id_}")
|
||||
|
||||
assert input_el.value[0] == f"Content {id_}" == input_el[0].value
|
||||
|
||||
new_value = f"New Value {id_}"
|
||||
input_el.value = new_value
|
||||
assert input_el.value[0] == new_value == input_el[0].value
|
||||
|
||||
# TODO: We only attach attributes to the classes that have them now which means we
|
||||
# would have to have some other way to help users if using attributes that aren't
|
||||
# actually on the class. Maybe a job for __setattr__?
|
||||
#
|
||||
# def test_element_without_value(self):
|
||||
# result = page.find(f"#tests-terminal"][0]
|
||||
# with pytest.raises(AttributeError):
|
||||
# result.value = "some value"
|
||||
#
|
||||
# def test_element_without_value_via_collection(self):
|
||||
# result = page.find(f"#tests-terminal"]
|
||||
# with pytest.raises(AttributeError):
|
||||
# result.value = "some value"
|
||||
|
||||
|
||||
class TestSelect:
|
||||
def test_select_options_iter(self):
|
||||
select = page.find(f"#test_select_element_w_options")[0]
|
||||
|
||||
for i, option in enumerate(select.options, 1):
|
||||
assert option.value == f"{i}"
|
||||
assert option.innerHTML == f"Option {i}"
|
||||
|
||||
def test_select_options_len(self):
|
||||
select = page.find(f"#test_select_element_w_options")[0]
|
||||
assert len(select.options) == 2
|
||||
|
||||
def test_select_options_clear(self):
|
||||
select = page.find(f"#test_select_element_to_clear")[0]
|
||||
assert len(select.options) == 3
|
||||
|
||||
select.options.clear()
|
||||
|
||||
assert len(select.options) == 0
|
||||
|
||||
def test_select_element_add(self):
|
||||
# GIVEN the existing select element with no options
|
||||
select = page.find(f"#test_select_element")[0]
|
||||
|
||||
# EXPECT the select element to have no options
|
||||
assert len(select.options) == 0
|
||||
|
||||
# WHEN we add an option
|
||||
select.options.add(value="1", html="Option 1")
|
||||
|
||||
# EXPECT the select element to have 1 option matching the attributes
|
||||
# we passed in
|
||||
assert len(select.options) == 1
|
||||
assert select.options[0].value == "1"
|
||||
assert select.options[0].innerHTML == "Option 1"
|
||||
|
||||
# WHEN we add another option (blank this time)
|
||||
select.options.add("")
|
||||
|
||||
# EXPECT the select element to have 2 options
|
||||
assert len(select.options) == 2
|
||||
|
||||
# EXPECT the last option to have an empty value and html
|
||||
assert select.options[1].value == ""
|
||||
assert select.options[1].innerHTML == ""
|
||||
|
||||
# WHEN we add another option (this time adding it in between the other 2
|
||||
# options by using an integer index)
|
||||
select.options.add(value="2", html="Option 2", before=1)
|
||||
|
||||
# EXPECT the select element to have 3 options
|
||||
assert len(select.options) == 3
|
||||
|
||||
# EXPECT the middle option to have the value and html we passed in
|
||||
assert select.options[0].value == "1"
|
||||
assert select.options[0].innerHTML == "Option 1"
|
||||
assert select.options[1].value == "2"
|
||||
assert select.options[1].innerHTML == "Option 2"
|
||||
assert select.options[2].value == ""
|
||||
assert select.options[2].innerHTML == ""
|
||||
|
||||
# WHEN we add another option (this time adding it in between the other 2
|
||||
# options but using the option itself)
|
||||
select.options.add(
|
||||
value="3", html="Option 3", before=select.options[2], selected=True
|
||||
)
|
||||
|
||||
# EXPECT the select element to have 3 options
|
||||
assert len(select.options) == 4
|
||||
|
||||
# EXPECT the middle option to have the value and html we passed in
|
||||
assert select.options[0].value == "1"
|
||||
assert select.options[0].innerHTML == "Option 1"
|
||||
assert (
|
||||
select.options[0].selected
|
||||
== select.options[0]._dom_element.selected
|
||||
== False
|
||||
)
|
||||
assert select.options[1].value == "2"
|
||||
assert select.options[1].innerHTML == "Option 2"
|
||||
assert select.options[2].value == "3"
|
||||
assert select.options[2].innerHTML == "Option 3"
|
||||
assert (
|
||||
select.options[2].selected
|
||||
== select.options[2]._dom_element.selected
|
||||
== True
|
||||
)
|
||||
assert select.options[3].value == ""
|
||||
assert select.options[3].innerHTML == ""
|
||||
|
||||
# WHEN we add another option (this time adding it in between the other 2
|
||||
# options but using the JS element of the option itself)
|
||||
select.options.add(
|
||||
value="2a", html="Option 2a", before=select.options[2]._dom_element
|
||||
)
|
||||
|
||||
# EXPECT the select element to have 3 options
|
||||
assert len(select.options) == 5
|
||||
|
||||
# EXPECT the middle option to have the value and html we passed in
|
||||
assert select.options[0].value == "1"
|
||||
assert select.options[0].innerHTML == "Option 1"
|
||||
assert select.options[1].value == "2"
|
||||
assert select.options[1].innerHTML == "Option 2"
|
||||
assert select.options[2].value == "2a"
|
||||
assert select.options[2].innerHTML == "Option 2a"
|
||||
assert select.options[3].value == "3"
|
||||
assert select.options[3].innerHTML == "Option 3"
|
||||
assert select.options[4].value == ""
|
||||
assert select.options[4].innerHTML == ""
|
||||
|
||||
def test_select_options_remove(self):
|
||||
# GIVEN the existing select element with 3 options
|
||||
select = page.find(f"#test_select_element_to_remove")[0]
|
||||
|
||||
# EXPECT the select element to have 3 options
|
||||
assert len(select.options) == 4
|
||||
# EXPECT the options to have the values originally set
|
||||
assert select.options[0].value == "1"
|
||||
assert select.options[1].value == "2"
|
||||
assert select.options[2].value == "3"
|
||||
assert select.options[3].value == "4"
|
||||
|
||||
# WHEN we remove the second option (index starts at 0)
|
||||
select.options.remove(1)
|
||||
|
||||
# EXPECT the select element to have 2 options
|
||||
assert len(select.options) == 3
|
||||
# EXPECT the options to have the values originally set but the second
|
||||
assert select.options[0].value == "1"
|
||||
assert select.options[1].value == "3"
|
||||
assert select.options[2].value == "4"
|
||||
|
||||
def test_select_get_selected_option(self):
|
||||
# GIVEN the existing select element with one selected option
|
||||
select = page.find(f"#test_select_element_w_options")[0]
|
||||
|
||||
# WHEN we get the selected option
|
||||
selected_option = select.options.selected
|
||||
|
||||
# EXPECT the selected option to be correct
|
||||
assert selected_option.value == "2"
|
||||
assert selected_option.innerHTML == "Option 2"
|
||||
assert selected_option.selected == selected_option._dom_element.selected == True
|
||||
16
pyscript.core/tests/service-worker/index.html
Normal file
16
pyscript.core/tests/service-worker/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Service Worker</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy" service-worker="./sabayon.js" worker>
|
||||
from pyscript import document
|
||||
document.body.append('OK')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
28
pyscript.core/tests/service-worker/mini-coi.js
Normal file
28
pyscript.core/tests/service-worker/mini-coi.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */
|
||||
/*! mini-coi - Andrea Giammarchi and contributors, licensed under MIT */
|
||||
(({ document: d, navigator: { serviceWorker: s } }) => {
|
||||
if (d) {
|
||||
const { currentScript: c } = d;
|
||||
s.register(c.src, { scope: c.getAttribute('scope') || '.' }).then(r => {
|
||||
r.addEventListener('updatefound', () => location.reload());
|
||||
if (r.active && !s.controller) location.reload();
|
||||
});
|
||||
}
|
||||
else {
|
||||
addEventListener('install', () => skipWaiting());
|
||||
addEventListener('activate', e => e.waitUntil(clients.claim()));
|
||||
addEventListener('fetch', e => {
|
||||
const { request: r } = e;
|
||||
if (r.cache === 'only-if-cached' && r.mode !== 'same-origin') return;
|
||||
e.respondWith(fetch(r).then(r => {
|
||||
const { body, status, statusText } = r;
|
||||
if (!status || status > 399) return r;
|
||||
const h = new Headers(r.headers);
|
||||
h.set('Cross-Origin-Opener-Policy', 'same-origin');
|
||||
h.set('Cross-Origin-Embedder-Policy', 'require-corp');
|
||||
h.set('Cross-Origin-Resource-Policy', 'cross-origin');
|
||||
return new Response(body, { status, statusText, headers: h });
|
||||
}));
|
||||
});
|
||||
}
|
||||
})(self);
|
||||
1
pyscript.core/tests/service-worker/sabayon.js
Normal file
1
pyscript.core/tests/service-worker/sabayon.js
Normal file
@@ -0,0 +1 @@
|
||||
const{isArray:e}=Array,t=new Map,s=e=>{e.stopImmediatePropagation(),e.preventDefault()};var n=Object.freeze({__proto__:null,activate:e=>e.waitUntil(clients.claim()),fetch:e=>{const{request:n}=e;"POST"===n.method&&n.url===`${location.href}?sabayon`&&(s(e),e.respondWith(n.json().then((async e=>{const{promise:s,resolve:o}=Promise.withResolvers(),a=e.join(",");t.set(a,o);for(const t of await clients.matchAll())t.postMessage(e);return s.then((e=>new Response(`[${e.join(",")}]`,n.headers)))}))))},install:()=>skipWaiting(),message:n=>{const{data:o}=n;if(e(o)&&4===o.length){const[e,a,i,r]=o,l=[e,a,i].join(",");t.has(l)&&(s(n),t.get(l)(r),t.delete(l))}}});for(const e in n)addEventListener(e,n[e]);
|
||||
251
pyscript.core/tests/ui/demo.py
Normal file
251
pyscript.core/tests/ui/demo.py
Normal file
@@ -0,0 +1,251 @@
|
||||
try:
|
||||
from textwrap import dedent
|
||||
except ImportError:
|
||||
dedent = lambda x: x
|
||||
|
||||
import examples
|
||||
import shoelace
|
||||
import styles
|
||||
from markdown import markdown
|
||||
from pyscript import when, window
|
||||
from pyweb import pydom
|
||||
from pyweb.ui import elements as el
|
||||
from pyweb.ui.elements import a, button, div, grid, h1, h2, h3
|
||||
|
||||
MAIN_PAGE_MARKDOWN = dedent(
|
||||
"""
|
||||
## What is pyweb.ui?
|
||||
Pyweb UI is a totally immagnary exercise atm but..... imagine it is a Python library that allows you to create
|
||||
web applications using Python only.
|
||||
|
||||
It is based on base HTML/JS components but is extensible, for instance, it can have a [Shoelace](https://shoelace.style/) backend...
|
||||
|
||||
PyWeb is a Python library that allows you to create web applications using Python only.
|
||||
|
||||
## What can I do with Pyweb.ui?
|
||||
|
||||
You can create web applications using Python only.
|
||||
"""
|
||||
)
|
||||
|
||||
# First thing we do is to load all the external resources we need
|
||||
shoelace.load_resources()
|
||||
|
||||
|
||||
# Let's define some convenience functions first
|
||||
def create_component_details(component_label, component):
|
||||
"""Create a component details card.
|
||||
|
||||
Args:
|
||||
component (str): The name of the component to create.
|
||||
|
||||
Returns:
|
||||
the component created
|
||||
|
||||
"""
|
||||
# Get the example from the examples catalog
|
||||
example = component["instance"]
|
||||
details = (
|
||||
getattr(example, "__doc__", "")
|
||||
or f"Details missing for component {component_label}"
|
||||
)
|
||||
|
||||
return div(
|
||||
[
|
||||
# Title and description (description is picked from the class docstring)
|
||||
h1(component_label),
|
||||
markdown(details),
|
||||
# Example section
|
||||
h2("Example:"),
|
||||
create_component_example(component["instance"], component["code"]),
|
||||
],
|
||||
style={"margin": "20px"},
|
||||
)
|
||||
|
||||
|
||||
def add_component_section(component_label, component, parent_div):
|
||||
"""Create a link to a component and add it to the left panel.
|
||||
|
||||
Args:
|
||||
component (str): The name of the component to add.
|
||||
|
||||
Returns:
|
||||
the component created
|
||||
|
||||
"""
|
||||
# Create the component link element
|
||||
div_ = div(
|
||||
a(component_label, href="#"),
|
||||
style={"display": "block", "text-align": "center", "margin": "auto"},
|
||||
)
|
||||
|
||||
# Create a handler that opens the component details when the link is clicked
|
||||
@when("click", div_)
|
||||
def _change():
|
||||
new_main = create_component_details(component_label, component)
|
||||
main_area.html = ""
|
||||
main_area.append(new_main)
|
||||
|
||||
# Add the new link element to the parent div (left panel)
|
||||
parent_div.append(div_)
|
||||
return div_
|
||||
|
||||
|
||||
def create_component_example(widget, code):
|
||||
"""Create a grid div with the widget on the left side and the relate code
|
||||
on the right side.
|
||||
|
||||
Args:
|
||||
widget (ElementBase): The widget to add to the grid.
|
||||
code (str): The code to add to the grid.
|
||||
|
||||
Returns:
|
||||
the grid created
|
||||
|
||||
"""
|
||||
# Create the grid that splits the window in two columns (25% and 75%)
|
||||
grid_ = grid("29% 2% 74%")
|
||||
|
||||
# Add the widget
|
||||
grid_.append(div(widget, style=styles.STYLE_EXAMPLE_INSTANCE))
|
||||
|
||||
# Add the code div
|
||||
widget_code = markdown(dedent(f"""```python\n{code}\n```"""))
|
||||
grid_.append(shoelace.Divider(vertical=True))
|
||||
grid_.append(div(widget_code, style=styles.STYLE_CODE_BLOCK))
|
||||
|
||||
return grid_
|
||||
|
||||
|
||||
def create_main_area():
|
||||
"""Create the main area of the right side of page, with the description of the
|
||||
demo itself and how to use it.
|
||||
|
||||
Returns:
|
||||
the main area
|
||||
|
||||
"""
|
||||
div_ = div(
|
||||
[
|
||||
h1("Welcome to PyWeb UI!", style={"text-align": "center"}),
|
||||
markdown(MAIN_PAGE_MARKDOWN),
|
||||
]
|
||||
)
|
||||
|
||||
main = el.main(
|
||||
style={
|
||||
"padding-top": "4rem",
|
||||
"padding-bottom": "7rem",
|
||||
"max-width": "52rem",
|
||||
"margin-left": "auto",
|
||||
"margin-right": "auto",
|
||||
"padding-left": "1.5rem",
|
||||
"padding-right": "1.5rem",
|
||||
"width": "100%",
|
||||
}
|
||||
)
|
||||
main.append(div_)
|
||||
|
||||
return main
|
||||
|
||||
|
||||
def create_basic_components_page(label, kit_name):
|
||||
"""Create the basic components page.
|
||||
|
||||
Returns:
|
||||
the main area
|
||||
|
||||
"""
|
||||
div_ = div(h2(label))
|
||||
|
||||
for component_label, component in examples.kits[kit_name].items():
|
||||
div_.append(h3(component_label))
|
||||
div_.append(create_component_example(component["instance"], component["code"]))
|
||||
|
||||
return div_
|
||||
|
||||
|
||||
# ********** CREATE ALL THE LAYOUT **********
|
||||
|
||||
main_grid = grid("140px 20px auto", style={"min-height": "100%"})
|
||||
|
||||
# ********** MAIN PANEL **********
|
||||
main_area = create_main_area()
|
||||
|
||||
|
||||
def write_to_main(content):
|
||||
main_area.html = ""
|
||||
main_area.append(content)
|
||||
|
||||
|
||||
def restore_home():
|
||||
write_to_main(create_main_area())
|
||||
|
||||
|
||||
def basic_components():
|
||||
write_to_main(
|
||||
create_basic_components_page(label="Basic Components", kit_name="elements")
|
||||
)
|
||||
# Make sure we highlight the code
|
||||
window.hljs.highlightAll()
|
||||
|
||||
|
||||
def markdown_components():
|
||||
write_to_main(create_basic_components_page(label="", kit_name="markdown"))
|
||||
|
||||
|
||||
def create_new_section(title, parent_div):
|
||||
basic_components_text = h3(
|
||||
title, style={"text-align": "left", "margin": "20px auto 0"}
|
||||
)
|
||||
parent_div.append(basic_components_text)
|
||||
parent_div.append(
|
||||
shoelace.Divider(style={"margin-top": "5px", "margin-bottom": "30px"})
|
||||
)
|
||||
return basic_components_text
|
||||
|
||||
|
||||
# ********** LEFT PANEL **********
|
||||
left_div = div()
|
||||
left_panel_title = h1(
|
||||
"PyWeb.UI", style={"text-align": "center", "margin": "20px auto 30px"}
|
||||
)
|
||||
left_div.append(left_panel_title)
|
||||
left_div.append(shoelace.Divider(style={"margin-bottom": "30px"}))
|
||||
# Let's map the creation of the main area to when the user clocks on "Components"
|
||||
when("click", left_panel_title)(restore_home)
|
||||
|
||||
# BASIC COMPONENTS
|
||||
basic_components_text = h3(
|
||||
"Basic Components",
|
||||
style={"text-align": "left", "margin": "20px auto 0", "cursor": "pointer"},
|
||||
)
|
||||
left_div.append(basic_components_text)
|
||||
left_div.append(shoelace.Divider(style={"margin-top": "5px", "margin-bottom": "30px"}))
|
||||
# Let's map the creation of the main area to when the user clocks on "Components"
|
||||
when("click", basic_components_text)(basic_components)
|
||||
|
||||
# MARKDOWN COMPONENTS
|
||||
markdown_title = create_new_section("Markdown", left_div)
|
||||
when("click", markdown_title)(markdown_components)
|
||||
|
||||
|
||||
# SHOELACE COMPONENTS
|
||||
shoe_components_text = h3(
|
||||
"Shoe Components", style={"text-align": "left", "margin": "20px auto 0"}
|
||||
)
|
||||
left_div.append(shoe_components_text)
|
||||
left_div.append(shoelace.Divider(style={"margin-top": "5px", "margin-bottom": "30px"}))
|
||||
|
||||
# Create the links to the components on th left panel
|
||||
print("SHOELACE EXAMPLES", examples.kits["shoelace"])
|
||||
for component_label, component in examples.kits["shoelace"].items():
|
||||
add_component_section(component_label, component, left_div)
|
||||
|
||||
left_div.append(shoelace.Divider(style={"margin-top": "5px", "margin-bottom": "30px"}))
|
||||
left_div.append(a("Gallery", href="gallery.html", style={"text-align": "left"}))
|
||||
# ********** ADD LEFT AND MAIN PANEL TO MAIN **********
|
||||
main_grid.append(left_div)
|
||||
main_grid.append(shoelace.Divider(vertical=True))
|
||||
main_grid.append(main_area)
|
||||
pydom.body.append(main_grid)
|
||||
300
pyscript.core/tests/ui/examples.py
Normal file
300
pyscript.core/tests/ui/examples.py
Normal file
@@ -0,0 +1,300 @@
|
||||
from markdown import markdown
|
||||
from pyscript import when, window
|
||||
from pyweb import pydom
|
||||
from pyweb.ui.elements import (
|
||||
a,
|
||||
br,
|
||||
button,
|
||||
code,
|
||||
div,
|
||||
grid,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
img,
|
||||
input_,
|
||||
p,
|
||||
small,
|
||||
strong,
|
||||
)
|
||||
from shoelace import (
|
||||
Alert,
|
||||
Button,
|
||||
Card,
|
||||
CopyButton,
|
||||
Details,
|
||||
Dialog,
|
||||
Divider,
|
||||
Icon,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Range,
|
||||
Rating,
|
||||
RelativeTime,
|
||||
Skeleton,
|
||||
Spinner,
|
||||
Switch,
|
||||
Tag,
|
||||
Textarea,
|
||||
)
|
||||
|
||||
LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||
details_code = """
|
||||
LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||
Details(LOREM_IPSUM, summary="Try me")
|
||||
"""
|
||||
example_dialog_close_btn = Button("Close")
|
||||
example_dialog = Dialog(div([p(LOREM_IPSUM), example_dialog_close_btn]), label="Try me")
|
||||
example_dialog_btn = Button("Open Dialog")
|
||||
|
||||
|
||||
def toggle_dialog():
|
||||
example_dialog.open = not (example_dialog.open)
|
||||
|
||||
|
||||
when("click", example_dialog_btn)(toggle_dialog)
|
||||
when("click", example_dialog_close_btn)(toggle_dialog)
|
||||
|
||||
pydom.body.append(example_dialog)
|
||||
|
||||
|
||||
# ELEMENTS
|
||||
|
||||
# Button
|
||||
btn = button("Click me!")
|
||||
when("click", btn)(lambda: window.alert("Clicked!"))
|
||||
|
||||
# Inputs
|
||||
inputs_div = div()
|
||||
inputs_code = []
|
||||
for input_type in [
|
||||
"text",
|
||||
"password",
|
||||
"email",
|
||||
"number",
|
||||
"date",
|
||||
"time",
|
||||
"color",
|
||||
"range",
|
||||
]:
|
||||
inputs_div.append(input_(type=input_type, style={"display": "block"}))
|
||||
inputs_code.append(f"input_(type='{input_type}')")
|
||||
|
||||
|
||||
headers_div = div()
|
||||
headers_code = []
|
||||
for header in [h1, h2, h3, h4, h5, h6]:
|
||||
headers_div.append(header(f"{header.tag.upper()} header"))
|
||||
headers_code.append(f'{header.tag}("{header.tag.upper()} header")')
|
||||
headers_code = "\n".join(headers_code)
|
||||
|
||||
rich_input = input_(
|
||||
type="text",
|
||||
name="some name",
|
||||
autofocus=True,
|
||||
pattern="\w{3,16}",
|
||||
placeholder="add text with > 3 chars",
|
||||
required=True,
|
||||
size="20",
|
||||
)
|
||||
inputs_div.append(rich_input)
|
||||
inputs_code.append("# You can create inputs with more options like")
|
||||
inputs_code.append("# this by passing properties as kwargs")
|
||||
inputs_code.append(
|
||||
"input_(type='text', name='some name', autofocus=True, pattern='\\w{3,16}', placeholder='add text with > 3 chars', required=True, size='20')"
|
||||
)
|
||||
inputs_code = "\n".join(inputs_code)
|
||||
|
||||
MARKDOWN_EXAMPLE = """# This is a header
|
||||
|
||||
This is a ~~paragraph~~ text with **bold** and *italic* text in it!
|
||||
"""
|
||||
|
||||
kits = {
|
||||
"shoelace": {
|
||||
"Alert": {
|
||||
"instance": Alert(
|
||||
"This is a standard alert. You can customize its content and even the icon."
|
||||
),
|
||||
"code": "Alert('This is a standard alert. You can customize its content and even the icon.'",
|
||||
},
|
||||
"Icon": {
|
||||
"instance": Icon(name="heart"),
|
||||
"code": 'Icon(name="heart")',
|
||||
},
|
||||
"Button": {
|
||||
"instance": Button("Try me"),
|
||||
"code": 'Button("Try me")',
|
||||
},
|
||||
"Card": {
|
||||
"instance": Card(
|
||||
p("This is a cool card!"),
|
||||
image="https://pyscript.net/assets/images/pyscript-sticker-black.svg",
|
||||
footer=div([Button("More Info"), Rating()]),
|
||||
),
|
||||
"code": """
|
||||
Card(p("This is a cool card!"), image="https://pyscript.net/assets/images/pyscript-sticker-black.svg", footer=div([Button("More Info"), Rating()]))
|
||||
""",
|
||||
},
|
||||
"Details": {
|
||||
"instance": Details(LOREM_IPSUM, summary="Try me"),
|
||||
"code": 'Details(LOREM_IPSUM, summary="Try me")',
|
||||
},
|
||||
"Dialog": {
|
||||
"instance": example_dialog_btn,
|
||||
"code": 'Dialog(div([p(LOREM_IPSUM), Button("Close")]), summary="Try me")',
|
||||
},
|
||||
"Divider": {
|
||||
"instance": Divider(),
|
||||
"code": "Divider()",
|
||||
},
|
||||
"Rating": {
|
||||
"instance": Rating(),
|
||||
"code": "Rating()",
|
||||
},
|
||||
"Radio": {
|
||||
"instance": Radio("Option 42"),
|
||||
"code": code('Radio("Option 42")'),
|
||||
},
|
||||
"Radio Group": {
|
||||
"instance": RadioGroup(
|
||||
[
|
||||
Radio("radio 1", name="radio 1", value=1, style={"margin": "20px"}),
|
||||
Radio("radio 2", name="radio 2", value=2, style={"margin": "20px"}),
|
||||
Radio("radio 3", name="radio 3", value=3, style={"margin": "20px"}),
|
||||
],
|
||||
label="Select an option",
|
||||
),
|
||||
"code": code(
|
||||
"""
|
||||
RadioGroup([Radio("radio 1", name="radio 1", value=1, style={"margin": "20px"}),
|
||||
Radio("radio 2", name="radio 2", value=2, style={"margin": "20px"}),
|
||||
Radio("radio 3", name="radio 3", value=3, style={"margin": "20px"})],
|
||||
label="Select an option"),"""
|
||||
),
|
||||
},
|
||||
"CopyButton": {
|
||||
"instance": CopyButton(
|
||||
value="PyShoes!",
|
||||
copy_label="Copy me!",
|
||||
sucess_label="Copied, check your clipboard!",
|
||||
error_label="Oops, something went wrong!",
|
||||
feedback_timeout=2000,
|
||||
tooltip_placement="top",
|
||||
),
|
||||
"code": 'CopyButton(value="PyShoes!", copy_label="Copy me!", sucess_label="Copied, check your clipboard!", error_label="Oops, something went wrong!", feedback_timeout=2000, tooltip_placement="top")',
|
||||
},
|
||||
"Skeleton": {
|
||||
"instance": Skeleton(effect="pulse"),
|
||||
"code": "Skeleton(effect='pulse')",
|
||||
},
|
||||
"Spinner": {
|
||||
"instance": Spinner(),
|
||||
"code": "Spinner()",
|
||||
},
|
||||
"Switch": {
|
||||
"instance": Switch(name="switch", size="large"),
|
||||
"code": 'Switch(name="switch", size="large")',
|
||||
},
|
||||
"Textarea": {
|
||||
"instance": Textarea(
|
||||
name="textarea",
|
||||
label="Textarea",
|
||||
size="medium",
|
||||
help_text="This is a textarea",
|
||||
resize="auto",
|
||||
),
|
||||
"code": 'Textarea(name="textarea", label="Textarea", size="medium", help_text="This is a textarea", resize="auto")',
|
||||
},
|
||||
"Tag": {
|
||||
"instance": Tag("Tag", variant="primary", size="medium"),
|
||||
"code": 'Tag("Tag", variant="primary", size="medium")',
|
||||
},
|
||||
"Range": {
|
||||
"instance": Range(min=0, max=100, value=50),
|
||||
"code": "Range(min=0, max=100, value=50)",
|
||||
},
|
||||
"RelativeTime": {
|
||||
"instance": RelativeTime(date="2021-01-01T00:00:00Z"),
|
||||
"code": 'RelativeTime(date="2021-01-01T00:00:00Z")',
|
||||
},
|
||||
# "SplitPanel": {
|
||||
# "instance": SplitPanel(
|
||||
# div("First panel"), div("Second panel"), orientation="vertical"
|
||||
# ),
|
||||
# "code": code(
|
||||
# 'SplitPanel(div("First panel"), div("Second panel"), orientation="vertical")'
|
||||
# ),
|
||||
# },
|
||||
},
|
||||
"elements": {
|
||||
"button": {
|
||||
"instance": btn,
|
||||
"code": """btn = button("Click me!")
|
||||
when('click', btn)(lambda: window.alert("Clicked!"))
|
||||
parentdiv.append(btn)
|
||||
""",
|
||||
},
|
||||
"div": {
|
||||
"instance": div(
|
||||
"This is a div",
|
||||
style={
|
||||
"text-align": "center",
|
||||
"margin": "0 auto",
|
||||
"background-color": "cornsilk",
|
||||
},
|
||||
),
|
||||
"code": 'div("This is a div", style={"text-align": "center", "margin": "0 auto", "background-color": "cornsilk"})',
|
||||
},
|
||||
"input": {"instance": inputs_div, "code": inputs_code},
|
||||
"grid": {
|
||||
"instance": grid(
|
||||
"30% 70%",
|
||||
[
|
||||
div("This is a grid", style={"background-color": "lightblue"}),
|
||||
p("with 2 elements", style={"background-color": "lightyellow"}),
|
||||
],
|
||||
),
|
||||
"code": 'grid([div("This is a grid")])',
|
||||
},
|
||||
"headers": {"instance": headers_div, "code": headers_code},
|
||||
"a": {
|
||||
"instance": a(
|
||||
"Click here for something awesome",
|
||||
href="https://pyscript.net",
|
||||
target="_blank",
|
||||
),
|
||||
"code": 'a("Click here for something awesome", href="https://pyscript.net", target="_blank")',
|
||||
},
|
||||
"br": {
|
||||
"instance": div([p("This is a paragraph"), br(), p("with a line break")]),
|
||||
"code": 'div([p("This is a paragraph"), br(), p("with a line break")])',
|
||||
},
|
||||
"img": {
|
||||
"instance": img(src="./giphy_winner.gif", style={"max-width": "200px"}),
|
||||
"code": 'img(src="./giphy_winner.gif", style={"max-width": "200px"})',
|
||||
},
|
||||
"code": {
|
||||
"instance": code("print('Hello, World!')"),
|
||||
"code": "code(\"print('Hello, World!')\")",
|
||||
},
|
||||
"p": {"instance": p("This is a paragraph"), "code": 'p("This is a paragraph")'},
|
||||
"small": {
|
||||
"instance": small("This is a small text"),
|
||||
"code": 'small("This is a small text")',
|
||||
},
|
||||
"strong": {
|
||||
"instance": strong("This is a strong text"),
|
||||
"code": 'strong("This is a strong text")',
|
||||
},
|
||||
},
|
||||
"markdown": {
|
||||
"markdown": {
|
||||
"instance": markdown(MARKDOWN_EXAMPLE),
|
||||
"code": f'markdown("""{MARKDOWN_EXAMPLE}""")',
|
||||
},
|
||||
},
|
||||
}
|
||||
31
pyscript.core/tests/ui/gallery.html
Normal file
31
pyscript.core/tests/ui/gallery.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>PyDom UI</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked@11.1.1/lib/marked.umd.min.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||
|
||||
<!-- and it's easy to individually load additional languages -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/go.min.js"></script>
|
||||
|
||||
<script>hljs.highlightAll();</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, "system-ui", "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="mpy" src="./gallery.py" config="./pyscript.toml"></script>
|
||||
</body>
|
||||
</html>
|
||||
180
pyscript.core/tests/ui/gallery.py
Normal file
180
pyscript.core/tests/ui/gallery.py
Normal file
@@ -0,0 +1,180 @@
|
||||
try:
|
||||
from textwrap import dedent
|
||||
except ImportError:
|
||||
dedent = lambda x: x
|
||||
|
||||
import inspect
|
||||
|
||||
import shoelace
|
||||
import styles
|
||||
import tictactoe
|
||||
from markdown import markdown
|
||||
from pyscript import when, window
|
||||
from pyweb import pydom
|
||||
from pyweb.ui import elements as el
|
||||
|
||||
MAIN_PAGE_MARKDOWN = dedent(
|
||||
"""
|
||||
This gallery is a collection of demos using the PyWeb.UI library. There are meant
|
||||
to be examples of how to use the library to create GUI applications using Python
|
||||
only.
|
||||
|
||||
## How to use the gallery
|
||||
|
||||
Simply click on the demo you want to see and the details will appear on the right
|
||||
"""
|
||||
)
|
||||
|
||||
# First thing we do is to load all the external resources we need
|
||||
shoelace.load_resources()
|
||||
|
||||
|
||||
def add_demo(demo_name, demo_creator_cb, parent_div, source=None):
|
||||
"""Create a link to a component and add it to the left panel.
|
||||
|
||||
Args:
|
||||
component (str): The name of the component to add.
|
||||
|
||||
Returns:
|
||||
the component created
|
||||
|
||||
"""
|
||||
# Create the component link element
|
||||
div = el.div(el.a(demo_name, href="#"), style=styles.STYLE_LEFT_PANEL_LINKS)
|
||||
|
||||
# Create a handler that opens the component details when the link is clicked
|
||||
@when("click", div)
|
||||
def _change():
|
||||
if source:
|
||||
demo_div = el.grid("50% 50%")
|
||||
demo_div.append(demo_creator_cb())
|
||||
widget_code = markdown(dedent(f"""```python\n{source}\n```"""))
|
||||
demo_div.append(el.div(widget_code, style=styles.STYLE_CODE_BLOCK))
|
||||
else:
|
||||
demo_div = demo_creator_cb()
|
||||
demo_div.style["margin"] = "20px"
|
||||
write_to_main(demo_div)
|
||||
window.hljs.highlightAll()
|
||||
|
||||
# Add the new link element to the parent div (left panel)
|
||||
parent_div.append(div)
|
||||
return div
|
||||
|
||||
|
||||
def create_main_area():
|
||||
"""Create the main area of the right side of page, with the description of the
|
||||
demo itself and how to use it.
|
||||
|
||||
Returns:
|
||||
the main area
|
||||
|
||||
"""
|
||||
return el.div(
|
||||
[
|
||||
el.h1("PyWeb UI Gallery", style={"text-align": "center"}),
|
||||
markdown(MAIN_PAGE_MARKDOWN),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def create_markdown_app():
|
||||
"""Create the basic components page.
|
||||
|
||||
Returns:
|
||||
the main area
|
||||
|
||||
"""
|
||||
translate_button = shoelace.Button("Convert", variant="primary")
|
||||
markdown_txt_area = shoelace.TextArea(label="Use this to write your Markdown")
|
||||
result_div = el.div(style=styles.STYLE_MARKDOWN_RESULT)
|
||||
|
||||
@when("click", translate_button)
|
||||
def translate_markdown():
|
||||
result_div.html = markdown(markdown_txt_area.value).html
|
||||
|
||||
return el.div(
|
||||
[
|
||||
el.h2("Markdown"),
|
||||
markdown_txt_area,
|
||||
translate_button,
|
||||
result_div,
|
||||
],
|
||||
style={"margin": "20px"},
|
||||
)
|
||||
|
||||
|
||||
# ********** MAIN PANEL **********
|
||||
main_area = create_main_area()
|
||||
|
||||
|
||||
def write_to_main(content):
|
||||
main_area.html = ""
|
||||
main_area.append(content)
|
||||
|
||||
|
||||
def restore_home():
|
||||
write_to_main(create_main_area())
|
||||
|
||||
|
||||
def create_new_section(title, parent_div):
|
||||
basic_components_text = el.h3(
|
||||
title, style={"text-align": "left", "margin": "20px auto 0"}
|
||||
)
|
||||
parent_div.append(basic_components_text)
|
||||
parent_div.append(
|
||||
shoelace.Divider(style={"margin-top": "5px", "margin-bottom": "30px"})
|
||||
)
|
||||
return basic_components_text
|
||||
|
||||
|
||||
# ********** LEFT PANEL **********
|
||||
left_panel_title = el.h1("PyWeb.UI", style=styles.STYLE_LEFT_PANEL_TITLE)
|
||||
left_div = el.div(
|
||||
[
|
||||
left_panel_title,
|
||||
shoelace.Divider(style={"margin-bottom": "30px"}),
|
||||
el.h3("Demos", style=styles.STYLE_LEFT_PANEL_TITLE),
|
||||
]
|
||||
)
|
||||
|
||||
# Let's map the creation of the main area to when the user clocks on "Components"
|
||||
when("click", left_panel_title)(restore_home)
|
||||
|
||||
# ------ ADD DEMOS ------
|
||||
markdown_source = """
|
||||
translate_button = shoelace.Button("Convert", variant="primary")
|
||||
markdown_txt_area = shoelace.TextArea(label="Markdown",
|
||||
help_text="Write your Mardown here and press convert to see the result",
|
||||
)
|
||||
result_div = el.div(style=styles.STYLE_MARKDOWN_RESULT)
|
||||
@when("click", translate_button)
|
||||
def translate_markdown():
|
||||
result_div.html = markdown(markdown_txt_area.value).html
|
||||
|
||||
el.div([
|
||||
el.h2("Markdown"),
|
||||
markdown_txt_area,
|
||||
translate_button,
|
||||
result_div,
|
||||
])
|
||||
"""
|
||||
add_demo("Markdown", create_markdown_app, left_div, source=markdown_source)
|
||||
add_demo(
|
||||
"Tic Tac Toe",
|
||||
tictactoe.create_tic_tac_toe,
|
||||
left_div,
|
||||
source=inspect.getsource(tictactoe),
|
||||
)
|
||||
|
||||
left_div.append(shoelace.Divider(style={"margin-top": "5px", "margin-bottom": "30px"}))
|
||||
left_div.append(el.a("Examples", href="/tests/ui/", style={"text-align": "left"}))
|
||||
|
||||
# ********** CREATE ALL THE LAYOUT **********
|
||||
grid = el.grid("minmax(100px, 200px) 20px auto", style={"min-height": "100%"})
|
||||
grid.append(left_div)
|
||||
grid.append(shoelace.Divider(vertical=True))
|
||||
grid.append(main_area)
|
||||
|
||||
pydom.body.append(grid)
|
||||
pydom.body.append(el.a("Back to the main page", href="/tests/ui/", target="_blank"))
|
||||
pydom.body.append(el.a("Hidden!!!", href="/tests/ui/", target="_blank", hidden=True))
|
||||
39
pyscript.core/tests/ui/index.html
Normal file
39
pyscript.core/tests/ui/index.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>PyDom UI</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked@11.1.1/lib/marked.umd.min.js"></script>
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||
|
||||
<!-- and it's easy to individually load additional languages -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/go.min.js"></script>
|
||||
<!-- SHOWLACE CUSTOM CSS -->
|
||||
<style>
|
||||
</style>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, "system-ui", "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"
|
||||
}
|
||||
|
||||
input:invalid {
|
||||
background-color: lightpink;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="mpy" src="./demo.py" config="./pyscript.toml"></script>
|
||||
</body>
|
||||
</html>
|
||||
8
pyscript.core/tests/ui/pyscript.toml
Normal file
8
pyscript.core/tests/ui/pyscript.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
packages = []
|
||||
|
||||
[files]
|
||||
"./examples.py" = "./examples.py"
|
||||
"./tictactoe.py" = "./tictactoe.py"
|
||||
"./styles.py" = "./styles.py"
|
||||
"./shoelace.py" = "./shoelace.py"
|
||||
"./markdown.py" = "./markdown.py"
|
||||
6
pyscript.core/tests/ws.spec.js
Normal file
6
pyscript.core/tests/ws.spec.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('MicroPython WebSocket', async ({ page }) => {
|
||||
await page.goto('http://localhost:5037/');
|
||||
await page.waitForSelector('html.ok');
|
||||
});
|
||||
33
pyscript.core/tests/ws/index.html
Normal file
33
pyscript.core/tests/ws/index.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="../../dist/core.css">
|
||||
<script type="module" src="../../dist/core.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="mpy" worker>
|
||||
from pyscript import WebSocket, document
|
||||
|
||||
def onopen(event):
|
||||
print(event.type)
|
||||
ws.send("hello")
|
||||
|
||||
def onmessage(event):
|
||||
print(event.type, event.data)
|
||||
ws.close()
|
||||
|
||||
def onclose(event):
|
||||
print(event.type)
|
||||
document.documentElement.classList.add("ok")
|
||||
|
||||
ws = WebSocket(
|
||||
url="ws://localhost:5037/",
|
||||
onopen=onopen,
|
||||
onmessage=onmessage,
|
||||
onclose=onclose
|
||||
)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
33
pyscript.core/tests/ws/index.js
Normal file
33
pyscript.core/tests/ws/index.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { serve, file } from 'bun';
|
||||
|
||||
import path, { dirname, join } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const dir = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
serve({
|
||||
port: 5037,
|
||||
fetch(req, server) {
|
||||
if (server.upgrade(req)) return;
|
||||
const url = new URL(req.url);
|
||||
let { pathname } = url;
|
||||
if (pathname === '/') pathname = '/index.html';
|
||||
else if (/^\/dist\//.test(pathname)) pathname = `/../..${pathname}`;
|
||||
else if (pathname === '/favicon.ico')
|
||||
return new Response('Not Found', { status: 404 });
|
||||
const response = new Response(file(`${dir}${pathname}`));
|
||||
const { headers } = response;
|
||||
headers.set('Cross-Origin-Opener-Policy', 'same-origin');
|
||||
headers.set('Cross-Origin-Embedder-Policy', 'require-corp');
|
||||
headers.set('Cross-Origin-Resource-Policy', 'cross-origin');
|
||||
return response;
|
||||
},
|
||||
websocket: {
|
||||
message(ws, message) {
|
||||
ws.send(message);
|
||||
},
|
||||
close() {
|
||||
process.exit(0);
|
||||
}
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user