Skip to content
Vitest 3
Main Navigation Przewodnik & APIKonfiguracjaTryb przeglądarkiZaawansowane API
3.2.0
2.1.9
1.6.1
0.34.6

Polski

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Türkçe
čeština
magyar

Polski

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Türkçe
čeština
magyar

Wygląd

Sidebar Navigation

Wprowadzenie

Dlaczego Vitest

Pierwsze kroki

Funkcje

Konfiguracja Vitest

API

Dokumentacja API testowego

Funkcje Mock

Vi

expect

expectTypeOf

assert

assertType

Przewodnik

Interfejs Wiersza Poleceń

Filtrowanie testów

Projekty testowe

Reportery

Pokrycie kodu

Migawki

Mockowanie

Równoległość

Typy testów

Interfejs użytkownika Vitest

Testy w kodzie źródłowym

Kontekst Testu

Adnotacje testowe

Środowisko testowe

Rozszerzanie matcherów

Integracje z IDE

Debugowanie

Typowe błędy

Przewodnik migracji

Migracja do Vitest 3.0

Migracja z Jest

Wydajność

Profilowanie wydajności testów

Poprawa wydajności

Tryb przeglądarkowy

Zaawansowane API

Porównania z innymi narzędziami do uruchamiania testów

Na tej stronie

Mockowanie ​

Podczas pisania testów prędzej czy później pojawi się potrzeba stworzenia „fałszywej” wersji wewnętrznej lub zewnętrznej usługi. Jest to powszechnie określane jako mockowanie. Vitest udostępnia funkcje pomocnicze, które wspierają ten proces za pośrednictwem pomocnika vi. Możesz go zaimportować z vitest lub używać globalnie, jeśli konfiguracja global jest włączona.

WARNING

Zawsze pamiętaj o czyszczeniu lub przywracaniu mocków przed lub po każdym teście, aby cofnąć zmiany stanu mocków między uruchomieniami! Więcej informacji znajdziesz w dokumentacji mockReset.

Jeśli nie znasz metod vi.fn, vi.mock lub vi.spyOn, najpierw zapoznaj się z sekcją API.

Daty ​

Czasami konieczne jest kontrolowanie daty, aby zapewnić spójność testów. Vitest używa pakietu @sinonjs/fake-timers do manipulowania timerami oraz datą systemową. Więcej szczegółów na temat konkretnego API znajdziesz tutaj.

Przykład ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

const businessHours = [9, 17];

function purchase() {
  const currentHour = new Date().getHours();
  const [open, close] = businessHours;

  if (currentHour > open && currentHour < close) {
    return { message: 'Success' };
  }

  return { message: 'Error' };
}

describe('purchasing flow', () => {
  beforeEach(() => {
    // informujemy Vitest, że używamy zamockowanego czasu
    vi.useFakeTimers();
  });

  afterEach(() => {
    // przywracanie rzeczywistej daty po każdym uruchomieniu testu
    vi.useRealTimers();
  });

  it('allows purchases within business hours', () => {
    // ustaw godzinę w godzinach pracy
    const date = new Date(2000, 1, 1, 13);
    vi.setSystemTime(date);

    // dostęp do Date.now() zwróci datę ustawioną powyżej
    expect(purchase()).toEqual({ message: 'Success' });
  });

  it('disallows purchases outside of business hours', () => {
    // ustaw godzinę poza godzinami pracy
    const date = new Date(2000, 1, 1, 19);
    vi.setSystemTime(date);

    // dostęp do Date.now() zwróci datę ustawioną powyżej
    expect(purchase()).toEqual({ message: 'Error' });
  });
});

Funkcje ​

Mockowanie funkcji można podzielić na dwie kategorie: szpiegowanie i mockowanie.

Czasami wystarczy tylko sprawdzić, czy określona funkcja została wywołana i jakie argumenty zostały przekazane. W takich przypadkach wystarczy szpieg, którego można użyć bezpośrednio za pomocą vi.spyOn() (czytaj więcej tutaj).

Jednak szpiedzy mogą jedynie monitorować funkcje, nie są w stanie zmieniać ich implementacji. W przypadku, gdy musimy stworzyć fałszywą (lub zamockowaną) wersję funkcji, możemy użyć vi.fn() (czytaj więcej tutaj).

