expect
아래 타입은 아래 타입 정의에서 사용됩니다.
type Awaitable<T> = T | PromiseLike<T>;
expect
는 어설션을 생성하는 데 사용됩니다. 여기서 어설션(assertion)
은 특정 조건이 참인지 확인하는 함수를 호출하는 것을 의미합니다. Vitest는 기본적으로 chai
어설션을 제공하며, chai
를 기반으로 구축된 Jest
호환 어설션도 제공합니다.
예를 들어, 다음 코드는 input
값이 2
와 같은지 단언합니다. 그렇지 않으면 어설션이 오류를 발생시키고 테스트가 실패합니다.
import { expect } from 'vitest';
const input = Math.sqrt(4);
expect(input).to.equal(2); // chai API
expect(input).toBe(2); // jest API
정확히 말하면, 이 예제는 test
함수를 사용하지 않으므로 콘솔에 Vitest 출력이 아닌 Node.js 오류가 표시됩니다. test
에 대해 자세히 알아보려면 테스트 API 참조를 확인하세요.
또한 expect
는 매처 함수 등에 접근하기 위해 정적으로 사용할 수도 있습니다.
WARNING
expect
는 표현식에 타입 오류가 없을 경우 타입 테스트에 영향을 주지 않습니다. Vitest를 타입 검사기로 사용하려면 expectTypeOf
또는 assertType
을 사용하세요.
soft
- 타입:
ExpectStatic & (actual: any) => Assertions
expect.soft
는 expect
와 유사하게 동작하지만, 실패한 어설션이 발생하더라도 테스트 실행을 중단하지 않고 계속 진행하며, 해당 실패를 테스트 실패로 기록합니다. 테스트 중에 발생한 모든 오류는 테스트가 완료될 때 출력됩니다.
import { expect, test } from 'vitest';
test('expect.soft 테스트', () => {
expect.soft(1 + 1).toBe(3); // 테스트를 실패로 표시하고 계속 진행
expect.soft(1 + 2).toBe(4); // 테스트를 실패로 표시하고 계속 진행
});
// 테스트가 끝나면 위의 오류들이 출력됩니다.
expect
와 함께 사용할 수 있습니다. expect
어설션이 실패하면 테스트가 즉시 종료되고 모든 오류가 표시됩니다.
import { expect, test } from 'vitest';
test('expect.soft 테스트', () => {
expect.soft(1 + 1).toBe(3); // 테스트를 실패로 표시하고 계속 진행
expect(1 + 2).toBe(3); // 실패하고 테스트를 종료하며, 이전의 모든 오류가 출력됩니다.
expect.soft(1 + 2).toBe(4); // 실행되지 않음
});
WARNING
expect.soft
는 test
함수 내에서만 사용할 수 있습니다.
not
not
을 사용하면 어설션의 결과를 부정할 수 있습니다. 예를 들어, 다음 코드는 input
값이 2
와 같지 않음을 단언합니다. 만약 같다면 어설션이 오류를 발생시키고 테스트가 실패합니다.
import { expect, test } from 'vitest';
const input = Math.sqrt(16);
expect(input).not.to.equal(2); // chai API
expect(input).not.toBe(2); // jest API
toBe
- 타입:
(value: any) => Awaitable<void>
toBe
는 원시 타입의 값이 같은지, 또는 객체가 동일한 메모리 주소를 참조하는지 확인할 때 사용합니다. 이는 expect(Object.is(3, 3)).toBe(true)
를 호출하는 것과 같습니다. 객체가 동일하지 않지만 구조가 같은지 확인하려면 toEqual
을 사용하세요.
예를 들어, 다음 코드는 거래자가 사과 13개를 가지고 있는지 확인합니다.
import { expect, test } from 'vitest';
const stock = {
type: 'apples',
count: 13,
};
test('stock has 13 apples', () => {
expect(stock.type).toBe('apples');
expect(stock.count).toBe(13);
});
test('stocks are the same', () => {
const refStock = stock; // same reference
expect(stock).toBe(refStock);
});
부동 소수점 숫자와 함께 toBe
를 사용하는 것은 권장되지 않습니다. JavaScript는 숫자를 반올림하므로 0.1 + 0.2
는 정확히 0.3
이 아닙니다. 부동 소수점 숫자를 안정적으로 단언하려면 toBeCloseTo
어설션을 사용하세요.
toBeCloseTo
- 타입:
(value: number, numDigits?: number) => Awaitable<void>
toBeCloseTo
를 사용하여 부동 소수점 숫자를 비교할 수 있습니다. 선택적 인수인 numDigits
는 소수점 이하 몇 자리까지 비교할지 지정합니다. 예를 들어:
import { expect, test } from 'vitest';
test.fails('decimals are not equal in javascript', () => {
expect(0.2 + 0.1).toBe(0.3); // 0.2 + 0.1은 0.30000000000000004입니다.
});
test('decimals are rounded to 5 after the point', () => {
// 0.2 + 0.1은 0.30000 | "000000000004"가 제거되었습니다.
expect(0.2 + 0.1).toBeCloseTo(0.3, 5);
// 0.30000000000000004에서 제거된 것은 없습니다.
expect(0.2 + 0.1).not.toBeCloseTo(0.3, 50);
});
toBeDefined
- 타입:
() => Awaitable<void>
toBeDefined
는 값이 undefined
가 아님을 단언합니다. 함수가 어떤 값이든 반환했는지 확인하는 데 유용합니다.
import { expect, test } from 'vitest';
function getApples() {
return 3;
}
test('function returned something', () => {
expect(getApples()).toBeDefined();
});
toBeUndefined
- 타입:
() => Awaitable<void>
toBeUndefined
는 toBeDefined
와 반대로, 값이 undefined
인지 확인합니다. 함수가 아무것도 반환하지 않았는지 확인하는 데 유용합니다.
import { expect, test } from 'vitest';
function getApplesFromStock(stock) {
if (stock === 'Bill') return 13;
}
test("mary doesn't have a stock", () => {
expect(getApplesFromStock('Mary')).toBeUndefined();
});
toBeTruthy
- 타입:
() => Awaitable<void>
toBeTruthy
는 값이 불리언으로 변환될 때 true
인지 단언합니다. 값 자체보다는 true
로 평가되는지 확인할 때 유용합니다.
예를 들어, 다음 코드가 있을 때 stocks.getInfo
의 반환 값에는 관심이 없습니다. 복잡한 객체, 문자열 또는 다른 어떤 것이든 될 수 있습니다. 코드는 여전히 작동합니다.
import { Stocks } from './stocks.js';
const stocks = new Stocks();
stocks.sync('Bill');
if (stocks.getInfo('Bill')) stocks.sell('apples', 'Bill');
따라서 stocks.getInfo
가 truthy인지 테스트하려면 다음과 같이 작성할 수 있습니다.
import { expect, test } from 'vitest';
import { Stocks } from './stocks.js';
const stocks = new Stocks();
test('if we know Bill stock, sell apples to him', () => {
stocks.sync('Bill');
expect(stocks.getInfo('Bill')).toBeTruthy();
});
JavaScript의 모든 값은 false
, 0
, ''
, null
, undefined
및 NaN
을 제외하고는 truthy입니다.
toBeFalsy
- 타입:
() => Awaitable<void>
toBeFalsy
는 값이 불리언으로 변환될 때 false
인지 단언합니다. 값 자체보다는 false
로 평가되는지 확인할 때 유용합니다.
예를 들어, 다음 코드가 있을 때 stocks.stockFailed
의 반환 값에는 관심이 없습니다. falsy 값을 반환할 수 있지만 코드는 여전히 실행됩니다.
import { Stocks } from './stocks.js';
const stocks = new Stocks();
stocks.sync('Bill');
if (!stocks.stockFailed('Bill')) stocks.sell('apples', 'Bill');
따라서 stocks.stockFailed
가 falsy인지 테스트하려면 다음과 같이 작성할 수 있습니다.
import { expect, test } from 'vitest';
import { Stocks } from './stocks.js';
const stocks = new Stocks();
test("if Bill stock hasn't failed, sell apples to him", () => {
stocks.syncStocks('Bill');
expect(stocks.stockFailed('Bill')).toBeFalsy();
});
JavaScript의 모든 값은 false
, 0
, ''
, null
, undefined
및 NaN
을 제외하고는 truthy입니다.
toBeNull
- 타입:
() => Awaitable<void>
toBeNull
은 단순히 어떤 값이 null
인지 단언합니다. .toBe(null)
의 별칭입니다.
import { expect, test } from 'vitest';
function apples() {
return null;
}
test("we don't have apples", () => {
expect(apples()).toBeNull();
});
toBeNaN
- 타입:
() => Awaitable<void>
toBeNaN
은 단순히 어떤 값이 NaN
인지 단언합니다. .toBe(NaN)
의 별칭입니다.
import { expect, test } from 'vitest';
let i = 0;
function getApplesCount() {
i++;
return i > 1 ? Number.NaN : i;
}
test('getApplesCount has some unusual side effects...', () => {
expect(getApplesCount()).not.toBeNaN();
expect(getApplesCount()).toBeNaN();
});
toBeTypeOf
- 타입:
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>
toBeTypeOf
는 실제 값이 주어진 타입과 같은 타입인지 단언합니다.
import { expect, test } from 'vitest';
const actual = 'stock';
test('stock is type of string', () => {
expect(actual).toBeTypeOf('string');
});
toBeInstanceOf
- 타입:
(c: any) => Awaitable<void>
toBeInstanceOf
는 실제 값이 주어진 클래스의 인스턴스인지 단언합니다.
import { expect, test } from 'vitest';
import { Stocks } from './stocks.js';
const stocks = new Stocks();
test('stocks are instance of Stocks', () => {
expect(stocks).toBeInstanceOf(Stocks);
});
toBeGreaterThan
- 타입:
(n: number | bigint) => Awaitable<void>
toBeGreaterThan
은 실제 값이 주어진 값보다 큰지 단언합니다. 값이 같으면 테스트는 실패합니다.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('have more then 10 apples', () => {
expect(getApples()).toBeGreaterThan(10);
});
toBeGreaterThanOrEqual
- 타입:
(n: number | bigint) => Awaitable<void>
toBeGreaterThanOrEqual
은 실제 값이 주어진 값보다 크거나 같은지 단언합니다.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('have 11 apples or more', () => {
expect(getApples()).toBeGreaterThanOrEqual(11);
});
toBeLessThan
- 타입:
(n: number | bigint) => Awaitable<void>
toBeLessThan
은 실제 값이 주어진 값보다 작은지 단언합니다. 값이 같으면 테스트는 실패합니다.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('have less then 20 apples', () => {
expect(getApples()).toBeLessThan(20);
});
toBeLessThanOrEqual
- 타입:
(n: number | bigint) => Awaitable<void>
toBeLessThanOrEqual
은 실제 값이 주어진 값보다 작거나 같은지 단언합니다.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('have 11 apples or less', () => {
expect(getApples()).toBeLessThanOrEqual(11);
});
toEqual
- 타입:
(received: any) => Awaitable<void>
toEqual
은 실제 값이 주어진 값과 같거나 객체인 경우, 재귀적으로 비교하여 동일한 구조를 갖는지 단언합니다. 다음 예제에서 toEqual
과 toBe
의 차이점을 확인할 수 있습니다.
import { expect, test } from 'vitest';
const stockBill = {
type: 'apples',
count: 13,
};
const stockMary = {
type: 'apples',
count: 13,
};
test('stocks have the same properties', () => {
expect(stockBill).toEqual(stockMary);
});
test('stocks are not the same', () => {
expect(stockBill).not.toBe(stockMary);
});
WARNING
Error
객체에 대해서는 깊은 동일성 비교가 수행되지 않습니다. 어떤 값이 throw되었는지 테스트하려면 toThrowError
어설션을 사용하세요.
toStrictEqual
- 타입:
(received: any) => Awaitable<void>
toStrictEqual
은 실제 값이 주어진 값과 같거나 객체인 경우, 동일한 구조를 갖는지 (재귀적으로 비교) 그리고 동일한 타입인지 단언합니다.
.toEqual
과의 차이점:
undefined
속성이 있는 키를 확인합니다. 예를 들어.toStrictEqual
을 사용할 때{a: undefined, b: 2}
는{b: 2}
와 일치하지 않습니다.- 배열의 빈 요소를 확인합니다. 예를 들어
.toStrictEqual
을 사용할 때[, 1]
은[undefined, 1]
과 일치하지 않습니다. - 객체의 타입이 동일한지 확인합니다. 예를 들어 필드
a
와b
가 있는 클래스 인스턴스는 필드a
와b
가 있는 리터럴 객체와 같지 않습니다.
import { expect, test } from 'vitest';
class Stock {
constructor(type) {
this.type = type;
}
}
test('structurally the same, but semantically different', () => {
expect(new Stock('apples')).toEqual({ type: 'apples' });
expect(new Stock('apples')).not.toStrictEqual({ type: 'apples' });
});
toContain
- 타입:
(received: string) => Awaitable<void>
toContain
은 배열에 특정 요소가 포함되어 있는지 확인합니다. 또한 toContain
은 문자열이 다른 문자열의 하위 문자열인지 확인할 수도 있습니다.
import { expect, test } from 'vitest';
import { getAllFruits } from './stocks.js';
test('the fruit list contains orange', () => {
expect(getAllFruits()).toContain('orange');
});
toContainEqual
- 타입:
(received: any) => Awaitable<void>
toContainEqual
은 배열에 특정 구조와 값을 가진 요소가 포함되어 있는지 확인합니다. 배열의 각 요소에 대해 toEqual
을 적용하는 것과 같습니다.
import { expect, test } from 'vitest';
import { getFruitStock } from './stocks.js';
test('apple available', () => {
expect(getFruitStock()).toContainEqual({ fruit: 'apple', count: 5 });
});
toHaveLength
- 타입:
(received: number) => Awaitable<void>
toHaveLength
는 객체가 .length
속성을 가지고 있고, 그 값이 특정 숫자인지 확인합니다.
import { expect, test } from 'vitest';
test('toHaveLength', () => {
expect('abc').toHaveLength(3);
expect([1, 2, 3]).toHaveLength(3);
expect('').not.toHaveLength(3); // .length가 3이 아님
expect({ length: 3 }).toHaveLength(3);
});
toHaveProperty
타입:
(key: any, received?: any) => Awaitable<void>
toHaveProperty
는 객체가 주어진key
에 해당하는 속성을 가지고 있는지 확인합니다.선택적으로 값 매개변수를 제공하여 속성 값에 대한 깊은 동일성(deep equality) 비교를 수행할 수 있습니다. 이는
toEqual
매처와 유사하게, 객체의 해당 속성 값과 비교하는 데 사용됩니다.tsimport { expect, test } from 'vitest'; const invoice = { isActive: true, 'P.O': '12345', customer: { first_name: 'John', last_name: 'Doe', location: 'China', }, total_amount: 5000, items: [ { type: 'apples', quantity: 10, }, { type: 'oranges', quantity: 5, }, ], }; test('John Doe 인보이스', () => { expect(invoice).toHaveProperty('isActive'); // 키의 존재 여부를 확인합니다. expect(invoice).toHaveProperty('total_amount', 5000); // 키가 존재하고 값이 일치하는지 확인합니다. expect(invoice).not.toHaveProperty('account'); // 해당 키가 존재하지 않는지 확인합니다. // 점 표기법을 사용한 깊은 접근 expect(invoice).toHaveProperty('customer.first_name'); expect(invoice).toHaveProperty('customer.last_name', 'Doe'); expect(invoice).not.toHaveProperty('customer.location', 'India'); // 키를 포함하는 배열을 사용한 깊은 접근 expect(invoice).toHaveProperty('items[0].type', 'apples'); expect(invoice).toHaveProperty('items.0.type', 'apples'); // 점 표기법도 작동합니다. // keyPath를 포함하는 배열을 사용한 깊은 접근 expect(invoice).toHaveProperty(['items', 0, 'type'], 'apples'); expect(invoice).toHaveProperty(['items', '0', 'type'], 'apples'); // 문자열 표기법도 작동합니다. // 키가 깊은 접근으로 해석되는 것을 방지하려면 키를 배열로 감싸세요. expect(invoice).toHaveProperty(['P.O'], '12345'); });
toMatch
타입:
(received: string | regexp) => Awaitable<void>
toMatch
는 문자열이 정규 표현식 또는 문자열과 일치하는지 확인합니다.tsimport { expect, test } from 'vitest'; test('인기 과일', () => { expect('top fruits include apple, orange and grape').toMatch(/apple/); expect('applefruits').toMatch('fruit'); // toMatch는 문자열도 사용할 수 있습니다. });
TIP
오류 메시지에서 값이 너무 짧게 잘려 표시되는 경우, 설정 파일에서 chaiConfig.truncateThreshold 값을 늘려 보세요.
toMatchObject
타입:
(received: object | array) => Awaitable<void>
toMatchObject
는 객체가 다른 객체의 속성 부분 집합과 일치하는지 확인합니다. 즉,received
객체가 주어진 객체의 속성을 포함하는지 확인합니다.객체 배열을 전달할 수도 있습니다. 이는
arrayContaining
이 수신된 배열에 추가 요소가 있어도 통과하는 것과 달리, 두 배열의 요소 개수가 정확히 일치하는지 확인할 때 유용합니다.tsimport { expect, test } from 'vitest'; const johnInvoice = { isActive: true, customer: { first_name: 'John', last_name: 'Doe', location: 'China', }, total_amount: 5000, items: [ { type: 'apples', quantity: 10, }, { type: 'oranges', quantity: 5, }, ], }; const johnDetails = { customer: { first_name: 'John', last_name: 'Doe', location: 'China', }, }; test('송장에 John의 개인 정보가 있는지 확인', () => { expect(johnInvoice).toMatchObject(johnDetails); }); test('요소 개수가 정확히 일치해야 함을 확인', () => { // 객체 배열이 일치하는지 확인합니다. expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([ { foo: 'bar' }, { baz: 1 }, ]); });
toThrowError
타입:
(received: any) => Awaitable<void>
별칭:
toThrow
toThrowError
는 함수를 호출했을 때 오류가 발생하는지 확인합니다.특정 오류가 발생하는지 확인하기 위해 선택적 인수를 제공할 수 있습니다.
- 정규 표현식: 오류 메시지가 주어진 패턴과 일치하는지 확인합니다.
- 문자열: 오류 메시지에 주어진 문자열이 포함되어 있는지 확인합니다.
TIP
오류를 catch하려면 테스트하려는 코드를 함수로 감싸야 합니다. 그렇지 않으면 테스트가 실패합니다.
예를 들어
getFruitStock('pineapples')
함수가 오류를 발생시키는지 테스트하려면 다음과 같이 작성할 수 있습니다.tsimport { expect, test } from 'vitest'; function getFruitStock(type) { if (type === 'pineapples') throw new DiabetesError( 'Pineapples are not good for people with diabetes' ); // 다른 작업 수행 } test('파인애플 처리 시 오류 발생', () => { // 오류 메시지에 "diabetes"가 포함되어 있는지 테스트합니다. 다음은 동일합니다. expect(() => getFruitStock('pineapples')).toThrowError(/diabetes/); expect(() => getFruitStock('pineapples')).toThrowError('diabetes'); // 정확한 오류 메시지 테스트 expect(() => getFruitStock('pineapples')).toThrowError( /^Pineapples are not good for people with diabetes$/ ); });
TIP
비동기 함수의 오류 발생 여부를 테스트하려면 rejects와 함께 사용하세요.
jsfunction getAsyncFruitStock() { return Promise.reject(new Error('empty')); } test('파인애플 처리 시 오류 발생', async () => { await expect(() => getAsyncFruitStock()).rejects.toThrowError('empty'); });
toMatchSnapshot
타입:
<T>(shape?: Partial<T> | string, message?: string) => void
이 매처는 값이 최신 스냅샷과 일치하는지 확인합니다.
테스트 이름에 추가되는 선택적
hint
문자열 인수를 제공할 수 있습니다. Vitest는 스냅샷 이름 끝에 항상 숫자를 추가하지만, 짧고 설명적인 힌트를 사용하면 하나의it
또는test
블록 내에서 여러 스냅샷을 숫자보다 효과적으로 구별할 수 있습니다. Vitest는 해당.snap
파일에서 이름별로 스냅샷을 정렬합니다.TIP
스냅샷이 일치하지 않아 테스트가 실패하는 경우, 예상되는 불일치라면
u
키를 눌러 스냅샷을 업데이트할 수 있습니다. 또는-u
또는--update
CLI 옵션을 전달하여 Vitest가 항상 테스트를 업데이트하도록 설정할 수 있습니다.tsimport { expect, test } from 'vitest'; test('스냅샷과 일치', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchSnapshot(); });
객체의 구조만 테스트하고 완전한 일치가 필요하지 않은 경우 객체의 모양(shape)을 제공할 수도 있습니다.
tsimport { expect, test } from 'vitest'; test('스냅샷과 일치', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchSnapshot({ foo: expect.any(Set) }); });
toMatchInlineSnapshot
타입:
<T>(shape?: Partial<T> | string, snapshot?: string, message?: string) => void
이 매처는 값이 최신 인라인 스냅샷과 일치하는지 확인합니다.
Vitest는 외부
.snap
파일 대신 테스트 파일 내의 매처에inlineSnapshot
문자열 인수를 추가하고 업데이트합니다.tsimport { expect, test } from 'vitest'; test('인라인 스냅샷과 일치', () => { const data = { foo: new Set(['bar', 'snapshot']) }; // Vitest는 스냅샷을 업데이트할 때 다음 내용을 업데이트합니다. expect(data).toMatchInlineSnapshot(` { "foo": Set { "bar", "snapshot", }, } `); });
객체의 구조만 테스트하고 완전한 일치가 필요하지 않은 경우 객체의 모양(shape)을 제공할 수도 있습니다.
tsimport { expect, test } from 'vitest'; test('스냅샷과 일치', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchInlineSnapshot( { foo: expect.any(Set) }, ` { "foo": Any<Set>, } ` ); });
toMatchFileSnapshot
타입:
<T>(filepath: string, message?: string) => Promise<void>
버전: Vitest 0.30.0 이후
스냅샷을
.snap
파일 대신, 사용자가 명시적으로 지정한 파일의 내용과 비교하거나 업데이트합니다.tsimport { expect, it } from 'vitest'; it('기본 렌더링', async () => { const result = renderHTML(h('div', { class: 'foo' })); await expect(result).toMatchFileSnapshot('./test/basic.output.html'); });
파일 시스템 작업은 비동기적으로 수행되므로
toMatchFileSnapshot()
와 함께await
를 사용해야 합니다.
toThrowErrorMatchingSnapshot
타입:
(message?: string) => void
toMatchSnapshot
과 동일한 방식으로 작동하지만,toThrowError
매처와 함께 사용하기 위해 오류 값을 예상합니다.함수가
Error
를 발생시키면 스냅샷은 오류 메시지가 됩니다. 그렇지 않으면 스냅샷은 함수에서 반환된 값이 됩니다.
toThrowErrorMatchingInlineSnapshot
타입:
(snapshot?: string, message?: string) => void
toMatchInlineSnapshot
과 동일한 방식으로 작동하지만,toThrowError
매처와 함께 사용하기 위해 오류 값을 예상합니다.함수가
Error
를 발생시키면 스냅샷은 오류 메시지가 됩니다. 그렇지 않으면 스냅샷은 함수에서 반환된 값이 됩니다.
toHaveBeenCalled
타입:
() => Awaitable<void>
이 단언은 함수가 호출되었는지 여부를 테스트하는 데 유용합니다.
expect
에 스파이 함수를 전달해야 합니다.tsimport { expect, test, vi } from 'vitest'; const market = { buy(subject: string, amount: number) { // ... }, }; test('모의 함수', () => { const buySpy = vi.spyOn(market, 'buy'); expect(buySpy).not.toHaveBeenCalled(); market.buy('apples', 10); expect(buySpy).toHaveBeenCalled(); });
toHaveBeenCalledTimes
- 타입:
(amount: number) => Awaitable<void>
이 단언은 함수가 특정 횟수만큼 호출되었는지 확인합니다. expect
에 스파이 함수를 전달해야 합니다.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('모의 함수가 두 번 호출되었는지 확인', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenCalledTimes(2);
});
toHaveBeenCalledWith
- 타입:
(...args: any[]) => Awaitable<void>
이 단언은 함수가 특정 매개변수를 사용하여 최소 한 번 이상 호출되었는지 확인합니다. expect
에 스파이 함수를 전달해야 합니다.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('모의 함수', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenCalledWith('apples', 10);
expect(buySpy).toHaveBeenCalledWith('apples', 20);
});
toHaveBeenLastCalledWith
- 타입:
(...args: any[]) => Awaitable<void>
이 단언은 함수가 마지막으로 호출되었을 때 특정 매개변수를 사용하여 호출되었는지 확인합니다. expect
에 스파이 함수를 전달해야 합니다.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('모의 함수', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).not.toHaveBeenLastCalledWith('apples', 10);
expect(buySpy).toHaveBeenLastCalledWith('apples', 20);
});
toHaveBeenNthCalledWith
- 타입:
(time: number, ...args: any[]) => Awaitable<void>
이 단언은 함수가 특정 순서로 호출되었을 때 특정 매개변수를 사용하여 호출되었는지 확인합니다. 호출 횟수는 1부터 시작합니다. 따라서 두 번째 호출을 확인하려면 .toHaveBeenNthCalledWith(2, ...)
와 같이 작성합니다.
expect
에 스파이 함수를 전달해야 합니다.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('스파이 함수의 첫 번째 호출이 올바른 매개변수로 호출됨', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenNthCalledWith(1, 'apples', 10);
});
toHaveReturned
- 타입:
() => Awaitable<void>
이 단언은 함수가 최소 한 번 이상 성공적으로 값을 반환했는지 확인합니다 (즉, 오류를 발생시키지 않았는지 확인합니다). expect
에 스파이 함수를 전달해야 합니다.
import { expect, test, vi } from 'vitest';
function getApplesPrice(amount: number) {
const PRICE = 10;
return amount * PRICE;
}
test('모의 함수가 값을 반환함', () => {
const getPriceSpy = vi.fn(getApplesPrice);
const price = getPriceSpy(10);
expect(price).toBe(100);
expect(getPriceSpy).toHaveReturned();
});
toHaveReturnedTimes
- 타입:
(amount: number) => Awaitable<void>
이 단언은 함수가 정확히 지정된 횟수만큼 성공적으로 값을 반환했는지 확인합니다 (즉, 오류를 발생시키지 않았는지 확인합니다). expect
에 스파이 함수를 전달해야 합니다.
import { expect, test, vi } from 'vitest';
test('모의 함수가 두 번 값을 반환했는지 확인', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveReturnedTimes(2);
});
toHaveReturnedWith
- 타입:
(returnValue: any) => Awaitable<void>
이 어설션은 함수가 특정 인수로 호출되어 최소 한 번 이상 성공적으로 값을 반환했는지 확인합니다. expect
에 스파이 함수를 전달해야 합니다.
import { expect, test, vi } from 'vitest';
test('스파이 함수가 제품을 반환합니다', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('사과');
expect(sell).toHaveReturnedWith({ product: '사과' });
});
toHaveLastReturnedWith
- 타입:
(returnValue: any) => Awaitable<void>
이 어설션은 함수가 마지막 호출에서 특정 인수를 사용하여 값을 성공적으로 반환했는지 확인합니다. expect
에 스파이 함수를 전달해야 합니다.
import { expect, test, vi } from 'vitest';
test('스파이 함수가 마지막 호출에서 바나나를 반환합니다', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('사과');
sell('바나나');
expect(sell).toHaveLastReturnedWith({ product: '바나나' });
});
toHaveNthReturnedWith
- 타입:
(time: number, returnValue: any) => Awaitable<void>
이 어설션은 함수가 특정 번째 호출에서 특정 인수를 사용하여 값을 성공적으로 반환했는지 확인합니다. expect
에 스파이 함수를 전달해야 합니다.
import { expect, test, vi } from 'vitest';
test('스파이 함수가 두 번째 호출에서 바나나를 반환합니다', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('사과');
sell('바나나');
expect(sell).toHaveNthReturnedWith(2, { product: '바나나' });
});
toSatisfy
- 타입:
(predicate: (value: any) => boolean) => Awaitable<void>
이 어설션은 값이 주어진 조건 함수를 만족하는지 확인합니다.
describe('toSatisfy()', () => {
const isOdd = (value: number) => value % 2 !== 0;
it('1로 통과', () => {
expect(1).toSatisfy(isOdd);
});
it('부정일 때 통과', () => {
expect(2).not.toSatisfy(isOdd);
});
});
resolves
타입:
Promisify<Assertions>
resolves
는 비동기 코드에 대한 어설션을 더 쉽게 작성할 수 있도록 도와줍니다. Promise가 성공적으로 이행되었을 때의 값을 추출하여 일반적인 어설션으로 검증하는 데 사용됩니다. Promise가 거부되면 어설션은 실패합니다.동일한
Assertions
객체를 반환하지만, 모든 매처가 이제Promise
를 반환하므로await
해야 합니다.chai
어설션과도 호환됩니다.예를 들어 API 호출을 수행하고 데이터를 반환하는 함수가 있는 경우, 다음 코드를 사용하여 반환 값을 어설션할 수 있습니다.
tsimport { expect, test } from 'vitest'; async function buyApples() { return fetch('/buy/apples').then(r => r.json()); } test('buyApples는 새 재고 ID를 반환합니다', async () => { // toEqual은 이제 프로미스를 반환하므로 await해야 합니다. await expect(buyApples()).resolves.toEqual({ id: 1 }); // jest API await expect(buyApples()).resolves.to.equal({ id: 1 }); // chai API });
WARNING
어설션을
await
하지 않으면 매번 통과하는 오탐(false positive) 테스트가 발생할 수 있습니다. 어설션이 실제로 호출되었는지 확인하려면expect.assertions(number)
를 사용해야 합니다.
rejects
타입:
Promisify<Assertions>
rejects
는 비동기 코드에 대한 어설션을 더 쉽게 작성할 수 있도록 도와줍니다. Promise가 거부되었을 때의 이유를 추출하여 일반적인 어설션으로 검증하는 데 사용됩니다. Promise가 성공적으로 이행되면 어설션은 실패합니다.동일한
Assertions
객체를 반환하지만, 모든 매처가 이제Promise
를 반환하므로await
해야 합니다.chai
어설션과도 호환됩니다.예를 들어 호출 시 실패하는 함수가 있는 경우, 다음 코드를 사용하여 거부 이유를 어설션할 수 있습니다.
tsimport { expect, test } from 'vitest'; async function buyApples(id) { if (!id) throw new Error('id가 없습니다'); } test('id가 제공되지 않으면 buyApples가 오류를 발생시킵니다', async () => { // toThrow는 이제 프로미스를 반환하므로 await해야 합니다. await expect(buyApples()).rejects.toThrow('id가 없습니다'); });
WARNING
어설션을
await
하지 않으면 매번 통과하는 오탐(false positive) 테스트가 발생할 수 있습니다. 어설션이 실제로 호출되었는지 확인하려면expect.assertions(number)
를 사용해야 합니다.
expect.assertions
타입:
(count: number) => void
테스트가 완료된 후, 테스트 중에 특정 횟수의 어설션이 호출되었는지 확인합니다. 비동기 코드의 어설션 실행 여부를 확인할 때 유용합니다.
예를 들어 두 개의 매처를 비동기적으로 호출하는 함수가 있는 경우, 실제로 호출되었는지 어설션할 수 있습니다.
tsimport { expect, test } from 'vitest'; async function doAsync(...cbs) { await Promise.all(cbs.map((cb, index) => cb({ index }))); } test('모든 어설션이 호출됩니다', async () => { expect.assertions(2); function callback1(data) { expect(data).toBeTruthy(); } function callback2(data) { expect(data).toBeTruthy(); } await doAsync(callback1, callback2); });
WARNING
비동기 동시 테스트와 함께
assertions
를 사용하는 경우, 올바른 테스트가 감지되도록 로컬 테스트 컨텍스트의expect
를 사용해야 합니다.
expect.hasAssertions
타입:
() => void
테스트가 완료된 후, 테스트 중에 최소 하나의 어설션이 호출되었는지 확인합니다. 비동기 코드의 어설션 실행 여부를 확인할 때 유용합니다.
예를 들어 콜백을 호출하는 코드가 있는 경우, 콜백 내에서 어설션을 만들 수 있지만 어설션이 호출되었는지 확인하지 않으면 테스트가 항상 통과합니다.
tsimport { expect, test } from 'vitest'; import { db } from './db.js'; const cbs = []; function onSelect(cb) { cbs.push(cb); } // db에서 선택한 후 모든 콜백을 호출합니다. function select(id) { return db.select({ id }).then(data => { return Promise.all(cbs.map(cb => cb(data))); }); } test('콜백이 호출되었습니다', async () => { expect.hasAssertions(); onSelect(data => { // 선택 시 호출되어야 합니다. expect(data).toBeTruthy(); }); // 기다리지 않으면 테스트가 실패합니다. // expect.hasAssertions()가 없으면 테스트가 통과합니다. await select(3); });
expect.unreachable
타입:
(message?: string) => never
이 메서드는 특정 코드 줄이 실행되지 않아야 함을 나타낼 때 사용됩니다.
예를 들어
build()
함수가src
폴더가 없는 디렉터리를 인수로 받아 예외를 발생시키는지 테스트하고, 각 오류를 개별적으로 처리하려는 경우 다음과 같이 할 수 있습니다.tsimport { expect, test } from 'vitest'; async function build(dir) { if (dir.includes('no-src')) throw new Error(`${dir}/src가 존재하지 않습니다`); } const errorDirs = [ 'no-src-folder', // ... ]; test.each(errorDirs)('build가 "%s"로 실패합니다', async dir => { try { await build(dir); expect.unreachable('빌드를 통과해서는 안 됩니다'); } catch (err: any) { expect(err).toBeInstanceOf(Error); expect(err.stack).toContain('build'); switch (dir) { case 'no-src-folder': expect(err.message).toBe(`${dir}/src가 존재하지 않습니다`); break; default: // 모든 오류 케이스를 처리하기 위해 expect.unreachable('모든 오류 테스트를 처리해야 합니다'); break; } } });
expect.anything
타입:
() => any
이 비대칭 매처는 값 비교 시 항상
true
를 반환합니다. 속성의 존재 여부만 확인할 때 유용합니다.tsimport { expect, test } from 'vitest'; test('객체에 "apples" 키가 있습니다', () => { expect({ apples: 22 }).toEqual({ apples: expect.anything() }); });
expect.any
타입:
(constructor: unknown) => any
이 비대칭 매처는 값 비교 시 값이 지정된 생성자의 인스턴스인 경우에만
true
를 반환합니다. 매번 값이 생성될 때, 해당 값이 올바른 타입인지 확인할 때 유용합니다.tsimport { expect, test } from 'vitest'; import { generateId } from './generators.js'; test('"id"는 숫자입니다', () => { expect({ id: generateId() }).toEqual({ id: expect.any(Number) }); });
expect.arrayContaining
타입:
<T>(expected: T[]) => any
이 비대칭 매처는 값 비교 시 값이 배열이고 지정된 항목을 포함하는 경우
true
를 반환합니다.tsimport { expect, test } from 'vitest'; test('바구니에 후지(Fuji)가 포함되어 있습니다', () => { const basket = { varieties: ['Empire', 'Fuji', 'Gala'], count: 3, }; expect(basket).toEqual({ count: 3, varieties: expect.arrayContaining(['Fuji']), }); });
TIP
expect.not
과 함께 사용하면 예상 값을 반대로 검증할 수 있습니다.
expect.objectContaining
타입:
(expected: any) => any
이 비대칭 매처는 값 비교 시 값이 지정된 속성을 포함하는 객체인 경우
true
를 반환합니다.tsimport { expect, test } from 'vitest'; test('바구니에 엠파이어(Empire) 사과가 있습니다', () => { const basket = { varieties: [ { name: 'Empire', count: 1, }, ], }; expect(basket).toEqual({ varieties: [expect.objectContaining({ name: 'Empire' })], }); });
TIP
expect.not
과 함께 사용하면 예상 값을 반대로 검증할 수 있습니다.
expect.stringContaining
타입:
(expected: any) => any
이 비대칭 매처는 값 비교 시 값이 문자열이고 지정된 하위 문자열을 포함하는 경우
true
를 반환합니다.tsimport { expect, test } from 'vitest'; test('사과 품종 이름에 "Emp"가 있습니다', () => { const variety = { name: 'Empire', count: 1, }; expect(variety).toEqual({ name: expect.stringContaining('Emp'), count: 1, }); });
TIP
expect.not
과 함께 사용하면 예상 값을 반대로 검증할 수 있습니다.
expect.stringMatching
타입:
(expected: any) => any
이 비대칭 매처는 값 비교 시 값이 문자열이고 지정된 하위 문자열을 포함하거나 문자열이 정규식과 일치하는 경우
true
를 반환합니다.tsimport { expect, test } from 'vitest'; test('사과 품종이 "re"로 끝납니다', () => { const variety = { name: 'Empire', count: 1, }; expect(variety).toEqual({ name: expect.stringMatching(/re$/), count: 1, }); });
TIP
expect.not
과 함께 사용하면 예상 값을 반대로 검증할 수 있습니다.
expect.addSnapshotSerializer
타입:
(plugin: PrettyFormatPlugin) => void
이 메서드는 스냅샷을 생성할 때 호출되는 사용자 지정 직렬 변환기를 추가합니다. 이는 고급 사용자를 위한 기능입니다. 자세한 내용은 사용자 지정 직렬 변환기 가이드를 참조하십시오.
커스텀 직렬 변환기를 추가하려면
setupFiles
내에서 이 메서드를 호출해야 합니다. 이는 모든 스냅샷에 적용됩니다.TIP
이전에 Jest와 함께 Vue CLI를 사용한 경우 jest-serializer-vue를 설치하는 것이 좋습니다. 그렇지 않으면 스냅샷이 문자열로 래핑되어
"
가 이스케이프 처리될 수 있습니다.
expect.extend
타입:
(matchers: MatchersObject) => void
기본 매처를 직접 확장할 수 있습니다. 이 함수는 사용자 지정 매처를 정의하여 매처 객체를 확장하는 데 사용됩니다.
이러한 방식으로 매처를 정의하면
expect.stringContaining
처럼 사용할 수 있는 비대칭 매처 또한 생성됩니다.tsimport { expect, test } from 'vitest'; test('사용자 지정 매처', () => { expect.extend({ toBeFoo: (received, expected) => { if (received !== 'foo') { return { message: () => `expected ${received} to be foo`, pass: false, }; } }, }); expect('foo').toBeFoo(); expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() }); });
TIP
매처가 모든 테스트에 나타나도록 하려면
setupFiles
내에서 이 메서드를 호출해야 합니다.이 함수는 Jest의
expect.extend
와 호환되므로, 사용자 지정 매처를 만드는 데 사용하는 모든 라이브러리가 Vitest와 함께 작동합니다.TypeScript를 사용하는 경우, Vitest 0.31.0부터 다음 코드를 사용하여 앰비언트 선언 파일(예:
vitest.d.ts
)에서 기본Assertion
인터페이스를 확장할 수 있습니다.tsinterface CustomMatchers<R = unknown> { toBeFoo(): R; } declare module 'vitest' { interface Assertion<T = any> extends CustomMatchers<T> {} interface AsymmetricMatchersContaining extends CustomMatchers {} }
WARNING
앰비언트 선언 파일 포함을 잊지 마세요.
TIP
자세한 내용은 매처 확장 가이드를 참조하십시오.