From a956fffa5aa81725de3c29da33d2c93e4ce733c3 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Sat, 21 Feb 2026 13:20:41 -0500 Subject: [PATCH 1/5] ci: split into source tests and wheel-based integration tests Restructure CI into two tiers: Source-level tests (no deps, run immediately): - LintPython, TestPython (unit + storybook), TestPythonMaxVersions Integration tests (needs: BuildJS, install the wheel): - TestServer, TestMarimo, TestWASMMarimo These simulate end-user experience: install the pre-built wheel into a clean(ish) environment, no source code. BuildJS builds the wheel once and caches it (keyed on SHA) via actions/cache/save. Integration jobs restore from Depot's fast cache and install with uv pip install --force-reinstall dist/*.whl. Server tests extracted from TestPython into their own TestServer job since they already create a clean venv and install the wheel. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/ci.yml | 217 ++++++++++++++++++++++++++++++--------- 1 file changed, 171 insertions(+), 46 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ea56d2275..9c7022cad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,52 @@ jobs: - name: Run ruff run: uv run ruff check + BuildWheel: + name: Build JS + Python Wheel + runs-on: depot-ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: "3.13" + prune-cache: false + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.10.0 + - name: Setup Node.js with pnpm cache + uses: actions/setup-node@v4 + with: + cache: 'pnpm' + cache-dependency-path: 'packages/pnpm-lock.yaml' + - name: Install pnpm dependencies + working-directory: packages + run: pnpm install --frozen-lockfile + - name: Install the project + run: uv sync --all-extras --dev + - name: Build JS extension + Python wheel + run: ./scripts/full_build.sh + - name: Run Jest tests + run: | + cd packages/buckaroo-js-core + pnpm install && pnpm run build + pnpm run test + - name: Cache built wheel and JS + uses: actions/cache/save@v4 + with: + path: | + ./dist + ./buckaroo/static/ + ./packages/buckaroo-js-core/dist/ + ./packages/buckaroo-widget/dist/ + key: buckaroo-build-${{ github.sha }} + + # --------------------------------------------------------------------------- + # Source-level tests — operate on the codebase, no wheel needed + # --------------------------------------------------------------------------- + TestPython: name: Python / Test runs-on: ${{ matrix.os }} @@ -37,14 +83,9 @@ jobs: fail-fast: false matrix: python-version: - # - "3.8" #other conflicts - #- "3.9" - #- "3.10" - "3.11" - "3.12" - "3.13" - #- "3.14 - #os: [depot-ubuntu-latest#, depot-windows-2025] os: [depot-ubuntu-latest] steps: - uses: actions/checkout@v4 @@ -79,7 +120,7 @@ jobs: run: | uv run --with pytest-cov pytest ./tests/unit --color=yes --cov anywidget --cov-report xml - uses: codecov/codecov-action@v5 - - name: Test the JS extension + - name: Build JS extension run: | ./scripts/full_build.sh cd packages/buckaroo-js-core @@ -97,20 +138,6 @@ jobs: run: | bash scripts/test_playwright_screenshots.sh - - name: Run Server Playwright Tests - run: | - bash scripts/test_playwright_server.sh - - - name: Run Marimo Playwright Tests - continue-on-error: true - run: | - bash scripts/test_playwright_marimo.sh - - - name: Run WASM Marimo Playwright Tests - continue-on-error: true - run: | - bash scripts/test_playwright_wasm_marimo.sh - - name: Upload Theme Screenshots if: matrix.python-version == '3.13' && always() uses: actions/upload-artifact@v4 @@ -119,32 +146,6 @@ jobs: path: packages/buckaroo-js-core/screenshots/ if-no-files-found: ignore - # - name: Run JupyterLab Playwright Tests - # run: | - # # Ensure uv environment is set up - # uv sync --all-extras --group dev - - # # Install the built buckaroo wheel - # uv pip install --force-reinstall dist/*.whl - - # # Install test dependencies (polars, jupyterlab) - # uv pip install polars jupyterlab - - # # Detect venv location (uv sync creates .venv by default, but check if it exists) - # if [ -d ".venv" ]; then - # VENV_LOCATION=".venv" - # else - # # Fallback: try to detect from uv's Python environment - # VENV_LOCATION=$(uv run python -c "import sys; print(sys.prefix)" 2>/dev/null || echo ".venv") - # fi - - # # Run the integration test script with venv location - # bash scripts/test_playwright_jupyter.sh --venv-location="$VENV_LOCATION" - # env: - # UV_PYTHON: ${{ matrix.python-version }} - - - TestPythonMaxVersions: name: Python / Test (Max Versions) runs-on: depot-ubuntu-latest @@ -203,3 +204,127 @@ jobs: # Use .venv/bin/python directly to avoid uv run re-syncing .venv/bin/python -m pytest ./tests/unit --color=yes --cov anywidget --cov-report xml + # --------------------------------------------------------------------------- + # Integration tests — install the pre-built wheel, simulate end-user install + # --------------------------------------------------------------------------- + + TestServer: + name: Server Playwright Tests + needs: [BuildWheel] + runs-on: depot-ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: "3.13" + prune-cache: false + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.10.0 + - name: Setup Node.js with pnpm cache + uses: actions/setup-node@v4 + with: + cache: 'pnpm' + cache-dependency-path: 'packages/pnpm-lock.yaml' + - name: Install pnpm dependencies + working-directory: packages + run: pnpm install --frozen-lockfile + - name: Restore built wheel and JS + uses: actions/cache/restore@v4 + with: + path: | + ./dist + ./buckaroo/static/ + ./packages/buckaroo-js-core/dist/ + ./packages/buckaroo-widget/dist/ + key: buckaroo-build-${{ github.sha }} + - name: Run Server Playwright Tests + run: | + bash scripts/test_playwright_server.sh + + TestMarimo: + name: Marimo Playwright Tests + needs: [BuildWheel] + runs-on: depot-ubuntu-latest + continue-on-error: true + steps: + - uses: actions/checkout@v4 + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: "3.13" + prune-cache: false + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.10.0 + - name: Setup Node.js with pnpm cache + uses: actions/setup-node@v4 + with: + cache: 'pnpm' + cache-dependency-path: 'packages/pnpm-lock.yaml' + - name: Install pnpm dependencies + working-directory: packages + run: pnpm install --frozen-lockfile + - name: Restore built wheel and JS + uses: actions/cache/restore@v4 + with: + path: | + ./dist + ./buckaroo/static/ + ./packages/buckaroo-js-core/dist/ + ./packages/buckaroo-widget/dist/ + key: buckaroo-build-${{ github.sha }} + - name: Install the project + run: uv sync --all-extras --dev + - name: Install built wheel + run: uv pip install --force-reinstall dist/*.whl + - name: Run Marimo Playwright Tests + run: | + bash scripts/test_playwright_marimo.sh + + TestWASMMarimo: + name: WASM Marimo Playwright Tests + needs: [BuildWheel] + runs-on: depot-ubuntu-latest + continue-on-error: true + steps: + - uses: actions/checkout@v4 + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + python-version: "3.13" + prune-cache: false + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.10.0 + - name: Setup Node.js with pnpm cache + uses: actions/setup-node@v4 + with: + cache: 'pnpm' + cache-dependency-path: 'packages/pnpm-lock.yaml' + - name: Install pnpm dependencies + working-directory: packages + run: pnpm install --frozen-lockfile + - name: Restore built wheel and JS + uses: actions/cache/restore@v4 + with: + path: | + ./dist + ./buckaroo/static/ + ./packages/buckaroo-js-core/dist/ + ./packages/buckaroo-widget/dist/ + key: buckaroo-build-${{ github.sha }} + - name: Install the project + run: uv sync --all-extras --dev + - name: Install built wheel + run: uv pip install --force-reinstall dist/*.whl + - name: Run WASM Marimo Playwright Tests + run: | + bash scripts/test_playwright_wasm_marimo.sh From 8721c08af3c7c1dc604aa3a33139516e10064393 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Sat, 21 Feb 2026 13:52:32 -0500 Subject: [PATCH 2/5] ci: split into source tests and wheel-based integration tests Restructure CI into two tiers: Source-level tests (no deps, run immediately): - LintPython, TestPython (unit + storybook), TestPythonMaxVersions Integration tests (needs: BuildWheel, install the wheel): - TestServer, TestMarimo, TestWASMMarimo These simulate end-user experience: install the pre-built wheel into a clean(ish) environment, no source code. BuildWheel builds the wheel once and caches it (keyed on SHA) via actions/cache/save. Integration jobs restore from Depot's fast cache and install with uv pip install --force-reinstall dist/*.whl. Server tests extracted from TestPython into their own TestServer job. Also fix marimo notebook: rename duplicate `widget` variable to `_widget` (private) to satisfy marimo's unique-variable-per-cell rule. Co-Authored-By: Claude Opus 4.6 --- tests/notebooks/marimo_pw_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/notebooks/marimo_pw_test.py b/tests/notebooks/marimo_pw_test.py index cdc4e1257..07bf3a1bd 100644 --- a/tests/notebooks/marimo_pw_test.py +++ b/tests/notebooks/marimo_pw_test.py @@ -31,8 +31,8 @@ def _(BuckarooWidget, pd): 'age': [30, 25, 35, 28, 32], 'score': [88.5, 92.3, 76.1, 95.0, 81.7], }) - widget = BuckarooWidget(small_df) - return small_df, widget + _widget = BuckarooWidget(small_df) + return small_df, _widget @app.cell @@ -47,8 +47,8 @@ def _(BuckarooInfiniteWidget, pd): for i in range(200): rows.append({'id': i, 'value': i * 10, 'label': f'row_{i}'}) large_df = pd.DataFrame(rows) - widget = BuckarooInfiniteWidget(large_df) - return large_df, rows, widget + _widget = BuckarooInfiniteWidget(large_df) + return large_df, rows, _widget @app.cell From db6c0c2e213390548e3f1d5cba0a57eb55af4d9e Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Sat, 21 Feb 2026 14:17:21 -0500 Subject: [PATCH 3/5] ci: remove uv pip install --force-reinstall from marimo test jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The marimo playwright config runs `uv run marimo run ...`, which re-syncs the environment and undoes the wheel install, leaving things broken. The cached static files from BuildWheel + uv sync (editable) is sufficient — matches how marimo tests worked in the old TestPython. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c7022cad..7ecdb059c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -281,8 +281,6 @@ jobs: key: buckaroo-build-${{ github.sha }} - name: Install the project run: uv sync --all-extras --dev - - name: Install built wheel - run: uv pip install --force-reinstall dist/*.whl - name: Run Marimo Playwright Tests run: | bash scripts/test_playwright_marimo.sh @@ -323,8 +321,6 @@ jobs: key: buckaroo-build-${{ github.sha }} - name: Install the project run: uv sync --all-extras --dev - - name: Install built wheel - run: uv pip install --force-reinstall dist/*.whl - name: Run WASM Marimo Playwright Tests run: | bash scripts/test_playwright_wasm_marimo.sh From 2c6722fb83a65ffad7429c60be3ad9049474db6a Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Sat, 21 Feb 2026 14:31:56 -0500 Subject: [PATCH 4/5] ci: tighten marimo/wasm playwright timeouts and retries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marimo: 60s→30s timeout, 2→1 retries (was 3×60s=180s worst case per test) WASM: 90s→60s timeout, 1→0 retries, inner waits 90s→60s and 30s→15s If it fails early, no point waiting around for retries. Co-Authored-By: Claude Opus 4.6 --- packages/buckaroo-js-core/playwright.config.marimo.ts | 4 ++-- packages/buckaroo-js-core/playwright.config.wasm-marimo.ts | 6 +++--- packages/buckaroo-js-core/pw-tests/wasm-marimo.spec.ts | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/buckaroo-js-core/playwright.config.marimo.ts b/packages/buckaroo-js-core/playwright.config.marimo.ts index 8d129f0a1..0ddbd086b 100644 --- a/packages/buckaroo-js-core/playwright.config.marimo.ts +++ b/packages/buckaroo-js-core/playwright.config.marimo.ts @@ -7,7 +7,7 @@ export default defineConfig({ testMatch: ['marimo.spec.ts', 'theme-screenshots-marimo.spec.ts'], fullyParallel: false, forbidOnly: !!process.env.CI, - retries: process.env.CI ? 2 : 0, + retries: process.env.CI ? 1 : 0, workers: 1, reporter: 'html', use: { @@ -15,7 +15,7 @@ export default defineConfig({ trace: 'on-first-retry', ...devices['Desktop Chrome'], }, - timeout: 60_000, + timeout: 30_000, projects: [ { diff --git a/packages/buckaroo-js-core/playwright.config.wasm-marimo.ts b/packages/buckaroo-js-core/playwright.config.wasm-marimo.ts index 0e98a733a..a90e11b37 100644 --- a/packages/buckaroo-js-core/playwright.config.wasm-marimo.ts +++ b/packages/buckaroo-js-core/playwright.config.wasm-marimo.ts @@ -11,7 +11,7 @@ export default defineConfig({ testMatch: ['wasm-marimo.spec.ts'], fullyParallel: false, forbidOnly: !!process.env.CI, - retries: process.env.CI ? 1 : 0, + retries: 0, workers: 1, reporter: 'html', use: { @@ -19,8 +19,8 @@ export default defineConfig({ trace: 'on-first-retry', ...devices['Desktop Chrome'], }, - // Longer timeout for WASM: Pyodide initialization can be slow (15-30s) - timeout: 90_000, + // Pyodide init can take 15-30s, plus widget render + timeout: 60_000, projects: [ { diff --git a/packages/buckaroo-js-core/pw-tests/wasm-marimo.spec.ts b/packages/buckaroo-js-core/pw-tests/wasm-marimo.spec.ts index f3e0d89e8..2fc58249e 100644 --- a/packages/buckaroo-js-core/pw-tests/wasm-marimo.spec.ts +++ b/packages/buckaroo-js-core/pw-tests/wasm-marimo.spec.ts @@ -16,8 +16,8 @@ test.describe('Buckaroo in Marimo WASM (Pyodide)', () => { sharedPage = await browser.newPage(); await sharedPage.goto('/'); // Wait for Pyodide init + buckaroo widget + AG-Grid render - await sharedPage.locator('.buckaroo_anywidget').first().waitFor({ state: 'visible', timeout: 90_000 }); - await sharedPage.locator('.ag-cell').first().waitFor({ state: 'visible', timeout: 30_000 }); + await sharedPage.locator('.buckaroo_anywidget').first().waitFor({ state: 'visible', timeout: 60_000 }); + await sharedPage.locator('.ag-cell').first().waitFor({ state: 'visible', timeout: 15_000 }); }); test.afterAll(async () => { From 7467b145bf235a6bb9701c2b830a154b7e6bc98f Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Sat, 21 Feb 2026 14:50:24 -0500 Subject: [PATCH 5/5] fix: rename marimo widget vars to unique non-private names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _widget (underscore prefix) is private in marimo and won't display as cell output. Use small_widget/large_widget instead — unique across cells and visible so the widgets actually render. Co-Authored-By: Claude Opus 4.6 --- tests/notebooks/marimo_pw_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/notebooks/marimo_pw_test.py b/tests/notebooks/marimo_pw_test.py index 07bf3a1bd..f7f4f5b19 100644 --- a/tests/notebooks/marimo_pw_test.py +++ b/tests/notebooks/marimo_pw_test.py @@ -31,8 +31,8 @@ def _(BuckarooWidget, pd): 'age': [30, 25, 35, 28, 32], 'score': [88.5, 92.3, 76.1, 95.0, 81.7], }) - _widget = BuckarooWidget(small_df) - return small_df, _widget + small_widget = BuckarooWidget(small_df) + return small_df, small_widget @app.cell @@ -47,8 +47,8 @@ def _(BuckarooInfiniteWidget, pd): for i in range(200): rows.append({'id': i, 'value': i * 10, 'label': f'row_{i}'}) large_df = pd.DataFrame(rows) - _widget = BuckarooInfiniteWidget(large_df) - return large_df, rows, _widget + large_widget = BuckarooInfiniteWidget(large_df) + return large_df, rows, large_widget @app.cell