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

Seed-uri Prisma pentru CI: Cum faci datele de test 100% reproducibile

De Ana Ionescu, 4 iun. 2026 · 1 vizualizări · 3 like-uri

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

const prisma = new PrismaClient();
// Fixăm seed-ul pentru predictibilitate în CI
faker.seed(42);

async function main() {
  const adminEmail = 'admin@community.ro';

  await prisma.user.upsert({
    where: { email: adminEmail },
    update: {}, // Nu modificăm nimic dacă există deja
    create: {
      email: adminEmail,
      name: 'Admin Community',
      role: 'ADMIN',
      profile: {
        create: {
          bio: faker.lorem.sentence(),
        },
      },
    },
  });
}

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

Am pierdut numărul dăților când mi-a picat pipeline-ul de CI din cauză că baza de date de test era ba goală, ba plină de date corupte de la rulările anterioare. Dacă folosești Prisma, probabil știi deja de comanda prisma db seed, dar scripturile default scrise la repezeală crapă imediat ce le rulezi a doua oară. Hai să vedem cum facem seed-uri idempotente și curate pe care te poți baza în CI/CD fără să-ți blochezi colegii la deploy.

Problema cu scripturile scrise la repezeală

La început, tentația e mare să arunci un prisma.user.create() într-un loop și să-i dai bice. Funcționează impecabil prima dată. A doua oară, însă, te lovești de erori de tipul Unique constraint failed pe câmpul de email.

Am pățit asta la un proiect cu peste 15 tabele interconectate. Prima soluție disperată a echipei a fost să punem un deleteMany() pe toate tabelele la începutul scriptului. Sună bine în teorie, dar în practică am dat de două probleme mari. În primul rând, ordinea ștergerii contează din cauza cheilor străine (foreign keys). În al doilea rând, pe măsură ce baza crește, operațiunea devine extrem de lentă. La noi, resetarea bazei și re-popularea adăugau aproape 45 de secunde la fiecare rulare de pipeline. Enorm, când vrei feedback rapid.

De ce upsert este sfântul Graal în CI

Soluția corectă este să folosești upsert în loc de create. Prisma are o metodă nativă excelentă pentru asta. Îi spui ce să caute (de regulă un câmp unic, cum ar fi emailul sau un ID stabil), ce să facă dacă nu găsește înregistrarea (create) și ce să facă dacă o găsește (update).

Dacă nu vrei să modifici datele existente în timpul testelor, poți lăsa obiectul de update gol sau poți actualiza doar o bifă de sistem.

Marele avantaj? Scriptul devine complet idempotent. Îl poți rula de 100 de ori pe secundă și rezultatul va fi exact același. Baza de date rămâne într-o stare stabilă, predictibilă și gata de teste.

Capcana Faker.js în pipeline-ul de test

Faker.js este o unealtă genială pentru development-ul local. Te ajută să vezi cum arată interfața cu date care seamănă cu realitatea. Totuși, în CI, randomness-ul este cel mai mare inamic.

Dacă Faker îți generează un nume de companie extrem de lung care rupe layout-ul în testele de Cypress, sau dacă generează din pură coincidență un string care pică un regex de validare, build-ul tău va pica aleatoriu (flaky tests). Am pierdut ore întregi debugând teste care picau o dată la 20 de rulări din cauza asta.

Dacă vrei neapărat Faker în CI, folosește faker.seed(12345) la începutul scriptului. Asta forțează librăria să genereze exact aceleași valori la fiecare rulare. Totuși, pentru testele de integrare și e2e, recomandarea mea e să folosești un set de date 100% statice și bine definite. Știi exact că userul test@example.com are rol de admin și că are exact trei comenzi în istoric.

Voi cum gestionați datele de test în CI? Mergeți pe varianta cu baze de date efemere pornite în Docker la fiecare build, sau aveți o bază persistentă pe care o curățați controlat?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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