Używamy Tinyspy jako podstawy do mockowania funkcji, ale posiadamy własną otoczkę, która zapewnia kompatybilność z jest. Zarówno vi.fn(), jak i vi.spyOn() współdzielą te same metody, jednak tylko vi.fn() zwraca wywoływalny wynik.

Przykład ​

js
import { afterEach, describe, expect, it, vi } from 'vitest';

const messages = {
  items: [
    { message: 'Simple test message', from: 'Testman' },
    // ...
  ],
  getLatest, // może być również `getterem lub setterem, jeśli obsługiwane`
};

function getLatest(index = messages.items.length - 1) {
  return messages.items[index];
}

describe('reading messages', () => {
  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('should get the latest message with a spy', () => {
    const spy = vi.spyOn(messages, 'getLatest');
    expect(spy.getMockName()).toEqual('getLatest');

    expect(messages.getLatest()).toEqual(
      messages.items[messages.items.length - 1]
    );

    expect(spy).toHaveBeenCalledTimes(1);

    spy.mockImplementationOnce(() => 'access-restricted');
    expect(messages.getLatest()).toEqual('access-restricted');

    expect(spy).toHaveBeenCalledTimes(2);
  });

  it('should get with a mock', () => {
    const mock = vi.fn().mockImplementation(getLatest);

    expect(mock()).toEqual(messages.items[messages.items.length - 1]);
    expect(mock).toHaveBeenCalledTimes(1);

    mock.mockImplementationOnce(() => 'access-restricted');
    expect(mock()).toEqual('access-restricted');

    expect(mock).toHaveBeenCalledTimes(2);

    expect(mock()).toEqual(messages.items[messages.items.length - 1]);
    expect(mock).toHaveBeenCalledTimes(3);
  });
});

Więcej ​

  • Funkcje Mock Jest

Zmienne globalne ​

Możesz mockować zmienne globalne, które nie są obecne w jsdom lub node, używając pomocnika vi.stubGlobal. Umieści on wartość zmiennej globalnej w obiekcie globalThis.

ts
import { vi } from 'vitest';

const IntersectionObserverMock = vi.fn(() => ({
  disconnect: vi.fn(),
  observe: vi.fn(),
  takeRecords: vi.fn(),
  unobserve: vi.fn(),
}));

vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);

// teraz możesz uzyskać do niego dostęp jako `IntersectionObserver` lub `window.IntersectionObserver`

Moduły ​

Mockowanie modułów pozwala obserwować biblioteki stron trzecich, które są wywoływane w innym kodzie, umożliwiając testowanie argumentów, danych wyjściowych, a nawet ponowne definiowanie ich implementacji.

Szczegółowy opis API znajdziesz w sekcji vi.mock() API.

Algorytm automatycznego mockowania ​

Jeśli Twój kod importuje zamockowany moduł, bez powiązanego pliku __mocks__ lub factory dla tego modułu, Vitest samodzielnie zamockuje moduł, wywołując go i mockując wszystkie eksporty.

Obowiązują następujące zasady:

  • Wszystkie tablice zostaną wyczyszczone.
  • Wszystkie prymitywy i kolekcje pozostaną niezmienione.
  • Wszystkie obiekty zostaną głęboko sklonowane.
  • Wszystkie instancje klas i ich prototypy będą głęboko klonowane.

Moduły wirtualne ​

Vitest obsługuje mockowanie modułów wirtualnych Vite. Działa to inaczej niż sposób, w jaki moduły wirtualne są traktowane w Jest. Zamiast przekazywać virtual: true do funkcji vi.mock, musisz poinformować Vite o istnieniu modułu, w przeciwnym razie podczas parsowania wystąpi błąd. Możesz to zrobić na kilka sposobów:

  1. Podaj alias
ts
import { defineConfig } from 'vitest/config';
import { resolve } from 'node:path';
export default defineConfig({
  test: {
    alias: {
      '$app/forms': resolve('./mocks/forms.js'),
    },
  },
});
  1. Udostępnij wtyczkę, która rozwiązuje moduł wirtualny
ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
  plugins: [
    {
      name: 'virtual-modules',
      resolveId(id) {
        if (id === '$app/forms') {
          return 'virtual:$app/forms';
        }
      },
    },
  ],
});

Zaletą drugiego podejścia jest to, że możesz dynamicznie tworzyć różne wirtualne punkty wejścia. Jeśli przekierujesz kilka modułów wirtualnych do jednego pliku, wszystkie z nich będą podlegać vi.mock, więc upewnij się, że używasz unikalnych identyfikatorów.

Pułapki mockowania ​

Pamiętaj, że nie jest możliwe mockowanie wywołań metod, które są wywoływane wewnątrz innych metod tego samego pliku. Na przykład w tym kodzie:

ts
export function foo() {
  return 'foo';
}

export function foobar() {
  return `${foo()}bar`;
}

Nie jest możliwe mockowanie metody foo z zewnątrz, ponieważ jest ona bezpośrednio odwoływana. Zatem ten kod nie będzie miał wpływu na wywołanie foo wewnątrz foobar (ale wpłynie na wywołanie foo w innych modułach):

ts
import { vi } from 'vitest';
import * as mod from './foobar.js';

// to wpłynie tylko na "foo" poza oryginalnym modułem
vi.spyOn(mod, 'foo');
vi.mock('./foobar.js', async importOriginal => {
  return {
    ...(await importOriginal<typeof import('./foobar.js')>()),
    // to wpłynie tylko na "foo" poza oryginalnym modułem
    foo: () => 'mocked',
  };
});

Możesz potwierdzić to zachowanie, dostarczając implementację metody foobar bezpośrednio:

ts
import * as mod from './foobar.js';

vi.spyOn(mod, 'foo');

// wyeksportowane foo odwołuje się do zamockowanej metody
mod.foobar(mod.foo);
ts
export function foo() {
  return 'foo';
}

export function foobar(injectedFoo) {
  return injectedFoo === foo; // false
}

Jest to zamierzone zachowanie. Zazwyczaj jest to oznaka złego kodu, gdy mockowanie jest stosowane w ten sposób. Rozważ refaktoryzację kodu na wiele plików lub ulepszenie architektury aplikacji za pomocą technik takich jak wstrzykiwanie zależności.

Przykład ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { Client } from 'pg';
import { failure, success } from './handlers.js';

// pobierz zadania
export async function getTodos(event, context) {
  const client = new Client({
    // ...clientOptions
  });

  await client.connect();

  try {
    const result = await client.query('SELECT * FROM todos;');

    client.end();

    return success({
      message: `${result.rowCount} item(s) returned`,
      data: result.rows,
      status: true,
    });
  } catch (e) {
    console.error(e.stack);

    client.end();

    return failure({ message: e, status: false });
  }
}

vi.mock('pg', () => {
  const Client = vi.fn();
  Client.prototype.connect = vi.fn();
  Client.prototype.query = vi.fn();
  Client.prototype.end = vi.fn();

  return { Client };
});

vi.mock('./handlers.js', () => {
  return {
    success: vi.fn(),
    failure: vi.fn(),
  };
});

describe('get a list of todo items', () => {
  let client;

  beforeEach(() => {
    client = new Client();
  });

  afterEach(() => {
    vi.clearAllMocks();
  });

  it('should return items successfully', async () => {
    client.query.mockResolvedValueOnce({ rows: [], rowCount: 0 });

    await getTodos();

    expect(client.connect).toBeCalledTimes(1);
    expect(client.query).toBeCalledWith('SELECT * FROM todos;');
    expect(client.end).toBeCalledTimes(1);

    expect(success).toBeCalledWith({
      message: '0 item(s) returned',
      data: [],
      status: true,
    });
  });

  it('should throw an error', async () => {
    const mError = new Error('Unable to retrieve rows');
    client.query.mockRejectedValueOnce(mError);

    await getTodos();

    expect(client.connect).toBeCalledTimes(1);
    expect(client.query).toBeCalledWith('SELECT * FROM todos;');
    expect(client.end).toBeCalledTimes(1);
    expect(failure).toBeCalledWith({ message: mError, status: false });
  });
});

System plików ​

Mockowanie systemu plików gwarantuje niezależność testów od rzeczywistego systemu plików, co czyni testy bardziej niezawodnymi i przewidywalnymi. Taka izolacja zapobiega efektom ubocznym między testami. Pozwala testować sytuacje błędów i przypadki brzegowe, które mogą być trudne lub niemożliwe do odtworzenia w rzeczywistym systemie plików, takich jak problemy z uprawnieniami, scenariusze pełnego dysku lub błędy odczytu/zapisu.

