mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-15 02:23:07 +00:00
test: align municipality e2e journeys with responsive columns
This commit is contained in:
parent
cc60b82245
commit
2f8d16881d
3 changed files with 78 additions and 24 deletions
|
|
@ -39,8 +39,8 @@ test.describe('Seletor de colunas', () => {
|
|||
await campaign.login(page, email, password)
|
||||
await page.goto('/campanha/municipios')
|
||||
|
||||
const levelHeader = page.getByRole('columnheader', { name: /Nível/ })
|
||||
await expect(levelHeader).toBeVisible()
|
||||
const votesHeader = page.getByRole('columnheader', { name: /2022/ })
|
||||
await expect(votesHeader).toBeVisible()
|
||||
|
||||
const picker = page.getByRole('button', { name: /Mostrar ou ocultar colunas/ })
|
||||
await picker.click()
|
||||
|
|
@ -57,15 +57,15 @@ test.describe('Seletor de colunas', () => {
|
|||
.toContain('municipios:__none__')
|
||||
|
||||
await picker.click()
|
||||
await page.getByRole('checkbox', { name: 'Nível' }).click()
|
||||
await page.getByRole('checkbox', { name: 'Votação 2022' }).click()
|
||||
// Closing flushes the batched cookie write and refreshes the RSC.
|
||||
await page.keyboard.press('Escape')
|
||||
|
||||
await expect(levelHeader).toHaveCount(0, REFRESH)
|
||||
await expect(votesHeader).toHaveCount(0, REFRESH)
|
||||
await expect(page.getByRole('button', { name: /1 oculta/ })).toBeVisible()
|
||||
|
||||
await page.reload()
|
||||
await expect(page.getByRole('columnheader', { name: /Nível/ })).toHaveCount(0, REFRESH)
|
||||
await expect(page.getByRole('columnheader', { name: /2022/ })).toHaveCount(0, REFRESH)
|
||||
|
||||
// The cookie carries one key per list: another list is untouched. The
|
||||
// territories list is the honest neighbour here — its 27 rows come from
|
||||
|
|
@ -79,9 +79,9 @@ test.describe('Seletor de colunas', () => {
|
|||
await page.getByRole('button', { name: 'Restaurar todas' }).click()
|
||||
await page.keyboard.press('Escape')
|
||||
|
||||
await expect(page.getByRole('columnheader', { name: /Nível/ })).toBeVisible(REFRESH)
|
||||
await expect(page.getByRole('columnheader', { name: /2022/ })).toBeVisible(REFRESH)
|
||||
await page.reload()
|
||||
await expect(page.getByRole('columnheader', { name: /Nível/ })).toBeVisible(REFRESH)
|
||||
await expect(page.getByRole('columnheader', { name: /2022/ })).toBeVisible(REFRESH)
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import type { Page } from '@playwright/test'
|
||||
|
||||
import { SUPPORTER_REGISTRATION_CONSENT_KEY } from '../../src/lib/campaignConsentKeys.js'
|
||||
import {
|
||||
ensureLeasedConsent,
|
||||
|
|
@ -15,6 +17,15 @@ import {
|
|||
collectActionBoundingBoxes,
|
||||
} from './helpers/actionGridGeometry.js'
|
||||
|
||||
const showAllMunicipalityColumns = (page: Page, url: string) =>
|
||||
page.context().addCookies([
|
||||
{
|
||||
name: 'campaign_columns',
|
||||
value: encodeURIComponent('municipios:__none__'),
|
||||
url,
|
||||
},
|
||||
])
|
||||
|
||||
/**
|
||||
* Core municipality-model journeys per role: coordinator strategy editing, advisor
|
||||
* scoping, staff declare/estimate privacy boundary, leader lockdown, and staff-only
|
||||
|
|
@ -26,6 +37,14 @@ import {
|
|||
*/
|
||||
|
||||
test.describe('Municípios — jornadas por papel', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// B158 keys the table stages to content width and gives fresh profiles a
|
||||
// compact default. These pre-B158 journeys exercise specific desktop
|
||||
// cells, so make that prerequisite explicit instead of finding hidden
|
||||
// copies in the always-mounted mobile-card tree.
|
||||
await page.setViewportSize({ width: 2400, height: 1000 })
|
||||
})
|
||||
|
||||
test('coordinator opens the municipalities list, edits strategy and assigns an advisor', async ({
|
||||
campaign,
|
||||
page,
|
||||
|
|
@ -41,6 +60,7 @@ test.describe('Municípios — jornadas por papel', () => {
|
|||
const municipality = await fixtures.claimMunicipality()
|
||||
|
||||
await campaign.login(page, coordinator.email!, password)
|
||||
await showAllMunicipalityColumns(page, campaign.baseURL)
|
||||
await page.goto(`${campaign.baseURL}/campanha/municipios`)
|
||||
await expect(campaignPageChrome(page, 'Municípios')).toBeVisible()
|
||||
|
||||
|
|
@ -96,6 +116,7 @@ test.describe('Municípios — jornadas por papel', () => {
|
|||
const municipality = await fixtures.claimMunicipality()
|
||||
|
||||
await campaign.login(page, coordinator.email!, password)
|
||||
await showAllMunicipalityColumns(page, campaign.baseURL)
|
||||
await page.goto(
|
||||
`${campaign.baseURL}/campanha/municipios?q=${encodeURIComponent(municipality.name)}`,
|
||||
)
|
||||
|
|
@ -117,16 +138,12 @@ test.describe('Municípios — jornadas por papel', () => {
|
|||
// No "Salvar" button in this popover: selecting the option auto-saves the
|
||||
// delta and renders it as a removable chip immediately.
|
||||
const chip = advisorsPopover.getByRole('button', { name: `Remover ${advisor.name}` })
|
||||
// Click the option itself: the inner text generic does not always trigger
|
||||
// the combobox selection (measured — the popover stayed on "selected: você").
|
||||
// Retry loop for the pre-hydration flake class (same as
|
||||
// `checkRadixWhenHydrated`): a click before React attaches is a silent
|
||||
// no-op, so the probe retries until the chip sticks.
|
||||
await expect(async () => {
|
||||
await search.fill(searchNamePart)
|
||||
await option.click({ timeout: 1_000 })
|
||||
await expect(chip).toBeVisible({ timeout: 4_000 })
|
||||
}).toPass({ timeout: 20_000 })
|
||||
// Opening this client-only popover already proves hydration. Wait for the
|
||||
// write itself: the chip and trigger are optimistic and do not prove the
|
||||
// assignment reached the database before the reload below.
|
||||
await search.fill(searchNamePart)
|
||||
await Promise.all([expectPostResponse(page, '/campanha/municipios/advisors'), option.click()])
|
||||
await expect(chip).toBeVisible()
|
||||
|
||||
// The popover stays open after the write (auto-save, not submit+close).
|
||||
await expect(advisorsPopover).toBeVisible()
|
||||
|
|
@ -170,6 +187,7 @@ test.describe('Municípios — jornadas por papel', () => {
|
|||
const newAdvisorName = fixtures.value('Novo Assessor')
|
||||
|
||||
await campaign.login(page, coordinator.email!, password)
|
||||
await showAllMunicipalityColumns(page, campaign.baseURL)
|
||||
await page.goto(
|
||||
`${campaign.baseURL}/campanha/municipios?q=${encodeURIComponent(municipality.name)}`,
|
||||
)
|
||||
|
|
@ -241,6 +259,7 @@ test.describe('Municípios — jornadas por papel', () => {
|
|||
const party = 'PCdoB'
|
||||
|
||||
await campaign.login(page, coordinator.email!, password)
|
||||
await showAllMunicipalityColumns(page, campaign.baseURL)
|
||||
await page.goto(
|
||||
`${campaign.baseURL}/campanha/municipios?q=${encodeURIComponent(municipality.name)}`,
|
||||
)
|
||||
|
|
@ -307,6 +326,7 @@ test.describe('Municípios — jornadas por papel', () => {
|
|||
const note = fixtures.value('Vereador confirmou apoio local')
|
||||
|
||||
await campaign.login(page, coordinator.email!, password)
|
||||
await showAllMunicipalityColumns(page, campaign.baseURL)
|
||||
await page.goto(
|
||||
`${campaign.baseURL}/campanha/municipios?q=${encodeURIComponent(municipality.name)}`,
|
||||
)
|
||||
|
|
@ -349,6 +369,7 @@ test.describe('Municípios — jornadas por papel', () => {
|
|||
const municipality = await fixtures.claimMunicipality()
|
||||
|
||||
await campaign.login(page, coordinator.email!, password)
|
||||
await showAllMunicipalityColumns(page, campaign.baseURL)
|
||||
await page.goto(
|
||||
`${campaign.baseURL}/campanha/municipios?q=${encodeURIComponent(municipality.name)}`,
|
||||
)
|
||||
|
|
@ -433,6 +454,7 @@ test.describe('Municípios — jornadas por papel', () => {
|
|||
|
||||
// Advisor scope: only the administered municipality shows up.
|
||||
await campaign.login(page, advisor.email!, password)
|
||||
await showAllMunicipalityColumns(page, campaign.baseURL)
|
||||
await page.goto(`${campaign.baseURL}/campanha/municipios`)
|
||||
await expect(
|
||||
page.getByRole('link', { name: administered.name, exact: true }).first(),
|
||||
|
|
|
|||
|
|
@ -5,7 +5,10 @@ import { expect, test } from './fixtures/campaignE2EFixtures.js'
|
|||
const REM_IN_PIXELS = 16
|
||||
const municipalityColumnsCookie = encodeURIComponent('municipios:__none__')
|
||||
|
||||
const municipalityContainer = (page: Page) => page.locator('[data-container="municipality-list"]')
|
||||
// During a concurrent RSC navigation Next may briefly retain the previous
|
||||
// segment beside the incoming one. The current segment is appended last.
|
||||
const municipalityContainer = (page: Page) =>
|
||||
page.locator('[data-container="municipality-list"]').last()
|
||||
|
||||
const setContainerWidth = async (container: Locator, width: number) => {
|
||||
await container.evaluate((element, nextWidth) => {
|
||||
|
|
@ -62,8 +65,8 @@ const loginWithAllColumns = async (
|
|||
},
|
||||
])
|
||||
await page.goto('/campanha/municipios')
|
||||
await expect(municipalityContainer(page)).toBeVisible()
|
||||
await page.waitForLoadState('networkidle')
|
||||
await expect(municipalityContainer(page)).toBeVisible()
|
||||
}
|
||||
|
||||
const expectedHeadersAt = (width: number) => {
|
||||
|
|
@ -144,7 +147,9 @@ test.describe('B158 — colunas responsivas por largura do conteúdo', () => {
|
|||
}) => {
|
||||
test.slow()
|
||||
|
||||
await page.setViewportSize({ width: 1800, height: 900 })
|
||||
// Calibrated so the real sidebar/chat transitions cross the 66rem stage
|
||||
// even when both campaign rails consume their full production widths.
|
||||
await page.setViewportSize({ width: 1920, height: 900 })
|
||||
await loginWithAllColumns(page, campaign)
|
||||
const container = municipalityContainer(page)
|
||||
const viewportBefore = page.viewportSize()
|
||||
|
|
@ -155,17 +160,44 @@ test.describe('B158 — colunas responsivas por largura do conteúdo', () => {
|
|||
await expect
|
||||
.poll(() => container.evaluate((element) => element.clientWidth))
|
||||
.toBeGreaterThan(widthWithSidebar)
|
||||
await expect
|
||||
.poll(async () => (await visibleHeaders(container)).length)
|
||||
.toBeGreaterThan(headersWithSidebar.length)
|
||||
const widthAfterSidebarToggle = await container.evaluate((element) => element.clientWidth)
|
||||
const initiallyOpenChatClose = page
|
||||
.getByRole('button', { name: 'Fechar', exact: true })
|
||||
.filter({ visible: true })
|
||||
if ((await initiallyOpenChatClose.count()) > 0) {
|
||||
await initiallyOpenChatClose.click()
|
||||
await expect
|
||||
.poll(() => container.evaluate((element) => element.clientWidth))
|
||||
.toBeGreaterThan(widthAfterSidebarToggle)
|
||||
}
|
||||
const widthWithoutSidebar = await container.evaluate((element) => element.clientWidth)
|
||||
const headersWithoutSidebar = await visibleHeaders(container)
|
||||
expect(headersWithoutSidebar.length).toBeGreaterThan(headersWithSidebar.length)
|
||||
|
||||
await page.getByRole('button', { name: 'Sollinha — Assistente virtual' }).first().click()
|
||||
await page
|
||||
.getByRole('button', { name: 'Sollinha — Assistente virtual' })
|
||||
.filter({ visible: true })
|
||||
.click()
|
||||
await expect
|
||||
.poll(() => container.evaluate((element) => element.clientWidth))
|
||||
.toBeLessThan(widthWithoutSidebar)
|
||||
await expect
|
||||
.poll(async () => (await visibleHeaders(container)).length)
|
||||
.toBeLessThan(headersWithoutSidebar.length)
|
||||
const widthWithChat = await container.evaluate((element) => element.clientWidth)
|
||||
const headersWithChat = await visibleHeaders(container)
|
||||
await page.getByRole('button', { name: 'Fechar' }).last().click()
|
||||
await page
|
||||
.getByRole('button', { name: 'Fechar', exact: true })
|
||||
.filter({ visible: true })
|
||||
.click()
|
||||
await expect
|
||||
.poll(() => container.evaluate((element) => element.clientWidth))
|
||||
.toBeGreaterThan(widthWithChat)
|
||||
expect((await visibleHeaders(container)).length).toBeGreaterThan(headersWithChat.length)
|
||||
await expect
|
||||
.poll(async () => (await visibleHeaders(container)).length)
|
||||
.toBeGreaterThan(headersWithChat.length)
|
||||
expect(page.viewportSize()).toEqual(viewportBefore)
|
||||
await expectNoHorizontalOverflow(container)
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue