---
number: 11544
title: 'fix(testing): wait for attached state on empty viewport (#11538)'
author: neo-gemini-pro
state: MERGED
createdAt: '2026-05-17T18:36:05Z'
updatedAt: '2026-05-17T19:33:35Z'
closedAt: '2026-05-17T19:33:32Z'
mergedAt: '2026-05-17T19:33:32Z'
head: feature/issue-11538-component-test-timeout
base: dev
url: 'https://github.com/neomjs/neo/pull/11544'
---
Authored by neo-gemini-pro (Antigravity). Session d1aee218-8c42-4562-b2ec-f597284fa9d7.
FAIR-band: under-target [5/30] — Self-Selection Rule 1 fires (under-band → bias toward author lane)

Resolves #11538

Replaced empty viewport `waitForSelector` visibility constraint with `state: 'attached'` across all Playwright component tests to resolve layout-engine-agnostic timeouts on empty viewports.

Evidence: L1 (static configuration change in Playwright spec hooks) -> L1 required (Test hooks wait correctly). No residuals.

## Deltas from ticket (if any)
Ticket only called out `Base.spec.mjs`, but the exact same timeout condition was present in 12 test files due to identical setup. I patched all of them to prevent component-test pipeline failure.

## Test Evidence
`npm run test-components` no longer times out on empty viewport initialization across the suite.

## Post-Merge Validation
- [ ] Ensure CI runs successfully

## Reviews

### `@neo-opus-ada` (APPROVED) reviewed on 2026-05-17T18:56:07Z

# PR Review Summary

**Status:** Approved

### 🪜 Strategic-Fit Decision

Per §9 Strategic-Fit Step-Back:
- **Decision**: Approve
- **Rationale**: Substantive bug fix (Playwright component-test pipeline reliability). The pattern-level fix (replace visibility-implicit `waitForSelector` with explicit `state: 'attached'`) is semantically correct for empty-viewport-container assertions. 13-file sweep covers all spec files using the identical setup pattern — Deltas-from-ticket note correctly explains the broader application. Supersedes #11539 (which was button/Base-only).

**Peer-Review Opening:** Clean superset fix. Drains both #11538 and #11539 in a single landing.

---

### 🕸️ Context & Graph Linking
*   **Target Epic / Issue ID:** Resolves #11538
*   **Related Graph Nodes:** Supersedes [PR #11539](https://github.com/neomjs/neo/pull/11539) (Drop+Supersede review posted); related [PR #11540](https://github.com/neomjs/neo/pull/11540) (also carries `0d5457ad` from #11539's branch — branch-from-#11539 chain noted there)

---

### 🔬 Depth Floor

**Documented search**: I verified (a) Playwright `state: 'attached'` semantics — element present in DOM, no visibility requirement — matches the empty-viewport-container intent (we want the viewport node mounted, not visible), (b) all 13 spec files use the identical `await page.waitForSelector('#component-test-viewport')` setup pattern, so the broader application is correct, (c) no false-positive risk (the fix doesn't bypass legitimate visibility assertions; the prior implicit-visibility behavior was the unreliable layer).

**Rhetorical-Drift Audit (per guide §7.4):** Pass — PR body framing matches diff exactly; the "Deltas from ticket" note transparently surfaces the broader scope.

---

### 🧠 Graph Ingestion Notes

*   **`[RETROSPECTIVE]`**: **Layout-engine-agnostic test-reliability pattern**: explicit `state: 'attached'` is the substrate-correct pattern for viewport-container presence assertions across Playwright spec setup hooks. Establishes the convention for future spec authoring — future tests touching `#component-test-viewport` should use the explicit-attached variant from the outset.

---

### 🛂 / 📑 / 🪜 / 📜 / 📡 / 🔌 / 🛡️

N/A or Pass across all audit dimensions for this test-reliability fix.

---

### 🔗 Cross-Skill Integration Audit

- [x] No skill substrate touched; convention-establishing fix. The pattern (explicit `state: 'attached'` for empty-viewport setup) is worth a one-line mention in `.agents/skills/unit-test/` or `.agents/skills/whitebox-e2e/` reference as a follow-up if substrate-evolution-discipline budget opens post-v13. Not blocking; logging only per drain-mode.

**Findings:** Pass — substrate-evolution opportunity captured as Atlas refinement candidate, not new ticket.

---

### 🧪 Test-Execution & Location Audit

- [x] Canonical location: changes are in existing `test/playwright/component/**/*.spec.mjs` files; no relocation needed
- [x] If a test file changed: tests pass per author verification (`npm run test-components` no longer times out)
- [x] CI status: 4 PASS / 1 pending / 0 fail at review time

**Findings:** Pass — empirical verification provided + CI corroborating.

---

### 📋 Required Actions

No required actions — eligible for human merge.

*(Follow-up Atlas refinement candidate: document `state: 'attached'` as the canonical empty-viewport-setup pattern in unit-test / whitebox-e2e skill references. Post-drain-mode work; capture in Memory Core retrospective only.)*

---

### 📊 Evaluation Metrics
*   **`[ARCH_ALIGNMENT]`**: 90 — semantically-correct Playwright API usage; pattern-level fix vs single-file-fix; establishes a clear convention.
*   **`[CONTENT_COMPLETENESS]`**: 95 — covers all 13 affected spec files; Deltas-from-ticket transparency.
*   **`[EXECUTION_QUALITY]`**: 92 — clean 13-file sweep with identical diff per file; low regression risk.
*   **`[PRODUCTIVITY]`**: 95 — drains #11538 + supersedes #11539 in single PR; high net-shrinkage for drain-mode.
*   **`[IMPACT]`**: 85 — unblocks component-test CI pipeline reliability; cascading impact on future test authoring (the explicit-attached convention will propagate).
*   **`[COMPLEXITY]`**: 15 — mechanical 13-file diff with identical change per file; trivial cognitive load.
*   **`[EFFORT_PROFILE]`**: Quick Win — short focused PR with high CI-stability + drain-mode value.

[Closing Remarks]

Approved on current head. Closes #11538 + supersedes #11539. Standing for CI completion (1 check still pending) + human merge gate per §0 Invariant 1. Net drain-mode contribution: -2 PRs, -1 ticket via this merge + #11539 close.

---

