Przejdź do treści

Kiedy stosować Cypress Component Testing w Next.js

Porównaj Cypress Component Testing z RTL w React i Next.js. Poznaj realne zalety, ograniczenia oraz sytuacje, gdy warto po niego sięgnąć w projekcie.

Maciej Sala

Founder StriveLab

8 min czytaniaAktualizacja

Czym Cypress Component Testing różni się od testów E2E?

W E2E testujesz działającą aplikację. Może to być serwer deweloperski, ale Next.js zaleca również testowanie buildu produkcyjnego, np. po npm run build i npm run start.

W CT montujesz komponent lub drzewo komponentów w przygotowanej stronie testowej. Cypress uruchamia własny dev server, który kompiluje i serwuje kod; nie uruchamiasz pełnego serwera Next.js.

Code
E2E: Cypress → przeglądarka → działająca aplikacja → komponent
CT:  Cypress → przeglądarka → strona testowa z komponentem
                            ↑
                     dev server Cypress CT

Izolacja często ułatwia diagnozę i skraca przygotowanie scenariusza. Czas wykonania zależy jednak także od kompilacji, providerów i liczby testów.

Setup Cypress Component Testing w Next.js i TypeScript

Przykłady używają aktualnego API Cypress, React 18/19 oraz integracji Next.js 15/16 z Webpackiem. Sprawdź obsługiwane wersje przed instalacją i zachowaj lockfile. Bundler CT jest osobną konfiguracją od Turbopacka używanego przez aplikację.

Instalacja Cypress Component Testing

Code
npm install -D cypress
npx cypress open

Przy pierwszym uruchomieniu Cypress daje nam wybór pomiędzy E2E Testing, a Component Testing - wybierz Component Testing i pozwól mu wygenerować bazową konfigurację. W przypadku Next.js Component Testing, opiera się zwykle na integracji z Webpackiem, więc warto potraktować to jako osobną warstwę testów dla komponentów, a nie próbę uruchamiania całej aplikacji App Router 1:1 wewnątrz Cypressa.

Konfiguracja Cypress CT w projekcie Next.js

Code
// cypress.config.ts
import { defineConfig } from 'cypress'
 
export default defineConfig({
  component: {
    devServer: {
      framework: 'next',
      bundler: 'webpack',
    },
    specPattern: 'cypress/component/**/*.cy.{ts,tsx}',
    supportFile: 'cypress/support/component.tsx',
  },
})

Support file dla Cypress Component Testing

Code
// cypress/support/component.tsx
import { mount } from 'cypress/react'
import '../../src/app/globals.css' // dopasuj do ścieżki w projekcie
 
declare global {
  namespace Cypress {
    interface Chainable {
      mount: typeof mount
    }
  }
}
 
Cypress.Commands.add('mount', mount)

Import cypress/react zastąpił adapter cypress/react18 w Cypress 14. Nie przenoś automatycznie tej konfiguracji do starszych wersji. Przewodnik migracji.

Globalny CSS, reset, fonty oraz klasy lub atrybuty motywu muszą być obecne także w CT. Samo zamontowanie komponentu nie uruchamia app/layout.tsx. Zachowaj wygenerowany plik component-index.html i elementy potrzebne integracji Next.js do wstrzykiwania stylów. Konfiguracja stylów w CT.

Przykłady zakładają alias @/ wskazujący katalog kodu aplikacji. Dostosuj importy do własnego tsconfig.json.

Pierwszy test komponentu w Cypress CT

Zacznijmy od prostego komponentu Alert:

Code
// components/Alert.tsx
'use client';
 
interface AlertProps {
  type: "success" | "error" | "warning";
  message: string;
  onClose?: () => void;
}
 
export function Alert({ type, message, onClose }: AlertProps) {
  return (
    <div role="alert" className={`alert alert-${type}`}>
      <span>{message}</span>
      {onClose && (
        <button onClick={onClose} aria-label="Zamknij">
          ×
        </button>
      )}
    </div>
  );
}
Code
// cypress/component/Alert.cy.tsx
import { Alert } from "@/components/Alert";
 
describe("Alert", () => {
  it("renders success message", () => {
    cy.mount(<Alert type="success" message="Zapisano pomyślnie!" />);
 
    cy.get("[role='alert']")
      .should("be.visible")
      .and("have.class", "alert-success");
    cy.contains("Zapisano pomyślnie!");
  });
 
  it("renders error variant", () => {
    cy.mount(<Alert type="error" message="Coś poszło nie tak" />);
 
    cy.get("[role='alert']").should("have.class", "alert-error");
  });
 
  it("calls onClose when dismiss button is clicked", () => {
    const onClose = cy.stub().as("onCloseHandler");
 
    cy.mount(
      <Alert type="warning" message="Uwaga!" onClose={onClose} />
    );
 
    cy.get("[aria-label='Zamknij']").click();
    cy.get("@onCloseHandler").should("have.been.calledOnce");
  });
 
  it("does not render close button without onClose prop", () => {
    cy.mount(<Alert type="success" message="Info" />);
 
    cy.get("[aria-label='Zamknij']").should("not.exist");
  });
});

Uruchom testy:

Code
npx cypress open --component

Sprawdzenie have.class potwierdza nazwę klasy, a nie jej efekt wizualny. Powyższe testy służą poznaniu API; podobne zachowanie można sprawdzić także w RTL.

Test layoutu, który uzasadnia użycie CT

Poniższy komponent zmienia układ przy szerokości viewportu 600 px. CSS Modules jest importowany razem z komponentem.