Vitest domyślnie nie udostępnia żadnego API do mockowania systemu plików. Możesz mockować moduł fs ręcznie przez vi.mock, ale utrzymanie takiego kodu jest trudne. Zamiast tego zalecamy użycie memfs, który automatyzuje ten proces. memfs tworzy system plików w pamięci, który symuluje operacje na plikach bez dotykania rzeczywistego dysku. To rozwiązanie jest szybkie i bezpieczne, eliminując ryzyko efektów ubocznych w rzeczywistym systemie plików.

Przykład ​

Aby automatycznie przekierować wszystkie wywołania fs do memfs, możesz utworzyć pliki __mocks__/fs.cjs i __mocks__/fs/promises.cjs w katalogu głównym swojego projektu:

ts
// możemy również użyć `import`, ale wtedy
// każdy eksport powinien być jawnie zdefiniowany

const { fs } = require('memfs');
module.exports = fs;
ts
// możemy również użyć `import`, ale wtedy
// każdy eksport powinien być jawnie zdefiniowany

const { fs } = require('memfs');
module.exports = fs.promises;
ts
import { readFileSync } from 'node:fs';

export function readHelloWorld(path) {
  return readFileSync(path, 'utf-8');
}
ts
import { beforeEach, expect, it, vi } from 'vitest';
import { fs, vol } from 'memfs';
import { readHelloWorld } from './read-hello-world.js';

// powiedz Vitest, aby użył mocka fs z folderu __mocks__
// można to zrobić w pliku setup, jeśli fs zawsze ma być mockowany
vi.mock('node:fs');
vi.mock('node:fs/promises');

beforeEach(() => {
  // zresetuj stan systemu plików w pamięci
  vol.reset();
});

it('should return correct text', () => {
  const path = '/hello-world.txt';
  fs.writeFileSync(path, 'hello world');

  const text = readHelloWorld(path);
  expect(text).toBe('hello world');
});

it('can return a value multiple times', () => {
  // możesz użyć vol.fromJSON, aby zdefiniować kilka plików
  vol.fromJSON(
    {
      './dir1/hw.txt': 'hello dir1',
      './dir2/hw.txt': 'hello dir2',
    },
    // domyślny katalog roboczy
    '/tmp'
  );

  expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1');
  expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2');
});

Żądania ​

Ponieważ Vitest działa w Node.js, mockowanie żądań sieciowych jest złożone; API webowe nie są dostępne, więc potrzebujemy czegoś, co będzie symulować zachowanie sieciowe. Zalecamy użycie Mock Service Worker do tego celu. Pozwala on mockować żądania sieciowe http, WebSocket i GraphQL i jest niezależny od frameworka.

Mock Service Worker (MSW) działa poprzez przechwytywanie żądań generowanych przez testy, co pozwala na jego użycie bez zmiany kodu aplikacji. W przeglądarce wykorzystuje to Service Worker API. W Node.js i dla Vitest używa biblioteki @mswjs/interceptors. Aby dowiedzieć się więcej o MSW, przeczytaj ich wprowadzenie

Konfiguracja ​

Możesz go użyć w swoim pliku konfiguracyjnym w następujący sposób:

js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { http, HttpResponse } from 'msw';

const posts = [
  {
    userId: 1,
    id: 1,
    title: 'first post title',
    body: 'first post body',
  },
  // ...
];

export const restHandlers = [
  http.get('https://rest-endpoint.example/path/to/posts', () => {
    return HttpResponse.json(posts);
  }),
];

const server = setupServer(...restHandlers);

// Uruchom serwer przed wszystkimi testami
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// Zamknij serwer po wszystkich testach
afterAll(() => server.close());

// Zresetuj handlery po każdym teście dla zachowania izolacji
afterEach(() => server.resetHandlers());
js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { graphql, HttpResponse } from 'msw';

const posts = [
  {
    userId: 1,
    id: 1,
    title: 'first post title',
    body: 'first post body',
  },
  // ...
];

const graphqlHandlers = [
  graphql.query('ListPosts', () => {
    return HttpResponse.json({
      data: { posts },
    });
  }),
];

const server = setupServer(...graphqlHandlers);

// Uruchom serwer przed wszystkimi testami
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// Zamknij serwer po wszystkich testach
afterAll(() => server.close());

