mirror of
https://github.com/vernu/textbee.git
synced 2026-08-02 18:38:41 -04:00
community-links was the only file in the app still wrapping a Button in a Link, four times, producing an anchor around a button: invalid markup and a nested interactive control that assistive tech announces twice. Everywhere else already uses Button asChild. Two whole Card blocks sat commented out, with an icon imported solely for that dead code. community/page.tsx was the only dashboard section that never got the mobile pass, keeping p-6 with no p-4 step and an unconditional text-3xl. It was also the only section missing from the 375px overflow guard, which is presumably how it was missed. Extracting the shared PageHeader, which the messaging, webhooks and account layouts all repeated by hand, fixes that outlier by construction. Both billing limit grids and the promo modal were locked to two columns at every width, so the meter captions had no room on a phone. window.open kept a live opener handle back to the app in four places. Browsers imply noopener for anchor targets but not for window.open. The share dialog grid moves to 3 columns then 7. Worth stating plainly: this is not an overflow fix. I expected 7 icons at grid-cols-4 to overflow at 375px and the extended guard proved they do not. It was only an awkward 4 + 3 split. The overflow guard now covers 12 routes instead of 6 and opens a dialog, since the densest layouts in the app only exist inside modals. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
77 lines
2.6 KiB
TypeScript
77 lines
2.6 KiB
TypeScript
import { expect, test } from '@playwright/test'
|
|
import { authenticate } from './session'
|
|
import { mockApi } from './mock-api'
|
|
|
|
// Regression guard for mobile horizontal overflow: at 375px no page may be
|
|
// wider than the viewport (the bug showed a blank strip when scrolling right).
|
|
// document.scrollingElement covers the page; body scrollWidth catches clipped
|
|
// overflow introduced inside the layout.
|
|
|
|
const AUTHED_PAGES = [
|
|
'/dashboard',
|
|
'/dashboard/messaging',
|
|
'/dashboard/messaging/bulk',
|
|
'/dashboard/messaging/history',
|
|
'/dashboard/messaging/api-guide',
|
|
'/dashboard/webhooks',
|
|
'/dashboard/webhooks/deliveries',
|
|
'/dashboard/account',
|
|
'/dashboard/account/profile',
|
|
'/dashboard/account/security',
|
|
'/dashboard/account/support',
|
|
// Community was the only section missing from this list, and also the only
|
|
// one that never got the mobile padding pass. Those two facts are related.
|
|
'/dashboard/community',
|
|
]
|
|
|
|
async function expectNoHorizontalScroll(page: import('@playwright/test').Page) {
|
|
const { scrollWidth, innerWidth } = await page.evaluate(() => ({
|
|
scrollWidth: document.documentElement.scrollWidth,
|
|
innerWidth: window.innerWidth,
|
|
}))
|
|
expect(scrollWidth, 'page must not scroll sideways at 375px').toBeLessThanOrEqual(
|
|
innerWidth
|
|
)
|
|
}
|
|
|
|
test.describe('no horizontal overflow at 375px (mocked API)', () => {
|
|
test.use({ viewport: { width: 375, height: 800 } })
|
|
|
|
for (const path of AUTHED_PAGES) {
|
|
test(`authed page ${path}`, async ({ page, context }) => {
|
|
await authenticate(context)
|
|
await mockApi(page)
|
|
await page.goto(path)
|
|
await page.waitForLoadState('networkidle')
|
|
await expectNoHorizontalScroll(page)
|
|
})
|
|
}
|
|
|
|
// The tightest grid in the app only exists inside a dialog, so a guard that
|
|
// never opens one cannot see it.
|
|
test('community share dialog fits at 375px', async ({ page, context }) => {
|
|
await authenticate(context)
|
|
await mockApi(page)
|
|
await page.goto('/dashboard/community')
|
|
|
|
await page.getByRole('button', { name: /Share textbee\.dev/ }).click()
|
|
const dialog = page.getByRole('dialog')
|
|
await expect(dialog.getByText('Choose your platform')).toBeVisible()
|
|
|
|
await expectNoHorizontalScroll(page)
|
|
|
|
// The dialog itself must not overflow its own box either.
|
|
const overflows = await dialog.evaluate(
|
|
(el) => el.scrollWidth > el.clientWidth + 1
|
|
)
|
|
expect(overflows, 'share dialog must not scroll sideways').toBe(false)
|
|
})
|
|
|
|
test('login page', async ({ page }) => {
|
|
await mockApi(page)
|
|
await page.goto('/login')
|
|
await page.waitForLoadState('networkidle')
|
|
await expectNoHorizontalScroll(page)
|
|
})
|
|
})
|