Code
/* components/ResponsiveActions.module.css */
.actions {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
 
@media (min-width: 600px) {
  .actions {
    flex-direction: row;
  }
}
Code
// components/ResponsiveActions.tsx
import styles from './ResponsiveActions.module.css'
 
export function ResponsiveActions() {
  return (
    <div className={styles.actions} data-cy="actions">
      <button type="button">Zapisz</button>
      <button type="button">Anuluj</button>
    </div>
  )
}
Code
// cypress/component/ResponsiveActions.cy.tsx
import { ResponsiveActions } from '@/components/ResponsiveActions'
 
it('zmienia układ przy szerszym ekranie', () => {
  cy.viewport(400, 800)
  cy.mount(<ResponsiveActions />)
 
  cy.get('[data-cy="actions"]').should('have.css', 'flex-direction', 'column')
  cy.get('[data-cy="actions"] button').should(($buttons) => {
    const first = $buttons[0].getBoundingClientRect()
    const second = $buttons[1].getBoundingClientRect()
    expect(second.top).to.be.at.least(first.bottom)
  })
 
  cy.viewport(900, 800)
  cy.get('[data-cy="actions"]').should('have.css', 'flex-direction', 'row')
  cy.get('[data-cy="actions"] button').should(($buttons) => {
    const first = $buttons[0].getBoundingClientRect()
    const second = $buttons[1].getBoundingClientRect()
    expect(second.left).to.be.at.least(first.right)
  })
})

Test sprawdza efekt CSS i położenie elementów, których jsdom nie wylicza jak przeglądarka. Rozmiar viewportu nie emuluje jednak całego telefonu, jego dotyku ani wydajności.

Podgląd w runnerze nie jest automatyczną regresją wizualną. Asercje powyżej nie wykryją dowolnej zmiany koloru czy fontu. Porównywanie screenshotów wymaga osobnej konfiguracji, wzorców i stabilnego środowiska renderowania.

Testowanie komponentów React z hookami i stanem

Debounce można zwykle taniej sprawdzić testem hooka lub komponentu w RTL. Poniżej pokazuję kontrolę czasu w Cypress oraz kompletny hook. Ustalony kontrakt: nie wysyłamy zapytania przy montowaniu; zmianę wysyłamy po okresie ciszy, a wyczyszczenie wcześniej wysłanej frazy zgłaszamy jako pusty ciąg.

Code
// hooks/useDebounce.ts
import { useEffect, useState } from 'react'
 
export function useDebounce<T>(value: T, delay: number): T {
  const [debounced, setDebounced] = useState(value)
 
  useEffect(() => {
    const timer = setTimeout(() => setDebounced(value), delay)
    return () => clearTimeout(timer)
  }, [value, delay])
 
  return debounced
}
Code
// components/SearchInput.tsx
'use client';
 
import { useState, useEffect, useRef } from "react";
import { useDebounce } from "@/hooks/useDebounce";
 
interface SearchInputProps {
  onSearch: (query: string) => void;
  placeholder?: string;
  debounceMs?: number;
}
 
export function SearchInput({
  onSearch,
  placeholder = "Szukaj...",
  debounceMs = 300,
}: SearchInputProps) {
  const [query, setQuery] = useState("");
  const debouncedQuery = useDebounce(query, debounceMs);
  const lastSent = useRef("");
 
  useEffect(() => {
    if (lastSent.current !== debouncedQuery) {
      lastSent.current = debouncedQuery;
      onSearch(debouncedQuery);
    }
  }, [debouncedQuery, onSearch]);
 
  return (
    <input
      type="search"
      value={query}
      onChange={(e) => setQuery(e.target.value)}
      placeholder={placeholder}
      aria-label="Pole wyszukiwania"
    />
  );
}
Code
// cypress/component/SearchInput.cy.tsx
import { SearchInput } from "@/components/SearchInput";
 
describe("SearchInput", () => {
  it("calls onSearch after debounce", () => {
    cy.clock(); // przejmuje kontrolę nad timerami przeglądarki
    const onSearch = cy.stub().as("searchHandler");
 
    cy.mount(<SearchInput onSearch={onSearch} debounceMs={200} />);
 
    cy.get("[aria-label='Pole wyszukiwania']").type("React");
 
    // Przed debounce – onSearch nie powinien być wywołany
    cy.get("@searchHandler").should("not.have.been.called");
 
    // Uruchom timery zaplanowane w tym przedziale czasu
    cy.tick(200);
    cy.get("@searchHandler").should("have.been.calledWith", "React");
  });
 
  it("anuluje poprzedni timer i zgłasza wyczyszczenie frazy", () => {
    cy.clock();
    const onSearch = cy.stub().as("searchHandler");
    cy.mount(<SearchInput onSearch={onSearch} debounceMs={200} />);
 
    cy.get("input").type("Re", { delay: 0 });
    cy.tick(100);
    cy.get("input").type("act", { delay: 0 });
    cy.tick(100);
    cy.get("@searchHandler").should("not.have.been.called");
    cy.tick(100);
    cy.get("@searchHandler").should("have.been.calledOnceWithExactly", "React");
 
    cy.get("input").clear();
    cy.tick(200);
    cy.get("@searchHandler").should("have.been.calledTwice");
    cy.get("@searchHandler").its("lastCall.args").should("deep.equal", [""]);
  });
 
  it("renders custom placeholder", () => {
    cy.mount(
      <SearchInput onSearch={cy.stub()} placeholder="Znajdź produkt..." />
    );
 
    cy.get("input").should("have.attr", "placeholder", "Znajdź produkt...");
  });
});

Testowanie komponentów z kontekstem i providerami

Wiele komponentów zależy od kontekstu, który w CT musisz dostarczyć samodzielnie. Poniższy wariant zastępuje wcześniejszy support file. Zakłada zainstalowany @tanstack/react-query i własny ThemeProvider; dopasuj importy i wymagane propsy do aplikacji. Plik ma rozszerzenie .tsx, ponieważ zawiera JSX.

Code
// cypress/support/component.tsx – rozszerzony
import { mount } from "cypress/react";
import type { ReactNode } from "react";
import "../../src/app/globals.css";
import { ThemeProvider } from "@/context/ThemeContext";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
 
declare global {
  namespace Cypress {
    interface Chainable {
      mount: typeof mount;
    }
  }
}
 
function createWrapper() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
    },
  });
 
  return function Wrapper({ children }: { children: ReactNode }) {
    return (
      <QueryClientProvider client={queryClient}>
        <ThemeProvider>{children}</ThemeProvider>
      </QueryClientProvider>
    );
  };
}
 
Cypress.Commands.add("mount", (component, options = {}) => {
  const Wrapper = createWrapper();
  return mount(<Wrapper>{component}</Wrapper>, options);
});

Każde montowanie tworzy nowy QueryClient, więc cache zapytań nie jest współdzielony między tymi montowaniami. Jeśli aplikacja używa mutacji lub dodatkowych magazynów stanu, skonfiguruj też ich retry i izolację. Nie umieszczaj wspólnego klienta ani store'a na poziomie modułu, jeśli jego dane mogłyby przeciekać między testami.

Cypress Component Testing vs Jest i React Testing Library

RTL jest biblioteką testowania Reacta. Poniższe porównanie dotyczy konkretnie zestawu Jest + RTL w jsdom, nie wszystkich możliwych środowisk RTL.

AspektCypress CTJest + RTL w jsdom
ŚrodowiskoPrawdziwa przeglądarkaImplementacja API DOM w Node.js
CSS i geometriaRenderowanie po załadowaniu stylówBrak rzeczywistego layoutu i renderowania
DebugowanieRunner, DOM snapshots, DevToolsPodgląd DOM, debug(), debugger
Koszt wykonaniaPrzeglądarka i kompilacja komponentówZwykle mniejszy dla prostych testów
ZdarzeniaZależne od komendy: symulowane lub natywneSymulacja interakcji w jsdom
KonfiguracjaBundler, style, providery i przeglądarkaRunner, jsdom, transformacja kodu i mocki

Ograniczenia jsdom dotyczą m.in. geometrii elementów; nie oznacza to, że biblioteka ignoruje każde API związane ze stylami.

Prawdziwa przeglądarka nie oznacza, że wszystkie zdarzenia są natywne. Przykładowo cy.type() symuluje wpisywanie, a cy.press() wysyła natywne zdarzenia klawiatury i nadaje się do nawigacji Tab. Hover i drag and drop wymagają strategii odpowiedniej dla użytej implementacji; samo wywołanie handlera nie sprawdza całej interakcji.

Kiedy Cypress Component Testing wygrywa?

W telegraficznym skrócie:

  • Komponent intensywnie korzysta z CSS (animacje, responsive layout),
  • Zależy Ci na wizualnym debugowaniu,
  • Testujesz interakcje drag & drop, scroll, resize,
  • Chcesz spójności z istniejącymi testami Cypress E2E.

Kiedy Jest i React Testing Library wygrywają?

  • Kiedy szybkość jest priorytetem (),
  • Sprawdzasz formularze, stany ładowania, renderowanie warunkowe lub hooki bez zależności od rzeczywistego layoutu,
  • Twój zespół już zna i używa z powodzeniem RTL.

Interceptowanie requestów w Cypress Component Testing

Cypress CT pozwala przez cy.intercept() zastąpić odpowiedzi HTTP dla żądań wykonywanych przez komponent w przeglądarce. Zarejestruj intercept przed montowaniem i dopasuj rzeczywisty URL. Nie uruchamia to Route Handlera Next.js ani nie sprawdza jego implementacji.

Przykład zakłada istniejący UserProfile, który pobiera /api/user/1 i renderuje wskazane dane lub komunikat błędu:

Code
// cypress/component/UserProfile.cy.tsx
import { UserProfile } from "@/components/UserProfile";
 
describe("UserProfile", () => {
  it("displays user data from API", () => {
    cy.intercept("GET", "/api/user/1", {
      statusCode: 200,
      body: { name: "Jan Kowalski", email: "jan@example.com" },
    }).as("getUser");
 
    cy.mount(<UserProfile userId="1" />);
 
    cy.wait("@getUser");
    cy.contains("Jan Kowalski");
    cy.contains("jan@example.com");
  });
 
  it("shows error state on API failure", () => {
    cy.intercept("GET", "/api/user/1", {
      statusCode: 500,
      body: { error: "Internal Server Error" },
    });
 
    cy.mount(<UserProfile userId="1" />);
 
    cy.contains(/nie udało się załadować/i);
  });
});

Ograniczenia Cypress Component Testing w projektach Next.js

To jest miejsce, w którym wiele osób próbuje wycisnąć z CT za dużo.

  • Client Components często nadają się do CT, jeśli ich zależności da się zapewnić w przeglądarce. Sama dyrektywa 'use client' nie gwarantuje izolacji.

  • Asynchroniczne Server Components nie są obsługiwane przez CT. Prosty, synchroniczny komponent prezentacyjny bez zależności serwerowych można zamontować w izolacji, ale nie sprawdza to wykonania RSC ani cache Next.js.

  • Routing App Routera nie jest celem CT. Jeśli chcesz testować przejścia między stronami, middleware, auth guardy czy redirect(), pisz testy E2E.

  • generateMetadata, generateStaticParams, route handlers i cache Next.js to nie są "zachowania komponentu" i nie warto na siłę wrzucać ich do CT.

Zwróć uwagę na zależności charakterystyczne dla Next.js:

  • next/navigation: hooki routera wymagają odpowiedniego kontekstu lub kontrolowanego zastępstwa. Możesz sprawdzić reakcję UI na podaną ścieżkę, ale prawdziwe przejście między trasami weryfikuj w E2E.
  • next/image: optymalizacja może wymagać endpointu serwera, którego CT nie uruchamia. W teście UI można dostarczyć kontrolowaną odpowiedź lub wariant unoptimized; nie potwierdza to działania optymalizacji produkcyjnej.
  • Fonty i layout: odtwórz style, klasy, zmienne CSS i dostęp do plików fontów. CT nie renderuje automatycznie głównego layoutu aplikacji.
  • Server Actions: zastąp granicę akcji callbackiem, jeśli sprawdzasz stan formularza. Wykonanie na serwerze i autoryzację testuj oddzielnie.

Dokumentacja Next.js opisuje ograniczenia asynchronicznych Server Components oraz funkcji wymagających serwera.

Dobry podział odpowiedzialności wygląda zwykle tak:

  • Vitest/Jest: wydzielona logika; RTL z runnerem: hooki i zachowanie UI bez wymagań dotyczących layoutu,
  • Cypress CT: komponenty interaktywne, layout zależny od przeglądarki, drag and drop, focus states,
  • Cypress/Playwright E2E: krytyczne flow użytkownika, routing, autentykacja, checkout.

Uruchamianie CT w CI i izolacja testów

Po zainstalowaniu zależności z lockfile uruchom:

Code
npx cypress run --component --browser chrome

Środowisko CI musi mieć zainstalowane zgodne wersje Node.js, Cypress, przeglądarki oraz jej zależności systemowych. Możesz użyć wersjonowanego obrazu Cypress z przeglądarkami. CT uruchamia własny dev server, więc nie wymaga wcześniejszego next start. Przeglądarkę i obraz przypnij do wersji, a przy aktualizacjach sprawdź macierz zgodności.

Dla powtarzalności:

  • twórz providery i store'y z czystym stanem dla każdego testu,
  • rejestruj intercepty oraz stuby w każdym teście lub beforeEach,
  • korzystaj z ponawianych asercji i aliasów żądań zamiast stałych opóźnień,
  • dla debounce używaj cy.clock() i cy.tick(),
  • określ viewport, motyw i fonty, jeśli sprawdzasz geometrię,
  • zachowuj raporty oraz screenshoty błędów jako artefakty CI.

Cypress izoluje testy CT i resetuje m.in. intercepty oraz kontrolę zegara, ale nie zastępuje to świadomego zarządzania własnymi singletonami i zewnętrznymi danymi. Izolacja testów.

Kiedy koszt dodatkowej warstwy CT się opłaca?

Zacznij od kilku komponentów, których błędy zależą od przeglądarki: układu, focusu, przewijania albo złożonej interakcji. Oceń, czy testy wykrywają regresje pomijane przez dotychczasowy zestaw i czy ich przygotowanie nie wymaga nadmiernego odtwarzania Next.js.

Nie trzeba testować tego samego placeholdera w RTL, CT i E2E. Zachowaj test na najprostszym poziomie, który wiarygodnie sprawdza dane ryzyko. Samo używanie Cypress E2E obniża koszt poznania narzędzia, ale nie przesądza o potrzebie CT.

Dobre praktyki Cypress Component Testing w React i Next.js

Organizacja plików – trzymaj testy CT blisko komponentów lub w dedykowanym cypress/component/:

Code
├── components/
│   ├── Alert.tsx
│   └── SearchInput.tsx
├── cypress/
│   ├── component/
│   │   ├── Alert.cy.tsx
│   │   └── SearchInput.cy.tsx
│   └── e2e/
│       └── checkout.cy.ts

Data-testid vs role – preferuj role i aria-label (jak RTL), ale data-testid to pragmatyczny fallback.

Dobieraj poziom testu do zależności — CT może sprawdzać formularz z wieloma polami, walidacją i providerem. Liczba komponentów nie przesądza o E2E; decyduje potrzeba prawdziwego routingu, serwera i przepływu aplikacji. Kompletny setup Cypress E2E w App Router — od konfiguracji CI po fixtures i custom commands — opisuję w osobnym artykule o testach E2E w Next.js.

Testy automatyczne komponentów i E2E w Cypress.
QA & Automation

Często zadawane pytania

Czy Cypress Component Testing zastępuje React Testing Library?

Nie. Cypress Component Testing uzupełnia RTL tam, gdzie ważna jest prawdziwa przeglądarka, CSS, focus, drag and drop albo interakcje trudne do wiarygodnego sprawdzenia w jsdom.

Kiedy lepiej wybrać test E2E zamiast component testu?

Gdy chcesz sprawdzić routing, autoryzację, integrację z backendem, Server Components albo pełny przepływ użytkownika między ekranami. Component testing jest najlepszy dla izolowanych komponentów UI.

Czym jest Cypress Component Testing?

W CT montujesz komponent lub drzewo React w prawdziwej przeglądarce. Nie uruchamiasz całej aplikacji Next.js, ale Cypress uruchamia własny serwer deweloperski do kompilacji i serwowania testowanych komponentów. Style i konteksty aplikacji trzeba zapewnić w środowisku testu.

Jaka jest różnica między Cypress CT a Jest z RTL w jsdom?

Cypress CT ma prawdziwy layout i renderowanie CSS. Jest z RTL w jsdom sprawdza DOM i zachowanie UI bez rzeczywistego układania elementów na ekranie. RTL jest biblioteką, nie środowiskiem wykonawczym. Sposób generowania zdarzeń w Cypress zależy od komendy: cy.type symuluje wpisywanie, a cy.press wysyła natywne zdarzenia klawiatury.

Kiedy wybrać Cypress CT zamiast RTL?

Wybierz CT, jeśli test wymaga rzeczywistego layoutu, focusu, przewijania albo zachowania zależnego od CSS. Dla wielu testów formularzy, hooków i warunkowego renderowania wystarczy RTL w jsdom. Warto dodać CT wtedy, gdy pokrywa konkretną lukę, a nie dubluje istniejące testy.

Czy można testować Next.js Server Components w Cypress CT?

CT nie odtwarza serwerowego wykonania RSC i nie obsługuje asynchronicznych Server Components. Prosty synchroniczny komponent prezentacyjny bez zależności serwerowych można sprawdzić w izolacji, ale nie sprawdza to zachowania RSC. Integrację z Next.js weryfikuj na uruchomionej aplikacji.

Jak skonfigurować Cypress Component Testing w Next.js?

Zainstaluj Cypress, uruchom npx cypress open i wybierz Component Testing z frameworkiem Next.js. Konfiguracja używa framework: 'next' oraz bundler: 'webpack'. W support file zarejestruj mount, zaimportuj style i dodaj potrzebne providery. Plik zawierający JSX musi mieć rozszerzenie .tsx.

Czy Cypress CT zastępuje testy E2E?

Nie musi zastępować E2E. CT może sprawdzać integrację wielu komponentów, ale nie odtwarza pełnego środowiska Next.js. Prawdziwy routing, autoryzację i wykonanie Server Actions sprawdzaj na działającej aplikacji. E2E warto uruchamiać również na buildzie produkcyjnym.

Jak mockować API w Cypress Component Testing?

Cypress CT wspiera cy.intercept() tak samo jak E2E, czyli przechwytuje requesty HTTP i zwraca mock response. W teście: cy.intercept('GET', '/api/user', { body: mockUser }), potem montuj komponent i weryfikuj render. Możesz też używać cy.stub() do mockowania propsów będących callbackami. Dla komponentów używających React Query warto skonfigurować QueryClient z retry: false w wrapperze testowym.

O autorze

Maciej Sala

Maciej Sala — konsultant technologiczny produktów cyfrowych i web developer z bogatym doświadczeniem w marketingu internetowym oraz SEO. Na co dzień pracuje z Reactem, Next.js i TypeScriptem, a ostatnio także z Astro i narzędziami do automatyzacji procesów AI. Sprawnie łączy perspektywę produktową z praktycznym podejściem do kodu. Przez kilka lat był związany z branżą gier wideo jako project manager i game designer. Absolwent historii na Uniwersytecie Jagiellońskim oraz studiów podyplomowych z marketingu internetowego na AGH w Krakowie. Po godzinach trenuje na siłowni, maluje figurki i rozwija własne projekty.

Pomagam przekładać takie tematy na konkretne wdrożenia w frontendzie, SEO, analityce i procesie produktowym.

Skontaktuj się ze mną
LH.pl – Hosting Mango

Biblioteka wiedzy na temat Next.js

Czytaj dalej

Zobacz więcej wpisów
Porównanie Cypress i Playwright dla projektu w Next.js

Wybór frameworka do testów E2E to jedna z tych decyzji, która będzie wpływać na cały zespół przez miesiące czy nawet lata. W 2026 roku dwóch głównych graczy to Cypress i Playwright . Oba narzędzia są dojrzałe i mają bardzo aktywną społeczność.

Maciej Sala

Maciej Sala

Founder StriveLab

Testy E2E Cypress w Next.js App Router i GitHub Actions

Stabilność zestawu testów E2E nie zależy od ich liczby, lecz od świadomego wyznaczenia granic. W architekturze Next.js App Router zadania rozdzielają się między przeglądarkę, proces serwera Next.js oraz bazę danych. W związku z tym, że Cypress inaczej interpretuje każdą z tych warstw, nieprzemyślane użycie cy.intercept może zamienić kompleksowy test systemu w płytki test samego interfejsu.

Maciej Sala

Maciej Sala

Founder StriveLab

Jak testować Server Components w Next.js?

React Testing Library renderuje komponenty w środowisku JSDOM, podczas gdy Next.js uruchamia Server Components w warstwie serwerowej. Wynika to z różnic architektonicznych. JSDOM nie obsługuje środowiska serwerowego, na którym opierają się asynchroniczne komponenty korzystające z baz danych, plików cookies, nagłówków czy operacji sieciowych. Zobacz, jak ominąć te ograniczenia i spokojnie testować nowoczesny kod.

Maciej Sala

Maciej Sala

Founder StriveLab

LH.pl – Cloud Server 1C4G