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

Seed-uri de Prisma în CI: Cum scapi de flaky tests și date nedeterministice

De Ștefan Iliescu, 5 aug. 2026 · 12 vizualizări · 2 like-uri

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

const prisma = new PrismaClient();

async function main() {
  const isCI = process.env.CI === 'true';
  
  // Determinism garantat în CI
  if (isCI) {
    faker.seed(42);
  }

  const totalUsers = isCI ? 10 : 100;

  for (let i = 0; i < totalUsers; i++) {
    const email = `user-${i}@example.test`;
    
    await prisma.user.upsert({
      where: { email },
      update: { name: faker.person.fullName() },
      create: {
        email,
        name: faker.person.fullName(),
        role: i === 0 ? 'ADMIN' : 'USER',
      },
    });
  }
}

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

Acum vreo doi ani, la un proiect cu peste 15 microservicii și vreo 8k useri activi, aveam o problemă extrem de enervantă pe pipeline-ul de CI. Testele de integrare picau cam o dată la 5-6 commit-uri fără absolut niciun motiv logic în codul schimbat.

După ce am pierdut vreo 2 zile făcând debug pe runnerii de GitHub Actions, m-am prins: problema era în scriptul nostru de prisma db seed. Generam date random cu Faker, iar uneori edge-case-urile generate (string-uri prea lungi, caractere speciale neașteptate sau e-mail-uri duplicate din pură coincidență) dădeau peste cap testele de API.

De ce Faker nedeterminist îți distruge pipeline-ul

Implicit, librăriile de tip @faker-js/faker generează valori folosind o sursă de pseudorandomness bazată pe timestamp-ul curent. În dev local e super ok, că vrei să vezi aplicația plină de date variate. În CI, e o rețetă sigură pentru dezastru.

Soluția simplă pe care mulți o uită e setarea unui seed fix: faker.seed(12345). Dacă apelezi asta la începutul scriptului de seed, Faker va genera exact aceeași secvență de date de fiecare dată când rulează pe CI. Dacă testul a trecut o dată, va trece și a 100-a oară.

Trapa createMany vs siguranța din upsert

Un alt moment în care ne-am furat-o a fost când rulam teste în paralel pe același container de bază de date fără să facem cleanup complet. Foloseam prisma.user.createMany(), iar la a doua rulare crăpa totul din cauza unique constraints pe email.

Am schimbat abordarea și am trecut pe upsert. În loc să presupunem că baza e mereu goală, facem match pe un identifier unic (de exemplu email sau un id determinist).

Există un trade-off clar aici. upsert e sensibil mai lent decât un createMany brut sau un SQL INSERT direct. La noi, timpul de seed pentru ~400 de entități a crescut de la 1.1 secunde la aproape 4 secunde. Dar cinstit? Prefer să aștept 3 secunde în plus în CI decât să am un build roșu aiurea la ora 7 seara înainte de deploy.

Separarea mediilor: Dev vs CI

Nu vrei 10.000 de înregistrări în CI când testezi doar fluxul de checkout. Timpul de build e scump.

Am împărțit scriptul de seed folosind o variabilă de mediu simplă: CI=true sau SEED_SIZE. Dacă suntem în CI, generăm doar minimul necesar (de exemplu 5 categorii și 10 produse) cu faker.seed(). Dacă suntem în dev local pe laptop, lăsăm Faker liber și generăm 500 de produse ca să testăm paginarea și UI-ul.

Voi cum gestionați teardown-ul și datele de test în CI? Resetați schema complet cu prisma migrate reset --force la fiecare run sau mergeți pe tranzacții cu rollback?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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