Skip to content

test(e2e): three more acceptance properties — depth, refusal, autoscroll - #1109

Merged
mobeenabdullah merged 1 commit into
mainfrom
test/e2e/acceptance-remaining-properties
Aug 19, 2026
Merged

mobeenabdullah merged 1 commit into
mainfrom
test/e2e/acceptance-remaining-properties

Conversation

@mobeenabdullah

@mobeenabdullah mobeenabdullah commented Aug 19, 2026 •

Copy link
Copy Markdown
Collaborator

Takes the canvas acceptance suite from 7 of 12 to 10 of 12. Each property needed a fixture that could express it at all; none needed a change to the canvas.

A1 — collision resolves by tree depth

The fixture gains a core/section holding a text block, so a point is over two containers at once. On a flat document every drop resolves at the root and a canvas ignoring depth entirely passes — which is why this was deferred rather than asserted.

The control drags over a root-level block and requires the answer to be the root, so a canvas that simply always answered "deepest" isn't passing by accident either.

A7 — the invalid-target state

core/columns accepts only core/column — the one structural refusal in the core set. Both halves, because a refusal shown nowhere and one shown everywhere pass each other's test.

Reaching it took two corrections, both measured rather than reasoned:

  • an empty column renders zero pixels tall (top 337, height 0), and a region with no height contains no pointer
  • core/column itself accepts a text block, so anywhere over the column resolves to the column's slot and never meets the restriction — the restriction lives on the row

The row is padded so a band of it isn't covered by its child. That band is the only place the refusal is reachable.

A8 — autoscroll

Needed a document taller than its box. Before, scrollHeight equalled clientHeight, so "it did not scroll" and "there was nowhere to scroll" were the same observation. The test asserts the overflow exists before asserting the scroll, and that the scroll stops at the bound.

The 900px spacer is last on purpose: placed earlier it pushed the nested containers below the fold, where a pointer cannot reach them and a drop over a nested block resolved to nothing at all.

The guard did its job three times

  • Adding nodes broke the population assertions in both specs before any property ran.
  • The taller fixture put five previously-passing tests' drag source below the fold; they now drag from a block above it.
  • A10's hardcoded "original order" list is replaced by a comparison against what it captured, so it can't go stale when the fixture gains a node.

Verification

playwright test canvas/ → 51 passed, exit 0. Lint, e2e typecheck and playground typecheck clean.

A9 and A11 stay deferred with their reasons, printed by every run:

  • A9 needs the canvas to report its geometry reads; counting getBoundingClientRect from the test instruments the page rather than the engine, and the frame-rate half is deliberately not a merge gate.
  • A11 needs the three-tier inserter mounted; with no panel there is no panel drag and the property is vacuously true.

No changeset: test-only.

Summary by CodeRabbit

  • New Features

    • Added expanded canvas scenarios with nested sections, text, columns, and column content.
    • Added coverage for nested-region selection, valid and invalid column drops, and automatic scrolling.
    • Added autoscroll checks for overflow, edge holding, and scroll boundaries.
  • Bug Fixes

    • Improved undo and Escape-cancellation validation.
    • Updated canvas geometry checks to accurately measure root-level spacing.

Takes the canvas suite from seven of twelve to ten. Each needed a fixture that
could express the property at all; none needed a change to the canvas.

## A1 — collision resolves by tree depth

The fixture gains a `core/section` holding a text block, so a point is over two
containers at once. On a flat document every drop resolves at the root and a
canvas ignoring depth entirely passes, which is why this was deferred rather
than asserted. The control drags over a ROOT-level block and requires the answer
to be the root, so a canvas that always answered "deepest" is not passing by
accident either.

## A7 — the invalid-target state

`core/columns` accepts only `core/column`, which is the one structural refusal in
the core set. Two halves, because a refusal shown nowhere and one shown
everywhere pass each other's test.

Reaching it took two corrections, both measured. An EMPTY column renders zero
pixels tall — top 337, height 0 — and a region with no height contains no
pointer. And `core/column` itself accepts a text block, so anywhere over the
column resolves to the COLUMN's slot and never meets the restriction: the
refusal lives on the ROW. The row is padded so a band of it is not covered by
its child, which is the only place the restriction is reachable.

## A8 — autoscroll

Needed a document taller than its box; before, `scrollHeight` equalled
`clientHeight`, so "it did not scroll" and "there was nowhere to scroll" were
the same observation. The test asserts the overflow exists BEFORE asserting the
scroll, and that the scroll stops at the bound.

