teqo-backup/tests/e2e/campaignDemandVisibility.e2e.spec.ts

115 lines
4.8 KiB
TypeScript

import {
campaignPageChrome,
expect,
expectPostResponse,
test,
type CampaignE2EFixture,
} from './fixtures/campaignE2EFixtures.js'
test.describe('C143 — demand visibility (explicit responsibles)', () => {
const setupDemand = async (
campaign: CampaignE2EFixture,
fixtures: CampaignE2EFixture['fixtures'],
) => {
const municipality = await fixtures.claimMunicipality()
const coordinator = await fixtures.createCampaignUser('coordinator', {
name: fixtures.value('Coordenadora C143'),
})
const responsible = await fixtures.createCampaignUser('advisor', {
name: fixtures.value('Assessora Responsável'),
})
const peer = await fixtures.createCampaignUser('advisor', {
name: fixtures.value('Assessor Colega'),
})
await campaign.payload.update({
collection: 'municipality',
id: municipality.id,
data: { advisors: [responsible.id, peer.id] },
depth: 0,
})
const demand = await fixtures.createCampaignDemand({
municipality: municipality.id,
createdBy: coordinator.id,
responsibles: [responsible.id],
title: fixtures.value('Demanda de acesso restrito'),
})
return { municipality, coordinator, responsible, peer, demand }
}
test('hides the demand from a same-municipality advisor who is not responsible', async ({
campaign,
context,
page,
}) => {
const { fixtures } = campaign
const { peer, demand } = await setupDemand(campaign, fixtures)
await campaign.sessionFor(context, peer)
await page.goto(`${campaign.baseURL}/campanha/demandas`)
// The list rendered for him: the empty state proves the page settled
// (and that the demand is absent — the link assertion below is the
// fail-closed complement).
await expect(page.getByText('Nenhuma demanda por aqui')).toBeVisible()
await expect(page.getByRole('link', { name: demand.title })).toHaveCount(0)
// The URL does not open either — the demand simply does not exist for him
// (the default 404 boundary is the root one, no campaign-specific page).
await page.goto(`${campaign.baseURL}/campanha/demandas/${demand.slug}`)
await expect(page.getByText('This page could not be found.')).toBeVisible()
})
test('lets a responsible hand access to a peer and revoke it again', async ({
campaign,
context,
page,
}) => {
const { fixtures } = campaign
const { peer, responsible, demand } = await setupDemand(campaign, fixtures)
const demandURL = `${campaign.baseURL}/campanha/demandas/${demand.slug}`
// The responsible manages the list: add the peer through the search dialog.
await campaign.sessionFor(context, responsible)
await page.goto(demandURL)
await expect(page.getByText('Só quem é responsável vê esta demanda.')).toBeVisible()
// The trigger announces the current selection (e.g. "…: 1 responsável").
await page.getByRole('button', { name: /Responsáveis pela demanda/ }).click()
await page.getByPlaceholder('Buscar assessor…').fill(peer.name)
await page.getByRole('option', { name: peer.name }).click()
// The multi-add dialog stays open (modal) — close it before saving.
await page.keyboard.press('Escape')
await page.getByRole('button', { name: 'Salvar responsáveis' }).click()
await expect(page.getByText('Responsáveis atualizados.')).toBeVisible()
await expect(page.getByRole('button', { name: `Remover ${peer.name}` })).toBeVisible()
// The peer now opens the demand.
await campaign.sessionFor(context, peer)
await page.goto(demandURL)
await expect(campaignPageChrome(page, demand.title)).toBeVisible()
// Back as the responsible, remove the peer and revoke the access again.
await campaign.sessionFor(context, responsible)
await page.goto(demandURL)
await page.getByRole('button', { name: `Remover ${peer.name}` }).click()
// The responsibles save is an optimistic server-action write — wait for the
// POST to land BEFORE swapping to the peer, or the peer's navigation can
// race the revoke (OPS83 run #16: the accessible demand still served).
await Promise.all([
expectPostResponse(page, demandURL),
page.getByRole('button', { name: 'Salvar responsáveis' }).click(),
])
await expect(page.getByRole('button', { name: `Remover ${peer.name}` })).toHaveCount(0)
// The peer already rendered THIS URL (granted, line 88), so the Next RSC
// cache can serve the previous payload on a plain goto even after the
// cookie swap (OPS83 run #15/#16). Break the router context through a
// blank page so the 404 boundary is fetched fresh from the server.
await campaign.sessionFor(context, peer)
await page.goto('about:blank')
await expect(page).toHaveURL(/about:blank/)
await page.goto(demandURL)
await expect(page.getByText('This page could not be found.')).toBeVisible()
})
})