Skip to content

test: add layout component e2e test cases#372

Open
SonyLeo wants to merge 4 commits into
opentiny:developfrom
SonyLeo:feat/layout-e2e-test
Open

test: add layout component e2e test cases#372
SonyLeo wants to merge 4 commits into
opentiny:developfrom
SonyLeo:feat/layout-e2e-test

Conversation

@SonyLeo

@SonyLeo SonyLeo commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

背景

本次变更补充 Layout 组件的 E2E 测试覆盖。

  • 基础结构与插槽渲染
  • Aside 模式切换、收起、改宽、受控/非受控行为
  • Floating 拖拽、缩放、定位、受控/非受控行为
  • ProxyScrollbar 主区滚动代理行为
  • 对外公开 CSS 变量契约

变更范围

本次仅涉及 packages/test 下的 Layout E2E 测试相关代码,主要包括:

  • packages/test/src/App.vue
  • packages/test/src/layout/index.vue
  • packages/test/src/layout/helpers/*
  • packages/test/src/layout/fixtures/*
  • packages/test/src/layout/specs/*
  • packages/test/package.json

当前覆盖项

当前已覆盖:

  • 结构与插槽渲染
  • Aside 模式、状态、改宽、drawer 遮罩、受控/非受控
  • Floating 模式、placement、拖拽、缩放、边界限制、受控/非受控
  • ProxyScrollbar 滚动同步、thumb 拖拽、动态内容更新
  • Layout 公开 CSS 变量与旧变量保护

用例矩阵

模块 覆盖项 对应用例
结构 header / footer / left-aside / right-aside 插槽渲染 structure.spec.ts
结构 主体结构、主区、左右侧栏稳定识别 structure.spec.ts
结构 Layout.AsideToggle 插槽参数 isOpen structure.spec.ts
结构 class / id / data-* 透传到 surface structure.spec.ts
结构 条件插槽声明省略后不保留空壳和 resize trigger structure.spec.ts
Aside 左右侧栏 dock / drawer 模式切换 aside.spec.ts
Aside 外部 open 受控更新驱动 UI aside.spec.ts
Aside drawer 遮罩打开与关闭 aside.spec.ts
Aside collapseEffect=slide 行为契约 aside.spec.ts
Aside 改宽交互与 aside-resize* 三阶段事件对齐 aside.spec.ts
Aside 双侧展开时主区最小宽度保护 aside.spec.ts
Aside collapsedWidth=0 后完全隐藏 aside.spec.ts
Aside resizable=false 时隐藏 resize trigger aside.spec.ts
Aside 受控 open 但父级不回写时仅发事件、不自改 UI aside.spec.ts
Aside 受控 expandedWidth 但父级不回写时仅发事件、不自改宽度 aside.spec.ts
Aside 非受控 defaultOpen / defaultExpandedWidth 初始化 aside.spec.ts
Aside 非受控收起后保留 rail aside.spec.ts
Aside 初始化后修改 default* 不重新同步 aside.spec.ts
Aside 非受控改宽遵守 min/max 边界 aside.spec.ts
Aside open / expandedWidth = undefined 时回退为非受控语义 aside.spec.ts
Aside drawer 宽度变量生效,双 drawer 保持互斥 aside.spec.ts
Floating normal / floating 模式切换 floating.spec.ts
Floating 5 种 placement 初始定位 floating.spec.ts
Floating floating-drag* 三阶段事件对齐 floating.spec.ts
Floating 可拖拽时位置更新 floating.spec.ts
Floating 外部重置后再次拖拽不使用过期 anchor floating.spec.ts
Floating draggable=false 后禁止拖动 floating.spec.ts
Floating resize 期间 drag bar 临时失去 draggable 状态 floating.spec.ts
Floating resizable=false 后隐藏 7 个 resize handle floating.spec.ts
Floating 7 个方向缩放及 floating-resize* 三阶段事件对齐 floating.spec.ts
Floating 拖拽和缩放结果被限制在视口内 floating.spec.ts
Floating 受控 floatingState 但父级不回写时仅发事件、不自改位置尺寸 floating.spec.ts
Floating 非受控 defaultFloatingState 初始化与交互更新 floating.spec.ts
Floating 初始化后修改 defaultFloatingState 不重新同步 floating.spec.ts
Floating floatingState = undefined 时回退为非受控语义 floating.spec.ts
Floating minWidth / maxWidth 缩放边界约束 floating.spec.ts
主区滚动 scrollTarget 解析真实滚动宿主 main-scrollbar.spec.ts
主区滚动 长列表时代理滚动条显示并与滚动同步 main-scrollbar.spec.ts
主区滚动 拖动 thumb 驱动宿主滚动 main-scrollbar.spec.ts
主区滚动 拖动 thumb 时锁定并恢复 body 交互 main-scrollbar.spec.ts
主区滚动 内容追加后 scrollbar metrics 同步更新 main-scrollbar.spec.ts
主区滚动 内容从不可滚动变为可滚动后自动显示代理滚动条 main-scrollbar.spec.ts
主区滚动 thumb 在下边界不越出轨道 main-scrollbar.spec.ts
CSS 变量 --tr-layout-height / --tr-layout-bg 生效 css-vars.spec.ts
CSS 变量 左右侧栏、头部、主区、底部背景和分隔线变量生效 css-vars.spec.ts
CSS 变量 --tr-layout-main-min-width 生效 css-vars.spec.ts
CSS 变量 drawer 遮罩与 panel shadow 变量生效 css-vars.spec.ts
CSS 变量 --tr-layout-drawer-width 生效 css-vars.spec.ts
CSS 变量 floating 圆角、阴影、层级、背景变量生效 css-vars.spec.ts
CSS 变量 scrollbar 宽度与 thumb 默认/hover/active 变量生效 css-vars.spec.ts
CSS 变量 旧变量不再作为公开契约生效 css-vars.spec.ts

Fixture 对应

AsideStateFixtures.vue

  • 受控 aside 不回写场景
  • 非受控 aside 场景
  • drawer 宽度与互斥场景
  • undefined 回退非受控场景

FloatingStateFixtures.vue

  • 受控 floating 不回写场景
  • 非受控 floating 场景
  • undefined 回退非受控场景
  • placement 初始化场景

LayoutCssVarFixtures.vue

  • 普通布局变量场景
  • 主区最小宽度变量场景
  • 左右 drawer 变量场景
  • floating 变量场景
  • proxy scrollbar 变量场景
  • 旧变量保护场景

自检项

  • 已补充 Layout E2E 测试用例
  • 当前改动仅限测试侧代码
  • 未修改 Layout 组件源码
  • 未引入破坏性变更

是否包含破坏性变更

Summary by CodeRabbit

  • New Features

    • Added a new Layout demo to the test app’s navigation, making layout examples easier to access.
    • Introduced richer layout scenarios covering docked drawers, floating panels, CSS-variable styling, and scrollbars.
  • Bug Fixes

    • Improved layout interaction handling for resizing, dragging, collapsing, and open/closed state updates.
    • Fixed visual and behavioral consistency for main content, backdrops, and scrollbar behavior during content changes.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This PR adds a full Playwright-based E2E test suite for a TrLayout component. It introduces a "Layout" demo route in the test app, a harness page exposing internal state/metrics via a window global, three fixture components exercising aside/floating/CSS-variable scenarios, reusable Playwright test helpers/selectors, and five spec files covering aside, floating, CSS variables, main scrollbar, and structural behavior.

Changes

Layout E2E Test Suite

Layer / File(s) Summary
Demo route wiring
packages/test/src/App.vue
Registers a new Layout navigation entry and maps it to LayoutDemo in the component registry.
Harness page
packages/test/src/layout/index.vue
Implements reactive aside/floating layout state, metrics/log tracking from TrLayout events, and publishes a snapshot to window.__TR_LAYOUT_HARNESS__ for tests to read.
Fixture components
packages/test/src/layout/fixtures/*.vue
Adds fixtures for controlled/uncontrolled aside behavior, floating placement/resize behavior, and CSS-variable-driven layout modes including a scrollbar fixture.
Test helpers & selectors
packages/test/src/layout/helpers/*.ts, packages/test/src/layout/selectors.ts
Adds LayoutTestPage class with navigation, action, assertion, and drag/resize helpers, a fixture-based test wrapper, and a CSS selector map.
Aside spec
packages/test/src/layout/specs/aside.spec.ts
Tests aside mode switching, controlled/uncontrolled state, drawer/backdrop, collapse effects, resizing, and rail behavior.
Floating spec
packages/test/src/layout/specs/floating.spec.ts
Tests floating placement, drag/resize event sequencing, draggable/resizable flags, viewport clamping, and controlled semantics.
CSS variables spec
packages/test/src/layout/specs/css-vars.spec.ts
Tests public CSS variables affecting surface/area styling, drawer, floating styling, scrollbar colors, and a legacy-variable guard.
Scrollbar & structure specs
packages/test/src/layout/specs/main-scrollbar.spec.ts, packages/test/src/layout/specs/structure.spec.ts
Tests scrollbar thumb sync/drag/lock behavior and slot rendering/fallthrough attribute structure.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • opentiny/tiny-robot#364: Introduces the TrLayout component that this PR's test harness, fixtures, and specs directly exercise.

Suggested reviewers: gene9831

Poem

A rabbit hops through aside and drawer,
Testing floats that drag and soar,
Metrics counted, widths in tow,
CSS vars make colors glow,
Specs all green — hooray, let's go! 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding end-to-end test coverage for the Layout component.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@SonyLeo SonyLeo changed the title test: add layout components e2e test cases test: add layout component e2e test cases Jun 30, 2026
@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

✅ Preview build completed successfully!

Click the image above to preview.
Preview will be automatically removed when this PR is closed.

@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

@SonyLeo SonyLeo marked this pull request as ready for review June 30, 2026 04:32
@SonyLeo SonyLeo marked this pull request as draft July 1, 2026 02:43
@SonyLeo SonyLeo force-pushed the feat/layout-e2e-test branch from a8d643e to 9aea032 Compare July 1, 2026 07:12
@SonyLeo SonyLeo marked this pull request as ready for review July 1, 2026 07:19

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (4)
packages/test/src/layout/specs/aside.spec.ts (1)

61-74: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Loose post-resize width assertions could miss a no-op resize.

After an explicit resizeAside('left', 160, ...)/resizeAside('right', -160, ...), the width checks use toBeGreaterThanOrEqual(before...) (lines 71, 86), which would still pass even if the resize produced zero net change. The start/end phase and count assertions (lines 69-70, 72-74, 84-85, 87-89) partially cover this, but a strict bound (or asserting the delta magnitude) would better catch a regression where drag input is registered but width never actually updates.

Also applies to: 76-89

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/test/src/layout/specs/aside.spec.ts` around lines 61 - 74, The
post-resize width checks in aside.spec.ts are too permissive and can pass even
when resize is a no-op. In the resize tests around resizeAside('left', 160) and
resizeAside('right', -160), tighten the assertions on harness.widths.left and
harness.widths.right so they verify an actual size change relative to the
pre-resize values, rather than just using a greater-than-or-equal check. Keep
the existing phase/count checks, but make the width assertion in the resize test
block explicitly validate the expected delta using the resize helpers and
harness.readHarness() results.
packages/test/src/layout/specs/main-scrollbar.spec.ts (1)

30-54: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated drag mechanics.

This test reimplements the down/move/up hover+boundingBox flow that LayoutTestPage.dragBy already encapsulates (see LayoutTestPage.ts:335-348), duplicating logic just to insert a mid-drag assertion. Consider adding a small helper (e.g., pressAndHold/dragBy with an optional callback) to avoid re-deriving drag coordinates here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/test/src/layout/specs/main-scrollbar.spec.ts` around lines 30 - 54,
The scrollbar drag test is duplicating the same hover/bounding-box/mouse down-up
flow already handled by LayoutTestPage.dragBy. Refactor the test to reuse
LayoutTestPage.dragBy, or extend it with a small optional hook/callback so the
mid-drag assertion can run without re-deriving coordinates in
main-scrollbar.spec.ts. Keep the drag mechanics centralized in LayoutTestPage
and only express the assertion-specific behavior in the spec.
packages/test/src/layout/helpers/LayoutTestPage.ts (1)

91-109: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider scoping main, scrollbar, scrollbarThumb, backdrop like their sibling getters.

getAside, getAsideContent, getResizeTrigger, and getBackdrop all accept an optional scope parameter defaulting to this.page, but main/scrollbar/scrollbarThumb/backdrop are hardcoded to this.page. Once multiple TrLayout surfaces are visible simultaneously (aside/floating/css-var fixtures render as siblings, not replacements), these unscoped locators risk matching more than one element and failing Playwright's strict-mode single-match requirement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/test/src/layout/helpers/LayoutTestPage.ts` around lines 91 - 109,
Update the LayoutTestPage locator getters so they can be scoped like the sibling
helpers. The hardcoded page-wide locators in main, scrollbar, scrollbarThumb,
and backdrop should accept an optional scope parameter defaulting to this.page,
matching getAside, getAsideContent, getResizeTrigger, and getBackdrop. Use that
scope when calling locator(...) so LayoutTestPage can target a specific TrLayout
surface and avoid strict-mode multi-match failures.
packages/test/src/layout/specs/floating.spec.ts (1)

206-227: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Manual mouse simulation duplicates drag/resize logic already encapsulated in the helper.

This test bypasses resizeSurface/dragSurface and hand-rolls mouse.move/down/move to inspect mid-gesture state, duplicating positioning/step logic used elsewhere in the file. If mid-gesture inspection is a recurring need, consider exposing a helper (e.g., a startResize/stepResize/endResize sequence on LayoutTestPage) so other specs can assert intermediate states without re-implementing raw mouse mechanics.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/test/src/layout/specs/floating.spec.ts` around lines 206 - 227, The
test in floating.spec.ts is re-implementing raw mouse drag/resize steps instead
of using the existing LayoutTestPage helpers. Refactor the interaction setup
around getFloatingResizeTrigger and the drag bar into reusable helper methods on
LayoutTestPage (for example a start/step/end resize flow, or equivalent
dragSurface/resizeSurface support for mid-gesture assertions), then update this
spec to use that helper so intermediate state checks can be expressed without
duplicating mouse mechanics.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/test/src/layout/fixtures/LayoutCssVarFixtures.vue`:
- Around line 165-179: The scroll target in LayoutCssVarFixtures.vue reuses the
same data-testid as the main layout harness, which causes locator collisions
when both fixtures are mounted together. Update the TrLayout main slot markup
for the scrollbar fixture to use a fixture-specific testid instead of
layout-scroll-target, and keep the ref and TrLayout.ProxyScrollbar wiring intact
so this fixture remains independently addressable.

In `@packages/test/src/layout/helpers/LayoutTestPage.ts`:
- Around line 350-366: The startX calculation in dragResizeHandle is redundant
because both branches of the side ternary are identical. Update the logic in
dragResizeHandle to either remove the conditional if the same edge is always
intended, or make the left and right branches return different starting
positions to match the behavior of dragFloatingResizeHandle and the intended
resize direction.

In `@packages/test/src/layout/selectors.ts`:
- Around line 5-8: The aside content selectors are targeting the outer
`.tr-layout__aside` instead of the nested content wrapper used by the fixture.
Update `leftAsideContent` and `rightAsideContent` in `selectors.ts` to point at
the inner `.layout-demo__aside-content` elements tied to the `left-aside-slot`
and `right-aside-slot` test IDs, or remove the redundant helpers if
`getAsideContent` is not needed.

In `@packages/test/src/layout/specs/aside.spec.ts`:
- Line 267: The drawer toggle interaction in aside.spec.ts is using a synthetic
DOM click via evaluate(...click()), which bypasses Playwright actionability
checks and can hide real occlusion/interactivity issues. Update the drawer
toggle in the relevant test to use the locator’s native click path, matching the
other interactions in this spec (for example the same pattern used around
fixture.getByTestId and related drawer toggles), so the test exercises real
user-visible behavior and fails if the element is not actually clickable.
- Line 67: The test file uses Array.prototype.at(-1), which is not available in
the package’s ES2020 type libs and will break typechecking. Replace the
last-item access in aside.spec.ts with an ES2020-compatible approach such as
slice(-1)[0] at leftEndLog and every other .at(-1) usage in this file, keeping
the existing test logic unchanged.

In `@packages/test/src/layout/specs/floating.spec.ts`:
- Line 146: The floating spec uses Array.prototype.at(-1), but packages/test
only targets ES2020 libs so these calls won’t type-check. Update
floating.spec.ts by either adding the ES2022 array lib in the test tsconfig or
replacing the .at(-1) usages in the affected assertions with ES2020-compatible
last-item access, keeping the references in harness.logs.floatingDrag and the
related log arrays consistent.

---

Nitpick comments:
In `@packages/test/src/layout/helpers/LayoutTestPage.ts`:
- Around line 91-109: Update the LayoutTestPage locator getters so they can be
scoped like the sibling helpers. The hardcoded page-wide locators in main,
scrollbar, scrollbarThumb, and backdrop should accept an optional scope
parameter defaulting to this.page, matching getAside, getAsideContent,
getResizeTrigger, and getBackdrop. Use that scope when calling locator(...) so
LayoutTestPage can target a specific TrLayout surface and avoid strict-mode
multi-match failures.

In `@packages/test/src/layout/specs/aside.spec.ts`:
- Around line 61-74: The post-resize width checks in aside.spec.ts are too
permissive and can pass even when resize is a no-op. In the resize tests around
resizeAside('left', 160) and resizeAside('right', -160), tighten the assertions
on harness.widths.left and harness.widths.right so they verify an actual size
change relative to the pre-resize values, rather than just using a
greater-than-or-equal check. Keep the existing phase/count checks, but make the
width assertion in the resize test block explicitly validate the expected delta
using the resize helpers and harness.readHarness() results.

In `@packages/test/src/layout/specs/floating.spec.ts`:
- Around line 206-227: The test in floating.spec.ts is re-implementing raw mouse
drag/resize steps instead of using the existing LayoutTestPage helpers. Refactor
the interaction setup around getFloatingResizeTrigger and the drag bar into
reusable helper methods on LayoutTestPage (for example a start/step/end resize
flow, or equivalent dragSurface/resizeSurface support for mid-gesture
assertions), then update this spec to use that helper so intermediate state
checks can be expressed without duplicating mouse mechanics.

In `@packages/test/src/layout/specs/main-scrollbar.spec.ts`:
- Around line 30-54: The scrollbar drag test is duplicating the same
hover/bounding-box/mouse down-up flow already handled by LayoutTestPage.dragBy.
Refactor the test to reuse LayoutTestPage.dragBy, or extend it with a small
optional hook/callback so the mid-drag assertion can run without re-deriving
coordinates in main-scrollbar.spec.ts. Keep the drag mechanics centralized in
LayoutTestPage and only express the assertion-specific behavior in the spec.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0ce1a6e7-6891-4c4f-adb0-51541ff5a46b

📥 Commits

Reviewing files that changed from the base of the PR and between 6b17156 and 9aea032.

📒 Files selected for processing (13)
  • packages/test/src/App.vue
  • packages/test/src/layout/fixtures/AsideStateFixtures.vue
  • packages/test/src/layout/fixtures/FloatingStateFixtures.vue
  • packages/test/src/layout/fixtures/LayoutCssVarFixtures.vue
  • packages/test/src/layout/helpers/LayoutTestPage.ts
  • packages/test/src/layout/helpers/index.ts
  • packages/test/src/layout/index.vue
  • packages/test/src/layout/selectors.ts
  • packages/test/src/layout/specs/aside.spec.ts
  • packages/test/src/layout/specs/css-vars.spec.ts
  • packages/test/src/layout/specs/floating.spec.ts
  • packages/test/src/layout/specs/main-scrollbar.spec.ts
  • packages/test/src/layout/specs/structure.spec.ts

Comment thread packages/test/src/layout/fixtures/LayoutCssVarFixtures.vue
Comment thread packages/test/src/layout/helpers/LayoutTestPage.ts Outdated
Comment thread packages/test/src/layout/selectors.ts Outdated
Comment thread packages/test/src/layout/specs/aside.spec.ts Outdated
Comment thread packages/test/src/layout/specs/aside.spec.ts Outdated
Comment thread packages/test/src/layout/specs/floating.spec.ts Outdated
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