Skip to content

Test coverage that replaces manual testing (plan 005) - #7

Draft
hatton wants to merge 11 commits into
masterfrom
more-e2e-tests
Draft

Test coverage that replaces manual testing (plan 005)#7
hatton wants to merge 11 commits into
masterfrom
more-e2e-tests

Conversation

@hatton

@hatton hatton commented Sep 6, 2026

Copy link
Copy Markdown
Member

Problem

bloom-table is about to ship inside Bloom, and until now a release needed a manual pass through the editor. Twelve source modules had no unit tests, no CI ran any suite on push, and the Playwright specs covered only a handful of flows. A regression in a menu command, a drag handle, the saved HTML, or the published bundle could reach Bloom without any test noticing.

What the PR does

  • Adds a GitHub Actions workflow that runs typecheck, unit tests with coverage thresholds, the build, the package smoke test, and the Playwright suite on every push and pull request.
  • Adds unit tests for the twelve modules that had none, one table-driven test that runs every Row, Column, Table and Cell menu item once, and tests for the React panel. Unit tests grow from 532 to 1031; statement coverage rises from 83.5% to 89.7%, and the thresholds now enforce it.
  • Adds ten Playwright specs on the UI harness: drag to resize, the cell menu, every pill-menu item clicked where the browser draws it, save round trip, text editing, a scrolling container, host-injected table api and color picker, row growth, container narrowing, and visual snapshots of every sample and fixture.
  • Adds a smoke test of the built package: it imports dist/bloom-table.mjs, edits a table through it, checks React and MUI stay external, and snapshots the exported names.
  • Fixes three defects the new tests and the reviewers found: the gap sliders were not undoable, Undo of a gap drag kept the painted spacing, and the React panel did not disable Delete Row and Delete Column on a one-row or one-column table.
  • Records two known gaps as test.fixme for plan 004: a nested table's rows do not grow with their text, and a table does not refit when its container narrows.

Plan: plans/005-test-coverage-for-shipping.md.


Devin review

hatton and others added 9 commits September 5, 2026 16:30
Nothing ran either suite automatically, so a release depended on someone
remembering three commands. Several e2e specs also passed while proving
nothing: one asserted on a literal object it had just written, two logged
their findings and asserted only that a table exists, and the undo test was
skipped with a comment that undo is unsupported, which it no longer is.

A GitHub Actions workflow now runs typecheck, the unit suite and the
Playwright suite on every push and pull request, and uploads the Playwright
report on failure. The screenshot baselines are all -chromium-win32 and this
machine cannot render the Linux ones, so playwright.config.ts ignores
snapshots when CI is set; the plan records the debt.

