Logo Light
Published on

Fitnotes (2. díl) - zprovoznění testovacího frameworku Jest

Nastavení Jest v Next.js + TypeScript aplikaci s Prisma

Tento článek navazuje na první část o nastavení Prisma a PostgreSQL. V tomto příspěvku ukážu, jak nastavit testovací framework Jest v projektu s Next.js, TypeScriptem a Prismou.

Cílem je mít funkční základ pro testování modelů z Prisma schématu.


1. Instalace balíčků

npm install --save-dev jest ts-jest @types/jest

Prisma a některé další moderní knihovny používají tzv. ECMAScript moduly (ES Modules, zkráceně ESM) místo tradičních CommonJS modulů. Jest je původně navržen pro CommonJS. Pokud narazím na chyby jako SyntaxError: Cannot use import statement outside a module, je to právě kvůli rozdílným typům modulů. Knihovna jest-environment-node pomůže tyto rozdíly lépe zpracovat. I když Next.js a TypeScript vše většinou dobře vyřeší, přidání jest-environment-node pomáhá předejít problémům s ESM, které může Prisma vyvolat.

npm install --save-dev jest-environment-node

2. Inicializace konfigurace Jest

npx ts-jest config:init

Příkaz vytvoří soubor jest.config.js. Ten upravím takto:

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  moduleDirectories: ['node_modules', '<rootDir>/'],
}

Vysvětlení změn v jest.config.js

  • preset: 'ts-jest' – zajišťuje podporu TypeScriptu v testech.

  • testEnvironment: 'node' – nastavuje výchozí prostředí pro backendové testy (např. při testování Prisma modelů nebo serverové logiky). Pro frontend bych použil hodnotu jsdom.

  • moduleDirectories – usnadňuje importy.
    Můžu teď psát:

    import { something } from 'utils/something';
    

    Místo:

    import { something } from '../../../utils/something';
    

Pokud mám v tsconfig.json povolené užívání aliasů jako @/, např.:

"paths": {
  "@/*": ["./src/*"]
}

můžu ještě do jest.config.js přidat:

  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
  }

Tohle Jestu říká: Kdykoliv v importech narazíš na @/some/path nahraď to <rootDir>/src/some/path.


Jak testovat backend i frontend kód v jednom projektu?

  • Pro backendové testy - Prisma a databázovou logiku – použiju node prostředí.
  • Pro React komponenty – použiju jsdom, což simuluje prostředí prohlížeče.

V zásadě mám dvě možnosti:

1. Nastavení prostředí přímo v testovacím souboru pomocí speciálního komentáře:

Jest standardně používá hodnotu z testEnvironment, ale pomocí komentářů (@jest-environment) můžu přepsat prostředí jen pro konkrétní soubor.

Backendový test
/**
 * @jest-environment node
 */
import { PrismaClient } from '@prisma/client'
// ...testy s databází
Frontendový test
/**
 * @jest-environment jsdom
 */
import { render, screen } from '@testing-library/react'
// ...testy komponent

2. Nastavím různé prostředí pro různé adresáře

V jest.config.js můžu nadefinovat dva projekty:

module.exports = {
  projects: [
    {
      displayName: 'backend',
      testMatch: ['<rootDir>/tests/backend/**/*.test.ts'],
      testEnvironment: 'node',
    },
    {
      displayName: 'frontend',
      testMatch: ['<rootDir>/tests/frontend/**/*.test.tsx'],
      testEnvironment: 'jsdom',
    },
  ],
}

Testy potom umístím do samostatných adresářů: tests/backend/ – Prisma, DB, etc. tests/frontend/ – React components


3. Script do package.json

Do souboru package.json přidám alias pro spouštění testů:

"scripts": {
  "test": "jest"
}

4. První test pro model Workout

Vytvořím adresář tests/ a v něm soubor sample.test.ts:

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

describe('Workout model', () => {
  it('should create a new workout record', async () => {
    const workout = await prisma.workout.create({
      data: {
        date: new Date('2024-10-11'),
        exercise: 'Bench Press',
        category: 'Chest',
        weight: 100,
        weightUnit: 'kgs',
        reps: 10,
      },
    })

    expect(workout).toHaveProperty('id')
    expect(workout.exercise).toBe('Bench Press')
  })
})

5. Spuštění testu

npm test

Očekávaný výsledek:

PASS  tests/workout.test.ts
Workout model
✓ should create a new workout record
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.166 s
Ran all test suites.

Co bude dál?

V dalším díle přidám sadu reálných smysluplných testů našeho modelu databáze.