The existing 380-test backend suite runs entirely against the in-memory
datastore provider, which treats every partition-key value as equivalent.
This hid one entire class of bug — partition-key mismatches — until
production. D7 closes that gap.
Implementation:
- backend/src/test-helpers.ts adds useCosmosDatastore() that swaps the
active provider for CosmosDatastoreProvider using COSMOS_ENDPOINT /
COSMOS_KEY / COSMOS_DATABASE. Throws synchronously when env is missing
so a misconfigured run fails loudly instead of silently falling back
to in-memory.
- backend/vitest.config.ts now excludes src/**/*.cosmos.test.ts so the
default 'pnpm test' run stays green for contributors without Docker.
- backend/vitest.cosmos.config.ts (new) includes ONLY *.cosmos.test.ts,
bumps testTimeout to 30s / hookTimeout to 60s for the real client
round-trips, and locks DB_PROVIDER=cosmos in test env.
- backend/src/cosmos.smoke.cosmos.test.ts (new) covers the four most
important partition-key contracts in NoteLett:
workspaces /userId
notes /workspaceId
note_tasks /workspaceId
note_shares /workspaceId (full create → resolve → delete → null)
Each test also asserts that a wrong-partition-key lookup returns null,
which is the failure mode the in-memory provider cannot simulate.
- backend/package.json adds 'test:cosmos' script.
- .github/workflows/ci.yml gains a backend-cosmos job that boots the
official mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator
container as a service, waits for it to be ready (60 × 5s polls of
/_explorer/emulator.pem), then runs pnpm test:cosmos against it.
The job depends on the existing backend job so the emulator only
spins up after unit tests pass.
Verified locally:
- pnpm --filter @notelett/backend test: 380/380 (cosmos suite excluded)
- vitest list --config vitest.cosmos.config.ts: 4 tests under the cosmos
smoke suite, as designed
- pnpm run verify: end-to-end green (backend 380/380, web 96/96,
mobile 97/97)
- ci.yml passes Python yaml.safe_load
CI verification: the new job will execute on the next push. Local
verification against the emulator requires Docker on the dev host.
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
import Fastify from 'fastify';
|
|
import { CosmosDatastoreProvider, MemoryDatastoreProvider } from '@bytelyst/datastore';
|
|
import { setProvider } from './lib/datastore.js';
|
|
|
|
export function resetMemoryDatastore(): void {
|
|
const provider = new MemoryDatastoreProvider();
|
|
setProvider(provider);
|
|
}
|
|
|
|
/**
|
|
* Bind the active datastore to a live Azure Cosmos endpoint. Only used by
|
|
* `*.cosmos.test.ts` suites running under `vitest.cosmos.config.ts`, which
|
|
* is gated on COSMOS_ENDPOINT being set (CI: cosmos-emulator service).
|
|
*
|
|
* Throws synchronously if the required env vars are missing so individual
|
|
* tests fail loudly instead of silently falling back to in-memory.
|
|
*/
|
|
export function useCosmosDatastore(): void {
|
|
if (!process.env.COSMOS_ENDPOINT || !process.env.COSMOS_KEY) {
|
|
throw new Error('useCosmosDatastore() requires COSMOS_ENDPOINT and COSMOS_KEY to be set');
|
|
}
|
|
const provider = new CosmosDatastoreProvider({
|
|
endpoint: process.env.COSMOS_ENDPOINT,
|
|
key: process.env.COSMOS_KEY,
|
|
database: process.env.COSMOS_DATABASE || 'notelett_test',
|
|
});
|
|
setProvider(provider);
|
|
}
|
|
|
|
export async function buildTestApp(
|
|
routePlugin: (app: ReturnType<typeof Fastify>) => Promise<void>,
|
|
) {
|
|
resetMemoryDatastore();
|
|
|
|
const app = Fastify({ logger: false });
|
|
await app.register(routePlugin, { prefix: '/api' });
|
|
await app.ready();
|
|
return app;
|
|
}
|
|
|
|
export const TEST_USER_ID = 'test-user-1';
|
|
export const TEST_PRODUCT_ID = 'notelett';
|
|
|
|
export function authHeader() {
|
|
return { authorization: 'Bearer test-token' };
|
|
}
|