[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-2993":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":19,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":22,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":45,"readmeContent":46,"aiSummary":47,"trendingCount":16,"starSnapshotCount":16,"syncStatus":48,"lastSyncTime":49,"discoverSource":50},2993,"javascript-testing-best-practices","goldbergyoni\u002Fjavascript-testing-best-practices","goldbergyoni","📗🌐 🚢 Comprehensive and exhaustive JavaScript & Node.js testing best practices (August 2025)","https:\u002F\u002Ftestjavascript.com\u002F",null,"JavaScript",24595,2100,309,51,0,5,15,1,44.97,"MIT License",false,"master",true,[26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44],"angular","chai","ci","cicd","contract-testing","e2e","e2e-tests","express","integration-testing","javascript","jest","mocha","mutation","mutation-testing","nodejs","react","test","testing","unittest","2026-06-12 02:00:45","\u003Cimg src=\"\u002Fassets\u002Fjtbp-header-blue.png\" width=\"1920px\"\u002F>\n\n\n\u003Cbr\u002F>\n\n# 👇 Why this guide can take your testing skills to the next level\n\n\u003Cbr\u002F>\n\n## 📗 50+ best practices: Super-comprehensive and exhaustive\n\nThis is a guide for JavaScript & Node.js reliability from A-Z. It summarizes and curates for you dozens of the best blog posts, books, and tools the market has to offer\n\n## 🚢 Advanced: Goes 10,000 miles beyond the basics\n\nHop into a journey that travels way beyond the basics into advanced topics like testing in production, mutation testing, property-based testing, and many other strategic & professional tools. Should you read every word in this guide your testing skills are likely to go way above the average\n\n## 🌐 Full-stack: front, backend, CI, anything\n\nStart by understanding the ubiquitous testing practices that are the foundation for any application tier. Then, delve into your area of choice: frontend\u002FUI, backend, CI, or maybe all of them?\n\n\u003Cbr\u002F>\n\n### Written By Yoni Goldberg - A JavaScript & Node.js consultant\n\n### 👨‍🏫 Exciting news: I've just released my super-comprehensive testing course after two years of recording and editing. [Less than 48 hours left for the 🎁 special launch deal](https:\u002F\u002Ftestjavascript.com\u002F)\n\n\u003Cbr\u002F>\n\n### Translations - read in your own language\n\n- 🇨🇳[Chinese](readme-zh-CN.md) - Courtesy of [Yves yao](https:\u002F\u002Fgithub.com\u002Fyvesyao)\n- 🇰🇷[Korean](readme.kr.md) - Courtesy of [Rain Byun](https:\u002F\u002Fgithub.com\u002Fragubyun)\n- 🇵🇱[Polish](readme-pl.md) - Courtesy of [Michal Biesiada](https:\u002F\u002Fgithub.com\u002Fmbiesiad)\n- 🇪🇸[Spanish](readme-es.md) - Courtesy of [Miguel G. Sanguino](https:\u002F\u002Fgithub.com\u002Fsanguino)\n- 🇧🇷[Portuguese-BR](readme-pt-br.md) - Courtesy of [Iago Angelim Costa Cavalcante](https:\u002F\u002Fgithub.com\u002Fiagocavalcante) , [Douglas Mariano Valero](https:\u002F\u002Fgithub.com\u002FDouglasMV) and [koooge](https:\u002F\u002Fgithub.com\u002Fkoooge)\n- 🇫🇷[French](readme-fr.md) - Courtesy of [Mathilde El Mouktafi](https:\u002F\u002Fgithub.com\u002Fmel-mouk)\n- 🇯🇵[Japanese (draft)](https:\u002F\u002Fgithub.com\u002Fyuichkun\u002Fjavascript-testing-best-practices\u002Fblob\u002Fmaster\u002Freadme-jp.md) - Courtesy of [Yuichi Yogo](https:\u002F\u002Fgithub.com\u002Fyuichkun) and [ryo](https:\u002F\u002Fgithub.com\u002Fkawamataryo)\n- 🇹🇼[Traditional Chinese](readme-zh-TW.md) - Courtesy of [Yubin Hsu](https:\u002F\u002Fgithub.com\u002FyubinTW)\n- 🇺🇦[Ukrainian](readme-ua.md) - Courtesy of [Serhii Shramko](https:\u002F\u002Fgithub.com\u002FShramkoweb)\n- 🇮🇷[Persian](readme-pr-fr.md) - Courtesy of [Ali Azmoodeh](https:\u002F\u002Fgithub.com\u002FTREER00T)\n- 🇷🇺[Russian](readme-ru.md) - Courtesy of [Alex Popov](https:\u002F\u002Fgithub.com\u002FSaimon398)\n\n- Want to translate to your own language? please open an issue 💜\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## `Table of Contents`\n\n#### [`Section 0: The Golden Rule`](#section-0️⃣-the-golden-rule)\n\nA single advice that inspires all the others (1 special bullet)\n\n#### [`Section 1: The Test Anatomy`](#section-1-the-test-anatomy-1)\n\nThe foundation - structuring clean tests (12 bullets)\n\n#### [`Section 2: Backend`](#section-2️⃣-backend-testing)\n\nWriting backend and Microservices tests efficiently (13 bullets)\n\n#### [`Section 3: Frontend`](#section-3️⃣-frontend-testing)\n\nWriting tests for web UI including component and E2E tests (11 bullets)\n\n#### [`Section 4: Measuring Tests Effectiveness`](#section-4️⃣-measuring-test-effectiveness)\n\nWatching the watchman - measuring test quality (4 bullets)\n\n#### [`Section 5: Continuous Integration`](#section-5️⃣-ci-and-other-quality-measures)\n\nGuidelines for CI in the JS world (9 bullets)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n# Section 0️⃣: The Golden Rule\n\n\u003Cbr\u002F>\n\n## ⚪️ 0 The Golden Rule: Design for lean testing\n\n:white_check_mark: **Do:**\nTesting code is not production-code - Design it to be short, dead-simple, flat, and delightful to work with. One should look at a test and get the intent instantly.\n\nSee, our minds are already occupied with our main job - the production code. There is no 'headspace' for additional complexity. Should we try to squeeze yet another sus-system into our poor brain it will slow the team down which works against the reason we do testing. Practically this is where many teams just abandon testing.\n\nThe tests are an opportunity for something else - a friendly assistant, co-pilot, that delivers great value for a small investment. Science tells us that we have two brain systems: system 1 is used for effortless activities like driving a car on an empty road and system 2 is meant for complex and conscious operations like solving a math equation. Design your test for system 1, when looking at test code it should _feel_ as easy as modifying an HTML document and not like solving 2X(17 × 24).\n\nThis can be achieved by selectively cherry-picking techniques, tools, and test targets that are cost-effective and provide great ROI. Test only as much as needed, and strive to keep it nimble, sometimes it's even worth dropping some tests and trading reliability for agility and simplicity.\n\n![alt text](\u002Fassets\u002Fheadspace.png \"We have no head room for additional complexity\")\n\nMost of the advice below are derivatives of this principle.\n\n### Ready to start?\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n# Section 1: The Test Anatomy\n\n\u003Cbr\u002F>\n\n## ⚪ ️ 1.1 Include 3 parts in each test name\n\n:white_check_mark: **Do:** A test report should tell whether the current application revision satisfies the requirements for the people who are not necessarily familiar with the code: the tester, the DevOps engineer who is deploying and the future you two years from now. This can be achieved best if the tests speak at the requirements level and include 3 parts:\n\n(1) What is being tested? For example, the ProductsService.addNewProduct method\n\n(2) Under what circumstances and scenario? For example, no price is passed to the method\n\n(3) What is the expected result? For example, the new product is not approved\n\n\u003Cbr\u002F>\n\n❌ **Otherwise:** A deployment just failed, a test named “Add product” failed. Does this tell you what exactly is malfunctioning?\n\n\u003Cbr\u002F>\n\n**👇 Note:** Each bullet has code examples and sometime also an image illustration. Click to expand\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n  \n\u003Cbr\u002F>\n  \n### :clap: Doing It Right Example: A test name that constitutes 3 parts\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔨%20Example%20using%20Mocha-blue.svg \"Using Mocha to illustrate the idea\")\n\n```javascript\n\u002F\u002F1. unit under test\ndescribe('Products Service', function() {\n  describe('Add new product', function() {\n    \u002F\u002F2. scenario and 3. expectation\n    it('When no price is specified, then the product status is pending approval', ()=> {\n      const newProduct = new ProductService().add(...);\n      expect(newProduct.status).to.equal('pendingApproval');\n    });\n  });\n});\n\n```\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: A test name that constitutes 3 parts\n\n![alt text](\u002Fassets\u002Fbp-1-3-parts.jpeg \"A test name that constitutes 3 parts\")\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\n\u003Cdetails>\u003Csummary>© \u003Cb>Credits & read-more\u003C\u002Fb>\u003C\u002Fsummary>\n  1. \u003Ca href='https:\u002F\u002Fosherove.com\u002Fblog\u002F2005\u002F4\u002F3\u002Fnaming-standards-for-unit-tests.html'>Roy Osherove - Naming standards for unit tests\u003C\u002Fa>\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️ 1.2 Structure tests by the AAA pattern\n\n:white_check_mark: **Do:** Structure your tests with 3 well-separated sections Arrange, Act & Assert (AAA). Following this structure guarantees that the reader spends no brain-CPU on understanding the test plan:\n\n1st A - Arrange: All the setup code to bring the system to the scenario the test aims to simulate. This might include instantiating the unit under test constructor, adding DB records, mocking\u002Fstubbing on objects, and any other preparation code\n\n2nd A - Act: Execute the unit under test. Usually 1 line of code\n\n3rd A - Assert: Ensure that the received value satisfies the expectation. Usually 1 line of code\n\n\u003Cbr\u002F>\n\n❌ **Otherwise:** Not only do you spend hours understanding the main code but what should have been the simplest part of the day (testing) stretches your brain\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: A test structured with the AAA pattern\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Jest-blue.svg \"Examples with Jest\") ![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Mocha-blue.svg \"Examples with Mocha\")\n\n```javascript\ndescribe(\"Customer classifier\", () => {\n  test(\"When customer spent more than 500$, should be classified as premium\", () => {\n    \u002F\u002FArrange\n    const customerToClassify = { spent: 505, joined: new Date(), id: 1 };\n    const DBStub = sinon.stub(dataAccess, \"getCustomer\").reply({ id: 1, classification: \"regular\" });\n\n    \u002F\u002FAct\n    const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);\n\n    \u002F\u002FAssert\n    expect(receivedClassification).toMatch(\"premium\");\n  });\n});\n```\n\n\u003Cbr\u002F>\n\n### :thumbsdown: Anti-Pattern Example: No separation, one bulk, harder to interpret\n\n```javascript\ntest(\"Should be classified as premium\", () => {\n  const customerToClassify = { spent: 505, joined: new Date(), id: 1 };\n  const DBStub = sinon.stub(dataAccess, \"getCustomer\").reply({ id: 1, classification: \"regular\" });\n  const receivedClassification = customerClassifier.classifyCustomer(customerToClassify);\n  expect(receivedClassification).toMatch(\"premium\");\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️1.3 Describe expectations in a product language: use BDD-style assertions\n\n:white_check_mark: **Do:** Coding your tests in a declarative-style allows the reader to get the grab instantly without spending even a single brain-CPU cycle. When you write imperative code that is packed with conditional logic, the reader is forced to exert more brain-CPU cycles. In that case, code the expectation in a human-like language, declarative BDD style using `expect` or `should` and not using custom code. If Chai & Jest doesn't include the desired assertion and it’s highly repeatable, consider [extending Jest matcher (Jest)](https:\u002F\u002Fjestjs.io\u002Fdocs\u002Fen\u002Fexpect#expectextendmatchers) or writing a [custom Chai plugin](https:\u002F\u002Fwww.chaijs.com\u002Fguide\u002Fplugins\u002F)\n\u003Cbr\u002F>\n\n❌ **Otherwise:** The team will write less tests and decorate the annoying ones with .skip()\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\u003Cbr\u002F>\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Mocha-blue.svg \"Examples with Mocha & Chai\") ![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Jest-blue.svg \"Examples with Jest\")\n\n### :thumbsdown: Anti-Pattern Example: The reader must skim through not so short, and imperative code just to get the test story\n\n```javascript\ntest(\"When asking for an admin, ensure only ordered admins in results\", () => {\n  \u002F\u002Fassuming we've added here two admins \"admin1\", \"admin2\" and \"user1\"\n  const allAdmins = getUsers({ adminOnly: true });\n\n  let admin1Found,\n    adming2Found = false;\n\n  allAdmins.forEach(aSingleUser => {\n    if (aSingleUser === \"user1\") {\n      assert.notEqual(aSingleUser, \"user1\", \"A user was found and not admin\");\n    }\n    if (aSingleUser === \"admin1\") {\n      admin1Found = true;\n    }\n    if (aSingleUser === \"admin2\") {\n      admin2Found = true;\n    }\n  });\n\n  if (!admin1Found || !admin2Found) {\n    throw new Error(\"Not all admins were returned\");\n  }\n});\n```\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: Skimming through the following declarative test is a breeze\n\n```javascript\nit(\"When asking for an admin, ensure only ordered admins in results\", () => {\n  \u002F\u002Fassuming we've added here two admins\n  const allAdmins = getUsers({ adminOnly: true });\n\n  expect(allAdmins)\n    .to.include.ordered.members([\"admin1\", \"admin2\"])\n    .but.not.include.ordered.members([\"user1\"]);\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️ 1.4 Stick to black-box testing: Test only public methods\n\n:white_check_mark: **Do:** Testing the internals brings huge overhead for almost nothing. If your code\u002FAPI delivers the right results, should you really invest your next 3 hours in testing HOW it worked internally and then maintain these fragile tests? Whenever a public behavior is checked, the private implementation is also implicitly tested and your tests will break only if there is a certain problem (e.g. wrong output). This approach is also referred to as `behavioral testing`. On the other side, should you test the internals (white box approach) — your focus shifts from planning the component outcome to nitty-gritty details and your test might break because of minor code refactors although the results are fine - this dramatically increases the maintenance burden\n\u003Cbr\u002F>\n\n❌ **Otherwise:** Your tests behave like the [boy who cried wolf](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FThe_Boy_Who_Cried_Wolf): shouting false-positive cries (e.g., A test fails because a private variable name was changed). Unsurprisingly, people will soon start to ignore the CI notifications until someday, a real bug gets ignored…\n\n\u003Cbr\u002F>\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :thumbsdown: Anti-Pattern Example: A test case is testing the internals for no good reason\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Mocha-blue.svg \"Examples with Mocha & Chai\")\n\n```javascript\nclass ProductService {\n  \u002F\u002Fthis method is only used internally\n  \u002F\u002FChange this name will make the tests fail\n  calculateVATAdd(priceWithoutVAT) {\n    return { finalPrice: priceWithoutVAT * 1.2 };\n    \u002F\u002FChange the result format or key name above will make the tests fail\n  }\n  \u002F\u002Fpublic method\n  getPrice(productId) {\n    const desiredProduct = DB.getProduct(productId);\n    const finalPrice = this.calculateVATAdd(desiredProduct.price).finalPrice;\n    return finalPrice;\n  }\n}\n\nit(\"White-box test: When the internal methods get 0 vat, it return 0 response\", async () => {\n  \u002F\u002FThere's no requirement to allow users to calculate the VAT, only show the final price. Nevertheless we falsely insist here to test the class internals\n  expect(new ProductService().calculateVATAdd(0).finalPrice).to.equal(0);\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️ ️1.5 Choose the right test doubles: Avoid mocks in favor of stubs and spies\n\n:white_check_mark: **Do:** Test doubles are a necessary evil because they are coupled to the application internals, yet some provide immense value (\u003Ca href=\"https:\u002F\u002Fmartinfowler.com\u002Farticles\u002FmocksArentStubs.html\" data-href=\"https:\u002F\u002Fmartinfowler.com\u002Farticles\u002FmocksArentStubs.html\" class=\"markup--anchor markup--p-anchor\" rel=\"noopener nofollow\" target=\"_blank\">[Read here a reminder about test doubles: mocks vs stubs vs spies](https:\u002F\u002Fmartinfowler.com\u002Farticles\u002FmocksArentStubs.html)\u003C\u002Fa>).\n\nBefore using test doubles, ask a very simple question: Do I use it to test functionality that appears, or could appear, in the requirements document? If not, it’s a white-box testing smell.\n\nFor example, if you want to test that your app behaves reasonably when the payment service is down, you might stub the payment service and trigger some ‘No Response’ return to ensure that the unit under test returns the right value. This checks our application behavior\u002Fresponse\u002Foutcome under certain scenarios. You might also use a spy to assert that an email was sent when that service is down — this is again a behavioral check which is likely to appear in a requirements doc (“Send an email if payment couldn’t be saved”). On the flip side, if you mock the Payment service and ensure that it was called with the right JavaScript types — then your test is focused on internal things that have nothing to do with the application functionality and are likely to change frequently\n\u003Cbr\u002F>\n\n❌ **Otherwise:** Any refactoring of code mandates searching for all the mocks in the code and updating accordingly. Tests become a burden rather than a helpful friend\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :thumbsdown: Anti-pattern example: Mocks focus on the internals\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Sinon-blue.svg \"Examples with Sinon\")\n\n```javascript\nit(\"When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config\", async () => {\n  \u002F\u002FAssume we already added a product\n  const dataAccessMock = sinon.mock(DAL);\n  \u002F\u002Fhmmm BAD: testing the internals is actually our main goal here, not just a side-effect\n  dataAccessMock\n    .expects(\"deleteProduct\")\n    .once()\n    .withArgs(DBConfig, theProductWeJustAdded, true, false);\n  new ProductService().deletePrice(theProductWeJustAdded);\n  dataAccessMock.verify();\n});\n```\n\n\u003Cbr\u002F>\n\n### :clap:Doing It Right Example: spies are focused on testing the requirements but as a side-effect are unavoidably touching to the internals\n\n```javascript\nit(\"When a valid product is about to be deleted, ensure an email is sent\", async () => {\n  \u002F\u002FAssume we already added here a product\n  const spy = sinon.spy(Emailer.prototype, \"sendEmail\");\n  new ProductService().deletePrice(theProductWeJustAdded);\n  \u002F\u002Fhmmm OK: we deal with internals? Yes, but as a side effect of testing the requirements (sending an email)\n  expect(spy.calledOnce).to.be.true;\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## 📗 Want to learn all these practices with live video?\n\n### Visit my online course [Testing Node.js & JavaScript From A To Z](https:\u002F\u002Fwww.testjavascript.com)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️1.6 Don’t “foo”, use realistic input data\n\n:white_check_mark: **Do:** Often production bugs are revealed under some very specific and surprising input — the more realistic the test input is, the greater the chances are to catch bugs early. Use dedicated libraries like [Chance](https:\u002F\u002Fgithub.com\u002Fchancejs\u002Fchancejs) or [Faker](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Ffaker) to generate pseudo-real data that resembles the variety and form of production data. For example, such libraries can generate realistic phone numbers, usernames, credit cards, company names, and even ‘lorem ipsum’ text. You may also create some tests (on top of unit tests, not as a replacement) that randomize fakers' data to stretch your unit under test or even import real data from your production environment. Want to take it to the next level? See the next bullet (property-based testing).\n\u003Cbr\u002F>\n\n❌ **Otherwise:** All your development testing will falsely show green when you use synthetic inputs like “Foo”, but then production might turn red when a hacker passes-in a nasty string like “@3e2ddsf . ##’ 1 fdsfds . fds432 AAAA”\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :thumbsdown: Anti-Pattern Example: A test suite that passes due to non-realistic data\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Jest-blue.svg \"Examples with Jest\")\n\n```javascript\nconst addProduct = (name, price) => {\n  const productNameRegexNoSpace = \u002F^\\S*$\u002F; \u002F\u002Fno white-space allowed\n\n  if (!productNameRegexNoSpace.test(name)) return false; \u002F\u002Fthis path never reached due to dull input\n\n  \u002F\u002Fsome logic here\n  return true;\n};\n\ntest(\"Wrong: When adding new product with valid properties, get successful confirmation\", async () => {\n  \u002F\u002FThe string \"Foo\" which is used in all tests never triggers a false result\n  const addProductResult = addProduct(\"Foo\", 5);\n  expect(addProductResult).toBe(true);\n  \u002F\u002FPositive-false: the operation succeeded because we never tried with long\n  \u002F\u002Fproduct name including spaces\n});\n```\n\n\u003Cbr\u002F>\n\n### :clap:Doing It Right Example: Randomizing realistic input\n\n```javascript\nit(\"Better: When adding new valid product, get successful confirmation\", async () => {\n  const addProductResult = addProduct(faker.commerce.productName(), faker.random.number());\n  \u002F\u002FGenerated random input: {'Sleek Cotton Computer',  85481}\n  expect(addProductResult).to.be.true;\n  \u002F\u002FTest failed, the random input triggered some path we never planned for.\n  \u002F\u002FWe discovered a bug early!\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️ 1.7 Test many input combinations using Property-based testing\n\n:white_check_mark: **Do:** Typically we choose a few input samples for each test. Even when the input format resembles real-world data (see bullet [‘Don’t foo’](https:\u002F\u002Fgithub.com\u002Fgoldbergyoni\u002Fjavascript-testing-best-practices#-%EF%B8%8F16-dont-foo-use-realistic-input-data)), we cover only a few input combinations (method(‘’, true, 1), method(“string” , false , 0)), However, in production, an API that is called with 5 parameters can be invoked with thousands of different permutations, one of them might render our process down ([see Fuzz Testing](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFuzzing)). What if you could write a single test that sends 1000 permutations of different inputs automatically and catches for which input our code fails to return the right response? Property-based testing is a technique that does exactly that: sending all the possible input combinations to your unit under test it increases the serendipity of finding a bug. For example, given a method — addNewProduct(id, name, isDiscount) — the supporting libraries will call this method with many combinations of (number, string, boolean) like (1, “iPhone”, false), (2, “Galaxy”, true). You can run property-based testing using your favorite test runner (Mocha, Jest, etc) using libraries like [js-verify](https:\u002F\u002Fgithub.com\u002Fjsverify\u002Fjsverify) or [testcheck](https:\u002F\u002Fgithub.com\u002Fleebyron\u002Ftestcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https:\u002F\u002Fgithub.com\u002Fdubzzz\u002Ffast-check#readme) which seems to offer some additional features and also to be actively maintained\n\u003Cbr\u002F>\n\n❌ **Otherwise:** Unconsciously, you choose the test inputs that cover only code paths that work well. Unfortunately, this decreases the efficiency of testing as a vehicle to expose bugs\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: Testing many input permutations with “fast-check”\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Jest-blue.svg \"Examples with Jest\")\n\n```javascript\nimport fc from \"fast-check\";\n\ndescribe(\"Product service\", () => {\n  describe(\"Adding new\", () => {\n    \u002F\u002Fthis will run 100 times with different random properties\n    it(\"Add new product with random yet valid properties, always successful\", () =>\n      fc.assert(\n        fc.property(fc.integer(), fc.string(), (id, name) => {\n          expect(addNewProduct(id, name).status).toEqual(\"approved\");\n        })\n      ));\n  });\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️ 1.8 If needed, use only short & inline snapshots\n\n:white_check_mark: **Do:** When there is a need for [snapshot testing](https:\u002F\u002Fjestjs.io\u002Fdocs\u002Fen\u002Fsnapshot-testing), use only short and focused snapshots (i.e. 3-7 lines) that are included as part of the test ([Inline Snapshot](https:\u002F\u002Fjestjs.io\u002Fdocs\u002Fen\u002Fsnapshot-testing#inline-snapshots)) and not within external files. Keeping this guideline will ensure your tests remain self-explanatory and less fragile.\n\nOn the other hand, ‘classic snapshots’ tutorials and tools encourage storing big files (e.g. component rendering markup, API JSON result) over some external medium and ensure each time when the test runs to compare the received result with the saved version. This, for example, can implicitly couple our test to 1000 lines with 3000 data values that the test writer never read and reasoned about. Why is this wrong? By doing so, there are 1000 reasons for your test to fail - it’s enough for a single line to change for the snapshot to get invalid and this is likely to happen a lot. How frequently? for every space, comment, or minor CSS\u002FHTML change. Not only this, the test name wouldn’t give a clue about the failure as it just checks that 1000 lines didn’t change, also it encourages the test writer to accept as the desired true a long document he couldn’t inspect and verify. All of these are symptoms of obscure and eager test that is not focused and aims to achieve too much\n\nIt’s worth noting that there are few cases where long & external snapshots are acceptable - when asserting on schema and not data (extracting out values and focusing on fields) or when the received document rarely changes\n\u003Cbr\u002F>\n\n❌ **Otherwise:** A UI test fails. The code seems right, the screen renders perfect pixels, what happened? your snapshot testing just found a difference from the original document to the current received one - a single space character was added to the markdown...\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :thumbsdown: Anti-Pattern Example: Coupling our test to unseen 2000 lines of code\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Jest-blue.svg \"Examples with Jest\")\n\n```javascript\nit(\"TestJavaScript.com is renderd correctly\", () => {\n  \u002F\u002FArrange\n\n  \u002F\u002FAct\n  const receivedPage = renderer\n    .create(\u003CDisplayPage page=\"http:\u002F\u002Fwww.testjavascript.com\"> Test JavaScript \u003C\u002FDisplayPage>)\n    .toJSON();\n\n  \u002F\u002FAssert\n  expect(receivedPage).toMatchSnapshot();\n  \u002F\u002FWe now implicitly maintain a 2000 lines long document\n  \u002F\u002Fevery additional line break or comment - will break this test\n});\n```\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: Expectations are visible and focused\n\n```javascript\nit(\"When visiting TestJavaScript.com home page, a menu is displayed\", () => {\n  \u002F\u002FArrange\n\n  \u002F\u002FAct\n  const receivedPage = renderer\n    .create(\u003CDisplayPage page=\"http:\u002F\u002Fwww.testjavascript.com\"> Test JavaScript \u003C\u002FDisplayPage>)\n    .toJSON();\n\n  \u002F\u002FAssert\n\n  const menu = receivedPage.content.menu;\n  expect(menu).toMatchInlineSnapshot(`\n\u003Cul>\n\u003Cli>Home\u003C\u002Fli>\n\u003Cli> About \u003C\u002Fli>\n\u003Cli> Contact \u003C\u002Fli>\n\u003C\u002Ful>\n`);\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️ 1.9 Copy code, but only what's neccessary\n\n:white_check_mark: **Do:** Include all the necessary details that affect the test result, but nothing more. As an example, consider a test that should factor 100 lines of input JSON - Pasting this in every test is tedious. Extracting it outside to transferFactory.getJSON() will leave the test vague - Without data, it's hard to correlate the test result with the cause (\"why is it supposed to return 400 status?\"). The classic book x-unit patterns named this pattern 'the mystery guest' - Something unseen affected our test results, we don't know what exactly. We can do better by extracting repeatable long parts outside AND mentioning explicitly which specific details matter to the test. Going with the example above, the test can pass parameters that highlight what is important: transferFactory.getJSON({sender: undefined}). In this example, the reader should immediately infer that the empty sender field is the reason why the test should expect a validation error or any other similar adequate outcome.\n\u003Cbr\u002F>\n\n❌ **Otherwise:** Copying 500 JSON lines in will leave your tests unmaintainable and unreadable. Moving everything outside will end with vague tests that are hard to understand\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :thumbsdown: Anti-Pattern Example: The test failure is unclear because all the cause is external and hides within huge JSON\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Mocha-blue.svg \"Examples with Mocha\")\n\n```javascript\ntest(\"When no credit, then the transfer is declined\", async() => {\n      \u002F\u002F Arrange\n      const transferRequest = testHelpers.factorMoneyTransfer() \u002F\u002Fget back 200 lines of JSON;\n      const transferServiceUnderTest = new TransferService();\n\n      \u002F\u002F Act\n      const transferResponse = await transferServiceUnderTest.transfer(transferRequest);\n\n      \u002F\u002F Assert\n      expect(transferResponse.status).toBe(409);\u002F\u002F But why do we expect failure: All seems perfectly valid in the test 🤔\n    });\n```\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: The test highlights what is the cause of the test result\n\n```javascript\n\ntest(\"When no credit, then the transfer is declined \", async() => {\n      \u002F\u002F Arrange\n      const transferRequest = testHelpers.factorMoneyTransfer({userCredit:100, transferAmount:200}) \u002F\u002Fobviously there is lack of credit\n      const transferServiceUnderTest = new TransferService({disallowOvercharge:true});\n\n      \u002F\u002F Act\n      const transferResponse = await transferServiceUnderTest.transfer(transferRequest);\n\n      \u002F\u002F Assert\n      expect(transferResponse.status).toBe(409); \u002F\u002F Obviously if the user has no credit it should fail\n    });\n  ```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️ 1.10 Don’t catch errors, expect them\n\n:white_check_mark: **Do:** When trying to assert that some input triggers an error, it might look right to use try-catch-finally and asserts that the catch clause was entered. The result is an awkward and verbose test case (example below) that hides the simple test intent and the result expectations\n\nA more elegant alternative is the using the one-line dedicated Chai assertion: expect(method).to.throw (or in Jest: expect(method).toThrow()). It’s absolutely mandatory to also ensure the exception contains a property that tells the error type, otherwise given just a generic error the application won’t be able to do much rather than show a disappointing message to the user\n\u003Cbr\u002F>\n\n❌ **Otherwise:** It will be challenging to infer from the test reports (e.g. CI reports) what went wrong\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :thumbsdown: Anti-pattern Example: A long test case that tries to assert the existence of error with try-catch\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Mocha-blue.svg \"Examples with Mocha\")\n\n```javascript\nit(\"When no product name, it throws error 400\", async () => {\n  let errorWeExceptFor = null;\n  try {\n    const result = await addNewProduct({});\n  } catch (error) {\n    expect(error.code).to.equal(\"InvalidInput\");\n    errorWeExceptFor = error;\n  }\n  expect(errorWeExceptFor).not.to.be.null;\n  \u002F\u002Fif this assertion fails, the tests results\u002Freports will only show\n  \u002F\u002Fthat some value is null, there won't be a word about a missing Exception\n});\n```\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: A human-readable expectation that could be understood easily, maybe even by QA or technical PM\n\n```javascript\nit(\"When no product name, it throws error 400\", async () => {\n  await expect(addNewProduct({}))\n    .to.eventually.throw(AppError)\n    .with.property(\"code\", \"InvalidInput\");\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️ 1.11 Tag your tests\n\n:white_check_mark: **Do:** Different tests must run on different scenarios: quick smoke, IO-less, tests should run when a developer saves or commits a file, full end-to-end tests usually run when a new pull request is submitted, etc. This can be achieved by tagging tests with keywords like #cold #api #sanity so you can grep with your testing harness and invoke the desired subset. For example, this is how you would invoke only the sanity test group with Mocha: mocha — grep ‘sanity’\n\u003Cbr\u002F>\n\n❌ **Otherwise:** Running all the tests, including tests that perform dozens of DB queries, any time a developer makes a small change can be extremely slow and keeps developers away from running tests\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: Tagging tests as ‘#cold-test’ allows the test runner to execute only fast tests (Cold===quick tests that are doing no IO and can be executed frequently even as the developer is typing)\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Jest-blue.svg \"Examples with Jest\")\n\n```javascript\n\u002F\u002Fthis test is fast (no DB) and we're tagging it correspondigly\n\u002F\u002Fnow the user\u002FCI can run it frequently\ndescribe(\"Order service\", function() {\n  describe(\"Add new order #cold-test #sanity\", function() {\n    test(\"Scenario - no currency was supplied. Expectation - Use the default currency #sanity\", function() {\n      \u002F\u002Fcode logic here\n    });\n  });\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️ 1.12 Categorize tests under at least 2 levels\n\n:white_check_mark: **Do:** Apply some structure to your test suite so an occasional visitor could easily understand the requirements (tests are the best documentation) and the various scenarios that are being tested. A common method for this is by placing at least 2 'describe' blocks above your tests: the 1st is for the name of the unit under test and the 2nd for an additional level of categorization like the scenario or custom categories (see code examples and the print screen below). Doing so will also greatly improve the test reports: The reader will easily infer the test categories, delve into the desired section and correlate failing tests. In addition, it will get much easier for a developer to navigate through the code of a suite with many tests. There are multiple alternative structures for the test suite that you may consider like [given-when-then](https:\u002F\u002Fgithub.com\u002Fsearls\u002Fjasmine-given) and [RITE](https:\u002F\u002Fgithub.com\u002Fericelliott\u002Friteway)\n\n\u003Cbr\u002F>\n\n❌ **Otherwise:** When looking at a report with a flat and long list of tests, the reader has to skim-read through long texts to conclude the major scenarios and correlate the commonality of failing tests. Consider the following case: When 7\u002F100 tests fail, looking at a flat list will demand reading the text of the failing to see how they relate to each other. However, in a hierarchical report, all of them could be under the same flow or category and the reader will quickly infer what or at least where is the root failure cause\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: Structuring suite with the name of unit under test and scenarios will lead to the convenient report that is shown below\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Jest-blue.svg \"Examples with Jest\")\n\n```javascript\n\u002F\u002F Unit under test\ndescribe(\"Transfer service\", () => {\n  \u002F\u002FScenario\n  describe(\"When no credit\", () => {\n    \u002F\u002FExpectation\n    test(\"Then the response status should decline\", () => {});\n\n    \u002F\u002FExpectation\n    test(\"Then it should send email to admin\", () => {});\n  });\n});\n```\n\n![alt text](assets\u002Fhierarchical-report.png)\n\n\u003Cbr\u002F>\n\n### :thumbsdown: Anti-pattern Example: A flat list of tests will make it harder for the reader to identify the user stories and correlate failing tests\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Jest-blue.svg \"Examples with Mocha\")\n\n```javascript\ntest(\"Then the response status should decline\", () => {});\n\ntest(\"Then it should send email\", () => {});\n\ntest(\"Then there should not be a new transfer record\", () => {});\n```\n\n![alt text](assets\u002Fflat-report.png)\n\n\u003Cbr\u002F>\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️1.13 Other generic good testing hygiene\n\n:white_check_mark: **Do:** This post is focused on testing advice that is related to or at least can be exemplified with Node JS. This bullet, however, groups a few non-Node related tips that are well-known\n\nLearn and practice [TDD principles](https:\u002F\u002Fwww.sm-cloud.com\u002Fbook-review-test-driven-development-by-example-a-tldr\u002F) — they are extremely valuable for many but don’t get intimidated if they don’t fit your style, you’re not the only one. Consider writing the tests before the code in a [red-green-refactor style](https:\u002F\u002Fblog.cleancoder.com\u002Funcle-bob\u002F2014\u002F12\u002F17\u002FTheCyclesOfTDD.html), ensure each test checks exactly one thing, when you find a bug — before fixing write a test that will detect this bug in the future, and let each test fail at least once before turning green, start a module by writing a quick and simplistic code that satisfies the test - then refactor gradually and take it to a production grade level, avoid any dependency on the environment (paths, OS, etc)\n\u003Cbr\u002F>\n\n❌ **Otherwise:** You‘ll miss pearls of wisdom that were collected for decades\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n# Section 2️⃣: Backend Testing\n\n## ⚪ ️2.1 Enrich your testing portfolio: Look beyond unit tests and the pyramid\n\n:white_check_mark: **Do:** The [testing pyramid](https:\u002F\u002Fmartinfowler.com\u002Fbliki\u002FTestPyramid.html), though 10> years old, is a great and relevant model that suggests three testing types and influences most developers’ testing strategies. At the same time, more than a handful of shiny new testing techniques emerged and are hiding in the shadows of the testing pyramid. Given all the dramatic changes that we’ve seen in the recent 10 years (Microservices, cloud, serverless), is it even possible that one quite-old model will suit *all* types of applications? shouldn’t the testing world consider welcoming new testing techniques?\n\nDon’t get me wrong, in 2019 the testing pyramid, TDD, and unit tests are still a powerful technique and are probably the best match for many applications. Only like any other model, despite its usefulness, [it must be wrong sometimes](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FAll_models_are_wrong). For example, consider an IoT application that ingests many events into a message-bus like Kafka\u002FRabbitMQ, which then flow into some data-warehouse and are eventually queried by some analytics UI. Should we really spend 50% of our testing budget on writing unit tests for an application that is integration-centric and has almost no logic? As the diversity of application types increases (bots, crypto, Alexa-skills) greater are the chances to find scenarios where the testing pyramid is not the best match.\n\nIt’s time to enrich your testing portfolio and become familiar with more testing types (the next bullets suggest a few ideas), mind models like the testing pyramid but also match testing types to real-world problems that you’re facing (‘Hey, our API is broken, let’s write consumer-driven contract testing!’), diversify your tests like an investor that builds a portfolio based on risk analysis — assess where problems might arise and match some prevention measures to mitigate those potential risks\n\nA word of caution: the TDD argument in the software world takes a typical false-dichotomy face, some preach to use it everywhere, and others think it’s the devil. Everyone who speaks in absolutes is wrong :]\n\n\u003Cbr\u002F>\n\n❌ **Otherwise:** You’re going to miss some tools with amazing ROI, some like Fuzz, lint, and mutation can provide value in 10 minutes\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the same way’\n\n![alt text](assets\u002Fbp-12-rich-testing.jpeg \"Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’\")\n\n\u003Cstrong class=\"markup--strong markup--p-strong\">☺️Example: \u003C\u002Fstrong>\u003Ca href=\"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=-2zP494wdUY&amp;feature=youtube\" data-href=\"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=-2zP494wdUY&amp;feature=youtu.be\" class=\"markup--anchor markup--p-anchor\" rel=\"nofollow noopener\" target=\"_blank\">[YouTube: “Beyond Unit Tests: 5 Shiny Node.JS Test Types (2018)” (Yoni Goldberg)](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=-2zP494wdUY&feature=youtu.be)\u003C\u002Fa>\n\n\u003Cbr\u002F>\n\n![alt text](assets\u002Fbp-12-Yoni-Goldberg-Testing.jpeg \"A test name that constitutes 3 parts\")\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️2.2 Component testing might be your best affair\n\n:white_check_mark: **Do:** Each unit test covers a tiny portion of the application and it’s expensive to cover the whole, whereas end-to-end testing easily covers a lot of ground but is flaky and slower, why not apply a balanced approach and write tests that are bigger than unit tests but smaller than end-to-end testing? Component testing is the unsung song of the testing world — they provide the best of both worlds: reasonable performance and a possibility to apply TDD patterns + realistic and great coverage.\n\nComponent tests focus on the Microservice ‘unit’, they work against the API and don’t mock anything which belongs to the Microservice itself (e.g. real DB, or at least the in-memory version of that DB) but stub anything that is external like calls to other Microservices. By doing so, we test what we deploy, approach the app from outward to inward and gain great confidence in a reasonable amount of time.\n\n[We have a full guide that is solely dedicated to writing component tests in the right way](https:\u002F\u002Fgithub.com\u002Ftestjavascript\u002Fnodejs-integration-tests-best-practices)\n\n\u003Cbr\u002F>\n\n❌ **Otherwise:** You may spend long days on writing unit tests to find out that you got only 20% system coverage\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: Supertest allows approaching Express API in-process (fast and cover many layers)\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Mocha-blue.svg \"Examples with Mocha\")\n\n![alt text](assets\u002Fbp-13-component-test-yoni-goldberg.png \" [Supertest](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fsupertest) allows approaching Express API in-process (fast and cover many layers)\")\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️2.3 Ensure new releases don’t break the API using contract tests\n\n:white_check_mark: **Do:** So your Microservice has multiple clients, and you run multiple versions of the service for compatibility reasons (keeping everyone happy). Then you change some field and ‘boom!’, some important client who relies on this field is angry. This is the Catch-22 of the integration world: It’s very challenging for the server side to consider all the multiple client expectations — On the other hand, the clients can’t perform any testing because the server controls the release dates. There is a spectrum of techniques that can mitigate the contract problem, some are simple, other are more feature-rich and demand a steeper learning curve. In a simple and recommended approach, the API provider publishes npm package with the API typing (e.g. JSDoc, TypeScript). Then the consumers can fetch this library and benefit from codign time intellisense and validation. A fancier approach is to use [PACT](https:\u002F\u002Fdocs.pact.io\u002F) which was born to formalize this process with a very disruptive approach — not the server defines the test plan itself rather the client defines the tests of the… server! PACT can record the client expectation and put it in a shared location, “broker”, so the server can pull the expectations and run on every build using the PACT library to detect broken contracts — a client expectation that is not met. By doing so, all the server-client API mismatches are caught early during build\u002FCI and might save you a great deal of frustration\n\u003Cbr\u002F>\n\n❌ **Otherwise:** The alternatives are exhausting manual testing or deployment fear\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example:\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20PACT-blue.svg \"Examples with PACT\")\n\n![alt text](assets\u002Fbp-14-testing-best-practices-contract-flow.png)\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️ 2.4 Test your middlewares in isolation\n\n:white_check_mark: **Do:** Many avoid Middleware testing because they represent a small portion of the system and require a live Express server. Both reasons are wrong — Middlewares are small but affect all or most of the requests and can be tested easily as pure functions that get {req,res} JS objects. To test a middleware function one should just invoke it and spy ([using Sinon for example](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fsinon)) on the interaction with the {req,res} objects to ensure the function performed the right action. The library [node-mock-http](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fnode-mocks-http) takes it even further and factors the {req,res} objects along with spying on their behavior. For example, it can assert whether the http status that was set on the res object matches the expectation (See example below)\n\u003Cbr\u002F>\n\n❌ **Otherwise:** A bug in Express middleware === a bug in all or most requests\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap:Doing It Right Example: Testing middleware in isolation without issuing network calls and waking-up the entire Express machine\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Jest-blue.svg \"Examples with Jest\")\n\n```javascript\n\u002F\u002Fthe middleware we want to test\nconst unitUnderTest = require(\".\u002Fmiddleware\");\nconst httpMocks = require(\"node-mocks-http\");\n\u002F\u002FJest syntax, equivelant to describe() & it() in Mocha\ntest(\"A request without authentication header, should return http status 403\", () => {\n  const request = httpMocks.createRequest({\n    method: \"GET\",\n    url: \"\u002Fuser\u002F42\",\n    headers: {\n      authentication: \"\"\n    }\n  });\n  const response = httpMocks.createResponse();\n  unitUnderTest(request, response);\n  expect(response.statusCode).toBe(403);\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️2.5 Measure and refactor using static analysis tools\n\n:white_check_mark: **Do:** Using static analysis tools helps by giving objective ways to improve code quality and keep your code maintainable. You can add static analysis tools to your CI build to abort when it finds code smells. Its main selling points over plain linting are the ability to inspect quality in the context of multiple files (e.g. detect duplications), perform advanced analysis (e.g. code complexity) and follow the history and progress of code issues. Two examples of tools you can use are [SonarQube](https:\u002F\u002Fwww.sonarqube.org\u002F) (4,900+ [stars](https:\u002F\u002Fgithub.com\u002FSonarSource\u002Fsonarqube)) and [Code Climate](https:\u002F\u002Fcodeclimate.com\u002F) (2,000+ [stars](https:\u002F\u002Fgithub.com\u002Fcodeclimate\u002Fcodeclimate))\n\nCredit: \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FTheHollidayInn\" data-href=\"https:\u002F\u002Fgithub.com\u002FTheHollidayInn\" class=\"markup--anchor markup--p-anchor\" rel=\"noopener nofollow\" target=\"_blank\">[Keith Holliday](https:\u002F\u002Fgithub.com\u002FTheHollidayInn)\u003C\u002Fa>\n\n\u003Cbr\u002F>\n\n❌ **Otherwise:** With poor code quality, bugs and performance will always be an issue that no shiny new library or state of the art features can fix\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: CodeClimate, a commercial tool that can identify complex methods:\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Code%20Climate-blue.svg \"Examples with CodeClimate\")\n\n![alt text](assets\u002Fbp-16-yoni-goldberg-quality.png \"CodeClimate, a commercial tool that can identify complex methods:\")\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️ 2.6 Check your readiness for Node-related chaos\n\n:white_check_mark: **Do:** Weirdly, most software testings are about logic & data only, but some of the worst things that happen (and are really hard to mitigate) are infrastructural issues. For example, did you ever test what happens when your process memory is overloaded, or when the server\u002Fprocess dies, or does your monitoring system realizes when the API becomes 50% slower?. To test and mitigate these type of bad things — [Chaos engineering](https:\u002F\u002Fprinciplesofchaos.org\u002F) was born by Netflix. It aims to provide awareness, frameworks and tools for testing our app resiliency for chaotic issues. For example, one of its famous tools, [the chaos monkey](https:\u002F\u002Fgithub.com\u002FNetflix\u002Fchaosmonkey), randomly kills servers to ensure that our service can still serve users and not relying on a single server (there is also a Kubernetes version, [kube-monkey](https:\u002F\u002Fgithub.com\u002Fasobti\u002Fkube-monkey), that kills pods). All these tools work on the hosting\u002Fplatform level, but what if you wish to test and generate pure Node chaos like check how your Node process copes with uncaught errors, unhandled promise rejection, v8 memory overloaded with the max allowed of 1.7GB or whether your UX remains satisfactory when the event loop gets blocked often? to address this I’ve written, [node-chaos](https:\u002F\u002Fgithub.com\u002Fi0natan\u002Fnode-chaos-monkey) (alpha) which provides all sort of Node-related chaotic acts\n\u003Cbr\u002F>\n\n❌ **Otherwise:** No escape here, Murphy’s law will hit your production without mercy\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: : Node-chaos can generate all sort of Node.js pranks so you can test how resilience is your app to chaos\n\n![alt text](assets\u002Fbp-17-yoni-goldberg-chaos-monkey-nodejs.png \"Node-chaos can generate all sort of Node.js pranks so you can test how resilience is your app to chaos\")\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\n\n## ⚪ ️2.7 Avoid global test fixtures and seeds, add data per-test\n\n:white_check_mark: **Do:** Going by the golden rule (bullet 0), each test should add and act on its own set of DB rows to prevent coupling and easily reason about the test flow. In reality, this is often violated by testers who seed the DB with data before running the tests (also known as ‘test fixture’) for the sake of performance improvement. While performance is indeed a valid concern — it can be mitigated (see “Component testing” bullet), however, test complexity is a much painful sorrow that should govern other considerations most of the time. Practically, make each test case explicitly add the DB records it needs and act only on those records. If performance becomes a critical concern — a balanced compromise might come in the form of seeding the only suite of tests that are not mutating data (e.g. queries)\n\u003Cbr\u002F>\n\n❌ **Otherwise:** Few tests fail, a deployment is aborted, our team is going to spend precious time now, do we have a bug? let’s investigate, oh no — it seems that two tests were mutating the same seed data\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :thumbsdown: Anti-Pattern Example: tests are not independent and rely on some global hook to feed global DB data\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20Mocha-blue.svg \"Examples with Mocha\")\n\n```javascript\nbefore(async () => {\n  \u002F\u002Fadding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework\n  await DB.AddSeedDataFromJson('seed.json');\n});\nit(\"When updating site name, get successful confirmation\", async () => {\n  \u002F\u002FI know that site name \"portal\" exists - I saw it in the seed files\n  const siteToUpdate = await SiteService.getSiteByName(\"Portal\");\n  const updateNameResult = await SiteService.changeName(siteToUpdate, \"newName\");\n  expect(updateNameResult).to.be(true);\n});\nit(\"When querying by site name, get the right site\", async () => {\n  \u002F\u002FI know that site name \"portal\" exists - I saw it in the seed files\n  const siteToCheck = await SiteService.getSiteByName(\"Portal\");\n  expect(siteToCheck.name).to.be.equal(\"Portal\"); \u002F\u002FFailure! The previous test change the name :[\n});\n\n```\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data\n\n```javascript\nit(\"When updating site name, get successful confirmation\", async () => {\n  \u002F\u002Ftest is adding a fresh new records and acting on the records only\n  const siteUnderTest = await SiteService.addSite({\n    name: \"siteForUpdateTest\"\n  });\n  const updateNameResult = await SiteService.changeName(siteUnderTest, \"newName\");\n  expect(updateNameResult).to.be(true);\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\n\n## ⚪ ️2.8 Choose a clear data clean-up strategy: After-all (recommended) or after-each\n\n:white_check_mark: **Do:** The timing when the tests clean the database determines the way the tests are being written. The two most viable options are cleaning after all the tests vs cleaning after every single test. Choosing the latter option, cleaning after every single test guarantees clean tables and builds convenient testing perks for the developer. No other records exist when the test starts, one can have certainty which data is being queried and even might be tempted to count rows during assertions. This comes with severe downsides: When running in a multi-process mode, tests are likely to interfere with each other. While process-1 purges tables, at the very moment process-2 queries for data and fail (because the DB was suddenly deleted by process-1). On top of this, It's harder to troubleshoot failing tests - Visiting the DB will show no records.\n\nThe second option is to clean up after all the test files have finished (or even daily!). This approach means that the same DB with existing records serves all the tests and processes. To avoid stepping on each other's toes, the tests must add and act on specific records that they have added. Need to check that some record was added? Assume that there are other thousands of records and query for records that were added explicitly. Need to check that a record was deleted? Can't assume an empty table, check that this specific record is not there. This technique brings few powerful gains: It works natively in multi-process mode, when a developer wishes to understand what happened - the data is there and not deleted. It also increases the chance of finding bugs because the DB is full of records and not artificially empty. [See the full comparison table here](https:\u002F\u002Fgithub.com\u002Ftestjavascript\u002Fnodejs-integration-tests-best-practices\u002Fblob\u002Fmaster\u002Fgraphics\u002Fdb-clean-options.png).\n\u003Cbr\u002F>\n\n❌ **Otherwise:** Without a strategy to separate records or clean - Tests will step on each other toes; Using transactions will work only for relational DB and likely to get complicated once there are inner transactions\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Cleaning after ALL the tests. Not neccesserily after every run. The more data we have while the tests are running - The more it resembles the production perks\n\n```javascript\n  \u002F\u002F After-all clean up (recommended)\n\u002F\u002F global-teardown.js\nmodule.exports = async () => {\n  \u002F\u002F ...\n  if (Math.ceil(Math.random() * 10) === 10) {\n    await new OrderRepository().cleanup();\n  }\n};\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\n\n## ⚪ ️2.9 Isolate the component from the world using HTTP interceptor\n\n:white_check_mark: **Do:** Isolate the component under test by intercepting any outgoing HTTP request and providing the desired response so the collaborator HTTP API won't get hit. Nock is a great tool for this mission as it provides a convenient syntax for defining external services behavior. Isolation is a must to prevent noise and slow performance but mostly to simulate various scenarios and responses - A good flight simulator is not about painting clear blue sky rather bringing safe storms and chaos. This is reinforced in a Microservice architecture where the focus should always be on a single component without involving the rest of the world. Though it's possible to simulate external service behavior using test doubles (mocking), it's preferable not to touch the deployed code and act on the network level to keep the tests pure black-box. The downside of isolation is not detecting when the collaborator component changes and not realizing misunderstandings between the two services - Make sure to compensate for this using a few contract or E2E tests\n\u003Cbr\u002F>\n\n❌ **Otherwise:** Some services provide a fake version that can be deployed by the caller locally, usually using Docker - This will ease the setup and boost the performance but won't help with simulating various responses; Some services provide 'sandbox' environment, so the real service is hit but no costs or side effects are triggered - This will cut down the noise of setting up the 3rd party service but also won't allow simulating scenarios\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Preventing network calls to externous components allows simulating scenarios and minimizing the noise\n\n```javascript\n\u002F\u002F Intercept requests for 3rd party APIs and return a predefined response \nbeforeEach(() => {\n  nock('http:\u002F\u002Flocalhost\u002Fuser\u002F').get(`\u002F1`).reply(200, {\n    id: 1,\n    name: 'John',\n  });\n});\n```\n\n\u003C\u002Fdetails>\n\u003Cbr\u002F>\n\n## ⚪ ️2.10 Test the response schema, mostly when there are auto-generated fields\n\n:white_check_mark: **Do:** When it is impossible to assert for specific data, check for mandatory field existence and types. Sometimes, the response contains important fields with dynamic data that can't be predicted when writing the test, like dates and incrementing numbers. If the API contract promises that these fields won't be null and hold the right types, it's imperative to test it. Most assertion libraries support checking types. If the response is small, check the return data and type together within the same assertion (see code example). One more option is to verify the entire response against an OpenAPI doc (Swagger). Most test runners have community extensions that validate API responses against their documentation.\n\n\n\u003Cbr\u002F>\n\n❌ **Otherwise:** Although the code\u002FAPI caller relies on some field with dynamic data (e.g., ID, date), it will not come in return and break the contract\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Asserting that fields with dynamic value exist and have the right type\n\n```javascript\n  test('When adding a new valid order, Then should get back approval with 200 response', async () => {\n  \u002F\u002F ...\n  \u002F\u002FAssert\n  expect(receivedAPIResponse).toMatchObject({\n    status: 200,\n    data: {\n      id: expect.any(Number), \u002F\u002F Any number satisfies this test\n      mode: 'approved',\n    },\n  });\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\n\n## ⚪ ️2.11 Check integrations corner cases and chaos\n\n:white_check_mark: **Do:** When checking integrations, go beyond the happy and sad paths. Check not only error responses (e.g. HTTP 500 error) but also network-level anomalies like slow and timed-out responses. This will prove that the code is resilient and can handle various network scenarios like taking the right path after a timeout, has no fragile race conditions, and contains a circuit breaker for retries. Reputable interceptor tools can easily simulate various network behaviors like hectic service that occasionally fail. It can even realize when the default HTTP client timeout value is longer than the simulated response time and throw a timeout exception right away without waiting\n\n\n\u003Cbr\u002F>\n\n❌ **Otherwise:** All your tests pass, it's only the production who will crash or won't report errors correctly when 3rd parties send exceptional responses\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Ensuring that on network failures, the circuit breaker can save the day\n\n```javascript\n  test('When users service replies with 503 once and retry mechanism is applied, then an order is added successfully', async () => {\n  \u002F\u002FArrange\n  nock.removeInterceptor(userServiceNock.interceptors[0])\n  nock('http:\u002F\u002Flocalhost\u002Fuser\u002F')\n    .get('\u002F1')\n    .reply(503, undefined, { 'Retry-After': 100 });\n  nock('http:\u002F\u002Flocalhost\u002Fuser\u002F')\n    .get('\u002F1')\n    .reply(200);\n  const orderToAdd = {\n    userId: 1,\n    productId: 2,\n    mode: 'approved',\n  };\n\n  \u002F\u002FAct\n  const response = await axiosAPIClient.post('\u002Forder', orderToAdd);\n\n  \u002F\u002FAssert\n  expect(response.status).toBe(200);\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\n\n\n## ⚪ ️2.12 Test the five potential outcomes\n\n:white_check_mark: **Do:** When planning your tests, consider covering the five typical flow's outputs. When your test is triggering some action (e.g., API call), a reaction is happening, something meaningful occurs and calls for testing. Note that we don't care about how things work. Our focus is on outcomes, things that are noticeable from the outside and might affect the user. These outcomes\u002Freactions can be put in 5 categories:\n\n• Response - The test invokes an action (e.g., via API) and gets a response. It's now concerned with checking the response data correctness, schema, and HTTP status\n\n• A new state - After invoking an action, some **publicly accessible** data is probably modified\n\n• External calls - After invoking an action, the app might call an external component via HTTP or any other transport. For example, a call to send SMS, email or charge a credit card\n\n• Message queues - The outcome of a flow might be a message in a queue\n\n• Observability - Some things must be monitored, like errors or remarkable business events. When a transaction fails, not only we expect the right response but also correct error handling and proper logging\u002Fmetrics. This information goes directly to a very important user - The ops user (i.e., production SRE\u002Fadmin)\n\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n# Section 3️⃣: Frontend Testing\n\n## ⚪ ️ 3.1 Separate UI from functionality\n\n:white_check_mark: **Do:** When focusing on testing component logic, UI details become a noise that should be extracted, so your tests can focus on pure data. Practically, extract the desired data from the markup in an abstract way that is not too coupled to the graphic implementation, assert only on pure data (vs HTML\u002FCSS graphic details) and disable animations that slow down. You might get tempted to avoid rendering and test only the back part of the UI (e.g. services, actions, store) but this will result in fictional tests that don't resemble the reality and won't reveal cases where the right data doesn't even arrive in the UI\n\n\u003Cbr\u002F>\n\n❌ **Otherwise:** The pure calculated data of your test might be ready in 10ms, but then the whole test will last 500ms (100 tests = 1 min) due to some fancy and irrelevant animation\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: Separating out the UI details\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20React-blue.svg \"Examples with React\") ![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20React%20Testing%20Library-blue.svg \"Examples with react-testing-library\")\n\n```javascript\ntest(\"When users-list is flagged to show only VIP, should display only VIP members\", () => {\n  \u002F\u002F Arrange\n  const allUsers = [{ id: 1, name: \"Yoni Goldberg\", vip: false }, { id: 2, name: \"John Doe\", vip: true }];\n\n  \u002F\u002F Act\n  const { getAllByTestId } = render(\u003CUsersList users={allUsers} showOnlyVIP={true} \u002F>);\n\n  \u002F\u002F Assert - Extract the data from the UI first\n  const allRenderedUsers = getAllByTestId(\"user\").map(uiElement => uiElement.textContent);\n  const allRealVIPUsers = allUsers.filter(user => user.vip).map(user => user.name);\n  expect(allRenderedUsers).toEqual(allRealVIPUsers); \u002F\u002Fcompare data with data, no UI here\n});\n```\n\n\u003Cbr\u002F>\n\n### :thumbsdown: Anti-Pattern Example: Assertion mix UI details and data\n\n```javascript\ntest(\"When flagging to show only VIP, should display only VIP members\", () => {\n  \u002F\u002F Arrange\n  const allUsers = [{ id: 1, name: \"Yoni Goldberg\", vip: false }, { id: 2, name: \"John Doe\", vip: true }];\n\n  \u002F\u002F Act\n  const { getAllByTestId } = render(\u003CUsersList users={allUsers} showOnlyVIP={true} \u002F>);\n\n  \u002F\u002F Assert - Mix UI & data in assertion\n  expect(getAllByTestId(\"user\")).toEqual('[\u003Cli data-test-id=\"user\">John Doe\u003C\u002Fli>]');\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ⚪ ️ 3.2 Query HTML elements based on attributes that are unlikely to change\n\n:white_check_mark: **Do:** Query HTML elements based on attributes that are likely to survive graphic changes unlike CSS selectors and like form labels. If the designated element doesn't have such attributes, create a dedicated test attribute like 'test-id-submit-button'. Going this route not only ensures that your functional\u002Flogic tests never break because of look & feel changes but also it becomes clear to the entire team that this element and attribute are utilized by tests and shouldn't get removed\n\n\u003Cbr\u002F>\n\n❌ **Otherwise:** You want to test the login functionality that spans many components, logic and services, everything is set up perfectly - stubs, spies, Ajax calls are isolated. All seems perfect. Then the test fails because the designer changed the div CSS class from 'thick-border' to 'thin-border'\n\n\u003Cbr\u002F>\n\n\u003Cdetails>\u003Csummary>✏ \u003Cb>Code Examples\u003C\u002Fb>\u003C\u002Fsummary>\n\n\u003Cbr\u002F>\n\n### :clap: Doing It Right Example: Querying an element using a dedicated attribute for testing\n\n![](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F🔧%20Example%20using%20React-blue.svg \"Examples with React\")\n\n```jsx\n\u002F\u002F the markup code (part of React component)\n\u003Ch3>\n  \u003CBadge pill className=\"fixed_badge\" variant=\"dark\">\n    \u003Cspan data-test-id=\"errorsLabel\">{value}\u003C\u002Fspan>\n    \u003C!-- note the attribute data-test-id -->\n  \u003C\u002FBadge>\n\u003C\u002Fh3>\n```\n\n```javascript\n\u002F\u002F this example is using react-testing-library\ntest(\"Whenever no data is passed to metric, show 0 as default\", () => {\n  \u002F\u002F Arrange\n  const metricValue = undefined;\n\n  \u002F\u002F Act\n  const { getByTestId } = render(\u003CdashboardMetric value={undefined} \u002F>);\n\n  expect(getByTestId(\"errorsLabel\").text()).toBe(\"0\");\n});\n```\n\n\u003Cbr\u002F>\n\n### :thumbsdown: Anti-Pattern Example: Relying on CSS attributes\n\n```jsx\n\u003C!-- the markup code (part of React component) -->\n\u003Cspan id=\"metric\" className=\"d-flex-column\">{value}\u003C\u002Fspan>\n\u003C!-- what if the designer changes the classs? -->\n```\n\n```javascript\n\u002F\u002F this exammple is using enzyme\ntest(\"Whenever no data is passed, error metric shows zero\", () => {\n  \u002F\u002F ...\n\n  expect(wrapper.find(\"[className='d-flex-column']\").text()).toBe(\"0\");\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\n\n## ⚪ ️ 3.3 Whenever possible, test with a realistic and fully rendered component\n\n:white_check_mark: **Do:** Whenever reasonably sized, test your component from outside like your users do, fully render the UI, act on it and assert that the rendered UI behaves as expected. Avoid all sort of mocking, partial and shallow rendering - this approach might result in untrapped bugs due to lack of details and harden the maintenance as the tests mess with the internals (see bullet ['Favour blackbox testing'](https:\u002F\u002Fgithub.com\u002Fgoldbergyoni\u002Fjavascript-testing-best-practices#-%EF%B8%8F-14-stick-to-black-box-testing-test-only-public-methods)). If one of the child components is significantly slowing down (e.g. animation) or complicating the setup - consider explicitly replacing it with a fake\n\nWith all that said, a word of caution is in order: this technique works for small\u002Fmedium components that pack a reasonable size of child components. Fully rendering a component with too many children will make it hard to reason about test failures (root cause analysis) and might get too slow. In such cases, write only a few tests against that fat parent component and more tests against its children\n\n\u003Cbr\u002F>\n\n❌ **Otherwise:** When poking into a component's internal by invoking its private me","该项目是一个全面详尽的JavaScript与Node.js测试最佳实践指南。它汇集了市场上数十篇优秀的博客文章、书籍以及工具，提供了超过50条从基础到高级的最佳实践建议，涵盖前端\u002FUI、后端及持续集成等全栈测试场景。特别强调了生产环境中的测试、变异测试和属性为基础的测试等内容，帮助开发者将测试技能提升至专业水平之上。适用于希望提高代码质量与系统可靠性的个人开发者或团队，在构建复杂应用时作为参考。",2,"2026-06-11 02:52:03","top_language"]