// Zresetuj handlery po każdym teście dla zachowania izolacji
afterEach(() => server.resetHandlers());
js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { ws } from 'msw';

const chat = ws.link('wss://chat.example.com');

const wsHandlers = [
  chat.addEventListener('connection', ({ client }) => {
    client.addEventListener('message', event => {
      console.log('Received message from client:', event.data);
      // Odeślij odebraną wiadomość z powrotem do klienta
      client.send(`Server received: ${event.data}`);
    });
  }),
];

const server = setupServer(...wsHandlers);

// Uruchom serwer przed wszystkimi testami
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// Zamknij serwer po wszystkich testach
afterAll(() => server.close());

// Zresetuj handlery po każdym teście dla zachowania izolacji
afterEach(() => server.resetHandlers());

Konfiguracja serwera z opcją onUnhandledRequest: 'error' zapewnia, że błąd zostanie zgłoszony, gdy pojawi się żądanie, które nie ma odpowiadającego mu handlera żądań.

Więcej ​

MSW oferuje znacznie więcej. Możesz uzyskać dostęp do ciasteczek i parametrów zapytania, definiować mockowe odpowiedzi błędów i wiele więcej! Aby zobaczyć wszystko, co możesz zrobić z MSW, przeczytaj ich dokumentację.

Timery ​

Kiedy testujemy kod, który obejmuje timeouty lub interwały, zamiast czekać na ich naturalne zakończenie lub przekroczenie limitu czasu, możemy przyspieszyć nasze testy, używając „fałszywych” timerów, które mockują wywołania setTimeout i setInterval.

Szczegółowy opis API znajdziesz w sekcji vi.useFakeTimers API.

Przykład ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

function executeAfterTwoHours(func) {
  setTimeout(func, 1000 * 60 * 60 * 2); // 2 godziny
}

function executeEveryMinute(func) {
  setInterval(func, 1000 * 60); // 1 minuta
}

const mock = vi.fn(() => console.log('executed'));

describe('delayed execution', () => {
  beforeEach(() => {
    vi.useFakeTimers();
  });
  afterEach(() => {
    vi.restoreAllMocks();
  });
  it('should execute the function', () => {
    executeAfterTwoHours(mock);
    vi.runAllTimers();
    expect(mock).toHaveBeenCalledTimes(1);
  });
  it('should not execute the function', () => {
    executeAfterTwoHours(mock);
    // przesunięcie o 2ms nie uruchomi funkcji
    vi.advanceTimersByTime(2);
    expect(mock).not.toHaveBeenCalled();
  });
  it('should execute every minute', () => {
    executeEveryMinute(mock);
    vi.advanceTimersToNextTimer();
    expect(mock).toHaveBeenCalledTimes(1);
    vi.advanceTimersToNextTimer();
    expect(mock).toHaveBeenCalledTimes(2);
  });
});

Klasy ​

Możesz zamockować całą klasę za pomocą pojedynczego wywołania vi.fn - ponieważ wszystkie klasy są również funkcjami, działa to domyślnie. Należy pamiętać, że obecnie Vitest nie uwzględnia słowa kluczowego new, więc new.target jest zawsze undefined w ciele funkcji.

ts
class Dog {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  static getType(): string {
    return 'animal';
  }

  greet = (): string => {
    return `Hi! My name is ${this.name}!`;
  };

  speak(): string {
    return 'bark!';
  }

  isHungry() {}
  feed() {}
}

Możemy odtworzyć tę klasę za pomocą funkcji ES5:

ts
const Dog = vi.fn(function (name) {
  this.name = name;
  // mockuj metody instancji w konstruktorze, każda instancja będzie miała własnego szpiega
  this.greet = vi.fn(() => `Hi! My name is ${this.name}!`);
});

// zauważ, że metody statyczne są mockowane bezpośrednio na funkcji,
// a nie na instancji klasy
Dog.getType = vi.fn(() => 'mocked animal');

// mockuj metody "speak" i "feed" na każdej instancji klasy
// wszystkie instancje `new Dog()` odziedziczą i będą współdzielić te szpiegi
Dog.prototype.speak = vi.fn(() => 'loud bark!');
Dog.prototype.feed = vi.fn();

WARNING

Jeśli z funkcji konstruktora zostanie zwrócona wartość nieprymitywna, ta wartość stanie się wynikiem wyrażenia new. W tym przypadku [[Prototype]] może nie być poprawnie powiązany:

ts
const CorrectDogClass = vi.fn(function (name) {
  this.name = name;
});

const IncorrectDogClass = vi.fn(name => ({
  name,
}));

const Marti = new CorrectDogClass('Marti');
const Newt = new IncorrectDogClass('Newt');

Marti instanceof CorrectDogClass; // ✅ true
Newt instanceof IncorrectDogClass; // ❌ false!

KIEDY UŻYWAĆ?

Ogólnie rzecz biorąc, zazwyczaj odtwarza się klasę w ten sposób w fabryce modułów, jeśli klasa jest ponownie eksportowana z innego modułu:

ts
import { Dog } from './dog.js';

vi.mock(import('./dog.js'), () => {
  const Dog = vi.fn();
  Dog.prototype.feed = vi.fn();
  // ... inne mocki
  return { Dog };
});

Ta metoda może być również użyta do przekazania instancji klasy do funkcji, która akceptuje ten sam interfejs:

ts
function feed(dog: Dog) {
  // ...
}
ts
import { expect, test, vi } from 'vitest';
import { feed } from '../src/feed.js';

const Dog = vi.fn();
Dog.prototype.feed = vi.fn();

test('can feed dogs', () => {
  const dogMax = new Dog('Max');

  feed(dogMax);

  expect(dogMax.feed).toHaveBeenCalled();
  expect(dogMax.isHungry()).toBe(false);
});

Teraz, gdy tworzymy nową instancję klasy Dog, jej metoda speak (wraz z feed i greet) jest już zamockowana:

ts
const Cooper = new Dog('Cooper');
Cooper.speak(); // głośne szczekanie!
Cooper.greet(); // Cześć! Nazywam się Cooper!

// możesz użyć wbudowanych asercji, aby sprawdzić poprawność wywołania
expect(Cooper.speak).toHaveBeenCalled();
expect(Cooper.greet).toHaveBeenCalled();

const Max = new Dog('Max');

// metody przypisane do prototypu są współdzielone między instancjami
expect(Max.speak).toHaveBeenCalled();
expect(Max.greet).not.toHaveBeenCalled();

Możemy ponownie przypisać wartość zwracaną dla konkretnej instancji:

ts
const dog = new Dog('Cooper');

// "vi.mocked" to pomocnik typów, ponieważ
// TypeScript nie wie, że Dog to zamockowana klasa,
// opakowuje każdą funkcję w typ MockInstance<T>
// bez walidacji, czy funkcja jest mockiem
vi.mocked(dog.speak).mockReturnValue('hau hau');

dog.speak(); // hau hau

Aby zamockować właściwość, możemy użyć metody vi.spyOn(dog, 'name', 'get'). Umożliwia to użycie asercji szpiega na zamockowanej właściwości:

ts
const dog = new Dog('Cooper');

const nameSpy = vi.spyOn(dog, 'name', 'get').mockReturnValue('Max');

expect(dog.name).toBe('Max');
expect(nameSpy).toHaveBeenCalledTimes(1);

TIP

Tą samą metodą można też szpiegować gettery i settery.

Ściągawka ​

INFO

vi w poniższych przykładach jest importowane bezpośrednio z vitest. Możesz również używać go globalnie, jeśli ustawisz globals na true w swojej konfiguracji.

Chcę…

Mockować wyeksportowane zmienne ​

js
export const getter = 'variable';
ts
import * as exports from './example.js';

vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');

Mockować wyeksportowaną funkcję ​

  1. Przykład z vi.mock:

WARNING

Pamiętaj, że wywołanie vi.mock jest hoistowane na początek pliku. Zawsze zostanie wykonane przed wszystkimi importami.

ts
export function method() {}
ts
import { method } from './example.js';

vi.mock('./example.js', () => ({
  method: vi.fn(),
}));
  1. Przykład z vi.spyOn:
ts
import * as exports from './example.js';

vi.spyOn(exports, 'method').mockImplementation(() => {});

Mockować implementację wyeksportowanej klasy ​

  1. Przykład z vi.mock i .prototype:
ts
export class SomeClass {}
ts
import { SomeClass } from './example.js';

vi.mock(import('./example.js'), () => {
  const SomeClass = vi.fn();
  SomeClass.prototype.someMethod = vi.fn();
  return { SomeClass };
});
// SomeClass.mock.instances będzie instancją SomeClass
  1. Przykład z vi.spyOn:
ts
import * as mod from './example.js';

const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();

vi.spyOn(mod, 'SomeClass').mockImplementation(SomeClass);

Szpiegować obiekt zwrócony z funkcji ​

  1. Przykład użycia pamięci podręcznej:
ts
export function useObject() {
  return { method: () => true };
}
ts
import { useObject } from './example.js';

const obj = useObject();
obj.method();
ts
import { useObject } from './example.js';

vi.mock(import('./example.js'), () => {
  let _cache;
  const useObject = () => {
    if (!_cache) {
      _cache = {
        method: vi.fn(),
      };
    }
    // teraz za każdym razem, gdy wywoływane jest useObject(),
    // zwróci ono to samo odwołanie do obiektu
    return _cache;
  };
  return { useObject };
});

const obj = useObject();
// obj.method zostało wywołane wewnątrz some-path
expect(obj.method).toHaveBeenCalled();

Mockować część modułu ​

ts
import { mocked, original } from './some-path.js';

vi.mock(import('./some-path.js'), async importOriginal => {
  const mod = await importOriginal();
  return {
    ...mod,
    mocked: vi.fn(),
  };
});
original(); // ma oryginalne zachowanie
mocked(); // jest funkcją szpiegującą

WARNING

Nie zapominaj, że to tylko mockuje dostęp zewnętrzny. W tym przykładzie, jeśli original wywołuje mocked wewnętrznie, zawsze wywoła funkcję zdefiniowaną w module, a nie w fabryce mocków.

Mockować bieżącą datę ​

Aby zamockować czas Date, możesz użyć funkcji pomocniczej vi.setSystemTime. Ta wartość nie zostanie automatycznie zresetowana między różnymi testami.

Należy pamiętać, że użycie vi.useFakeTimers również zmienia czas Date.

ts
const mockDate = new Date(2022, 0, 1);
vi.setSystemTime(mockDate);
const now = new Date();
expect(now.valueOf()).toBe(mockDate.valueOf());
// zresetuj zamockowany czas
vi.useRealTimers();

Mockować zmienną globalną ​

Możesz ustawić zmienną globalną, przypisując jej wartość do globalThis lub używając pomocnika vi.stubGlobal. Podczas używania vi.stubGlobal, nie zostanie ona automatycznie zresetowana między różnymi testami, chyba że włączysz opcję konfiguracyjną unstubGlobals lub wywołasz vi.unstubAllGlobals.

ts
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');

Mockować import.meta.env ​

  1. Aby zmienić zmienną środowiskową, możesz po prostu przypisać jej nową wartość.

WARNING

Wartość zmiennej środowiskowej nie zostanie automatycznie zresetowana między różnymi testami.

ts
import { beforeEach, expect, it } from 'vitest';

// przed uruchomieniem testów "VITE_ENV" jest "test"
const originalViteEnv = import.meta.env.VITE_ENV;

beforeEach(() => {
  import.meta.env.VITE_ENV = originalViteEnv;
});

it('changes value', () => {
  import.meta.env.VITE_ENV = 'staging';
  expect(import.meta.env.VITE_ENV).toBe('staging');
});
  1. Jeśli chcesz automatycznie zresetować wartość(i), możesz użyć pomocnika vi.stubEnv z włączoną opcją konfiguracyjną unstubEnvs (lub ręcznie wywołać vi.unstubAllEnvs w hooku beforeEach):
ts
import { expect, it, vi } from 'vitest';

// przed uruchomieniem testów "VITE_ENV" jest "test"
import.meta.env.VITE_ENV === 'test';

it('changes value', () => {
  vi.stubEnv('VITE_ENV', 'staging');
  expect(import.meta.env.VITE_ENV).toBe('staging');
});

it('wartość jest przywracana przed uruchomieniem kolejnego testu', () => {
  expect(import.meta.env.VITE_ENV).toBe('test');
});
ts
export default defineConfig({
  test: {
    unstubEnvs: true,
  },
});
Pager
Poprzednia stronaMigawki
Następna stronaRównoległość

Opublikowano na licencji MIT.

Copyright (c) 2021-Present Vitest Team

https://vitest.dev/guide/mocking

Opublikowano na licencji MIT.

Copyright (c) 2021-Present Vitest Team