Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,14 @@ jobs:
PG_PORT: 5432
PG_DATABASE: herbario_test
PG_USERNAME: postgres
PG_PASSWORD: testpassword
PG_MIGRATION_USERNAME: postgres
PG_MIGRATION_PASSWORD: testpassword
PG_PASSWORD: secret
services:
postgres:
image: postgis/postgis:18-3.6
env:
POSTGRES_DB: herbario_test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: testpassword
POSTGRES_PASSWORD: secret
ports:
- 5432:5432
options: >-
Expand All @@ -74,9 +72,9 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Apply base schema
run: psql -h $PG_HOST -p $PG_PORT -U $PG_MIGRATION_USERNAME -d $PG_DATABASE -f test/integration/setup/schema.sql
run: psql -h $PG_HOST -p $PG_PORT -U $PG_USERNAME -d $PG_DATABASE -f test/integration/setup/schema.sql
env:
PGPASSWORD: ${{ env.PG_MIGRATION_PASSWORD }}
PGPASSWORD: ${{ env.PG_PASSWORD }}
- name: Run integration tests
run: yarn test:integration

Expand Down
6 changes: 3 additions & 3 deletions compose.integration.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
services:
postgres:
image: postgis/postgis:18-3.6
container_name: herbario_postgresql_e2e
container_name: herbario_postgresql_test
environment:
POSTGRES_DB: herbario_e2e
POSTGRES_DB: herbario_test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: testpassword
POSTGRES_PASSWORD: secret
ports:
- "5433:5432"
volumes:
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
"build": "node build.mjs",
"test": "vitest --run",
"test:unit": "vitest --run --project unit",
"test:unit:watch": "vitest --project unit",
"test:unit:watch": "vitest --project unit",
"test:integration": "vitest --run --project integration",
"test:integration:watch": "vitest --project integration",
"test:integration:watch": "vitest --project integration",
"test:coverage": "vitest --run --project unit --coverage",
"prepare": "husky",
"audit": "npm audit --audit-level=moderate",
Expand Down
47 changes: 22 additions & 25 deletions test/integration/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Testes de integração

Os testes de integração rodam contra um banco PostgreSQL real. **Você é responsável por
iniciar o container e aplicar as migrations antes de executar os testes.**
Os testes de integração sobem o Express in-process (via `supertest`) e falam com
um PostgreSQL/PostGIS real. **Você é responsável por iniciar o container antes
de executar os testes.** O schema é aplicado automaticamente na primeira
inicialização do banco (`schema.sql` montado em `docker-entrypoint-initdb.d`).

## Pré-requisitos

Expand All @@ -16,30 +18,34 @@ iniciar o container e aplicar as migrations antes de executar os testes.**
docker compose -f compose.integration.yml up -d
```

Isso sobe um container PostgreSQL na porta **5433** usando as credenciais do `.env`.
Isso sobe um PostgreSQL na porta **5433** (`herbario_test` / `postgres` / `secret`),
os mesmos valores de `.env.test`. O arquivo Compose já fixa `POSTGRES_*` e a porta;
não depende do `.env` da aplicação.

### 2. Aplique as migrations
### 2. Schema (sem migrations)

```bash
npm run migration:apply
```
A suíte **não** executa `migration:apply`. Muitos arquivos em
`src/database/migration/` são incrementais, dependem de dados reais ou ainda
usam SQL de MySQL — não dá para replayar o histórico no Postgres de teste.

Isso executa o stack completo de migrations no banco definido no `.env`. Você só precisa
rodar de novo quando novas migrations forem adicionadas.
O contrato é: `schema.sql` é um dump do schema **já migrado**. Quando uma
migration alterar o schema que os testes usam, regenere o dump e commite junto.

## Executando os testes

```bash
npm run test:integration
yarn test:integration
```

A suíte de testes conecta ao banco já em execução e roda todos os testes
em `test/integration/`. Nenhuma alteração de schema é feita no momento do teste.
A suíte conecta ao banco já em execução e roda os arquivos em
`test/integration/**/*.test.ts`. Nenhuma alteração de schema é feita no momento
do teste. O `globalSetup` apenas verifica a conexão e faz `TRUNCATE` das tabelas
usadas pelos testes.

Para o modo watch (reexecuta ao mudar arquivos):

```bash
npm run test:integration:watch
yarn test:integration:watch
```

## Parando o banco
Expand All @@ -48,8 +54,8 @@ npm run test:integration:watch
docker compose -f compose.integration.yml down
```

Como o container usa `tmpfs`, todos os dados são perdidos ao parar. Na próxima vez,
comece do zero com `docker compose up -d` seguido de `migration:apply`.
Como o container usa `tmpfs`, todos os dados (e o schema) são perdidos ao parar.
Na próxima vez, comece do zero com `docker compose -f compose.integration.yml up -d`.

---

Expand All @@ -61,15 +67,6 @@ Cada teste deve ser dono dos seus dados:
coluna identificadora (sigla, nome, etc.) que distinga suas linhas das de outros arquivos de teste.
- Limpe os dados inseridos em um bloco `finally`, para que a limpeza rode mesmo se a asserção falhar.
- **`afterAll`** — chame `knex.destroy()` para liberar o pool de conexões.
- Nunca use `TRUNCATE` — isso apagaria dados de outros arquivos de teste que rodam em paralelo.
- Nunca use `TRUNCATE` no arquivo de teste — isso apagaria dados de outros arquivos que rodam em paralelo.

Veja `test/integration/pais/lista-paises.test.ts` para um exemplo concreto.

### Convenção de namespace

Use um prefixo curto e único nos identificadores para evitar colisões entre arquivos de teste:

| Arquivo de teste | Prefixo usado |
|---|---|
| `lista-paises.test.ts` | `XPBR`/`XPAR`/`XPCB` (sigla do país), `XPAI`/`XPCI` (prefixo do nome) |
| `lista-estados.test.ts` | `XEBR` (sigla do país), `XEPR`/`XESP` (sigla do estado) |
9 changes: 5 additions & 4 deletions test/integration/setup/global-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ export async function setup(): Promise<void> {
try {
await knex.raw('SELECT 1')
await truncateTables(knex)
} catch {
} catch (error) {
const reason = error instanceof Error ? error.message : String(error)
throw new Error(
`Cannot connect to the test database (${PG_HOST}:${PG_PORT}/${PG_DATABASE}). `
+ 'Start the container and apply the schema before running e2e tests — '
`Cannot prepare the test database (${PG_HOST}:${PG_PORT}/${PG_DATABASE}): ${reason}. `
+ 'Start the container (schema is applied on first boot) — '
+ 'see test/integration/README.md'
)
} finally {
Expand All @@ -51,5 +52,5 @@ export async function setup(): Promise<void> {
}

export async function teardown(): Promise<void> {
// Container lifecycle is managed by the developer — see test/e2e/README.md
// Container lifecycle is managed by the developer — see test/integration/README.md
}
7 changes: 7 additions & 0 deletions test/integration/setup/load-env.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { mkdirSync } from 'node:fs'
import path from 'node:path'
import { loadEnvFile } from 'node:process'

try {
loadEnvFile('.env.test')
} catch {
// In CI, environment variables are injected directly into the process
}

mkdirSync(path.resolve(process.cwd(), 'uploads'), { recursive: true })
2 changes: 1 addition & 1 deletion test/integration/setup/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ COMMENT ON SCHEMA public IS '';
-- Name: topology; Type: SCHEMA; Schema: -; Owner: -
--

CREATE SCHEMA topology;
CREATE SCHEMA IF NOT EXISTS topology;


--
Expand Down
Loading