mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 23:53:05 +00:00
fix(e2e): B196 atividades deriva a data da fixture de hoje — desbloqueia deploy verify
A fixture B196 'chassis elsewhere' criava 5 atividades com startAt fixo em 2026-09-01. A aba default de /campanha/atividades (proximos) filtra status=confirmado e startAt >= now, então a partir de 02/09 a lista virou empty state, o scrollport perdeu overflow e a assert scrollHeight - clientHeight > 0 falhou nas 3 retries do verify do deploy de 2026-09-11 (run 34652323456), bloqueando o job de deploy. Deriva o startAt de hoje (+7 dias, tempo civil da Bahia) como os specs de agenda já fazem, dá ao poll do scrollport o orçamento de 30s da classe de latência B196 documentada no arquivo, e adiciona guard ESLint (no-restricted-syntax escopado a tests/e2e) que bane ISO literal em propriedades start*/end*/date* de fixture — pinado em eslintConventions.unit.spec.ts.
This commit is contained in:
parent
3aad110e48
commit
e846c916b6
3 changed files with 62 additions and 4 deletions
|
|
@ -43,6 +43,22 @@ const noHardcodedConsentId = {
|
|||
'Never hardcode a Consent document id — resolve it by stable key via requireConsentByKey (keys in src/lib/campaignConsentKeys.ts).',
|
||||
}
|
||||
|
||||
// E2E fixtures must derive dates from "today": a hardcoded ISO instant
|
||||
// silently expires once it stops matching a time-windowed default view. The
|
||||
// B196 activities fixture (`startAt: '2026-09-01...'`) emptied the default
|
||||
// `proximos` tab and blocked the 2026-09-11 deploy verify. Derive with
|
||||
// `civilDatePlusDays(formatBahiaCivilDate(new Date()), days)` +
|
||||
// `parseBahiaDateTimeInput` (tests/e2e/helpers/agendaPeriodLabels.ts,
|
||||
// src/lib/campaignTime.ts). Deliberately narrow (start*/end*/date* keys):
|
||||
// state timestamps like `disabledAt`/`lastSyncedAt` are the scenario under
|
||||
// test, not a time window.
|
||||
const noHardcodedE2eFixtureDate = {
|
||||
selector:
|
||||
"Property[key.name=/^(start|end|date)/][value.type='Literal'][value.raw=/20[0-9]{2}-[0-9]{2}-[0-9]{2}T/]",
|
||||
message:
|
||||
'Never hardcode a fixture date in e2e specs — derive it from today (civilDatePlusDays + parseBahiaDateTimeInput); a literal expires and empties time-windowed lists (B196 deploy verify, 2026-09-11).',
|
||||
}
|
||||
|
||||
const eslintConfig = [
|
||||
...compat.extends('next/core-web-vitals', 'next/typescript'),
|
||||
{
|
||||
|
|
@ -212,6 +228,15 @@ const eslintConfig = [
|
|||
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
// E2E fixture dates must derive from "today" (B196 deploy verify,
|
||||
// 2026-09-11): a hardcoded ISO instant expires and empties the
|
||||
// time-windowed default view. Keeps the global as-never ban too.
|
||||
files: ['tests/e2e/**/*.{ts,tsx}'],
|
||||
rules: {
|
||||
'no-restricted-syntax': ['error', noAsNeverCast, noHardcodedE2eFixtureDate],
|
||||
},
|
||||
},
|
||||
prettier,
|
||||
// Override default ignores of eslint-config-next.
|
||||
globalIgnores([
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type { Page } from '@playwright/test'
|
||||
|
||||
import { SUPPORTER_REGISTRATION_CONSENT_KEY } from '../../src/lib/campaignConsentKeys.js'
|
||||
import { formatBahiaCivilDate, parseBahiaDateTimeInput } from '../../src/lib/campaignTime.js'
|
||||
import { fallbackDemandTitle } from '../../src/lib/demandTitle.js'
|
||||
import { hookFilledCreateData } from '../../src/utilities/hookFilledData.js'
|
||||
import {
|
||||
|
|
@ -24,6 +25,7 @@ import {
|
|||
assertThreeColumnActionGrid,
|
||||
collectActionBoundingBoxes,
|
||||
} from './helpers/actionGridGeometry.js'
|
||||
import { civilDatePlusDays } from './helpers/agendaPeriodLabels.js'
|
||||
|
||||
const showAllMunicipalityColumns = (page: Page, url: string) =>
|
||||
page.context().addCookies([
|
||||
|
|
@ -1496,6 +1498,14 @@ test.describe('Municípios — barra colada e card denso (B196)', () => {
|
|||
name: fixtures.value('Coordenadora B196 Ativ'),
|
||||
})
|
||||
const municipality = await fixtures.claimMunicipality()
|
||||
// The default tab (`proximos`) only lists `confirmado` activities with
|
||||
// `startAt >= now`, so the fixture start must be derived from "today" —
|
||||
// a hardcoded date empties the list once it expires (deploy verify
|
||||
// 2026-09-11: `scrollHeight - clientHeight` stuck at 0 on all retries).
|
||||
const startAt = parseBahiaDateTimeInput(
|
||||
`${civilDatePlusDays(formatBahiaCivilDate(new Date()), 7)}T13:00`,
|
||||
)
|
||||
if (!startAt) throw new Error('Falha ao montar horário da fixture de atividades.')
|
||||
// Enough rows to make the scrollport scrollable once the top bar takes over.
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await fixtures.payload.create({
|
||||
|
|
@ -1503,7 +1513,7 @@ test.describe('Municípios — barra colada e card denso (B196)', () => {
|
|||
data: hookFilledCreateData<'activity'>({
|
||||
title: `Atividade B196 ${fixtures.value('x')}`,
|
||||
status: 'confirmado',
|
||||
startAt: '2026-09-01T13:00:00.000Z',
|
||||
startAt,
|
||||
municipality: municipality.id,
|
||||
responsible: [{ relationTo: 'campaignUser', value: coordinator.id }],
|
||||
}),
|
||||
|
|
@ -1524,10 +1534,14 @@ test.describe('Municípios — barra colada e card denso (B196)', () => {
|
|||
const headerBottomValue = await headerBottom(topBar)
|
||||
expect((await form.boundingBox())!.y).toBeGreaterThan(headerBottomValue)
|
||||
|
||||
// The scrollport must actually scroll for the sticky to engage.
|
||||
// The scrollport must actually scroll for the sticky to engage. Same B196
|
||||
// stream-latency class as the sibling polls: the list chunk can land late
|
||||
// under 4-worker load, so use the 30s budget instead of the 10s default.
|
||||
const scrollport = contentScroll(page)
|
||||
await expect
|
||||
.poll(() => scrollport.evaluate((el) => el.scrollHeight - el.clientHeight))
|
||||
.poll(() => scrollport.evaluate((el) => el.scrollHeight - el.clientHeight), {
|
||||
timeout: 30_000,
|
||||
})
|
||||
.toBeGreaterThan(0)
|
||||
await scrollport.evaluate((el) => el.scrollTo(0, el.scrollHeight))
|
||||
await expect.poll(async () => (await form.boundingBox())!.y).toBe(headerBottomValue)
|
||||
|
|
|
|||
|
|
@ -189,11 +189,30 @@ describe('ESLint conventions', () => {
|
|||
it('allows async function and type-only exports from use server modules', async () => {
|
||||
await expectValid(
|
||||
'src/app/(campaign)/campanha/actions/futureAction.ts',
|
||||
`'use server'\n\nexport type Result = { ok: true }\nexport const save = async () => ({ ok: true as const })\nexport async function load() { return 1 }\n`,
|
||||
`'use server'\nexport type Result = { ok: true }\nexport const save = async () => ({ ok: true as const })\nexport async function load() { return 1 }\n`,
|
||||
)
|
||||
await expectValid(
|
||||
'src/app/(campaign)/campanha/(app)/municipios/municipalityStaffEditMessages.ts',
|
||||
`export const municipalityStaffEditSafeMessages = ['x'] as const\n`,
|
||||
)
|
||||
})
|
||||
|
||||
it('bans hardcoded ISO fixture dates in e2e specs but not state timestamps', async () => {
|
||||
await expectInvalid(
|
||||
'tests/e2e/futureFixture.e2e.spec.ts',
|
||||
`const fixture = { startAt: '2026-09-01T13:00:00.000Z' }`,
|
||||
'no-restricted-syntax',
|
||||
)
|
||||
await expectInvalid(
|
||||
'tests/e2e/futureFixture.e2e.spec.ts',
|
||||
`const fixture = { endDate: '2026-09-01T13:00:00.000Z' }`,
|
||||
'no-restricted-syntax',
|
||||
)
|
||||
// `disabledAt`/`lastSyncedAt` are the state under test, not a time window;
|
||||
// a computed `startAt` is exactly the sanctioned derivation.
|
||||
await expectValid(
|
||||
'tests/e2e/futureFixture.e2e.spec.ts',
|
||||
`const fixture = { disabledAt: '2026-08-11T00:00:00.000Z' }\nconst startAt = 'dynamic'\nconst activity = { startAt }`,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue