Skip to content
Vitest 0
Main Navigation GuíaAPIConfiguraciónAvanzado
1.6.1
0.34.6

Español

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

Español

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

Apariencia

Sidebar Navigation

Guía

Por qué Vitest

Empezando

Características

Espacio de trabajo

Interfaz de Línea de Comandos

Filtrado de Pruebas

Cobertura

Capturas instantáneas

Mocking

Pruebas de Tipos

Interfaz de Usuario de Vitest

Modo Navegador (experimental)

Pruebas en el código fuente

Contexto de prueba

Entorno de Pruebas

Extender Matchers

Integración con IDEs

Depuración

Comparaciones con otros Ejecutores de Pruebas

Guía de Migración

Errores frecuentes

API

Referencia de la API de pruebas

Funciones Mock

Vi

expect

expectTypeOf

assertType

Configuración

Configuración de Vitest

En esta página

Mocking ​

Al escribir pruebas, es inevitable que necesites crear una versión "falsa" de un servicio, ya sea interno o externo. Esto se conoce comúnmente como mocking (simulación). Vitest proporciona funciones de utilidad para ayudarte a través de su helper vi. Puedes import { vi } from 'vitest' o acceder a él globalmente (cuando la configuración global está habilitada).

WARNING

¡Recuerda siempre limpiar o restaurar los mocks antes o después de cada ejecución de prueba para deshacer los cambios de estado de los mocks entre ejecuciones! Consulta la documentación de mockReset para obtener más información.

Si quieres empezar directamente, consulta la sección de la API; si no, sigue leyendo para profundizar en el mundo del mocking.

Dates (Fechas) ​

A veces, necesitas tener el control de la fecha para garantizar la coherencia en las pruebas. Vitest utiliza el paquete @sinonjs/fake-timers para manipular los temporizadores, así como la fecha del sistema. Puedes encontrar información más detallada sobre la API específica aquí.

Example (Ejemplo) ​

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(() => {
    // indica a vitest que usaremos tiempo simulado
    vi.useFakeTimers();
  });

  afterEach(() => {
    // restaurando la fecha después de cada ejecución de prueba
    vi.useRealTimers();
  });

  it('allows purchases within business hours', () => {
    // establece la hora dentro del horario comercial
    const date = new Date(2000, 1, 1, 13);
    vi.setSystemTime(date);

    // acceder a Date.now() resultará en la fecha establecida arriba
    expect(purchase()).toEqual({ message: 'Success' });
  });

  it('disallows purchases outside of business hours', () => {
    // establece la hora fuera del horario comercial
    const date = new Date(2000, 1, 1, 19);
    vi.setSystemTime(date);

    // acceder a Date.now() resultará en la fecha establecida arriba
    expect(purchase()).toEqual({ message: 'Error' });
  });
});

Functions (Funciones) ​

El mocking de funciones se puede dividir en dos categorías diferentes: spying (espionaje) & mocking (simulación).

A veces, solo necesitas validar si una función específica ha sido llamada o no (y posiblemente qué argumentos se pasaron). En estos casos, un spy sería suficiente, y puedes usarlo directamente con vi.spyOn() (lee más aquí).

Sin embargo, los spies solo pueden ayudarte a espiar funciones, no pueden modificar su implementación. En el caso de que necesitemos crear una versión falsa (o simulada) de una función, podemos usar vi.fn() (lee más aquí).

Usamos Tinyspy como base para el mocking de funciones, pero tenemos nuestro propio wrapper para hacerlo compatible con jest. Tanto vi.fn() como vi.spyOn() comparten los mismos métodos; sin embargo, solo el resultado de retorno de vi.fn() es invocable.

Example (Ejemplo) ​

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

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

const messages = {
  items: [
    { message: 'Simple test message', from: 'Testman' },
    // ...
  ],
  getLatest, // can also be a `getter or setter if supported`
};

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);
  });
});

More (Más) ​

  • Jest's Mock Functions

Globals (Variables Globales) ​

Puedes simular variables globales que no están presentes con jsdom o node utilizando el helper vi.stubGlobal. Esto asignará el valor de la variable global a un objeto 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);

// ahora puedes acceder a ella como `IntersectionObserver` o `window.IntersectionObserver`

Modules (Módulos) ​

Los módulos simulados se utilizan para simular bibliotecas de terceros que se invocan en otro código, lo que te permite probar argumentos, la salida o incluso redeclarar su implementación.

Consulta la sección de la API vi.mock() para obtener una descripción más detallada de la API.

Automocking algorithm (Algoritmo de Automocking) ​

Si tu código está importando un módulo simulado, sin ningún archivo __mocks__ asociado o factory para este módulo, Vitest simulará el módulo en sí invocándolo y simulando cada exportación.

Se aplican los siguientes principios:

  • Todos los arrays se vaciarán.
  • Todas las primitivas y colecciones permanecerán igual.
  • Todos los objetos se clonarán profundamente.
  • Todas las instancias de clases y sus prototipos se clonarán profundamente.

Example (Ejemplo) ​

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

// handlers (manejadores)
export function success(data) {}
export function failure(data) {}

// get todos (obtener tareas)
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 });
  });
});

Requests (Peticiones) ​

Dado que Vitest se ejecuta en Node, simular peticiones de red es complicado; las APIs web no están disponibles, por lo que necesitamos algo que simule el comportamiento de la red. Recomendamos Mock Service Worker para lograr esto. Te permitirá simular peticiones de red tanto REST como GraphQL, y es independiente del framework.

Mock Service Worker (MSW) funciona interceptando las peticiones que hacen tus pruebas, lo que te permite usarlo sin cambiar nada de tu código de aplicación. En el navegador, esto usa la Service Worker API. En Node.js, y para Vitest, usa node-request-interceptor. Para aprender más sobre MSW, lee su introducción

Configuration (Configuración) ​

Puedes usarlo como se muestra a continuación en tu archivo de configuración

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

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

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

const graphqlHandlers = [
  graphql.query(
    'https://graphql-endpoint.example/api/v1/posts',
    (req, res, ctx) => {
      return res(ctx.data(posts));
    }
  ),
];

const server = setupServer(...restHandlers, ...graphqlHandlers);

// Inicia el servidor antes de todas las pruebas
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// Cierra el servidor después de todas las pruebas
afterAll(() => server.close());

// Restablece los handlers después de cada prueba (importante para el aislamiento de las pruebas)
afterEach(() => server.resetHandlers());

Configurar el servidor con onUnhandleRequest: 'error' garantiza que se genere un error cuando haya una petición sin un handler correspondiente.

Example (Ejemplo) ​

Tenemos un ejemplo completo que usa MSW: React Testing with MSW.

More (Más) ​

Hay mucho más en MSW. Puedes acceder a cookies y parámetros de consulta, definir respuestas de error simuladas, ¡y mucho más! Para ver todo lo que puedes hacer con MSW, lee su documentación.

Timers (Temporizadores) ​

Cuando probamos código que involucra timeouts o intervals, en lugar de hacer que nuestras pruebas esperen o excedan el tiempo de espera, podemos acelerar nuestras pruebas usando temporizadores "falsos" que simulan llamadas a setTimeout y setInterval.

Consulta la sección de la API vi.useFakeTimers para obtener una descripción más detallada de la API.

Example (Ejemplo) ​

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

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

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

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);
    // avanzar 2ms no activará la función
    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);
  });
});

Hoja de Referencia ​

INFO

vi en los ejemplos siguientes se importa directamente desde vitest. También puedes usarlo globalmente si estableces globals a true en tu configuración.

Quiero…

  • Espiar un método
ts
const instance = new SomeClass();
vi.spyOn(instance, 'method');
  • Simular variables exportadas
js
// some-path.js
export const getter = 'variable';
ts
// some-path.test.ts
import * as exports from './some-path.js';

vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');
  • Simular una función exportada

Ejemplo con vi.mock:

ts
// ./some-path.js
export function method() {}
ts
import { method } from './some-path.js';

vi.mock('./some-path.js', () => ({
  method: vi.fn(),
}));

WARNING

Recuerda que la llamada a vi.mock se eleva al principio del archivo. No incluyas llamadas a vi.mock dentro de beforeEach, ya que solo la primera simulará el módulo correctamente.

Ejemplo con vi.spyOn:

ts
import * as exports from './some-path.js';

vi.spyOn(exports, 'method').mockImplementation(() => {});
  • Simular la implementación de una clase exportada

