aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub')
-rw-r--r--packages/meshbay-hub/tests/harness/layout_probe.py2
-rw-r--r--packages/meshbay-hub/tests/harness/scroll_probe.py2
-rw-r--r--packages/meshbay-hub/tests/test_account_pinning.py4
-rw-r--r--packages/meshbay-hub/tests/test_argon2_off_loop.py2
-rw-r--r--packages/meshbay-hub/tests/test_asset_versioning.py2
-rw-r--r--packages/meshbay-hub/tests/test_availability_between_members.py2
-rw-r--r--packages/meshbay-hub/tests/test_browser_idle_signout.py2
-rw-r--r--packages/meshbay-hub/tests/test_bundle_kdf_parity.py8
-rw-r--r--packages/meshbay-hub/tests/test_captcha_host_check.py9
-rw-r--r--packages/meshbay-hub/tests/test_cast_subtitles.py6
-rw-r--r--packages/meshbay-hub/tests/test_challenge_signature_client.py6
-rw-r--r--packages/meshbay-hub/tests/test_chat_scroll_bottom.py2
-rw-r--r--packages/meshbay-hub/tests/test_client_version_gate.py8
-rw-r--r--packages/meshbay-hub/tests/test_downloads.py54
-rw-r--r--packages/meshbay-hub/tests/test_files_drop_upload.py2
-rw-r--r--packages/meshbay-hub/tests/test_files_sorting.py2
-rw-r--r--packages/meshbay-hub/tests/test_hook_ordering.py6
-rw-r--r--packages/meshbay-hub/tests/test_index_seal_client.py4
-rw-r--r--packages/meshbay-hub/tests/test_indexing_dock.py8
-rw-r--r--packages/meshbay-hub/tests/test_invite_link_client.py4
-rw-r--r--packages/meshbay-hub/tests/test_layout_measured.py4
-rw-r--r--packages/meshbay-hub/tests/test_layout_responsive.py4
-rw-r--r--packages/meshbay-hub/tests/test_locales.py11
-rw-r--r--packages/meshbay-hub/tests/test_media_pager.py4
-rw-r--r--packages/meshbay-hub/tests/test_member_removal.py2
-rw-r--r--packages/meshbay-hub/tests/test_memory_ceiling.py8
-rw-r--r--packages/meshbay-hub/tests/test_music_queue.py2
-rw-r--r--packages/meshbay-hub/tests/test_node_page_width_measured.py2
-rw-r--r--packages/meshbay-hub/tests/test_notification_dismissal.py4
-rw-r--r--packages/meshbay-hub/tests/test_offer_retry.py2
-rw-r--r--packages/meshbay-hub/tests/test_playlist_crypto.py6
-rw-r--r--packages/meshbay-hub/tests/test_playlist_key.py6
-rw-r--r--packages/meshbay-hub/tests/test_playlist_merge.py6
-rw-r--r--packages/meshbay-hub/tests/test_queue_ops.py6
-rw-r--r--packages/meshbay-hub/tests/test_reconnect_refresh.py12
-rw-r--r--packages/meshbay-hub/tests/test_recovery_key.py4
-rw-r--r--packages/meshbay-hub/tests/test_resume_position.py2
-rw-r--r--packages/meshbay-hub/tests/test_rewrap_fanout.py4
-rw-r--r--packages/meshbay-hub/tests/test_search_connect_deadline.py2
-rw-r--r--packages/meshbay-hub/tests/test_search_fanout.py2
-rw-r--r--packages/meshbay-hub/tests/test_search_files_unmerged.py2
-rw-r--r--packages/meshbay-hub/tests/test_search_media_merge.py10
-rw-r--r--packages/meshbay-hub/tests/test_search_pool.py2
-rw-r--r--packages/meshbay-hub/tests/test_search_source_merge.py6
-rw-r--r--packages/meshbay-hub/tests/test_season_panel_placement.py10
-rw-r--r--packages/meshbay-hub/tests/test_session_renewal.py14
-rw-r--r--packages/meshbay-hub/tests/test_site_basics.py2
-rw-r--r--packages/meshbay-hub/tests/test_spa_ordering.py12
-rw-r--r--packages/meshbay-hub/tests/test_spa_syntax.py6
-rw-r--r--packages/meshbay-hub/tests/test_streamed_download_reliability.py14
-rw-r--r--packages/meshbay-hub/tests/test_table_rows_measured.py2
-rw-r--r--packages/meshbay-hub/tests/test_transfers.py34
-rw-r--r--packages/meshbay-hub/tests/test_transport_contracts.py12
-rw-r--r--packages/meshbay-hub/tests/test_upload_seal_client.py4
-rw-r--r--packages/meshbay-hub/tests/test_versions_agree.py6
-rw-r--r--packages/meshbay-hub/tests/test_video_audio_track.py6
-rw-r--r--packages/meshbay-hub/tests/test_video_buffer_ceiling.py6
-rw-r--r--packages/meshbay-hub/tests/test_video_default_season.py6
-rw-r--r--packages/meshbay-hub/tests/test_video_detail_measured.py4
-rw-r--r--packages/meshbay-hub/tests/test_video_reconnect.py4
-rw-r--r--packages/meshbay-hub/tests/test_video_seek.py12
-rw-r--r--packages/meshbay-hub/tests/test_video_stream_switch.py6
-rw-r--r--packages/meshbay-hub/tests/test_video_subtitles.py6
-rw-r--r--packages/meshbay-hub/tests/test_zip_size_limit.py6
-rw-r--r--packages/meshbay-hub/tests/test_zipstream.py16
65 files changed, 219 insertions, 217 deletions
diff --git a/packages/meshbay-hub/tests/harness/layout_probe.py b/packages/meshbay-hub/tests/harness/layout_probe.py
index 65b3083..0abbda6 100644
--- a/packages/meshbay-hub/tests/harness/layout_probe.py
+++ b/packages/meshbay-hub/tests/harness/layout_probe.py
@@ -81,7 +81,7 @@ RECORDS = []
def main() -> int:
widths = [int(w) for w in sys.argv[1].split(",")]
- fragment = Path(sys.argv[2]).read_text()
+ fragment = Path(sys.argv[2]).read_text(encoding="utf-8")
selectors = sys.argv[3:]
class H(http.server.BaseHTTPRequestHandler):
diff --git a/packages/meshbay-hub/tests/harness/scroll_probe.py b/packages/meshbay-hub/tests/harness/scroll_probe.py
index ae407b8..55d5b2b 100644
--- a/packages/meshbay-hub/tests/harness/scroll_probe.py
+++ b/packages/meshbay-hub/tests/harness/scroll_probe.py
@@ -32,7 +32,7 @@ STATIC = Path(__file__).resolve().parents[2] / "src" / "meshbay_hub" / "static"
# group-page refactor.
APP = STATIC / "chat-app.js"
PORT = 8736
-FRAG = Path(sys.argv[1]).read_text()
+FRAG = Path(sys.argv[1]).read_text(encoding="utf-8")
HEIGHTS = ([int(h) for h in sys.argv[2].split(",")]
if len(sys.argv) > 2 else [700, 900, 1200])
diff --git a/packages/meshbay-hub/tests/test_account_pinning.py b/packages/meshbay-hub/tests/test_account_pinning.py
index 529ebd5..ebd29bd 100644
--- a/packages/meshbay-hub/tests/test_account_pinning.py
+++ b/packages/meshbay-hub/tests/test_account_pinning.py
@@ -102,11 +102,11 @@ def _entry(user, pk_ed, pk_x="cGtY", *, added_by="", sk_signer=None,
def _verify(devices, node_pk=NODE_PK):
with tempfile.TemporaryDirectory() as tmp:
h = Path(tmp) / "h.js"
- h.write_text(_HARNESS)
+ h.write_text(_HARNESS, encoding="utf-8")
payload = Path(tmp) / "in.json"
payload.write_text(json.dumps(
{"payload": {"devices": devices, "node_pk": node_pk},
- "node_pk": node_pk}))
+ "node_pk": node_pk}), encoding="utf-8")
run = subprocess.run(
["node", str(h), str(CRYPTO), transport_argv(), str(payload)],
capture_output=True, timeout=60)
diff --git a/packages/meshbay-hub/tests/test_argon2_off_loop.py b/packages/meshbay-hub/tests/test_argon2_off_loop.py
index 5c25a8e..ae6cc08 100644
--- a/packages/meshbay-hub/tests/test_argon2_off_loop.py
+++ b/packages/meshbay-hub/tests/test_argon2_off_loop.py
@@ -28,7 +28,7 @@ def test_nothing_derives_argon2_on_the_event_loop():
for path in SRC.rglob("*.py"):
if path.name == "auth.py":
continue
- for n, line in enumerate(path.read_text().splitlines(), 1):
+ for n, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
if direct.search(line):
offenders.append(f"{path.relative_to(SRC)}:{n}: {line.strip()}")
assert not offenders, (
diff --git a/packages/meshbay-hub/tests/test_asset_versioning.py b/packages/meshbay-hub/tests/test_asset_versioning.py
index aa2dc6d..7057311 100644
--- a/packages/meshbay-hub/tests/test_asset_versioning.py
+++ b/packages/meshbay-hub/tests/test_asset_versioning.py
@@ -135,7 +135,7 @@ def test_a_new_file_moves_the_fingerprint():
before = _asset_version()
extra = STATIC_DIR / "locales" / "zz-test-only.js"
try:
- extra.write_text("export default {};\n")
+ extra.write_text("export default {};\n", encoding="utf-8")
assert _asset_version() != before
finally:
extra.unlink()
diff --git a/packages/meshbay-hub/tests/test_availability_between_members.py b/packages/meshbay-hub/tests/test_availability_between_members.py
index cd10046..24d85a0 100644
--- a/packages/meshbay-hub/tests/test_availability_between_members.py
+++ b/packages/meshbay-hub/tests/test_availability_between_members.py
@@ -537,7 +537,7 @@ def test_no_mail_is_sent_from_the_event_loop():
for path in root.rglob("*.py"):
if path.name == "mail.py":
continue
- for n, line in enumerate(path.read_text().splitlines(), 1):
+ for n, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
if direct_call.search(line):
offenders.append(f"{path.name}:{n}: {line.strip()}")
assert not offenders, (
diff --git a/packages/meshbay-hub/tests/test_browser_idle_signout.py b/packages/meshbay-hub/tests/test_browser_idle_signout.py
index 50f7f04..454874a 100644
--- a/packages/meshbay-hub/tests/test_browser_idle_signout.py
+++ b/packages/meshbay-hub/tests/test_browser_idle_signout.py
@@ -84,7 +84,7 @@ def outcome():
pytest.skip("node is not available")
proc = subprocess.run(
[NODE, "--input-type=module", "--eval", HARNESS, IDLE.as_uri()],
- capture_output=True, text=True, timeout=30)
+ capture_output=True, text=True, encoding="utf-8", timeout=30)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout.strip().splitlines()[-1])
diff --git a/packages/meshbay-hub/tests/test_bundle_kdf_parity.py b/packages/meshbay-hub/tests/test_bundle_kdf_parity.py
index 27e10d4..c62aace 100644
--- a/packages/meshbay-hub/tests/test_bundle_kdf_parity.py
+++ b/packages/meshbay-hub/tests/test_bundle_kdf_parity.py
@@ -77,19 +77,19 @@ const argon2 = require(process.argv[3]);
def js_hashes(tmp_path_factory):
d = tmp_path_factory.mktemp("kdf")
harness = d / "harness.cjs"
- harness.write_text(_HARNESS)
+ harness.write_text(_HARNESS, encoding="utf-8")
vectors = [
{"username": u, "password": p,
"mem": MEM_KIB, "time": TIME_COST, "lanes": LANES}
for u in CASES for p in PASSWORDS
]
payload = d / "vectors.json"
- payload.write_text(json.dumps(vectors))
+ payload.write_text(json.dumps(vectors), encoding="utf-8")
proc = subprocess.run(
["node", str(harness), str(VENDOR / "argon2.wasm"),
str(VENDOR / "argon2.min.js"), str(payload)],
- capture_output=True, text=True, timeout=300,
+ capture_output=True, text=True, encoding="utf-8", timeout=300,
)
if proc.returncode != 0:
pytest.fail(f"node harness failed:\n{proc.stderr[-2000:]}")
@@ -124,7 +124,7 @@ def test_parameters_still_match_the_client():
The numbers live in keyderive.js; this test is the second copy. Tuning one
without the other orphans every bundle already written, so make it fail.
"""
- source = (STATIC / "keyderive.js").read_text()
+ source = (STATIC / "keyderive.js").read_text(encoding="utf-8")
assert f"ARGON2_MEM_KIB = {MEM_KIB}" in source
assert f"ARGON2_TIME = {TIME_COST}" in source
assert f"ARGON2_LANES = {LANES}" in source
diff --git a/packages/meshbay-hub/tests/test_captcha_host_check.py b/packages/meshbay-hub/tests/test_captcha_host_check.py
index 778009f..a0ff509 100644
--- a/packages/meshbay-hub/tests/test_captcha_host_check.py
+++ b/packages/meshbay-hub/tests/test_captcha_host_check.py
@@ -208,7 +208,7 @@ def test_hub_toml_carries_the_allowed_hosts(tmp_path):
'[captcha]\n'
'site_key = "6Lsite"\n'
'secret_key = "6Lsecret"\n'
- 'allowed_hosts = ["meshbay.org", " meshbay ", "", "localhost"]\n')
+ 'allowed_hosts = ["meshbay.org", " meshbay ", "", "localhost"]\n', encoding="utf-8")
cfg = load_config(cfg_file)
@@ -222,7 +222,8 @@ def test_a_hub_toml_without_the_key_checks_nothing(tmp_path):
"""The upgrade path. A hub that never heard of this setting keeps the
behaviour it has, with reCAPTCHA doing the origin check."""
cfg_file = tmp_path / "hub.toml"
- cfg_file.write_text('[captcha]\nsite_key = "6Lsite"\nsecret_key = "6Lsecret"\n')
+ cfg_file.write_text('[captcha]\nsite_key = "6Lsite"\nsecret_key = "6Lsecret"\n',
+ encoding="utf-8")
assert load_config(cfg_file).captcha.host_check is None
@@ -231,10 +232,10 @@ def test_the_unattributed_flag_comes_from_the_config(tmp_path, monkeypatch):
cfg_file = tmp_path / "hub.toml"
cfg_file.write_text(
'[captcha]\nsite_key = "k"\nsecret_key = "s"\n'
- 'allowed_hosts = ["meshbay.org"]\nallow_unattributed_host = true\n')
+ 'allowed_hosts = ["meshbay.org"]\nallow_unattributed_host = true\n', encoding="utf-8")
assert load_config(cfg_file).captcha.allow_unattributed_host is True
- cfg_file.write_text('[captcha]\nsite_key = "k"\nsecret_key = "s"\n')
+ cfg_file.write_text('[captcha]\nsite_key = "k"\nsecret_key = "s"\n', encoding="utf-8")
assert load_config(cfg_file).captcha.allow_unattributed_host is False, (
"the default has to stay off — it is the looser of the two")
diff --git a/packages/meshbay-hub/tests/test_cast_subtitles.py b/packages/meshbay-hub/tests/test_cast_subtitles.py
index fdf7fcc..bdc279b 100644
--- a/packages/meshbay-hub/tests/test_cast_subtitles.py
+++ b/packages/meshbay-hub/tests/test_cast_subtitles.py
@@ -66,7 +66,7 @@ def _run(tmp_path, body: str, *args: str):
+ "\n" + body, encoding="utf-8")
proc = subprocess.run(
["node", str(script), *args],
- capture_output=True, text=True, timeout=30)
+ capture_output=True, text=True, encoding="utf-8", timeout=30)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
@@ -260,7 +260,7 @@ def served(tmp_path_factory):
script.write_text(RELAY_SCRIPT, encoding="utf-8")
proc = subprocess.run(
["node", str(script), str(RELAY)],
- capture_output=True, text=True, timeout=60)
+ capture_output=True, text=True, encoding="utf-8", timeout=60)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout.strip().splitlines()[-1])
@@ -363,7 +363,7 @@ def loaded(tmp_path_factory):
script.write_text(CHROMECAST_SCRIPT, encoding="utf-8")
proc = subprocess.run(
["node", str(script), str(CHROMECAST)],
- capture_output=True, text=True, timeout=60)
+ capture_output=True, text=True, encoding="utf-8", timeout=60)
if proc.returncode != 0:
pytest.skip(f"cast-chromecast.js is not loadable here: {proc.stderr}")
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_challenge_signature_client.py b/packages/meshbay-hub/tests/test_challenge_signature_client.py
index e3c33ac..b904698 100644
--- a/packages/meshbay-hub/tests/test_challenge_signature_client.py
+++ b/packages/meshbay-hub/tests/test_challenge_signature_client.py
@@ -93,11 +93,11 @@ def test_the_browser_holds_the_node_to_its_challenge(tmp_path):
"garbage for a signature": (case(sig=b"\x00" * 64), "refused"),
}
harness = tmp_path / "harness.js"
- harness.write_text(_HARNESS)
+ harness.write_text(_HARNESS, encoding="utf-8")
payload = tmp_path / "cases.json"
- payload.write_text(json.dumps([c for c, _ in cases.values()]))
+ payload.write_text(json.dumps([c for c, _ in cases.values()]), encoding="utf-8")
proc = subprocess.run(["node", str(harness), str(STATIC), str(payload), transport_argv()],
- capture_output=True, text=True, timeout=60)
+ capture_output=True, text=True, encoding="utf-8", timeout=60)
assert proc.returncode == 0, proc.stderr
got = dict(zip(cases, json.loads(proc.stdout)))
assert got == {name: want for name, (_, want) in cases.items()}
diff --git a/packages/meshbay-hub/tests/test_chat_scroll_bottom.py b/packages/meshbay-hub/tests/test_chat_scroll_bottom.py
index 7b66c00..42b1055 100644
--- a/packages/meshbay-hub/tests/test_chat_scroll_bottom.py
+++ b/packages/meshbay-hub/tests/test_chat_scroll_bottom.py
@@ -42,7 +42,7 @@ pytestmark = pytest.mark.skipif(not CHAT.exists(), reason="SPA sources not prese
def _chat_panel_source() -> str:
- src = CHAT.read_text()
+ src = CHAT.read_text(encoding="utf-8")
start = src.index("\nfunction ChatPanel(")
end = src.find("\nfunction ", start + 1)
return src[start:end if end != -1 else len(src)]
diff --git a/packages/meshbay-hub/tests/test_client_version_gate.py b/packages/meshbay-hub/tests/test_client_version_gate.py
index 4dc9b98..91cb99a 100644
--- a/packages/meshbay-hub/tests/test_client_version_gate.py
+++ b/packages/meshbay-hub/tests/test_client_version_gate.py
@@ -32,7 +32,7 @@ pytestmark = pytest.mark.skipif(
def _lift(name: str) -> str:
- src = MAIN.read_text()
+ src = MAIN.read_text(encoding="utf-8")
cut = src[src.index(name):]
return cut[:cut.index("\n}\n") + 2]
@@ -69,8 +69,8 @@ out.compare = [
compareVersions('nonsense', '1.1.0'),
];
console.log(JSON.stringify(out));
-""")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+""", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
@@ -133,7 +133,7 @@ def test_a_first_run_with_no_hub_yet_is_not_stopped(tmp_path):
def test_the_gate_runs_before_the_window_is_built():
"""A window that opens and then cannot connect is the failure this
replaces, so the order is the whole point."""
- src = MAIN.read_text()
+ src = MAIN.read_text(encoding="utf-8")
ready = src[src.index("app.whenReady().then("):]
ready = ready[:ready.index("createWindow();")]
assert "await refuseIfTooOld()" in ready, (
diff --git a/packages/meshbay-hub/tests/test_downloads.py b/packages/meshbay-hub/tests/test_downloads.py
index 395053b..c8c68a9 100644
--- a/packages/meshbay-hub/tests/test_downloads.py
+++ b/packages/meshbay-hub/tests/test_downloads.py
@@ -26,7 +26,7 @@ pytestmark = pytest.mark.skipif(
def _run(body, tmp_path):
module = tmp_path / "downloads.mjs"
- module.write_text(DOWNLOADS.read_text())
+ module.write_text(DOWNLOADS.read_text(encoding="utf-8"), encoding="utf-8")
script = tmp_path / "case.mjs"
script.write_text(
# A localStorage good enough for a preference, so the module can be
@@ -36,12 +36,12 @@ def _run(body, tmp_path):
" getItem: k => (store.has(k) ? store.get(k) : null),\n"
" setItem: (k, v) => store.set(k, String(v)),\n"
"};\n"
- f"const M = await import('{module.as_posix()}');\n"
+ f"const M = await import('{module.as_uri()}');\n"
"const out = [];\n"
"const say = (...a) => out.push(...a);\n"
f"{body}\n"
- "console.log(JSON.stringify(out));\n")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+ "console.log(JSON.stringify(out));\n", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
@@ -104,7 +104,7 @@ def test_the_open_action_reads_the_file_back(tmp_path):
manager either. It is only offered for a file written into a granted folder,
since that is the one a page can read back.
"""
- src = DOWNLOADS.read_text()
+ src = DOWNLOADS.read_text(encoding="utf-8")
target = src[src.index("export async function openTarget"):]
assert "getFile()" in target and "window.open(" in target
assert "revokeObjectURL" in target, "the blob URL must not be leaked"
@@ -122,7 +122,7 @@ def test_the_worker_only_answers_its_own_urls():
service worker that answers more than it should is a cache bug waiting to
happen.
"""
- src = SW.read_text()
+ src = SW.read_text(encoding="utf-8")
assert "startsWith(PREFIX)" in src
assert "self.location.origin" in src, "cross-origin requests must fall through"
# The API, not the word: the file explains in prose that it caches nothing.
@@ -131,7 +131,7 @@ def test_the_worker_only_answers_its_own_urls():
def test_the_download_is_announced_as_an_attachment():
- src = SW.read_text()
+ src = SW.read_text(encoding="utf-8")
assert "Content-Disposition" in src and "attachment" in src
assert "filename*=UTF-8''" in src, "a name with accents would be mangled"
assert "Content-Length" in src
@@ -142,7 +142,7 @@ def test_a_length_is_only_promised_when_it_is_known(tmp_path):
An archive is assembled as it goes and is larger than the files in it.
Announcing the sum of their sizes would truncate the download at that mark.
"""
- src = SW.read_text()
+ src = SW.read_text(encoding="utf-8")
assert "if (entry.size > 0)" in src
# The zip-directory download started in files-app.js (group-page refactor)
@@ -153,7 +153,7 @@ def test_a_length_is_only_promised_when_it_is_known(tmp_path):
# became a bare `target = ...` inside a try when _openDownloadTarget gained
# the ability to refuse an oversized download (test_memory_ceiling.py).
# What this test is about -- the `0` -- did not move.
- app = (STATIC / "file-utils.js").read_text()
+ app = (STATIC / "file-utils.js").read_text(encoding="utf-8")
# Anchored on the argument list, not on the function name: the call became
# `_openTargetInTurn(suggested, …)` when target openings were serialised.
# The `0` this test is about did not move.
@@ -169,7 +169,7 @@ def test_backpressure_is_real(tmp_path):
is transferred gives `writer.write()` something to wait on; posting chunks
to a port would queue them in memory and look identical from here.
"""
- src = DOWNLOADS.read_text()
+ src = DOWNLOADS.read_text(encoding="utf-8")
fn = src[src.index("export async function openStreamedDownload"):]
assert "new TransformStream()" in fn
# The transfer list may carry more than the stream — a reply port rides
@@ -210,13 +210,13 @@ def test_the_streamed_path_gives_up_rather_than_blocking_for_ever():
So the worker confirms that it actually answered, and this path reports
failure instead of returning a sink nobody drains.
"""
- src = DOWNLOADS.read_text()
+ src = DOWNLOADS.read_text(encoding="utf-8")
fn = src[src.index("export async function openStreamedDownload"):]
assert "mbdl-serving" in fn, "the worker has to confirm it served the request"
assert "Promise.race" in fn, "the confirmation needs a deadline"
assert "writable.abort" in fn, "give up cleanly so the caller can fall back"
- sw = (DOWNLOADS.parent / "sw.js").read_text()
+ sw = (DOWNLOADS.parent / "sw.js").read_text(encoding="utf-8")
assert "mbdl-serving" in sw, "and the worker has to send that confirmation"
@@ -227,7 +227,7 @@ def test_an_uncontrolled_page_is_not_treated_as_ready():
# became a parameter, and `serviceWorker()` no longer contains the words.
# The behaviour itself is executed in test_streamed_download_reliability.py;
# this stays as the cheap guard on the module's shape.
- src = DOWNLOADS.read_text()
+ src = DOWNLOADS.read_text(encoding="utf-8")
section = src[src.index("// ── Streaming to disk"):]
assert "navigator.serviceWorker.controller" in section
assert "controllerchange" in section, (
@@ -251,7 +251,7 @@ def test_an_apostrophe_in_a_name_does_not_lose_the_name(tmp_path):
The real function is lifted out of sw.js and run — a second copy here would
have the same blind spot as the first.
"""
- src = SW.read_text()
+ src = SW.read_text(encoding="utf-8")
fn = src[src.index("function contentDisposition"):]
fn = fn[:fn.index("\n}") + 2]
@@ -263,8 +263,8 @@ for (const name of ["S03E02. Queen's Landing.mp4", 'Caf\\u00e9 (2019).mkv',
out[name] = contentDisposition(name);
}
console.log(JSON.stringify(out));
-""")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+""", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
out = json.loads(proc.stdout)
@@ -304,7 +304,7 @@ def test_a_sink_that_stops_consuming_fails_instead_of_hanging(tmp_path):
wrong. Bounding it does not fix whatever stopped the sink — it turns an
unexplainable freeze into a failed transfer that names itself.
"""
- src = (STATIC / "file-utils.js").read_text()
+ src = (STATIC / "file-utils.js").read_text(encoding="utf-8")
fn = src[src.index("async function _writeOrStall"):]
fn = fn[:fn.index("\n}\n") + 2]
@@ -328,8 +328,8 @@ const live = { write: async () => {} };
await _writeOrStall(live, new Uint8Array(4), 0);
out.liveOk = true;
console.log(JSON.stringify(out));
-""")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+""", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
out = json.loads(proc.stdout)
assert out["threw"], "a dead sink hung for ever instead of failing"
@@ -358,8 +358,8 @@ def test_the_worker_is_kept_alive_while_it_streams():
clock. What it protects is that the ping exists at all, is cleared on both
exits, and is answered by the worker.
"""
- dl = DOWNLOADS.read_text()
- sw = SW.read_text()
+ dl = DOWNLOADS.read_text(encoding="utf-8")
+ sw = SW.read_text(encoding="utf-8")
assert "SW_KEEPALIVE_MS" in dl and "mbdl-ping" in dl, (
"nothing keeps the worker alive; downloads longer than ~30 s will "
@@ -389,7 +389,7 @@ def _turn_harness(tmp_path, name, body, *, picker=True, budget_ms=90000):
the budget is supplied here, so a case about the budget need not wait a
minute and a half for it.
"""
- src = (STATIC / "file-utils.js").read_text()
+ src = (STATIC / "file-utils.js").read_text(encoding="utf-8")
def lift(decl):
cut = src[src.index(decl):]
@@ -422,8 +422,8 @@ const TARGET_QUEUE_BUDGET_MS = {budget_ms};
""" + lift("function _openTargetInTurn") + lift("function _waitBriefly") + f"""
{body}
console.log(JSON.stringify(out));
-""")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+""", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
@@ -518,7 +518,7 @@ def test_a_pause_falls_between_chunks_and_resumes_at_one(tmp_path):
rule this repo follows for the video player: model the environment, never
the code under test.
"""
- src = (STATIC / "file-utils.js").read_text()
+ src = (STATIC / "file-utils.js").read_text(encoding="utf-8")
fn = src[src.index("async function pipelinedDownload"):]
fn = fn[:fn.index("\n}\n") + 2]
@@ -558,8 +558,8 @@ await pipelinedDownload({}, 'k', 'file', 10, () => {}, {}, signal, '',
out.resumeFrom);
out.writtenAfterResume = written.slice();
console.log(JSON.stringify(out));
-""")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+""", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
out = json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_files_drop_upload.py b/packages/meshbay-hub/tests/test_files_drop_upload.py
index fc15c47..aa39f30 100644
--- a/packages/meshbay-hub/tests/test_files_drop_upload.py
+++ b/packages/meshbay-hub/tests/test_files_drop_upload.py
@@ -41,7 +41,7 @@ def source():
def _run(tmp_path, source, expr):
script = tmp_path / "case.js"
script.write_text(f"{source}\nconsole.log(JSON.stringify({expr}));", encoding="utf-8")
- out = subprocess.run(["node", str(script)], capture_output=True, text=True, check=True)
+ out = subprocess.run(["node", str(script)], capture_output=True, encoding="utf-8", check=True)
return json.loads(out.stdout)
diff --git a/packages/meshbay-hub/tests/test_files_sorting.py b/packages/meshbay-hub/tests/test_files_sorting.py
index 730d1e8..f3aaf34 100644
--- a/packages/meshbay-hub/tests/test_files_sorting.py
+++ b/packages/meshbay-hub/tests/test_files_sorting.py
@@ -38,7 +38,7 @@ def _names(tmp_path, source, rows, key, asc):
f"{source}\nconsole.log(JSON.stringify("
f"sortRows({json.dumps(rows)}, {json.dumps(key)}, {json.dumps(asc)}).map((r) => r.name)));",
encoding="utf-8")
- out = subprocess.run(["node", str(script)], capture_output=True, text=True, check=True)
+ out = subprocess.run(["node", str(script)], capture_output=True, encoding="utf-8", check=True)
return json.loads(out.stdout)
diff --git a/packages/meshbay-hub/tests/test_hook_ordering.py b/packages/meshbay-hub/tests/test_hook_ordering.py
index d5ffcfe..0172127 100644
--- a/packages/meshbay-hub/tests/test_hook_ordering.py
+++ b/packages/meshbay-hub/tests/test_hook_ordering.py
@@ -67,7 +67,7 @@ DEPS = re.compile(r"^ \}, \[([^\]]*)\]\);", re.M)
@pytest.fixture(scope="module")
def app():
- return APP.read_text()
+ return APP.read_text(encoding="utf-8")
def _components(src: str):
@@ -84,7 +84,7 @@ def _all_components():
path = STATIC / name
if not path.exists():
continue
- for cname, body in _components(path.read_text()):
+ for cname, body in _components(path.read_text(encoding="utf-8")):
yield f"{name}:{cname}", body
@@ -147,7 +147,7 @@ def test_the_mse_harness_reads_functions_in_source_order():
running it, which is the one class of defect it would otherwise be well
placed to catch.
"""
- harness = (Path(__file__).parent / "harness" / "mse_harness.mjs").read_text()
+ harness = (Path(__file__).parent / "harness" / "mse_harness.mjs").read_text(encoding="utf-8")
assert "sort" in harness and "indexOf" in harness, (
"the harness still extracts the player functions in a hardcoded order, "
"so it cannot see one declared before its own dependency")
diff --git a/packages/meshbay-hub/tests/test_index_seal_client.py b/packages/meshbay-hub/tests/test_index_seal_client.py
index 20f89d1..f12d791 100644
--- a/packages/meshbay-hub/tests/test_index_seal_client.py
+++ b/packages/meshbay-hub/tests/test_index_seal_client.py
@@ -69,10 +69,10 @@ def _run(frames: list[str], gek: bytes = GEK) -> dict:
with tempfile.TemporaryDirectory() as tmp:
vectors = Path(tmp) / "vectors.json"
vectors.write_text(json.dumps(
- {"gek": gek.hex(), "group_id": GROUP, "frames": frames}))
+ {"gek": gek.hex(), "group_id": GROUP, "frames": frames}), encoding="utf-8")
proc = subprocess.run(
["node", str(PROBE), str(STATIC), str(vectors), transport_argv()],
- capture_output=True, text=True, timeout=120)
+ capture_output=True, text=True, encoding="utf-8", timeout=120)
if proc.returncode != 0:
pytest.fail(f"probe failed:\n{proc.stderr}")
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_indexing_dock.py b/packages/meshbay-hub/tests/test_indexing_dock.py
index d69564d..93803a0 100644
--- a/packages/meshbay-hub/tests/test_indexing_dock.py
+++ b/packages/meshbay-hub/tests/test_indexing_dock.py
@@ -33,11 +33,11 @@ needs_node = pytest.mark.skipif(shutil.which("node") is None, reason="node is no
def _run(tmp_path, body: str):
- (tmp_path / "package.json").write_text('{"type":"module"}')
- (tmp_path / "model.js").write_text(MODEL.read_text(encoding="utf-8"))
+ (tmp_path / "package.json").write_text('{"type":"module"}', encoding="utf-8")
+ (tmp_path / "model.js").write_text(MODEL.read_text(encoding="utf-8"), encoding="utf-8")
script = tmp_path / "case.js"
- script.write_text("import * as m from './model.js';\n" + body)
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True,
+ script.write_text("import * as m from './model.js';\n" + body, encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8",
cwd=str(tmp_path))
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_invite_link_client.py b/packages/meshbay-hub/tests/test_invite_link_client.py
index 313e224..aa8c194 100644
--- a/packages/meshbay-hub/tests/test_invite_link_client.py
+++ b/packages/meshbay-hub/tests/test_invite_link_client.py
@@ -54,8 +54,8 @@ def _module_body() -> str:
def _run(tmp_path, script: str):
harness = tmp_path / "h.js"
- harness.write_text(script)
- out = subprocess.run(["node", str(harness)], capture_output=True, text=True, timeout=60)
+ harness.write_text(script, encoding="utf-8")
+ out = subprocess.run(["node", str(harness)], capture_output=True, encoding="utf-8", timeout=60)
assert out.returncode == 0, out.stderr
return json.loads(out.stdout)
diff --git a/packages/meshbay-hub/tests/test_layout_measured.py b/packages/meshbay-hub/tests/test_layout_measured.py
index 9bf1bde..c5d6280 100644
--- a/packages/meshbay-hub/tests/test_layout_measured.py
+++ b/packages/meshbay-hub/tests/test_layout_measured.py
@@ -78,7 +78,7 @@ def measured(tmp_path_factory):
"""One browser for every width, because launching one apiece cost the
suite three minutes."""
fragment = tmp_path_factory.mktemp("layout") / "fragment.html"
- fragment.write_text(NAV)
+ fragment.write_text(NAV, encoding="utf-8")
proc = subprocess.run(
["python3", str(HARNESS), ",".join(str(w) for w in WIDTHS),
str(fragment), *SELECTORS],
@@ -211,7 +211,7 @@ GROUPED_SELECTORS = [".transfer-panel", ".transfer-head", ".transfer-head-summar
@pytest.fixture(scope="module")
def grouped(tmp_path_factory):
fragment = tmp_path_factory.mktemp("grouped") / "fragment.html"
- fragment.write_text(GROUPED)
+ fragment.write_text(GROUPED, encoding="utf-8")
proc = subprocess.run(
["python3", str(HARNESS), ",".join(str(w) for w in WIDTHS),
str(fragment), *GROUPED_SELECTORS],
diff --git a/packages/meshbay-hub/tests/test_layout_responsive.py b/packages/meshbay-hub/tests/test_layout_responsive.py
index 4ee07d0..bb73557 100644
--- a/packages/meshbay-hub/tests/test_layout_responsive.py
+++ b/packages/meshbay-hub/tests/test_layout_responsive.py
@@ -38,7 +38,7 @@ pytestmark = pytest.mark.skipif(
@pytest.fixture(scope="module")
def css():
- return CSS.read_text()
+ return CSS.read_text(encoding="utf-8")
def _rule(css: str, selector: str) -> str:
@@ -119,7 +119,7 @@ APP = STATIC / "chat-app.js"
@pytest.fixture(scope="module")
def app():
- return APP.read_text()
+ return APP.read_text(encoding="utf-8")
def test_the_chat_panel_is_measured_not_guessed(app):
diff --git a/packages/meshbay-hub/tests/test_locales.py b/packages/meshbay-hub/tests/test_locales.py
index 602d161..05e1115 100644
--- a/packages/meshbay-hub/tests/test_locales.py
+++ b/packages/meshbay-hub/tests/test_locales.py
@@ -35,19 +35,20 @@ EXPECTED = ["en", "fr", "es", "pt-BR", "zh-CN", "ja", "de", "it", "nl", "pl"]
def _sandbox(tmp_path):
"""A directory node will treat as ESM, holding the real sources."""
- (tmp_path / "package.json").write_text('{"type":"module"}')
+ (tmp_path / "package.json").write_text('{"type":"module"}', encoding="utf-8")
(tmp_path / "locales").mkdir(exist_ok=True)
for src in LOCALES.glob("*.js"):
- (tmp_path / "locales" / src.name).write_text(src.read_text())
- (tmp_path / "i18n.js").write_text(I18N.read_text())
+ (tmp_path / "locales" / src.name).write_text(src.read_text(encoding="utf-8"),
+ encoding="utf-8")
+ (tmp_path / "i18n.js").write_text(I18N.read_text(encoding="utf-8"), encoding="utf-8")
return tmp_path
def _node(tmp_path, body):
script = tmp_path / "case.js"
- script.write_text(body)
+ script.write_text(body, encoding="utf-8")
proc = subprocess.run(
- ["node", str(script)], capture_output=True, text=True, cwd=str(tmp_path))
+ ["node", str(script)], capture_output=True, text=True, encoding="utf-8", cwd=str(tmp_path))
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_media_pager.py b/packages/meshbay-hub/tests/test_media_pager.py
index a8a0569..835ed6f 100644
--- a/packages/meshbay-hub/tests/test_media_pager.py
+++ b/packages/meshbay-hub/tests/test_media_pager.py
@@ -36,8 +36,8 @@ def source():
def _run(tmp_path, source, expr):
script = tmp_path / "case.js"
- script.write_text(f"{source}\nconsole.log(JSON.stringify({expr}));")
- out = subprocess.run(["node", str(script)], capture_output=True, text=True, check=True)
+ script.write_text(f"{source}\nconsole.log(JSON.stringify({expr}));", encoding="utf-8")
+ out = subprocess.run(["node", str(script)], capture_output=True, encoding="utf-8", check=True)
return json.loads(out.stdout)
diff --git a/packages/meshbay-hub/tests/test_member_removal.py b/packages/meshbay-hub/tests/test_member_removal.py
index 7af73a0..5073873 100644
--- a/packages/meshbay-hub/tests/test_member_removal.py
+++ b/packages/meshbay-hub/tests/test_member_removal.py
@@ -27,7 +27,7 @@ pytestmark = pytest.mark.skipif(
def _remove_member_body() -> str:
- source = SETTINGS.read_text()
+ source = SETTINGS.read_text(encoding="utf-8")
start = source.find("const removeMember = useCallback(")
assert start != -1, "removeMember is gone from group-settings.js"
end = source.find("\n }, [", start)
diff --git a/packages/meshbay-hub/tests/test_memory_ceiling.py b/packages/meshbay-hub/tests/test_memory_ceiling.py
index 5984292..9ea6ad3 100644
--- a/packages/meshbay-hub/tests/test_memory_ceiling.py
+++ b/packages/meshbay-hub/tests/test_memory_ceiling.py
@@ -51,7 +51,7 @@ def _lift(name, source):
@pytest.fixture(scope="module")
def target_fn():
"""The ceiling, its error and the real function — read, never re-typed."""
- src = FILE_UTILS.read_text()
+ src = FILE_UTILS.read_text(encoding="utf-8")
ceiling = re.search(r"^const MEMORY_CEILING = .*?;$", src, re.M)
assert ceiling, "MEMORY_CEILING is gone from file-utils.js"
# The test's own CEILING constant must agree with the source's, or every
@@ -123,8 +123,8 @@ try {{
outcome = {{ kind: 'refused', name: err.name, message: err.message }};
}}
console.log(JSON.stringify(outcome));
-""")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+""", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
@@ -259,7 +259,7 @@ def test_no_unguarded_memory_floor(target_fn):
def test_the_guard_is_what_the_preview_uses_too(target_fn):
"""`FilePreview` decrypts a whole entry with no writable at all, so it needs
the same ceiling — and must import it rather than keep a second number."""
- files_app = (STATIC / "files-app.js").read_text()
+ files_app = (STATIC / "files-app.js").read_text(encoding="utf-8")
assert "MEMORY_CEILING" in files_app
assert re.search(r"entry\.size\s*>\s*MEMORY_CEILING", files_app), (
"the preview modal must refuse an oversized entry before fetching it")
diff --git a/packages/meshbay-hub/tests/test_music_queue.py b/packages/meshbay-hub/tests/test_music_queue.py
index 5bf9e97..8f3f9bd 100644
--- a/packages/meshbay-hub/tests/test_music_queue.py
+++ b/packages/meshbay-hub/tests/test_music_queue.py
@@ -123,7 +123,7 @@ def test_an_unreachable_group_is_skipped_whole_rather_than_one_track_at_a_time(s
def test_the_music_wrapper_names_the_op_it_forwards(name):
"""A wrapper that takes two arguments forwards two, and the third is lost
without a word. Both of these did exactly that."""
- src = (STATIC / name).read_text()
+ src = (STATIC / name).read_text(encoding="utf-8")
marker = ("const onPlayQueue = useCallback((tracks, startIndex, op)"
if name == "group-page.js"
else "const handleMusicPlay = useCallback((tracks, startIndex, op)")
diff --git a/packages/meshbay-hub/tests/test_node_page_width_measured.py b/packages/meshbay-hub/tests/test_node_page_width_measured.py
index bd6a231..ae49641 100644
--- a/packages/meshbay-hub/tests/test_node_page_width_measured.py
+++ b/packages/meshbay-hub/tests/test_node_page_width_measured.py
@@ -122,7 +122,7 @@ SELECTORS = ["#node.node-page", "#settings", "#node .node-table-scroll",
def measured(tmp_path_factory):
"""One browser for every width — launching one apiece cost three minutes."""
fragment = tmp_path_factory.mktemp("nodewidth") / "fragment.html"
- fragment.write_text(FRAGMENT)
+ fragment.write_text(FRAGMENT, encoding="utf-8")
proc = subprocess.run(
["python3", str(HARNESS), ",".join(str(w) for w in WIDTHS),
str(fragment), *SELECTORS],
diff --git a/packages/meshbay-hub/tests/test_notification_dismissal.py b/packages/meshbay-hub/tests/test_notification_dismissal.py
index d498b4d..0198dee 100644
--- a/packages/meshbay-hub/tests/test_notification_dismissal.py
+++ b/packages/meshbay-hub/tests/test_notification_dismissal.py
@@ -149,7 +149,7 @@ def test_the_spa_asks_for_unread_only():
exercising it, and here it is the only thing that catches the defect that
actually happened.
"""
- src = APP.read_text()
+ src = APP.read_text(encoding="utf-8")
fetches = re.findall(r"hubFetch\('(/v1/notifications\?[^']*)'", src)
assert fetches, "the notification list fetch is no longer where this reads it"
for url in fetches:
@@ -167,7 +167,7 @@ def test_the_feed_does_not_style_a_state_it_can_no_longer_show():
was dead code that described behaviour the application had abandoned —
and reading it is what made the two halves' disagreement visible.
"""
- src = APP.read_text()
+ src = APP.read_text(encoding="utf-8")
assert "n.read ?" not in src, (
"the feed branches on `read` again; either it is dead code or the "
"dismissal contract has changed and this file should say how")
diff --git a/packages/meshbay-hub/tests/test_offer_retry.py b/packages/meshbay-hub/tests/test_offer_retry.py
index 6389f8e..1239ae0 100644
--- a/packages/meshbay-hub/tests/test_offer_retry.py
+++ b/packages/meshbay-hub/tests/test_offer_retry.py
@@ -33,7 +33,7 @@ pytestmark = pytest.mark.skipif(
def _post(**cfg) -> dict:
proc = subprocess.run(
["node", str(HARNESS), transport_argv(), json.dumps(cfg)],
- capture_output=True, text=True)
+ capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_playlist_crypto.py b/packages/meshbay-hub/tests/test_playlist_crypto.py
index 4ff3080..4dcfcb6 100644
--- a/packages/meshbay-hub/tests/test_playlist_crypto.py
+++ b/packages/meshbay-hub/tests/test_playlist_crypto.py
@@ -69,11 +69,11 @@ const bigBody = (n) => ({
def _run(tmp_path, body):
- src = SRC.read_text().replace("export {", "const _unused_export = {")
+ src = SRC.read_text(encoding="utf-8").replace("export {", "const _unused_export = {")
script = tmp_path / "case.mjs"
- script.write_text(f"{src}\n{PRELUDE}\n{body}\n")
+ script.write_text(f"{src}\n{PRELUDE}\n{body}\n", encoding="utf-8")
out = subprocess.run(["node", str(script)],
- capture_output=True, text=True, timeout=60)
+ capture_output=True, text=True, encoding="utf-8", timeout=60)
assert out.returncode == 0, out.stderr
return json.loads(out.stdout)
diff --git a/packages/meshbay-hub/tests/test_playlist_key.py b/packages/meshbay-hub/tests/test_playlist_key.py
index dbed8ae..261cc32 100644
--- a/packages/meshbay-hub/tests/test_playlist_key.py
+++ b/packages/meshbay-hub/tests/test_playlist_key.py
@@ -58,11 +58,11 @@ globalThis.argon2 = {
def _run(tmp_path, body):
- src = KEYDERIVE.read_text()
+ src = KEYDERIVE.read_text(encoding="utf-8")
script = tmp_path / "case.mjs"
- script.write_text(f"{PRELUDE}\n{src}\n{body}\n")
+ script.write_text(f"{PRELUDE}\n{src}\n{body}\n", encoding="utf-8")
out = subprocess.run(["node", str(script)],
- capture_output=True, text=True, timeout=60)
+ capture_output=True, text=True, encoding="utf-8", timeout=60)
assert out.returncode == 0, out.stderr
return json.loads(out.stdout)
diff --git a/packages/meshbay-hub/tests/test_playlist_merge.py b/packages/meshbay-hub/tests/test_playlist_merge.py
index 2c7b612..dd089e8 100644
--- a/packages/meshbay-hub/tests/test_playlist_merge.py
+++ b/packages/meshbay-hub/tests/test_playlist_merge.py
@@ -39,7 +39,7 @@ EXPORT = re.compile(r"^export \{[^}]*\};?\s*$", re.M | re.S)
@pytest.fixture(scope="module")
def module_source():
- text = SRC.read_text()
+ text = SRC.read_text(encoding="utf-8")
assert not IMPORT.search(text), (
"playlist-merge.js has gained an import. It is executed standalone "
"here, and the merge is untested from the moment it cannot be — keep "
@@ -53,9 +53,9 @@ def module_source():
def _run(tmp_path, module_source, body):
script = tmp_path / "case.js"
- script.write_text(f"{module_source}\n{body}\n")
+ script.write_text(f"{module_source}\n{body}\n", encoding="utf-8")
out = subprocess.run(
- ["node", str(script)], capture_output=True, text=True, timeout=30)
+ ["node", str(script)], capture_output=True, text=True, encoding="utf-8", timeout=30)
assert out.returncode == 0, out.stderr
return json.loads(out.stdout)
diff --git a/packages/meshbay-hub/tests/test_queue_ops.py b/packages/meshbay-hub/tests/test_queue_ops.py
index 64b5ca1..e3853f2 100644
--- a/packages/meshbay-hub/tests/test_queue_ops.py
+++ b/packages/meshbay-hub/tests/test_queue_ops.py
@@ -38,7 +38,7 @@ EXPORT = re.compile(r"^export \{[^}]*\};?\s*$", re.M)
@pytest.fixture(scope="module")
def module_source():
- text = SRC.read_text()
+ text = SRC.read_text(encoding="utf-8")
assert not IMPORT.search(text), (
"queue-ops.js has gained an import. It is executed standalone here, "
"and the queue is untested from the moment it cannot be — keep the "
@@ -52,9 +52,9 @@ def module_source():
def _run(tmp_path, module_source, body):
script = tmp_path / "case.js"
- script.write_text(f"{module_source}\n{body}\n")
+ script.write_text(f"{module_source}\n{body}\n", encoding="utf-8")
out = subprocess.run(
- ["node", str(script)], capture_output=True, text=True, timeout=30)
+ ["node", str(script)], capture_output=True, text=True, encoding="utf-8", timeout=30)
assert out.returncode == 0, out.stderr
return json.loads(out.stdout)
diff --git a/packages/meshbay-hub/tests/test_reconnect_refresh.py b/packages/meshbay-hub/tests/test_reconnect_refresh.py
index ff6d7fb..cd702d3 100644
--- a/packages/meshbay-hub/tests/test_reconnect_refresh.py
+++ b/packages/meshbay-hub/tests/test_reconnect_refresh.py
@@ -43,12 +43,12 @@ def transport():
@pytest.fixture(scope="module")
def group_page():
- return GROUP_PAGE.read_text()
+ return GROUP_PAGE.read_text(encoding="utf-8")
@pytest.fixture(scope="module")
def video_player():
- return VIDEO_PLAYER.read_text()
+ return VIDEO_PLAYER.read_text(encoding="utf-8")
def _reconnect_loop(transport: str) -> str:
@@ -93,7 +93,7 @@ def test_one_listener_throwing_does_not_rob_the_next(transport):
def test_nothing_assigns_the_old_setter():
"""`grep onReconnected =` is what this is, spelled so it cannot rot."""
offenders = [p.name for p in STATIC.glob("*.js")
- if re.search(r"\.onReconnected\s*=", p.read_text())]
+ if re.search(r"\.onReconnected\s*=", p.read_text(encoding="utf-8"))]
assert offenders == [], (
f"{offenders} still assign a slot that no longer exists")
@@ -159,10 +159,10 @@ def test_every_harness_that_renders_the_group_page_stubs_the_subscription():
"""
harness = Path(__file__).parent / "harness"
stubs = [p for p in harness.glob("*.py")
- if "window.MeshBayTransport" in p.read_text()
- and "GroupPage" in p.read_text()]
+ if "window.MeshBayTransport" in p.read_text(encoding="utf-8")
+ and "GroupPage" in p.read_text(encoding="utf-8")]
assert stubs, "no harness stubs the transport any more — has this moved?"
missing = [p.name for p in stubs
- if "addReconnectListener" not in p.read_text()]
+ if "addReconnectListener" not in p.read_text(encoding="utf-8")]
assert missing == [], (
f"{missing} render GroupPage against a node that cannot be subscribed to")
diff --git a/packages/meshbay-hub/tests/test_recovery_key.py b/packages/meshbay-hub/tests/test_recovery_key.py
index 54415f6..e43e6de 100644
--- a/packages/meshbay-hub/tests/test_recovery_key.py
+++ b/packages/meshbay-hub/tests/test_recovery_key.py
@@ -102,10 +102,10 @@ const fp = async (key) => hex(await webcrypto.subtle.encrypt(
def result(tmp_path_factory):
d = tmp_path_factory.mktemp("recovery")
harness = d / "harness.cjs"
- harness.write_text(_HARNESS)
+ harness.write_text(_HARNESS, encoding="utf-8")
proc = subprocess.run(
["node", str(harness), str(KEYDERIVE)],
- capture_output=True, text=True, timeout=120,
+ capture_output=True, text=True, encoding="utf-8", timeout=120,
)
if proc.returncode != 0:
pytest.fail(f"node harness failed:\n{proc.stderr[-2000:]}")
diff --git a/packages/meshbay-hub/tests/test_resume_position.py b/packages/meshbay-hub/tests/test_resume_position.py
index 07ac23a..67eb786 100644
--- a/packages/meshbay-hub/tests/test_resume_position.py
+++ b/packages/meshbay-hub/tests/test_resume_position.py
@@ -85,7 +85,7 @@ def _run(body: str, tmp_path: Path):
f"{body}\n"
"console.log(JSON.stringify(out));\n",
encoding="utf-8")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_rewrap_fanout.py b/packages/meshbay-hub/tests/test_rewrap_fanout.py
index 7c0f272..b278d0c 100644
--- a/packages/meshbay-hub/tests/test_rewrap_fanout.py
+++ b/packages/meshbay-hub/tests/test_rewrap_fanout.py
@@ -154,10 +154,10 @@ const names = (a) => a.map((x) => x.name).sort();
def result(tmp_path_factory):
d = tmp_path_factory.mktemp("rewrap")
harness = d / "harness.cjs"
- harness.write_text(_HARNESS)
+ harness.write_text(_HARNESS, encoding="utf-8")
proc = subprocess.run(
["node", str(harness), transport_argv()],
- capture_output=True, text=True, timeout=120,
+ capture_output=True, text=True, encoding="utf-8", timeout=120,
)
if proc.returncode != 0:
pytest.fail(f"node harness failed:\n{proc.stderr[-2000:]}")
diff --git a/packages/meshbay-hub/tests/test_search_connect_deadline.py b/packages/meshbay-hub/tests/test_search_connect_deadline.py
index 2d3db06..953f027 100644
--- a/packages/meshbay-hub/tests/test_search_connect_deadline.py
+++ b/packages/meshbay-hub/tests/test_search_connect_deadline.py
@@ -49,7 +49,7 @@ CAP_MS = 30000
def _attempt(**cfg) -> dict:
proc = subprocess.run(
["node", str(HARNESS), search_argv(), json.dumps(cfg)],
- capture_output=True, text=True)
+ capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_search_fanout.py b/packages/meshbay-hub/tests/test_search_fanout.py
index fca879a..23a8b67 100644
--- a/packages/meshbay-hub/tests/test_search_fanout.py
+++ b/packages/meshbay-hub/tests/test_search_fanout.py
@@ -67,7 +67,7 @@ DEAD_MS = 10000 # a node that does not, to the connection deadline
def _sweep(**cfg) -> dict:
proc = subprocess.run(
["node", str(HARNESS), search_argv(), json.dumps(cfg)],
- capture_output=True, text=True)
+ capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_search_files_unmerged.py b/packages/meshbay-hub/tests/test_search_files_unmerged.py
index b84b25d..b6621e5 100644
--- a/packages/meshbay-hub/tests/test_search_files_unmerged.py
+++ b/packages/meshbay-hub/tests/test_search_files_unmerged.py
@@ -38,7 +38,7 @@ MERGE_CALL = "mergeUnitEntries"
def _memo(name):
"""The body of `const <name> = useMemo(() => { ... }, [...]);`."""
- src = SEARCH_PAGE.read_text()
+ src = SEARCH_PAGE.read_text(encoding="utf-8")
m = re.search(
r"^ const " + re.escape(name) + r" = useMemo\(\(\) => \{.*?^ \}, \[.*?\]\);",
src, re.M | re.S)
diff --git a/packages/meshbay-hub/tests/test_search_media_merge.py b/packages/meshbay-hub/tests/test_search_media_merge.py
index 3464902..082de7e 100644
--- a/packages/meshbay-hub/tests/test_search_media_merge.py
+++ b/packages/meshbay-hub/tests/test_search_media_merge.py
@@ -50,7 +50,7 @@ EXPORT = re.compile(r"^export \{[^}]*\};?\s*$", re.M)
def _block(path, header):
"""One top-level `function name(...) {` ... `}` read out of a module."""
- src = path.read_text()
+ src = path.read_text(encoding="utf-8")
m = re.search(r"^" + re.escape(header) + r".*?^\}", src, re.M | re.S)
assert m, (
f"{header} is no longer where this test reads it from in {path.name} — "
@@ -60,7 +60,7 @@ def _block(path, header):
def _const(name):
m = re.search(r"^const " + re.escape(name) + r" = .*?;$",
- SEARCH_PAGE.read_text(), re.M)
+ SEARCH_PAGE.read_text(encoding="utf-8"), re.M)
assert m, f"{name} moved — the search-page units cannot be lifted"
return m.group(0)
@@ -70,7 +70,7 @@ def pipeline():
"""Everything the three views need, in one script."""
return "\n".join([
"const t = (k) => k;",
- EXPORT.sub("", MERGE.read_text()),
+ EXPORT.sub("", MERGE.read_text(encoding="utf-8")),
_block(VIDEO_APP, "function underVideoRoot(entry, directories) {"),
_block(VIDEO_APP, "function buildSeasons(episodes) {"),
_block(VIDEO_APP, "function groupVideoEntries(entries, videoDirectories) {"),
@@ -90,9 +90,9 @@ def pipeline():
def _node(tmp_path, pipeline, body):
script = tmp_path / "case.js"
- script.write_text(f"{pipeline}\n{body}\n")
+ script.write_text(f"{pipeline}\n{body}\n", encoding="utf-8")
out = subprocess.run(
- ["node", str(script)], capture_output=True, text=True, timeout=30)
+ ["node", str(script)], capture_output=True, text=True, encoding="utf-8", timeout=30)
assert out.returncode == 0, out.stderr
return json.loads(out.stdout)
diff --git a/packages/meshbay-hub/tests/test_search_pool.py b/packages/meshbay-hub/tests/test_search_pool.py
index cf9eeb8..89b46cd 100644
--- a/packages/meshbay-hub/tests/test_search_pool.py
+++ b/packages/meshbay-hub/tests/test_search_pool.py
@@ -36,7 +36,7 @@ pytestmark = pytest.mark.skipif(
def _run(**cfg) -> dict:
proc = subprocess.run(
["node", str(HARNESS), search_argv(), json.dumps(cfg)],
- capture_output=True, text=True)
+ capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_search_source_merge.py b/packages/meshbay-hub/tests/test_search_source_merge.py
index b471891..10d10fc 100644
--- a/packages/meshbay-hub/tests/test_search_source_merge.py
+++ b/packages/meshbay-hub/tests/test_search_source_merge.py
@@ -44,7 +44,7 @@ EXPORT = re.compile(r"^export \{[^}]*\};?\s*$", re.M)
@pytest.fixture(scope="module")
def module_source():
- text = SRC.read_text()
+ text = SRC.read_text(encoding="utf-8")
assert not IMPORT.search(text), (
"source-merge.js has gained an import. It is executed standalone here, "
"and the merge is untested from the moment it cannot be — keep the "
@@ -58,9 +58,9 @@ def module_source():
def _run(tmp_path, module_source, body):
script = tmp_path / "case.js"
- script.write_text(f"{module_source}\n{body}\n")
+ script.write_text(f"{module_source}\n{body}\n", encoding="utf-8")
out = subprocess.run(
- ["node", str(script)], capture_output=True, text=True, timeout=30)
+ ["node", str(script)], capture_output=True, text=True, encoding="utf-8", timeout=30)
assert out.returncode == 0, out.stderr
return json.loads(out.stdout)
diff --git a/packages/meshbay-hub/tests/test_season_panel_placement.py b/packages/meshbay-hub/tests/test_season_panel_placement.py
index 8c04ea7..6e5f78b 100644
--- a/packages/meshbay-hub/tests/test_season_panel_placement.py
+++ b/packages/meshbay-hub/tests/test_season_panel_placement.py
@@ -43,7 +43,7 @@ BLOCK = re.compile(
@pytest.fixture(scope="module")
def source():
- m = BLOCK.search(APP.read_text())
+ m = BLOCK.search(APP.read_text(encoding="utf-8"))
assert m, ("placeSeasonPanel is no longer where this test reads it from — "
"the season menu's placement is untested until this is fixed")
return m.group(0)
@@ -58,8 +58,8 @@ def _place(tmp_path, source, *, top, bottom, left=40, width=300, inner_height=74
const el = {{ getBoundingClientRect: () => ({{
top: {top}, bottom: {bottom}, left: {left}, width: {width} }}) }};
console.log(JSON.stringify(placeSeasonPanel(el)));
- """)
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+ """, encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
@@ -157,7 +157,7 @@ def test_no_element_means_no_position(tmp_path, source):
globalThis.window = {{ innerHeight: 740 }};
{source}
console.log(JSON.stringify(placeSeasonPanel(null)));
- """)
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+ """, encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
assert json.loads(proc.stdout) is None
diff --git a/packages/meshbay-hub/tests/test_session_renewal.py b/packages/meshbay-hub/tests/test_session_renewal.py
index 7b8c108..ecf9ac5 100644
--- a/packages/meshbay-hub/tests/test_session_renewal.py
+++ b/packages/meshbay-hub/tests/test_session_renewal.py
@@ -50,7 +50,7 @@ pytestmark = pytest.mark.skipif(
def _run(scenario: str, app: Path = APP) -> dict:
proc = subprocess.run(
["node", str(HARNESS), str(app), json.dumps({"scenario": scenario})],
- capture_output=True, text=True, timeout=60)
+ capture_output=True, text=True, encoding="utf-8", timeout=60)
assert proc.returncode == 0, f"{proc.stdout}\n{proc.stderr}"
return json.loads(proc.stdout.strip().splitlines()[-1])
@@ -59,14 +59,14 @@ def _run(scenario: str, app: Path = APP) -> dict:
def broken(tmp_path_factory):
"""The client as it shipped: the rotated refresh token dropped."""
out = tmp_path_factory.mktemp("session") / "broken.js"
- src = APP.read_text()
+ src = APP.read_text(encoding="utf-8")
replaced = src.replace(
" refreshToken: data.refresh_token || _auth.refreshToken,",
" refreshToken: _auth.refreshToken,")
assert replaced != src, (
"could not reconstruct the defect — the line it hinged on has moved, "
"and the A/B below would be comparing the fix against itself")
- out.write_text(replaced)
+ out.write_text(replaced, encoding="utf-8")
return out
@@ -186,13 +186,13 @@ def test_the_session_is_much_longer_than_the_token():
def test_renewal_happens_before_expiry_not_after():
"""A margin, so the first click after a long film does not pay for a 401."""
- src = APP.read_text()
+ src = APP.read_text(encoding="utf-8")
import re
margin = int(re.search(r"const TOKEN_RENEW_MARGIN_S = (\d+)", src).group(1))
assert margin >= 300, (
f"{margin} s of margin against a one-hour token is thin: a backgrounded "
"tab has its timers throttled and may not check for minutes")
- assert "visibilitychange" in APP_JS.read_text(), (
+ assert "visibilitychange" in APP_JS.read_text(encoding="utf-8"), (
"nothing re-checks when the tab comes back, which is exactly when the "
"token is most likely to have aged out unnoticed")
@@ -213,7 +213,7 @@ def test_renewing_does_not_tear_down_the_webrtc_connection():
Signing in or out must still re-run it, so the dependency is whether there
is a token, not which one.
"""
- src = GROUP_PAGE.read_text()
+ src = GROUP_PAGE.read_text(encoding="utf-8")
i = src.index("means tearing down the WebRTC connection")
deps = src[i:src.index(");", i)]
assert "Boolean(token)" in deps, (
@@ -228,7 +228,7 @@ def test_the_connection_signs_its_offer_with_a_live_token():
It signs the offer relayed through the hub, where an expired one is a 401
and no connection at all.
"""
- src = GROUP_PAGE.read_text()
+ src = GROUP_PAGE.read_text(encoding="utf-8")
connect = src[src.index("const connect = async () => {"):]
connect = connect[:connect.index("\n };")]
assert "await ensureFreshToken()" in connect, (
diff --git a/packages/meshbay-hub/tests/test_site_basics.py b/packages/meshbay-hub/tests/test_site_basics.py
index a3da39a..78cad83 100644
--- a/packages/meshbay-hub/tests/test_site_basics.py
+++ b/packages/meshbay-hub/tests/test_site_basics.py
@@ -47,7 +47,7 @@ def test_the_icons_are_served_from_the_root(client, path, magic):
def test_meshbay_org_sends_them_to_the_hub(path):
"""The public site owns only the paths its matcher names; a file claimed
there would be looked for in /srv/meshbay/site and 404."""
- m = re.search(r"^\s*@site path (.+)$", CADDYFILE.read_text(), re.M)
+ m = re.search(r"^\s*@site path (.+)$", CADDYFILE.read_text(encoding="utf-8"), re.M)
assert m, "the @site matcher is gone"
assert path not in m.group(1).split()
diff --git a/packages/meshbay-hub/tests/test_spa_ordering.py b/packages/meshbay-hub/tests/test_spa_ordering.py
index 087298f..fdedaf8 100644
--- a/packages/meshbay-hub/tests/test_spa_ordering.py
+++ b/packages/meshbay-hub/tests/test_spa_ordering.py
@@ -132,7 +132,7 @@ COMPONENT_FILES = {
def _component(name: str) -> str:
"""The source of one top-level `function Name(...)`, up to the next one."""
- source = COMPONENT_FILES.get(name, APP).read_text()
+ source = COMPONENT_FILES.get(name, APP).read_text(encoding="utf-8")
start = source.find(f"\nfunction {name}(")
if start == -1:
start = source.find(f"\nexport function {name}(")
@@ -225,7 +225,7 @@ def test_the_uploader_keeps_several_chunks_in_flight():
def test_no_caller_waits_for_one_chunk_at_a_time():
- app = APP.read_text()
+ app = APP.read_text(encoding="utf-8")
assert "uploadChunk(" not in app, (
"a per-chunk await is back in the SPA; use transport.uploadFile()")
@@ -248,7 +248,7 @@ def test_leaving_a_group_hands_the_transport_over_rather_than_closing_it():
def test_signing_out_stops_them():
- app = APP.read_text()
+ app = APP.read_text(encoding="utf-8")
logout = app[app.index(" logout: () => {"):]
logout = logout[:logout.index("navigate('/login')")]
assert "transfers.reset()" in logout, (
@@ -257,7 +257,7 @@ def test_signing_out_stops_them():
def test_the_files_panel_no_longer_carries_its_own_progress_bars():
"""They moved next to the bell, where they stay visible across the app."""
- app = APP.read_text()
+ app = APP.read_text(encoding="utf-8")
for gone in ("setUlState", "setDlState", "dl-bar"):
assert gone not in app, f"{gone} survived the move to the transfer widget"
@@ -270,7 +270,7 @@ def test_a_multi_file_download_waits_for_each_picker():
meant the first opened a dialog and the rest were rejected — two files
selected, one file downloaded.
"""
- app = STATIC.joinpath("files-app.js").read_text()
+ app = STATIC.joinpath("files-app.js").read_text(encoding="utf-8")
# Anchored on the loop rather than on the markup around it: the toolbar
# moved from a dropdown to icon buttons and took the old wrapper with it,
# while the property under test — one picker at a time — did not change.
@@ -289,7 +289,7 @@ def test_links_in_chat_are_built_as_elements_not_markup():
never HTML, and only for http(s) — otherwise javascript: would be one
message away from running here.
"""
- app = STATIC.joinpath("chat-app.js").read_text()
+ app = STATIC.joinpath("chat-app.js").read_text(encoding="utf-8")
fn = app[app.index("function linkify("):]
fn = fn[:fn.index("\nfunction ", 1)]
assert "innerHTML" not in fn and "dangerouslySetInnerHTML" not in fn
diff --git a/packages/meshbay-hub/tests/test_spa_syntax.py b/packages/meshbay-hub/tests/test_spa_syntax.py
index 352f84b..aac4010 100644
--- a/packages/meshbay-hub/tests/test_spa_syntax.py
+++ b/packages/meshbay-hub/tests/test_spa_syntax.py
@@ -47,7 +47,7 @@ def test_every_module_parses(tmp_path):
copy = tmp_path / (path.stem + ".mjs")
copy.write_text(path.read_text(encoding="utf-8"), encoding="utf-8")
proc = subprocess.run(["node", "--check", str(copy)],
- capture_output=True, text=True)
+ capture_output=True, text=True, encoding="utf-8")
if proc.returncode != 0:
first = (proc.stderr or "").strip().splitlines()
detail = next((ln for ln in first if "Error" in ln), first[:1] and first[0] or "")
@@ -67,12 +67,12 @@ def test_the_check_would_notice_a_broken_file(tmp_path):
as_js = tmp_path / "sample.js"
as_js.write_text(bad, encoding="utf-8")
lenient = subprocess.run(["node", "--check", str(as_js)],
- capture_output=True, text=True)
+ capture_output=True, text=True, encoding="utf-8")
as_mjs = tmp_path / "sample.mjs"
as_mjs.write_text(bad, encoding="utf-8")
strict = subprocess.run(["node", "--check", str(as_mjs)],
- capture_output=True, text=True)
+ capture_output=True, text=True, encoding="utf-8")
assert strict.returncode != 0, (
"the .mjs check no longer reports a module syntax error — this whole "
diff --git a/packages/meshbay-hub/tests/test_streamed_download_reliability.py b/packages/meshbay-hub/tests/test_streamed_download_reliability.py
index e1b3800..e60e833 100644
--- a/packages/meshbay-hub/tests/test_streamed_download_reliability.py
+++ b/packages/meshbay-hub/tests/test_streamed_download_reliability.py
@@ -195,8 +195,8 @@ def _run(tmp_path, body, *, control_after_ms=0, active=True,
controlled_at_load=False, registered_at_load=False,
worker_asleep=False):
module = tmp_path / "downloads.mjs"
- module.write_text(DOWNLOADS.read_text())
- (tmp_path / "package.json").write_text('{"type":"module"}')
+ module.write_text(DOWNLOADS.read_text(encoding="utf-8"), encoding="utf-8")
+ (tmp_path / "package.json").write_text('{"type":"module"}', encoding="utf-8")
plan = {
"controlAfterMs": control_after_ms,
"active": active,
@@ -211,12 +211,12 @@ def _run(tmp_path, body, *, control_after_ms=0, active=True,
}
script = tmp_path / "case.mjs"
script.write_text(
- (PRELUDE % {"plan": json.dumps(plan), "module": module.as_posix(),
+ (PRELUDE % {"plan": json.dumps(plan), "module": module.as_uri(),
"control": control_budget_ms,
"controlled": json.dumps(controlled_at_load)})
+ body
- + "\nout.log = log;\nconsole.log(JSON.stringify(out));\n")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True,
+ + "\nout.log = log;\nconsole.log(JSON.stringify(out));\n", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8",
timeout=120)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
@@ -338,7 +338,7 @@ def test_the_worker_is_primed_at_boot_not_at_the_first_click(tmp_path):
from a module that actually imports it — `node --check` would not notice a
missing import, which is a mistake this repo has already shipped once.
"""
- app = (STATIC / "app.js").read_text()
+ app = (STATIC / "app.js").read_text(encoding="utf-8")
assert "downloads.primeServiceWorker()" in app, "nothing primes the worker"
assert "import * as downloads from './downloads.js'" in app, (
"app.js calls downloads.primeServiceWorker() without importing downloads")
@@ -350,7 +350,7 @@ def test_the_worker_is_primed_at_boot_not_at_the_first_click(tmp_path):
def test_the_worker_answers_a_re_claim(tmp_path):
"""The page's last resort before declaring the path unavailable only works
if sw.js implements the other half."""
- sw = (STATIC / "sw.js").read_text()
+ sw = (STATIC / "sw.js").read_text(encoding="utf-8")
assert "mbdl-claim" in sw and "clients.claim()" in sw
diff --git a/packages/meshbay-hub/tests/test_table_rows_measured.py b/packages/meshbay-hub/tests/test_table_rows_measured.py
index f203624..b1f36ea 100644
--- a/packages/meshbay-hub/tests/test_table_rows_measured.py
+++ b/packages/meshbay-hub/tests/test_table_rows_measured.py
@@ -61,7 +61,7 @@ SELECTORS = [f"tbody tr:nth-child({r}) td:nth-child({c})"
@pytest.fixture(scope="module")
def measured(tmp_path_factory):
fragment = tmp_path_factory.mktemp("table") / "fragment.html"
- fragment.write_text(TABLE)
+ fragment.write_text(TABLE, encoding="utf-8")
proc = subprocess.run(
["python3", str(HARNESS), ",".join(str(w) for w in WIDTHS),
str(fragment), *SELECTORS],
diff --git a/packages/meshbay-hub/tests/test_transfers.py b/packages/meshbay-hub/tests/test_transfers.py
index b1bac4a..1d0c0f0 100644
--- a/packages/meshbay-hub/tests/test_transfers.py
+++ b/packages/meshbay-hub/tests/test_transfers.py
@@ -26,15 +26,15 @@ pytestmark = pytest.mark.skipif(
def _run(body, tmp_path):
module = tmp_path / "transfers.mjs"
- module.write_text(TRANSFERS.read_text())
+ module.write_text(TRANSFERS.read_text(encoding="utf-8"), encoding="utf-8")
script = tmp_path / "case.mjs"
script.write_text(
- f"import {{ TransferStore, formatSpeed }} from '{module.as_posix()}';\n"
+ f"import {{ TransferStore, formatSpeed }} from '{module.as_uri()}';\n"
"const out = [];\n"
"const say = (...a) => out.push(...a);\n"
f"{body}\n"
- "console.log(JSON.stringify(out));\n")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+ "console.log(JSON.stringify(out));\n", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
@@ -388,11 +388,11 @@ def test_asking_for_a_slot_on_a_dead_channel_does_not_throw(tmp_path):
# first time it arms its watchdog.
start = src.index("const LEASE_WATCHDOG_MS")
end = src.index("\nclass MeshBayTransport")
- module.write_text(src[start:end] + "\nexport { Lease };\n")
+ module.write_text(src[start:end] + "\nexport { Lease };\n", encoding="utf-8")
script = tmp_path / "case.mjs"
script.write_text(f"""
-import {{ Lease }} from '{module.as_posix()}';
+import {{ Lease }} from '{module.as_uri()}';
const out = [];
const transport = {{
supportsTransferSlots: true,
@@ -409,8 +409,8 @@ try {{ lease.release('cancelled'); out.push('release ok'); }}
catch (e) {{ out.push('release threw: ' + e.message); }}
clearTimeout(lease._watchdog);
console.log(JSON.stringify(out));
-""")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+""", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
out = json.loads(proc.stdout)
assert out[0] is None, f"asking for a slot threw: {out[0]}"
@@ -433,7 +433,7 @@ def test_the_slot_is_asked_for_after_there_is_somewhere_to_write():
Source-reading, because the ordering is the whole property and it has no
behaviour of its own to drive: what matters is which call comes first.
"""
- src = (STATIC / "file-utils.js").read_text()
+ src = (STATIC / "file-utils.js").read_text(encoding="utf-8")
fn = src[src.index("async function downloadEntry"):]
fn = fn[:fn.index("\n}\n")]
# `_openTargetInTurn` since target openings were serialised — same call,
@@ -832,7 +832,7 @@ def test_a_paused_transfer_is_not_filed_under_finished(tmp_path):
here: a copy of them in this file would agree with a broken version by
construction.
"""
- src = (STATIC / "app.js").read_text()
+ src = (STATIC / "app.js").read_text(encoding="utf-8")
start = src.index(" const running = items.filter(")
block = src[start:src.index("const active =", start)]
@@ -851,8 +851,8 @@ const items = [
const seen = { running, waiting, paused, finished };
console.log(JSON.stringify(Object.fromEntries(
Object.entries(seen).map(([k, v]) => [k, v.map(i => i.id)]))));
-""")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+""", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
groups = json.loads(proc.stdout)
@@ -870,7 +870,7 @@ def test_a_paused_transfer_still_counts_as_active(tmp_path):
"""The badge says how much is going on. A paused transfer is not over — the
person means to come back to it — so counting it as nothing would be a
panel that says "0" over work that is still there."""
- src = (STATIC / "app.js").read_text()
+ src = (STATIC / "app.js").read_text(encoding="utf-8")
start = src.index(" const running = items.filter(")
block = src[start:src.index("\n\n", src.index("const active =", start))]
@@ -879,8 +879,8 @@ def test_a_paused_transfer_still_counts_as_active(tmp_path):
const items = [{ id: 1, status: 'paused' }, { id: 2, status: 'done' }];
""" + block + """
console.log(JSON.stringify({ active }));
-""")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+""", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
assert json.loads(proc.stdout)["active"] == 1
@@ -897,7 +897,7 @@ def test_a_row_that_cannot_pause_says_so_where_the_button_would_be():
Shown only where a folder can actually be chosen: Firefox and Safari have
none to choose, and "choose a folder" would be advice that cannot be taken.
"""
- src = (STATIC / "app.js").read_text()
+ src = (STATIC / "app.js").read_text(encoding="utf-8")
row = src[src.index("function TransferRow"):]
row = row[:row.index("\n}\n")]
@@ -917,4 +917,4 @@ def test_the_reason_is_translated_everywhere():
"""`t()` falls back to the key, so a missing catalogue entry shows
`transfers.not_pausable` in a tooltip rather than a sentence."""
for path in sorted((STATIC / "locales").glob("*.js")):
- assert "'transfers.not_pausable'" in path.read_text(), path.name
+ assert "'transfers.not_pausable'" in path.read_text(encoding="utf-8"), path.name
diff --git a/packages/meshbay-hub/tests/test_transport_contracts.py b/packages/meshbay-hub/tests/test_transport_contracts.py
index 978c2e5..c1ca36b 100644
--- a/packages/meshbay-hub/tests/test_transport_contracts.py
+++ b/packages/meshbay-hub/tests/test_transport_contracts.py
@@ -59,22 +59,22 @@ def transport():
@pytest.fixture(scope="module")
def app():
- return APP.read_text()
+ return APP.read_text(encoding="utf-8")
@pytest.fixture(scope="module")
def chat():
- return CHAT_APP.read_text()
+ return CHAT_APP.read_text(encoding="utf-8")
@pytest.fixture(scope="module")
def group_page():
- return GROUP_PAGE.read_text()
+ return GROUP_PAGE.read_text(encoding="utf-8")
@pytest.fixture(scope="module")
def create_group():
- return CREATE_GROUP.read_text()
+ return CREATE_GROUP.read_text(encoding="utf-8")
def test_chat_history_pages_backwards(transport):
@@ -187,7 +187,7 @@ def test_messages_are_keyed_by_id_not_index(chat):
def test_presence_has_three_states_and_a_label_for_each(app):
for state in ("online", "offline", "unknown"):
- assert f"presence-{state}" in (STATIC / "style.css").read_text()
+ assert f"presence-{state}" in (STATIC / "style.css").read_text(encoding="utf-8")
assert "t('presence.' + state)" in app, (
"red and green are the pair colour-blind readers cannot separate, so "
"the dot needs a title and an aria-label, not just a colour")
@@ -278,7 +278,7 @@ def test_no_setter_survives_the_state_it_belonged_to():
"""
import re
for path in SPLIT_FILES:
- app = path.read_text()
+ app = path.read_text(encoding="utf-8")
declared = set(re.findall(r"const \[\s*\w+\s*,\s*(set\w+)\s*\]\s*=\s*useState", app))
# Names brought in from another module are defined, just not here.
imported = set()
diff --git a/packages/meshbay-hub/tests/test_upload_seal_client.py b/packages/meshbay-hub/tests/test_upload_seal_client.py
index bcda14c..f62aa68 100644
--- a/packages/meshbay-hub/tests/test_upload_seal_client.py
+++ b/packages/meshbay-hub/tests/test_upload_seal_client.py
@@ -48,10 +48,10 @@ BODY = bytes(range(256)) * 3 # 768 bytes → 24 chunks of 32
def _run_probe(payload: dict) -> dict:
with tempfile.TemporaryDirectory() as d:
f = Path(d) / "input.json"
- f.write_text(json.dumps(payload))
+ f.write_text(json.dumps(payload), encoding="utf-8")
proc = subprocess.run(
["node", str(PROBE), str(STATIC), str(f), transport_argv()],
- capture_output=True, text=True, timeout=60,
+ capture_output=True, text=True, encoding="utf-8", timeout=60,
)
if proc.returncode != 0 or not proc.stdout:
pytest.fail(f"upload probe failed:\n{proc.stderr}")
diff --git a/packages/meshbay-hub/tests/test_versions_agree.py b/packages/meshbay-hub/tests/test_versions_agree.py
index 4466c93..46887c0 100644
--- a/packages/meshbay-hub/tests/test_versions_agree.py
+++ b/packages/meshbay-hub/tests/test_versions_agree.py
@@ -27,11 +27,11 @@ PACKAGES = ROOT / "packages"
def _python_versions() -> dict[str, str]:
found = {}
for pyproject in sorted(PACKAGES.glob("*/pyproject.toml")):
- m = re.search(r'^version = "([^"]+)"', pyproject.read_text(), re.M)
+ m = re.search(r'^version = "([^"]+)"', pyproject.read_text(encoding="utf-8"), re.M)
if m:
found[f"{pyproject.parent.name}/pyproject.toml"] = m.group(1)
for init in sorted(PACKAGES.glob("*/src/*/__init__.py")):
- m = re.search(r'^__version__ = "([^"]+)"', init.read_text(), re.M)
+ m = re.search(r'^__version__ = "([^"]+)"', init.read_text(encoding="utf-8"), re.M)
if m:
found[f"{init.parent.name}/__init__.py"] = m.group(1)
return found
@@ -41,7 +41,7 @@ def _client_version() -> str | None:
pkg = PACKAGES / "meshbay-client" / "package.json"
if not pkg.exists():
return None
- return json.loads(pkg.read_text()).get("version")
+ return json.loads(pkg.read_text(encoding="utf-8")).get("version")
@pytest.mark.skipif(not PACKAGES.is_dir(), reason="package layout not present")
diff --git a/packages/meshbay-hub/tests/test_video_audio_track.py b/packages/meshbay-hub/tests/test_video_audio_track.py
index 54beca2..82d6e18 100644
--- a/packages/meshbay-hub/tests/test_video_audio_track.py
+++ b/packages/meshbay-hub/tests/test_video_audio_track.py
@@ -42,7 +42,7 @@ pytestmark = pytest.mark.skipif(
@pytest.fixture(scope="module")
def app():
- return APP.read_text()
+ return APP.read_text(encoding="utf-8")
def _player(app: str) -> str:
@@ -88,10 +88,10 @@ def _label_cases(tmp_path, app, cases, locale="en"):
"const t = (k, p) => `${k}:${p.n}`;\n"
+ src
+ "\nconst out = JSON.parse(process.argv[2]).map(audioTrackLabel);\n"
- "console.log(JSON.stringify(out));\n")
+ "console.log(JSON.stringify(out));\n", encoding="utf-8")
proc = subprocess.run(
["node", str(script), json.dumps(cases)],
- capture_output=True, text=True)
+ capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_video_buffer_ceiling.py b/packages/meshbay-hub/tests/test_video_buffer_ceiling.py
index a488976..da9766e 100644
--- a/packages/meshbay-hub/tests/test_video_buffer_ceiling.py
+++ b/packages/meshbay-hub/tests/test_video_buffer_ceiling.py
@@ -67,7 +67,7 @@ pytestmark = pytest.mark.skipif(
@pytest.fixture(scope="module")
def app():
- return APP.read_text()
+ return APP.read_text(encoding="utf-8")
def _player(app: str) -> str:
@@ -95,7 +95,7 @@ HARNESS = Path(__file__).parent / "harness" / "mse_harness.mjs"
def _harness(**cfg) -> dict:
proc = subprocess.run(
["node", str(HARNESS), str(APP), json.dumps(cfg)],
- capture_output=True, text=True)
+ capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
@@ -437,7 +437,7 @@ def test_credit_is_a_window_and_not_a_debt(app):
pump = pump[:pump.index("\n }, [")]
assert "STREAM_WINDOW - outstandingRef.current" in pump, (
"pump() no longer tops a window up to what is allowed in flight")
- src = APP.read_text()
+ src = APP.read_text(encoding="utf-8")
window = int(re.search(r"const STREAM_WINDOW = (\d+)", src).group(1))
assert 2 <= window <= 16, (
f"a window of {window} segments is either too small to keep the pipe "
diff --git a/packages/meshbay-hub/tests/test_video_default_season.py b/packages/meshbay-hub/tests/test_video_default_season.py
index 898d3f5..ab1d7c1 100644
--- a/packages/meshbay-hub/tests/test_video_default_season.py
+++ b/packages/meshbay-hub/tests/test_video_default_season.py
@@ -43,7 +43,7 @@ BLOCK = re.compile(r"^function defaultSeason\(show\) \{.*?^\}", re.M | re.S)
@pytest.fixture(scope="module")
def source():
- m = BLOCK.search(APP.read_text())
+ m = BLOCK.search(APP.read_text(encoding="utf-8"))
assert m, ("defaultSeason is no longer where this test reads it from — the "
"season a show opens on is untested until this is fixed")
return m.group(0)
@@ -57,8 +57,8 @@ def _default(tmp_path, source, seasons):
script.write_text(f"""
{source}
console.log(JSON.stringify(defaultSeason({json.dumps(show)})));
- """)
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+ """, encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_video_detail_measured.py b/packages/meshbay-hub/tests/test_video_detail_measured.py
index 1ac8586..4cd5969 100644
--- a/packages/meshbay-hub/tests/test_video_detail_measured.py
+++ b/packages/meshbay-hub/tests/test_video_detail_measured.py
@@ -182,7 +182,7 @@ SELECTORS = [
def measured(tmp_path_factory):
"""One browser for every width — launching one apiece cost three minutes."""
fragment = tmp_path_factory.mktemp("videodetail") / "fragment.html"
- fragment.write_text(FRAGMENT)
+ fragment.write_text(FRAGMENT, encoding="utf-8")
proc = subprocess.run(
["python3", str(HARNESS), ",".join(str(w) for w in WIDTHS),
str(fragment), *SELECTORS],
@@ -292,7 +292,7 @@ def test_the_episode_list_reserves_its_scrollbar():
rectangle — `test_layout_responsive.py` says so at length — but it is
worth more than a test that cannot fail.
"""
- css = (STATIC / "style.css").read_text()
+ css = (STATIC / "style.css").read_text(encoding="utf-8")
rule = re.search(
r"\.video-detail\.video-detail-steady \.video-season-list \{([^}]*)\}", css)
assert rule, "the steady episode-list rule is gone"
diff --git a/packages/meshbay-hub/tests/test_video_reconnect.py b/packages/meshbay-hub/tests/test_video_reconnect.py
index beeeace..91aa87b 100644
--- a/packages/meshbay-hub/tests/test_video_reconnect.py
+++ b/packages/meshbay-hub/tests/test_video_reconnect.py
@@ -53,7 +53,7 @@ pytestmark = pytest.mark.skipif(
@pytest.fixture(scope="module")
def app():
- return APP.read_text()
+ return APP.read_text(encoding="utf-8")
def _player(app: str) -> str:
@@ -87,7 +87,7 @@ def _plan(app: str, cases: list[dict]) -> list[dict]:
"(c) => reconnectPlan(c.playhead, c.range, c.ended, c.cast))));"
)
proc = subprocess.run(["node", "--input-type=module", "-e", script],
- capture_output=True, text=True)
+ capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_video_seek.py b/packages/meshbay-hub/tests/test_video_seek.py
index 9436065..3289eda 100644
--- a/packages/meshbay-hub/tests/test_video_seek.py
+++ b/packages/meshbay-hub/tests/test_video_seek.py
@@ -46,7 +46,7 @@ pytestmark = pytest.mark.skipif(not APP.exists(), reason="SPA sources unavailabl
@pytest.fixture(scope="module")
def app():
- return APP.read_text()
+ return APP.read_text(encoding="utf-8")
def _player(app: str) -> str:
@@ -164,7 +164,7 @@ def test_the_leak_deadlocks_the_window_and_the_fix_clears_it():
proc = subprocess.run(
["node", str(harness), str(APP),
json.dumps({"decrementFirst": decrement_first})],
- capture_output=True, text=True)
+ capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
@@ -269,7 +269,7 @@ def test_seeks_are_debounced(app):
"""Dragging fires `seeking` continuously; each one we act on costs a spawn."""
player = _player(app)
assert "SEEK_DEBOUNCE_MS" in player, "every intermediate drag position seeks"
- ms = int(re.search(r"const SEEK_DEBOUNCE_MS = (\d+)", APP.read_text()).group(1))
+ ms = int(re.search(r"const SEEK_DEBOUNCE_MS = (\d+)", APP.read_text(encoding="utf-8")).group(1))
assert 150 <= ms <= 1000, (
f"{ms} ms is either short enough to still storm the node or long "
"enough to feel broken")
@@ -289,7 +289,7 @@ def test_a_seek_inside_the_buffer_does_not_reach_the_node(app):
def test_the_position_is_kept_in_this_browser(app):
"""localStorage: no protocol, no storage for anyone else to keep, and
nothing new learns what you watch."""
- src = APP.read_text()
+ src = APP.read_text(encoding="utf-8")
assert "mb:pos:" in src, "no position is stored"
read = src[src.index("function readResumePosition"):]
read = read[:read.index("\n}")]
@@ -299,7 +299,7 @@ def test_the_position_is_kept_in_this_browser(app):
def test_a_finished_film_does_not_offer_to_resume(app):
- src = APP.read_text()
+ src = APP.read_text(encoding="utf-8")
write = src[src.index("function writeResumePosition"):]
write = write[:write.index("\n}")]
assert "RESUME_MAX_FRACTION" in write and "removeItem" in write, (
@@ -317,6 +317,6 @@ def test_the_viewer_can_refuse_the_resume(app):
@pytest.mark.parametrize("locale", ["en", "fr", "es", "pt-BR", "zh-CN", "ja",
"de", "it", "nl", "pl"])
def test_the_resume_strings_exist_everywhere(locale):
- text = (STATIC / "locales" / f"{locale}.js").read_text()
+ text = (STATIC / "locales" / f"{locale}.js").read_text(encoding="utf-8")
for key in ("video.resumed_at", "video.from_start"):
assert key in text, f"{locale} is missing {key}"
diff --git a/packages/meshbay-hub/tests/test_video_stream_switch.py b/packages/meshbay-hub/tests/test_video_stream_switch.py
index 7859057..6c67430 100644
--- a/packages/meshbay-hub/tests/test_video_stream_switch.py
+++ b/packages/meshbay-hub/tests/test_video_stream_switch.py
@@ -45,7 +45,7 @@ pytestmark = pytest.mark.skipif(
@pytest.fixture(scope="module")
def app():
- return APP.read_text()
+ return APP.read_text(encoding="utf-8")
def _player(app: str) -> str:
@@ -125,8 +125,8 @@ def test_the_stall_is_reproduced_and_the_reset_clears_it(tmp_path):
out[name] = p.st.appended - afterFirst;
}
console.log(JSON.stringify(out));
- """)
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+ """, encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
got = json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_video_subtitles.py b/packages/meshbay-hub/tests/test_video_subtitles.py
index 5a4b215..68058cd 100644
--- a/packages/meshbay-hub/tests/test_video_subtitles.py
+++ b/packages/meshbay-hub/tests/test_video_subtitles.py
@@ -47,7 +47,7 @@ pytestmark = pytest.mark.skipif(
@pytest.fixture(scope="module")
def app():
- return APP.read_text()
+ return APP.read_text(encoding="utf-8")
@pytest.fixture(scope="module")
@@ -117,10 +117,10 @@ def _label_cases(tmp_path, app, cases, locale="en"):
"const t = (k, p) => (p ? `${k}:${p.n}` : k);\n"
+ src
+ "\nconst out = JSON.parse(process.argv[2]).map(subtitleTrackLabel);\n"
- "console.log(JSON.stringify(out));\n")
+ "console.log(JSON.stringify(out));\n", encoding="utf-8")
proc = subprocess.run(
["node", str(script), json.dumps(cases)],
- capture_output=True, text=True)
+ capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_zip_size_limit.py b/packages/meshbay-hub/tests/test_zip_size_limit.py
index 9243fd1..6ef0989 100644
--- a/packages/meshbay-hub/tests/test_zip_size_limit.py
+++ b/packages/meshbay-hub/tests/test_zip_size_limit.py
@@ -46,7 +46,7 @@ def _run(total_bytes, tmp_path, picker=False):
for src in STATIC.glob("*.js"):
(sandbox / src.name).write_text(src.read_text(encoding="utf-8"),
encoding="utf-8")
- (tmp_path / "package.json").write_text('{"type":"module"}')
+ (tmp_path / "package.json").write_text('{"type":"module"}', encoding="utf-8")
# ask.js draws a dialog in the DOM, which Node has none of; the question is
# answered here instead, exactly where `confirm` used to be stubbed.
(sandbox / "ask.js").write_text(
@@ -87,7 +87,7 @@ if ({picker_js}) {{
}});
}}
-const M = await import('{(sandbox / "file-utils.js").as_posix()}');
+const M = await import('{(sandbox / "file-utils.js").as_uri()}');
// Faithful enough to the real store: it runs `prepare` and honours what it
// returns. The target is opened there now — the row exists from the click and
@@ -126,7 +126,7 @@ out.limit = M.ZIP_MAX_BYTES;
console.log(JSON.stringify(out));
""", encoding="utf-8")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
diff --git a/packages/meshbay-hub/tests/test_zipstream.py b/packages/meshbay-hub/tests/test_zipstream.py
index 51a42d0..55a4d97 100644
--- a/packages/meshbay-hub/tests/test_zipstream.py
+++ b/packages/meshbay-hub/tests/test_zipstream.py
@@ -32,12 +32,12 @@ def _build(files, force_zip64=False, tmp_path=None):
# <script type="module">, but Node reads a bare .js as CommonJS unless a
# package.json says otherwise, and there is none next to the SPA.
module = tmp_path / "zipstream.mjs"
- module.write_text(ZIPSTREAM.read_text())
+ module.write_text(ZIPSTREAM.read_text(encoding="utf-8"), encoding="utf-8")
script = tmp_path / "build.mjs"
out = tmp_path / "out.zip"
script.write_text(f"""
import {{ writeFileSync }} from 'node:fs';
-import {{ ZipStream }} from '{module.as_posix()}';
+import {{ ZipStream }} from '{module.as_uri()}';
const files = {json.dumps({k: list(v) for k, v in files.items()})};
const parts = [];
@@ -55,8 +55,8 @@ for (const [name, bytes] of Object.entries(files)) {{
}}
await zip.finish();
writeFileSync('{out.as_posix()}', Buffer.concat(parts));
-""")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+""", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return out.read_bytes()
@@ -140,14 +140,14 @@ def test_an_empty_archive_is_still_an_archive(tmp_path):
def _under(entries, dir_, tmp_path):
module = tmp_path / "zipstream.mjs"
- module.write_text(ZIPSTREAM.read_text())
+ module.write_text(ZIPSTREAM.read_text(encoding="utf-8"), encoding="utf-8")
script = tmp_path / "under.mjs"
script.write_text(f"""
-import {{ entriesUnder }} from '{module.as_posix()}';
+import {{ entriesUnder }} from '{module.as_uri()}';
const out = entriesUnder({json.dumps(entries)}, {json.dumps(dir_)});
console.log(JSON.stringify(out.map(o => o.name)));
-""")
- proc = subprocess.run(["node", str(script)], capture_output=True, text=True)
+""", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8")
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)