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

Seed-uri Prisma în CI: cum scapi de teste flaky și ID-uri buclucașe

De Diana Oprea, 11 oct. 2026 · 5 vizualizări · 2 like-uri

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

const prisma = new PrismaClient();

async function main() {
  // Forțăm generatorul să fie determinist
  faker.seed(1337);

  // Utilizator de test fix pentru aserțiuni E2E
  await prisma.user.upsert({
    where: { email: 'admin.ci@example.com' },
    update: {},
    create: {
      id: '00000000-0000-0000-0000-000000000001',
      email: 'admin.ci@example.com',
      name: 'CI Superadmin',
      role: 'ADMIN',
    },
  });

  // Date de umplutură doar dacă NU rulăm în CI rapid
  if (!process.env.CI) {
    const devUsers = Array.from({ length: 50 }).map(() => ({
      email: faker.internet.email().toLowerCase(),
      name: faker.person.fullName(),
    }));

    await prisma.user.createMany({
      data: devUsers,
      skipDuplicates: true,
    });
  }
}

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

Toată lumea iubește seed-urile până când crapă pipeline-ul de GitHub Actions la ora 18:00 din cauza unui Unique constraint failed. Dacă rulezi teste de integrare sau E2E în CI bazându-te pe prisma db seed, ai nevoie de două lucruri clare: determinism absolut și idempotență.

Am pățit-o pe un proiect B2B cu vreo 40 de tabele și un suite de teste Playwright. Cineva scrisese un seed plin de @faker-js/faker fără seed fix. Rezultatul? Testele picau o dată la 5 rulări pentru că Faker genera uneori un string prea lung sau un email duplicat. Depanarea locală era un calvar: rulai local, mergea; rula pe CI, crăpa.

Faker determinist vs date statice

Mulți cred că Faker n-are ce căuta în CI. Nu e neapărat adevărat, dar dacă îl folosești, prima linie din scriptul tău de seed trebuie să fie faker.seed(42).

O valoare fixă forțează generatorul pseudo-random să scuipe exact aceeași secvență de date la fiecare execuție. Userul cu indexul 1 va avea mereu același nume, același email și aceleași adrese asociate.

Totuși, pentru entitățile critice folosite direct în aserțiuni, eu prefer să sar peste Faker. Dacă un test verifică că un admin poate edita o comandă, adminul ăla ar trebui să aibă un UUID hardcodat și credențiale fixe. Folosește Faker doar ca să umpli fundalul (categorii secundare, loguri, produse de umplutură).

Idempotență: capcana dintre upsert și createMany

A doua mare greșeală este presupunerea că baza de date pornește mereu de la zero. Pe CI folosești containere efemere, dar dacă reîncerci un job picat sau rulezi seed-ul peste o bază existentă, un simplu create explodează la chei unice.

Aici apare prisma.model.upsert(). E sfânt pentru idempotență: dacă înregistrarea există deja după cheia unică, o actualizează; dacă nu, o creează.

Există însă un trade-off serios: upsert e lent. Foarte lent dacă îl compari cu un createMany. La proiectul menționat mai devreme, când făceam upsert pe 1.200 de produse rând cu rând, seed-ul dura aproape 45 de secunde. Trecerea la un DELETE FROM "Product" urmat de prisma.product.createMany() a redus execuția la 3 secunde. Regula mea empirică: upsert pentru entități de bază (roluri, permisiuni, conturi de test) și curățare brută urmată de createMany pentru date de volum.

Separă mediile direct din seed.ts

Nu arunca aceleași date în CI ca pe mașina de dev. În dev vrei 200 de comenzi ca să testezi paginarea și scroll-ul infinit. În CI vrei fix 3 comenzi: una plătită, una în așteptare și una anulată. Fiecare secundă adăugată la seed se multiplică la fiecare commit.

Noi am rezolvat asta verificând simplu process.env.CI. Dacă suntem pe runner, rulăm doar scenariile minimale necesare testelor. Am tăiat astfel 3 minute și jumătate din durata totală a pipeline-ului fără să pierdem acoperire pe scenarii.

Voi cum abordați popularea bazei în pipeline? Mergeți pe seed dedicat per test suite sau aveți un mega-seed global la început de workflow?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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