Skip to content

feat(bento): Phase Ic — responsive polish and visual regression tests#75

Open
4444J99 wants to merge 1 commit intomainfrom
feature/phase-ic-bento-polish
Open

feat(bento): Phase Ic — responsive polish and visual regression tests#75
4444J99 wants to merge 1 commit intomainfrom
feature/phase-ic-bento-polish

Conversation

@4444J99
Copy link
Copy Markdown
Owner

@4444J99 4444J99 commented Mar 27, 2026

Summary

  • Tablet: featured cards reset row span at 768-1023px
  • Mobile: stat pills become horizontal scrollable row
  • 10 new structural tests for bento grid HTML output
  • Validates: hero, stats, featured cards, controls, personas, CTA, absence of old components
  • No data-reveal on bento cells (above-fold, no scroll trigger needed)

Part of

Alpha-to-Omega roadmap Phase I (Bento Grid Homepage). Spec: docs/superpowers/specs/2026-03-26-alpha-omega-roadmap-design.md

  • Phase Ia: Hero bento (merged to main)
  • Phase Ib: Full bento migration (merged to main)
  • Phase Ic: Responsive polish + tests (this PR)

Test plan

  • 537/537 tests pass (10 new bento structural tests)
  • Build: 102 pages
  • Lint clean
  • Mobile (375px): single column, stat pills scroll horizontally
  • Tablet (768px): 2-col, featured cards 1 row height
  • Desktop (1024px+): 4-col, featured cards 2×2

🤖 Generated with Claude Code

Summary by Sourcery

Polish the bento homepage’s responsive behavior and add structural regression tests for the generated bento grid HTML.

New Features:

  • Enable horizontally scrollable stat pills layout on small mobile viewports.

Tests:

  • Add bento grid structural tests validating hero, stats, featured cards, controls, personas, CTA, dual-view attributes, and removal of legacy home components.

@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.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Mar 27, 2026

Reviewer's Guide

Implements responsive polish for the bento grid (mobile stat pills horizontal scrolling) and adds HTML-structure-focused visual regression tests to validate the new homepage bento grid layout and remove reliance on old components.

Sequence diagram for bento visual regression structural tests

sequenceDiagram
  actor Developer
  participant JestRunner
  participant BentoVisualTestSuite
  participant HomePageRenderer
  participant DOM

  Developer->>JestRunner: run bento-visual.test
  JestRunner->>BentoVisualTestSuite: execute test_hero_structure
  BentoVisualTestSuite->>HomePageRenderer: render_homepage_bento
  HomePageRenderer-->>DOM: HTML for homepage grid
  BentoVisualTestSuite->>DOM: query_hero_bento_cells
  DOM-->>BentoVisualTestSuite: hero_nodes
  BentoVisualTestSuite->>JestRunner: assert_hero_structure

  JestRunner->>BentoVisualTestSuite: execute test_stats_structure
  BentoVisualTestSuite->>HomePageRenderer: render_homepage_bento
  HomePageRenderer-->>DOM: HTML for homepage grid
  BentoVisualTestSuite->>DOM: query_stat_pills
  DOM-->>BentoVisualTestSuite: stat_pill_nodes
  BentoVisualTestSuite->>JestRunner: assert_stat_pill_structure

  JestRunner->>BentoVisualTestSuite: execute test_absence_of_legacy_components
  BentoVisualTestSuite->>DOM: query_legacy_components
  DOM-->>BentoVisualTestSuite: empty_node_list
  BentoVisualTestSuite->>JestRunner: assert_legacy_components_absent
Loading

Updated class diagram for bento visual regression test structure

classDiagram
  class HomePageBentoGridComponent {
    +string id
    +string layoutMode
    +renderDesktop()
    +renderTablet()
    +renderMobile()
  }

  class BentoVisualTestSuite {
    +testHeroStructure()
    +testStatsStructure()
    +testFeaturedCardsStructure()
    +testControlsStructure()
    +testPersonasStructure()
    +testCtaStructure()
    +testNoLegacyComponents()
    +renderHomepageBento(layoutMode)
    +queryHeroCells(dom)
    +queryStatPills(dom)
    +queryFeaturedCards(dom)
    +queryControls(dom)
    +queryPersonas(dom)
    +queryCta(dom)
    +queryLegacyComponents(dom)
  }

  class CSSStatPillsMobileRule {
    +string selector
    +string maxWidthBreakpoint
    +bool flexWrap
    +string overflowX
    +bool webkitOverflowScrolling
    +string paddingBottom
  }

  class DOM {
    +querySelectorAll(selector)
  }

  BentoVisualTestSuite --> HomePageBentoGridComponent : renders
  BentoVisualTestSuite --> DOM : queries
  BentoVisualTestSuite --> CSSStatPillsMobileRule : validates_effect_on_structure

  CSSStatPillsMobileRule : selector = .stat-pills
  CSSStatPillsMobileRule : maxWidthBreakpoint = 767px
  CSSStatPillsMobileRule : flexWrap = false
  CSSStatPillsMobileRule : overflowX = auto
  CSSStatPillsMobileRule : webkitOverflowScrolling = true
  CSSStatPillsMobileRule : paddingBottom = var(--space-2xs)
