Files
pn-new-crm/tests/integration/residential-module.test.ts
Matt 172af02f81 feat(residential-toggle): port-level module gate for Residential
Adds a `residential_module_enabled` port setting (default ON) that
hides/disables the entire Residential surface when an admin turns it
off, mirroring the Tenancies / Invoices / Expenses module-toggle
pattern. Disabling is a soft hide — residential clients/interests are
preserved and reappear on re-enable.

Surfaces gated:
- Route guard: new residential/layout.tsx renders ModuleDisabledPage
  (covers all 5 residential pages)
- Sidebar "Residential" section + mobile more-sheet tile (SSR-resolved
  residentialModuleByPort threaded layout → app-shell → sidebar)
- Global search: residential client/interest buckets early-return at
  the shared chokepoint so disabled-port records don't dead-end
- Public intake: /api/public/residential-inquiries 404s when off
- Admin Switch in settings-manager (writes via settings PUT)

Service TDD'd (residential-module.test.ts, 6 tests) plus a
disabled-port rejection test on the public endpoint. tsc + lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 18:49:16 +02:00

53 lines
2.0 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { NotFoundError } from '@/lib/errors';
import {
assertResidentialModuleEnabled,
disableResidentialModule,
enableResidentialModule,
isResidentialModuleEnabled,
} from '@/lib/services/residential-module.service';
import { makePort } from '../helpers/factories';
describe('residential module gate', () => {
it('defaults to ENABLED for a fresh port (no setting row)', async () => {
const port = await makePort();
expect(await isResidentialModuleEnabled(port.id)).toBe(true);
});
it('disableResidentialModule turns it off (soft hide; setting persists)', async () => {
const port = await makePort();
await disableResidentialModule(port.id);
expect(await isResidentialModuleEnabled(port.id)).toBe(false);
});
it('enableResidentialModule turns it back on after a disable', async () => {
const port = await makePort();
await disableResidentialModule(port.id);
expect(await isResidentialModuleEnabled(port.id)).toBe(false);
await enableResidentialModule(port.id);
expect(await isResidentialModuleEnabled(port.id)).toBe(true);
});
it('enable/disable are idempotent (safe to call when already in that state)', async () => {
const port = await makePort();
await enableResidentialModule(port.id);
await enableResidentialModule(port.id);
expect(await isResidentialModuleEnabled(port.id)).toBe(true);
await disableResidentialModule(port.id);
await disableResidentialModule(port.id);
expect(await isResidentialModuleEnabled(port.id)).toBe(false);
});
it('assertResidentialModuleEnabled resolves when enabled', async () => {
const port = await makePort();
await expect(assertResidentialModuleEnabled(port.id)).resolves.toBeUndefined();
});
it('assertResidentialModuleEnabled throws NotFoundError when disabled', async () => {
const port = await makePort();
await disableResidentialModule(port.id);
await expect(assertResidentialModuleEnabled(port.id)).rejects.toBeInstanceOf(NotFoundError);
});
});