> For the complete documentation index, see [llms.txt](https://javascriptuse.gitbook.io/javascript/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://javascriptuse.gitbook.io/javascript/gioi-thieu-ve-jest-delightful-javascript-testing.md).

# Giới thiệu về Jest (Delightful JavaScript Testing)

#### Giới thiệu chung về jest. <a href="#gioi-thieu-chung-ve-jest-0" id="gioi-thieu-chung-ve-jest-0"></a>

![](https://viblo.asia/uploads/ab3c10a8-864a-41cd-802d-d65b068cc1b7.png)

* Jest là một thư viện testing được tạo bởi facebook.
* Nó được tạo ra với mục tiêu ban đầu là cho reactjs, nhưng nó đã vượt xa những nhu cầu ban đầu, để trở thành một thư viện testing cho javascript một cách hoàn chỉnh.
* Một trong nhưng ưu điểm lớn của jest là nó làm việc hiệu quả với rất ít bước setup và configuration. Nó đến với các tính năng chính là assertion library và hỗ trợ mocking.
* Nó được viết theo BDD style như hầu hết các thư viện testing hiện nay. Jest còn có một tính năng đặc biệt, đó là [snapshot testing](https://facebook.github.io/jest/docs/snapshot-testing.html#content), nó lưu lại snapshot (hay nói cách khác là cấu trúc view tại thời điểm hiện tại) rồi so sánh với snapshot trong tương lai, nếu chúng không giống nhau thì test của chúng ta đã fail hoặc có một số thứ đã thay đổi.
* Jest có một số nhược điểm quan trọng như: nó là một thư viện mới, vẫn chưa được dùng nhiều bởi cộng đồng developer. Nó có ít tool và thư viện support so với các thư viện cũ và lão làng như [Mocha](https://mochajs.org/).

#### Overview các tính năng của jest. <a href="#overview-cac-tinh-nang-cua-jest-1" id="overview-cac-tinh-nang-cua-jest-1"></a>

1. Using Matchers

```
test('two plus two is four', () => {
  expect(2 + 2).toBe(4);
});
```

```
test('object assignment', () => {
  const data = {one: 1};
  data['two'] = 2;
  expect(data).toEqual({one: 1, two: 2});
});
```

1. Test Truthiness (kiểm tra tính đúng đắn)

```
test('null', () => {
  const n = null;
  expect(n).toBeNull();
  expect(n).toBeDefined();
  expect(n).not.toBeUndefined();
  expect(n).not.toBeTruthy();
  expect(n).toBeFalsy();
});

test('zero', () => {
  const z = 0;
  expect(z).not.toBeNull();
  expect(z).toBeDefined();
  expect(z).not.toBeUndefined();
  expect(z).not.toBeTruthy();
  expect(z).toBeFalsy();
});
```

1. Number:

```
test('two plus two', () => {
  const value = 2 + 2;
  expect(value).toBeGreaterThan(3);
  expect(value).toBeGreaterThanOrEqual(3.5);
  expect(value).toBeLessThan(5);
  expect(value).toBeLessThanOrEqual(4.5);

  // toBe and toEqual are equivalent for numbers
  expect(value).toBe(4);
  expect(value).toEqual(4);
});
```

1. String:

```
test('there is no I in team', () => {
  expect('team').not.toMatch(/I/);
});

test('but there is a "stop" in Christoph', () => {
  expect('Christoph').toMatch(/stop/);
});
```

1. Array:

```
const shoppingList = [
  'diapers',
  'kleenex', 
  'trash bags', 
  'paper towels', 
  'beer',
];

test('the shopping list has beer on it', () => {
  expect(shoppingList).toContain('beer');
});
```

1. Exception:

```
function compileAndroidCode() {
  throw new ConfigError('you are using the wrong JDK');
}

test('compiling android goes as expected', () => {
  expect(compileAndroidCode).toThrow();
  expect(compileAndroidCode).toThrow(ConfigError);

  // You can also use the exact error message or a regexp
  expect(compileAndroidCode).toThrow('you are using the wrong JDK');
  expect(compileAndroidCode).toThrow(/JDK/);
});
```

1. Callbacks

```
test('the data is peanut butter', done => {
  function callback(data) {
    expect(data).toBe('peanut butter');
    done();
  }

  fetchData(callback);
});
```

1. Promise:

```
test('the data is peanut butter', () => {
  expect.assertions(1);
  return fetchData().then(data => {
    expect(data).toBe('peanut butter');
  });
});
```

1. Async/Await

```
test('the data is peanut butter', async () => {
  expect.assertions(1);
  const data = await fetchData();
  expect(data).toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
  expect.assertions(1);
  try {
    await fetchData();
  } catch (e) {
    expect(e).toMatch('error');
  }
});
```

1. Setup cho nhiều test:

```
beforeEach(() => {
  initializeCityDatabase();
});

afterEach(() => {
  clearCityDatabase();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});
```

1. Setup một lần (bắt đầu hoặc kết thúc):

```
beforeAll(() => {
  return initializeCityDatabase();
});

afterAll(() => {
  return clearCityDatabase();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});
```

1. Nhóm test lại (describe):

```
// Applies to all tests in this file
beforeEach(() => {
  return initializeCityDatabase();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});

describe('matching cities to foods', () => {
  // Applies only to tests in this describe block
  beforeEach(() => {
    return initializeFoodDatabase();
  });

  test('Vienna <3 sausage', () => {
    expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
  });

  test('San Juan <3 plantains', () => {
    expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
  });
});
```

1. Dùng mock function:

```
function forEach(items, callback) {
  for (let index = 0; index < items.length; index++) {
    callback(items[index]);
  }
}
const mockCallback = jest.fn();
forEach([0, 1], mockCallback);

// The mock function is called twice
expect(mockCallback.mock.calls.length).toBe(2);

// The first argument of the first call to the function was 0
expect(mockCallback.mock.calls[0][0]).toBe(0);

// The first argument of the second call to the function was 1
expect(mockCallback.mock.calls[1][0]).toBe(1);
```

1. Mock return value (define giá trị trả lại của function)

```
const myMock = jest.fn();
console.log(myMock());
// > undefined

myMock.mockReturnValueOnce(10)
 .mockReturnValueOnce('x')
 .mockReturnValue(true);

console.log(myMock(), myMock(), myMock(), myMock());
// > 10, 'x', true, true
```

1. Custom Matchers

```
// The mock function was called at least once
expect(mockFunc).toBeCalled();

// The mock function was called at least once with the specified args
expect(mockFunc).toBeCalledWith(arg1, arg2);

// The last call to the mock function was called with the specified args
expect(mockFunc).lastCalledWith(arg1, arg2);
```

Dùng thuộc tính .mock để inspect nhiều xác định hơn:

```
// The mock function was called at least once
expect(mockFunc.mock.calls.length).toBeGreaterThan(0);

// The mock function was called at least once with the specified args
expect(mockFunc.mock.calls).toContain([arg1, arg2]);

// The last call to the mock function was called with the specified args
expect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1]).toEqual(
  [arg1, arg2]
);

// The first arg of the last call to the mock function was `42`
// (note that there is no sugar helper for this specific of an assertion)
expect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1][0]).toBe(42);
```

1. Mock Implementations: Hơn cả chức năng trả lại, nó còn thay thế toàn bộ hàm mocking:

```
const myMockFn = jest.fn(() => 'default')
  .mockImplementationOnce(() => 'first call')
  .mockImplementationOnce(() => 'second call');

console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
// > 'first call', 'second call', 'default', 'default'
```

1. Testing snapshot:

```
it('renders a snapshot', () => {
  const tree = renderer.create(<App/>).toJSON();
  expect(tree).toMatchSnapshot();
});
```

**renderer.create** create ra view và chuyển view này thành json, toMatchSnapshot() sẽ so sánh cấu trúc hiện tại với snapshot lần cuối, nếu chưa có thì nó sẽ tạo cái mới và cho test này pass. Snapshot file sẽ chứa output như:

```
exports[`test renders a snapshot 1`] = `
<div
  className="App">
  <div
    className="App-header">
    <img
      alt="logo"
      className="App-logo"
      src="test-file-stub" />
    <h2>
      Welcome to React
    </h2>
  </div>
  <p
    className="App-intro">
    To get started, edit
    <code>
      src/App.js
    </code>
     and save to reload.
  </p>
</div>
`;
```

![](https://viblo.asia/uploads/a308d999-bdcc-4691-865a-ee67ffd7a93d.png) Trên đây là một số giới thiệu cho cái nhìn tổng quan về jest, hy vọng mọi người có thể trải nghiệm và vận dụng được nó ![😃](https://twemoji.maxcdn.com/2/72x72/1f603.png)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://javascriptuse.gitbook.io/javascript/gioi-thieu-ve-jest-delightful-javascript-testing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
