{"id":24559568,"url":"https://github.com/dvbtham/monthly-reports","last_synced_at":"2026-02-11T00:38:27.495Z","repository":{"id":158626044,"uuid":"265654396","full_name":"dvbtham/monthly-reports","owner":"dvbtham","description":null,"archived":false,"fork":false,"pushed_at":"2020-05-20T19:14:40.000Z","size":173,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-07-31T11:31:47.404Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dvbtham.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-20T18:33:10.000Z","updated_at":"2022-10-08T13:01:22.000Z","dependencies_parsed_at":"2023-08-23T04:46:51.800Z","dependency_job_id":null,"html_url":"https://github.com/dvbtham/monthly-reports","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dvbtham/monthly-reports","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvbtham%2Fmonthly-reports","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvbtham%2Fmonthly-reports/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvbtham%2Fmonthly-reports/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvbtham%2Fmonthly-reports/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dvbtham","download_url":"https://codeload.github.com/dvbtham/monthly-reports/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvbtham%2Fmonthly-reports/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272192669,"owners_count":24889452,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-26T02:00:07.904Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-23T06:17:03.220Z","updated_at":"2026-02-11T00:38:22.438Z","avatar_url":"https://github.com/dvbtham.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Test ứng dụng javascript với Jest Framework\n## Jest là gì?\nJest là một JS framework khá thú vị và đơn giản được dùng để viết unit testing. Nó có thể làm việc tốt trên: React, Angular, Vue, Javascipt, Typescript\n## Jest có gì hay ho?\nJest là một thư viện testing được tạo bởi facebook và được các công ty lớn như Twitter, Instagram, Spotify,... sử dụng. Nó có các ưu điểm sau:\n- Nhanh, tối ưu\n- Cấu hình đơn giản\n- Tuỳ chọn Code coverage \n- Mocking dễ dàng\n- Hỗ trợ snapshots\n- Document chi tiết, dễ hiểu\n## Cài Jest về máy\nTôi tạo một thư mục mới và chạy `npm init` (cài node tại đây: https://nodejs.org/en/ nếu trên máy bạn chưa cài) \n- Dùng `npm`: `npm install --save-dev jest`\n- hoặc `yarn`: `yarn add --dev jest` để cài jest về máy. Vậy là bạn đã xong phần chuẩn bị rồi đấy\n## Viết test case đơn giản\nTôi sẽ viết test case đơn giản cho việc công 2 số với nhau, tôi tạo mới file `app.js` chưa đoạn code thực hiện việc tính toán như sau:\n```javascript\nfunction sum(a, b) {\n  return a + b;\n}\nmodule.exports = sum;\n```\nSau đó, tạo file `app.test.js`, chưa các đoạn code test case\n```javascript\nconst sum = require('./app');\n\ntest('adds 1 + 2 to equal 3', () =\u003e {\n  expect(sum(1, 2)).toBe(3);\n});\n```\nThêm đọan sau để set lệnh chạy test\n```js\n{\n  \"scripts\": {\n    \"test\": \"jest\"\n  }\n}\n```\nCuối cùng, trên terminal, bạn chạy lệnh `yarn test` hoặc `npm run test`. Trên console sẽ in ra màn hình như sau nếu thành công:\n```\nPASS  ./app.test.js\n✓ adds 1 + 2 to equal 3 (5ms)\n```\n## Các tính năng khác\nTrên đây là 1 ví dụ cơ bản và test case đơn giản, để thực hiện test các test case phức tạp hơn thì dưới đây là các tính năng của Jest:\n\n- Using Matchers\n```javascript\ntest('two plus two is four', () =\u003e {\n  expect(2 + 2).toBe(4);\n});\ntest('object assignment', () =\u003e {\n  const data = {one: 1};\n  data['two'] = 2;\n  expect(data).toEqual({one: 1, two: 2});\n});\n```\n- Test Truthiness (kiểm tra tính đúng đắn)\n```javascript\ntest('null', () =\u003e {\n  const n = null;\n  expect(n).toBeNull();\n  expect(n).toBeDefined();\n  expect(n).not.toBeUndefined();\n  expect(n).not.toBeTruthy();\n  expect(n).toBeFalsy();\n});\n\ntest('zero', () =\u003e {\n  const z = 0;\n  expect(z).not.toBeNull();\n  expect(z).toBeDefined();\n  expect(z).not.toBeUndefined();\n  expect(z).not.toBeTruthy();\n  expect(z).toBeFalsy();\n});\n```\n- Number:\n```javascript\ntest('two plus two', () =\u003e {\n  const value = 2 + 2;\n  expect(value).toBeGreaterThan(3);\n  expect(value).toBeGreaterThanOrEqual(3.5);\n  expect(value).toBeLessThan(5);\n  expect(value).toBeLessThanOrEqual(4.5);\n\n  // toBe and toEqual are equivalent for numbers\n  expect(value).toBe(4);\n  expect(value).toEqual(4);\n});\n```\n- String:\n```javascript\ntest('there is no I in team', () =\u003e {\n  expect('team').not.toMatch(/I/);\n});\n\ntest('but there is a \"stop\" in Christoph', () =\u003e {\n  expect('Christoph').toMatch(/stop/);\n});\n```\n- Array:\n```javascript\nconst shoppingList = [\n  'diapers',\n  'kleenex', \n  'trash bags', \n  'paper towels', \n  'beer',\n];\n\ntest('the shopping list has beer on it', () =\u003e {\n  expect(shoppingList).toContain('beer');\n});\n```\n- Exception:\n```javascript\nfunction compileAndroidCode() {\n  throw new ConfigError('you are using the wrong JDK');\n}\n\ntest('compiling android goes as expected', () =\u003e {\n  expect(compileAndroidCode).toThrow();\n  expect(compileAndroidCode).toThrow(ConfigError);\n\n  // You can also use the exact error message or a regexp\n  expect(compileAndroidCode).toThrow('you are using the wrong JDK');\n  expect(compileAndroidCode).toThrow(/JDK/);\n});\n```\n- Callbacks\n```javascript\ntest('the data is peanut butter', done =\u003e {\n  function callback(data) {\n    expect(data).toBe('peanut butter');\n    done();\n  }\n\n  fetchData(callback);\n});\n- Promise:\ntest('the data is peanut butter', () =\u003e {\n  expect.assertions(1);\n  return fetchData().then(data =\u003e {\n    expect(data).toBe('peanut butter');\n  });\n});\n```\n- Async/Await\n```javascript\ntest('the data is peanut butter', async () =\u003e {\n  expect.assertions(1);\n  const data = await fetchData();\n  expect(data).toBe('peanut butter');\n});\n\ntest('the fetch fails with an error', async () =\u003e {\n  expect.assertions(1);\n  try {\n    await fetchData();\n  } catch (e) {\n    expect(e).toMatch('error');\n  }\n});\n```\n- Setup cho nhiều test:\n```javascript\nbeforeEach(() =\u003e {\n  initializeCityDatabase();\n});\n\nafterEach(() =\u003e {\n  clearCityDatabase();\n});\n\ntest('city database has Vienna', () =\u003e {\n  expect(isCity('Vienna')).toBeTruthy();\n});\n\ntest('city database has San Juan', () =\u003e {\n  expect(isCity('San Juan')).toBeTruthy();\n});\n```\n- Setup một lần (bắt đầu hoặc kết thúc):\n```javascript\nbeforeAll(() =\u003e {\n  return initializeCityDatabase();\n});\n\nafterAll(() =\u003e {\n  return clearCityDatabase();\n});\n\ntest('city database has Vienna', () =\u003e {\n  expect(isCity('Vienna')).toBeTruthy();\n});\n\ntest('city database has San Juan', () =\u003e {\n  expect(isCity('San Juan')).toBeTruthy();\n});\n```\n- Nhóm test lại (describe):\n```javascript\n// Applies to all tests in this file\nbeforeEach(() =\u003e {\n  return initializeCityDatabase();\n});\n\ntest('city database has Vienna', () =\u003e {\n  expect(isCity('Vienna')).toBeTruthy();\n});\n\ntest('city database has San Juan', () =\u003e {\n  expect(isCity('San Juan')).toBeTruthy();\n});\n\ndescribe('matching cities to foods', () =\u003e {\n  // Applies only to tests in this describe block\n  beforeEach(() =\u003e {\n    return initializeFoodDatabase();\n  });\n\n  test('Vienna \u003c3 sausage', () =\u003e {\n    expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);\n  });\n\n  test('San Juan \u003c3 plantains', () =\u003e {\n    expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);\n  });\n});\n```\n- Dùng mock function:\n```javascript\nfunction forEach(items, callback) {\n  for (let index = 0; index \u003c items.length; index++) {\n    callback(items[index]);\n  }\n}\nconst mockCallback = jest.fn();\nforEach([0, 1], mockCallback);\n\n// The mock function is called twice\nexpect(mockCallback.mock.calls.length).toBe(2);\n\n// The first argument of the first call to the function was 0\nexpect(mockCallback.mock.calls[0][0]).toBe(0);\n\n// The first argument of the second call to the function was 1\nexpect(mockCallback.mock.calls[1][0]).toBe(1);\n```\n- Mock return value (define giá trị trả lại của function)\n```javascript\nconst myMock = jest.fn();\nconsole.log(myMock());\n// \u003e undefined\n\nmyMock.mockReturnValueOnce(10)\n .mockReturnValueOnce('x')\n .mockReturnValue(true);\n\nconsole.log(myMock(), myMock(), myMock(), myMock());\n// \u003e 10, 'x', true, true\n```\n- Custom Matchers\n```javascript\n// The mock function was called at least once\nexpect(mockFunc).toBeCalled();\n\n// The mock function was called at least once with the specified args\nexpect(mockFunc).toBeCalledWith(arg1, arg2);\n\n// The last call to the mock function was called with the specified args\nexpect(mockFunc).lastCalledWith(arg1, arg2);\n```\n- Dùng thuộc tính .mock để inspect nhiều xác định hơn:\n```javascript\n// The mock function was called at least once\nexpect(mockFunc.mock.calls.length).toBeGreaterThan(0);\n\n// The mock function was called at least once with the specified args\nexpect(mockFunc.mock.calls).toContain([arg1, arg2]);\n\n// The last call to the mock function was called with the specified args\nexpect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1]).toEqual(\n  [arg1, arg2]\n);\n\n// The first arg of the last call to the mock function was `42`\n// (note that there is no sugar helper for this specific of an assertion)\nexpect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1][0]).toBe(42);\n```\n- Mock Implementations: Hơn cả chức năng trả lại, nó còn thay thế toàn bộ hàm mocking:\n```javascript\nconst myMockFn = jest.fn(() =\u003e 'default')\n  .mockImplementationOnce(() =\u003e 'first call')\n  .mockImplementationOnce(() =\u003e 'second call');\n\nconsole.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());\n\n// \u003e 'first call', 'second call', 'default', 'default'\n```\n- Testing snapshot:\n```javascript\nit('renders a snapshot', () =\u003e {\n  const tree = renderer.create(\u003cApp/\u003e).toJSON();\n  expect(tree).toMatchSnapshot();\n});\n```\n## Kết luận\nTrên đây là các tính năng và ví dụ đơn giản về Jest mà tôi muốn giới thiệu với các bạn. Hy vọng các bạn đã đọc được bài viết bổ ích.\nXin cảm ơn.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdvbtham%2Fmonthly-reports","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdvbtham%2Fmonthly-reports","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdvbtham%2Fmonthly-reports/lists"}