245 lines
9.5 KiB
TypeScript
245 lines
9.5 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { resolveActivityQuickActions } from '@/lib/activityQuickActions'
|
|
import { CAMPAIGN_WIZARD_ACTION_SLUGS } from '@/lib/campaignActionRoutes'
|
|
import { UNCOVERED_MUNICIPALITIES_LIST_HREF, homeActionsForRole } from '@/lib/campaignHomeActions'
|
|
import {
|
|
isCampaignActionsPath,
|
|
isCampaignHomePath,
|
|
isLeaderContactsPath,
|
|
shouldMountQuickActionsDrawer,
|
|
} from '@/lib/campaignQuickActionMount'
|
|
import {
|
|
ACTIVITY_LIST_PATH,
|
|
ACTIVITY_NEW_PATH,
|
|
ACTIVITY_TOUR_COMPOSER_PATH,
|
|
ORGANIZATIONS_LIST_PATH,
|
|
ORGANIZATION_NEW_PATH,
|
|
isActivityTourComposerPath,
|
|
parseActivityQuickActionSurface,
|
|
parseOrganizationQuickActionSurface,
|
|
} from '@/lib/campaignQuickActionPaths'
|
|
import { resolveQuickActionsForPath } from '@/lib/campaignQuickActionRegistry'
|
|
import {
|
|
QUICK_ACTIONS_SNAP_COLLAPSED,
|
|
QUICK_ACTIONS_SNAP_EXPANDED,
|
|
quickActionsSnapIsExpanded,
|
|
} from '@/lib/campaignQuickActionSnap'
|
|
import { resolveOrganizationQuickActions } from '@/lib/organizationQuickActions'
|
|
|
|
describe('campaignQuickActionMount', () => {
|
|
it('treats Início as exact match only', () => {
|
|
expect(isCampaignHomePath('/campanha')).toBe(true)
|
|
expect(isCampaignHomePath('/campanha/')).toBe(true)
|
|
expect(isCampaignHomePath('/campanha/municipios')).toBe(false)
|
|
})
|
|
|
|
it('matches action wizard subtree', () => {
|
|
expect(isCampaignActionsPath('/campanha/acoes')).toBe(true)
|
|
expect(isCampaignActionsPath('/campanha/acoes/atualizar-votos')).toBe(true)
|
|
expect(isCampaignActionsPath('/campanha/municipios')).toBe(false)
|
|
})
|
|
|
|
it('matches leader contacts subtree', () => {
|
|
expect(isLeaderContactsPath('/campanha/contatos')).toBe(true)
|
|
expect(isLeaderContactsPath('/campanha/contatos/novo')).toBe(true)
|
|
expect(isLeaderContactsPath('/campanha')).toBe(false)
|
|
})
|
|
|
|
it('mounts for staff outside Início and acoes', () => {
|
|
expect(shouldMountQuickActionsDrawer('/campanha/municipios', 'coordinator')).toBe(true)
|
|
expect(shouldMountQuickActionsDrawer('/campanha/territorios', 'coordinator')).toBe(true)
|
|
expect(shouldMountQuickActionsDrawer('/campanha', 'coordinator')).toBe(false)
|
|
expect(shouldMountQuickActionsDrawer('/campanha/acoes/registrar-sinal', 'advisor')).toBe(false)
|
|
})
|
|
|
|
it('mounts for leader only on contacts', () => {
|
|
expect(shouldMountQuickActionsDrawer('/campanha/contatos', 'leader')).toBe(true)
|
|
expect(shouldMountQuickActionsDrawer('/campanha/municipios', 'leader')).toBe(false)
|
|
})
|
|
|
|
it('skips the E13 tour composer (B84)', () => {
|
|
expect(isActivityTourComposerPath(ACTIVITY_TOUR_COMPOSER_PATH)).toBe(true)
|
|
expect(shouldMountQuickActionsDrawer(ACTIVITY_TOUR_COMPOSER_PATH, 'coordinator')).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('campaignQuickActionPaths (activities)', () => {
|
|
it('parses list and detail surfaces', () => {
|
|
expect(parseActivityQuickActionSurface(ACTIVITY_LIST_PATH)).toEqual({ kind: 'list' })
|
|
expect(parseActivityQuickActionSurface(`${ACTIVITY_LIST_PATH}/`)).toEqual({ kind: 'list' })
|
|
expect(parseActivityQuickActionSurface('/campanha/atividades/caminhada-centro')).toEqual({
|
|
kind: 'detail',
|
|
activitySlug: 'caminhada-centro',
|
|
})
|
|
})
|
|
|
|
it('ignores nova, giros and nested edit routes', () => {
|
|
expect(parseActivityQuickActionSurface(ACTIVITY_NEW_PATH)).toBeNull()
|
|
expect(parseActivityQuickActionSurface(ACTIVITY_TOUR_COMPOSER_PATH)).toBeNull()
|
|
expect(parseActivityQuickActionSurface('/campanha/atividades/foo/editar')).toBeNull()
|
|
})
|
|
})
|
|
|
|
describe('organizationQuickActions (B88)', () => {
|
|
it('parses list and detail surfaces', () => {
|
|
expect(parseOrganizationQuickActionSurface(ORGANIZATIONS_LIST_PATH)).toEqual({ kind: 'list' })
|
|
expect(parseOrganizationQuickActionSurface(`${ORGANIZATIONS_LIST_PATH}/`)).toEqual({
|
|
kind: 'list',
|
|
})
|
|
expect(parseOrganizationQuickActionSurface('/campanha/organizacoes/sindmed')).toEqual({
|
|
kind: 'detail',
|
|
organizationSlug: 'sindmed',
|
|
})
|
|
})
|
|
|
|
it('ignores nova and nested routes', () => {
|
|
expect(parseOrganizationQuickActionSurface(ORGANIZATION_NEW_PATH)).toBeNull()
|
|
expect(parseOrganizationQuickActionSurface('/campanha/organizacoes/foo/editar')).toBeNull()
|
|
})
|
|
|
|
it('lists new-organization on the catalog page', () => {
|
|
const actions = resolveOrganizationQuickActions({ kind: 'list' }, 'coordinator', {})
|
|
expect(actions.map((action) => action.id)).toEqual(['new-organization'])
|
|
expect(actions[0]?.href).toBe(ORGANIZATION_NEW_PATH)
|
|
})
|
|
|
|
it('returns empty detail catalog without leadership filter URL', () => {
|
|
expect(
|
|
resolveOrganizationQuickActions(
|
|
{ kind: 'detail', organizationSlug: 'sindmed' },
|
|
'coordinator',
|
|
{ organizationSlug: 'sindmed' },
|
|
),
|
|
).toEqual([])
|
|
})
|
|
|
|
it('returns empty catalog for leader lockdown', () => {
|
|
expect(resolveOrganizationQuickActions({ kind: 'list' }, 'leader', {})).toEqual([])
|
|
})
|
|
})
|
|
|
|
describe('activityQuickActions (B84)', () => {
|
|
it('lists vertical verbs on the activity list', () => {
|
|
const actions = resolveActivityQuickActions({ kind: 'list' }, 'coordinator', {})
|
|
expect(actions.map((action) => action.id)).toEqual(['new-activity', 'plan-tour'])
|
|
expect(actions[0]?.href).toBe(ACTIVITY_NEW_PATH)
|
|
expect(actions[1]?.href).toBe(ACTIVITY_TOUR_COMPOSER_PATH)
|
|
})
|
|
|
|
it('prefills wizards and detail shortcuts on activity detail', () => {
|
|
const actions = resolveActivityQuickActions(
|
|
{ kind: 'detail', activitySlug: 'comicio-feira' },
|
|
'coordinator',
|
|
{ activitySlug: 'comicio-feira', municipalitySlug: 'feira-de-santana' },
|
|
)
|
|
|
|
expect(actions.some((action) => action.id === 'update-votes')).toBe(true)
|
|
expect(
|
|
actions
|
|
.find((action) => action.id === 'update-votes')
|
|
?.href?.includes('municipio=feira-de-santana'),
|
|
).toBe(true)
|
|
expect(actions.find((action) => action.id === 'edit-activity')?.href).toBe(
|
|
'/campanha/atividades/comicio-feira/editar',
|
|
)
|
|
expect(actions.find((action) => action.id === 'activity-tasks')?.href).toBe(
|
|
'/campanha/atividades/comicio-feira?tab=tasks',
|
|
)
|
|
})
|
|
|
|
it('omits wizard prefills without municipality context', () => {
|
|
const actions = resolveActivityQuickActions(
|
|
{ kind: 'detail', activitySlug: 'panfletagem' },
|
|
'advisor',
|
|
{ activitySlug: 'panfletagem' },
|
|
)
|
|
|
|
expect(actions.some((action) => action.id === 'register-demand')).toBe(false)
|
|
expect(actions.map((action) => action.id)).toEqual([
|
|
'edit-activity',
|
|
'activity-tasks',
|
|
'activity-updates',
|
|
])
|
|
})
|
|
})
|
|
|
|
describe('campaignQuickActionRegistry', () => {
|
|
const staffActionIds = homeActionsForRole('coordinator').map((action) => action.id)
|
|
|
|
it('delegates organization routes to the B88 catalog', () => {
|
|
const actions = resolveQuickActionsForPath(ORGANIZATIONS_LIST_PATH, 'coordinator', {})
|
|
expect(actions.map((action) => action.id)).toEqual(['new-organization'])
|
|
expect(actions[0]?.href).toBe(ORGANIZATION_NEW_PATH)
|
|
})
|
|
|
|
it('returns empty organization detail catalog in the registry', () => {
|
|
expect(
|
|
resolveQuickActionsForPath('/campanha/organizacoes/sindmed', 'advisor', {
|
|
organizationSlug: 'sindmed',
|
|
}),
|
|
).toEqual([])
|
|
})
|
|
|
|
it('returns empty catalog for unregistered paths', () => {
|
|
expect(resolveQuickActionsForPath('/campanha/apoiadores', 'coordinator', {})).toEqual([])
|
|
})
|
|
|
|
it('delegates municipality list and detail catalogs (B80)', () => {
|
|
const list = resolveQuickActionsForPath('/campanha/municipios', 'coordinator', {})
|
|
expect(list).toHaveLength(6)
|
|
|
|
const detail = resolveQuickActionsForPath('/campanha/municipios/foo', 'coordinator', {
|
|
municipalitySlug: 'foo',
|
|
})
|
|
expect(detail).toHaveLength(5)
|
|
expect(detail.find((action) => action.id === 'update-votes')?.href).toBe(
|
|
'/campanha/acoes/atualizar-votos?municipio=foo',
|
|
)
|
|
})
|
|
|
|
it('delegates activity routes to the B84 catalog', () => {
|
|
const actions = resolveQuickActionsForPath(ACTIVITY_LIST_PATH, 'coordinator', {})
|
|
expect(actions.map((action) => action.id)).toEqual(['new-activity', 'plan-tour'])
|
|
})
|
|
|
|
it('builds wizard hrefs with municipality slug from context', () => {
|
|
const actions = resolveQuickActionsForPath(
|
|
'/campanha/atividades/evento-zona-1',
|
|
'coordinator',
|
|
{
|
|
municipalitySlug: 'salvador-ze-01',
|
|
},
|
|
)
|
|
const registerSignal = actions.find((action) => action.id === 'register-signal')
|
|
expect(registerSignal?.href).toBe(
|
|
`/campanha/acoes/${CAMPAIGN_WIZARD_ACTION_SLUGS['register-signal']}?municipio=salvador-ze-01`,
|
|
)
|
|
})
|
|
|
|
it('returns staff Início catalog on territorios without municipality prefill (B81)', () => {
|
|
const actions = resolveQuickActionsForPath('/campanha/territorios', 'coordinator', {})
|
|
expect(actions.map((action) => action.id)).toEqual(staffActionIds)
|
|
expect(actions.find((action) => action.id === 'update-votes')?.href).toBe(
|
|
'/campanha/acoes/atualizar-votos',
|
|
)
|
|
expect(actions.find((action) => action.id === 'uncovered-municipalities')?.href).toBe(
|
|
UNCOVERED_MUNICIPALITIES_LIST_HREF,
|
|
)
|
|
for (const action of actions) {
|
|
expect(action.href).not.toContain('municipio=')
|
|
}
|
|
})
|
|
|
|
it('returns empty catalog on territorios for leader lockdown', () => {
|
|
expect(resolveQuickActionsForPath('/campanha/territorios', 'leader', {})).toEqual([])
|
|
})
|
|
})
|
|
|
|
describe('campaignQuickActionSnap', () => {
|
|
it('detects expanded snap', () => {
|
|
expect(quickActionsSnapIsExpanded(QUICK_ACTIONS_SNAP_EXPANDED)).toBe(true)
|
|
expect(quickActionsSnapIsExpanded(QUICK_ACTIONS_SNAP_COLLAPSED)).toBe(false)
|
|
expect(quickActionsSnapIsExpanded(null)).toBe(false)
|
|
})
|
|
})
|