The 900px spacer is LAST for a reason worth keeping: placed earlier it pushed the
nested containers below the fold, where a pointer cannot reach them and a drop
over a nested block resolved to nothing at all.

## What the manifest guard caught

Adding nodes broke the population assertions in both specs before any property
ran, which is the guard working. It also caught the fixture change breaking five
previously-passing tests: the tall spacer put their drag source below the fold,
so they now drag from a block above it. And A10's hardcoded "original order"
list was replaced by a comparison against what it captured, which cannot go
stale when the fixture gains a node.

A9 and A11 remain deferred with their reasons, printed by every run.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@mobeenabdullah
mobeenabdullah merged commit c29f9e9 into main Aug 19, 2026
9 of 12 checks passed
@coderabbitai

coderabbitai Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6acd45c9-87e0-4ccb-8b37-595885d69e82

📥 Commits

Reviewing files that changed from the base of the PR and between 4b80efd and 8fc09c4.

📒 Files selected for processing (4)
  • apps/playground/src/app/builder-canvas/seed.ts
  • e2e/tests/canvas/acceptance-manifest.ts
  • e2e/tests/canvas/acceptance.spec.ts
  • e2e/tests/canvas/harness-route.spec.ts

📝 Walkthrough

Walkthrough

The canvas fixture now contains nested sections, text, columns, and overflow. Acceptance tests cover nested-region resolution, restricted column drops, undo order, cancellation, and autoscroll. The acceptance manifest marks properties 1, 7, and 8 as covered.

Changes

Canvas acceptance coverage

Layer / File(s) Summary
Expanded canvas fixture
apps/playground/src/app/builder-canvas/seed.ts, e2e/tests/canvas/harness-route.spec.ts
The fixture adds nested section, text, columns, and column content. The spacer height increases to 900px. Geometry checks now use root-level nodes only.
Baseline acceptance updates
e2e/tests/canvas/acceptance.spec.ts
Population, drag, undo, and cancellation checks use the expanded fixture. Undo compares the post-action tree with the captured pre-drag order.
Nested drop and autoscroll acceptance
e2e/tests/canvas/acceptance.spec.ts, e2e/tests/canvas/acceptance-manifest.ts
Tests cover nested-region resolution, valid and invalid column drops, overflow scrolling, and scroll bounds. Acceptance properties 1, 7, and 8 are marked covered.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AcceptanceTests
  participant CanvasHarness
  participant NestedRegionResolver
  participant ColumnsContainer
  participant ScrollContainer
  AcceptanceTests->>CanvasHarness: start drag over seeded content
  CanvasHarness->>NestedRegionResolver: resolve drop region
  NestedRegionResolver->>ColumnsContainer: validate nested drop target
  ColumnsContainer-->>AcceptanceTests: accept or reject drop
  AcceptanceTests->>ScrollContainer: hold drag near bottom edge
  ScrollContainer-->>AcceptanceTests: update scroll position to bound
Loading

Possibly related PRs

  • nextlyhq/nextly#533: Introduced the canvas acceptance fixture and driver behavior extended by these tests.
  • nextlyhq/nextly#736: Expanded related nested-canvas, collision, and autoscroll acceptance coverage.
  • nextlyhq/nextly#795: Introduced related nested columns restrictions and drop behavior.

Suggested labels: scope: ui

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/e2e/acceptance-remaining-properties

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Fallow audit report

Found 37 findings.

Details
Severity Rule Location Description
major fallow/unused-dependency apps/playground/package.json:24 Package '@nextlyhq/adapter-drizzle' is in dependencies but never imported; imported in other workspaces: packages/adapter-mysql, packages/adapter-postgres, packages/adapter-sqlite, packages/nextly
major fallow/unused-dependency apps/playground/package.json:25 Package '@nextlyhq/adapter-mysql' is in dependencies but never imported; imported in other workspaces: packages/nextly
major fallow/unused-dependency apps/playground/package.json:26 Package '@nextlyhq/adapter-postgres' is in dependencies but never imported; imported in other workspaces: packages/nextly
major fallow/unused-dependency apps/playground/package.json:27 Package '@nextlyhq/adapter-sqlite' is in dependencies but never imported; imported in other workspaces: packages/nextly
major fallow/unused-dependency apps/playground/package.json:43 Package 'sharp' is in dependencies but never imported; imported in other workspaces: packages/nextly
minor fallow/unused-dev-dependency apps/playground/package.json:46 Package '@eslint/eslintrc' is in devDependencies but never imported
minor fallow/unused-dev-dependency apps/playground/package.json:55 Package 'better-sqlite3' is in devDependencies but never imported; imported in other workspaces: packages/adapter-sqlite, packages/nextly
minor fallow/unused-dev-dependency apps/playground/package.json:56 Package 'culori' is in devDependencies but never imported; imported in other workspaces: packages/ui
minor fallow/unused-dev-dependency e2e/package.json:19 Package '@nextlyhq/adapter-drizzle' is in devDependencies but never imported; imported in other workspaces: packages/adapter-mysql, packages/adapter-postgres, packages/adapter-sqlite, packages/nextly
minor fallow/unused-dev-dependency e2e/package.json:20 Package '@nextlyhq/adapter-sqlite' is in devDependencies but never imported; imported in other workspaces: packages/nextly
minor fallow/unused-dev-dependency e2e/package.json:24 Package '@nextlyhq/plugin-form-builder' is in devDependencies but never imported; imported in other workspaces: apps/playground
minor fallow/unused-dev-dependency e2e/package.json:25 Package '@nextlyhq/plugin-page-builder' is in devDependencies but never imported; imported in other workspaces: apps/playground
minor fallow/dev-dependency-in-production package.json:93 devDependency '@manypkg/get-packages' is imported by production code at runtime (consider moving to dependencies)
minor fallow/dev-dependency-in-production package.json:105 devDependency 'micromatch' is imported by production code at runtime (consider moving to dependencies)
minor fallow/unused-dev-dependency package.json:107 Package 'publint' is in devDependencies but never imported
major fallow/unused-dependency packages/admin/package.json:110 Package '@lexical/history' is in dependencies but never imported
major fallow/unused-dependency packages/admin/package.json:119 Package '@radix-ui/react-accordion' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:120 Package '@radix-ui/react-alert-dialog' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:121 Package '@radix-ui/react-avatar' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:122 Package '@radix-ui/react-checkbox' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:123 Package '@radix-ui/react-collapsible' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:124 Package '@radix-ui/react-dialog' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:125 Package '@radix-ui/react-dropdown-menu' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:127 Package '@radix-ui/react-popover' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:128 Package '@radix-ui/react-radio-group' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:129 Package '@radix-ui/react-select' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:130 Package '@radix-ui/react-separator' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:132 Package '@radix-ui/react-switch' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:133 Package '@radix-ui/react-tabs' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:134 Package '@radix-ui/react-tooltip' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:140 Package 'cmdk' is in dependencies but never imported; imported in other workspaces: packages/ui
major fallow/unused-dependency packages/admin/package.json:149 Package 'tailwind-variants' is in dependencies but never imported
major fallow/unused-dependency packages/admin/package.json:150 Package 'tailwindcss-animate' is in dependencies but never imported
minor fallow/unused-dev-dependency packages/builder/package.json:68 Package '@nextlyhq/plugin-sdk' is in devDependencies but never imported; imported in other workspaces: apps/playground, packages/plugin-form-builder, packages/plugin-page-builder, packages/plugin-sdk, packages/plugin-seo
major fallow/unused-dependency packages/plugin-page-builder/package.json:54 Package 'isomorphic-dompurify' is in dependencies but never imported; imported in other workspaces: packages/nextly
minor fallow/unused-dev-dependency packages/plugin-page-builder/package.json:61 Package '@tanstack/react-query' is in devDependencies but never imported; imported in other workspaces: packages/admin, packages/plugin-form-builder
major fallow/unused-dependency packages/telemetry/package.json:32 Package 'env-paths' is in dependencies but never imported

Generated by fallow.

@github-actions

Copy link
Copy Markdown
Contributor

PR title fails Conventional Commits check

Unknown scope "e2e" found in pull request title "test(e2e): three more acceptance properties — depth, refusal, autoscroll". Scope must match one of: nextly, admin, admin-css, client, ui, adapter-postgres, adapter-mysql, adapter-sqlite, adapter-drizzle, storage-s3, storage-vercel-blob, storage-uploadthing, blocks-engine, blocks-react, builder, plugin-form-builder, plugin-page-builder, plugin-seo, plugin-sdk, create-nextly-app, eslint-config, eslint-plugin, module-specifiers, prettier-config, tsconfig, telemetry, playground, root, ci, docs, deps, release.

Examples of valid titles:

  • feat(admin): add role manager dialog
  • fix(adapter-postgres): handle connection pool exhaustion
  • chore(deps): bump zod to 4.2.0

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