Loading

File-Level Changes

Change Details Files
Make stat pills horizontally scrollable on mobile viewports.
  • Add a max-width 767px media query targeting the stat-pills container
  • Prevent flex wrapping so pills stay in a single row
  • Enable horizontal overflow with touch-friendly scrolling
  • Add small bottom padding to avoid clipping with scrollbars
src/styles/global.css
Add structural visual regression tests for the built bento homepage.
  • Introduce a Vitest suite that reads dist/index.html from the built site
  • Assert presence of the main bento grid section and its aria-label
  • Verify hero cell, featured cards, controls cell, persona links, CTA, and see-all card are rendered
  • Assert removal of legacy components (ProjectGrid, home-pair, organ-group__toggle) from the output
  • Validate dual-view data attributes for hero and stats views
src/__tests__/bento-visual.test.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 4 issues, and left some high level feedback:

  • The visual regression tests repeatedly read and parse dist/index.html in each it block; consider reading it once (e.g., in a beforeAll or a shared const html = ...) to reduce duplication and make the tests a bit faster and easier to maintain.
  • The new bento structural tests assert on raw string contents like Anthony James Padavano and Start a conversation, which may be brittle as copy changes; you might want to key off more stable selectors or data attributes instead.
  • For the HTML structure checks, using a DOM parser (e.g., JSDOM) instead of regex/string matching would make the tests more robust to formatting changes and allow more precise assertions on element counts and attributes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The visual regression tests repeatedly read and parse `dist/index.html` in each `it` block; consider reading it once (e.g., in a `beforeAll` or a shared `const html = ...`) to reduce duplication and make the tests a bit faster and easier to maintain.
- The new bento structural tests assert on raw string contents like `Anthony James Padavano` and `Start a conversation`, which may be brittle as copy changes; you might want to key off more stable selectors or data attributes instead.
- For the HTML structure checks, using a DOM parser (e.g., JSDOM) instead of regex/string matching would make the tests more robust to formatting changes and allow more precise assertions on element counts and attributes.

## Individual Comments

### Comment 1
<location path="src/__tests__/bento-visual.test.ts" line_range="7" />
<code_context>
+
+const DIST = resolve(process.cwd(), 'dist');
+
+describe('bento grid structure', () => {
+	const indexPath = resolve(DIST, 'index.html');
+
</code_context>
<issue_to_address>
**suggestion:** Reuse the built HTML instead of reading index.html from disk in every test

Each test re-reads `dist/index.html`, adding unnecessary I/O and duplication. Consider loading it once in a `beforeAll` (e.g., into a shared `let html: string`) and reusing it across tests to keep them focused on structure and simplify future changes (like switching entry files).

Suggested implementation:

```typescript
import { existsSync, readFileSync } from 'fs';
import { resolve } from 'path';
import { beforeAll, describe, expect, it } from 'vitest';

const DIST = resolve(process.cwd(), 'dist');

describe('bento grid structure', () => {
	const indexPath = resolve(DIST, 'index.html');
	let html: string;

	beforeAll(() => {
		html = readFileSync(indexPath, 'utf-8');
	});

	it('dist/index.html exists', () => {
		expect(existsSync(indexPath)).toBe(true);
	});

	it('has bento-grid section', () => {

```

Anywhere later in this file that calls `readFileSync(indexPath, ...)` or otherwise re-reads `dist/index.html` should be updated to use the shared `html` variable instead. For example, replace `const html = readFileSync(indexPath, 'utf-8');` with uses of the top-level `html` defined in the `describe` block (e.g., directly passing `html` into the DOM parser or string matchers).
</issue_to_address>

### Comment 2
<location path="src/__tests__/bento-visual.test.ts" line_range="27-32" />
<code_context>
+		expect(html).toContain('stat-pill');
+	});
+
+	it('has 2 featured project cards with transition:name', () => {
+		const html = readFileSync(indexPath, 'utf8');
+		const featured = html.match(/bento-card--featured/g);
+		expect(featured?.length).toBe(2);
+		expect(html).toContain('data-astro-transition-scope');
+	});
+
</code_context>
<issue_to_address>
**suggestion (testing):** Tighten featured cards assertion to ensure the transition scope is applied specifically to featured cards

This test only checks that `data-astro-transition-scope` exists somewhere in the HTML, so it would still pass if the attribute moved off the featured cards. Please assert that it’s present specifically on the `bento-card--featured` elements (or that the count of `data-astro-transition-scope` matches the number of featured cards) so the test better reflects the intended behavior.

```suggestion
	it('has 2 featured project cards with transition:name', () => {
		const html = readFileSync(indexPath, 'utf8');

		// Count all featured cards
		const featured = html.match(/bento-card--featured/g) ?? [];
		expect(featured.length).toBe(2);

		// Ensure each featured card has a data-astro-transition-scope attribute
		const featuredWithTransitionScope =
			html.match(/<[^>]*class="[^"]*\bbento-card--featured\b[^"]*"[^>]*data-astro-transition-scope[^>]*>/g) ?? [];
		expect(featuredWithTransitionScope.length).toBe(featured.length);
	});
```
</issue_to_address>

### Comment 3
<location path="src/__tests__/bento-visual.test.ts" line_range="41-45" />
<code_context>
+		expect(html).toContain('data-shibui-control');
+	});
+
+	it('has persona cell with 4 persona links', () => {
+		const html = readFileSync(indexPath, 'utf8');
+		expect(html).toContain('persona-cell');
+		const personaLinks = html.match(/persona-cell__link/g);
+		expect(personaLinks?.length).toBeGreaterThanOrEqual(4);
+	});
+
</code_context>
<issue_to_address>
**question (testing):** Clarify whether exactly 4 personas are expected and assert accordingly

The test name implies exactly 4 persona links, but the assertion uses `toBeGreaterThanOrEqual(4)`. Please either change the assertion to `toBe(4)` if exactly four are required, or update the test name to indicate an "at least 4" expectation.
</issue_to_address>

### Comment 4
<location path="src/__tests__/bento-visual.test.ts" line_range="66-71" />
<code_context>
+		expect(html).not.toContain('organ-group__toggle');
+	});
+
+	it('has dual-view data attributes', () => {
+		const html = readFileSync(indexPath, 'utf8');
+		expect(html).toContain('data-hero-view="engineering"');
+		expect(html).toContain('data-hero-view="creative"');
+		expect(html).toContain('data-stats-view="engineering"');
+		expect(html).toContain('data-stats-view="creative"');
+	});
+});
</code_context>
<issue_to_address>
**issue (testing):** Add a test to assert that bento cells do not use `data-reveal`, as mentioned in the PR description

The PR description specifies “No `data-reveal` on bento cells (above-fold, no scroll trigger needed)”, but there’s no test enforcing this. Please add a test that asserts `data-reveal` never appears on bento cell elements (or anywhere in the document, if that’s the requirement) to capture this behavior.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.


const DIST = resolve(process.cwd(), 'dist');

