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

Cum scrii seed-uri de Prisma care nu-ți crapă pipeline-ul de CI

De Ana Ionescu, 3 iul. 2026 · 20 vizualizări · 3 like-uri

Postat 3 iul. 2026
typescript
import { PrismaClient } from '@prisma/client';
import { faker } from '@faker-js/faker';

const prisma = new PrismaClient();

async function main() {
  // Forțăm Faker să genereze date identice la fiecare rulare
  faker.seed(12345);

  const testUsers = Array.from({ length: 10 }).map(() => ({
    email: faker.internet.email().toLowerCase(),
    name: faker.person.fullName(),
  }));

  for (const user of testUsers) {
    await prisma.user.upsert({
      where: { email: user.email },
      update: { name: user.name },
      create: {
        email: user.email,
        name: user.name,
      },
    });
  }
}

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

Să ridici un mediu de test curat în CI e simplu pe hârtie, dar în practică devine rapid un coșmar dacă datele tale de test sunt complet random. Am pățit asta pe un proiect cu vreo 12k utilizatori activi, unde testele de integrare picau o dată la trei build-uri fără niciun motiv evident în cod. Vinovatul? Un seed de Prisma care folosea Faker clasic și genera ocazional aceleași emailuri sau string-uri prea lungi pentru constrângerile din baza de date.

După ce am pierdut câteva nopți bune făcând debugging pe loguri din GitHub Actions, am înțeles că un seed bun de CI are nevoie de două reguli de aur: determinism și idempotență.

De ce crapă seed-ul clasic în pipeline?

Cea mai mare greșeală e să lași Faker-ul liber. Dacă rulezi npx prisma db seed și ai coloane cu constrângeri de unicitate (cum ar fi un email de user), mai devreme sau mai târziu Faker va genera un duplicat. În acel moment, tot build-ul tău din CI se duce pe apa sâmbetei.

A doua problemă e lipsa idempotenței. Dacă pipeline-ul tău nu curăță complet baza de date înainte de fiecare rulare (de exemplu, dacă folosești o bază de date de test partajată), un simplu prisma.user.create() va crăpa la a doua rulare pentru că userul există deja.

Soluția 1: Determinism cu Faker Seed

Faker are o funcție ascunsă dar extrem de utilă: faker.seed(). Dacă îi pasezi un număr fix (un seed), Faker va genera exact aceleași date, în exact aceeași ordine, la fiecare rulare.

Asta înseamnă că dacă testul tău se bazează pe faptul că al cincilea user din listă se numește "Andrei", acel user se va numi mereu "Andrei", indiferent de câte ori rulezi pipeline-ul.

Soluția 2: Upsert în loc de Create

În loc să folosești create, folosește upsert. Este singura metodă sigură prin care te asiguri că seed-ul poate fi rulat de 100 de ori pe aceeași bază de date fără să arunce erori de cheie unică. Prisma te obligă să definești un câmp unic pentru where, ce să faci dacă înregistrarea există (update) și ce să faci dacă nu există (create).

Trade-off-ul cinstit: Viteza vs Stabilitate

Trebuie să fim realiști. upsert-ul este mult mai lent decât un create simplu sau un createMany. La un proiect unde aveam de populat vreo 4000 de rânduri de produse, rularea seed-ului cu upsert a crescut timpul de build cu aproape un minut.

Pentru noi, compromisul a meritat din plin. Am preferat să pierdem 60 de secunde în plus la build decât să avem developeri blocați pentru că build-ul a picat din senin din cauza unui email duplicat generat la mișto.

Dacă ai un volum uriaș de date, recomandarea mea este să folosești upsert doar pentru tabelele de nomenclator sau utilizatorii de test de bază, iar pentru datele tranzacționale mari să folosești un script separat care dă TRUNCATE și apoi createMany.

Cum gestionați voi datele de test în CI? Mergeți pe curățare completă la fiecare rulare sau folosiți seed-uri inteligente?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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