Merge pull request #472 from fsolla/OPS20-isolar-a-porta-do-e2e-por-worktree-playwright-base-url
fix(worktree): e2e usa porta do slot — PLAYWRIGHT_BASE_URL no .env.test.local (OPS20, #464)
This commit is contained in:
commit
d7a796b4d9
6 changed files with 194 additions and 32 deletions
|
|
@ -30,7 +30,7 @@ Parallel agents must not fight over port 3000, the shared `teqo_test`, or a seco
|
|||
|
||||
- `slot` = numeric part of the issue code (`C15` → 15, `B164` → 164; hash fallback without digits; bumped on collision among live worktrees).
|
||||
- Dev server port `3100+slot`; databases `teqo_wt<slot>` (dev) and `teqo_wt<slot>_test` (tests), created on the **one shared container** with the full migration chain applied (one-time, ~30 s each).
|
||||
- Writes `.env.local` (DATABASE_URL, PORT, NEXT_PUBLIC_SITE_URL, PLAYWRIGHT_BASE_URL, PAYLOAD_SECRET + Blob/VAPID copied from the main repo) and `.env.test.local` (test DATABASE_URL). Both carry the marker `# teqo worktree env (generated by pnpm worktree next)`; **manual env files are never overwritten** — remove them and re-run `pnpm worktree next` (or `pnpm worktree plan` for the /plan-issue worktree) to regenerate.
|
||||
- Writes `.env.local` (DATABASE_URL, PORT, NEXT_PUBLIC_SITE_URL, PLAYWRIGHT_BASE_URL, PAYLOAD_SECRET + Blob/VAPID copied from the main repo) and `.env.test.local` (test DATABASE_URL, NEXT_PUBLIC_SITE_URL, **PLAYWRIGHT_BASE_URL** — both URL vars derived from the same slot port so a parallel e2e run never falls back to :3000; see `worktreeEnvFileContents` in `scripts/lib/worktree-env.mjs`). Both carry the marker `# teqo worktree env (generated by pnpm worktree next)`; **manual env files are never overwritten** — remove them and re-run `pnpm worktree next` (or `pnpm worktree plan` for the /plan-issue worktree) to regenerate.
|
||||
- `--no-migrate` skips the migration runs; `pnpm worktree kill` drops the worktree's generated databases (best-effort, `DROP DATABASE … WITH (FORCE)`).
|
||||
- Without Docker (Cursor Cloud) it degrades to the shared `teqo`/`teqo_test` with a warning and no port override.
|
||||
- Pure derivation: `scripts/lib/worktree-env.mjs` (unit-tested in `tests/unit/worktree.unit.spec.ts`).
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ Conteúdo movido do `AGENTS.md` em 2026-07-30 (fatiamento do paradigma de agente
|
|||
|
||||
---
|
||||
|
||||
**Recently resolved (2026-08-09):** **OPS20** (Issue #464) — o e2e de cada worktree agora usa a porta do slot próprio (`3100+slot`), nunca o fallback `3000`: o `.env.test.local` (que o `playwright.config.ts` lê em `playwright.config.ts:14`) passou a carregar `PLAYWRIGHT_BASE_URL` — antes ele só ia para o `.env.local` (que o config **não** lê), então dois `pnpm test:e2e` em worktrees paralelos subiam dois dev servers na porta `3000`. Causa-raiz tratada além do sintoma: os dois blocos env inline do `provision` (que já tinham derivado uma vez) viraram um builder puro único `worktreeEnvFileContents` em `scripts/lib/worktree-env.mjs` que deriva `NEXT_PUBLIC_SITE_URL` + `PLAYWRIGHT_BASE_URL` do mesmo `env.devPort` para **ambos** `.env.local`/`.env.test.local` (paridade estrutural, drift impossível) + unit tests de paridade em `tests/unit/worktree.unit.spec.ts` (falham se o drift voltar). `playwright.config.ts` intocado (a variável certa já existia; só faltava chegar). Sem Docker (fallback) continua degradando ao compartilhado — fora de escopo. Sem migration. Intenção [`porta-e2e-isolada-por-worktree.md`](plans/porta-e2e-isolada-por-worktree.md); impl [`porta-e2e-isolada-por-worktree-impl.md`](plans/porta-e2e-isolada-por-worktree-impl.md).
|
||||
**Recently resolved (2026-08-08):** **B174** (Issue #449) — a Sollinha (`/campanha/api/ai-chat`) trocou o provider de `@ai-sdk/deepseek` (API oficial `api.deepseek.com`) pelo **`@ai-sdk/deepinfra`** no caminho OpenAI-compatível da Deep Infra — **mesmo modelo** (`deepseek-ai/DeepSeek-V4-Flash`), **mesmas tools** e **mesma chave** que os agentes do time usam (um provedor, uma chave, uma fatura). Swap de 2 linhas no `route.ts`; dep `@ai-sdk/deepinfra@3.0.20` pinada na mesma ferroviária do `ai@7.0.47` (provider 4.0.4 / provider-utils 5.0.18, `pnpm why` confirma cópia única — nada de 4.0.7 duplicado), `@ai-sdk/deepseek` removido (dead dep, knip); `.env.example` `DEEPSEEK_API_KEY` → `DEEPINFRA_API_KEY` (B173 STT/Whisper reusa a mesma chave). Sem migration, access, UI ou teste novo — e2e já mocka o SSE (sem chave real no CI); rollback documentado = `git revert` (restaura provider/baseURL antiga); smoke de deploy = 2–3 perguntas forçando tool calling real antes de confiar o flip. Intenção [`sollinha-no-deepinfra.md`](plans/sollinha-no-deepinfra.md); impl [`sollinha-no-deepinfra-impl.md`](plans/sollinha-no-deepinfra-impl.md).
|
||||
|
||||
**Recently resolved (2026-08-08):** **B170** (Issue #441, follow-up B169) — o **contrato do colapso de chips virou spec unitário** (`tests/unit/relationChipCellCollapse.unit.spec.tsx`): `RelationChipCell` renderiza 16 chips com `getBoundingClientRect` stubado (4/linha, 20px, gap 6 — a matemática real de `COLLAPSED_CHIP_ROWS`/`CHIP_GAP_PX`) e o spec pina que o slice fica em 12 (3 linhas), "Ver mais…" expande para 16 e "Ver menos" recolhe para 12; casos tudo-cabe (8) e exatamente-cheio (12) não mostram toggle. Antes, os specs das células usavam `measureOverflow: false` ou colapsavam para 1 chip — a mudança de timing do B169 (medição em `useLayoutEffect`) não tinha regressão do comportamento de colapso. **F2 medido e deferido em vez de eliminado**: `PerformanceObserver('layout-shift')` no worktree confirma o resíduo pré-hidratação exatamente como registrado no B169 — load SSR→hidratação com shifts únicos `0.139/0.043/0.257` (fontes: shell — sidebar/Drawer/main/col-resize — nenhuma célula de chips) e a linha da célula indo `97px/42chips → 57px/0chips` numa única transição; **ordenação client-side (RSC) → zero shifts novos**. Eliminar a paint pré-hidratação exigiria estimativa de largura por label (rejeitada pelo dono, que mede layout real de propósito) ou mudança de layout/regra de colapso (anti-goal) — o shift único do primeiro load é aceitável num painel interno staff. Sem migration, dados, access ou mudança visual. Intenção [`estabilizar-lista-dobradinhas-followup.md`](docs/plans/estabilizar-lista-dobradinhas-followup.md); impl [`estabilizar-lista-dobradinhas-followup-impl.md`](docs/plans/estabilizar-lista-dobradinhas-followup-impl.md).
|
||||
|
|
|
|||
68
docs/plans/porta-e2e-isolada-por-worktree-impl.md
Normal file
68
docs/plans/porta-e2e-isolada-por-worktree-impl.md
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# Impl: Isolar a porta do e2e por worktree (e2e não deve disputar a porta 3000)
|
||||
|
||||
Status: aprovado
|
||||
Atualizado em: 2026-08-09
|
||||
Issue: #464
|
||||
Intenção: docs/plans/porta-e2e-isolada-por-worktree.md
|
||||
Appetite restante: herdado (~0,5 dia; o caminho cabe folgado)
|
||||
|
||||
## Leitura da intenção
|
||||
|
||||
- **Outcome:** dois `pnpm test:e2e` em worktrees diferentes, no mesmo host, rodam sem `EADDRINUSE` e sem um falar com o servidor do outro; cada run usa banco de teste + porta do slot do próprio worktree (nunca queda em `3000`); o dev server do e2e permanece amarrado ao banco de teste.
|
||||
- **O que NÃO negociar:** nada de autenticação/rota/DB novo; contratos de URL pública intactos; `playwright.config.ts` fora do escopo (a variável certa já existe e o config já a lê — o que precisa é a variável **chegar** em `.env.test.local`).
|
||||
- **O que reavaliar:** a hipótese da intenção é que a mudança é “meia linha” no bloco do `.env.test.local`. Confirmei a leitura — `playwright.config.ts:14` carrega `.env.test.local` com `override: true`, `playwright.config.ts:23` deriva `baseURL = PLAYWRIGHT_BASE_URL ?? http://localhost:3000`, e o webServer deriva `PORT` dessa `baseURL` (`playwright.config.ts:24,115`). Logo a meia linha resolve. **Mas** a causa-raiz não é a linha: é que os dois blocos env do provisionamento são mantidos à mão em paralelo (`scripts/worktree.mjs:250-279`) e isso já derivou uma vez — a única linha que faltou está em um lugar e não no outro. Decidi tratar a causa (paridade estrutural) além do sintoma.
|
||||
|
||||
## Abordagem recomendada
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[worktree.mjs provision] --> B[worktreeEnvFileContents em scripts/lib/worktree-env.mjs]
|
||||
B --> C[.env.local: dev + PLAYWRIGHT_BASE_URL]
|
||||
B --> D[.env.test.local: test + PLAYWRIGHT_BASE_URL -- NOVO]
|
||||
B -. mesma url do slot .-> E[baseURL + webServer.PORT em playwright.config.ts já transformam em porta do slot]
|
||||
```
|
||||
|
||||
**Opções consideradas:** A | B | C
|
||||
**Recomendação:** B — um único builder puro de **ambos** os arquivos env, com as duas URL (`NEXT_PUBLIC_SITE_URL` + `PLAYWRIGHT_BASE_URL`) derivadas do **mesmo** `env.devPort`, + testes de unidade na paridade. Troca a cola de dois blocos manuais irmãos (a exata classe de deriva que a intenção narra) por construção estrutural que torna a deriva impossível, e dá ao gate uma verificação automatizada real — a alternativa não teria **nenhuma** (playwright.config.ts não muda e rodar o provision real precisa de Docker fora do `gate:fast`).
|
||||
**Rejeitadas:**
|
||||
|
||||
- **A — meia linha só** (`PLAYWRIGHT_BASE_URL` no bloco do `.env.test.local` + doc): barato e vale como fix mínimo, mas deixa a estrutura de dois blocos manuais que **causou** o bug; a próxima variável nova cai em um bloco só de novo. Sem nenhum teste cobrindo o fix.
|
||||
- **C — reescrever/reordenar o fluxo de env do playwright** (templating único, carregar `.env.local` no config, faixa de porta própria para e2e): estoura o aceite e é o rabbit hole que a intenção manda cortar.
|
||||
|
||||
### Componentes / mudanças
|
||||
|
||||
- **`worktreeEnvFileContents` (novo, `scripts/lib/worktree-env.mjs`)**: função pura que recebe `{ branch, issueLabel, generatedBy, env, devUrl, testUrl, payloadSecret, copiedLines }` e devolve `{ dev: string[], test: string[] }`. Constroi o header compartilhado (marker + branch/slot/purpose) e deriva `url = http://localhost:${env.devPort}` **uma vez**, injetando `NEXT_PUBLIC_SITE_URL` + `PLAYWRIGHT_BASE_URL` nos dois. Morada conforme o padrão documentado em AGENTS.md: “Pure derivation lives in `scripts/lib/worktree-env.mjs` (unit-tested)”.
|
||||
- **`provision` (`scripts/worktree.mjs`)**: os dois blocos inline (linhas ~250-279) viram uma chamada ao builder puro; `writeFileSync` de `.env.local`/`.env.test.local` com `devLines`/`testLines`. Contratos de conteúdo **idênticos** aos de antes + `PLAYWRIGHT_BASE_URL` no test. `writeFallbackEnv` (sem Docker) intacto — a intenção exclui a porta compartilhada do fallback.
|
||||
- **Migration:** sem migration.
|
||||
- **Access / Consent:** N/A.
|
||||
- **UI:** N/A — Impeccable A.
|
||||
|
||||
### Testes
|
||||
|
||||
- `tests/unit/worktree.unit.spec.ts`: novo bloco cobrindo (1) arquivo test inclui `PLAYWRIGHT_BASE_URL=http://localhost:<devPort>` e `NEXT_PUBLIC_SITE_URL` no mesmo port; (2) paridade dev×test das duas URL (o teste que falha se o drift voltar); (3) header/marker presente e valores de DB corretos (dev vs test).
|
||||
|
||||
## Fases verificáveis
|
||||
|
||||
1. **Builder puro + fix** — extrair `worktreeEnvFileContents`, substituir blocos, escrever os testes de unidade.
|
||||
2. **Gates** — `pnpm gate:fast` (lint, typecheck, test:unit com o novo bloco verde); `pnpm format` se Prettier reclamar; `pnpm exec knip` para ver que nada ficou órfão.
|
||||
3. **Docs** — `.agents/skills/local-database/SKILL.md:33` (rolagem do `.env.test.local` passa a citar `PLAYWRIGHT_BASE_URL`); entrada curta em `docs/CHANGELOG-AGENTS.md`.
|
||||
|
||||
## Rabbit holes / Não escopo (engenharia)
|
||||
|
||||
- Reordenar o fluxo de env do playwright / mexer no `playwright.config.ts` (fora do escopo da intenção).
|
||||
- Isolar Blob/Vercel/tmp entre e2e paralelos (intenção: item próprio se medir conflito).
|
||||
- Sem-Docker fallback ganhar porta própria (intenção: degrada e fica assim).
|
||||
- `.env.example` documentando `PLAYWRIGHT_BASE_URL` — o config já tem fallback `3000` autocontido.
|
||||
|
||||
## Riscos e mitigação
|
||||
|
||||
- **Quebrar o provisionamento em ambientes reais** (ex.: ordem de linhas muda, mas dotenv não depende de ordem) — mitigação: builder reproduz exatamente as linhas de antes (diff 1:1) + testes de paridade; `kill`/`worktreeDatabaseNamesOf` continuam lendo `DATABASE_URL` dos dois arquivos, preservados.
|
||||
- **`PLAYWRIGHT_BASE_URL` cai no `.env.local` do worktree mas o e2e não lê esse arquivo em lugar nenhum novo** — esperado e inofensivo: `.env.local` é do dev server (que também passa a subir na porta do slot pelo `PORT` já existente); o config lê `.env.test.local`.
|
||||
- **Gate sem Docker**: o fix é exercitado pela unit test pura; nada depende do container.
|
||||
|
||||
## Aceite de engenharia
|
||||
|
||||
- [ ] Aceite de produto da intenção ainda coberto (e2e usa porta+banco do slot; sem fallback `3000`; dev server do e2e no banco de teste)
|
||||
- [ ] Invariantes AGENTS/engineering-standards (derivação mora em `worktree-env.mjs`; sem tocar contratos públicos)
|
||||
- [ ] Testes de domínio previstos (unit de paridade dos dois env files — o guard do drift)
|
||||
- [ ] Modelo: a Issue não declara `model-local:` — registrar `deepseek-v4-flash-high` (pareamento canônico de `composer-2.5`) no corpo da Issue ao fechar.
|
||||
|
|
@ -65,3 +65,53 @@ export const worktreeEnvironment = ({ branch, code, takenSlots = new Set() }) =>
|
|||
testDatabase: testDatabaseForSlot(slot),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Line arrays for `.env.local` (dev) and `.env.test.local` (test) of a
|
||||
* provisioned worktree. `NEXT_PUBLIC_SITE_URL` and `PLAYWRIGHT_BASE_URL` must
|
||||
* point BOTH files at the SAME slot port — the parity is what keeps a parallel
|
||||
* e2e run in another worktree from falling back to port 3000 (OPS20: they had
|
||||
* drifted — the dev file carried PLAYWRIGHT_BASE_URL, the test file didn't, and
|
||||
* playwright.config.ts only reads `.env.test.local`). Building both from one
|
||||
* `url` makes the drift structurally impossible.
|
||||
*
|
||||
* @param {{ branch: string, issueLabel?: string, generatedBy: string, env: { slot: number, devPort: number, devDatabase: string, testDatabase: string }, payloadSecret: string, copiedLines?: string[] }} options
|
||||
* @returns {{ dev: string[], test: string[] }}
|
||||
*/
|
||||
export const worktreeEnvFileContents = ({
|
||||
branch,
|
||||
issueLabel = '',
|
||||
generatedBy,
|
||||
env,
|
||||
payloadSecret,
|
||||
copiedLines = [],
|
||||
}) => {
|
||||
// Both DATABASE_URLs derive from the same slot as the port (module contract).
|
||||
const devUrl = `postgresql://teqo:teqo@localhost:5432/${env.devDatabase}`
|
||||
const testUrl = `postgresql://teqo:teqo@localhost:5432/${env.testDatabase}`
|
||||
const url = `http://localhost:${env.devPort}`
|
||||
const header = [
|
||||
GENERATED_ENV_MARKER,
|
||||
`# branch ${branch}${issueLabel} · slot ${env.slot} — ${generatedBy}`,
|
||||
]
|
||||
return {
|
||||
dev: [
|
||||
...header,
|
||||
`DATABASE_URL=${devUrl}`,
|
||||
`PORT=${env.devPort}`,
|
||||
`NEXT_PUBLIC_SITE_URL=${url}`,
|
||||
`PLAYWRIGHT_BASE_URL=${url}`,
|
||||
`PAYLOAD_SECRET=${payloadSecret}`,
|
||||
...copiedLines,
|
||||
'',
|
||||
],
|
||||
test: [
|
||||
...header,
|
||||
'# Lido DEPOIS de .env.test (vitest.setup.ts / playwright.config.ts) — suites isoladas.',
|
||||
`DATABASE_URL=${testUrl}`,
|
||||
`NEXT_PUBLIC_SITE_URL=${url}`,
|
||||
`PLAYWRIGHT_BASE_URL=${url}`,
|
||||
'',
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ import {
|
|||
DEV_PORT_BASE,
|
||||
GENERATED_ENV_MARKER,
|
||||
isGeneratedDatabaseName,
|
||||
worktreeEnvFileContents,
|
||||
worktreeEnvironment,
|
||||
} from './lib/worktree-env.mjs'
|
||||
import { branchNameForIssue, planBranchName } from './lib/worktree.mjs'
|
||||
|
|
@ -236,8 +237,6 @@ const provision = async ({ dir, branch, issue, env, skipMigrate, mainRoot, purpo
|
|||
|
||||
const devDatabase = env.devDatabase
|
||||
const testDatabase = env.testDatabase
|
||||
const devUrl = `postgresql://teqo:teqo@localhost:5432/${devDatabase}`
|
||||
const testUrl = `postgresql://teqo:teqo@localhost:5432/${testDatabase}`
|
||||
await ensureDatabases([devDatabase, testDatabase])
|
||||
|
||||
const mainEnv = readMainEnv(mainRoot)
|
||||
|
|
@ -247,36 +246,26 @@ const provision = async ({ dir, branch, issue, env, skipMigrate, mainRoot, purpo
|
|||
const issueLabel = issue ? ` · issue #${issue.number}` : ''
|
||||
const generatedBy = `gerado por pnpm worktree ${purpose}`
|
||||
|
||||
const devEnv = [
|
||||
GENERATED_ENV_MARKER,
|
||||
`# branch ${branch}${issueLabel} · slot ${env.slot} — ${generatedBy}`,
|
||||
`DATABASE_URL=${devUrl}`,
|
||||
`PORT=${env.devPort}`,
|
||||
`NEXT_PUBLIC_SITE_URL=http://localhost:${env.devPort}`,
|
||||
`PLAYWRIGHT_BASE_URL=http://localhost:${env.devPort}`,
|
||||
`PAYLOAD_SECRET=${payloadSecret}`,
|
||||
...copy('BLOB_READ_WRITE_TOKEN'),
|
||||
...copy('NEXT_PUBLIC_VAPID_PUBLIC_KEY'),
|
||||
...copy('VAPID_PUBLIC_KEY'),
|
||||
...copy('VAPID_PRIVATE_KEY'),
|
||||
...copy('VAPID_SUBJECT'),
|
||||
...copy('RESEND_API_KEY'),
|
||||
...copy('CAMPAIGN_EMAIL_FROM'),
|
||||
...copy('CAMPAIGN_EMAIL_FROM_NAME'),
|
||||
'',
|
||||
].join('\n')
|
||||
writeFileSync(join(dir, '.env.local'), devEnv)
|
||||
const { dev: devLines, test: testLines } = worktreeEnvFileContents({
|
||||
branch,
|
||||
issueLabel,
|
||||
generatedBy,
|
||||
env,
|
||||
payloadSecret,
|
||||
copiedLines: [
|
||||
...copy('BLOB_READ_WRITE_TOKEN'),
|
||||
...copy('NEXT_PUBLIC_VAPID_PUBLIC_KEY'),
|
||||
...copy('VAPID_PUBLIC_KEY'),
|
||||
...copy('VAPID_PRIVATE_KEY'),
|
||||
...copy('VAPID_SUBJECT'),
|
||||
...copy('RESEND_API_KEY'),
|
||||
...copy('CAMPAIGN_EMAIL_FROM'),
|
||||
...copy('CAMPAIGN_EMAIL_FROM_NAME'),
|
||||
],
|
||||
})
|
||||
writeFileSync(join(dir, '.env.local'), devLines.join('\n'))
|
||||
console.log(`[worktree] .env.local escrito (porta ${env.devPort}).`)
|
||||
|
||||
const testEnv = [
|
||||
GENERATED_ENV_MARKER,
|
||||
`# branch ${branch}${issueLabel} · slot ${env.slot} — ${generatedBy}`,
|
||||
'# Lido DEPOIS de .env.test (vitest.setup.ts / playwright.config.ts) — suites isoladas.',
|
||||
`DATABASE_URL=${testUrl}`,
|
||||
`NEXT_PUBLIC_SITE_URL=http://localhost:${env.devPort}`,
|
||||
'',
|
||||
].join('\n')
|
||||
writeFileSync(join(dir, '.env.test.local'), testEnv)
|
||||
writeFileSync(join(dir, '.env.test.local'), testLines.join('\n'))
|
||||
console.log('[worktree] .env.test.local escrito.')
|
||||
|
||||
if (skipMigrate) {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
isGeneratedDatabaseName,
|
||||
numericSlotOfCode,
|
||||
testDatabaseForSlot,
|
||||
worktreeEnvFileContents,
|
||||
worktreeEnvironment,
|
||||
} from '../../scripts/lib/worktree-env.mjs'
|
||||
import {
|
||||
|
|
@ -205,3 +206,56 @@ describe('worktreeEnvironment (per-worktree ports and databases)', () => {
|
|||
expect(GENERATED_ENV_MARKER).toContain('generated by pnpm worktree next')
|
||||
})
|
||||
})
|
||||
|
||||
describe('worktreeEnvFileContents (dev/test env parity)', () => {
|
||||
const env = worktreeEnvironment({ branch: 'C15-fullcalendar', code: 'C15' })
|
||||
const lines = worktreeEnvFileContents({
|
||||
branch: 'C15-fullcalendar',
|
||||
issueLabel: ' · issue #390',
|
||||
generatedBy: 'gerado por pnpm worktree next',
|
||||
env,
|
||||
payloadSecret: 'secret',
|
||||
copiedLines: ['BLOB_READ_WRITE_TOKEN=blob', 'VAPID_PRIVATE_KEY=key'],
|
||||
})
|
||||
const dev = lines.dev.join('\n')
|
||||
const test = lines.test.join('\n')
|
||||
const url = `http://localhost:${devPortForSlot(env.slot)}`
|
||||
|
||||
it('the test env carries PLAYWRIGHT_BASE_URL on the slot port (e2e never falls back to 3000)', () => {
|
||||
expect(test).toContain(`PLAYWRIGHT_BASE_URL=${url}`)
|
||||
})
|
||||
|
||||
it('keeps NEXT_PUBLIC_SITE_URL and PLAYWRIGHT_BASE_URL in parity across both files', () => {
|
||||
for (const key of ['NEXT_PUBLIC_SITE_URL', 'PLAYWRIGHT_BASE_URL']) {
|
||||
const devValue = dev.split('\n').find((line) => line.startsWith(`${key}=`))
|
||||
const testValue = test.split('\n').find((line) => line.startsWith(`${key}=`))
|
||||
expect(devValue).toBe(`${key}=${url}`)
|
||||
expect(testValue).toBe(devValue)
|
||||
}
|
||||
})
|
||||
|
||||
it('points each file at its own database and keeps dev-only fields in the dev file', () => {
|
||||
expect(dev).toContain(
|
||||
`DATABASE_URL=postgresql://teqo:teqo@localhost:5432/${devDatabaseForSlot(env.slot)}`,
|
||||
)
|
||||
expect(test).toContain(
|
||||
`DATABASE_URL=postgresql://teqo:teqo@localhost:5432/${testDatabaseForSlot(env.slot)}`,
|
||||
)
|
||||
expect(dev).toContain(`PORT=${devPortForSlot(env.slot)}`)
|
||||
expect(dev).toContain('PAYLOAD_SECRET=secret')
|
||||
expect(dev).toContain('BLOB_READ_WRITE_TOKEN=blob')
|
||||
expect(dev).toContain('VAPID_PRIVATE_KEY=key')
|
||||
expect(test).not.toContain('PAYLOAD_SECRET')
|
||||
expect(test).not.toContain('PORT=')
|
||||
expect(test).not.toContain('BLOB_READ_WRITE_TOKEN')
|
||||
expect(test).not.toContain('VAPID_PRIVATE_KEY')
|
||||
})
|
||||
|
||||
it('both files carry the generated marker and the same header', () => {
|
||||
for (const content of [dev, test]) {
|
||||
expect(content).toContain(GENERATED_ENV_MARKER)
|
||||
expect(content).toContain('branch C15-fullcalendar')
|
||||
expect(content).toContain(`· slot ${env.slot}`)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue