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

Cum scrii seed-uri Prisma deterministe pentru CI fără să strici pipeline-ul

De Liliana Ghiță, 10 aug. 2026 · 7 vizualizări · 3 like-uri

Postat acum 6 zile
typescript
import { PrismaClient } from '@prisma/client';
import { faker } from '@faker-js/faker';

const prisma = new PrismaClient();

async function main() {
  // Setăm seed fix: datele vor fi IDENTICE la fiecare rulare în CI
  faker.seed(1337);

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

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

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

Am pățit-o anul trecut la un proiect SaaS cu vreo 8k utilizatori activi unde aveam teste E2E executate automat pe GitHub Actions. În 30% din cazuri, pipeline-ul pica fără vreun motiv logic din cauză că scriptul de seed genera date dinamice incompatibile cu unele aserțiuni. Dacă te-ai lovit vreodată de erori ciudate când vine vorba de baza de date din CI, postarea asta e pentru tine.

De ce pică seed-urile naive în CI

Când începi un proiect, e tentant să arunci un prisma/seed.ts rapid plin de @faker-js/faker și câteva apeluri simple de prisma.user.create(). Pe mediul local merge brici. Ștergi baza, dai prisma db seed, gata treaba.

Problema apare când ajungi în CI/CD. Dacă reutilizezi baza de date între job-uri sau dacă testele depind de o valoare specifică generată de Faker, începe haosul. Faker generează valori aleatorii la fiecare execuție. Un test E2E care caută user_test_12@example.com o să crape când Faker decide să genereze john_doe99@gmail.com la rularea din pipeline.

A doua barieră e eroarea clasică de DB constraint (P2002 în Prisma - Unique constraint failed). Dacă scriptul tău rulează pe o bază care nu a fost curățată complet în prealabil, orice create direct va eșua instant.

Soluția: Faker determinist și Prisma Upsert

Ca să faci seed-ul 100% reproducibil, ai nevoie de doi stâlpi: determinism în datele generate și idempotenta la scriere.

Pentru Faker, soluția e banală dar surprinzător de des uitată: setarea unui seed fix la începutul scriptului. Apelul faker.seed(1337) garantează că secvența de date va fi exact aceeași la fiecare execuție. Același nume, același email, aceleași UUID-uri fictive.

Pentru scrierea în baza de date, renunță la .create() și treci pe .upsert(). Cu upsert, îi spui bazei: "Dacă există deja userul cu emailul ăsta, fă-i update. Dacă nu există, creează-l".

Trade-off-uri reale: Viteză vs. Stabilitate

Trebuie să fim sinceri pe parte de trade-off: upsert este simțitor mai lent decât un createMany. La un test de performanță pe o masă de 10.000 de înregistrări, folosirea loop-urilor cu upsert mi-a crescut timpul de executie al seed-ului de la 3 secunde la aproape 18 secunde.

Dacă ai volume uriașe de date, un upsert pur devine enervant în CI. În cazul ăsta, soluția hibridă e cea mai curată: folosești upsert pentru entitățile critice (roluri, admini, setări de sistem, useri de test fixați) și createMany cu skipDuplicates: true pentru datele voluminoase de fundal (loguri, tranzacții dummy).

Prin abordarea asta am scăzut rata de eșec a pipeline-ului de CI de la 30% la zero, iar build time-ul a rămas excelent.

Voi ce strategie folosiți când pregătiți baza de date pentru testele din CI? Trageți un container Docker proaspăt la fiecare job sau mergeț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.