@vitest/coverage-v8 is installed at the version vite-plus bundles, with a
test:coverage script and thresholds a point below the measured baseline of
83.52 statements, 72.56 branches, 81.89 functions, 86.52 lines. coverage.include
names src/** instead of excluding demo/ and tests/, because an exclude pattern
is matched against the absolute path and a checkout directory whose name ends
in "tests" then excludes the whole tree and reports zero of zero.

Every spec now takes test and expect from tests/e2e/utils/strict-page.ts,
which fails a test that produced a pageerror or a console.error. A silent
exception was invisible before.

resize-rows-and-columns.spec.ts keeps one real page.mouse row drag and gains
the undo test, which now runs through the history manager the harness
publishes. borders-changing.spec.ts drops "(BUG)" from titles that describe
behaviour that works. table-menu.spec.ts waits on conditions instead of
26 fixed delays. Local retries go from 0 to 1, so a flake reports as flaky.

Unit tests: 532 in 37 files. End-to-end: 65, none skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Phase 1 of plans/005-test-coverage-for-shipping.md. Each module named there
gains one test file beside it, written against what a caller of the module can
see rather than against how it works.

The two React context files carry the tests that matter most to Bloom, which
renders the panel in a different realm from the tables: defaultTableApi maps
each member to the function it wraps and carries nothing the interface does not
name, an injected api decides what the panel does, and an injected colour
picker replaces the built-in one and receives each control's label.

Three assertions in menu-widgets.test.ts read the box around a diagonal rather
than the diagonal itself, because the happy-dom CSS parser drops a
linear-gradient containing calc(). The drawn line stays covered by the e2e
screenshots.

Coverage rises to 84.42 statements, 73.54 branches, 83.51 functions and 87.32
lines, and the four thresholds move to one point below each.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Phase 2 of plans/005-test-coverage-for-shipping.md. One data table lists all
ninety-six controls the three pill menus render: the label the popup shows, the cell
the case selects, the model the item must change, how many undo entries it must
add, and the condition under which it renders disabled. Each item runs twice,
against a top-level table and against a nested one, and the nested run also
checks that the outer table comes through untouched. A completeness test
compares the labels each popup renders with the labels described here, so an
item added later fails until it is described.

The two spacing sliders in the Table menu are it.fails: they write data-gap-x
and data-gap-y with no history entry, so they cannot be undone while every
other item can.

table-size-buttons.test.ts gains the geometry the add previews and the
affordances are placed by, and the clamp that keeps a menu opened near the
window's edge inside it.

Coverage rises to 87.23 statements, 75.51 branches, 87.71 functions and 90.36
lines, and the four thresholds move to one point below each.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The two spacing sliders in the Table menu wrote data-gap-x and data-gap-y
straight into the table, so Ctrl+Z after moving one reverted an earlier
operation and left the new spacing in place.

A range input reports every step of a drag, and one history entry per step
would be as bad as none. So the slider row now also reports the end of a
gesture, and the spacing sliders write freely while the thumb moves and record
a single entry when the pointer is released, whose snapshot is the table as it
stood before the drag began. A drag that ends where it started records nothing.

Playwright addressed the dev server as localhost, which resolves to ::1 first.
Another checkout's dev server bound there answers 404 for the harness page, so
the probe timed out and the suite never started. It names 127.0.0.1 now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four new files cover the panel section by section: each Row, Column and Cell
control, and the border selector on its own. The panel reaches a table only
through the injected TableApi, so a BloomTable subclass that notes each call
and then does the real work shows which method ran and with which index.

Two end-to-end checks only ever read a menu button's title, which happy-dom
answers just as well. They move down beside the components, and the spec that
held nothing else is gone. What is left in e2e is the dashed border a real
browser has to compute.

Two it.fails record a defect: the panel never disables Delete Row on a one-row
table, or Delete Column on a one-column table, so the click reaches removeRowAt
or removeColumnAt and throws. The pill menu guards both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Delete Row and Delete Column buttons stayed enabled on a table that had
nothing left to give. The click reached removeRowAt or removeColumnAt, whose
assertion threw out of the React handler. The pill menu has always disabled
both commands in that state.

The buttons carry the assertion's own wording as their tooltip, because the
panel had no text of its own for it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ten new specs on the UI harness, each taking library objects from
window.bloomTableTestHooks: drag-resize, cell-menu, pill-menus,
save-round-trip, text-editing, scroll-container, host-injection,
row-growth, container-narrowing and visual-samples. The pill-menus spec
clicks every Row, Column and Table item where the browser draws it and
checks one undo step each; the menu labels move to
src/test-support/menu-item-labels.ts so the unit suite and the e2e
suite read one list. The harness publishes removeTableEditingArtifacts,
setContent and a stub-api call log, and mounts a stub table api and
color picker under ?stubs=1. The visual-samples spec snapshots every
sample and fixture through tests/samples/_harness.html at 1000x800.

Two test.fixme cases record known gaps for plan 004: a nested table's
rows do not grow with their text, and a table does not refit when its
container narrows.

resize-rows-and-columns.spec.ts and undo-resize-column.spec.ts are
replaced by drag-resize.spec.ts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
tests/package/dist-smoke.test.ts imports the built bundle, attaches a
table, adds a row and undoes it, checks the three stylesheets exist,
checks React, React DOM and MUI stay external, and snapshots the 61
exported names from the type file. It runs under its own vitest config
(vite.package.config.ts, `pnpm test:package`) so `pnpm test` does not
need dist. CI builds and runs it after the unit tests.

Coverage thresholds rise to 89/78/91/92 (statements, branches,
functions, lines).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The workflow pinned Node 22.12 and the runner failed before the install
step: pnpm 11.0.3 refuses Node earlier than 22.13. The engines field and
the toolchain note now say the same.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Sep 6, 2026

Copy link
Copy Markdown

Greptile Summary

This PR substantially expands unit, browser, package, and visual test coverage, introduces a CI workflow, and adjusts production behavior for undoable gap sliders and single-row/single-column deletion.

  • Adds unit coverage across previously untested model, menu, context, and React component modules.
  • Adds end-to-end coverage for editing, resizing, menu actions, host injection, scrolling, persistence, and visual fixtures.
  • Adds built-package smoke tests and coverage thresholds.
  • Fixes panel deletion availability and attempts to make gap-slider changes undoable.
  • The gap-slider undo implementation retains the changed visual spacing, while CI currently omits coverage enforcement and screenshot comparisons.

Security Review

The new CI workflow references GitHub Actions through mutable major-version tags. Pinning the actions to reviewed full commit SHAs would prevent later tag movement from changing the code executed by CI.

Important Files Changed

Filename Overview
src/table-size-buttons.ts Adds history-backed spacing sliders, but the pre-operation snapshot retains the newly rendered inline gap and produces an incomplete visual undo.
src/menu-widgets.ts Adds an optional range-input commit callback used to distinguish live updates from completed gestures.
src/components/RowSection.tsx Correctly disables row deletion when the canonical table metadata reports only one row.
src/components/ColumnSection.tsx Correctly disables column deletion when the canonical table metadata reports only one column.
.github/workflows/ci.yml Adds broad CI execution, but omits the coverage command and uses mutable action tags.
playwright.config.ts Improves local retry behavior and server addressing but disables all screenshot assertions in CI.
demo/ui-harness.tsx Adds host-injection and persistence hooks, though its synchronous two-update reset cannot force an equal-content remount under React batching.
tests/package/dist-smoke.test.ts Adds useful consumer-facing checks for bundle behavior, stylesheets, external dependencies, and exported API declarations.
vite.config.ts Defines focused source coverage and explicit thresholds, which are effective when the coverage-specific command is run.
tests/e2e/visual-samples.spec.ts Adds comprehensive fixture and sample screenshots, but their assertions are globally skipped by CI configuration.

Reviews (1): Last reviewed commit: "Test the package as Bloom receives it (p..." | Re-trigger Greptile

Comment thread src/table-size-buttons.ts
Comment thread demo/ui-harness.tsx
Comment thread .github/workflows/ci.yml
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 security Actions use mutable tags

The workflow executes checkout, pnpm setup, Node setup, and artifact upload through mutable major-version tags. If an upstream tag is repointed after a compromise, that code can run inside this repository’s CI with the workflow token’s configured access. Pin each action, including the third-party pnpm setup action, to a reviewed full commit SHA.

How this was verified: Each newly introduced uses entry references a mutable @v4 tag and the workflow provides no immutable commit reference.

…erage

When a spacing drag ended, the slider put the data attribute back before
the history entry captured the table, but not the inline gap the render
had painted from the dragged value. The snapshot therefore kept the
dragged spacing and Undo left the table visibly spaced. The slider now
renders the pre-drag state before the entry captures it, and the unit
test checks the painted style as well as the attribute.

CI runs the unit tests with coverage, so the thresholds in
vite.config.ts fail the run instead of only the local report.

The harness's setContent hook remounts MainContent through a key, so
markup equal to the current content still mounts fresh.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment thread playwright.config.ts
// The screenshot baselines in *-snapshots/ are all "-chromium-win32". Linux
// renders different fonts, and no Linux baseline exists yet, so a CI run
// compares nothing rather than failing on every snapshot.
ignoreSnapshots: !!process.env.CI,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Devin] Investigate: Linux visual regressions remain unchecked

CI disables every screenshot comparison through ignoreSnapshots. The new visual suite therefore provides no automated regression gate until Linux baselines are committed.

(playwright.config.ts:11. The baselines in the repo were taken on Windows; a Linux runner renders fonts differently, so the comparison is off on CI until Linux baselines exist.)

@hatton

hatton commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

[Claude Fable 5.1 from Hatton's machine during preflight] Consulted Devin on 2026-09-05 up to commit e956d2f. Devin raised two bugs, both fixed in e956d2f (Undo of a spacing drag kept the painted gap; CI ran the unit tests without coverage so the thresholds never applied), and one Investigate flag about screenshot comparison being off on CI, which is mirrored as a review thread and waits for a decision. CI is green.

With one local retry, a new sample or fixture wrote its baseline on the
first attempt, failed, and passed on the retry. The run reported flaky
and exited 0, so an unreviewed baseline landed green.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@hatton

hatton commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

[Claude Fable 5.1 from Hatton's machine during preflight] Consulted Devin on 2026-09-05 up to commit 34c6329. Devin repeated the two bugs that e956d2f already fixes and the open Investigate flag about screenshot comparison on CI; nothing new. CI is green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant