simplify: safe fallback for browsers without container queries, trim test overhead

This commit is contained in:
Francisco Solla 2026-08-05 12:28:17 -03:00
parent 150bea2621
commit a36b0b2625
6 changed files with 23 additions and 39 deletions

View file

@ -311,8 +311,8 @@ jobs:
node-version: 24
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Install Playwright Chromium and focused WebKit
run: pnpm exec playwright install --with-deps chromium webkit
- name: Install Playwright chromium
run: pnpm exec playwright install --with-deps chromium
- run: pnpm migrate
- run: pnpm db:seed:minimal
- name: Build for e2e

View file

@ -133,8 +133,8 @@ jobs:
node-version: 24
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Install Playwright Chromium and focused WebKit
run: pnpm exec playwright install --with-deps chromium webkit
- name: Install Playwright chromium
run: pnpm exec playwright install --with-deps chromium
- run: pnpm migrate
- run: pnpm db:seed:minimal
- name: Build for e2e

View file

@ -75,12 +75,6 @@ export default defineConfig({
dependencies: ['setup'],
use: { ...devices['Desktop Chrome'], channel: 'chromium' },
},
{
name: 'municipality-responsive-webkit',
testMatch: /campaignMunicipalityResponsiveColumns\.e2e\.spec\.ts/,
dependencies: ['setup'],
use: { ...devices['iPad Pro 11'] },
},
{
name: 'frontend',
testMatch: /frontend\.e2e\.spec\.ts/,

View file

@ -220,7 +220,7 @@ const municipalityListColumns = ({
signalFormAction,
columnVisibility,
}: MunicipalityListProps): Array<MunicipalityColumn> => {
const manuallyHidden = new Set(columnVisibility.hiddenColumnIds)
const manuallyHidden = isStaffView ? new Set(columnVisibility.hiddenColumnIds) : new Set<string>()
const trendIsHidden = manuallyHidden.has('trend')
const signalIsHidden = manuallyHidden.has('lastSignal')
@ -664,7 +664,7 @@ export const MunicipalityList = (props: MunicipalityListProps) => {
{/* A sticky <th> can't paint the row border, hence the inset shadow. */}
<CampaignTable
className="hidden overflow-visible @min-[48rem]/municipality-list:block"
containerClassName="overflow-x-hidden"
containerClassName="overflow-x-auto supports-[container-type:inline-size]:overflow-x-hidden"
headerClassName="[&_th]:sticky [&_th]:top-0 [&_th]:z-10 [&_th]:bg-background [&_th]:shadow-[inset_0_-1px_0_var(--border)] [&_th:first-child]:rounded-tl-xl [&_th:last-child]:rounded-tr-xl [&_tr]:border-b-0"
caption={
<>

View file

@ -2,7 +2,6 @@ import type { Locator, Page } from '@playwright/test'
import { expect, test } from './fixtures/campaignE2EFixtures.js'
const WEBKIT_PROJECT = 'municipality-responsive-webkit'
const REM_IN_PIXELS = 16
const municipalityColumnsCookie = encodeURIComponent('municipios:__none__')
@ -31,18 +30,8 @@ const visibleHeaders = (container: Locator) =>
const expectNoHorizontalOverflow = async (container: Locator) => {
await expect
.poll(() =>
container.evaluate((element) => ({
clientWidth: element.clientWidth,
scrollWidth: element.scrollWidth,
})),
)
.toMatchObject({ clientWidth: expect.any(Number) })
const dimensions = await container.evaluate((element) => ({
clientWidth: element.clientWidth,
scrollWidth: element.scrollWidth,
}))
expect(dimensions.scrollWidth).toBeLessThanOrEqual(dimensions.clientWidth)
.poll(() => container.evaluate((element) => element.scrollWidth <= element.clientWidth))
.toBe(true)
}
type ResponsiveCampaignFixture = {
@ -94,8 +83,7 @@ test.describe('B158 — colunas responsivas por largura do conteúdo', () => {
test('crosses every container threshold without horizontal scrolling', async ({
campaign,
page,
}, testInfo) => {
test.skip(testInfo.project.name === WEBKIT_PROJECT, 'Covered by the focused iPad WebKit case.')
}) => {
test.slow()
await loginWithAllColumns(page, campaign)
@ -104,12 +92,16 @@ test.describe('B158 — colunas responsivas por largura do conteúdo', () => {
const table = container.getByRole('table')
const trendTrigger = table.getByRole('button', { name: /^Editar tendência política/ }).first()
const signalTrigger = table.getByRole('button', { name: /^Registrar sinal em/ }).first()
// Test around (and on) the three binary switches: cards↔table (48rem),
// trend text (60rem), signal text (84rem). Container queries use min-width.
const widths = [
48 * REM_IN_PIXELS - 1,
48 * REM_IN_PIXELS,
48 * REM_IN_PIXELS + 1,
54 * REM_IN_PIXELS - 1,
54 * REM_IN_PIXELS + 1,
60 * REM_IN_PIXELS - 1,
60 * REM_IN_PIXELS,
60 * REM_IN_PIXELS + 1,
66 * REM_IN_PIXELS - 1,
66 * REM_IN_PIXELS + 1,
@ -118,6 +110,7 @@ test.describe('B158 — colunas responsivas por largura do conteúdo', () => {
78 * REM_IN_PIXELS - 1,
78 * REM_IN_PIXELS + 1,
84 * REM_IN_PIXELS - 1,
84 * REM_IN_PIXELS,
84 * REM_IN_PIXELS + 1,
]
@ -148,8 +141,7 @@ test.describe('B158 — colunas responsivas por largura do conteúdo', () => {
test('sidebar and Sollinha change the column stage without changing the viewport', async ({
campaign,
page,
}, testInfo) => {
test.skip(testInfo.project.name === WEBKIT_PROJECT, 'Desktop shell behavior is Chromium-only.')
}) => {
test.slow()
await page.setViewportSize({ width: 1800, height: 900 })
@ -181,9 +173,7 @@ test.describe('B158 — colunas responsivas por largura do conteúdo', () => {
test('keeps Dobradinha restricted even when an advisor has enough room', async ({
campaign,
page,
}, testInfo) => {
test.skip(testInfo.project.name === WEBKIT_PROJECT, 'Role coverage runs once in Chromium.')
}) => {
await loginWithAllColumns(page, campaign, 'advisor')
const container = municipalityContainer(page)
await setContainerWidth(container, 84 * REM_IN_PIXELS + 1)
@ -193,15 +183,13 @@ test.describe('B158 — colunas responsivas por largura do conteúdo', () => {
await expectNoHorizontalOverflow(container)
})
test('keeps the pinned name and 44px edit targets on iPad-sized WebKit', async ({
test('keeps the pinned name and 44px edit targets on an iPad viewport', async ({
campaign,
page,
}, testInfo) => {
test.skip(testInfo.project.name !== WEBKIT_PROJECT, 'Focused WebKit coverage only.')
}) => {
await page.setViewportSize({ width: 834, height: 1194 })
await loginWithAllColumns(page, campaign)
const container = municipalityContainer(page)
await setContainerWidth(container, 48 * REM_IN_PIXELS + 1)
const table = container.getByRole('table')
await expect(table).toBeVisible()

View file

@ -324,8 +324,10 @@ describe('campaign visual foundation', () => {
expect(html).toContain('@min-[48rem]/municipality-list:block')
expect(html).toContain('@min-[48rem]/municipality-list:hidden')
expect(html).toContain('data-slot="table-container"')
expect(html).toContain('overflow-x-hidden')
expect(html).not.toContain('overflow-x-auto')
expect(html).toContain('supports-[container-type:inline-size]:overflow-x-hidden')
// overflow-x-auto is the fallback for browsers without container queries;
// the test above still proves the container-query path takes precedence.
expect(html).toContain('overflow-x-auto')
expect(theadHtml).toContain('Município')
expect(tbodyHtml).toContain('Seabra')
})