describe('bento grid structure', () => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion: Reuse the built HTML instead of reading index.html from disk in every test

Each test re-reads dist/index.html, adding unnecessary I/O and duplication. Consider loading it once in a beforeAll (e.g., into a shared let html: string) and reusing it across tests to keep them focused on structure and simplify future changes (like switching entry files).

Suggested implementation:

import { existsSync, readFileSync } from 'fs';
import { resolve } from 'path';
import { beforeAll, describe, expect, it } from 'vitest';

const DIST = resolve(process.cwd(), 'dist');

describe('bento grid structure', () => {
	const indexPath = resolve(DIST, 'index.html');
	let html: string;

	beforeAll(() => {
		html = readFileSync(indexPath, 'utf-8');
	});

	it('dist/index.html exists', () => {
		expect(existsSync(indexPath)).toBe(true);
	});

	it('has bento-grid section', () => {

Anywhere later in this file that calls readFileSync(indexPath, ...) or otherwise re-reads dist/index.html should be updated to use the shared html variable instead. For example, replace const html = readFileSync(indexPath, 'utf-8'); with uses of the top-level html defined in the describe block (e.g., directly passing html into the DOM parser or string matchers).

Comment on lines +27 to +32
it('has 2 featured project cards with transition:name', () => {
const html = readFileSync(indexPath, 'utf8');
const featured = html.match(/bento-card--featured/g);
expect(featured?.length).toBe(2);
expect(html).toContain('data-astro-transition-scope');
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (testing): Tighten featured cards assertion to ensure the transition scope is applied specifically to featured cards

This test only checks that data-astro-transition-scope exists somewhere in the HTML, so it would still pass if the attribute moved off the featured cards. Please assert that it’s present specifically on the bento-card--featured elements (or that the count of data-astro-transition-scope matches the number of featured cards) so the test better reflects the intended behavior.

Suggested change
it('has 2 featured project cards with transition:name', () => {
const html = readFileSync(indexPath, 'utf8');
const featured = html.match(/bento-card--featured/g);
expect(featured?.length).toBe(2);
expect(html).toContain('data-astro-transition-scope');
});
it('has 2 featured project cards with transition:name', () => {
const html = readFileSync(indexPath, 'utf8');
// Count all featured cards
const featured = html.match(/bento-card--featured/g) ?? [];
expect(featured.length).toBe(2);
// Ensure each featured card has a data-astro-transition-scope attribute
const featuredWithTransitionScope =
html.match(/<[^>]*class="[^"]*\bbento-card--featured\b[^"]*"[^>]*data-astro-transition-scope[^>]*>/g) ?? [];
expect(featuredWithTransitionScope.length).toBe(featured.length);
});

Comment on lines +41 to +45
it('has persona cell with 4 persona links', () => {
const html = readFileSync(indexPath, 'utf8');
expect(html).toContain('persona-cell');
const personaLinks = html.match(/persona-cell__link/g);
expect(personaLinks?.length).toBeGreaterThanOrEqual(4);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

question (testing): Clarify whether exactly 4 personas are expected and assert accordingly

The test name implies exactly 4 persona links, but the assertion uses toBeGreaterThanOrEqual(4). Please either change the assertion to toBe(4) if exactly four are required, or update the test name to indicate an "at least 4" expectation.

Comment on lines +66 to +71
it('has dual-view data attributes', () => {
const html = readFileSync(indexPath, 'utf8');
expect(html).toContain('data-hero-view="engineering"');
expect(html).toContain('data-hero-view="creative"');
expect(html).toContain('data-stats-view="engineering"');
expect(html).toContain('data-stats-view="creative"');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (testing): Add a test to assert that bento cells do not use data-reveal, as mentioned in the PR description

The PR description specifies “No data-reveal on bento cells (above-fold, no scroll trigger needed)”, but there’s no test enforcing this. Please add a test that asserts data-reveal never appears on bento cell elements (or anywhere in the document, if that’s the requirement) to capture this behavior.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds a new visual test suite for the bento grid, updates quality and trust metrics, and introduces responsive horizontal scrolling for stat pills on mobile. The reviewer suggested improving test performance by reading the HTML file once at the suite level instead of repeatedly in every test block.

});

it('has bento-grid section', () => {
const html = readFileSync(indexPath, 'utf8');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Reading the index.html file repeatedly within each it block can lead to unnecessary I/O operations and slow down test execution. It's more efficient to read the file once at the beginning of the describe block and reuse its content across all tests in that suite.

  it('has bento-grid section', () => {
    expect(html).toContain('class="bento-grid"');

describe('bento grid structure', () => {
const indexPath = resolve(DIST, 'index.html');

it('dist/index.html exists', () => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

To improve test performance, the index.html file should be read only once for the entire test suite. Move the readFileSync call to the describe block scope so that html is available to all it blocks without redundant file reads.

  const indexPath = resolve(DIST, 'index.html');
  const html = readFileSync(indexPath, 'utf8');

  it('dist/index.html exists', () => {

@4444J99 4444J99 force-pushed the feature/phase-ic-bento-polish branch from e12c9e0 to 8deaf07 Compare March 27, 2026 22:10
- Mobile: stat pills horizontal scroll (nowrap + overflow-x: auto)
- Tablet row-2 and mobile span-2 resets already present (verified)
- Featured card arrow position: relative already set (verified)
- No data-reveal on bento components (verified clean)
- 10 structural tests for bento grid HTML output
- Verifies: hero, stats, featured cards, controls, personas, CTA, no old components

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@4444J99 4444J99 force-pushed the feature/phase-ic-bento-polish branch from 8deaf07 to 47ee989 Compare March 27, 2026 22:23
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