Ejemplo con vi.mock y prototipo:

ts
// some-path.ts
export class SomeClass {}
ts
import { SomeClass } from './some-path.js';

vi.mock('./some-path.js', () => {
  const SomeClass = vi.fn();
  SomeClass.prototype.someMethod = vi.fn();
  return { SomeClass };
});
// SomeClass.mock.instances contendrá instancias de SomeClass

Ejemplo con vi.mock y valor de retorno:

ts
import { SomeClass } from './some-path.js';

vi.mock('./some-path.js', () => {
  const SomeClass = vi.fn(() => ({
    someMethod: vi.fn(),
  }));
  return { SomeClass };
});
// SomeClass.mock.returns contendrá el objeto retornado

Ejemplo con vi.spyOn:

ts
import * as exports from './some-path.js';

vi.spyOn(exports, 'SomeClass').mockImplementation(() => {
  // lo que necesites de los dos primeros ejemplos
});
  • Espiar un objeto devuelto por una función

Ejemplo usando caché:

ts
// some-path.ts
export function useObject() {
  return { method: () => true };
}
ts
// useObject.js
import { useObject } from './some-path.js';

const obj = useObject();
obj.method();
ts
// useObject.test.js
import { useObject } from './some-path.js';

vi.mock('./some-path.js', () => {
  let _cache;
  const useObject = () => {
    if (!_cache) {
      _cache = {
        method: vi.fn(),
      };
    }
    // ahora cada vez que se llama a useObject()
    // devolverá la misma referencia al objeto
    return _cache;
  };
  return { useObject };
});

const obj = useObject();
// obj.method fue llamado dentro de some-path
expect(obj.method).toHaveBeenCalled();
  • Simular parte de un módulo
ts
import { mocked, original } from './some-path.js';

vi.mock('./some-path.js', async () => {
  const mod = await vi.importActual<typeof import('./some-path.js')>(
    './some-path.js'
  );
  return {
    ...mod,
    mocked: vi.fn(),
  };
});
original(); // tiene el comportamiento original
mocked(); // es una función espía
  • Simular la fecha actual

Para simular el tiempo de Date, puedes usar la función auxiliar vi.setSystemTime. Este valor no se restablecerá automáticamente entre pruebas.

Ten en cuenta que usar vi.useFakeTimers también modifica el tiempo de Date.

ts
const mockDate = new Date(2022, 0, 1);
vi.setSystemTime(mockDate);
const now = new Date();
expect(now.valueOf()).toBe(mockDate.valueOf());
// restablecer el tiempo simulado
vi.useRealTimers();
  • Simular una variable global

Puedes establecer una variable global asignando un valor a globalThis o usando el auxiliar vi.stubGlobal. Cuando se usa vi.stubGlobal, no se restablecerá automáticamente entre pruebas, a menos que actives la opción de configuración unstubGlobals o llames a vi.unstubAllGlobals.

ts
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');
  • Simular import.meta.env

Para cambiar una variable de entorno, puedes simplemente asignarle un nuevo valor. Este valor no se restablecerá automáticamente entre pruebas.

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

// puedes restablecerlo manualmente en el hook beforeEach
const originalViteEnv = import.meta.env.VITE_ENV;

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

it('cambia el valor', () => {
  import.meta.env.VITE_ENV = 'staging';
  expect(import.meta.env.VITE_ENV).toBe('staging');
});

Si deseas restablecer el valor automáticamente, puedes usar el auxiliar vi.stubEnv con la opción de configuración unstubEnvs habilitada (o llamar a vi.unstubAllEnvs manualmente en el hook beforeEach):

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

// antes de ejecutar las pruebas "VITE_ENV" es "test"
import.meta.env.VITE_ENV === 'test';

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

it('el valor se restaura antes de ejecutar otra prueba', () => {
  expect(import.meta.env.VITE_ENV).toBe('test');
});
ts
// vitest.config.ts
export default {
  test: {
    unstubAllEnvs: true,
  },
};
Pager
AnteriorCapturas instantáneas
SiguientePruebas de Tipos

Publicado bajo la licencia MIT.

Copyright (c) 2024 Mithril Contributors

https://v0.vitest.dev/guide/mocking

Publicado bajo la licencia MIT.

Copyright (c) 2024 Mithril Contributors