Procházet zdrojové kódy

test: test scripts run the build, type check and lint exits; app engine released per test; refresh the type-check baseline

maziggy před 3 dny
rodič
revize
ab7fb583da

+ 0 - 8
.basedpyright/baseline.json

@@ -1771,14 +1771,6 @@
             }
         ],
         "./backend/app/main.py": [
-            {
-                "code": "reportArgumentType",
-                "range": {
-                    "startColumn": 61,
-                    "endColumn": 79,
-                    "lineCount": 1
-                }
-            },
             {
                 "code": "reportAttributeAccessIssue",
                 "range": {

+ 1 - 1
CONTRIBUTING.md

@@ -195,7 +195,7 @@ ruff format backend/
 ruff format --check backend/
 ```
 
-Types are checked with [basedpyright](https://docs.basedpyright.com/) (configuration in `pyproject.toml`). Errors that existed when the check was introduced are listed in `.basedpyright/baseline.json` and pass; a new one fails the check. The check runs against the pinned library versions in `requirements-typecheck.lock`, because other versions report different errors. It needs Python 3.11 or newer on Linux, macOS on Apple Silicon, or WSL (the lock is built for Linux; on Intel Macs some pinned packages have no wheels). Once `.typecheck-venv` exists, `./test_backend.sh` runs it for you and rebuilds the venv whenever the lock changes. Running the commands by hand, re-run the `pip install` after a lock change:
+Types are checked with [basedpyright](https://docs.basedpyright.com/) (configuration in `pyproject.toml`). Errors that existed when the check was introduced are listed in `.basedpyright/baseline.json` and pass; a new one fails the check. The check runs against the pinned library versions in `requirements-typecheck.lock`, because other versions report different errors. It needs Python 3.11 or newer on Linux, macOS on Apple Silicon, or WSL (the lock is built for Linux; on Intel Macs some pinned packages have no wheels). `./test_backend.sh` runs it for you: it creates `.typecheck-venv` on first use when Python 3.11 is available (through `uv`, or as `python3.11`), and rebuilds it whenever the lock changes. Running the commands by hand, re-run the `pip install` after a lock change:
 
 ```bash
 python3 -m venv .typecheck-venv          # Python 3.11 or newer

+ 25 - 0
backend/tests/conftest.py

@@ -396,6 +396,29 @@ async def _reset_pg_test_schema(conn) -> None:
     await conn.execute(text(_PG_EMPTY_TABLES))
 
 
+async def _release_app_engine() -> None:
+    """Close the app engine's pooled connections before this test's loop ends.
+
+    Code that opens its own session (print completion, services) uses the
+    app's module-level engine, shared by every test on the worker. Its pool
+    would keep a connection opened in this test's event loop into the next
+    test's, where SQLAlchemy closes it in a loop it does not belong to; on
+    PostgreSQL that leaves asyncpg's cleanup unawaited, reported as an
+    unraisable "Connection._cancel" coroutine in some later test.
+    """
+    await _app_engine.dispose()
+
+
+if TEST_PG_URL is not None:
+
+    @pytest.fixture(autouse=True)
+    async def _app_engine_released_after_each_test():
+        """Every test, not only those with test_engine: any of them can reach
+        the app engine through code that opens its own session."""
+        yield
+        await _release_app_engine()
+
+
 @pytest.fixture
 async def test_engine():
     """Create a test database engine."""
@@ -455,6 +478,7 @@ async def test_engine():
         async with engine.begin() as conn:
             await _reset_pg_test_schema(conn)
         yield engine
+        await _release_app_engine()
         await engine.dispose()
         return
 
@@ -462,6 +486,7 @@ async def test_engine():
         await conn.run_sync(Base.metadata.create_all)
 
     yield engine
+    await _release_app_engine()
 
     async with engine.begin() as conn:
         await conn.run_sync(Base.metadata.drop_all)

+ 5 - 1
frontend/scripts/check-browser-baseline.mjs

@@ -31,7 +31,11 @@ import { readdirSync, readFileSync } from 'node:fs';
 import { join, dirname, relative, resolve } from 'node:path';
 import { fileURLToPath } from 'node:url';
 
-const ASSETS = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', 'static', 'assets');
+// The build's assets; another directory as the first argument, for a build
+// made elsewhere (test_frontend.sh builds into a temporary directory).
+const ASSETS = process.argv[2]
+  ? resolve(process.argv[2])
+  : resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', 'static', 'assets');
 
 /**
  * Every extension the build can emit executable JavaScript under. `.mjs`

+ 13 - 3
test_backend.sh

@@ -1,11 +1,21 @@
 #!/bin/sh
 
 cd backend
-ruff check && ruff format --check
+{ ruff check && ruff format --check; } || exit 1
 
 # Type check against the pinned environment (see CONTRIBUTING.md). The venv is
 # rebuilt whenever the lock changes, so it holds what CI installs (on Python
-# 3.11 exactly; newer Pythons add a few unpinned backports).
+# 3.11 exactly; newer Pythons add a few unpinned backports). Created here on
+# first use when Python 3.11 is available (through uv, or as python3.11).
+if [ ! -d ../.typecheck-venv ]; then
+    if command -v uv >/dev/null 2>&1; then
+        echo "Creating .typecheck-venv (Python 3.11, uv)"
+        uv venv -q --seed --python 3.11 ../.typecheck-venv || exit 1
+    elif command -v python3.11 >/dev/null 2>&1; then
+        echo "Creating .typecheck-venv (python3.11)"
+        python3.11 -m venv ../.typecheck-venv || exit 1
+    fi
+fi
 if [ -d ../.typecheck-venv ]; then
 (
     cd .. || exit 1
@@ -39,7 +49,7 @@ if [ -d ../.typecheck-venv ]; then
     .typecheck-venv/bin/basedpyright --pythonpath .typecheck-venv/bin/python
 ) || exit 1
 else
-echo "Skipping the type check: no .typecheck-venv (see CONTRIBUTING.md)."
+echo "Skipping the type check: no .typecheck-venv and no Python 3.11 to create it (see CONTRIBUTING.md)."
 fi
 
 # PostgreSQL upgrade check, as CI runs it, in a throwaway container. Needs

+ 10 - 3
test_frontend.sh

@@ -1,6 +1,6 @@
 #!/bin/sh
 # Typecheck, lint and knip run in parallel (all read-only and independent),
-# then the tests. Exits non-zero if any step fails, so a type or lint error
+# then the tests (with the i18n parity check), then the production build. Exits non-zero if any step fails, so a type or lint error
 # can't scroll past unnoticed behind a green test run.
 
 cd frontend || exit 1
@@ -25,9 +25,16 @@ rm -f /tmp/bambuddy-typecheck.$$ /tmp/bambuddy-lint.$$ /tmp/bambuddy-knip.$$
 npm run test:run
 test_rc=$?
 
+# The production build and its browser baseline check, into a temporary
+# directory: the tracked static/ is only rebuilt on purpose.
+build_dir=$(mktemp -d)
+npx vite build --outDir "$build_dir" --emptyOutDir && node scripts/check-browser-baseline.mjs "$build_dir/assets"
+build_rc=$?
+rm -rf "$build_dir"
+
 cd ..
 
-if [ $typecheck_rc -ne 0 ] || [ $lint_rc -ne 0 ] || [ $knip_rc -ne 0 ] || [ $test_rc -ne 0 ]; then
-    echo "FAILED: typecheck=$typecheck_rc lint=$lint_rc knip=$knip_rc tests=$test_rc"
+if [ $typecheck_rc -ne 0 ] || [ $lint_rc -ne 0 ] || [ $knip_rc -ne 0 ] || [ $test_rc -ne 0 ] || [ $build_rc -ne 0 ]; then
+    echo "FAILED: typecheck=$typecheck_rc lint=$lint_rc knip=$knip_rc tests=$test_rc build=$build_rc"
     exit 1
 fi