eduardweb.
Prisma ORMIntermediar#prisma#ci-cd#database#testing

Cum scrii seed-uri de Prisma pentru CI fără să-ți blochezi pipeline-ul

De Elena Dumitrescu, 4 iul. 2026 · 15 vizualizări · 2 like-uri

Postat 4 iul. 2026
typescript
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

async function main() {
  const testUsers = [
    { email: 'admin@test.com', name: 'Admin User', role: 'ADMIN' },
    { email: 'user@test.com', name: 'Regular User', role: 'USER' },
  ];

  // Rulăm în paralel pentru viteză, dar garantăm idempotența prin upsert
  await Promise.all(
    testUsers.map((user) =>
      prisma.user.upsert({
        where: { email: user.email },
        update: { name: user.name, role: user.role },
        create: user,
      })
    )
  );

  console.log('Seed-ul pentru CI a fost rulat cu succes.');
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

Am stricat de atâtea ori pipeline-ul de CI din cauza seed-urilor de bază de date încât am pierdut numărul. Ori dădea eroare de cheie unică la a doua rulare, ori dura 5 minute doar ca să insereze niște useri de test. Dacă folosești Prisma, există câteva reguli simple ca să ai date sigure la fiecare commit, fără bătăi de cap.

Problema cu create în loc de upsert

La început, toți facem greșeala asta: scriem un script simplu de seed care apelează prisma.user.create() pentru câțiva useri de test. Pe mașina locală merge perfect prima dată. A doua oară, primești un mare crash pentru că userul cu emailul ăla există deja în baza de date locală.

În CI, treaba asta devine critică. Dacă rulezi teste de integrare și baza de date nu este recreată de la zero la fiecare rulare (ceea ce e de preferat ca să economisești timp și resurse), seed-ul tău va crăpa instant.

Soluția este să folosești exclusiv upsert. Acesta verifică dacă înregistrarea există deja (folosind un câmp unic, de regulă ID sau email). Dacă există, face update (sau îi dai un obiect gol ca să nu modifice nimic), iar dacă nu, o creează de la zero. Trade-off-ul aici e că upsert este vizibil mai lent decât un simplu create, dar siguranța pe care ți-o oferă merită fiecare milisecundă în plus.

Capcana Faker în CI: Ai nevoie de determinism

Generatoarele de date fake, gen @faker-js/faker, sunt excelente pentru mediul de dezvoltare local. Îți umplu interfața cu nume și imagini realiste, dar în CI, Faker este moartea pasiunii.

Am avut un proiect cu vreo 80 de teste end-to-end în Playwright. O dată la zece build-uri, un test pica complet aleatoriu. Ne-a luat două zile de debugging să ne prindem că Faker genera uneori un nume de user extrem de lung care strica layout-ul sau conținea caractere speciale care dădeau peste cap selectorii CSS din teste.

Pentru CI, ai nevoie de determinism total. Dacă vrei neapărat Faker, folosește faker.seed(123) înainte de a genera datele. Asta garantează că Faker va genera exact aceleași valori la fiecare rulare. Totuși, sfatul meu este să rămâi la date statice, bine definite (de exemplu, user-admin@test.com, user-regular@test.com), pe care testele tale se pot baza fără surprize.

Cum facem seed-ul rapid?

Prisma nu are o metodă nativă de upsertMany. Dacă ai de inserat 200 de înregistrări și faci câte un await prisma.model.upsert într-o buclă for, o să dureze o veșnicie din cauza roundtrip-urilor către baza de date. La un proiect cu vreo 8k de înregistrări de nomenclator, seed-ul dura aproape 3 minute pe un container mic de CI.

Am rezolvat problema batch-uind promisiunile. În loc de await în buclă, împărțim datele în chunk-uri și folosim Promise.all pentru a rula operațiunile în paralel. Doar ai grijă să nu depășești limita de conexiuni a bazei de date din connection pool.

Voi cum gestionați datele de test în CI? Curățați baza de date complet la fiecare rulare sau vă bazați pe seed-uri idempotente?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.