Repository: pyodide/pytest-pyodide (language: python)

Issue:
Embed default html templates
This embeds `test.html` and `module_test.html` into pytest-pyodide wheel. So we don't need to bundle them into pyodide distribution.

_Additional context_ : I found that `pyodide-core` archive does not contain these test templates... which make it hard for me to run tests with `pyodide-core`. Anyway, I think it is better to remove test templates from pyodide distribution.


Discussion / hints:
@hoodmane @rth Can I ask for a review for this when you have time?

BTW, this PR also adds empty `__init__.py` file to make setuptools happy (https://github.com/pyodide/pyodide/pull/3814#issuecomment-1530157065)

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 380230ea..f0b86136 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,9 @@
 - BREAKING: dropped support for Node < 18.
   [#113](https://github.com/pyodide/pytest-pyodide/pull/113)
 
+- Added webworker test template files into the package.
+  [#112](https://github.com/pyodide/pytest-pyodide/pull/112)
+
 ## [0.53.1] - 2023-10-10
 
 - Removed the ctypes dependency so it can be used with Python builds with


Test patch:
diff --git a/pytest_pyodide/_templates/module_webworker_dev.js b/pytest_pyodide/_templates/module_webworker_dev.js
new file mode 100644
index 00000000..8ac35f7d
--- /dev/null
+++ b/pytest_pyodide/_templates/module_webworker_dev.js
@@ -0,0 +1,23 @@
+import { loadPyodide } from "./pyodide.mjs";
+
+onmessage = async function (e) {
+  try {
+    const data = e.data;
+    for (let key of Object.keys(data)) {
+      if (key !== "python") {
+        // Keys other than python must be arguments for the python script.
+        // Set them on self, so that `from js import key` works.
+        self[key] = data[key];
+      }
+    }
+
+    await self.pyodide.loadPackagesFromImports(data.python);
+    let results = await self.pyodide.runPythonAsync(data.python);
+    self.postMessage({ results });
+  } catch (e) {
+    // if you prefer messages with the error
+    self.postMessage({ error: e.message + "\n" + e.stack });
+    // if you prefer onerror events
+    // setTimeout(() => { throw err; });
+  }
+};
diff --git a/pytest_pyodide/_templates/webworker_dev.js b/pytest_pyodide/_templates/webworker_dev.js
new file mode 100644
index 00000000..05bc6460
--- /dev/null
+++ b/pytest_pyodide/_templates/webworker_dev.js
@@ -0,0 +1,23 @@
+importScripts("./pyodide.js");
+
+onmessage = async function (e) {
+  try {
+    const data = e.data;
+    for (let key of Object.keys(data)) {
+      if (key !== "python") {
+        // Keys other than python must be arguments for the python script.
+        // Set them on self, so that `from js import key` works.
+        self[key] = data[key];
+      }
+    }
+
+    await self.pyodide.loadPackagesFromImports(data.python);
+    let results = await self.pyodide.runPythonAsync(data.python);
+    self.postMessage({ results });
+  } catch (e) {
+    // if you prefer messages with the error
+    self.postMessage({ error: e.message + "\n" + e.stack });
+    // if you prefer onerror events
+    // setTimeout(() => { throw err; });
+  }
+};
diff --git a/pytest_pyodide/server.py b/pytest_pyodide/server.py
index 491c4c22..789d16ba 100644
--- a/pytest_pyodide/server.py
+++ b/pytest_pyodide/server.py
@@ -17,7 +17,10 @@ def _default_templates() -> dict[str, bytes]:
     templates_dir = pathlib.Path(__file__).parent / "_templates"
 
     templates = {}
-    for template_file in templates_dir.glob("*.html"):
+    template_files = list(templates_dir.glob("*.html")) + list(
+        templates_dir.glob("*.js")
+    )
+    for template_file in template_files:
         templates[f"/{template_file.name}"] = template_file.read_bytes()
 
     return templates
@@ -52,8 +55,11 @@ def get_template(self, path: str) -> bytes | None:
     def do_GET(self):
         body = self.get_template(self.path)
         if body:
+            content_type = (
+                "application/javascript" if self.path.endswith(".js") else "text/html"
+            )
             self.send_response(200)
-            self.send_header("Content-type", "text/html; charset=utf-8")
+            self.send_header("Content-type", f"{content_type}; charset=utf-8")
             self.send_header("Content-Length", str(len(body)))
             self.end_headers()