Replaces the checkbox-list + "Salvar assessores" button in the Assessors popover (/campanha/municipios) with removable chips + a Command combobox, delta-based auto-save (one advisor add/remove per request, never the whole array), and optimistic UI with request sequencing to resolve out-of-order responses correctly. - New POST /campanha/municipios/advisors JSON route (mirrors expected-votes/), backed by setMunicipalityAdvisorMembership(Record) in actions/municipality.ts (text advisory lock + transaction). - nextAdvisorIdsAfterMembership moved to src/lib/municipalityAdvisorMembership.ts with unit tests. - Shared isSameOriginRequest (src/utilities/sameOriginRequest.ts) and uniqueRelationshipIds (src/utilities/relationship.ts) helpers, de-duplicating the same-origin CSRF check and the Set+map(relationshipId)+filter pattern across advisor call sites. - MunicipalityListAdvisorsControl.tsx rewritten: chips, Command combobox, per-item pending affordance, rollback on error, and a request-sequence guard so only the most recently sent delta's response is adopted when concurrent optimistic updates settle. - e2e coverage for the combobox auto-save flow; setup prewarms the new POST-only route to avoid Playwright dev-server HMR aborting the first request. - Plan and roadmap marked as delivered (B27).
29 lines
1.1 KiB
TypeScript
29 lines
1.1 KiB
TypeScript
import { expect, test } from '@playwright/test'
|
|
|
|
const baseURL = process.env.PLAYWRIGHT_BASE_URL ?? 'http://localhost:3000'
|
|
|
|
test('prewarms shared Next route bundles sequentially', async ({ request }) => {
|
|
test.slow()
|
|
for (const path of [
|
|
'/campanha/login',
|
|
'/campanha/municipios',
|
|
'/campanha/territorios',
|
|
'/campanha/municipios/e2e-prewarm',
|
|
'/campanha/demandas',
|
|
'/campanha/conceitos',
|
|
'/campanha/convite/e2e-prewarm',
|
|
'/',
|
|
]) {
|
|
const response = await request.get(`${baseURL}${path}`)
|
|
expect(response.ok(), `Failed to prewarm ${path}`).toBe(true)
|
|
}
|
|
|
|
// POST-only API route handlers (auto-save popovers): Next dev compiles a
|
|
// route on its first hit, and that compile can trigger a full-page reload
|
|
// for any client currently connected — which aborts an in-flight fetch mid
|
|
// test. An unauthenticated POST never succeeds, but it still forces the
|
|
// compile before any spec's client makes the real request.
|
|
for (const path of ['/campanha/municipios/advisors', '/campanha/municipios/expected-votes']) {
|
|
await request.post(`${baseURL}${path}`, { data: {} }).catch(() => undefined)
|
|
}
|
|
})
|