mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-14 08:53:11 +00:00
173 lines
7.7 KiB
TypeScript
173 lines
7.7 KiB
TypeScript
import type { Page } from '@playwright/test'
|
|
|
|
import { expect, test } from './fixtures/campaignE2EFixtures.js'
|
|
|
|
/**
|
|
* B18 — a named recorte of `/campanha/municipios` becomes a sidebar shortcut.
|
|
*
|
|
* Own file for the same reason B17 took one: `campaignMunicipalities.e2e.spec.ts`
|
|
* carries deterministic failures at one worker, ledgered as P1, and a red run
|
|
* there must not be read as a regression here.
|
|
*/
|
|
|
|
/** 416 whole municipalities — deep enough that `?page=2` is a real page. */
|
|
const SAVED_RECORTE = '/campanha/municipios?priority=alta'
|
|
|
|
const SAVED_NAME = 'Recorte do teste'
|
|
const RENAMED = 'Recorte renomeado'
|
|
|
|
/**
|
|
* A route transition on this list costs a full RSC round-trip, and in dev the
|
|
* suite's two workers share one server — which overruns the 5 s default of
|
|
* `expect` and produces a flake nobody reproduces at one worker. Same budget,
|
|
* for the same reason, as `campaignColumnPicker.e2e.spec.ts`.
|
|
*/
|
|
const NAVIGATION = { timeout: 20_000 }
|
|
|
|
/**
|
|
* The nav link, scoped to the desktop sidebar: the same name also exists in the
|
|
* mobile bottom nav, so a bare `getByRole` violates strict mode (#669, OPS83).
|
|
*/
|
|
const municipalityNavLink = (page: Page) =>
|
|
page.locator('[data-slot="sidebar"]').getByRole('link', { name: 'Municípios', exact: true })
|
|
|
|
test.describe('Filtros salvos de Municípios', () => {
|
|
test('saves the current recorte, restores it from the sidebar and deletes it', async ({
|
|
campaign,
|
|
page,
|
|
}) => {
|
|
test.slow()
|
|
|
|
const { fixtures } = campaign
|
|
const coordinator = await fixtures.createCampaignUser('coordinator', {
|
|
name: fixtures.value('Coordenadora Filtros'),
|
|
})
|
|
const password = coordinator.password
|
|
const email = coordinator.email!
|
|
|
|
await campaign.login(page, email, password)
|
|
|
|
// The bare list has no recorte to name.
|
|
await page.goto('/campanha/municipios')
|
|
await expect(page.getByRole('button', { name: 'Salvar filtro', exact: true })).toHaveCount(0)
|
|
|
|
await page.goto(SAVED_RECORTE)
|
|
await page.getByRole('button', { name: 'Salvar filtro', exact: true }).click()
|
|
const nameInput = page.getByLabel('Nome do filtro')
|
|
// The suggested name is the active-filters summary the bar already shows.
|
|
await expect(nameInput).not.toHaveValue('')
|
|
await nameInput.fill(SAVED_NAME)
|
|
await page.getByRole('button', { name: 'Salvar', exact: true }).click()
|
|
|
|
const shortcut = page.getByRole('link', { name: SAVED_NAME })
|
|
await expect(shortcut).toBeVisible()
|
|
await expect(shortcut).toHaveAttribute('aria-current', 'page')
|
|
|
|
// A page is a position inside the recorte, not part of it.
|
|
await page.goto(`${SAVED_RECORTE}&page=2`, NAVIGATION)
|
|
await expect(shortcut).toHaveAttribute('aria-current', 'page')
|
|
|
|
// Another recorte is not this one, and the shortcut brings it back. Use the
|
|
// sidebar link — a bare `goto` here races an in-flight RSC navigation and
|
|
// flakes as net::ERR_ABORTED under prod load (measured in CI 2026-07-30).
|
|
await municipalityNavLink(page).click()
|
|
await expect(page).toHaveURL('/campanha/municipios', NAVIGATION)
|
|
await expect(shortcut).not.toHaveAttribute('aria-current', 'page')
|
|
await shortcut.click()
|
|
await expect(page).toHaveURL(SAVED_RECORTE, NAVIGATION)
|
|
await expect(shortcut).toHaveAttribute('aria-current', 'page', NAVIGATION)
|
|
|
|
// Saving a recorte already bookmarked renames it instead of adding a twin.
|
|
await page.getByRole('button', { name: `Renomear o filtro salvo ${SAVED_NAME}` }).click()
|
|
await expect(page.getByLabel('Nome do filtro')).toHaveValue(SAVED_NAME)
|
|
await page.getByLabel('Nome do filtro').fill(RENAMED)
|
|
await page.getByRole('button', { name: 'Atualizar nome' }).click()
|
|
await expect(page.getByRole('link', { name: RENAMED })).toBeVisible()
|
|
await expect(shortcut).toHaveCount(0)
|
|
|
|
const remove = page.getByRole('button', { name: `Apagar o filtro salvo ${RENAMED}` })
|
|
await remove.click()
|
|
await expect(page.getByRole('link', { name: RENAMED })).toHaveCount(0)
|
|
// Emptying the group unmounts the sub-list, so focus lands on the nav link
|
|
// rather than falling to <body>.
|
|
await expect(municipalityNavLink(page)).toBeFocused()
|
|
|
|
// Deleting is undoable, which is why it never asks for confirmation.
|
|
await page.getByRole('button', { name: 'Desfazer' }).click()
|
|
await expect(page.getByRole('link', { name: RENAMED })).toBeVisible()
|
|
})
|
|
|
|
test('survives a reload with shortcuts always visible', async ({ campaign, page }) => {
|
|
// Three loads of a heavy list route, against a dev server shared with the
|
|
// other worker — the login redirect alone can outrun the 30 s default.
|
|
test.slow()
|
|
|
|
const { fixtures } = campaign
|
|
const coordinator = await fixtures.createCampaignUser('coordinator', {
|
|
name: fixtures.value('Coordenadora Sidebar'),
|
|
})
|
|
const password = coordinator.password
|
|
const email = coordinator.email!
|
|
|
|
await campaign.login(page, email, password)
|
|
await page.goto(SAVED_RECORTE)
|
|
await page.getByRole('button', { name: 'Salvar filtro', exact: true }).click()
|
|
await page.getByLabel('Nome do filtro').fill(SAVED_NAME)
|
|
await page.getByRole('button', { name: 'Salvar', exact: true }).click()
|
|
|
|
const shortcut = page.getByRole('link', { name: SAVED_NAME })
|
|
await expect(shortcut).toBeVisible()
|
|
|
|
await page.reload()
|
|
await expect(shortcut).toBeVisible(NAVIGATION)
|
|
await expect(page.getByRole('list', { name: 'Filtros salvos de Municípios' })).toBeVisible()
|
|
await expect(page.getByRole('button', { name: /filtros salvos de Municípios/i })).toHaveCount(0)
|
|
})
|
|
|
|
test.describe('C102 — saved filters live in the "Mais" drawer on mobile', () => {
|
|
test.use({ viewport: { width: 390, height: 844 } })
|
|
|
|
test('saves, navigates from and deletes inside the drawer', async ({ campaign, page }) => {
|
|
test.slow()
|
|
|
|
const { fixtures } = campaign
|
|
const coordinator = await fixtures.createCampaignUser('coordinator', {
|
|
name: fixtures.value('Coordenadora Drawer Mobile'),
|
|
})
|
|
const password = coordinator.password
|
|
const email = coordinator.email!
|
|
|
|
await campaign.login(page, email, password)
|
|
await page.goto(SAVED_RECORTE)
|
|
await page.getByRole('button', { name: 'Salvar filtro', exact: true }).click()
|
|
await page.getByLabel('Nome do filtro').fill(SAVED_NAME)
|
|
await page.getByRole('button', { name: 'Salvar', exact: true }).click()
|
|
|
|
// The mobile staff top bar has no hamburger (C102) — the drawer is the home.
|
|
const topBar = page.locator('[data-slot="campaign-mobile-top-bar"]')
|
|
await expect(topBar.locator('[data-slot="sidebar-trigger"]')).toHaveCount(0)
|
|
|
|
const bottomNav = page.locator('[aria-label="Navegação principal"]')
|
|
await bottomNav.getByRole('button', { name: 'Mais' }).click()
|
|
const drawer = page.locator('[data-slot="drawer-content"]')
|
|
await expect(drawer).toBeVisible()
|
|
await expect(drawer.getByText('Filtros salvos de Municípios')).toBeVisible()
|
|
|
|
const shortcut = drawer.getByRole('link', { name: SAVED_NAME })
|
|
await expect(shortcut).toBeVisible()
|
|
await expect(shortcut).toHaveAttribute('aria-current', 'page')
|
|
|
|
// Tapping the row restores the recorte and closes the drawer.
|
|
await shortcut.click()
|
|
await expect(page).toHaveURL(SAVED_RECORTE, NAVIGATION)
|
|
await expect(drawer).toBeHidden()
|
|
|
|
// Delete and undo keep working in the drawer.
|
|
await bottomNav.getByRole('button', { name: 'Mais' }).click()
|
|
await drawer.getByRole('button', { name: `Apagar o filtro salvo ${SAVED_NAME}` }).click()
|
|
await expect(drawer.getByRole('link', { name: SAVED_NAME })).toHaveCount(0)
|
|
await page.getByRole('button', { name: 'Desfazer' }).click()
|
|
await expect(drawer.getByRole('link', { name: SAVED_NAME })).toBeVisible()
|
|
})
|
|
})
|
|
})
|