From 13f3fe6bc097e5b507643995829b46004c6679d7 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Thu, 20 May 2021 21:32:30 +0200 Subject: [PATCH 001/189] Create readme-fr file --- readme-fr.md | 1972 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1972 insertions(+) create mode 100644 readme-fr.md diff --git a/readme-fr.md b/readme-fr.md new file mode 100644 index 00000000..f75e1ab3 --- /dev/null +++ b/readme-fr.md @@ -0,0 +1,1972 @@ + + +
+ +# 👇 Why this guide can take your testing skills to the next level + +
+ +## 📗 46+ best practices: Super-comprehensive and exhaustive + +This 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 + +## 🚢 Advanced: Goes 10,000 miles beyond the basics + +Hop 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 + +## 🌐 Full-stack: front, backend, CI, anything + +Start by understanding the ubiquitous testing practices that are the foundation for any application tier. Then, delve into your area of choice: frontend/UI, backend, CI or maybe all of them? + +
+ +### Written By Yoni Goldberg + +- A JavaScript & Node.js consultant +- 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - My comprehensive online course with more than [10 hours of video](https://www.testjavascript.com), 14 test types and more than 40 best practices +- [Follow me on Twitter ](https://twitter.com/goldbergyoni/) + +
+ +### Translations - read in your own language + +- 🇨🇳[Chinese](readme-zh-CN.md) - Courtesy of [Yves yao](https://github.com/yvesyao) +- 🇰🇷[Korean](readme.kr.md) - Courtesy of [Rain Byun](https://github.com/ragubyun) +- 🇵🇱[Polish](readme-pl.md) - Courtesy of [Michal Biesiada](https://github.com/mbiesiad) +- 🇪🇸[Spanish](readme-es.md) - Courtesy of [Miguel G. Sanguino](https://github.com/sanguino) +- 🇧🇷[Portuguese-BR](readme-pt-br.md) - Courtesy of [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) +- Want to translate to your own language? please open an issue 💜 + +

+ +## `Table of Contents` + +#### [`Section 0: The Golden Rule`](#section-0️⃣-the-golden-rule) + +A single advice that inspires all the others (1 special bullet) + +#### [`Section 1: The Test Anatomy`](#section-1-the-test-anatomy-1) + +The foundation - structuring clean tests (12 bullets) + +#### [`Section 2: Backend`](#section-2️⃣-backend-testing) + +Writing backend and Microservices tests efficiently (8 bullets) + +#### [`Section 3: Frontend`](#section-3️⃣-frontend-testing) + +Writing tests for web UI including component and E2E tests (11 bullets) + +#### [`Section 4: Measuring Tests Effectiveness`](#section-4️⃣-measuring-test-effectiveness) + +Watching the watchman - measuring test quality (4 bullets) + +#### [`Section 5: Continuous Integration`](#section-5️⃣-ci-and-other-quality-measures) + +Guidelines for CI in the JS world (9 bullets) + +

+ +# Section 0️⃣: The Golden Rule + +
+ +## ⚪️ 0 The Golden Rule: Design for lean testing + +:white_check_mark: **Do:** +Testing code is not like production-code - design it to be dead-simple, short, abstraction-free, flat, delightful to work with, lean. One should look at a test and get the intent instantly. + +Our minds are full with the main production code, we don't have 'headspace' for additional complexity. Should we try to squeeze yet another challenging code 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. + +The tests are an opportunity for something else - a friendly and smiley assistant, one that it's delightful to work with and delivers great value for such 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 which 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). + +This 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, strive to keep it nimble, sometimes it's even worth dropping some tests and trade reliability for agility and simplicity. + +![alt text](/assets/headspace.png "We have no head room for additional complexity") + +Most of the advice below are derivatives of this principle. + +### Ready to start? + +

+ +# Section 1: The Test Anatomy + +
+ +## ⚪ ️ 1.1 Include 3 parts in each test name + +: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: + +(1) What is being tested? For example, the ProductsService.addNewProduct method + +(2) Under what circumstances and scenario? For example, no price is passed to the method + +(3) What is the expected result? For example, the new product is not approved + +
+ +❌ **Otherwise:** A deployment just failed, a test named “Add product” failed. Does this tell you what exactly is malfunctioning? + +
+ +**👇 Note:** Each bullet has code examples and sometime also an image illustration. Click to expand +
+ +
Code Examples + +
+ +### :clap: Doing It Right Example: A test name that constitutes 3 parts + +![](https://img.shields.io/badge/🔨%20Example%20using%20Mocha-blue.svg "Using Mocha to illustrate the idea") + +```javascript +//1. unit under test +describe('Products Service', function() { + describe('Add new product', function() { + //2. scenario and 3. expectation + it('When no price is specified, then the product status is pending approval', ()=> { + const newProduct = new ProductService().add(...); + expect(newProduct.status).to.equal('pendingApproval'); + }); + }); +}); + +``` + +
+ +### :clap: Doing It Right Example: A test name that constitutes 3 parts + +![alt text](/assets/bp-1-3-parts.jpeg "A test name that constitutes 3 parts") + +
+ +
+
© Credits & read-more + 1. Roy Osherove - Naming standards for unit tests +
+ +

+ +## ⚪ ️ 1.2 Structure tests by the AAA pattern + +: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: + +1st 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/stubbing on objects and any other preparation code + +2nd A - Act: Execute the unit under test. Usually 1 line of code + +3rd A - Assert: Ensure that the received value satisfies the expectation. Usually 1 line of code + +
+ +❌ **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 + +
+ +
Code Examples + +
+ +### :clap: Doing It Right Example: A test structured with the AAA pattern + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +describe("Customer classifier", () => { + test("When customer spent more than 500$, should be classified as premium", () => { + //Arrange + const customerToClassify = { spent: 505, joined: new Date(), id: 1 }; + const DBStub = sinon.stub(dataAccess, "getCustomer").reply({ id: 1, classification: "regular" }); + + //Act + const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); + + //Assert + expect(receivedClassification).toMatch("premium"); + }); +}); +``` + +
+ +### :thumbsdown: Anti-Pattern Example: No separation, one bulk, harder to interpret + +```javascript +test("Should be classified as premium", () => { + const customerToClassify = { spent: 505, joined: new Date(), id: 1 }; + const DBStub = sinon.stub(dataAccess, "getCustomer").reply({ id: 1, classification: "regular" }); + const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); + expect(receivedClassification).toMatch("premium"); +}); +``` + +
+ +

+ +## ⚪ ️1.3 Describe expectations in a product language: use BDD-style assertions + +: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://jestjs.io/docs/en/expect#expectextendmatchers) or writing a [custom Chai plugin](https://www.chaijs.com/guide/plugins/) +
+ +❌ **Otherwise:** The team will write less tests and decorate the annoying ones with .skip() + +
+ +
Code Examples
+ +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +### :thumbsdown: Anti-Pattern Example: The reader must skim through not so short, and imperative code just to get the test story + +```javascript +test("When asking for an admin, ensure only ordered admins in results", () => { + //assuming we've added here two admins "admin1", "admin2" and "user1" + const allAdmins = getUsers({ adminOnly: true }); + + let admin1Found, + adming2Found = false; + + allAdmins.forEach(aSingleUser => { + if (aSingleUser === "user1") { + assert.notEqual(aSingleUser, "user1", "A user was found and not admin"); + } + if (aSingleUser === "admin1") { + admin1Found = true; + } + if (aSingleUser === "admin2") { + admin2Found = true; + } + }); + + if (!admin1Found || !admin2Found) { + throw new Error("Not all admins were returned"); + } +}); +``` + +
+ +### :clap: Doing It Right Example: Skimming through the following declarative test is a breeze + +```javascript +it("When asking for an admin, ensure only ordered admins in results", () => { + //assuming we've added here two admins + const allAdmins = getUsers({ adminOnly: true }); + + expect(allAdmins) + .to.include.ordered.members(["admin1", "admin2"]) + .but.not.include.ordered.members(["user1"]); +}); +``` + +
+ +

+ +## ⚪ ️ 1.4 Stick to black-box testing: Test only public methods + +:white_check_mark: **Do:** Testing the internals brings huge overhead for almost nothing. If your code/API 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 +
+ +❌ **Otherwise:** Your tests behave like the [boy who cried wolf](https://en.wikipedia.org/wiki/The_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… + +
+
Code Examples + +
+ +### :thumbsdown: Anti-Pattern Example: A test case is testing the internals for no good reason + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") + +```javascript +class ProductService { + //this method is only used internally + //Change this name will make the tests fail + calculateVATAdd(priceWithoutVAT) { + return { finalPrice: priceWithoutVAT * 1.2 }; + //Change the result format or key name above will make the tests fail + } + //public method + getPrice(productId) { + const desiredProduct = DB.getProduct(productId); + finalPrice = this.calculateVATAdd(desiredProduct.price).finalPrice; + return finalPrice; + } +} + +it("White-box test: When the internal methods get 0 vat, it return 0 response", async () => { + //There'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 + expect(new ProductService().calculateVATAdd(0).finalPrice).to.equal(0); +}); +``` + +
+ +

+ +## ⚪ ️ ️1.5 Choose the right test doubles: Avoid mocks in favor of stubs and spies + +:white_check_mark: **Do:** Test doubles are a necessary evil because they are coupled to the application internals, yet some provide immense value ([Read here a reminder about test doubles: mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)). + +Before 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 no, it’s a white-box testing smell. + +For 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/response/outcome 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 +
+ +❌ **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 + +
+ +
Code Examples + +
+ +### :thumbsdown: Anti-pattern example: Mocks focus on the internals + +![](https://img.shields.io/badge/🔧%20Example%20using%20Sinon-blue.svg "Examples with Sinon") + +```javascript +it("When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config", async () => { + //Assume we already added a product + const dataAccessMock = sinon.mock(DAL); + //hmmm BAD: testing the internals is actually our main goal here, not just a side-effect + dataAccessMock + .expects("deleteProduct") + .once() + .withArgs(DBConfig, theProductWeJustAdded, true, false); + new ProductService().deletePrice(theProductWeJustAdded); + dataAccessMock.verify(); +}); +``` + +
+ +### :clap:Doing It Right Example: spies are focused on testing the requirements but as a side-effect are unavoidably touching to the internals + +```javascript +it("When a valid product is about to be deleted, ensure an email is sent", async () => { + //Assume we already added here a product + const spy = sinon.spy(Emailer.prototype, "sendEmail"); + new ProductService().deletePrice(theProductWeJustAdded); + //hmmm OK: we deal with internals? Yes, but as a side effect of testing the requirements (sending an email) + expect(spy.calledOnce).to.be.true; +}); +``` + +
+ +

+ +## 📗 Want to learn all these practices with live video? + +### Visit my online course [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) + +

+ +## ⚪ ️1.6 Don’t “foo”, use realistic input data + +: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 [Faker](https://www.npmjs.com/package/faker) 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 card, 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). +
+ +❌ **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” + +
+ +
Code Examples + +
+ +### :thumbsdown: Anti-Pattern Example: A test suite that passes due to non-realistic data + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +const addProduct = (name, price) => { + const productNameRegexNoSpace = /^\S*$/; //no white-space allowed + + if (!productNameRegexNoSpace.test(name)) return false; //this path never reached due to dull input + + //some logic here + return true; +}; + +test("Wrong: When adding new product with valid properties, get successful confirmation", async () => { + //The string "Foo" which is used in all tests never triggers a false result + const addProductResult = addProduct("Foo", 5); + expect(addProductResult).toBe(true); + //Positive-false: the operation succeeded because we never tried with long + //product name including spaces +}); +``` + +
+ +### :clap:Doing It Right Example: Randomizing realistic input + +```javascript +it("Better: When adding new valid product, get successful confirmation", async () => { + const addProductResult = addProduct(faker.commerce.productName(), faker.random.number()); + //Generated random input: {'Sleek Cotton Computer', 85481} + expect(addProductResult).to.be.true; + //Test failed, the random input triggered some path we never planned for. + //We discovered a bug early! +}); +``` + +
+ +

+ +## ⚪ ️ 1.7 Test many input combinations using Property-based testing + +: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’), 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://en.wikipedia.org/wiki/Fuzzing)). 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: by 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://github.com/jsverify/jsverify) or [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https://github.com/dubzzz/fast-check#readme) which seems to offer some additional features and also to be actively maintained +
+ +❌ **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 + +
+ +
Code Examples + +
+ +### :clap: Doing It Right Example: Testing many input permutations with “fast-check” + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +import fc from "fast-check"; + +describe("Product service", () => { + describe("Adding new", () => { + //this will run 100 times with different random properties + it("Add new product with random yet valid properties, always successful", () => + fc.assert( + fc.property(fc.integer(), fc.string(), (id, name) => { + expect(addNewProduct(id, name).status).toEqual("approved"); + }) + )); + }); +}); +``` + +
+ +

+ +## ⚪ ️ 1.8 If needed, use only short & inline snapshots + +:white_check_mark: **Do:** When there is a need for [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), use only short and focused snapshots (i.e. 3-7 lines) that are included as part of the test ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)) and not within external files. Keeping this guideline will ensure your tests remain self-explanatory and less fragile. + +On the other hand, ‘classic snapshots’ tutorials and tools encourage to store big files (e.g. component rendering markup, API JSON result) over some external medium and ensure each time when the test run 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/HTML 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 to 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 + +It’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 +
+ +❌ **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 origin document to current received one - a single space character was added to the markdown... + +
+ +
Code Examples + +
+ +### :thumbsdown: Anti-Pattern Example: Coupling our test to unseen 2000 lines of code + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +it("TestJavaScript.com is renderd correctly", () => { + //Arrange + + //Act + const receivedPage = renderer + .create( Test JavaScript ) + .toJSON(); + + //Assert + expect(receivedPage).toMatchSnapshot(); + //We now implicitly maintain a 2000 lines long document + //every additional line break or comment - will break this test +}); +``` + +
+ +### :clap: Doing It Right Example: Expectations are visible and focused + +```javascript +it("When visiting TestJavaScript.com home page, a menu is displayed", () => { + //Arrange + + //Act + const receivedPage = renderer + .create( Test JavaScript ) + .toJSON(); + + //Assert + + const menu = receivedPage.content.menu; + expect(menu).toMatchInlineSnapshot(` + +`); +}); +``` + +
+ +

+ +## ⚪ ️1.9 Avoid global test fixtures and seeds, add data per-test + +: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’](https://en.wikipedia.org/wiki/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) +
+ +❌ **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 + +
+ +
Code Examples + +
+ +### :thumbsdown: Anti-Pattern Example: tests are not independent and rely on some global hook to feed global DB data + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +before(async () => { + //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework + await DB.AddSeedDataFromJson('seed.json'); +}); +it("When updating site name, get successful confirmation", async () => { + //I know that site name "portal" exists - I saw it in the seed files + const siteToUpdate = await SiteService.getSiteByName("Portal"); + const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); + expect(updateNameResult).to.be(true); +}); +it("When querying by site name, get the right site", async () => { + //I know that site name "portal" exists - I saw it in the seed files + const siteToCheck = await SiteService.getSiteByName("Portal"); + expect(siteToCheck.name).to.be.equal("Portal"); //Failure! The previous test change the name :[ +}); + +``` + +
+ +### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data + +```javascript +it("When updating site name, get successful confirmation", async () => { + //test is adding a fresh new records and acting on the records only + const siteUnderTest = await SiteService.addSite({ + name: "siteForUpdateTest" + }); + + const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); + + expect(updateNameResult).to.be(true); +}); +``` + +
+ +
+ +## ⚪ ️ 1.10 Don’t catch errors, expect them + +: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 + +A 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 +
+ +❌ **Otherwise:** It will be challenging to infer from the test reports (e.g. CI reports) what went wrong + +
+ +
Code Examples + +
+ +### :thumbsdown: Anti-pattern Example: A long test case that tries to assert the existence of error with try-catch + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +it("When no product name, it throws error 400", async () => { + let errorWeExceptFor = null; + try { + const result = await addNewProduct({}); + } catch (error) { + expect(error.code).to.equal("InvalidInput"); + errorWeExceptFor = error; + } + expect(errorWeExceptFor).not.to.be.null; + //if this assertion fails, the tests results/reports will only show + //that some value is null, there won't be a word about a missing Exception +}); +``` + +
+ +### :clap: Doing It Right Example: A human-readable expectation that could be understood easily, maybe even by QA or technical PM + +```javascript +it("When no product name, it throws error 400", async () => { + await expect(addNewProduct({})) + .to.eventually.throw(AppError) + .with.property("code", "InvalidInput"); +}); +``` + +
+ +

+ +## ⚪ ️ 1.11 Tag your tests + +: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’ +
+ +❌ **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 + +
+ +
Code Examples + +
+ +### :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) + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +//this test is fast (no DB) and we're tagging it correspondigly +//now the user/CI can run it frequently +describe("Order service", function() { + describe("Add new order #cold-test #sanity", function() { + test("Scenario - no currency was supplied. Expectation - Use the default currency #sanity", function() { + //code logic here + }); + }); +}); +``` + +
+ +

+ +## ⚪ ️ 1.12 Categorize tests under at least 2 levels + +: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 additional level of categorization like the scenario or custom categories (see code examples and print screen below). Doing so will also greatly improve the test reports: The reader will easily infer the tests 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 test suite that you may consider like [given-when-then](https://github.com/searls/jasmine-given) and [RITE](https://github.com/ericelliott/riteway) + +
+ +❌ **Otherwise:** When looking at a report with flat and long list of tests, the reader have to skim-read through long texts to conclude the major scenarios and correlate the commonality of failing tests. Consider the following case: When 7/100 tests fail, looking at a flat list will demand reading the failing tests text 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 + +
+ +
Code Examples + +
+ +### :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 + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +// Unit under test +describe("Transfer service", () => { + //Scenario + describe("When no credit", () => { + //Expectation + test("Then the response status should decline", () => {}); + + //Expectation + test("Then it should send email to admin", () => {}); + }); +}); +``` + +![alt text](assets/hierarchical-report.png) + +
+ +### :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 + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Mocha") + +```javascript +test("Then the response status should decline", () => {}); + +test("Then it should send email", () => {}); + +test("Then there should not be a new transfer record", () => {}); +``` + +![alt text](assets/flat-report.png) + +
+ +
+ +

+ +## ⚪ ️1.13 Other generic good testing hygiene + +: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 few non-Node related tips that are well-known + +Learn and practice [TDD principles](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) — 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://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.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, 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) +
+ +❌ **Otherwise:** You‘ll miss pearls of wisdom that were collected for decades + +

+ +# Section 2️⃣: Backend Testing + +## ⚪ ️2.1 Enrich your testing portfolio: Look beyond unit tests and the pyramid + +:white_check_mark: **Do:** The [testing pyramid](https://martinfowler.com/bliki/TestPyramid.html), though 10> years old, is a great and relevant model that suggests three testing types and influences most developers’ testing strategy. 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? + +Don’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://en.wikipedia.org/wiki/All_models_are_wrong). For example, consider an IoT application that ingests many events into a message-bus like Kafka/RabbitMQ, 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 increase (bots, crypto, Alexa-skills) greater are the chances to find scenarios where the testing pyramid is not the best match. + +It’s time to enrich your testing portfolio and become familiar with more testing types (the next bullets suggest 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 build a portfolio based on risk analysis — assess where problems might arise and match some prevention measures to mitigate those potential risks + +A word of caution: the TDD argument in the software world takes a typical false-dichotomy face, some preach to use it everywhere, others think it’s the devil. Everyone who speaks in absolutes is wrong :] + +
+ +❌ **Otherwise:** You’re going to miss some tools with amazing ROI, some like Fuzz, lint, and mutation can provide value in 10 minutes + +
+ +
Code Examples + +
+ +### :clap: Doing It Right Example: Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the same way’ + +![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") + +☺️Example: [YouTube: “Beyond Unit Tests: 5 Shiny Node.JS Test Types (2018)” (Yoni Goldberg)](https://www.youtube.com/watch?v=-2zP494wdUY&feature=youtu.be) + +
+ +![alt text](assets/bp-12-Yoni-Goldberg-Testing.jpeg "A test name that constitutes 3 parts") + +
+ +

+ +## ⚪ ️2.2 Component testing might be your best affair + +: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 from both worlds: reasonable performance and a possibility to apply TDD patterns + realistic and great coverage. + +Component tests focus on the Microservice ‘unit’, they work against the API, 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 outwards to inwards and gain great confidence in a reasonable amount of time. +
+ +❌ **Otherwise:** You may spend long days on writing unit tests to find out that you got only 20% system coverage + +
+ +
Code Examples + +
+ +### :clap: Doing It Right Example: Supertest allows approaching Express API in-process (fast and cover many layers) + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +![alt text](assets/bp-13-component-test-yoni-goldberg.png " [Supertest](https://www.npmjs.com/package/supertest) allows approaching Express API in-process (fast and cover many layers)") + +
+ +

+ +## ⚪ ️2.3 Ensure new releases don’t break the API using contract tests + +: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. [Consumer-driven contracts and the framework PACT](https://docs.pact.io/) were born to formalize this process with a very disruptive approach — not the server defines the test plan of itself rather the client defines the tests of the… server! PACT can record the client expectation and put in a shared location, “broker”, so the server can pull the expectations and run on every build using 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/CI and might save you a great deal of frustration +
+ +❌ **Otherwise:** The alternatives are exhausting manual testing or deployment fear + +
+ +
Code Examples + +
+ +### :clap: Doing It Right Example: + +![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") + +![alt text](assets/bp-14-testing-best-practices-contract-flow.png) + +
+ +

+ +## ⚪ ️ 2.4 Test your middlewares in isolation + +: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://www.npmjs.com/package/sinon)) on the interaction with the {req,res} objects to ensure the function performed the right action. The library [node-mock-http](https://www.npmjs.com/package/node-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) +
+ +❌ **Otherwise:** A bug in Express middleware === a bug in all or most requests + +
+ +
Code Examples + +
+ +### :clap:Doing It Right Example: Testing middleware in isolation without issuing network calls and waking-up the entire Express machine + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +//the middleware we want to test +const unitUnderTest = require("./middleware"); +const httpMocks = require("node-mocks-http"); +//Jest syntax, equivelant to describe() & it() in Mocha +test("A request without authentication header, should return http status 403", () => { + const request = httpMocks.createRequest({ + method: "GET", + url: "/user/42", + headers: { + authentication: "" + } + }); + const response = httpMocks.createResponse(); + unitUnderTest(request, response); + expect(response.statusCode).toBe(403); +}); +``` + +
+ +

+ +## ⚪ ️2.5 Measure and refactor using static analysis tools + +: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://www.sonarqube.org/) (4,900+ [stars](https://github.com/SonarSource/sonarqube)) and [Code Climate](https://codeclimate.com/) (2,000+ [stars](https://github.com/codeclimate/codeclimate)) + +Credit: [Keith Holliday](https://github.com/TheHollidayInn) + +
+ +❌ **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 + +
+ +
Code Examples + +
+ +### :clap: Doing It Right Example: CodeClimate, a commercial tool that can identify complex methods: + +![](https://img.shields.io/badge/🔧%20Example%20using%20Code%20Climate-blue.svg "Examples with CodeClimate") + +![alt text](assets/bp-16-yoni-goldberg-quality.png "CodeClimate, a commercial tool that can identify complex methods:") + +
+ +

+ +## ⚪ ️ 2.6 Check your readiness for Node-related chaos + +: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/process 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://principlesofchaos.org/) 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://github.com/Netflix/chaosmonkey), 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://github.com/asobti/kube-monkey), that kills pods). All these tools work on the hosting/platform 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://github.com/i0natan/node-chaos-monkey) (alpha) which provides all sort of Node-related chaotic acts +
+ +❌ **Otherwise:** No escape here, Murphy’s law will hit your production without mercy + +
+ +
Code Examples + +
+ +### :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 + +![alt text](assets/bp-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") + +
+ +
+ +## ⚪ ️2.7 Avoid global test fixtures and seeds, add data per-test + +: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) +
+ +❌ **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 + +
+ +
Code Examples + +
+ +### :thumbsdown: Anti-Pattern Example: tests are not independent and rely on some global hook to feed global DB data + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +before(async () => { + //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework + await DB.AddSeedDataFromJson('seed.json'); +}); +it("When updating site name, get successful confirmation", async () => { + //I know that site name "portal" exists - I saw it in the seed files + const siteToUpdate = await SiteService.getSiteByName("Portal"); + const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); + expect(updateNameResult).to.be(true); +}); +it("When querying by site name, get the right site", async () => { + //I know that site name "portal" exists - I saw it in the seed files + const siteToCheck = await SiteService.getSiteByName("Portal"); + expect(siteToCheck.name).to.be.equal("Portal"); //Failure! The previous test change the name :[ +}); + +``` + +
+ +### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data + +```javascript +it("When updating site name, get successful confirmation", async () => { + //test is adding a fresh new records and acting on the records only + const siteUnderTest = await SiteService.addSite({ + name: "siteForUpdateTest" + }); + const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); + expect(updateNameResult).to.be(true); +}); +``` + +
+ +

+ +# Section 3️⃣: Frontend Testing + +## ⚪ ️ 3.1 Separate UI from functionality + +: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/CSS 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 + +
+ +❌ **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 + +
+ +
Code Examples + +
+ +### :clap: Doing It Right Example: Separating out the UI details + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +test("When users-list is flagged to show only VIP, should display only VIP members", () => { + // Arrange + const allUsers = [{ id: 1, name: "Yoni Goldberg", vip: false }, { id: 2, name: "John Doe", vip: true }]; + + // Act + const { getAllByTestId } = render(); + + // Assert - Extract the data from the UI first + const allRenderedUsers = getAllByTestId("user").map(uiElement => uiElement.textContent); + const allRealVIPUsers = allUsers.filter(user => user.vip).map(user => user.name); + expect(allRenderedUsers).toEqual(allRealVIPUsers); //compare data with data, no UI here +}); +``` + +
+ +### :thumbsdown: Anti-Pattern Example: Assertion mix UI details and data + +```javascript +test("When flagging to show only VIP, should display only VIP members", () => { + // Arrange + const allUsers = [{ id: 1, name: "Yoni Goldberg", vip: false }, { id: 2, name: "John Doe", vip: true }]; + + // Act + const { getAllByTestId } = render(); + + // Assert - Mix UI & data in assertion + expect(getAllByTestId("user")).toEqual('[
  • John Doe
  • ]'); +}); +``` + +
    + +

    + +## ⚪ ️ 3.2 Query HTML elements based on attributes that are unlikely to change + +: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/logic 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 + +
    + +❌ **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' + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Querying an element using a dedicated attribute for testing + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") + +```html +// the markup code (part of React component) +

    + + {value} + + +

    +``` + +```javascript +// this example is using react-testing-library +test("Whenever no data is passed to metric, show 0 as default", () => { + // Arrange + const metricValue = undefined; + + // Act + const { getByTestId } = render(); + + expect(getByTestId("errorsLabel").text()).toBe("0"); +}); +``` + +
    + +### :thumbsdown: Anti-Pattern Example: Relying on CSS attributes + +```html + +{value} + +``` + +```javascript +// this exammple is using enzyme +test("Whenever no data is passed, error metric shows zero", () => { + // ... + + expect(wrapper.find("[className='d-flex-column']").text()).toBe("0"); +}); +``` + +
    + +
    + +## ⚪ ️ 3.3 Whenever possible, test with a realistic and fully rendered component + +: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'). If one of the child components is significantly slowing down (e.g. animation) or complicating the setup - consider explicitly replacing it with a fake + +With all that said, a word of caution is in order: this technique works for small/medium 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 + +
    + +❌ **Otherwise:** When poking into a component's internal by invoking its private methods, and checking the inner state - you would have to refactor all tests when refactoring the components implementation. Do you really have a capacity for this level of maintenance? + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Working realistically with a fully rendered component + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Enzyme-blue.svg "Examples with Enzyme") + +```javascript +class Calendar extends React.Component { + static defaultProps = { showFilters: false }; + + render() { + return ( +
    + A filters panel with a button to hide/show filters + +
    + ); + } +} + +//Examples use React & Enzyme +test("Realistic approach: When clicked to show filters, filters are displayed", () => { + // Arrange + const wrapper = mount(); + + // Act + wrapper.find("button").simulate("click"); + + // Assert + expect(wrapper.text().includes("Choose Filter")); + // This is how the user will approach this element: by text +}); +``` + +### :thumbsdown: Anti-Pattern Example: Mocking the reality with shallow rendering + +```javascript +test("Shallow/mocked approach: When clicked to show filters, filters are displayed", () => { + // Arrange + const wrapper = shallow(); + + // Act + wrapper + .find("filtersPanel") + .instance() + .showFilters(); + // Tap into the internals, bypass the UI and invoke a method. White-box approach + + // Assert + expect(wrapper.find("Filter").props()).toEqual({ title: "Choose Filter" }); + // what if we change the prop name or don't pass anything relevant? +}); +``` + +
    + +
    + +## ⚪ ️ 3.4 Don't sleep, use frameworks built-in support for async events. Also try to speed things up + +:white_check_mark: **Do:** In many cases, the unit under test completion time is just unknown (e.g. animation suspends element appearance) - in that case, avoid sleeping (e.g. setTimeOut) and prefer more deterministic methods that most platforms provide. Some libraries allows awaiting on operations (e.g. [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), other provide API for waiting like [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). Sometimes a more elegant way is to stub the slow resource, like API for example, and then once the response moment becomes deterministic the component can be explicitly re-rendered. When depending upon some external component that sleeps, it might turn useful to [hurry-up the clock](https://jestjs.io/docs/en/timer-mocks). Sleeping is a pattern to avoid because it forces your test to be slow or risky (when waiting for a too short period). Whenever sleeping and polling is inevitable and there's no support from the testing framework, some npm libraries like [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) can help with a semi-deterministic solution +
    + +❌ **Otherwise:** When sleeping for a long time, tests will be an order of magnitude slower. When trying to sleep for small numbers, test will fail when the unit under test didn't respond in a timely fashion. So it boils down to a trade-off between flakiness and bad performance + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: E2E API that resolves only when the async operations is done (Cypress) + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") +![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +// using Cypress +cy.get("#show-products").click(); // navigate +cy.wait("@products"); // wait for route to appear +// this line will get executed only when the route is ready +``` + +### :clap: Doing It Right Example: Testing library that waits for DOM elements + +```javascript +// @testing-library/dom +test("movie title appears", async () => { + // element is initially not present... + + // wait for appearance + await wait(() => { + expect(getByText("the lion king")).toBeInTheDocument(); + }); + + // wait for appearance and return the element + const movie = await waitForElement(() => getByText("the lion king")); +}); +``` + +### :thumbsdown: Anti-Pattern Example: custom sleep code + +```javascript +test("movie title appears", async () => { + // element is initially not present... + + // custom wait logic (caution: simplistic, no timeout) + const interval = setInterval(() => { + const found = getByText("the lion king"); + if (found) { + clearInterval(interval); + expect(getByText("the lion king")).toBeInTheDocument(); + } + }, 100); + + // wait for appearance and return the element + const movie = await waitForElement(() => getByText("the lion king")); +}); +``` + +
    + +
    + +## ⚪ ️ 3.5 Watch how the content is served over the network + +![](https://img.shields.io/badge/🔧%20Example%20using%20Google%20LightHouse-blue.svg "Examples with Lighthouse") + +✅ **Do:** Apply some active monitor that ensures the page load under real network is optimized - this includes any UX concern like slow page load or un-minified bundle. The inspection tools market is no short: basic tools like [pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) can be easily configured to watch whether the server is alive and response under a reasonable SLA. This only scratches the surface of what might get wrong, hence it's preferable to opt for tools that specialize in frontend (e.g. [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) and perform richer analysis. The focus should be on symptoms, metrics that directly affect the UX, like page load time, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [time until the page gets interactive (TTI)](https://calibreapp.com/blog/time-to-interactive/). On top of that, one may also watch for technical causes like ensuring the content is compressed, time to the first byte, optimize images, ensuring reasonable DOM size, SSL and many others. It's advisable to have these rich monitors both during development, as part of the CI and most important - 24x7 over the production's servers/CDN + +
    + +❌ **Otherwise:** It must be disappointing to realize that after such great care for crafting a UI, 100% functional tests passing and sophisticated bundling - the UX is horrible and slow due to CDN misconfiguration + +
    + +
    Code Examples + +### :clap: Doing It Right Example: Lighthouse page load inspection report + +![](/assets/lighthouse2.png "Lighthouse page load inspection report") + +
    + +
    + +## ⚪ ️ 3.6 Stub flaky and slow resources like backend APIs + +:white_check_mark: **Do:** When coding your mainstream tests (not E2E tests), avoid involving any resource that is beyond your responsibility and control like backend API and use stubs instead (i.e. test double). Practically, instead of real network calls to APIs, use some test double library (like [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble), etc) for stubbing the API response. The main benefit is preventing flakiness - testing or staging APIs by definition are not highly stable and from time to time will fail your tests although YOUR component behaves just fine (production env was not meant for testing and it usually throttles requests). Doing this will allow simulating various API behavior that should drive your component behavior as when no data was found or the case when API throws an error. Last but not least, network calls will greatly slow down the tests + +
    + +❌ **Otherwise:** The average test runs no longer than few ms, a typical API call last 100ms>, this makes each test ~20x slower + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Stubbing or intercepting API calls + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +// unit under test +export default function ProductsList() { + const [products, setProducts] = useState(false); + + const fetchProducts = async () => { + const products = await axios.get("api/products"); + setProducts(products); + }; + + useEffect(() => { + fetchProducts(); + }, []); + + return products ?
    {products}
    :
    No products
    ; +} + +// test +test("When no products exist, show the appropriate message", () => { + // Arrange + nock("api") + .get(`/products`) + .reply(404); + + // Act + const { getByTestId } = render(); + + // Assert + expect(getByTestId("no-products-message")).toBeTruthy(); +}); +``` + +
    + +
    + +## ⚪ ️ 3.7 Have very few end-to-end tests that spans the whole system + +:white_check_mark: **Do:** Although E2E (end-to-end) usually means UI-only testing with a real browser (See bullet 3.6), for other they mean tests that stretch the entire system including the real backend. The latter type of tests is highly valuable as they cover integration bugs between frontend and backend that might happen due to a wrong understanding of the exchange schema. They are also an efficient method to discover backend-to-backend integration issues (e.g. Microservice A sends the wrong message to Microservice B) and even to detect deployment failures - there are no backend frameworks for E2E testing that are as friendly and mature as UI frameworks like [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). The downside of such tests is the high cost of configuring an environment with so many components, and mostly their brittleness - given 50 microservices, even if one fails then the entire E2E just failed. For that reason, we should use this technique sparingly and probably have 1-10 of those and no more. That said, even a small number of E2E tests are likely to catch the type of issues they are targeted for - deployment & integration faults. It's advisable to run those over a production-like staging environment + +
    + +❌ **Otherwise:** UI might invest much in testing its functionality only to realizes very late that the backend returned payload (the data schema the UI has to work with) is very different than expected + +
    + +## ⚪ ️ 3.8 Speed-up E2E tests by reusing login credentials + +:white_check_mark: **Do:** In E2E tests that involve a real backend and rely on a valid user token for API calls, it doesn't payoff to isolate the test to a level where a user is created and logged-in in every request. Instead, login only once before the tests execution start (i.e. before-all hook), save the token in some local storage and reuse it across requests. This seem to violate one of the core testing principle - keep the test autonomous without resources coupling. While this is a valid worry, in E2E tests performance is a key concern and creating 1-3 API requests before starting each individual tests might lead to horrible execution time. Reusing credentials doesn't mean the tests have to act on the same user records - if relying on user records (e.g. test user payments history) than make sure to generate those records as part of the test and avoid sharing their existence with other tests. Also remember that the backend can be faked - if your tests are focused on the frontend it might be better to isolate it and stub the backend API (see bullet 3.6). + +
    + +❌ **Otherwise:** Given 200 test cases and assuming login=100ms = 20 seconds only for logging-in again and again + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Logging-in before-all and not before-each + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +let authenticationToken; + +// happens before ALL tests run +before(() => { + cy.request('POST', 'http://localhost:3000/login', { + username: Cypress.env('username'), + password: Cypress.env('password'), + }) + .its('body') + .then((responseFromLogin) => { + authenticationToken = responseFromLogin.token; + }) +}) + +// happens before EACH test +beforeEach(setUser => () { + cy.visit('/home', { + onBeforeLoad (win) { + win.localStorage.setItem('token', JSON.stringify(authenticationToken)) + }, + }) +}) + +``` + +
    + +
    + +## ⚪ ️ 3.9 Have one E2E smoke test that just travels across the site map + +:white_check_mark: **Do:** For production monitoring and development-time sanity check, run a single E2E test that visits all/most of the site pages and ensures no one breaks. This type of test brings a great return on investment as it's very easy to write and maintain, but it can detect any kind of failure including functional, network and deployment issues. Other styles of smoke and sanity checking are not as reliable and exhaustive - some ops teams just ping the home page (production) or developers who run many integration tests which don't discover packaging and browser issues. Goes without saying that the smoke test doesn't replace functional tests rather just aim to serve as a quick smoke detector + +
    + +❌ **Otherwise:** Everything might seem perfect, all tests pass, production health-check is also positive but the Payment component had some packaging issue and only the /Payment route is not rendering + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Smoke travelling across all pages + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +it("When doing smoke testing over all page, should load them all successfully", () => { + // exemplified using Cypress but can be implemented easily + // using any E2E suite + cy.visit("https://mysite.com/home"); + cy.contains("Home"); + cy.contains("https://mysite.com/Login"); + cy.contains("Login"); + cy.contains("https://mysite.com/About"); + cy.contains("About"); +}); +``` + +
    + +
    + +## ⚪ ️ 3.10 Expose the tests as a live collaborative document + +:white_check_mark: **Do:** Besides increasing app reliability, tests bring another attractive opportunity to the table - serve as live app documentation. Since tests inherently speak at a less-technical and product/UX language, using the right tools they can serve as a communication artifact that greatly aligns all the peers - developers and their customers. For example, some frameworks allow expressing the flow and expectations (i.e. tests plan) using a human-readable language so any stakeholder, including product managers, can read, approve and collaborate on the tests which just became the live requirements document. This technique is also being referred to as 'acceptance test' as it allows the customer to define his acceptance criteria in plain language. This is [BDD (behavior-driven testing)](https://en.wikipedia.org/wiki/Behavior-driven_development) at its purest form. One of the popular frameworks that enable this is [Cucumber which has a JavaScript flavor](https://github.com/cucumber/cucumber-js), see example below. Another similar yet different opportunity, [StoryBook](https://storybook.js.org/), allows exposing UI components as a graphic catalog where one can walk through the various states of each component (e.g. render a grid w/o filters, render that grid with multiple rows or with none, etc), see how it looks like, and how to trigger that state - this can appeal also to product folks but mostly serves as live doc for developers who consume those components. + +❌ **Otherwise:** After investing top resources on testing, it's just a pity not to leverage this investment and win great value + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Describing tests in human-language using cucumber-js + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Examples using Cucumber") + +```javascript +// this is how one can describe tests using cucumber: plain language that allows anyone to understand and collaborate + +Feature: Twitter new tweet + + I want to tweet something in Twitter + + @focus + Scenario: Tweeting from the home page + Given I open Twitter home + Given I click on "New tweet" button + Given I type "Hello followers!" in the textbox + Given I click on "Submit" button + Then I see message "Tweet saved" + +``` + +### :clap: Doing It Right Example: Visualizing our components, their various states and inputs using Storybook + +![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") + +![alt text](assets/story-book.jpg "Storybook") + +
    + +

    + +## ⚪ ️ 3.11 Detect visual issues with automated tools + +:white_check_mark: **Do:** Setup automated tools to capture UI screenshots when changes are presented and detect visual issues like content overlapping or breaking. This ensures that not only the right data is prepared but also the user can conveniently see it. This technique is not widely adopted, our testing mindset leans toward functional tests but it's the visuals what the user experience and with so many device types it's very easy to overlook some nasty UI bug. Some free tools can provide the basics - generate and save screenshots for the inspection of human eyes. While this approach might be sufficient for small apps, it's flawed as any other manual testing that demands human labor anytime something changes. On the other hand, it's quite challenging to detect UI issues automatically due to the lack of clear definition - this is where the field of 'Visual Regression' chime in and solve this puzzle by comparing old UI with the latest changes and detect differences. Some OSS/free tools can provide some of this functionality (e.g. [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>) but might charge significant setup time. The commercial line of tools (e.g. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) takes is a step further by smoothing the installation and packing advanced features like management UI, alerting, smart capturing by eliminating 'visual noise' (e.g. ads, animations) and even root cause analysis of the DOM/CSS changes that led to the issue + +
    + +❌ **Otherwise:** How good is a content page that display great content (100% tests passed), loads instantly but half of the content area is hidden? + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: A typical visual regression - right content that is served badly + +![alt text](assets/amazon-visual-regression.jpeg "Amazon page breaks") + +
    + +### :clap: Doing It Right Example: Configuring wraith to capture and compare UI snapshots + +![](https://img.shields.io/badge/🔨%20Example%20using%20Wraith-blue.svg "Using Wraith") + +``` +​# Add as many domains as necessary. Key will act as a label​ + +domains: + english: "http://www.mysite.com"​ + +​# Type screen widths below, here are a couple of examples​ + +screen_widths: + + - 600​ + - 768​ + - 1024​ + - 1280​ + +​# Type page URL paths below, here are a couple of examples​ +paths: + about: + path: /about + selector: '.about'​ + subscribe: + selector: '.subscribe'​ + path: /subscribe +``` + +### :clap: Doing It Right Example: Using Applitools to get snapshot comparison and other advanced features + +![](https://img.shields.io/badge/🔨%20Example%20using%20AppliTools-blue.svg "Using Applitools") ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +import * as todoPage from "../page-objects/todo-page"; + +describe("visual validation", () => { + before(() => todoPage.navigate()); + beforeEach(() => cy.eyesOpen({ appName: "TAU TodoMVC" })); + afterEach(() => cy.eyesClose()); + + it("should look good", () => { + cy.eyesCheckWindow("empty todo list"); + todoPage.addTodo("Clean room"); + todoPage.addTodo("Learn javascript"); + cy.eyesCheckWindow("two todos"); + todoPage.toggleTodo(0); + cy.eyesCheckWindow("mark as completed"); + }); +}); +``` + +
    + +

    + +# Section 4️⃣: Measuring Test Effectiveness + +

    + +## ⚪ ️ 4.1 Get enough coverage for being confident, ~80% seems to be the lucky number + +:white_check_mark: **Do:** The purpose of testing is to get enough confidence for moving fast, obviously the more code is tested the more confident the team can be. Coverage is a measure of how many code lines (and branches, statements, etc) are being reached by the tests. So how much is enough? 10–30% is obviously too low to get any sense about the build correctness, on the other side 100% is very expensive and might shift your focus from the critical paths to the exotic corners of the code. The long answer is that it depends on many factors like the type of application — if you’re building the next generation of Airbus A380 than 100% is a must, for a cartoon pictures website 50% might be too much. Although most of the testing enthusiasts claim that the right coverage threshold is contextual, most of them also mention the number 80% as a thumb of a rule ([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)) that presumably should satisfy most of the applications. + +Implementation tips: You may want to configure your continuous integration (CI) to have a coverage threshold ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) and stop a build that doesn’t stand to this standard (it’s also possible to configure threshold per component, see code example below). On top of this, consider detecting build coverage decrease (when a newly committed code has less coverage) — this will push developers raising or at least preserving the amount of tested code. All that said, coverage is only one measure, a quantitative based one, that is not enough to tell the robustness of your testing. And it can also be fooled as illustrated in the next bullets + +
    + +❌ **Otherwise:** Confidence and numbers go hand in hand, without really knowing that you tested most of the system — there will also be some fear and fear will slow you down + +
    + +
    Code Examples + +
    + +### :clap: Example: A typical coverage report + +![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "A typical coverage report") + +
    + +### :clap: Doing It Right Example: Setting up coverage per component (using Jest) + +![](https://img.shields.io/badge/🔨%20Example%20using%20Jest-blue.svg "Using Jest") + +![alt text](assets/bp-18-code-coverage2.jpeg "Setting up coverage per component (using Jest)") + +
    + +

    + +## ⚪ ️ 4.2 Inspect coverage reports to detect untested areas and other oddities + +:white_check_mark: **Do:** Some issues sneak just under the radar and are really hard to find using traditional tools. These are not really bugs but more of surprising application behavior that might have a severe impact. For example, often some code areas are never or rarely being invoked — you thought that the ‘PricingCalculator’ class is always setting the product price but it turns out it is actually never invoked although we have 10000 products in DB and many sales… Code coverage reports help you realize whether the application behaves the way you believe it does. Other than that, it can also highlight which types of code is not tested — being informed that 80% of the code is tested doesn’t tell whether the critical parts are covered. Generating reports is easy — just run your app in production or during testing with coverage tracking and then see colorful reports that highlight how frequent each code area is invoked. If you take your time to glimpse into this data — you might find some gotchas +
    + +❌ **Otherwise:** If you don’t know which parts of your code are left un-tested, you don’t know where the issues might come from + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: What’s wrong with this coverage report? + +Based on a real-world scenario where we tracked our application usage in QA and find out interesting login patterns (Hint: the amount of login failures is non-proportional, something is clearly wrong. Finally it turned out that some frontend bug keeps hitting the backend login API) + +![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report?") + +
    + +

    + +## ⚪ ️ 4.3 Measure logical coverage using mutation testing + +:white_check_mark: **Do:** The Traditional Coverage metric often lies: It may show you 100% code coverage, but none of your functions, even not one, return the right response. How come? it simply measures over which lines of code the test visited, but it doesn’t check if the tests actually tested anything — asserted for the right response. Like someone who’s traveling for business and showing his passport stamps — this doesn’t prove any work done, only that he visited few airports and hotels. + +Mutation-based testing is here to help by measuring the amount of code that was actually TESTED not just VISITED. [Stryker](https://stryker-mutator.io/) is a JavaScript library for mutation testing and the implementation is really neat: + +(1) it intentionally changes the code and “plants bugs”. For example the code newOrder.price===0 becomes newOrder.price!=0. This “bugs” are called mutations + +(2) it runs the tests, if all succeed then we have a problem — the tests didn’t serve their purpose of discovering bugs, the mutations are so-called survived. If the tests failed, then great, the mutations were killed. + +Knowing that all or most of the mutations were killed gives much higher confidence than traditional coverage and the setup time is similar +
    + +❌ **Otherwise:** You’ll be fooled to believe that 85% coverage means your test will detect bugs in 85% of your code + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: 100% coverage, 0% testing + +![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Using Stryker") + +```javascript +function addNewOrder(newOrder) { + logger.log(`Adding new order ${newOrder}`); + DB.save(newOrder); + Mailer.sendMail(newOrder.assignee, `A new order was places ${newOrder}`); + + return { approved: true }; +} + +it("Test addNewOrder, don't use such test names", () => { + addNewOrder({ assignee: "John@mailer.com", price: 120 }); +}); //Triggers 100% code coverage, but it doesn't check anything +``` + +
    + +### :clap: Doing It Right Example: Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations) + +![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations)") + +
    + +

    + +## ⚪ ️4.4 Preventing test code issues with Test linters + +:white_check_mark: **Do:** A set of ESLint plugins were built specifically for inspecting the tests code patterns and discover issues. For example, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) will warn when a test is written at the global level (not a son of a describe() statement) or when tests are [skipped](https://mochajs.org/#inclusive-tests) which might lead to a false belief that all tests are passing. Similarly, [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) can, for example, warn when a test has no assertions at all (not checking anything) + +
    + +❌ **Otherwise:** Seeing 90% code coverage and 100% green tests will make your face wear a big smile only until you realize that many tests aren’t asserting for anything and many test suites were just skipped. Hopefully, you didn’t deploy anything based on this false observation + +
    +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: A test case full of errors, luckily all are caught by Linters + +```javascript +describe("Too short description", () => { + const userToken = userService.getDefaultToken() // *error:no-setup-in-describe, use hooks (sparingly) instead + it("Some description", () => {});//* error: valid-test-description. Must include the word "Should" + at least 5 words +}); + +it.skip("Test name", () => {// *error:no-skipped-tests, error:error:no-global-tests. Put tests only under describe or suite + expect("somevalue"); // error:no-assert +}); + +it("Test name", () => {*//error:no-identical-title. Assign unique titles to tests +}); +``` + +
    + +

    + +# Section 5️⃣: CI and Other Quality Measures + +

    + +## ⚪ ️ 5.1 Enrich your linters and abort builds that have linting issues + +:white_check_mark: **Do:** Linters are a free lunch, with 5 min setup you get for free an auto-pilot guarding your code and catching significant issue as you type. Gone are the days where linting was about cosmetics (no semi-colons!). Nowadays, Linters can catch severe issues like errors that are not thrown correctly and losing information. On top of your basic set of rules (like [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) or [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), consider including some specializing Linters like [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) that can discover tests without assertions, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) can discover promises with no resolve (your code will never continue), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) which can discover eager regex expressions that might get used for DOS attacks, and [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) is capable of alarming when the code uses utility library methods that are part of the V8 core methods like Lodash.\_map(…) +
    + +❌ **Otherwise:** Consider a rainy day where your production keeps crashing but the logs don’t display the error stack trace. What happened? Your code mistakenly threw a non-error object and the stack trace was lost, a good reason for banging your head against a brick wall. A 5 min linter setup could detect this TYPO and save your day + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug + +![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug") + +
    + +

    + +## ⚪ ️ 5.2 Shorten the feedback loop with local developer-CI + +:white_check_mark: **Do:** Using a CI with shiny quality inspections like testing, linting, vulnerabilities check, etc? Help developers run this pipeline also locally to solicit instant feedback and shorten the [feedback loop](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). Why? an efficient testing process constitutes many and iterative loops: (1) try-outs -> (2) feedback -> (3) refactor. The faster the feedback is, the more improvement iterations a developer can perform per-module and perfect the results. On the flip, when the feedback is late to come fewer improvement iterations could be packed into a single day, the team might already move forward to another topic/task/module and might not be up for refining that module. + +Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) allow running the pipeline locally. Some commercial tools like [wallaby provide highly-valuable & testing insights](https://wallabyjs.com/) as a developer prototype (no affiliation). Alternatively, you may just add npm script to package.json that runs all the quality commands (e.g. test, lint, vulnerabilities) — use tools like [concurrently](https://www.npmjs.com/package/concurrently) for parallelization and non-zero exit code if one of the tools failed. Now the developer should just invoke one command — e.g. ‘npm run quality’ — to get instant feedback. Consider also aborting a commit if the quality check failed using a githook ([husky can help](https://github.com/typicode/husky)) +
    + +❌ **Otherwise:** When the quality results arrive the day after the code, testing doesn’t become a fluent part of development rather an after the fact formal artifact + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: npm scripts that perform code quality inspection, all are run in parallel on demand or when a developer is trying to push new code + +```javascript +"scripts": { + "inspect:sanity-testing": "mocha **/**--test.js --grep \"sanity\"", + "inspect:lint": "eslint .", + "inspect:vulnerabilities": "npm audit", + "inspect:license": "license-checker --failOn GPLv2", + "inspect:complexity": "plato .", + + "inspect:all": "concurrently -c \"bgBlue.bold,bgMagenta.bold,yellow\" \"npm:inspect:quick-testing\" \"npm:inspect:lint\" \"npm:inspect:vulnerabilities\" \"npm:inspect:license\"" + }, + "husky": { + "hooks": { + "precommit": "npm run inspect:all", + "prepush": "npm run inspect:all" + } +} + +``` + +
    + +

    + +## ⚪ ️5.3 Perform e2e testing over a true production-mirror + +:white_check_mark: **Do:** End to end (e2e) testing are the main challenge of every CI pipeline — creating an identical ephemeral production mirror on the fly with all the related cloud services can be tedious and expensive. Finding the best compromise is your game: [Docker-compose](https://serverless.com/) allows crafting isolated dockerized environment with identical containers using a single plain text file but the backing technology (e.g. networking, deployment model) is different from real-world productions. You may combine it with [‘AWS Local’](https://github.com/localstack/localstack) to work with a stub of the real AWS services. If you went [serverless](https://serverless.com/) multiple frameworks like serverless and [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) allows the local invocation of FaaS code. + +The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for local and CI-mirroring though many new tools are launched frequently. One approach is running a ‘minimized-Kubernetes’ using tools like [Minikube](https://kubernetes.io/docs/setup/minikube/) and [MicroK8s](https://microk8s.io/) which resemble the real thing only come with less overhead. Another approach is testing over a remote ‘real-Kubernetes’, some CI providers (e.g. [Codefresh](https://codefresh.io/)) has native integration with Kubernetes environment and make it easy to run the CI pipeline over the real thing, others allow custom scripting against a remote Kubernetes. +
    + +❌ **Otherwise:** Using different technologies for production and testing demands maintaining two deployment models and keeps the developers and the ops team separated + +
    + +
    Code Examples + +
    + +### :clap: Example: a CI pipeline that generates Kubernetes cluster on the fly ([Credit: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/)) + +
    deploy:
    stage: deploy
    image: registry.gitlab.com/gitlab-examples/kubernetes-deploy
    script:
    - ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN
    - kubectl create ns $NAMESPACE
    - kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL"
    - mkdir .generated
    - echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF"
    - sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml"
    - kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml
    - kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml
    environment:
    name: test-for-ci
    + +
    + +

    + +## ⚪ ️5.4 Parallelize test execution + +:white_check_mark: **Do:** When done right, testing is your 24/7 friend providing almost instant feedback. In practice, executing 500 CPU-bounded unit test on a single thread can take too long. Luckily, modern test runners and CI platforms (like [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) and [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) can parallelize the test into multiple processes and achieve significant improvement in feedback time. Some CI vendors do also parallelize tests across containers (!) which shortens the feedback loop even further. Whether locally over multiple processes, or over some cloud CLI using multiple machines — parallelizing demand keeping the tests autonomous as each might run on different processes + +❌ **Otherwise:** Getting test results 1 hour long after pushing new code, as you already code the next features, is a great recipe for making testing less relevant + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) + +![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization (Credit: JavaScript Test-Runners Benchmark)") + +
    + +

    + +## ⚪ ️5.5 Stay away from legal issues using license and plagiarism check + +:white_check_mark: **Do:** Licensing and plagiarism issues are probably not your main concern right now, but why not tick this box as well in 10 minutes? A bunch of npm packages like [license check](https://www.npmjs.com/package/license-checker) and [plagiarism check](https://www.npmjs.com/package/plagiarism-checker) (commercial with free plan) can be easily baked into your CI pipeline and inspect for sorrows like dependencies with restrictive licenses or code that was copy-pasted from Stack Overflow and apparently violates some copyrights + +❌ **Otherwise:** Unintentionally, developers might use packages with inappropriate licenses or copy paste commercial code and run into legal issues + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: + +```javascript +//install license-checker in your CI environment or also locally +npm install -g license-checker + +//ask it to scan all licenses and fail with exit code other than 0 if it found unauthorized license. The CI system should catch this failure and stop the build +license-checker --summary --failOn BSD + +``` + +
    + +![alt text](assets/bp-25-nodejs-licsense.png) + +
    + +

    + +## ⚪ ️5.6 Constantly inspect for vulnerable dependencies + +:white_check_mark: **Do:** Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using community tools such as [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), or commercial tools like [snyk](https://snyk.io/) (offer also a free community version). Both can be invoked from your CI on every build + +❌ **Otherwise:** Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online publications about new threats. Quite tedious + +
    + +
    Code Examples + +
    + +### :clap: Example: NPM Audit result + +![alt text](assets/bp-26-npm-audit-snyk.png "NPM Audit result") + +
    + +

    + +## ⚪ ️5.7 Automate dependency updates + +:white_check_mark: **Do:** Yarn and npm latest introduction of package-lock.json introduced a serious challenge (the road to hell is paved with good intentions) — by default now, packages are no longer getting updates. Even a team running many fresh deployments with ‘npm install’ & ‘npm update’ won’t get any new updates. This leads to subpar dependent packages versions at best or to vulnerable code at worst. Teams now rely on developers goodwill and memory to manually update the package.json or use tools [like ncu](https://www.npmjs.com/package/npm-check-updates) manually. A more reliable way could be to automate the process of getting the most reliable dependency versions, though there are no silver bullet solutions yet there are two possible automation roads: + +(1) CI can fail builds that have obsolete dependencies — using tools like [‘npm outdated’](https://docs.npmjs.com/cli/outdated) or ‘npm-check-updates (ncu)’ . Doing so will enforce developers to update dependencies. + +(2) Use commercial tools that scan the code and automatically send pull requests with updated dependencies. One interesting question remaining is what should be the dependency update policy — updating on every patch generates too many overhead, updating right when a major is released might point to an unstable version (many packages found vulnerable on the very first days after being released, [see the](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) eslint-scope incident). + +An efficient update policy may allow some ‘vesting period’ — let the code lag behind the @latest for some time and versions before considering the local copy as obsolete (e.g. local version is 1.3.1 and repository version is 1.3.8) +
    + +❌ **Otherwise:** Your production will run packages that have been explicitly tagged by their author as risky + +
    + +
    Code Examples + +
    + +### :clap: Example: [ncu](https://www.npmjs.com/package/npm-check-updates) can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions + +![alt text](assets/bp-27-yoni-goldberg-npm.png "ncu can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions") + +
    + +

    + +## ⚪ ️ 5.8 Other, non-Node related, CI tips + +: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 few non-Node related tips that are well-known + +
    1. Use a declarative syntax. This is the only option for most vendors but older versions of Jenkins allows using code or UI
    2. Opt for a vendor that has native Docker support
    3. Fail early, run your fastest tests first. Create a ‘Smoke testing’ step/milestone that groups multiple fast inspections (e.g. linting, unit tests) and provide snappy feedback to the code committer
    4. Make it easy to skim-through all build artifacts including test reports, coverage reports, mutation reports, logs, etc
    5. Create multiple pipelines/jobs for each event, reuse steps between them. For example, configure a job for feature branch commits and a different one for master PR. Let each reuse logic using shared steps (most vendors provide some mechanism for code reuse)
    6. Never embed secrets in a job declaration, grab them from a secret store or from the job’s configuration
    7. Explicitly bump version in a release build or at least ensure the developer did so
    8. Build only once and perform all the inspections over the single build artifact (e.g. Docker image)
    9. Test in an ephemeral environment that doesn’t drift state between builds. Caching node_modules might be the only exception
    +
    + +❌ **Otherwise:** You‘ll miss years of wisdom + +

    + +## ⚪ ️ 5.9 Build matrix: Run the same CI steps using multiple Node versions + +:white_check_mark: **Do:** Quality checking is about serendipity, the more ground you cover the luckier you get in detecting issues early. When developing reusable packages or running a multi-customer production with various configuration and Node versions, the CI must run the pipeline of tests over all the permutations of configurations. For example, assuming we use MySQL for some customers and Postgres for others — some CI vendors support a feature called ‘Matrix’ which allow running the suit of testing against all permutations of MySQL, Postgres and multiple Node version like 8, 9 and 10. This is done using configuration only without any additional effort (assuming you have testing or any other quality checks). Other CIs who doesn’t support Matrix might have extensions or tweaks to allow that +
    + +❌ **Otherwise:** So after doing all that hard work of writing testing are we going to let bugs sneak in only because of configuration issues? + +
    + +
    Code Examples + +
    + +### :clap: Example: Using Travis (CI vendor) build definition to run the same test over multiple Node versions + +
    language: node_js
    node_js:
    - "7"
    - "6"
    - "5"
    - "4"
    install:
    - npm install
    script:
    - npm run test
    +
    + +

    + +# Team + +## Yoni Goldberg + +
    + +
    + +**Role:** Writer + +**About:** I'm an independent consultant who works with Fortune 500 companies and garage startups on polishing their JS & Node.js applications. More than any other topic I'm fascinated by and aims to master the art of testing. I'm also the author of [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices) + +**📗 Online Course:** Liked this guide and wish to take your testing skills to the extreme? Consider visiting my comprehensive course [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) + +
    + +**Follow:** + +- [🐦 Twitter](https://twitter.com/goldbergyoni/) +- [📞 Contact](https://testjavascript.com/contact-2/) +- [✉️ Newsletter](https://testjavascript.com/newsletter//) + +
    +
    +
    + +## [Bruno Scheufler](https://github.com/BrunoScheufler) + +**Role:** Tech reviewer and advisor + +Took care to revise, improve, lint and polish all the texts + +**About:** full-stack web engineer, Node.js & GraphQL enthusiast + +
    +
    + +## [Ido Richter](https://github.com/idori) + +**Role:** Concept, design and great advice + +**About:** A savvy frontend developer, CSS expert and emojis freak + +## [Kyle Martin](https://github.com/js-kyle) + +**Role:** Helps keep this project running, and reviews security related practices + +**About:** Loves working on Node.js projects and web application security. + +## Contributors ✨ + +Thanks goes to these wonderful people who have contributed to this repository! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Scott Davis

    🖋

    Adrien REDON

    🖋

    Stefano Magni

    🖋

    Yeoh Joer

    🖋

    Jhonny Moreira

    🖋

    Ian Germann

    🖋

    Hafez

    🖋

    Ruxandra Fediuc

    🖋

    Jack

    🖋

    Peter Carrero

    🖋

    Huhgawz

    🖋

    Haakon Borch

    🖋

    Jaime Mendoza

    🖋

    Cameron Dunford

    🖋

    John Gee

    🖋

    Aurelijus Rožėnas

    🖋

    Aaron

    🖋

    Tom Nagle

    🖋

    Yves yao

    🖋

    Userbit

    🖋

    Glaucia Lemos

    🚧

    koooge

    🖋

    Michal

    🖋

    roywalker

    🖋

    dangen

    🖋

    biesiadamich

    🖋

    Yanlin Jiang

    🖋

    sanguino

    🖋

    Morgan

    🖋

    Lukas Bischof

    ⚠️ 🖋

    JuanMa Ruiz

    🖋

    Luís Ângelo Rodrigues Jr.

    🖋

    José Fernández

    🖋

    Alejandro Gutierrez Barcenilla

    🖋

    Jason

    🖋
    + + + + From aba84d7c8eee67a509b2b5da5a251244cd931b18 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Fri, 21 May 2021 18:03:42 +0200 Subject: [PATCH 002/189] Introduction translation --- readme-fr.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index f75e1ab3..adbe555a 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -2,29 +2,29 @@
    -# 👇 Why this guide can take your testing skills to the next level +# 👇 Pourquoi ce guide peut faire passer vos compétences de test au niveau supérieur
    -## 📗 46+ best practices: Super-comprehensive and exhaustive +## 📗 46+ bonnes pratiques : complet et exhaustif -This 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 +Ceci est un guide complet pour Javascript & Node.js de A à Z. Il résume et organise pour vous les meilleurs articles de blogs, livres et outils du marché -## 🚢 Advanced: Goes 10,000 miles beyond the basics +## 🚢 Avancé : va bien au-delà des bases -Hop 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 +Embarque pour un voyage qui va bien au-delà des bases et aborde des sujets avancés tels que les tests en production, les tests de mutations, les tests basés sur les propriétés et de nombreux autres outils stratégiques et professionnels. Si vous lisez chaque mot de ce guide, vos compétences de tests seront probablement bien au-dessus la moyenne. -## 🌐 Full-stack: front, backend, CI, anything +## 🌐 Full-stack: front, backend, CI ... -Start by understanding the ubiquitous testing practices that are the foundation for any application tier. Then, delve into your area of choice: frontend/UI, backend, CI or maybe all of them? +Commence par comprendre les pratiques de tests omniprésentes qui sont à la base de tout niveau d'application. Ensuite, plonge dans ton domaine de prédilection : frontend/UI, backend, CI ou peut-être tous cela ?
    -### Written By Yoni Goldberg +### Écrit par Yoni Goldberg -- A JavaScript & Node.js consultant -- 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - My comprehensive online course with more than [10 hours of video](https://www.testjavascript.com), 14 test types and more than 40 best practices -- [Follow me on Twitter ](https://twitter.com/goldbergyoni/) +- Un consultant JavaScript & Node.js +- 📗 [Les tests Node.js & JavaScript de A à Z](https://www.testjavascript.com) - Mon cours en ligne complet avec plus de [10 heures de video](https://www.testjavascript.com), 14 types de tests et plus de 40 bonnes pratiques +- [Suis-moi sur Twitter ](https://twitter.com/goldbergyoni/)
    From 5cc16450fa53af7e0e0e23ff909b64041ff9bfb2 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Thu, 27 May 2021 08:28:01 +0200 Subject: [PATCH 003/189] Translation section + link towards french in the english version --- readme-fr.md | 16 ++++++++-------- readme.md | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index adbe555a..36e9d72e 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -28,14 +28,14 @@ Commence par comprendre les pratiques de tests omniprésentes qui sont à la bas
    -### Translations - read in your own language - -- 🇨🇳[Chinese](readme-zh-CN.md) - Courtesy of [Yves yao](https://github.com/yvesyao) -- 🇰🇷[Korean](readme.kr.md) - Courtesy of [Rain Byun](https://github.com/ragubyun) -- 🇵🇱[Polish](readme-pl.md) - Courtesy of [Michal Biesiada](https://github.com/mbiesiad) -- 🇪🇸[Spanish](readme-es.md) - Courtesy of [Miguel G. Sanguino](https://github.com/sanguino) -- 🇧🇷[Portuguese-BR](readme-pt-br.md) - Courtesy of [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) -- Want to translate to your own language? please open an issue 💜 +### Traductions - Lis dans la langue de ton choix +- 🇬🇧[Anglais](readme.md) +- 🇨🇳[Chinois](readme-zh-CN.md) - Traduit par [Yves yao](https://github.com/yvesyao) +- 🇰🇷[Coréen](readme.kr.md) - Traduit par [Rain Byun](https://github.com/ragubyun) +- 🇵🇱[Polonais](readme-pl.md) - Traduit par [Michal Biesiada](https://github.com/mbiesiad) +- 🇪🇸[Espagnol](readme-es.md) - Traduit par [Miguel G. Sanguino](https://github.com/sanguino) +- 🇧🇷[Portugais brésilien](readme-pt-br.md) - Traduit par [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) et [koooge](https://github.com/koooge) +- Envie de traduire dans ta propre langue ? Ouvres une issue 💜

    diff --git a/readme.md b/readme.md index f75e1ab3..5268fbf9 100644 --- a/readme.md +++ b/readme.md @@ -35,6 +35,7 @@ Start by understanding the ubiquitous testing practices that are the foundation - 🇵🇱[Polish](readme-pl.md) - Courtesy of [Michal Biesiada](https://github.com/mbiesiad) - 🇪🇸[Spanish](readme-es.md) - Courtesy of [Miguel G. Sanguino](https://github.com/sanguino) - 🇧🇷[Portuguese-BR](readme-pt-br.md) - Courtesy of [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) +- 🇫🇷[French](readme-fr.md) - Courtesy of [Mathilde El Mouktafi](https://github.com/mel-mouk) - Want to translate to your own language? please open an issue 💜

    From d9006c57ebd38512420ba36c9a1d70ac0e2d1f85 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Thu, 27 May 2021 17:11:56 +0200 Subject: [PATCH 004/189] Translate table of content --- readme-fr.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 36e9d72e..e0f644dd 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -16,7 +16,7 @@ Embarque pour un voyage qui va bien au-delà des bases et aborde des sujets avan ## 🌐 Full-stack: front, backend, CI ... -Commence par comprendre les pratiques de tests omniprésentes qui sont à la base de tout niveau d'application. Ensuite, plonge dans ton domaine de prédilection : frontend/UI, backend, CI ou peut-être tous cela ? +Commence par comprendre les pratiques de tests omniprésentes qui sont à la base de tout niveau d'application. Ensuite, plonge dans ton domaine de prédilection : frontend/UI, backend, CI ou peut-être tous ça ?
    @@ -39,31 +39,31 @@ Commence par comprendre les pratiques de tests omniprésentes qui sont à la bas

    -## `Table of Contents` +## `Table des matières` -#### [`Section 0: The Golden Rule`](#section-0️⃣-the-golden-rule) +#### [`Section 0: La règle d'or`](#section-0️⃣-the-golden-rule) -A single advice that inspires all the others (1 special bullet) +Un seul conseil qui inspire tout les autres (1 point spécial) -#### [`Section 1: The Test Anatomy`](#section-1-the-test-anatomy-1) +#### [`Section 1: Anatomie d'un test`](#section-1-the-test-anatomy-1) -The foundation - structuring clean tests (12 bullets) +La base - structurer des tests propre (12 points) #### [`Section 2: Backend`](#section-2️⃣-backend-testing) -Writing backend and Microservices tests efficiently (8 bullets) +Écrire efficacement des tests backend et de microservices (8 points) #### [`Section 3: Frontend`](#section-3️⃣-frontend-testing) -Writing tests for web UI including component and E2E tests (11 bullets) +Écrire des tests pour l'interface utilisateur, y compris des tests de composants et des tests E2E (11 points) -#### [`Section 4: Measuring Tests Effectiveness`](#section-4️⃣-measuring-test-effectiveness) +#### [`Section 4: Mesurer l'efficacité des tests`](#section-4️⃣-measuring-test-effectiveness) -Watching the watchman - measuring test quality (4 bullets) +Surveiller le surveillant - mesurer la qualité des tests (4 points) -#### [`Section 5: Continuous Integration`](#section-5️⃣-ci-and-other-quality-measures) +#### [`Section 5: Intégration continue`](#section-5️⃣-ci-and-other-quality-measures) -Guidelines for CI in the JS world (9 bullets) +Lignes directrices pour l'intégration continue dans le monde du JS (9 points)

    From d821333fc93a4a4c90b45eb99564180a6514302e Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Thu, 27 May 2021 17:42:15 +0200 Subject: [PATCH 005/189] Section 0 --- readme-fr.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index e0f644dd..8808c2f7 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -67,26 +67,27 @@ Lignes directrices pour l'intégration continue dans le monde du JS (9 points)

    -# Section 0️⃣: The Golden Rule +# Section 0️⃣: La règle d'or
    -## ⚪️ 0 The Golden Rule: Design for lean testing +## ⚪️ 0 La règle d'or: Concevoir des tests minimalistes :white_check_mark: **Do:** -Testing code is not like production-code - design it to be dead-simple, short, abstraction-free, flat, delightful to work with, lean. One should look at a test and get the intent instantly. +Le code des tests n'est pas comme le code de production - conçoit le pour être simple, court, sans abstraction, agréable à utiliser et minimaliste. En regardant le code d'un test, on doit pouvoir comprendre son but instantanément. -Our minds are full with the main production code, we don't have 'headspace' for additional complexity. Should we try to squeeze yet another challenging code 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. +Nos esprits sont déjà occupés avec le code de production, on n'a pas "d'espace" pour de la complexité additionnelle. Si on essaye d'insérer un autre code compliqué dans nos pauvres cerveaux, l'équipe va être ralentie ce qui est en contradiction avec la raison pour laquelle on fait des tests. +En pratique, c'est là que de nombreuses équipes abandonnent tout simplement les tests. -The tests are an opportunity for something else - a friendly and smiley assistant, one that it's delightful to work with and delivers great value for such 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 which 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). +Les tests sont une opportunité pour autre chose - un assistant amical et souriant, un avec qui il est agréable de travailler et qui nous apporte beaucoup pour peu d'investissement. La science nous dit que l'on a deux systèmes cérébraux : le premier est utilisé pour les activités qui ne demandent pas d'effort comme conduire une voiture sur une route vide ; le deuxième sert aux opérations complexe et conscientes comme résoudre une équation mathématique. Conçois tes tests pour le premier système, lire un test doit _sembler_ aussi simple que de modifier un fichier HTML, et pas comme résoudre 2X(17 x 24). -This 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, strive to keep it nimble, sometimes it's even worth dropping some tests and trade reliability for agility and simplicity. +On peut y arriver en sélectionnant des techniques, des outils et des cibles de tests qui sont rentables et offrent un bon retour sur investissement. Test seulement ce qui doit être testé, essaye de conserver de la souplesse, et parfois, il vaut même mieux supprimer quelques tests et échanger la fiabilité contre de l'agilité et de la simplicité. -![alt text](/assets/headspace.png "We have no head room for additional complexity") +![alt text](/assets/headspace.png "On a pas de place disponible pour une complexité supplémentaire") -Most of the advice below are derivatives of this principle. +La plupart des conseils ci-dessous sont des dérivés de ce principe. -### Ready to start? +### Prêt à commencer ?

    From 3bdd161b6ee536bca309acd34d82a73021178358 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Wed, 16 Jun 2021 00:18:44 +0200 Subject: [PATCH 006/189] Translate 1.1 --- readme-fr.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 8808c2f7..b9755443 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -91,34 +91,34 @@ La plupart des conseils ci-dessous sont des dérivés de ce principe.

    -# Section 1: The Test Anatomy +# Section 1: Anatomie d'un test
    -## ⚪ ️ 1.1 Include 3 parts in each test name +## ⚪ ️ 1.1 Chaque nom devrait contenir 3 parties -: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: +:white_check_mark: **À faire:** Un rapport de test devrait indiquer si la version actuelle de l'application correspond aux attentes pour des personnes qui ne sont pas forcément familier avec la base de code : le testeur, le dev ops qui deploie et toi dans 2 ans. Dans ce but, les noms des tests doivent expliciter les attentes et inclure 3 parties : -(1) What is being tested? For example, the ProductsService.addNewProduct method +(1) Qu'est-ce qui est testé ? Par exemple, la méthode ProductService.addNewProduct -(2) Under what circumstances and scenario? For example, no price is passed to the method +(2) Dans quel circonstance et scénario ? Par exemple, aucun prix n'est passé à la méthode -(3) What is the expected result? For example, the new product is not approved +(3) Quel est le résultat attendu ? Par exemple, le produit n'est pas approuvé
    -❌ **Otherwise:** A deployment just failed, a test named “Add product” failed. Does this tell you what exactly is malfunctioning? +❌ **Autrement:** Un deploiement a échoué, un test appelé "Add product" à échoué. Est-ce que celà indique exactement ce qui ne fonctionne plus correctement ?
    -**👇 Note:** Each bullet has code examples and sometime also an image illustration. Click to expand +**👇 Note:** Chaque point contient des exemples de codes et parfois une image d'illustration. Cliques pour agrandir.
    Code Examples
    -### :clap: Doing It Right Example: A test name that constitutes 3 parts +### :clap: Bien faire les choses Exemple: Un nom de test constitué de 3 parties ![](https://img.shields.io/badge/🔨%20Example%20using%20Mocha-blue.svg "Using Mocha to illustrate the idea") @@ -138,7 +138,7 @@ describe('Products Service', function() {
    -### :clap: Doing It Right Example: A test name that constitutes 3 parts +### :clap: Bien faire les choses Exemple: Un nom de test constitué de 3 parties ![alt text](/assets/bp-1-3-parts.jpeg "A test name that constitutes 3 parts") From cd7e5a3dc1b018a794bd452526fef1224c8b717b Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Wed, 16 Jun 2021 00:40:52 +0200 Subject: [PATCH 007/189] Translate 1.2 --- readme-fr.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index b9755443..4c0b31c4 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -151,19 +151,20 @@ describe('Products Service', function() {

    -## ⚪ ️ 1.2 Structure tests by the AAA pattern +## ⚪ ️ 1.2 Structurer les tests avec le pattern AAA -: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: +:white_check_mark: **À faire:** Structures tes tests avec 3 sections séparés: Organiser, Agir & Vérifier (Arrange, Act & Assert: AAA). Suivre cette structure garantit que le lecteur n'utilise pas de "CPU" de cerveau pour comprendre le plan du test: -1st 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/stubbing on objects and any other preparation code +1er A - Organiser (Arrange): Tout le code permettant de configurer le système selon le scénario qui doit être simulé. Cela peut inclure d'instancier le constructeur de l'élément testé, ajouter des entrées en DB, mocking/stubbing des objets et autre codes de préparation -2nd A - Act: Execute the unit under test. Usually 1 line of code +2ème A - Agir (Act): Exécute l'élément testé. En général 1 seule ligne de code -3rd A - Assert: Ensure that the received value satisfies the expectation. Usually 1 line of code +3éme A - Vérifier (Assert): Vérifier que les valeurs reçues correspondent aux attentes. En général 1 seule ligne de code
    -❌ **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 +❌ **Autrement:** Non seulement vous avez passé des heures à comprendre le code principal, mais en plus ce qui devait être la partie la plus simple de la journée (tester) vous tord le cerveau. +
    @@ -171,7 +172,7 @@ describe('Products Service', function() {
    -### :clap: Doing It Right Example: A test structured with the AAA pattern +### :clap: Bien faire les choses Exemple: Un test structuré avec le pattern AAA ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") @@ -193,7 +194,7 @@ describe("Customer classifier", () => {
    -### :thumbsdown: Anti-Pattern Example: No separation, one bulk, harder to interpret +### :thumbsdown: Exemple d'anti pattern: Pas de séparation, un bloc, plus dur à interpréter ```javascript test("Should be classified as premium", () => { From 4874247a7d1c545ae6a738704445dde1dbc7632e Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Wed, 16 Jun 2021 00:50:44 +0200 Subject: [PATCH 008/189] Translate 1.3 --- readme-fr.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 4c0b31c4..5d93470f 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -209,20 +209,21 @@ test("Should be classified as premium", () => {

    -## ⚪ ️1.3 Describe expectations in a product language: use BDD-style assertions +## ⚪ ️1.3 Décrire les attentes dans un language produit: Utiliser des assertions de type BDD + +:white_check_mark: **À faire:** Coder tes tests dans un language déclaratif permet au lecteur de comprendre immédiatement sans effectuer un seul cycle de "CPU" de cerveau. Lorsque tu écris du code impératif remplit de logique conditionnelles, le lecteur est forcé d'utiliser plus de cycles de "CPU" de cerveau. Dans ce cas, codes les attentes dans un language similaire au language humain, dans un style déclaratif de type BDD avec `expect` ou `should` et sans utiliser de code custom. Si Chai et Jest n'incluent pas les assertions nécéssaires et qu'elles reviennent régulièrement, considère [d'étendre Jest matcher (Jest)](https://jestjs.io/docs/en/expect#expectextendmatchers) ou d'écrire un [plugin Chai custom](https://www.chaijs.com/guide/plugins/) -: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://jestjs.io/docs/en/expect#expectextendmatchers) or writing a [custom Chai plugin](https://www.chaijs.com/guide/plugins/)
    -❌ **Otherwise:** The team will write less tests and decorate the annoying ones with .skip() +❌ **Autrement:** L'équipe écrira moins de tests et décorera ceux qui sont ennuyeux avec .skip()
    -
    Code Examples
    +
    Exemple de code
    ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") -### :thumbsdown: Anti-Pattern Example: The reader must skim through not so short, and imperative code just to get the test story +### :thumbsdown: Exemple d'anti pattern: Le lecteur doit parcourir un long code impératif juste pour comprendre l'histoire du test ```javascript test("When asking for an admin, ensure only ordered admins in results", () => { @@ -252,7 +253,7 @@ test("When asking for an admin, ensure only ordered admins in results", () => {
    -### :clap: Doing It Right Example: Skimming through the following declarative test is a breeze +### :clap: Bien faire les choses Exemple: Parcourir le test déclaratif suivant est un jeu d'enfant ```javascript it("When asking for an admin, ensure only ordered admins in results", () => { From 781eac6ac2b199cf852507782d342d695e72230e Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Fri, 18 Jun 2021 16:24:46 +0200 Subject: [PATCH 009/189] Translate 1.4 --- readme-fr.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 5d93470f..dcc75dbd 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -168,7 +168,7 @@ describe('Products Service', function() {
    -
    Code Examples +
    Exemple de code
    @@ -270,19 +270,19 @@ it("When asking for an admin, ensure only ordered admins in results", () => {

    -## ⚪ ️ 1.4 Stick to black-box testing: Test only public methods +## ⚪ ️ 1.4 S'en tenir aux tests des boites noires: Ne teste que les méthodes publiques -:white_check_mark: **Do:** Testing the internals brings huge overhead for almost nothing. If your code/API 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 +:white_check_mark: **À faire:** Tester les composants internes apporte beaucoup de complexité pour presque rien. Si ton code/API délivre les bon resultats, est-ce que tu dois vraiment passer les 3 prochaines heures à tester COMMENT il fonctionne et maintenir ces tests ? À chaque fois qu'un comportement publique est testé, l'implementation privée est aussi testé implicitement, et test tests n'échoueront que si il y a un certain problème (par exemple: mauvais retour). Cette approche est aussi appelé `behavioral testing` (test de comportement). De l'autre coté, si tu dois tester les éléments internes (approche de la boîte blanche) - l'objectif passe de planifier le résultat du composant à des détails de bases, et votre test peut échouer à cause de refactoring mineurs alors que le résultat est toujours bon - cela augmente la charge de maintenance.
    -❌ **Otherwise:** Your tests behave like the [boy who cried wolf](https://en.wikipedia.org/wiki/The_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… +❌ **Autrement:** Tes tests se comportent comme [l'enfant qui criait au loup](https://fr.wikipedia.org/wiki/L%27Enfant_qui_criait_au_loup): crier des faux positifs (par exemple, un test échoue parce qu'un nom de variable privé à été changé). Sans surprise, les gens vont rapidement ignorer les notifications, jusqu'à ce qu'un jour, un vrai beug soit ignoré
    -
    Code Examples +
    Exemple de code
    -### :thumbsdown: Anti-Pattern Example: A test case is testing the internals for no good reason +### :thumbsdown: Exemple d'anti pattern: Un cas qui test une méthode interne sans raison valable ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") From fc62f52f393ecd7ee110261ff2fed54cf1b639e7 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Fri, 18 Jun 2021 16:46:41 +0200 Subject: [PATCH 010/189] Translate 1.5 --- readme-fr.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index dcc75dbd..5a99026a 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -312,24 +312,24 @@ it("White-box test: When the internal methods get 0 vat, it return 0 response",

    -## ⚪ ️ ️1.5 Choose the right test doubles: Avoid mocks in favor of stubs and spies +## ⚪ ️ ️1.5 Choisir les bons "test doubles": Éviter les mocks en faveur des stubs et spies -:white_check_mark: **Do:** Test doubles are a necessary evil because they are coupled to the application internals, yet some provide immense value ([Read here a reminder about test doubles: mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)). +:white_check_mark: **À faire:** Les "test doubles" sont un mal nécéssaire parce qu'il sont couplé aux composants internes mais apportent néanmoins beaucoup de valeur ([Retrouve ici un rappel à propos des "test doubles": mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)). -Before 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 no, it’s a white-box testing smell. +Avant d'utiliser des "test doubles", pose toi une question trés simple: Est-ce que je l'utilise pour tester une fonctionnalité qui apparait, ou peut apparaitre, dans le document de spécification ? Si non, ça sent le test de boite blanche. -For 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/response/outcome 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 +Par exemple, si tu veux tester que ton application se comporte correctement quand le service de paiement est coupé, tu peux faire un stub du service de paiement et déclencher une réponse de type 'No Response' pour vérifier que l'unité testée retourne la bonne valeur. Cela vérifie le comportement/réponse de notre application suivant un certain scénario. Tu peux aussi utiliser un spy pour vérifier qu'un email a bien été envoyé quand ce service était coupé - il s'agit encore une fois d'un test de comportement qui pourrait apparaitre dans les spécification ("Envoyer un email si le paiement n'as pas pu être enregistré"). +D'un autre coté, si tu mock le service de paiement pour vérifié qu'il a bien été appelé avec le bon type Javascript, alors ton test est orienté sur des comportements internes qui n'ont rien à voir avec les fonctionnalités de l'application et changeront probablement fréquemment.
    -❌ **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 - +❌ **Autrement:** Chaque refactoring du code implique de chercher l'ensemble des mock dans le code afin de les mettre à jour. Les tests deviennent une corvée plutôt qu'un ami aidant.
    -
    Code Examples +
    Exemple de code
    -### :thumbsdown: Anti-pattern example: Mocks focus on the internals +### :thumbsdown: Exemple d'anti pattern: Les mocks se concentrent sur des composants internes ![](https://img.shields.io/badge/🔧%20Example%20using%20Sinon-blue.svg "Examples with Sinon") @@ -349,7 +349,7 @@ it("When a valid product is about to be deleted, ensure data access DAL was call
    -### :clap:Doing It Right Example: spies are focused on testing the requirements but as a side-effect are unavoidably touching to the internals +### :clap: Faire les choses bien, exemple : Les spies se concentrent sur les fonctionnalités requises mais touchent les composants internes par effet de bord ```javascript it("When a valid product is about to be deleted, ensure an email is sent", async () => { @@ -365,9 +365,9 @@ it("When a valid product is about to be deleted, ensure an email is sent", async

    -## 📗 Want to learn all these practices with live video? +## 📗 Envie d'apprendre ces bonnes pratiques en vidéo ? -### Visit my online course [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) +### Va voir mon cours en ligne [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com)

    From 287e634e40fa7cfe7bc6132c924991f2175e30dc Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Fri, 18 Jun 2021 17:01:26 +0200 Subject: [PATCH 011/189] Translate 1.7 --- readme-fr.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 5a99026a..254cd5dd 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -371,21 +371,19 @@ it("When a valid product is about to be deleted, ensure an email is sent", async

    -## ⚪ ️1.6 Don’t “foo”, use realistic input data +## ⚪ ️1.6 Utilise des données réaliste -: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 [Faker](https://www.npmjs.com/package/faker) 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 card, 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). +:white_check_mark: **À faire:** Souvent les beugs de production sont révélés par des entrées tres spécifiques et surprenantes. Plus les entrées de tests seront réalistes, plus il y a de chance de détecter les beugs tôt. Utilise une librairie dédiée comme [Faker](https://www.npmjs.com/package/faker) pour générer des pseudo-vrais données qui resemble aux données de production. Par exemple, ce type de librairie peut générer de façon réaliste des numéros de téléphones, noms d'utilisateur, cartes de crédit, nom de société et même du 'Lorem ipsum'. Tu peux aussi créer des tests (en plus des tests unitaires, par à leur place) qui utilise des fausses données randomisées pour pousser test tests, ou même importer de vrais données depuis ton environnement de production. Envie de passer au niveau supérieur ? Regarde le prochain point (property-based testing).
    -❌ **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” - +❌ **Autrement:** Tout vos tests de développement vont montrer du vert à tord avec des entrées tels que "Foo", mais en production ils passeront au rouge lorsqu'un hacker passera une chaine de caractère tel que “@3e2ddsf . ##’ 1 fdsfds . fds432 AAAA”
    -
    Code Examples +
    Exemple de code
    -### :thumbsdown: Anti-Pattern Example: A test suite that passes due to non-realistic data - +### :thumbsdown: Exemple d'anti pattern: Une suite de test qui passe à cause de données non réalistes ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ```javascript @@ -409,7 +407,7 @@ test("Wrong: When adding new product with valid properties, get successful confi
    -### :clap:Doing It Right Example: Randomizing realistic input +### :clap: Bien faire les choses, exemple : Données réalistes randomisés ```javascript it("Better: When adding new valid product, get successful confirmation", async () => { From bac23d5d8ebf47df0d984b32c460360e572833d8 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Wed, 23 Jun 2021 13:02:40 +0200 Subject: [PATCH 012/189] Translate 1.7 --- readme-fr.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 254cd5dd..20e1b829 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -371,7 +371,7 @@ it("When a valid product is about to be deleted, ensure an email is sent", async

    -## ⚪ ️1.6 Utilise des données réaliste +## ⚪ ️1.6 Utilise des données réalistes :white_check_mark: **À faire:** Souvent les beugs de production sont révélés par des entrées tres spécifiques et surprenantes. Plus les entrées de tests seront réalistes, plus il y a de chance de détecter les beugs tôt. Utilise une librairie dédiée comme [Faker](https://www.npmjs.com/package/faker) pour générer des pseudo-vrais données qui resemble aux données de production. Par exemple, ce type de librairie peut générer de façon réaliste des numéros de téléphones, noms d'utilisateur, cartes de crédit, nom de société et même du 'Lorem ipsum'. Tu peux aussi créer des tests (en plus des tests unitaires, par à leur place) qui utilise des fausses données randomisées pour pousser test tests, ou même importer de vrais données depuis ton environnement de production. Envie de passer au niveau supérieur ? Regarde le prochain point (property-based testing).
    @@ -423,20 +423,19 @@ it("Better: When adding new valid product, get successful confirmation", async (

    -## ⚪ ️ 1.7 Test many input combinations using Property-based testing +## ⚪ ️ 1.7 Teste plusieurs combinaisons d'input avec le Property-based testing -: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’), 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://en.wikipedia.org/wiki/Fuzzing)). 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: by 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://github.com/jsverify/jsverify) or [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https://github.com/dubzzz/fast-check#readme) which seems to offer some additional features and also to be actively maintained +:white_check_mark: **À faire:** En règle général, on choisit quelques valeurs d'entrées pour chaque test. Même lorsque le format des inputs est réaliste ( voir le point 'Utilise des données réalistes' ), on couvre seulement quelques combinaisons d'entrées. En revanche, en production, une API appelée avec 5 paramètres peut être invoquée avec des milliers de permutations différentes, l'une d'entre elle peut faire échouer notre processus ([voir le Fuzz testing](https://fr.wikipedia.org/wiki/Fuzzing)). Et si tu pouvais écrire un seul test qui envoie 1000 permutations d'entrées automatiquement et détecte pour lequel d'entre eux notre processus ne retourne pas la bonne valeur ? Le Property-based testing c'est une méthode qui fait exactement ça : En testant toute les combinaisons d'entrées possible on augmente les chance de détecter un beug. Par exemple, prenom une méthode : addNewProduct(id, name, isDiscount), la librairie appelera cette méthode avec plusieurs combinaisons de (number, string, boolean) tel que (1, “iPhone”, false), (2, “Galaxy”, true). Tu peux utiliser le property-based testing avec ta librairie de test préféré (Mocha, Jest ...etc) à l'aide de librairie tel que [js-verify](https://github.com/jsverify/jsverify) ou [testcheck](https://github.com/leebyron/testcheck-js) (meilleure documentation). MAJ: Nicolas Dubien à suggéré dans les commentaire de [regarder fast-check](https://github.com/dubzzz/fast-check#readme) qui semble offrir des fonctionnalitées supplémentaire et être activement maintenue.
    -❌ **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 - +❌ **Autrement:** Inconsciemment, tu choisis des entrées de test qui ne couvrent que les cas qui fonctionnent correctement. Malheuresement, cela réduit l'efficacité tests et leur capacité a détecter des beugs.
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: Testing many input permutations with “fast-check” +### :clap: Bien faire les choses, exemple: Tester plusieurs permutations d'entrées avec "fast-check" ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") From 15138fa4d02466cef4cbf2e438afaf5cd9cd343e Mon Sep 17 00:00:00 2001 From: Yiqiao Xu Date: Thu, 8 Jul 2021 09:39:31 +0800 Subject: [PATCH 013/189] =?UTF-8?q?fix:=20typo=20'=E6=B1=87=E6=8A=A5'=20->?= =?UTF-8?q?=20'=E5=9B=9E=E6=8A=A5'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme-zh-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme-zh-CN.md b/readme-zh-CN.md index 0566c382..67e0bcbc 100644 --- a/readme-zh-CN.md +++ b/readme-zh-CN.md @@ -68,7 +68,7 @@ JS 领域的 CI 指南(9 条) 我们的思维空间被主体生产代码充满,因此无法腾出额外的“大脑空间”存放复杂的东西。如果向可怜的大脑中塞进其他复杂代码,将会使得整个部分变慢,而这个部分正是用来解决我们需要测试的问题的。这也是大部分团队放弃测试的原因。 -另一方面,测试是一个友好的助手,一个你乐于与之合作、投资小汇报大的助手。科学证明我们有两套大脑系统:系统 1 用于无需努力的活动如在一个空旷的路上开车;系统 2 用于复杂和繁琐的工作如算一道数学表达式。将你的测试为系统 1 设计,当你看一段测试代码时,需要像改 HTML 文档一样简单而不是像计算 2 × (17 × 24)。 +另一方面,测试是一个友好的助手,一个你乐于与之合作、投资小回报大的助手。科学证明我们有两套大脑系统:系统 1 用于无需努力的活动如在一个空旷的路上开车;系统 2 用于复杂和繁琐的工作如算一道数学表达式。将你的测试为系统 1 设计,当你看一段测试代码时,需要像改 HTML 文档一样简单而不是像计算 2 × (17 × 24)。 为了达到这个目的,我们可以通过选择性价比高、投入产出比(ROI)高的技术、工具以及测试对象。仅测试需要的内容,努力保持其灵活性,某些时候甚至值得去舍弃一些测试来换取灵活性和简洁性。 From eaa500bf5f060863df7af537b8a99c1e637b2b29 Mon Sep 17 00:00:00 2001 From: Alireza Rezania Date: Mon, 9 Aug 2021 15:49:53 +0430 Subject: [PATCH 014/189] hyperlink references to bullet --- readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 55a639b7..6003f5aa 100644 --- a/readme.md +++ b/readme.md @@ -424,7 +424,7 @@ it("Better: When adding new valid product, get successful confirmation", async ( ## ⚪ ️ 1.7 Test many input combinations using Property-based testing -: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’), 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://en.wikipedia.org/wiki/Fuzzing)). 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: by 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://github.com/jsverify/jsverify) or [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https://github.com/dubzzz/fast-check#readme) which seems to offer some additional features and also to be actively maintained +: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://github.com/goldbergyoni/javascript-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://en.wikipedia.org/wiki/Fuzzing)). 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: by 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://github.com/jsverify/jsverify) or [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https://github.com/dubzzz/fast-check#readme) which seems to offer some additional features and also to be actively maintained
    ❌ **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 @@ -1081,7 +1081,7 @@ test("Whenever no data is passed, error metric shows zero", () => { ## ⚪ ️ 3.3 Whenever possible, test with a realistic and fully rendered component -: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'). If one of the child components is significantly slowing down (e.g. animation) or complicating the setup - consider explicitly replacing it with a fake +: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://github.com/goldbergyoni/javascript-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 With all that said, a word of caution is in order: this technique works for small/medium 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 @@ -1295,7 +1295,7 @@ test("When no products exist, show the appropriate message", () => { ## ⚪ ️ 3.7 Have very few end-to-end tests that spans the whole system -:white_check_mark: **Do:** Although E2E (end-to-end) usually means UI-only testing with a real browser (See bullet 3.6), for other they mean tests that stretch the entire system including the real backend. The latter type of tests is highly valuable as they cover integration bugs between frontend and backend that might happen due to a wrong understanding of the exchange schema. They are also an efficient method to discover backend-to-backend integration issues (e.g. Microservice A sends the wrong message to Microservice B) and even to detect deployment failures - there are no backend frameworks for E2E testing that are as friendly and mature as UI frameworks like [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). The downside of such tests is the high cost of configuring an environment with so many components, and mostly their brittleness - given 50 microservices, even if one fails then the entire E2E just failed. For that reason, we should use this technique sparingly and probably have 1-10 of those and no more. That said, even a small number of E2E tests are likely to catch the type of issues they are targeted for - deployment & integration faults. It's advisable to run those over a production-like staging environment +:white_check_mark: **Do:** Although E2E (end-to-end) usually means UI-only testing with a real browser (See [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)), for other they mean tests that stretch the entire system including the real backend. The latter type of tests is highly valuable as they cover integration bugs between frontend and backend that might happen due to a wrong understanding of the exchange schema. They are also an efficient method to discover backend-to-backend integration issues (e.g. Microservice A sends the wrong message to Microservice B) and even to detect deployment failures - there are no backend frameworks for E2E testing that are as friendly and mature as UI frameworks like [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). The downside of such tests is the high cost of configuring an environment with so many components, and mostly their brittleness - given 50 microservices, even if one fails then the entire E2E just failed. For that reason, we should use this technique sparingly and probably have 1-10 of those and no more. That said, even a small number of E2E tests are likely to catch the type of issues they are targeted for - deployment & integration faults. It's advisable to run those over a production-like staging environment
    @@ -1305,7 +1305,7 @@ test("When no products exist, show the appropriate message", () => { ## ⚪ ️ 3.8 Speed-up E2E tests by reusing login credentials -:white_check_mark: **Do:** In E2E tests that involve a real backend and rely on a valid user token for API calls, it doesn't payoff to isolate the test to a level where a user is created and logged-in in every request. Instead, login only once before the tests execution start (i.e. before-all hook), save the token in some local storage and reuse it across requests. This seem to violate one of the core testing principle - keep the test autonomous without resources coupling. While this is a valid worry, in E2E tests performance is a key concern and creating 1-3 API requests before starting each individual tests might lead to horrible execution time. Reusing credentials doesn't mean the tests have to act on the same user records - if relying on user records (e.g. test user payments history) than make sure to generate those records as part of the test and avoid sharing their existence with other tests. Also remember that the backend can be faked - if your tests are focused on the frontend it might be better to isolate it and stub the backend API (see bullet 3.6). +:white_check_mark: **Do:** In E2E tests that involve a real backend and rely on a valid user token for API calls, it doesn't payoff to isolate the test to a level where a user is created and logged-in in every request. Instead, login only once before the tests execution start (i.e. before-all hook), save the token in some local storage and reuse it across requests. This seem to violate one of the core testing principle - keep the test autonomous without resources coupling. While this is a valid worry, in E2E tests performance is a key concern and creating 1-3 API requests before starting each individual tests might lead to horrible execution time. Reusing credentials doesn't mean the tests have to act on the same user records - if relying on user records (e.g. test user payments history) than make sure to generate those records as part of the test and avoid sharing their existence with other tests. Also remember that the backend can be faked - if your tests are focused on the frontend it might be better to isolate it and stub the backend API (see [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)).
    From 68a3661362e8a594412e11764e8f1d0ff359fe22 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 15 Aug 2021 11:51:39 +0000 Subject: [PATCH 015/189] docs: update readme.md [skip ci] --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 6003f5aa..9edc8d90 100644 --- a/readme.md +++ b/readme.md @@ -1968,6 +1968,7 @@ Thanks goes to these wonderful people who have contributed to this repository!
    Otavio Araujo

    ⚠️ 🖋
    Alex Ivanov

    🖋 +
    Yiqiao Xu

    🖋 From 4cdb45045287b4659071026731a83b062255ff45 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 15 Aug 2021 11:51:39 +0000 Subject: [PATCH 016/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 19225d22..28eecb0d 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -341,6 +341,15 @@ "contributions": [ "content" ] + }, + { + "login": "YeeJone", + "name": "Yiqiao Xu", + "avatar_url": "https://avatars.githubusercontent.com/u/20400822?v=4", + "profile": "https://github.com/YeeJone", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From 85a88999f6d7e6e91da838e46e5a5971a464b1c7 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Sun, 15 Aug 2021 17:08:11 +0300 Subject: [PATCH 017/189] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 9edc8d90..30f800c2 100644 --- a/readme.md +++ b/readme.md @@ -424,7 +424,7 @@ it("Better: When adding new valid product, get successful confirmation", async ( ## ⚪ ️ 1.7 Test many input combinations using Property-based testing -: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://github.com/goldbergyoni/javascript-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://en.wikipedia.org/wiki/Fuzzing)). 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: by 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://github.com/jsverify/jsverify) or [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https://github.com/dubzzz/fast-check#readme) which seems to offer some additional features and also to be actively maintained +: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://github.com/goldbergyoni/javascript-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://en.wikipedia.org/wiki/Fuzzing)). 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: by 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://github.com/jsverify/jsverify) or [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https://github.com/dubzzz/fast-check#readme) which seems to offer some additional features and also to be actively maintained
    ❌ **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 From 7130098ec5d52ad68316ca789f2bf5c086e75021 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Tue, 17 Aug 2021 16:11:20 +0200 Subject: [PATCH 018/189] Translate 1.8 --- readme-fr.md | 103 +++++++++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 49 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 20e1b829..d5fcfd6e 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -459,24 +459,24 @@ describe("Product service", () => {

    -## ⚪ ️ 1.8 If needed, use only short & inline snapshots +## ⚪ ️ 1.8 Si besoin, n'utilise que des snapshots courts et inline -:white_check_mark: **Do:** When there is a need for [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), use only short and focused snapshots (i.e. 3-7 lines) that are included as part of the test ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)) and not within external files. Keeping this guideline will ensure your tests remain self-explanatory and less fragile. +:white_check_mark: **Do:** Quand il y a un besoin pour du [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), utilise seulement des snapshots courts ( 3-7 lignes ) qui sont inclut dans le test ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)) et pas dans des fichiers externes. Respecter cette règle permettra à vos tests de rester auto-explicatif et moins fragile. -On the other hand, ‘classic snapshots’ tutorials and tools encourage to store big files (e.g. component rendering markup, API JSON result) over some external medium and ensure each time when the test run 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/HTML 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 to 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 +D'un autre coté, les tutoriels et outils 'classique' encouragent à stocker de gros fichiers (résultats d'API JSON, markup d'un composant) sur un emplacement externe et de s'assurer à chaque fois que le test est lancé, de comparer le résultat reçu avec la version sauvegardée. Cela peux, par exemple, implicitement coupler notre test à 1000 lignes avec 3000 valeurs que le lecteur du test ne verra jamais et auquel il ne pensera pas. Pourquoi est-ce que c'est mauvais ? En faisant ça, il y a 1000 raisons pour votre test d'échouer - Il suffit qu'une seule ligne change pour que le snapshot soit invalide, et celà arrivera probablement souvent. A quelle frequence ? Pour chaque espace, commentaire ou changement mineur dans le HTML/CSS. De plus, le nom du test ne donnera pas la moindre indication à propos de l'erreur vu qu'il vérifie simplement que les 1000 lignes n'ont pas changé. Cela encourage aussi celui qui écrit les tests à accepter comme valeur de success un long document qu'il ne pourra pas inspecter et vérifier. Tout ces points sont des symptomes d'un test obscure qui n'est pas ciblé et cherche à en faire trop. -It’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 +Il faut noter qu'il y a quelques cas ou de long snapshots externes sont acceptable - Pour valideer un schema et pas des données ou concernant des documents qui ne changent presque jamais
    -❌ **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 origin document to current received one - a single space character was added to the markdown... +❌ **Sinon:** Un test UI échoue. Le code semble bon, l'écran rends parfaitement les pixels, que s'est-il passé ? Ton test de snapshot a trouvé une différence entre le document original et le document actuel - un simple espace à été ajouté dans le markdown...
    -
    Code Examples +
    Exemples de code
    -### :thumbsdown: Anti-Pattern Example: Coupling our test to unseen 2000 lines of code +### :thumbsdown: Exemple d'anti pattern: Coupler nos test à 2000 lignes de code qu'on ne voit pas ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") @@ -498,7 +498,7 @@ it("TestJavaScript.com is renderd correctly", () => {
    -### :clap: Doing It Right Example: Expectations are visible and focused +### :clap: Bien faire les choses, exemple: Les attentes sont claires et spécifiques ```javascript it("When visiting TestJavaScript.com home page, a menu is displayed", () => { @@ -1007,7 +1007,7 @@ test("When flagging to show only VIP, should display only VIP members", () => { const { getAllByTestId } = render(); // Assert - Mix UI & data in assertion - expect(getAllByTestId("user")).toEqual('[
  • John Doe
  • ]'); + expect(getAllByTestId("user")).toEqual('[
  • John Doe
  • ]'); }); ``` @@ -1037,8 +1037,8 @@ test("When flagging to show only VIP, should display only VIP members", () => { // the markup code (part of React component)

    - {value} - + {value} +

    ``` @@ -1271,7 +1271,7 @@ export default function ProductsList() { fetchProducts(); }, []); - return products ?
    {products}
    :
    No products
    ; + return products ?
    {products}
    :
    No products
    ; } // test @@ -1921,52 +1921,57 @@ Thanks goes to these wonderful people who have contributed to this repository! - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + +

    Scott Davis

    🖋

    Adrien REDON

    🖋

    Stefano Magni

    🖋

    Yeoh Joer

    🖋

    Jhonny Moreira

    🖋

    Ian Germann

    🖋

    Hafez

    🖋

    Scott Davis

    🖋

    Adrien REDON

    🖋

    Stefano Magni

    🖋

    Yeoh Joer

    🖋

    Jhonny Moreira

    🖋

    Ian Germann

    🖋

    Hafez

    🖋

    Ruxandra Fediuc

    🖋

    Jack

    🖋

    Peter Carrero

    🖋

    Huhgawz

    🖋

    Haakon Borch

    🖋

    Jaime Mendoza

    🖋

    Cameron Dunford

    🖋

    Ruxandra Fediuc

    🖋

    Jack

    🖋

    Peter Carrero

    🖋

    Huhgawz

    🖋

    Haakon Borch

    🖋

    Jaime Mendoza

    🖋

    Cameron Dunford

    🖋

    John Gee

    🖋

    Aurelijus Rožėnas

    🖋

    Aaron

    🖋

    Tom Nagle

    🖋

    Yves yao

    🖋

    Userbit

    🖋

    Glaucia Lemos

    🚧

    John Gee

    🖋

    Aurelijus Rožėnas

    🖋

    Aaron

    🖋

    Tom Nagle

    🖋

    Yves yao

    🖋

    Userbit

    🖋

    Glaucia Lemos

    🚧

    koooge

    🖋

    Michal

    🖋

    roywalker

    🖋

    dangen

    🖋

    biesiadamich

    🖋

    Yanlin Jiang

    🖋

    sanguino

    🖋

    koooge

    🖋

    Michal

    🖋

    roywalker

    🖋

    dangen

    🖋

    biesiadamich

    🖋

    Yanlin Jiang

    🖋

    sanguino

    🖋

    Morgan

    🖋

    Lukas Bischof

    ⚠️ 🖋

    JuanMa Ruiz

    🖋

    Luís Ângelo Rodrigues Jr.

    🖋

    José Fernández

    🖋

    Alejandro Gutierrez Barcenilla

    🖋

    Jason

    🖋

    Morgan

    🖋

    Lukas Bischof

    ⚠️ 🖋

    JuanMa Ruiz

    🖋

    Luís Ângelo Rodrigues Jr.

    🖋

    José Fernández

    🖋

    Alejandro Gutierrez Barcenilla

    🖋

    Jason

    🖋

    Otavio Araujo

    ⚠️ 🖋

    Alex Ivanov

    🖋
    - + - + + \ No newline at end of file From 538e55557648b2c9d27eb7c65c7f9300ada954dc Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Tue, 17 Aug 2021 16:23:56 +0200 Subject: [PATCH 019/189] Translate 1.10 --- readme-fr.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index d5fcfd6e..f764d376 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -526,20 +526,22 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => {

    -## ⚪ ️1.9 Avoid global test fixtures and seeds, add data per-test +## ⚪ ️1.9 Éviter les fixtures et seeds globals, ajouter les données par test + +:white_check_mark: **À faire:** En suivant la règle d'or (point 0), chaque test doit ajouter et agir sur son propre jeu d'entrée en base de donnée pour éviter d'être couplés et faciliter le raisonnement à propos de la logique du test. En réalité, cette règle est souvent violée par les testeurs qui remplissent la base de donnée avant de lancer les tests ([aussi connu sous le nom ‘test fixture’](https://en.wikipedia.org/wiki/Test_fixture)) afin d'améliorer les performances. Même si la performance est effectivement une inquiétude valide, elle peut être atténuée (voir "Component testing"), en revanche, la compléxité des tests est un chagrin bien plus douloureux qui devrait régir les autres considérations la plupart du temps. +En pratique, chaque cas testé doit explicitement ajouter les entrée en base de donnée dont il a besoin et n'agir que sur ces entrées. Si la performance devient une inquiétude critique - un compromis peut se trouver sous la forme de seeds pour les jeux de tests qui ne modifient pas les données (queries). -: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’](https://en.wikipedia.org/wiki/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)
    -❌ **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 +❌ **Autrement:** Certains tests échoue, le déploiement est annulé, l'équipe va dépenser un temps précieux maintenant, est-ce qu'on a un bug ? Investiguons, oh non - il semble que deux tests modifiaient les même données
    -
    Code Examples +
    Exemple de code
    -### :thumbsdown: Anti-Pattern Example: tests are not independent and rely on some global hook to feed global DB data +### :thumbsdown: Exemple d'anti pattern: les tests ne sont pas indépendants et reposent sur un hook global pour des données globales en DB ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") @@ -564,7 +566,7 @@ it("When querying by site name, get the right site", async () => {
    -### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data +### :clap: Bien faire les choses, exemple: On peut rester dans le test, chaque test agis sur ses propres données ```javascript it("When updating site name, get successful confirmation", async () => { From 1b15b3d32a890d880e6acb16254d18da8fa75629 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Tue, 17 Aug 2021 16:23:56 +0200 Subject: [PATCH 020/189] Translate 1.9 --- readme-fr.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index d5fcfd6e..f764d376 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -526,20 +526,22 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => {

    -## ⚪ ️1.9 Avoid global test fixtures and seeds, add data per-test +## ⚪ ️1.9 Éviter les fixtures et seeds globals, ajouter les données par test + +:white_check_mark: **À faire:** En suivant la règle d'or (point 0), chaque test doit ajouter et agir sur son propre jeu d'entrée en base de donnée pour éviter d'être couplés et faciliter le raisonnement à propos de la logique du test. En réalité, cette règle est souvent violée par les testeurs qui remplissent la base de donnée avant de lancer les tests ([aussi connu sous le nom ‘test fixture’](https://en.wikipedia.org/wiki/Test_fixture)) afin d'améliorer les performances. Même si la performance est effectivement une inquiétude valide, elle peut être atténuée (voir "Component testing"), en revanche, la compléxité des tests est un chagrin bien plus douloureux qui devrait régir les autres considérations la plupart du temps. +En pratique, chaque cas testé doit explicitement ajouter les entrée en base de donnée dont il a besoin et n'agir que sur ces entrées. Si la performance devient une inquiétude critique - un compromis peut se trouver sous la forme de seeds pour les jeux de tests qui ne modifient pas les données (queries). -: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’](https://en.wikipedia.org/wiki/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)
    -❌ **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 +❌ **Autrement:** Certains tests échoue, le déploiement est annulé, l'équipe va dépenser un temps précieux maintenant, est-ce qu'on a un bug ? Investiguons, oh non - il semble que deux tests modifiaient les même données
    -
    Code Examples +
    Exemple de code
    -### :thumbsdown: Anti-Pattern Example: tests are not independent and rely on some global hook to feed global DB data +### :thumbsdown: Exemple d'anti pattern: les tests ne sont pas indépendants et reposent sur un hook global pour des données globales en DB ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") @@ -564,7 +566,7 @@ it("When querying by site name, get the right site", async () => {
    -### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data +### :clap: Bien faire les choses, exemple: On peut rester dans le test, chaque test agis sur ses propres données ```javascript it("When updating site name, get successful confirmation", async () => { From 437179d2aea81147d3399c0fb1986809b3a737db Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Wed, 18 Aug 2021 13:40:58 +0200 Subject: [PATCH 021/189] Translate 1.10 --- readme-fr.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index f764d376..16947f61 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -585,22 +585,22 @@ it("When updating site name, get successful confirmation", async () => {
    -## ⚪ ️ 1.10 Don’t catch errors, expect them +## ⚪ ️ 1.10 Ne catch pas les erreurs, prevois les -: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 +:white_check_mark: **À faire:** Lorsqu'on essaye de detecter que certaines entrées déclenchent une erreur, il peut sembler être une bonne idée d'utiliser try-catch-finally et de vérifier qu'on est passé dans le catch. Le résultat est un test étrange et verbeux (exemple plus bas) qui cache l'intention simple du test et le résultat attendu. -A 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 +Une alternative plus élégante est d'utiliser l'assertion Chai dédiée : expect(method).to.throw (ou en Jest: expect(method).toThrow()). Il est également obligatoire de vérifier que l'exception contient une propriété qui indique le type d'erreur, sinon, en recevant un message d'erreur générique, l'application ne sera pas capable de faire beaucoup plus que de montrer un message décevant à l'utilisateur.
    -❌ **Otherwise:** It will be challenging to infer from the test reports (e.g. CI reports) what went wrong +❌ **Autrement:** Il sera compliqué de déduire du rapport de test ce qui s'est mal passé
    -
    Code Examples +
    Exemple de code
    -### :thumbsdown: Anti-pattern Example: A long test case that tries to assert the existence of error with try-catch +### :thumbsdown: Exemple d'anti pattern: Un long test qui essaye de vérifier la présence d'une erreur avec try-catch ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") @@ -621,7 +621,7 @@ it("When no product name, it throws error 400", async () => {
    -### :clap: Doing It Right Example: A human-readable expectation that could be understood easily, maybe even by QA or technical PM +### :clap: Bien faire les choses, exemple: Un attente lisible qui peut être comprise simplement, peut être même par un QA ou PM technique ```javascript it("When no product name, it throws error 400", async () => { From 566e890a3179ea4b15351f36af22dd27fcd6a598 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Wed, 18 Aug 2021 13:55:52 +0200 Subject: [PATCH 022/189] Translate 1.11 --- readme-fr.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 16947f61..ef9818b7 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -635,20 +635,20 @@ it("When no product name, it throws error 400", async () => {

    -## ⚪ ️ 1.11 Tag your tests +## ⚪ ️ 1.11 Tag tes tests -: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’ +:white_check_mark: **À faire:** Des tests différents doivent être lancés dans différents scénarios. Les tests de fumée (quick smoke), IO-less, doivent tourner à chaque fois qu'un développeur sauvegarde ou commit un fichier, les tests complets end-to-end sont en général lancés quand une nouvelle pull-request est soumise, etc. +On peux réaliser ça en taggant les tests avec des mots clefs comme #cold #api #sanity pour pouvoir utiliser grep et sélectionner les tests qui nous interesse. Par exemple, voila comment invoquer uniquement le groupe de test sanity avec Mocha : mocha - grep 'sanity'
    -❌ **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 - +❌ **Autrement:** Lancer tout les tests, y compris ceux qui éxecutent des dizaines de requetes DB, a chaque fois qu'un développeur fait un petit changement peut être extremement lent et pousser les développeurs a ne pas utiliser les tests.
    -
    Code Examples +
    Exemple de code
    -### :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) +### :clap: Bien faire les choses, exemple: Tagger des tests avec '#cold-test' permet à celui qui les lance de n'executer que les tests rapide (cold = tests rapides qui ne font pas d'opérations IO et peuvent être executés souvent, meme pendant que le développeur code) ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") From 5645dd8cfe52bda5f0d782196c5175a97664ec0d Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Wed, 18 Aug 2021 14:10:40 +0200 Subject: [PATCH 023/189] Translate 1.12 --- readme-fr.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index ef9818b7..bc4861e7 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -668,22 +668,21 @@ describe("Order service", function() {

    -## ⚪ ️ 1.12 Categorize tests under at least 2 levels +## ⚪ ️ 1.12 Catégorise tes tests sous au moins 2 niveaux -: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 additional level of categorization like the scenario or custom categories (see code examples and print screen below). Doing so will also greatly improve the test reports: The reader will easily infer the tests 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 test suite that you may consider like [given-when-then](https://github.com/searls/jasmine-given) and [RITE](https://github.com/ericelliott/riteway) +:white_check_mark: **À faire:** Applique une structure à ta suite de test pour qu'un visiteur occasionnel puisse facilement comprendre les attentes (Les tests sont la meilleure documentation) et les différents scénarios testés. Une méthode fréquence pour ça est de placer au moins 2 blocs 'describe' au dessus de vos tests : Le premier est pour le nom de l'unité testé et le deuxieme pour un niveau supplémentaire de catégorisation comme le scénario ou une catégorie (voir l'exemple de code plus bas). Cette organisation améliorera grandement vos rapports de tests: Le lecteur comprendra simplement les catégories de tests, examinera la section voulu et verra les corrélations entre les tests qui échouent. De plus, ce sera bien plus simple pour un développeur de naviguer dans le code d'une suite avec de nombreux tests. Il y a plusieurs structures alternatives pour les suites de tests que tu peux envisager comme [given-when-then](https://github.com/searls/jasmine-given) et [RITE](https://github.com/ericelliott/riteway)
    -❌ **Otherwise:** When looking at a report with flat and long list of tests, the reader have to skim-read through long texts to conclude the major scenarios and correlate the commonality of failing tests. Consider the following case: When 7/100 tests fail, looking at a flat list will demand reading the failing tests text 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 +❌ **Autrement:** En regardant un rapport avec une longue liste de tests a plat, le lecteur devra lire un long texte pour comprendre les scénarios majeur et comprendre les liens entre les tests qui échouent. Imagine le cas suivant : Quand 7/100 tests échouent, regarder une liste à plat nécéssitera d'aller lire le contenu des tests qui échouent pour comprendre le lien entre eux. En revanche, dans un rapport hiérarchique ils pourrait tous etre au sein du même scénario ou d'une catégorie et le lecteur pourra rapidement déduire ce qui est, ou du moins où est, la cause de l'erreur.
    -
    Code Examples +
    Exemple de code
    -### :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 - +### :clap: Bien faire les choses, exemple: Structurer une suite avec le nom de l'unité testé et les scénarios mènera au rapport pratique montré ci-dessous ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ```javascript @@ -704,7 +703,7 @@ describe("Transfer service", () => {
    -### :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 +### :thumbsdown: Exemple d'anti-pattern: Une liste de tests à plat qui rend l'identification du problème difficile pour le lecteur ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Mocha") From e080bb152f7a7ba2cff79f234cb686a5851d197b Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Wed, 18 Aug 2021 14:29:15 +0200 Subject: [PATCH 024/189] Translate 1.13 - Draft part 1 done --- readme-fr.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index bc4861e7..8ac7af2f 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -723,14 +723,14 @@ test("Then there should not be a new transfer record", () => {});

    -## ⚪ ️1.13 Other generic good testing hygiene +## ⚪ ️1.13 Autre bonnes pratiques génériques -: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 few non-Node related tips that are well-known +:white_check_mark: **À faire:** Ce post se concentre sur des conseils de tests qui sont en rapport, ou au moins peuvent être présentés, avec Node JS. ce point, cependant, regroupe quelques conseils sans rapport avec Node qui sont bien connus. -Learn and practice [TDD principles](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) — 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://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.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, 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) +Apprend et pratique [les principes TDD](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) - ils ont beaucoup de valeurs pour la plupart mais ne soit pas intimidés s'ils ne correspondent pas à ton style, tu n'es pas le seul. Envisage d'écrire les tests avec le code dans un [red-green-refactor style](https://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html), vérifie que chaque test vérifie exactement une chose, quand tu trouves un bug - avant de le fixer, écrit un test qui détectera le bug à l'avenir, laisse chaque test échouer au moins une fois avant de devenir vert, commence un module en écrivant du code simple et rapide qui valident le test - puis refactor graduellement et passe le code a un niveau de production, évite toute dépendance à l'environnement (paths, OS, etc)
    -❌ **Otherwise:** You‘ll miss pearls of wisdom that were collected for decades +❌ **Autrement:** Tu manqueras les perles de sagesses recueillies pendant des décennies.

    From 3323747cdcd2c3ea440819fdc9040a46b660851a Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Thu, 19 Aug 2021 16:29:56 +0200 Subject: [PATCH 025/189] Translate 2.1 --- readme-fr.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 8ac7af2f..9c0890b8 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -734,29 +734,29 @@ Apprend et pratique [les principes TDD](https://www.sm-cloud.com/book-review-tes

    -# Section 2️⃣: Backend Testing +# Section 2️⃣: Tests Backend -## ⚪ ️2.1 Enrich your testing portfolio: Look beyond unit tests and the pyramid +## ⚪ ️2.1 Enrichis ton portefeuille de test: Vois plus loin que les tests unitaire et la pyramide -:white_check_mark: **Do:** The [testing pyramid](https://martinfowler.com/bliki/TestPyramid.html), though 10> years old, is a great and relevant model that suggests three testing types and influences most developers’ testing strategy. 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? +:white_check_mark: **À faire:** La [pyramide de tests](https://martinfowler.com/bliki/TestPyramid.html), bien que vielle de plus de 10 ans, est un bon model qui suggère trois types de tests et influence la plupart des stratégies de tests des développeurs. Dans un même temps, une poignée de nouvelles techniques de tests brillantes ont émergés et sont dans l'ombre de la pyramide de tests. Étant donné l'étendu des changements que l'on a vu ces 10 dernières années (micro-services, cloud, serverless), est-il seulement possible qu'un vieux modèle soit adapté à *tout* les types d'applications ? Le monde du test ne devrait-il pas accueillir de nouvelles techniques ? -Don’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://en.wikipedia.org/wiki/All_models_are_wrong). For example, consider an IoT application that ingests many events into a message-bus like Kafka/RabbitMQ, 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 increase (bots, crypto, Alexa-skills) greater are the chances to find scenarios where the testing pyramid is not the best match. +Ne vous méprenez pas, en 2019, la pyramide de tests, le TDD et les tests unitaires sont toujours une technique puissante et sont probablement le meilleur choix pour beaucoup d'applications. Seulement, comme les autres modèles, malgrés qu'il soit utile, [il doit être faux parfois](https://en.wikipedia.org/wiki/All_models_are_wrong). Par exemple, imagine une application IoT qui traite de nombreux évènement dans une queue (message-bus) comme Kafka/RabbitMQ, qui vont ensuite dans un entrepot de donnée puis sont lus par une UI d'analyse. Est-ce qu'on devrait vraiment dépenser 50% de notre budget de test pour écrire des tests unitaire sur une application qui est centrée sur l'intégration et n'as presque aucune logique ? Plus la diversité des applications augmente (bots, crypto, Alexa-skills) plus les chances sont grandes de trouver un scénario ou la pyramide de test n'est pas le meilleur choix. -It’s time to enrich your testing portfolio and become familiar with more testing types (the next bullets suggest 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 build a portfolio based on risk analysis — assess where problems might arise and match some prevention measures to mitigate those potential risks +Il est temps d'enrichir ton portefeuille de test et de devenir familier avec plus de types de tests (les prochains points suggèrent quelques idées), de modèles tels que celui de la pyramide de tests mais aussi d'associer les types de tests aux problèmes que tu rencontres dans le monde réel ('Hey, notre API est cassé, écrivons des consumer-driven contract testing!'), diversifie tes tests comme un investisseur qui construit sont portefeuille en se basant sur l'analyse des risques - estime où les problèmes risquent de se poser et applique des mesures de prévention pour réduire ces risques. -A word of caution: the TDD argument in the software world takes a typical false-dichotomy face, some preach to use it everywhere, others think it’s the devil. Everyone who speaks in absolutes is wrong :] +Un mot d'avertissement: l'argument du TDD dans le monde du développement à un visage typique de fausse dichotomie, certains disent de l'utiliser de partout, d'autres pensent que c'est le diable. Tous ceux qui parlent en absolu ont tord :]
    -❌ **Otherwise:** You’re going to miss some tools with amazing ROI, some like Fuzz, lint, and mutation can provide value in 10 minutes +❌ **Autrement:** Tu va rater des outils avec un retour sur investissement incroyable, certains comme Fuzz, lint, ou mutation peuvent apporter de la valeur en 10 minutes
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the same way’ +### :clap: Bien faire les choses, exemple: Cindy Sridharan propose un portefeuille de tests riche dans ton excellent post 'Testing Microservices - the same way' ![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") From e81b8f18490060c7aedc927ef51cac82c893f2da Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Thu, 19 Aug 2021 16:45:04 +0200 Subject: [PATCH 026/189] Translate 2.2 --- readme-fr.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 9c0890b8..8290c263 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -770,22 +770,23 @@ Un mot d'avertissement: l'argument du TDD dans le monde du développement à un

    -## ⚪ ️2.2 Component testing might be your best affair +## ⚪ ️2.2 Les tests de composant pourrait être ta meilleure aventure -: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 from both worlds: reasonable performance and a possibility to apply TDD patterns + realistic and great coverage. +:white_check_mark: **À faire:** Chaque test unitaire couvre une petite portion de l'application et il est couteux de couvrir l'ensemble, alors que les tests end-to-end couvrent facilement une grande partie mais sont lent, pourquoi ne pas appliquer une approche intermédiaire et écrire des tests qui sont plus gros que les tests unitaire mais plus petit que les tests end-to-end ? Les tests de composant (Component testing) sont méconnus du monde de test mais ils offrent le meilleur des deux mondes: des performances raisonnable et la possibilité d'appliquer le pattern TDD + une couverture correct et réaliste + +Les tests de composant se concentre sur "l'unité" du microservice, ils fonctionnent sur l'API, ne mock rien qui appartient au microservice lui même (une vrai DB, ou au moins une version in-memory de cette DB) mais stub tout ce qui est externe, comme les appels à d'autres microservices. En fasant ça, on test ce que l'on déploie, on approche l'application de l'extérieur vers l'intérieur et on gagne en confiance dans un laps de temps raisonnable. -Component tests focus on the Microservice ‘unit’, they work against the API, 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 outwards to inwards and gain great confidence in a reasonable amount of time.
    -❌ **Otherwise:** You may spend long days on writing unit tests to find out that you got only 20% system coverage +❌ **Autrement:** Tu risque de passer de longues journée à écrire des tests unitaire pour te rendre compte que tu n'as que 20% de couverture
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: Supertest allows approaching Express API in-process (fast and cover many layers) +### :clap: Bien faire les choses, exemple: Supertest permet d'approcher l'API Express (rapide et couvre plusieurs niveaux) ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") From 8d79ae924b93050966b2c19737fa099edd3e6592 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 23 Aug 2021 08:00:48 +0200 Subject: [PATCH 027/189] Translate 2.3 --- readme-fr.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 8290c263..017ba06d 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -796,20 +796,19 @@ Les tests de composant se concentre sur "l'unité" du microservice, ils fonction

    -## ⚪ ️2.3 Ensure new releases don’t break the API using contract tests +## ⚪ ️2.3 Vérifie que les nouvelles versions ne cassent pas l'API avec les tests de contrat -: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. [Consumer-driven contracts and the framework PACT](https://docs.pact.io/) were born to formalize this process with a very disruptive approach — not the server defines the test plan of itself rather the client defines the tests of the… server! PACT can record the client expectation and put in a shared location, “broker”, so the server can pull the expectations and run on every build using 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/CI and might save you a great deal of frustration +:white_check_mark: **À faire:** Ton microservice a plusieurs clients, et tu exécutes plusieurs versions du service pour des raisons de compatibilité (pour que tout le monde soit content). Puis tu changes un champs et 'boom!', un client important qui compte sur ce champs est en colère. C'est le Catch-22 du monde de l'intégration : Il est trés difficilé pour le coté serveur de considérer toute les attentes des clients. D'un autre coté, les clients ne peuvent pas réaliser de tests puisque le serveur controles les dates de sorties. [Les "consumer-driven contracts" et le framework PACT](https://docs.pact.io) sont nés pour formaliser ce processus avec une approche disruptive - ce n'est pas le serveur qui défini ses propres plan de test, mais le client qui défini les tests du ...serveur! PACT peut enregistrer les attentes du client et les placer dans un emplacement partagé, "broker", afin que le serveur puisse extraire les attentes et s'éxécuter sur chaque version en utilisant la librairie PACT pour détecter les contrats rompus - une attente du client qui n'est pas satisfaite. En faisant ça, toutes les incompatibilités d'API server-client sont repérés tôt pendant le build/CI et peuvent vous éviter beaucoup de frustration.
    -❌ **Otherwise:** The alternatives are exhausting manual testing or deployment fear - +❌ **Autrement:** L'alternative sont les tests manuels épuisants ou la peur du déploiement
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: +### :clap: Bien faire les choses, exemple: ![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") From fc52f1e3771e29696b7c1b13c6cc93ff5fdb7b40 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 23 Aug 2021 08:07:58 +0200 Subject: [PATCH 028/189] Translate 2.4 --- readme-fr.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 017ba06d..22b53eb5 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -818,20 +818,19 @@ Les tests de composant se concentre sur "l'unité" du microservice, ils fonction

    -## ⚪ ️ 2.4 Test your middlewares in isolation +## ⚪ ️ 2.4 Test tes middlewares de manière isolée -: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://www.npmjs.com/package/sinon)) on the interaction with the {req,res} objects to ensure the function performed the right action. The library [node-mock-http](https://www.npmjs.com/package/node-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) +:white_check_mark: **À faire:** Beaucoup évitent les tests de Middleware parce qu'ils représentent une petite portion du systeme et requièrent un serveur express live. Ce sont deux mauvaises raisons - les Middlewares sont petit mais affectent toute ou la plupart des requetes et peuveunt être testés simplement en tant que fonction qui reçoit un objet JS {req,res}. Pour tester un middleware, il suffit de l'invoquer et d'espionner ([avec Sinon par exemple](https://www.npmjs.com/package/sinon) l'interaction avec l'object {req,res} pour s'assurer que la fonction a effectuée la bonne action. La librairie [node-mock-http](https://www.npmjs.com/package/node-mocks-http) va encore plus loin et prend en compte l'object {req,res} tout en surveillant son comportement. Par exemple, il peut vérifier que le status http qui à été défini sur l'objet res correspond aux attentes (voir l'exemple ci-dessous)
    -❌ **Otherwise:** A bug in Express middleware === a bug in all or most requests - +❌ **Autrement:** Un bug dans un middleware Express === un bug dans toutes ou la plupart des requêtes
    -
    Code Examples +
    Exemple de code
    -### :clap:Doing It Right Example: Testing middleware in isolation without issuing network calls and waking-up the entire Express machine +### :clap: Bien faire les choses, exemple: Tester le middleware en isolation sans effectuer d'appel réseau et sans réveiller l'ensemble de la machine Express ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") From cd5a0c378d6f6deae6a969b6f11fffec0dbc60ca Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Tue, 24 Aug 2021 08:00:24 +0200 Subject: [PATCH 029/189] Fix word + Translate 2.5 --- readme-fr.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 22b53eb5..fb2c5c39 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -770,7 +770,7 @@ Un mot d'avertissement: l'argument du TDD dans le monde du développement à un

    -## ⚪ ️2.2 Les tests de composant pourrait être ta meilleure aventure +## ⚪ ️2.2 Les tests de composant pourrait être ta meilleure affaire :white_check_mark: **À faire:** Chaque test unitaire couvre une petite portion de l'application et il est couteux de couvrir l'ensemble, alors que les tests end-to-end couvrent facilement une grande partie mais sont lent, pourquoi ne pas appliquer une approche intermédiaire et écrire des tests qui sont plus gros que les tests unitaire mais plus petit que les tests end-to-end ? Les tests de composant (Component testing) sont méconnus du monde de test mais ils offrent le meilleur des deux mondes: des performances raisonnable et la possibilité d'appliquer le pattern TDD + une couverture correct et réaliste @@ -857,23 +857,23 @@ test("A request without authentication header, should return http status 403", (

    -## ⚪ ️2.5 Measure and refactor using static analysis tools +## ⚪ ️2.5 Mesure et refactorise en utilisant des outils d'analyse statique -: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://www.sonarqube.org/) (4,900+ [stars](https://github.com/SonarSource/sonarqube)) and [Code Climate](https://codeclimate.com/) (2,000+ [stars](https://github.com/codeclimate/codeclimate)) +:white_check_mark: **À faire:** Utiliser des outils d'analye statique donne des moyens objectif d'améliorer la qualité et de garder le code maintenable. Tu peux ajouter un outil d'analyse statique à ton build CI pour l'annuler si il détecte un "code smell". Ses arguments de vente par rapport au linting simple sont la capacité d'inspecter la qualité dans le contexte de plusieurs fichiers (e.g. détécter des duplication), effectuer des analyses avancer (e.g. complexité du code) et suivre l'histoire et le progrés d'un problème de code. Deux exemples d'outils que tu peux utiliser sont [SonarQube](https://www.sonarqube.org/) (4,900+ [stars](https://github.com/SonarSource/sonarqube)) et [Code Climate](https://codeclimate.com/) (2,000+ [stars](https://github.com/codeclimate/codeclimate)) Credit: [Keith Holliday](https://github.com/TheHollidayInn)
    -❌ **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 +❌ **Autrement:** Avec du code de mauvaise qualité, les beugs et la performance seront toujours un problème qu'aucune nouvelle librairie ou fonctionnalitée de pointe ne peux corriger
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: CodeClimate, a commercial tool that can identify complex methods: +### :clap: Bien faire les choses, exemple: CodeClimate, un outil commercial qui peux identifier des méthodes complexes: ![](https://img.shields.io/badge/🔧%20Example%20using%20Code%20Climate-blue.svg "Examples with CodeClimate") From 10f408a333e6d2fe5b62ef2889e46c44ab97feb9 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Tue, 24 Aug 2021 08:18:13 +0200 Subject: [PATCH 030/189] Translate 2.6 --- readme-fr.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index fb2c5c39..7ecb4bec 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -883,20 +883,20 @@ Credit: Date: Thu, 26 Aug 2021 07:49:38 +0200 Subject: [PATCH 031/189] Translate 2.7 ( Duplicate of 1.9 ? ) --- readme-fr.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 7ecb4bec..63de077c 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -896,7 +896,7 @@ Il vise à fournir une sensibilisation, des frameworks et des outils pour tester
    -### :clap: Bien faire les choses, exemple: Le chaos-Node peut générer toute sortes de farces Node.js afin que tu puisses tester la résilience de votre application au chaos +### :clap: Bien faire les choses, exemple: Le chaos-Node peut générer toute sortes de farces Node.js afin que tu puisses tester la résilience de ton application au chaos ![alt text](assets/bp-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") @@ -904,20 +904,20 @@ Il vise à fournir une sensibilisation, des frameworks et des outils pour tester
    -## ⚪ ️2.7 Avoid global test fixtures and seeds, add data per-test +## ⚪ ️2.7 Éviter les fixtures et seeds globals, ajouter les données par test -: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) +:white_check_mark: **À faire:** En suivant la règle d'or (point 0), chaque test doit ajouter et agir sur son propre jeu d'entrée en base de donnée pour éviter d'être couplés et faciliter le raisonnement à propos de la logique du test. En réalité, cette règle est souvent violée par les testeurs qui remplissent la base de donnée avant de lancer les tests (aussi connu sous le nom ‘test fixture’) afin d'améliorer les performances. Même si la performance est effectivement une inquiétude valide, elle peut être atténuée (voir "Component testing"), en revanche, la compléxité des tests est un chagrin bien plus douloureux qui devrait régir les autres considérations la plupart du temps. En pratique, chaque cas testé doit explicitement ajouter les entrée en base de donnée dont il a besoin et n'agir que sur ces entrées. Si la performance devient une inquiétude critique - un compromis peut se trouver sous la forme de seeds pour les jeux de tests qui ne modifient pas les données (queries).
    -❌ **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 +❌ **Autrement:** Certains tests échoue, le déploiement est annulé, l'équipe va dépenser un temps précieux maintenant, est-ce qu'on a un bug ? Investiguons, oh non - il semble que deux tests modifiaient les même données
    -
    Code Examples +
    Exemple de code
    -### :thumbsdown: Anti-Pattern Example: tests are not independent and rely on some global hook to feed global DB data +### :thumbsdown: Exemple d'anti pattern: les tests ne sont pas indépendants et reposent sur un hook global pour des données globales en DB ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") @@ -942,7 +942,7 @@ it("When querying by site name, get the right site", async () => {
    -### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data +### :clap: Bien faire les choses, exemple: On peut rester dans le test, chaque test agis sur ses propres données ```javascript it("When updating site name, get successful confirmation", async () => { From a4c237c1212e62a6122366b063ebd07f07aca369 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Thu, 26 Aug 2021 08:00:00 +0200 Subject: [PATCH 032/189] Translate 3.1 --- readme-fr.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 63de077c..32c9628c 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -959,23 +959,21 @@ it("When updating site name, get successful confirmation", async () => {

    -# Section 3️⃣: Frontend Testing +# Section 3️⃣: Tests Frontend -## ⚪ ️ 3.1 Separate UI from functionality - -: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/CSS 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 +## ⚪ ️ 3.1 Separer l'UI des fonctionnalités +:white_check_mark: **À faire:** Lorsqu'on veux tester la logique d'un composant, les détail UI deviennent du bruit qui devrait être extrait, afin que les tests se concentrent purement sur les données. En pratique, extrait les donnée désirés du markup d'un facon abstrait qui n'est pas torop complée avec l'iplémentation graphique, assert seulement les donnée (vs des détails graphiques HTML/CSS) et désactive les animations qui ralentissent. Tu peux être tenté d'éviter le rendu et ne tester que les parties derrière l'UI (e.g. services, actions, store) mais ils s'agira de tests fictionnels qui ne ressemblent pas à la réalité et ne révèleront pas les cas ou la bonne donnée n'arrive pas à l'UI.
    -❌ **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 - +❌ **Autrement:** Les donnée calculée de ton tests peuvent être prêtes en 10ms, mais l'ensemble du tests durera 500ms (100 tests = 1 min) à cause d'animation qui ne nous concerne pas dans le cadre du test.
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: Separating out the UI details +### :clap: Bien faire les choses, exemple: Séparer les détails UI ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") @@ -996,7 +994,7 @@ test("When users-list is flagged to show only VIP, should display only VIP membe
    -### :thumbsdown: Anti-Pattern Example: Assertion mix UI details and data +### :thumbsdown: Exemple d'anti pattern: L'assertion mélange des détails UX et les données ```javascript test("When flagging to show only VIP, should display only VIP members", () => { From 3897db32fc6ad3a2cc59679024a5ab4d2d650711 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Thu, 26 Aug 2021 08:09:39 +0200 Subject: [PATCH 033/189] Translate 3.2 --- readme-fr.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 32c9628c..9f9b61ca 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1013,21 +1013,20 @@ test("When flagging to show only VIP, should display only VIP members", () => {

    -## ⚪ ️ 3.2 Query HTML elements based on attributes that are unlikely to change - -: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/logic 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 +## ⚪ ️ 3.2 Query les éléments HTML en te basant sur des attributs qui ont peu de chance de changer +:white_check_mark: **À faire:** Query les éléments HTML en te basant sur des attributs qui ont de grande chances de survivre à un changement graphique, contrairement aux selecteurs CSS ou aux labels des forms. Si l'élément n'as pas d'attribut de ce type, creer un attribut dédié au test comme 'test-id-submit-sutton'. Utiliser cette méthode permet non seulement d'être sur que vos tests fonctionnels/logique ne cassent pas à cause d'un changement visuel mais il devient également plus clair pour toute votre équipe que cet élément et son attribut sont utilisés par les tests et ne devraient pas être supprimés.
    -❌ **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' +❌ **Autrement:** Tu veux tester la fonctionnalité de connexion qui couvre de nombreux composants, logiques et services, tout est configuré parfaitement - subs, spies, les appels Ajax sont isolés. Tout semble parfait. Puis le test échoue car le designer à changé la class CSS du div de 'thick-border' à 'thin-border'
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: Querying an element using a dedicated attribute for testing +### :clap: Bien faire les choses, exemple: Query un élément en utilisant un attribut dédié aux tests ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") @@ -1056,7 +1055,7 @@ test("Whenever no data is passed to metric, show 0 as default", () => {
    -### :thumbsdown: Anti-Pattern Example: Relying on CSS attributes +### :thumbsdown: Exemple d'anti pattern: Compter sur les attributs CSS ```html From 5185e079b7f399f800dfff74669e500696efde8f Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Thu, 26 Aug 2021 08:21:58 +0200 Subject: [PATCH 034/189] Translate 3.3 --- readme-fr.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 9f9b61ca..7c2a3174 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1076,23 +1076,24 @@ test("Whenever no data is passed, error metric shows zero", () => {
    -## ⚪ ️ 3.3 Whenever possible, test with a realistic and fully rendered component +## ⚪ ️ 3.3 Lorsque c'est possible, test avec un composant réaliste et totalement rendu -: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'). If one of the child components is significantly slowing down (e.g. animation) or complicating the setup - consider explicitly replacing it with a fake +:white_check_mark: **Do:** Lorsqu'ils sont de taille raisonnable, tests tes composants de l'exterieur comme le font tes utilisateurs, rend complètement l'UI, agit dessus, et vérifie que l'UI rendu se comporte comme on l'attend. +Évite toute sorte de mocking, de rendu partiels ou superficiel - cette approche peut résulter en bugs non détéctés à cause du manque de détails et rendre plus difficile la maintenance des tests puisque les tests modifie les propiétés interne (voir le point 'Privilégier les tests blackbox'). Si l'un des composants enfants ralenti significativement (e.g animations) ou complique la configuration - considère de le remplacer explicitement avec un faux. -With all that said, a word of caution is in order: this technique works for small/medium 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 +Maintenant que c'est dit, une mise en garde s'impose: cette technique fonctionne pour des petit/moyens composants qui ont un nombre raisonnable de composants enfants. Rendre complètement un composants avec trop d'enfant compliquera le raisonnement à propos des échecs de tests (analyse de la cause originelle) et peut être trop lent. Dans ces cas, écrit seulement quelques tests pour ce parent, et plus de tests pour ses enfants.
    -❌ **Otherwise:** When poking into a component's internal by invoking its private methods, and checking the inner state - you would have to refactor all tests when refactoring the components implementation. Do you really have a capacity for this level of maintenance? +❌ **Autrement:** Lorsque tu fouilles dans les détails interne du composants en invoquant ses méthodes privée, et en vérifiant l'état interne - tu devra refactorer tout les tests lorsque tu refactorera l'implémentation du composants. Est-ce que tu as vraiment la capacité de tenir ce niveau de maintenance ?
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: Working realistically with a fully rendered component +### :clap: Bien faire les choses, exemple: Travailler de façon réaliste sur un composant complètement rendu ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Enzyme-blue.svg "Examples with Enzyme") @@ -1124,7 +1125,7 @@ test("Realistic approach: When clicked to show filters, filters are displayed", }); ``` -### :thumbsdown: Anti-Pattern Example: Mocking the reality with shallow rendering +### :thumbsdown: Exemple d'anti pattern: Mocker la réalité avec un rendu superficiel ```javascript test("Shallow/mocked approach: When clicked to show filters, filters are displayed", () => { From 1a89d8a87b2afbd05112d788b968b35334027a1e Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 30 Aug 2021 12:54:57 +0200 Subject: [PATCH 035/189] Translate 3.4 --- readme-fr.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 7c2a3174..274ef3e3 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1149,20 +1149,22 @@ test("Shallow/mocked approach: When clicked to show filters, filters are display
    -## ⚪ ️ 3.4 Don't sleep, use frameworks built-in support for async events. Also try to speed things up +## ⚪ ️ 3.4 N'attend pas, utilise la gestion des évènements asynchrone implémenté dans les frameworks. Essayes aussi d'accélérer les choses -:white_check_mark: **Do:** In many cases, the unit under test completion time is just unknown (e.g. animation suspends element appearance) - in that case, avoid sleeping (e.g. setTimeOut) and prefer more deterministic methods that most platforms provide. Some libraries allows awaiting on operations (e.g. [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), other provide API for waiting like [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). Sometimes a more elegant way is to stub the slow resource, like API for example, and then once the response moment becomes deterministic the component can be explicitly re-rendered. When depending upon some external component that sleeps, it might turn useful to [hurry-up the clock](https://jestjs.io/docs/en/timer-mocks). Sleeping is a pattern to avoid because it forces your test to be slow or risky (when waiting for a too short period). Whenever sleeping and polling is inevitable and there's no support from the testing framework, some npm libraries like [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) can help with a semi-deterministic solution +:white_check_mark: **À faire:** Souvent, le temps de complétion de l'unité qu'on test est inconnu (e.g animation qui suspendent l'apparition d'éléments) - Dans ce cas, évite d'attendre (e.g. setTimeOut ) et préfére des méthodes déterministe que la plupart des frameworks fournissent. Certaines librairies permettent d'attendre certaines opérations (e.g. [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), d'autres fournissent une API pour attendre comme [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). +Parfois il est plus élégant de stub la ressource lente, comme une API, une fois que le moment de réponse devient déterminé, le composant peut être re-rendu explicitement. Lorsque l'on dépend d'un composant externe qui attent, il peut être utile d'[accélérer l'horloge](https://jestjs.io/docs/en/timer-mocks). +Attendre est un pattern à éviter puisqu'il force tes tests à être lent ou risqué ( s'ils n'attendent pas assez longtemps ). A chaque fois qu'attendre ou requêter sont inévitable et qu'il n'y a pas de support de la part du framework de test, des librairies comme [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) peuvent aider avec une solution demi-déterministe.
    -❌ **Otherwise:** When sleeping for a long time, tests will be an order of magnitude slower. When trying to sleep for small numbers, test will fail when the unit under test didn't respond in a timely fashion. So it boils down to a trade-off between flakiness and bad performance +❌ **Autrement:** En attendant pour un long moment, les tests seront plus lent. En attendant trop peu, les tests échoueront si l'unité testé n'as pas répondu dans les temps. Cela se résume donc entre un compromis entre l'instabilité et les mauvaise performances.
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: E2E API that resolves only when the async operations is done (Cypress) +### :clap: Bien faire les choses, exemple: E2E API qui se résoud uniquement lorsque l'opération asynchrone est terminée (Cypress) ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") @@ -1174,7 +1176,7 @@ cy.wait("@products"); // wait for route to appear // this line will get executed only when the route is ready ``` -### :clap: Doing It Right Example: Testing library that waits for DOM elements +### :clap: Bien faire les choses, exemple: Librairie de tests qui attend les éléments du DOM ```javascript // @testing-library/dom @@ -1191,7 +1193,7 @@ test("movie title appears", async () => { }); ``` -### :thumbsdown: Anti-Pattern Example: custom sleep code +### :thumbsdown: Exemple d'anti pattern: Code custom qui attend ```javascript test("movie title appears", async () => { From 57bce8c850e2d894f423e368a8d1b6aab9501109 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 30 Aug 2021 13:07:14 +0200 Subject: [PATCH 036/189] Translate 3.5 --- readme-fr.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 274ef3e3..c1396020 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1217,21 +1217,20 @@ test("movie title appears", async () => {
    -## ⚪ ️ 3.5 Watch how the content is served over the network +## ⚪ ️ 3.5 Regarde comment le contenu est servi sur le réseau ![](https://img.shields.io/badge/🔧%20Example%20using%20Google%20LightHouse-blue.svg "Examples with Lighthouse") -✅ **Do:** Apply some active monitor that ensures the page load under real network is optimized - this includes any UX concern like slow page load or un-minified bundle. The inspection tools market is no short: basic tools like [pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) can be easily configured to watch whether the server is alive and response under a reasonable SLA. This only scratches the surface of what might get wrong, hence it's preferable to opt for tools that specialize in frontend (e.g. [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) and perform richer analysis. The focus should be on symptoms, metrics that directly affect the UX, like page load time, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [time until the page gets interactive (TTI)](https://calibreapp.com/blog/time-to-interactive/). On top of that, one may also watch for technical causes like ensuring the content is compressed, time to the first byte, optimize images, ensuring reasonable DOM size, SSL and many others. It's advisable to have these rich monitors both during development, as part of the CI and most important - 24x7 over the production's servers/CDN - +✅ **À faire:** Applique un monitoring active qui s'assure que le chargement de la page sur un vrai réseau est optimisé - ça inclue les questions UX comme un chargement lent ou un bundle non minifié. Le marché des outils d'inspection n'est pas petit: des outils basique comme pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) peuvent être configuré rapidement pour vérifier sur le server est disponible et répond sous un délai raisonnable. Cela ne fait qu'effleurer la surface de ce qui pourrait aller mal, il est donc préférable de choisir des outils spécialisés pour le frontend (e.g [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) et d'effectuer une analyse plus complète. L'attention doit être portée sur les symptomes, les métriques qui affectent directement l'experience utilisateur, comme le temps de chargement d'une page, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [le temps jusqu'à ce que la page devienne intéractive (TTI)](https://calibreapp.com/blog/time-to-interactive/). En plus de ça, on peut également surveiller les cause techniques, comme s'assurer que le contenu est complet, le temps jusqu'au premier byte, l'optimisation des images, s'assurer d'une taille de DOM raisonnable, SSL et autres. Il est recommandable d'avoir ces monitoring complet à la fois pendant le développement, dans le processus CI et surtout - 24h/24 7j/7 sur les serveurs/CDN de production
    -❌ **Otherwise:** It must be disappointing to realize that after such great care for crafting a UI, 100% functional tests passing and sophisticated bundling - the UX is horrible and slow due to CDN misconfiguration +❌ **Autrement:** Il doit être décevant de se rendre compte qu'après tout le soin apporté à la création d'une interface utilisateur, des tests 100% fonctionnels réussis et des bundles sophistiqué - l'expérience utilisateur est horrible et lente à cause d'une mauvaise configuration du CDN.
    -
    Code Examples +
    Exemple de code -### :clap: Doing It Right Example: Lighthouse page load inspection report +### :clap: Bien faire les choses, exemple: Rapport d'inspection du temps de chargement avec Lighthouse ![](/assets/lighthouse2.png "Lighthouse page load inspection report") From fa0dbc0b465e1bd65313d2f1a4f43ae5613cdeeb Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 30 Aug 2021 13:22:49 +0200 Subject: [PATCH 037/189] Translate 3.6 --- readme-fr.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index c1396020..4709f876 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1238,22 +1238,19 @@ test("movie title appears", async () => {
    -## ⚪ ️ 3.6 Stub flaky and slow resources like backend APIs - -:white_check_mark: **Do:** When coding your mainstream tests (not E2E tests), avoid involving any resource that is beyond your responsibility and control like backend API and use stubs instead (i.e. test double). Practically, instead of real network calls to APIs, use some test double library (like [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble), etc) for stubbing the API response. The main benefit is preventing flakiness - testing or staging APIs by definition are not highly stable and from time to time will fail your tests although YOUR component behaves just fine (production env was not meant for testing and it usually throttles requests). Doing this will allow simulating various API behavior that should drive your component behavior as when no data was found or the case when API throws an error. Last but not least, network calls will greatly slow down the tests +## ⚪ ️ 3.6 Stub les ressources lente ou incertaine comme l'API backend +:white_check_mark: **À faire:** Lorsque tu code tes tests mainstream ( pas les tests E2E ), évite d'impliquer toute ressources qui n'est pas sous ta responsabilité et sous ton controle comme l'API et utilise des stubs à la place (i.e. test double). en pratique, à la place de vrais appels à une API, utilise une librairie de tests double ( comme [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble), etc) pour simuler la réponse. L'avantage principal est d'éviter les comportements incertains - les APIs de tests ou de staging par définition ne sont pas toujours stable et de temps en temps peuvent faire échouer tes tests même si ton composant se comporte bien ( l'environnement de production n'a pas été fait pour les tests et limite généralement les requêtes ). Faire ça permettra de simuler plusieurs comportements d'API qui devrait diriger le comportement de ton composant, comme lorsqu'aucune donnée n'est trouvé ou que l'API emet une erreur. Enfin et surtout, les appels réseau vont énormément ralentir les tests.
    -❌ **Otherwise:** The average test runs no longer than few ms, a typical API call last 100ms>, this makes each test ~20x slower - +❌ **Autrement:** Le test moyen ne tourne pas plus de quelques ms, un API call moyen dure environ 100ms. Çela rend les tests ~20x plus lent.
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: Stubbing or intercepting API calls - +### :clap: Bien faire les choses, exemple: Stub ou intercepter les appels API ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") ```javascript From d45845805677b9c826e7129b9797109525f0585b Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 30 Aug 2021 13:32:40 +0200 Subject: [PATCH 038/189] Translate 3.7 --- readme-fr.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 4709f876..72ed8a4b 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1289,14 +1289,13 @@ test("When no products exist, show the appropriate message", () => {
    -## ⚪ ️ 3.7 Have very few end-to-end tests that spans the whole system +## ⚪ ️ 3.7 Avoir quelques tests end-to-end qui lancent le système entier -:white_check_mark: **Do:** Although E2E (end-to-end) usually means UI-only testing with a real browser (See bullet 3.6), for other they mean tests that stretch the entire system including the real backend. The latter type of tests is highly valuable as they cover integration bugs between frontend and backend that might happen due to a wrong understanding of the exchange schema. They are also an efficient method to discover backend-to-backend integration issues (e.g. Microservice A sends the wrong message to Microservice B) and even to detect deployment failures - there are no backend frameworks for E2E testing that are as friendly and mature as UI frameworks like [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). The downside of such tests is the high cost of configuring an environment with so many components, and mostly their brittleness - given 50 microservices, even if one fails then the entire E2E just failed. For that reason, we should use this technique sparingly and probably have 1-10 of those and no more. That said, even a small number of E2E tests are likely to catch the type of issues they are targeted for - deployment & integration faults. It's advisable to run those over a production-like staging environment +:white_check_mark: **À faire:** Même si E2E (end-to-end) veux généralement dire test UI avec un vrai navigateur (voir point 3.6), pour d'autre ils signifient des tests qui englobent le système entier, en incluant le vrai backend. Ce type de tests ont beaucoup de valeurs puisqu'ils couvrent les erreurs d'intégrations entre le frontend et le backend à cause d'une mauvaise compréhension des schémas d'échanges. Ils sont aussi un moyen efficace de découvrir des erreurs d'intégrations entre backends (e.g. le microservice A qui envoie le mauvais message au microservice B) et même de détecter des erreurs de déploiement - Il n'y a pas de framework backend pour les tests E2E qui soit aussi simple et mature que les frameworks UI comme [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). Le point négatif de ces tests, c'est le haut cout de configuration pour un environnement avec autant de composants, et surtout leur fragilité - avec 50 microservices, même si un seul échoue l'ensemble du test E2E échoue. Pour cette raison, cette technique doit être utilisée avec parcimonie, il ne faut pas avoir plus de 1-10 tests de ce type. Ceci dit, même un petit nombre de tests E2E sont susceptibles de détecter les problèmes pour lesquels ils sont en place - les défauts de déploiement et d'intégration. Il est conseillé de les exécuter sur un environnement de pré-production.
    -❌ **Otherwise:** UI might invest much in testing its functionality only to realizes very late that the backend returned payload (the data schema the UI has to work with) is very different than expected - +❌ **Autrement:** L'UI peut investir beaucoup en testant ces fonctionnalités seulement pour réaliser que les donnée retournée par le backend sont différentes de ce qui était attendu
    ## ⚪ ️ 3.8 Speed-up E2E tests by reusing login credentials From 09c6d6bd9aff59a3437ee1b96acb69113880c363 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 30 Aug 2021 13:46:48 +0200 Subject: [PATCH 039/189] Translate 3.8 --- readme-fr.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 72ed8a4b..02e1581c 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1298,22 +1298,20 @@ test("When no products exist, show the appropriate message", () => { ❌ **Autrement:** L'UI peut investir beaucoup en testant ces fonctionnalités seulement pour réaliser que les donnée retournée par le backend sont différentes de ce qui était attendu
    -## ⚪ ️ 3.8 Speed-up E2E tests by reusing login credentials - -:white_check_mark: **Do:** In E2E tests that involve a real backend and rely on a valid user token for API calls, it doesn't payoff to isolate the test to a level where a user is created and logged-in in every request. Instead, login only once before the tests execution start (i.e. before-all hook), save the token in some local storage and reuse it across requests. This seem to violate one of the core testing principle - keep the test autonomous without resources coupling. While this is a valid worry, in E2E tests performance is a key concern and creating 1-3 API requests before starting each individual tests might lead to horrible execution time. Reusing credentials doesn't mean the tests have to act on the same user records - if relying on user records (e.g. test user payments history) than make sure to generate those records as part of the test and avoid sharing their existence with other tests. Also remember that the backend can be faked - if your tests are focused on the frontend it might be better to isolate it and stub the backend API (see bullet 3.6). +## ⚪ ️ 3.8 Accélérer les tests E2E en réutilisants les informations d'authentification +:white_check_mark: **à faire:** Dans des tests E2E qui incluent un vrai backend et utilisent un token utilisteur valide pour les appels API, ce n'est pas rentable d'isoler les tests à un niveau ou l'utilisateur est créé et authentifié à chaque requete. A la place, authentifie l'utilisateur une seule fois avant que l'execution des tests commencent (i.e before-all hook), enregistre le token en local et réutilise le dans les requetes. Ça semble violer un des principes de test principal - garder les tests autonomes sans associers les ressources. Même si c'est une inquiétude valide, dans les tests E2E la performance est une inquiétude clé et créer 1-3 requête API avant chaque test peut mener a un temps d'execution horrible. Réutiliser les informations d'authentification ne veux pas dire que les tests doivent agir sur la même entrée utilisateur - si le test compte sur les entrée utilisateur (e.g. test l'historique de paiement d'un utilisateur) alors assure toi de générer ces entrées dans le test et évite de les partager avec d'autres tests. Rappelles-toi aussi que le backend peut être simulé - Si les tests se concentrent sur le frontend, il vaux mieux les isoler et simuler l'API backend (voir point 3.6).
    -❌ **Otherwise:** Given 200 test cases and assuming login=100ms = 20 seconds only for logging-in again and again +❌ **Autrement:** Si on prend 200 cas de tests et qu'on estime l'authentification à 100ms = 20 secondes simplement pour s'authentifier encore et encore
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: Logging-in before-all and not before-each - +### :clap: Bien faire les choses, exemple: Se connecter dans le before-all pas dans le before-each ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") ```javascript From b0c35f85b28a4b9b6e4326f3fe1a7de11657d6a1 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Tue, 31 Aug 2021 20:08:05 +0200 Subject: [PATCH 040/189] Translate 3.9 --- readme-fr.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 02e1581c..fc814112 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1344,21 +1344,21 @@ beforeEach(setUser => () {
    -## ⚪ ️ 3.9 Have one E2E smoke test that just travels across the site map +## ⚪ ️ 3.9 Avoir un test E2E qui parcours juste les pages du site -:white_check_mark: **Do:** For production monitoring and development-time sanity check, run a single E2E test that visits all/most of the site pages and ensures no one breaks. This type of test brings a great return on investment as it's very easy to write and maintain, but it can detect any kind of failure including functional, network and deployment issues. Other styles of smoke and sanity checking are not as reliable and exhaustive - some ops teams just ping the home page (production) or developers who run many integration tests which don't discover packaging and browser issues. Goes without saying that the smoke test doesn't replace functional tests rather just aim to serve as a quick smoke detector +:white_check_mark: **À faire:** Pour le suivi de production et la vérification pendant le développement, lance un seul test E2E qui visite toute ou la plupart des pages du site et vérifie qu'aucune n'échoue. Ce type de test apporte un bon retour sur investissement puisqu'il est trés simple à écrire et maintenir, mais peut détecter tout type d'erreur en incluant les problèmes fonctionnels, de réseau ou de déploiement. Les autres types de smoke test et sanity check ne sont pas aussi fiable et exhaustifs - certaines équipes opérationnelles ne font que ping la page d'accueil (production) ou les développeurs qui lancent plusieurs tests d'intégrations qui ne révèlent pas les problèmes de packaging ou liés au navigateur. Il est évident que ce smoke test ne remplace pas les test fonctionnels, mais il sert à détecter rapidement les problèmes.
    -❌ **Otherwise:** Everything might seem perfect, all tests pass, production health-check is also positive but the Payment component had some packaging issue and only the /Payment route is not rendering +❌ **Autrement:** Tout peu sembler parfait, tout les tests passent, le health-check de production est également positif mais le composant de paiement a eu des erreurs de packaging et suel la route /payment ne s'affiche pas
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: Smoke travelling across all pages +### :clap: Bien faire les choses, exemple: Smoke test qui parcours toute les pages ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") From dd61c74672f647802c6d7c4a16fa5687ce4d7c08 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Tue, 31 Aug 2021 20:18:56 +0200 Subject: [PATCH 041/189] Translate 3.10 --- readme-fr.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index fc814112..f28c681f 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1379,20 +1379,21 @@ it("When doing smoke testing over all page, should load them all successfully",
    -## ⚪ ️ 3.10 Expose the tests as a live collaborative document +## ⚪ ️ 3.10 Exposer les tests comme un document collaboratif -:white_check_mark: **Do:** Besides increasing app reliability, tests bring another attractive opportunity to the table - serve as live app documentation. Since tests inherently speak at a less-technical and product/UX language, using the right tools they can serve as a communication artifact that greatly aligns all the peers - developers and their customers. For example, some frameworks allow expressing the flow and expectations (i.e. tests plan) using a human-readable language so any stakeholder, including product managers, can read, approve and collaborate on the tests which just became the live requirements document. This technique is also being referred to as 'acceptance test' as it allows the customer to define his acceptance criteria in plain language. This is [BDD (behavior-driven testing)](https://en.wikipedia.org/wiki/Behavior-driven_development) at its purest form. One of the popular frameworks that enable this is [Cucumber which has a JavaScript flavor](https://github.com/cucumber/cucumber-js), see example below. Another similar yet different opportunity, [StoryBook](https://storybook.js.org/), allows exposing UI components as a graphic catalog where one can walk through the various states of each component (e.g. render a grid w/o filters, render that grid with multiple rows or with none, etc), see how it looks like, and how to trigger that state - this can appeal also to product folks but mostly serves as live doc for developers who consume those components. +:white_check_mark: **À faire:** En plus d'améliorer la stabilité de l'application, les tests apportent une autre opportunitée intéressante - ils servent comment une documentation de l'app. +Puisque les tests parlent naturellement à un niveau moins technique avec un language plus produit/UX, en utilisant les bons outils, ils peuvent être utilisés comme un outil de communication qui aligne toute l'équipe - les développeurs et les clients. +Par exemple, certains frameworks permettent d'exprimer les parcours et les attentes (i.e les plans de tests) en utilisant un language lisible par l'humain, donc chaque personne impliquée, y compris les product manager, peuvent lire, approuver et communiquer sur les tests qui sont juste devenu le document de spécification. Cette technique s'appelle aussi 'test d'acceptance' puisqu'il permet au client de définir ses critères de validité en language simple. Il s'agit de [BDD (behavior-driven testing)](https://en.wikipedia.org/wiki/Behavior-driven_development) dans sa forme la plus pure. L'un des frameworks populaire qui permet ça est [Cucumber qui a un goût de Javascript](https://github.com/cucumber/cucumber-js), voir l'exemple ci-dessous. Une autre opportunité similaire, [StoryBook](https://storybook.js.org/) permet d'exposer les composants UI comme un catalogue graphique dans lequel on peux se promener à travers les différents états de chaque composant (e.g afficher une grille avec ou sans filtre, l'afficher avec plusieurs lignes ou aucune, etc), voir à quoi il ressemble, et comment déclencher cet état - cela peut servir aux équipe produit mais sert surtout de documentation aux développeurs qui utilisent ces composants -❌ **Otherwise:** After investing top resources on testing, it's just a pity not to leverage this investment and win great value +❌ **Autrement:** Aprés avoir investi des ressources dans les tests, ce serait juste dommage de ne pas se servir de cet investissement pour apporter encore plus de valeur
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: Describing tests in human-language using cucumber-js - +### :clap: Bien faire les choses, exemple: Décrire les tests dans un language humain avec cucumber-js ![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Examples using Cucumber") ```javascript @@ -1412,8 +1413,7 @@ Feature: Twitter new tweet ``` -### :clap: Doing It Right Example: Visualizing our components, their various states and inputs using Storybook - +### :clap: Bien faire les choses, exemple: Visualiser nos composants, leurs états et entrées en utilisant Storybook ![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") ![alt text](assets/story-book.jpg "Storybook") From ce9c0323bd2efda191f2988fcd5dec2ca66eab28 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Tue, 31 Aug 2021 20:34:35 +0200 Subject: [PATCH 042/189] Translate 3.11 --- readme-fr.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index f28c681f..d2c3d894 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1422,27 +1422,27 @@ Feature: Twitter new tweet

    -## ⚪ ️ 3.11 Detect visual issues with automated tools +## ⚪ ️ 3.11 Détecter les problèmes visuels avec des outils automatisés -:white_check_mark: **Do:** Setup automated tools to capture UI screenshots when changes are presented and detect visual issues like content overlapping or breaking. This ensures that not only the right data is prepared but also the user can conveniently see it. This technique is not widely adopted, our testing mindset leans toward functional tests but it's the visuals what the user experience and with so many device types it's very easy to overlook some nasty UI bug. Some free tools can provide the basics - generate and save screenshots for the inspection of human eyes. While this approach might be sufficient for small apps, it's flawed as any other manual testing that demands human labor anytime something changes. On the other hand, it's quite challenging to detect UI issues automatically due to the lack of clear definition - this is where the field of 'Visual Regression' chime in and solve this puzzle by comparing old UI with the latest changes and detect differences. Some OSS/free tools can provide some of this functionality (e.g. [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>) but might charge significant setup time. The commercial line of tools (e.g. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) takes is a step further by smoothing the installation and packing advanced features like management UI, alerting, smart capturing by eliminating 'visual noise' (e.g. ads, animations) and even root cause analysis of the DOM/CSS changes that led to the issue +:white_check_mark: **À faire:** Configure des outils automatisés pour capturer des screenshots de l'UI quand des changements sont présentés et détecter les problèmes visuels comme du contenu qui se superpose ou qui est cassé. Cela permet de vérifier que non seulement les bonnes données sont présente mais également que l'utilisateur peut les voir correctement. Cette technique n'est pas trés courante, notre état d'esprit quand on pense aux tests est tourné sur les tests fonctionnels mais c'est le visuel que l'utilisateur expérimente et avec le nombre d'appareils différents disponible il est simple de rater un bug UI important. Certains outils gratuit procurent les bases - générer et enregistrer les screenshots pour qu'ils soient inspectés par un humain. Même si cette approche peut être suffisante pour de petites apps, son défaut comme tout test manuel est qu'il demande une intervention humaine à chaque fois que quelque chose change. D'un autre coté, il est assez difficile de détecter des problèmes UI automatiquement à cause du manque de définition claire - C'est ici que le domaine de 'Visual Regression' entre en jeu et résout ce problème en comparant d'ancienne UI avec les changements les plus récent pour détecter les différences. Certains outils gratuits peuvent fournir certaines de ces fonctionnalités (e.g [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>)) mais peuvent demander un temps de configuration considérable. Les outils commerciaux (e.g. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) vont un peu plus loin en simplifiant l'installation et en apportant des fonctionnalités avancés comme la gestion de l'UI, des alertes, de la capture automatique en éliminant le "bruit visuel" (e.g. pubs, animations) et même l'analyse du changement DOM/CSS qui a provoqué ce problème.
    -❌ **Otherwise:** How good is a content page that display great content (100% tests passed), loads instantly but half of the content area is hidden? +❌ **Autrement:** Quelle est la qualité d'une page qui affiche un bon contenu (100% des tests passent), charge instantanément mais dont la moitié du contenu est caché ?
    -
    Code Examples +
    Exemple de code
    -### :thumbsdown: Anti-Pattern Example: A typical visual regression - right content that is served badly +### :thumbsdown: Exemple d'anti pattern: Une régression visuelle typique - le bon contenu qui est mal servi ![alt text](assets/amazon-visual-regression.jpeg "Amazon page breaks")
    -### :clap: Doing It Right Example: Configuring wraith to capture and compare UI snapshots +### :clap: Bien faire les choses, exemple: Configurer wraith pour capturer et comparer les snapshots de l'UI ![](https://img.shields.io/badge/🔨%20Example%20using%20Wraith-blue.svg "Using Wraith") @@ -1471,7 +1471,7 @@ paths: path: /subscribe ``` -### :clap: Doing It Right Example: Using Applitools to get snapshot comparison and other advanced features +### :clap: Bien faire les choses, exemple: Utiliser Applitools pour obtenir des comparaisons de snapshots et d'autres fonctionnalités avancées ![](https://img.shields.io/badge/🔨%20Example%20using%20AppliTools-blue.svg "Using Applitools") ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") From 13fcf8b600552247852ac38b140b5cd46e15ae84 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Tue, 31 Aug 2021 20:45:27 +0200 Subject: [PATCH 043/189] Translate 4.1 --- readme-fr.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index d2c3d894..f0751d63 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1498,33 +1498,33 @@ describe("visual validation", () => {

    -# Section 4️⃣: Measuring Test Effectiveness +# Section 4️⃣: Mesurer l'éfficacité des tests

    -## ⚪ ️ 4.1 Get enough coverage for being confident, ~80% seems to be the lucky number +## ⚪ ️ 4.1 Avoir assez de couverture pour être confiant, ~80% semble être le nombre magique -:white_check_mark: **Do:** The purpose of testing is to get enough confidence for moving fast, obviously the more code is tested the more confident the team can be. Coverage is a measure of how many code lines (and branches, statements, etc) are being reached by the tests. So how much is enough? 10–30% is obviously too low to get any sense about the build correctness, on the other side 100% is very expensive and might shift your focus from the critical paths to the exotic corners of the code. The long answer is that it depends on many factors like the type of application — if you’re building the next generation of Airbus A380 than 100% is a must, for a cartoon pictures website 50% might be too much. Although most of the testing enthusiasts claim that the right coverage threshold is contextual, most of them also mention the number 80% as a thumb of a rule ([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)) that presumably should satisfy most of the applications. +:white_check_mark: **À faire:** Le but des tests est d'être assez confiant pour avancer rapidement, évidemment, plus le code est testé plus l'équipe peut être confiante. La couverture (coverage) est une mesure du nombre de lignes de code (et branches, statements, etc) sont atteint par les tests. À partir de quand est-ce suffisant ? 10-30% est évidemment trop bas pour avoir le moindre idée de la validité du build, d'un autre coté 100% est vraiment couteux et peut dévier votre intêret des parties importantes pour des coints exotiques du code. La réponse longue est que ça dépend de plusieurs facteurs comme le type de l'application - si tu construis la prochaine génération d'Airbus A380 alors 100% est obligatoire, pour un site d'image de dessin animé 50% peut être déjà trop. Même si la plupart des amateurs de tests assurent que le bon seuil dépend du contexte, la plupart d'entre eux mentionnent également le nombre 80% est une bonne règle générale ([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)) qui devrait répondre au besoin de la plupart des applications. -Implementation tips: You may want to configure your continuous integration (CI) to have a coverage threshold ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) and stop a build that doesn’t stand to this standard (it’s also possible to configure threshold per component, see code example below). On top of this, consider detecting build coverage decrease (when a newly committed code has less coverage) — this will push developers raising or at least preserving the amount of tested code. All that said, coverage is only one measure, a quantitative based one, that is not enough to tell the robustness of your testing. And it can also be fooled as illustrated in the next bullets +Conseil d'implémentation: Tu peux vouloir configurer ton intégration continu pour qu'elle ai un seuil de couverture ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) et arrêter les builds qui ne répondent pas à ce standard (il est également possible de configurer un seuil par composant, voir l'exemple ci-dessous). En plus de ça, envisage de détecter les baisse de couverture (quand un nouveau commit à une couverture infèrieure) - cela poussera les développeurs à augmenter ou au moins à conserver la même quantité de code testé. Maintenant que c'est dit, la couverture n'est qu'une mesure, une quantitative, ce n'est pas assez pour dire si vos tests sont robustes. Et il peut aussi être biaisé comme on le verra dans le point suivant
    -❌ **Otherwise:** Confidence and numbers go hand in hand, without really knowing that you tested most of the system — there will also be some fear and fear will slow you down +❌ **Autrement:** La confiance et les nombres vont ensemble, sans vraiment savoir si tu testes la majorité du système, il y aura de la peur, et la peur va te ralentir
    -
    Code Examples +
    Exemple de code
    -### :clap: Example: A typical coverage report +### :clap: Example: Un rapport de couverture classique ![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "A typical coverage report")
    -### :clap: Doing It Right Example: Setting up coverage per component (using Jest) +### :clap: Bien faire les choses, exemple: Configurer la couverture par composant (avec Jest) ![](https://img.shields.io/badge/🔨%20Example%20using%20Jest-blue.svg "Using Jest") From aa4cf6e198b62b6d7e23c5960d72726998a6b2ab Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Wed, 1 Sep 2021 17:08:12 +0200 Subject: [PATCH 044/189] Translate 4.2 --- readme-fr.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index f0751d63..98f8756c 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1518,7 +1518,7 @@ Conseil d'implémentation: Tu peux vouloir configurer ton intégration continu p
    -### :clap: Example: Un rapport de couverture classique +### :clap: Exemple: Un rapport de couverture classique ![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "A typical coverage report") @@ -1534,22 +1534,22 @@ Conseil d'implémentation: Tu peux vouloir configurer ton intégration continu p

    -## ⚪ ️ 4.2 Inspect coverage reports to detect untested areas and other oddities +## ⚪ ️ 4.2 Inspecter les rapports de couverture pour détecter les sections qui ne sont pas testées et autres bizarreries -:white_check_mark: **Do:** Some issues sneak just under the radar and are really hard to find using traditional tools. These are not really bugs but more of surprising application behavior that might have a severe impact. For example, often some code areas are never or rarely being invoked — you thought that the ‘PricingCalculator’ class is always setting the product price but it turns out it is actually never invoked although we have 10000 products in DB and many sales… Code coverage reports help you realize whether the application behaves the way you believe it does. Other than that, it can also highlight which types of code is not tested — being informed that 80% of the code is tested doesn’t tell whether the critical parts are covered. Generating reports is easy — just run your app in production or during testing with coverage tracking and then see colorful reports that highlight how frequent each code area is invoked. If you take your time to glimpse into this data — you might find some gotchas +:white_check_mark: **À faire:** Certains problèmes passent juste sous le radar et sont difficile à détecter en utilisants des outils traditionnels. Ce ne sont pas vraiment des beugs mais plutot des comportement surprenants de l'application qui peuvent avoir un impact important. Par exemple, souvent certaines parties du code sont rarement voir jamais invoquées - tu penses que la classe 'PricingCalculator' s'occupe toujours de déterminer le prix du produit mais il se trouve qu'elle n'est jamais invoquée alors qu'on a plus de 10000 produits en base de donnée et de nombreuses ventes ... Les rapports de couvertures t'aide à déterminer si l'application se comporte comme tu penses qu'elle le fait. En plus de ça, ils peuvent aussi montrer le type de code qui n'est pas testé - Être informé que 80% du code est testé n'indique pas si les parties critiques sont couvertes. Générer des rapports est simple - lance juste ton application en production ou pendant les tests avec le tracking de couverture activé et récupère des rapports qui montrent à quel fréquence chaque partie du code est invoquée. Si tu prend ton temps pour regarder ces donnée, tu pourras trouver des pièges
    -❌ **Otherwise:** If you don’t know which parts of your code are left un-tested, you don’t know where the issues might come from +❌ **Autrement:** Si tu ne sais pas quelles parties du code ne sont pas couvertes par les tests, tu ne sais pas d'ou peuvent venir les problèmes
    -
    Code Examples +
    Exemple de code
    -### :thumbsdown: Anti-Pattern Example: What’s wrong with this coverage report? +### :thumbsdown: Exemple d'anti pattern: Qu'est-ce qui ne va pas dans ce rapport de couverture ? -Based on a real-world scenario where we tracked our application usage in QA and find out interesting login patterns (Hint: the amount of login failures is non-proportional, something is clearly wrong. Finally it turned out that some frontend bug keeps hitting the backend login API) +Basé sur un scénario réel, où nous avont tracké l'usage de notre application en QA et detecté un pattern intéressant sur l'authentification (indice: la quantité d'erreur de connexion n'est pas proportionnelle, quelque chose ne va pas. Finalement il s'est avéré qu'un bug front-end n'arrétait pas d'appeler l'API d'authentification) ![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report?") From f97438c87dcf4cb8c7609a820531476197b42ed4 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Thu, 2 Sep 2021 13:58:32 +0200 Subject: [PATCH 045/189] Translate 4.3 --- readme-fr.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 98f8756c..8c9a1b19 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1557,28 +1557,28 @@ Basé sur un scénario réel, où nous avont tracké l'usage de notre applicatio

    -## ⚪ ️ 4.3 Measure logical coverage using mutation testing +## ⚪ ️ 4.3 Mesurer la couverture logique en utilisant les tests de mutations -:white_check_mark: **Do:** The Traditional Coverage metric often lies: It may show you 100% code coverage, but none of your functions, even not one, return the right response. How come? it simply measures over which lines of code the test visited, but it doesn’t check if the tests actually tested anything — asserted for the right response. Like someone who’s traveling for business and showing his passport stamps — this doesn’t prove any work done, only that he visited few airports and hotels. +:white_check_mark: **À faire:** Les données de couverture traditionnelles mentent souvent: elles peuvent montrer 100% de couverture, mais aucune de tes fonctions, pas même une seule, ne retourne la bonne réponse. Pourquoi ? Il mesure simplement le nombre de ligne de code que les tests ont visités, mais il ne vérifie pas si les tests ont effectivement testé quelque chose et vérifié la réponse. Comme quelqu'un qui effectuerai un voyage d'affaire et qui montre les tampons sur son passeport - Cela ne prouve pas qu'il a travaillé, seulement qu'il a visité quelques aéroports et hotels. -Mutation-based testing is here to help by measuring the amount of code that was actually TESTED not just VISITED. [Stryker](https://stryker-mutator.io/) is a JavaScript library for mutation testing and the implementation is really neat: +Les tests de mutations sont la pour aider à mesurer la quantité de code qui a effectivement été TESTÉ et pas juste VISITé. [Stryker](https://stryker-mutator.io/) est une librairie Javascript pour les teests de mutation et son implémentation est très soignée : -(1) it intentionally changes the code and “plants bugs”. For example the code newOrder.price===0 becomes newOrder.price!=0. This “bugs” are called mutations +(1) Il change volontairement le code et "implante des beugs". Par exemple, le code newOrder.price === 0 devient newOrder.price != 0. Ces "beugs" sont appelés des mutations -(2) it runs the tests, if all succeed then we have a problem — the tests didn’t serve their purpose of discovering bugs, the mutations are so-called survived. If the tests failed, then great, the mutations were killed. +(2) Il lance les tests, si tous réussissent, alors on a un problème - Les tests n'ont pas remplis leur rôle en découvrant les beugs, les mutations sont dites survivantes. Si les tests échouent, c'est bon, les mutations ont été tués. -Knowing that all or most of the mutations were killed gives much higher confidence than traditional coverage and the setup time is similar +Savoir que toute ou la plupart des mutations ont été tués donne une meilleure confiance qu'un rapport de couverture traditionnel et le temps de configuration est similaire.
    -❌ **Otherwise:** You’ll be fooled to believe that 85% coverage means your test will detect bugs in 85% of your code +❌ **Autrement:** Tu seras dupé en croyant que 85% de couverture de code signifie que tes tests détecteront les beugs dans 85% du code
    -
    Code Examples +
    Exemple de code
    -### :thumbsdown: Anti-Pattern Example: 100% coverage, 0% testing +### :thumbsdown: Exemple d'anti pattern: 100% de couverture, 0% testé ![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Using Stryker") @@ -1598,7 +1598,7 @@ it("Test addNewOrder, don't use such test names", () => {
    -### :clap: Doing It Right Example: Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations) +### :clap: Bien faire les choses, exemple: Un rapport Stryker, un outil pour les tests de mutations, qui détecte et compte la quantité de code qui n'est pas testé (Mutations) ![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations)") From c0c8fd6fcda2dfaa68dbe4d8d54bfe7133f32bfe Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Thu, 2 Sep 2021 14:04:29 +0200 Subject: [PATCH 046/189] Translate 4.4 --- readme-fr.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 8c9a1b19..450c6bdb 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1606,20 +1606,19 @@ it("Test addNewOrder, don't use such test names", () => {

    -## ⚪ ️4.4 Preventing test code issues with Test linters - -:white_check_mark: **Do:** A set of ESLint plugins were built specifically for inspecting the tests code patterns and discover issues. For example, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) will warn when a test is written at the global level (not a son of a describe() statement) or when tests are [skipped](https://mochajs.org/#inclusive-tests) which might lead to a false belief that all tests are passing. Similarly, [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) can, for example, warn when a test has no assertions at all (not checking anything) +## ⚪ ️4.4 Éviter les problèmes dans le code de test avec les Test linters +:white_check_mark: **À faire:** Un groupe de plugins ESLint ont été développés spécifiquement pour inspecter le code de test et détecter les problèmes. Par exemple, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) t'avertira lorsqu'un test est écrit à un niveau global (pas un enfant d'une déclaration describe()) ou lorsque les tests sont [sautés](https://mochajs.org/#inclusive-tests), ce qui peut conduire à une fausse croyance que les tests passent. De façon similaire, [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) peut avertir lorsqu'un test n'as pas d'assertion (ne vérifie rien)
    -❌ **Otherwise:** Seeing 90% code coverage and 100% green tests will make your face wear a big smile only until you realize that many tests aren’t asserting for anything and many test suites were just skipped. Hopefully, you didn’t deploy anything based on this false observation +❌ **Autrement:** Voir 90% de couverture de code et 100% de tests verts fera apparaitre un grand sourire sur ton visage, jusqu'à ce que tu réalises que de nombreux tests ne vérifient rien et que plusieurs suites de tests ont été sautées. Avec un peu de chance, tu n'as rien déployé basé sur de fausses observations
    -
    Code Examples +
    Exemple de code
    -### :thumbsdown: Anti-Pattern Example: A test case full of errors, luckily all are caught by Linters +### :thumbsdown: Exemple d'anti pattern: Un cas de test plein d'erreur, heuresement toutes détectés par les Linters ```javascript describe("Too short description", () => { From ff271c059b869374fcefe7113ea01ac55ddefc50 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Fri, 3 Sep 2021 14:48:20 +0200 Subject: [PATCH 047/189] Translate 5.1 --- readme-fr.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 450c6bdb..186bc76a 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1638,24 +1638,25 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test

    -# Section 5️⃣: CI and Other Quality Measures +# Section 5️⃣: CI et autres mesures de qualité

    -## ⚪ ️ 5.1 Enrich your linters and abort builds that have linting issues +## ⚪ ️ 5.1 Enrichir ses linter et annuler les builds qui ont des problèmes de lint + +:white_check_mark: **À faire:** Les linters sont un repas gratuit, avec 5 minutes de configurations, tu as gratuitement un auto-pilote qui surveille ton code et repère les problèmes pendant que tu tapes. Les jours ou les linters était reservés a l'esthetique sont terminés (pas de point-virgules!). De nos jours, les linters peuvent détecté des problèmes serieux comme des erreurs qui ne sont pas thrown correctement et les pertes d'informations. En plus de ta liste de règles basiques (like [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) or [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), considère d'ajouter des linters spécialisés comme [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) qui peux détecter les tests sans assertions, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) qui détecte les promesses qui ne se resolvent pas (le code ne va jamais continuer), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) qui peut découvrir les regex qui peuvent être utilisé pour des attaques DOS, et [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) qui est capable de t'indiquer lorsque le code utilise une méthode de librairie qui fait partie des méthodes du coeur V8 comme Lodash.\_map(...) -:white_check_mark: **Do:** Linters are a free lunch, with 5 min setup you get for free an auto-pilot guarding your code and catching significant issue as you type. Gone are the days where linting was about cosmetics (no semi-colons!). Nowadays, Linters can catch severe issues like errors that are not thrown correctly and losing information. On top of your basic set of rules (like [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) or [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), consider including some specializing Linters like [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) that can discover tests without assertions, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) can discover promises with no resolve (your code will never continue), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) which can discover eager regex expressions that might get used for DOS attacks, and [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) is capable of alarming when the code uses utility library methods that are part of the V8 core methods like Lodash.\_map(…)
    -❌ **Otherwise:** Consider a rainy day where your production keeps crashing but the logs don’t display the error stack trace. What happened? Your code mistakenly threw a non-error object and the stack trace was lost, a good reason for banging your head against a brick wall. A 5 min linter setup could detect this TYPO and save your day +❌ **Autrement:** Imagine un jour de pluie ou ta production n'arrête pas de crasher mais les logs ne montrent aucune stack trace d'erreur. Qu'est-ce qu'il s'est passé ? Ton code a malencontreusement émit un objet qui n'était pas une erreur et la stack trace a été perdu, une bonne raison de se taper la tête contre les murs. 5 minutes de configurations d'un linter pourrait permettre de détecter cette erreur et sauver la journée
    -
    Code Examples +
    Exemple de code
    -### :thumbsdown: Anti-Pattern Example: The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug +### :thumbsdown: Exemple d'anti pattern: Le mauvais objet d'erreur est émit par erreur, aucune stack-trace ne va apparaitre pour cette erreur. Heuresement, ESLint catch le prochain beug de production ![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug") From 8916c9ab1b87df0b23ce918b97bc5b7228054d53 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 6 Sep 2021 09:49:09 +0200 Subject: [PATCH 048/189] Translate 5.2 --- readme-fr.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 186bc76a..8c5cc34b 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1664,22 +1664,21 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test

    -## ⚪ ️ 5.2 Shorten the feedback loop with local developer-CI +## ⚪ ️ 5.2 Raccourcir la boucle de retours avec du CI local pour les développeurs -:white_check_mark: **Do:** Using a CI with shiny quality inspections like testing, linting, vulnerabilities check, etc? Help developers run this pipeline also locally to solicit instant feedback and shorten the [feedback loop](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). Why? an efficient testing process constitutes many and iterative loops: (1) try-outs -> (2) feedback -> (3) refactor. The faster the feedback is, the more improvement iterations a developer can perform per-module and perfect the results. On the flip, when the feedback is late to come fewer improvement iterations could be packed into a single day, the team might already move forward to another topic/task/module and might not be up for refining that module. +:white_check_mark: **À faire:** Tu utilises un outil de CI avec une bonne inspection de qualité comme des tests, du linting, des checks de vulnérabilités, etc ? Aide les développeurs à lancer également cette pipeline en local pour solliciter un retour instantané et raccourcir la [boucle de feedback](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). Pourquoi ? Un processus de tests efficace constitue de nombreuses boucles itératives: (1) essai -> (2) retours -> (3) refactor. Plus le retour est rapide, plus le développeur peut effectuer d'itérations d'améliorations par modules et perfonctionner le résultat. D'un autre coté, lorsque les retours sont lent à arriver, moins d'améliorations peuvent être effectuée au sein d'une journée, l'équipe peut être déjà passé à un autre sujet/tache/module et peut ne pas être prête a affiner ce module. -Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) allow running the pipeline locally. Some commercial tools like [wallaby provide highly-valuable & testing insights](https://wallabyjs.com/) as a developer prototype (no affiliation). Alternatively, you may just add npm script to package.json that runs all the quality commands (e.g. test, lint, vulnerabilities) — use tools like [concurrently](https://www.npmjs.com/package/concurrently) for parallelization and non-zero exit code if one of the tools failed. Now the developer should just invoke one command — e.g. ‘npm run quality’ — to get instant feedback. Consider also aborting a commit if the quality check failed using a githook ([husky can help](https://github.com/typicode/husky)) +En pratique, certains fournisseurs de CI (Exemple: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) autorisent le lancement de la pipeline en local. Certains outils commerciaux comme [wallaby fournissent des informations de valeur et des tests](https://wallabyjs.com/) pendant que le développeur prototype (pas d'affiliation). Alternativement, tu peux simplement ajouter un script npm au package.json qui lance toute les commandes de qualités (e.g. tests, lint, vulnérabilités) - utilise des outils comme [concurrently](https://www.npmjs.com/package/concurrently) pour la parallélisation et des code de retour différents de 0 si l'un des outils échoue. Maintenant le développeur peut juste lancer une commande - e.g. 'npm run quality' - pour recevoir un retour instantané. Envisage également d'annuler un commit si le controle de qualité ne passe pas en utilisant githook ([husky can help](https://github.com/typicode/husky))
    -❌ **Otherwise:** When the quality results arrive the day after the code, testing doesn’t become a fluent part of development rather an after the fact formal artifact - +❌ **Autrement:** Quand les résultats de qualité arrivent le jour suivant le développement, les tests ne sont pas une partie fluide du développement mais plutot une étape formelle aprés coup
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: npm scripts that perform code quality inspection, all are run in parallel on demand or when a developer is trying to push new code +### :clap: Bien faire les choses, exemple: Script npm qui effectue une inspection de la qualité du code, tout est lancé en parallèle sur demande ou lorsque le développeur essaye de push du code ```javascript "scripts": { From 68215922ef890186ee77827616b0ea9862898b50 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 6 Sep 2021 10:01:17 +0200 Subject: [PATCH 049/189] Translate 5.3 --- readme-fr.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 8c5cc34b..021dd6a3 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1703,22 +1703,21 @@ En pratique, certains fournisseurs de CI (Exemple: [CircleCI local CLI](https://

    -## ⚪ ️5.3 Perform e2e testing over a true production-mirror +## ⚪ ️5.3 Effectue des tests e2e sur un vrai mirroir de production -:white_check_mark: **Do:** End to end (e2e) testing are the main challenge of every CI pipeline — creating an identical ephemeral production mirror on the fly with all the related cloud services can be tedious and expensive. Finding the best compromise is your game: [Docker-compose](https://serverless.com/) allows crafting isolated dockerized environment with identical containers using a single plain text file but the backing technology (e.g. networking, deployment model) is different from real-world productions. You may combine it with [‘AWS Local’](https://github.com/localstack/localstack) to work with a stub of the real AWS services. If you went [serverless](https://serverless.com/) multiple frameworks like serverless and [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) allows the local invocation of FaaS code. +:white_check_mark: **À faire:** Les tests end to end (E2E) sont le défi principal de chaque pipeline CI - créer un mirroir éphémère de la production à la volée avec toute les services clouds lié peut être fastidieux et couteux. Le jeu est de trouver le meilleur compromis: [Docker-compose](https://serverless.com/) permet de créer des environnement dockerisés isolés avec des containers identiques en utilisant un simple fichier text mais la technologie backend (e.g réseau, modèle de deploiement) est différents de la vrai production. Tu peux l'associer à [‘AWS Local’](https://github.com/localstack/localstack) pour travailler avec un stub des services AWS. Si tu es [serverless](https://serverless.com/), plusieurs frameworks comme serverless et [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) permettent l'invocation locale de code FaaS. -The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for local and CI-mirroring though many new tools are launched frequently. One approach is running a ‘minimized-Kubernetes’ using tools like [Minikube](https://kubernetes.io/docs/setup/minikube/) and [MicroK8s](https://microk8s.io/) which resemble the real thing only come with less overhead. Another approach is testing over a remote ‘real-Kubernetes’, some CI providers (e.g. [Codefresh](https://codefresh.io/)) has native integration with Kubernetes environment and make it easy to run the CI pipeline over the real thing, others allow custom scripting against a remote Kubernetes. +Le large écosystème de Kubernetes doit encore formaliser un outils standard pour la mise en mirroir locale et CI, bien que de nombreux nouveaux outils soient lancés fréquemment. Une des approche est de lancer un 'minimized-Kubernetes' en utilisant des outils comme [Minikube](https://kubernetes.io/docs/setup/minikube/) et [MicroK8s](https://microk8s.io/). Une autre approche est de testé avec un 'vrai-Kebernetes' distant, certains fournisseurs CI (e.g. [Codefresh](https://codefresh.io/)) ont une intégration native avec l'environnement Kubernetes et rendent simple le lancement d'une pipeline CI sur le vrai environnement, d'autres permettent d'executer des scripts custom sur le Kubernetes distant.
    -❌ **Otherwise:** Using different technologies for production and testing demands maintaining two deployment models and keeps the developers and the ops team separated - +❌ **Autrement:** Utiliser des technologies différentes pour la production et pour les tests demande de maintenir deux modèles de déploiement et créer une séparation entre l'équipe dév et l'équipe ops.
    -
    Code Examples +
    Exemple de code
    -### :clap: Example: a CI pipeline that generates Kubernetes cluster on the fly ([Credit: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/)) +### :clap: Exemple: Une pipeline CI qui génère un cluster Kubernetes à la volée ([Credit: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/))
    deploy:
    stage: deploy
    image: registry.gitlab.com/gitlab-examples/kubernetes-deploy
    script:
    - ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN
    - kubectl create ns $NAMESPACE
    - kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL"
    - mkdir .generated
    - echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF"
    - sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml"
    - kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml
    - kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml
    environment:
    name: test-for-ci
    From 9023c9989e9467e7490dd753921a5f6a6fe5081e Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 6 Sep 2021 10:08:41 +0200 Subject: [PATCH 050/189] Translate 5.4 --- readme-fr.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 021dd6a3..4d248047 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1725,19 +1725,18 @@ Le large écosystème de Kubernetes doit encore formaliser un outils standard po

    -## ⚪ ️5.4 Parallelize test execution +## ⚪ ️5.4 Paralléliser l'exécution des tests -:white_check_mark: **Do:** When done right, testing is your 24/7 friend providing almost instant feedback. In practice, executing 500 CPU-bounded unit test on a single thread can take too long. Luckily, modern test runners and CI platforms (like [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) and [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) can parallelize the test into multiple processes and achieve significant improvement in feedback time. Some CI vendors do also parallelize tests across containers (!) which shortens the feedback loop even further. Whether locally over multiple processes, or over some cloud CLI using multiple machines — parallelizing demand keeping the tests autonomous as each might run on different processes - -❌ **Otherwise:** Getting test results 1 hour long after pushing new code, as you already code the next features, is a great recipe for making testing less relevant +:white_check_mark: **À faire:** Lorsque c'est fait correctement, les tests sont ton ami 24/7 en fournissant un retour quasi instantanné. En pratique, éxécuter 500 tests unitaire liés au processeur sur un seul thread peut prendre trop longtemps. Heuresement, les outils de tests et les plateformes CI moderne (comme [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) et [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) peuvent paralléliser les tests sur plusieurs processus et améliorer significativement le temps de retour. Certains fournisseurs CI font également de la parallélisation de tests à travers des containers (!) ce qui raccourcis encore plus la boucle de retour. Que ce soit locallement sur plusieurs processus, ou sur un serveur Cloud avec plusieurs machines - paralléliser demande de garder les tests autonomes puisqu'ils peuvent tourner sur différents processus. +❌ **Autrement:** Obtenir les résultats de tests 1h aprés avoir publié du nouveau code, pendant que tu es déjà en train de coder la fonctionnalité suivante, est une bonne recette pour rendre les tests moins pertinents
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) +### :clap: Bien faire les choses, exemple: Mocha parallel & Jest distancent facilement le Mocha traditionnel grace à la parallélisation ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) ![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization (Credit: JavaScript Test-Runners Benchmark)") From 0345595930e5a2c8e79ceaa7ab2309c4ada1fe8e Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 6 Sep 2021 10:12:21 +0200 Subject: [PATCH 051/189] Translate 5.5 --- readme-fr.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 4d248047..0eefaa1c 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1744,19 +1744,18 @@ Le large écosystème de Kubernetes doit encore formaliser un outils standard po

    -## ⚪ ️5.5 Stay away from legal issues using license and plagiarism check +## ⚪ ️5.5 Reste loin des problèmes légaux en utilisants des vérification de license et de plagiat -:white_check_mark: **Do:** Licensing and plagiarism issues are probably not your main concern right now, but why not tick this box as well in 10 minutes? A bunch of npm packages like [license check](https://www.npmjs.com/package/license-checker) and [plagiarism check](https://www.npmjs.com/package/plagiarism-checker) (commercial with free plan) can be easily baked into your CI pipeline and inspect for sorrows like dependencies with restrictive licenses or code that was copy-pasted from Stack Overflow and apparently violates some copyrights - -❌ **Otherwise:** Unintentionally, developers might use packages with inappropriate licenses or copy paste commercial code and run into legal issues +:white_check_mark: **À faire:** Les problèmes de licences et de plagiat ne sont probablement pas au centre de votre attention pour l'instant, mais pourquoi ne pas cocher également cette case en 10 minutes ? Plusieurs packages npm comme [license check](https://www.npmjs.com/package/license-checker) et [plagiarism check](https://www.npmjs.com/package/plagiarism-checker) (commerciaux avec un essai gratuit) peuvent être facilement intégré dans ta pipeline CI et inspecter les problèmes tels que les dépendances avec des licences restrictives ou du code qui a été copié-collé à partir de Stack Overflow et qui violerai certains droits d'auteur +❌ **Autrement:** Involontairement, les développeurs peuvent utiliser un packages avec une license inaproprié, ou copier/coller du code commercial et tomber sur des problèmes légaux
    -
    Code Examples +
    Exemple de code
    -### :clap: Doing It Right Example: +### :clap: Bien faire les choses, exemple: ```javascript //install license-checker in your CI environment or also locally From 3f26b0c00021a845fcb70baaffe545513cb66ee7 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 6 Sep 2021 10:23:02 +0200 Subject: [PATCH 052/189] Translate 5.6 --- readme-fr.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 0eefaa1c..358dcd6b 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1774,19 +1774,19 @@ license-checker --summary --failOn BSD

    -## ⚪ ️5.6 Constantly inspect for vulnerable dependencies +## ⚪ ️5.6 Inspecter constamment les dépendences vulnérables -:white_check_mark: **Do:** Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using community tools such as [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), or commercial tools like [snyk](https://snyk.io/) (offer also a free community version). Both can be invoked from your CI on every build +:white_check_mark: **À faire:** Même les dépendances les plus réputés comme Express ont des vulnérabilités connues. Cela peut être apprivoisé facilement avec des outils de la communauté comme [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), ou des outils commerciaux comme [snyk](https://snyk.io/) (qui offre également une version de la communauté gratuite). Les deux peuvent être appelé depuis ton CI à chaque build -❌ **Otherwise:** Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online publications about new threats. Quite tedious +❌ **Autrement:** Garder ton code exempt de vulnérabilités sans les outils appropriés demande de suivre constamment les publications en ligne à propos des nouvelles menaces. Plutot fastidieux.
    -
    Code Examples +
    Exemple de code
    -### :clap: Example: NPM Audit result +### :clap: Exemple: Résultat d'audit Npm ![alt text](assets/bp-26-npm-audit-snyk.png "NPM Audit result") From 02a10cb9837a078f247d695d10f1af7a7fe39e8e Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 6 Sep 2021 10:44:58 +0200 Subject: [PATCH 053/189] Translate 5.7 --- readme-fr.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 358dcd6b..c7ad8605 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1794,26 +1794,26 @@ license-checker --summary --failOn BSD

    -## ⚪ ️5.7 Automate dependency updates +## ⚪ ️5.7 Automatiser les mises-à-jour de dépendences -:white_check_mark: **Do:** Yarn and npm latest introduction of package-lock.json introduced a serious challenge (the road to hell is paved with good intentions) — by default now, packages are no longer getting updates. Even a team running many fresh deployments with ‘npm install’ & ‘npm update’ won’t get any new updates. This leads to subpar dependent packages versions at best or to vulnerable code at worst. Teams now rely on developers goodwill and memory to manually update the package.json or use tools [like ncu](https://www.npmjs.com/package/npm-check-updates) manually. A more reliable way could be to automate the process of getting the most reliable dependency versions, though there are no silver bullet solutions yet there are two possible automation roads: +:white_check_mark: **À faire:** L'introduction récente du package-lock.json par Yarn et npm à introduit un vrai défi (la route vers l'enfer est pavée de bonne intentions) - par défault maintenant, les packages ne sont pas mis à jour. Même une équipe qui lance plusieurs nouveaux déploiement avec 'npm install' & 'npm update' n'aura pas de nouvelles mise à jour. Cela conduit au mieux, à des dépendances à des packages de qualité infèrieur, au pire à du code vulnérable. Les équipes dépendent maintenant de la bonne volonté et de la mémoire des développeur pour mettre à jour manuellement le package.json ou utiliser des outils [comme ncu](https://www.npmjs.com/package/npm-check-updates). Une méthode plus fiable pourrait être d'automatiser le processus de récupération des versions de dépendances les plus fiables, bien qu'il n'y ai pas de solutions miracle, il y a deux possibilités d'automatisation: -(1) CI can fail builds that have obsolete dependencies — using tools like [‘npm outdated’](https://docs.npmjs.com/cli/outdated) or ‘npm-check-updates (ncu)’ . Doing so will enforce developers to update dependencies. +(1) Le CI peut faire échouer les buils qui ont des dépendances obsolètes - en utilisants des outils comme [‘npm outdated’](https://docs.npmjs.com/cli/outdated) ou 'npm-check-updates (ncu)'. Faire ça forcera les développeurs à mettre à jour les dépendances. -(2) Use commercial tools that scan the code and automatically send pull requests with updated dependencies. One interesting question remaining is what should be the dependency update policy — updating on every patch generates too many overhead, updating right when a major is released might point to an unstable version (many packages found vulnerable on the very first days after being released, [see the](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) eslint-scope incident). +(2) Utiliser un outil commercial qui peut scanner le code et envoyer automatiquement une pull-request avec les dépendances mises à jour. La question intéressante restante est, quel devrait être la politique de mises à jour - Mettre à jour chaque patch génère trop de surcharge, mettre à jour juste aprés une release majeure peut introduire une version instable (de nombreuses vulnérabilités sont découverte dans les premiers jours aprés la release, [voir l'incident](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) eslint-scope). -An efficient update policy may allow some ‘vesting period’ — let the code lag behind the @latest for some time and versions before considering the local copy as obsolete (e.g. local version is 1.3.1 and repository version is 1.3.8) +Une politique de mise à jour efficace peut autoriser une 'pèriode d'acquisition' - laisser le code en retard par rapport à @latest pour quelques temps et versions avant de considérer la copie locale comme obsolète (e.g la version locale est 1.3.1 et la version du repo est 1.3.8)
    -❌ **Otherwise:** Your production will run packages that have been explicitly tagged by their author as risky +❌ **Autrement:** Ta production utilisera des packages qui ont été taggé explicitement par leur auteurs comme risquées
    -
    Code Examples +
    Exemple de code
    -### :clap: Example: [ncu](https://www.npmjs.com/package/npm-check-updates) can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions +### :clap: Exemple: [ncu](https://www.npmjs.com/package/npm-check-updates) peut être utilisé manuellement ou dans une pipeline CI pour détecter à quel point le code est en retard vis a vis des dernières versions ![alt text](assets/bp-27-yoni-goldberg-npm.png "ncu can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions") @@ -1821,7 +1821,7 @@ An efficient update policy may allow some ‘vesting period’ — let the c

    -## ⚪ ️ 5.8 Other, non-Node related, CI tips +## ⚪ ️ 5.8 Autre conseils CI, sans rapports avec Node :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 few non-Node related tips that are well-known From 76035d599f6c022540a866caa5cf0fe87aad5813 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 6 Sep 2021 10:55:41 +0200 Subject: [PATCH 054/189] Translate 5.8 --- readme-fr.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index c7ad8605..790c946a 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1823,12 +1823,12 @@ Une politique de mise à jour efficace peut autoriser une 'pèriode d'acquisitio ## ⚪ ️ 5.8 Autre conseils CI, sans rapports avec Node -: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 few non-Node related tips that are well-known +:white_check_mark: **À faire:** Ce post se concentre sur les conseils de tests qui sont en lien avec, ou peuvent être illustrés, avec Node JS. Ce point, cependant, regroupe quelques conseils sans rapports avec Node qui sont bien connus -
    1. Use a declarative syntax. This is the only option for most vendors but older versions of Jenkins allows using code or UI
    2. Opt for a vendor that has native Docker support
    3. Fail early, run your fastest tests first. Create a ‘Smoke testing’ step/milestone that groups multiple fast inspections (e.g. linting, unit tests) and provide snappy feedback to the code committer
    4. Make it easy to skim-through all build artifacts including test reports, coverage reports, mutation reports, logs, etc
    5. Create multiple pipelines/jobs for each event, reuse steps between them. For example, configure a job for feature branch commits and a different one for master PR. Let each reuse logic using shared steps (most vendors provide some mechanism for code reuse)
    6. Never embed secrets in a job declaration, grab them from a secret store or from the job’s configuration
    7. Explicitly bump version in a release build or at least ensure the developer did so
    8. Build only once and perform all the inspections over the single build artifact (e.g. Docker image)
    9. Test in an ephemeral environment that doesn’t drift state between builds. Caching node_modules might be the only exception
    +
    1. Utilise une syntaxe déclarative. C'est la seule option pour la plupart des fournisseurs mais d'anciennes versions de Jenkins autorisent l'utilisation du code ou de l'UI
    2. Choisit un fournisseur qui à une intégration Docker native
    3. Échoue rapidement, lance les tests les plus rapide d'abord. Crée des 'tests de fumée' pour certaines étapes qui regroupe plusieurs inspections rapide (e.g liting, tests unitaires) et fourni des commentaires rapide à celui qui commit le code
    4. Facilite le parcours des informations de build, cela inclut les rapports de tests, de couverture, de mutation, les logs ..etc
    5. Crée plusieurs pipelines/jobs pour chaque évènement, réutiliser les étapes entre eux. Par exemple, configure un job pour les commits de features sur une branche et un différent pour une PR sur master. Laisse chacun réutiliser la logique en utilisants des étapes partagés (la plupart des fournisseurs ont des mécanisme pour réutiliser le code)
    6. Ne met jamais de secrets dans la déclaration du job, récupère les depuis un secret store ou depuis les configurations du job
    7. Augmente explicitement la version dans un build de release, ou au moins vérifie que le développeur l'a fait
    8. Build une fois et efféctue toute les inspections sur l'artefact de build (e.g. Docker image)
    9. Test dans un environnement ephémère qui ne change pas d'état entre les builds. Le cache des nodes peut être la seule exception

    -❌ **Otherwise:** You‘ll miss years of wisdom +❌ **Autrement:** Tu rateras des années de sagesse

    From 58a9d392d740621f99f85effc245f24afcd10e50 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 6 Sep 2021 11:03:44 +0200 Subject: [PATCH 055/189] Translate 5.9 --- readme-fr.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 790c946a..127ba1b5 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1832,20 +1832,20 @@ Une politique de mise à jour efficace peut autoriser une 'pèriode d'acquisitio

    -## ⚪ ️ 5.9 Build matrix: Run the same CI steps using multiple Node versions +## ⚪ ️ 5.9 Structure de build: Lance les mêmes étapes CI sur plusieurs versions de Node -:white_check_mark: **Do:** Quality checking is about serendipity, the more ground you cover the luckier you get in detecting issues early. When developing reusable packages or running a multi-customer production with various configuration and Node versions, the CI must run the pipeline of tests over all the permutations of configurations. For example, assuming we use MySQL for some customers and Postgres for others — some CI vendors support a feature called ‘Matrix’ which allow running the suit of testing against all permutations of MySQL, Postgres and multiple Node version like 8, 9 and 10. This is done using configuration only without any additional effort (assuming you have testing or any other quality checks). Other CIs who doesn’t support Matrix might have extensions or tweaks to allow that +:white_check_mark: **À faire:** Le controle de qualité est un jeu de hasard, plus tu couvres de terrain, plus tu as de chance de détecter les problèmes rapidement. Quand tu développes des packages réutilisable ou que tu lance une production avec plusieurs clients qui ont différentes configurations et versions de Node, le CI doit lancer la pipeline de trests sur toutes les configurations possible. Par exemple, imaginons qu'on utilise MySQL pour certains clients et Postgres pour d'autres - Certains fournisseurs CI supportent une fonctionnalitée appelée 'Matrix' qui permet de lancer les tests contre toute les permutations de MySQL, Postgres et plusieurs versions de Node comme 8, 9 et 10. Cela peut se faire en utilisant seulement des configurations sans efforts supplémentaire (en considérant que tu as des tests ou d'autres controles de qualités). D'autres CIs qui ne supportent pas Matrix peuvent avoir des extensions qui permettent ça
    -❌ **Otherwise:** So after doing all that hard work of writing testing are we going to let bugs sneak in only because of configuration issues? +❌ **Autrement:** Aprés avoir fait tout le travail d'écrire des tests, vas-t-on laisser passer des bugs seulement à cause de problèmes de configurations ?
    -
    Code Examples +
    Exemple de code
    -### :clap: Example: Using Travis (CI vendor) build definition to run the same test over multiple Node versions +### :clap: Exemple: Utiliser les définition de build de Travis (fournisseur CI) pour lancer le même test sur plusieurs versions de Node
    language: node_js
    node_js:
    - "7"
    - "6"
    - "5"
    - "4"
    install:
    - npm install
    script:
    - npm run test
    From 494d02a4ace9958e1e4997a207bcf1457cda0a95 Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 6 Sep 2021 11:10:58 +0200 Subject: [PATCH 056/189] Translate team --- readme-fr.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 127ba1b5..347db426 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -1852,7 +1852,7 @@ Une politique de mise à jour efficace peut autoriser une 'pèriode d'acquisitio

    -# Team +# L'équipe ## Yoni Goldberg @@ -1860,15 +1860,15 @@ Une politique de mise à jour efficace peut autoriser une 'pèriode d'acquisitio
    -**Role:** Writer +**Rôle:** Auteur -**About:** I'm an independent consultant who works with Fortune 500 companies and garage startups on polishing their JS & Node.js applications. More than any other topic I'm fascinated by and aims to master the art of testing. I'm also the author of [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices) +**À propos:** Je suis un consultatn indépendant qui travaille avec des entreprises Fortune 500 et des startup pour peaufiner leurs applications JS et Node.JS. Plus qu'aucun autre sujet, je suis fasciné par et vise à maitriser l'art du test. Je suis aussi l'auteur de [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices) -**📗 Online Course:** Liked this guide and wish to take your testing skills to the extreme? Consider visiting my comprehensive course [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) +**📗 Cours en ligne:** Tu aimes ce guide et tu veux pousser tes compétences de test à l'extreme ? Pense à regarder mon cours complet [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com)
    -**Follow:** +**Me suivre:** - [🐦 Twitter](https://twitter.com/goldbergyoni/) - [📞 Contact](https://testjavascript.com/contact-2/) @@ -1880,30 +1880,30 @@ Une politique de mise à jour efficace peut autoriser une 'pèriode d'acquisitio ## [Bruno Scheufler](https://github.com/BrunoScheufler) -**Role:** Tech reviewer and advisor +**Rôle:** Réviseur et conseiller technique -Took care to revise, improve, lint and polish all the texts +À pris soin de revoir, améliorer, linter et peaufiner tout les textes -**About:** full-stack web engineer, Node.js & GraphQL enthusiast +**À propos:** Ingénieur web full-stack, passioné par Node.js et GraphQL

    ## [Ido Richter](https://github.com/idori) -**Role:** Concept, design and great advice +**Rôle:** Concept, design et bons conseils -**About:** A savvy frontend developer, CSS expert and emojis freak +**À propos:** Un développeur front-end averti, expert CSS et maniaque des émojis ## [Kyle Martin](https://github.com/js-kyle) -**Role:** Helps keep this project running, and reviews security related practices +**Rôle:** Aide à faire tourner ce projet, et revois les pratiques liés à la sécurité -**About:** Loves working on Node.js projects and web application security. +**À propos:** Aime travailler sur des projets Node.JS et la sécurité des applications web. ## Contributors ✨ -Thanks goes to these wonderful people who have contributed to this repository! +Merci à ces merveilleuses personnes qui ont contribué à ce repo! From 976351fafa2ed742bd94a1ad8e8d8b6de16291ac Mon Sep 17 00:00:00 2001 From: mel-mouk Date: Mon, 6 Sep 2021 12:27:30 +0200 Subject: [PATCH 057/189] Global proofreading --- readme-fr.md | 274 +++++++++++++++++++++++++-------------------------- 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/readme-fr.md b/readme-fr.md index 347db426..fb8011e8 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -2,7 +2,7 @@
    -# 👇 Pourquoi ce guide peut faire passer vos compétences de test au niveau supérieur +# 👇 Comment ce guide peut faire passer vos compétences de test au niveau supérieur
    @@ -16,7 +16,7 @@ Embarque pour un voyage qui va bien au-delà des bases et aborde des sujets avan ## 🌐 Full-stack: front, backend, CI ... -Commence par comprendre les pratiques de tests omniprésentes qui sont à la base de tout niveau d'application. Ensuite, plonge dans ton domaine de prédilection : frontend/UI, backend, CI ou peut-être tous ça ? +Commence par comprendre les pratiques de tests omniprésentes qui sont à la base de tout niveau d'application. Ensuite, plonge dans ton domaine de prédilection : frontend/UI, backend, CI ou peut-être tous ça à la fois ?
    @@ -73,13 +73,13 @@ Lignes directrices pour l'intégration continue dans le monde du JS (9 points) ## ⚪️ 0 La règle d'or: Concevoir des tests minimalistes -:white_check_mark: **Do:** +:white_check_mark: **À faire:** Le code des tests n'est pas comme le code de production - conçoit le pour être simple, court, sans abstraction, agréable à utiliser et minimaliste. En regardant le code d'un test, on doit pouvoir comprendre son but instantanément. Nos esprits sont déjà occupés avec le code de production, on n'a pas "d'espace" pour de la complexité additionnelle. Si on essaye d'insérer un autre code compliqué dans nos pauvres cerveaux, l'équipe va être ralentie ce qui est en contradiction avec la raison pour laquelle on fait des tests. En pratique, c'est là que de nombreuses équipes abandonnent tout simplement les tests. -Les tests sont une opportunité pour autre chose - un assistant amical et souriant, un avec qui il est agréable de travailler et qui nous apporte beaucoup pour peu d'investissement. La science nous dit que l'on a deux systèmes cérébraux : le premier est utilisé pour les activités qui ne demandent pas d'effort comme conduire une voiture sur une route vide ; le deuxième sert aux opérations complexe et conscientes comme résoudre une équation mathématique. Conçois tes tests pour le premier système, lire un test doit _sembler_ aussi simple que de modifier un fichier HTML, et pas comme résoudre 2X(17 x 24). +Les tests sont une opportunité pour autre chose - un assistant amical et souriant, un avec qui il est agréable de travailler et qui nous apporte beaucoup pour peu d'investissement. La science nous dit que l'on a deux systèmes cérébraux : le premier est utilisé pour les activités qui ne demandent pas d'effort comme conduire une voiture sur une route vide ; le deuxième sert aux opérations complexes et conscientes comme résoudre une équation mathématique. Conçois tes tests pour le premier système, lire un test doit _sembler_ aussi simple que de modifier un fichier HTML, et pas comme résoudre 2X(17 x 24). On peut y arriver en sélectionnant des techniques, des outils et des cibles de tests qui sont rentables et offrent un bon retour sur investissement. Test seulement ce qui doit être testé, essaye de conserver de la souplesse, et parfois, il vaut même mieux supprimer quelques tests et échanger la fiabilité contre de l'agilité et de la simplicité. @@ -97,28 +97,28 @@ La plupart des conseils ci-dessous sont des dérivés de ce principe. ## ⚪ ️ 1.1 Chaque nom devrait contenir 3 parties -:white_check_mark: **À faire:** Un rapport de test devrait indiquer si la version actuelle de l'application correspond aux attentes pour des personnes qui ne sont pas forcément familier avec la base de code : le testeur, le dev ops qui deploie et toi dans 2 ans. Dans ce but, les noms des tests doivent expliciter les attentes et inclure 3 parties : +:white_check_mark: **À faire:** Un rapport de test devrait indiquer si la version actuelle de l'application correspond aux attentes pour des personnes qui ne sont pas forcément familières avec la base de code : le testeur, le dev ops qui déploie et toi dans 2 ans. Dans ce but, les noms des tests doivent expliciter les attentes et inclure 3 parties : (1) Qu'est-ce qui est testé ? Par exemple, la méthode ProductService.addNewProduct -(2) Dans quel circonstance et scénario ? Par exemple, aucun prix n'est passé à la méthode +(2) Dans quelle circonstance et scénario ? Par exemple, aucun prix n'est passé à la méthode (3) Quel est le résultat attendu ? Par exemple, le produit n'est pas approuvé
    -❌ **Autrement:** Un deploiement a échoué, un test appelé "Add product" à échoué. Est-ce que celà indique exactement ce qui ne fonctionne plus correctement ? +❌ **Autrement:** Un déploiement a échoué, un test appelé "Add product" à échoué. Est-ce que cela indique exactement ce qui ne fonctionne plus correctement ?
    **👇 Note:** Chaque point contient des exemples de codes et parfois une image d'illustration. Cliques pour agrandir.
    -
    Code Examples +
    Exemple de code
    -### :clap: Bien faire les choses Exemple: Un nom de test constitué de 3 parties +### :clap: Bien faire les choses, exemple: Un nom de test constitué de 3 parties ![](https://img.shields.io/badge/🔨%20Example%20using%20Mocha-blue.svg "Using Mocha to illustrate the idea") @@ -138,7 +138,7 @@ describe('Products Service', function() {
    -### :clap: Bien faire les choses Exemple: Un nom de test constitué de 3 parties +### :clap: Bien faire les choses, exemple: Un nom de test constitué de 3 parties ![alt text](/assets/bp-1-3-parts.jpeg "A test name that constitutes 3 parts") @@ -153,9 +153,9 @@ describe('Products Service', function() { ## ⚪ ️ 1.2 Structurer les tests avec le pattern AAA -:white_check_mark: **À faire:** Structures tes tests avec 3 sections séparés: Organiser, Agir & Vérifier (Arrange, Act & Assert: AAA). Suivre cette structure garantit que le lecteur n'utilise pas de "CPU" de cerveau pour comprendre le plan du test: +:white_check_mark: **À faire:** Structure tes tests avec 3 sections séparées: Organiser, Agir & Vérifier (Arrange, Act & Assert: AAA). Suivre cette structure garantit que le lecteur n'utilise pas de "CPU" de cerveau pour comprendre le plan du test : -1er A - Organiser (Arrange): Tout le code permettant de configurer le système selon le scénario qui doit être simulé. Cela peut inclure d'instancier le constructeur de l'élément testé, ajouter des entrées en DB, mocking/stubbing des objets et autre codes de préparation +1er A - Organiser (Arrange): Tout le code permettant de configurer le système selon le scénario qui doit être simulé. Cela peut inclure d'instancier le constructeur de l'élément testé, ajouter des entrées en DB, mocking/stubbing des objets et autres codes de préparation 2ème A - Agir (Act): Exécute l'élément testé. En général 1 seule ligne de code @@ -163,7 +163,7 @@ describe('Products Service', function() {
    -❌ **Autrement:** Non seulement vous avez passé des heures à comprendre le code principal, mais en plus ce qui devait être la partie la plus simple de la journée (tester) vous tord le cerveau. +❌ **Autrement:** Non seulement, vous avez passé des heures à comprendre le code principal, mais en plus ce qui devait être la partie la plus simple de la journée (tester) vous tord le cerveau.
    @@ -172,7 +172,7 @@ describe('Products Service', function() {
    -### :clap: Bien faire les choses Exemple: Un test structuré avec le pattern AAA +### :clap: Bien faire les choses, exemple: Un test structuré avec le pattern AAA ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") @@ -211,7 +211,7 @@ test("Should be classified as premium", () => { ## ⚪ ️1.3 Décrire les attentes dans un language produit: Utiliser des assertions de type BDD -:white_check_mark: **À faire:** Coder tes tests dans un language déclaratif permet au lecteur de comprendre immédiatement sans effectuer un seul cycle de "CPU" de cerveau. Lorsque tu écris du code impératif remplit de logique conditionnelles, le lecteur est forcé d'utiliser plus de cycles de "CPU" de cerveau. Dans ce cas, codes les attentes dans un language similaire au language humain, dans un style déclaratif de type BDD avec `expect` ou `should` et sans utiliser de code custom. Si Chai et Jest n'incluent pas les assertions nécéssaires et qu'elles reviennent régulièrement, considère [d'étendre Jest matcher (Jest)](https://jestjs.io/docs/en/expect#expectextendmatchers) ou d'écrire un [plugin Chai custom](https://www.chaijs.com/guide/plugins/) +:white_check_mark: **À faire:** Coder tes tests dans un langage déclaratif permet au lecteur de comprendre immédiatement sans effectuer un seul cycle de "CPU" de cerveau. Lorsque tu écris du code impératif remplis de logique conditionnelles, le lecteur est forcé d'utiliser plus de cycles de "CPU" de cerveau. Dans ce cas, code les attentes dans un langage similaire au langage humain, dans un style déclaratif de type BDD avec `expect` ou `should` et sans utiliser de code custom. Si Chai et Jest n'incluent pas les assertions nécessaires et qu'elles reviennent régulièrement, considère [d'étendre Jest matcher (Jest)](https://jestjs.io/docs/en/expect#expectextendmatchers) ou d'écrire un [plugin Chai custom](https://www.chaijs.com/guide/plugins/)
    @@ -253,7 +253,7 @@ test("When asking for an admin, ensure only ordered admins in results", () => {
    -### :clap: Bien faire les choses Exemple: Parcourir le test déclaratif suivant est un jeu d'enfant +### :clap: Bien faire les choses, exemple: Parcourir le test déclaratif suivant est un jeu d'enfant ```javascript it("When asking for an admin, ensure only ordered admins in results", () => { @@ -270,12 +270,12 @@ it("When asking for an admin, ensure only ordered admins in results", () => {

    -## ⚪ ️ 1.4 S'en tenir aux tests des boites noires: Ne teste que les méthodes publiques +## ⚪ ️ 1.4 S'en tenir aux tests des boites noires : Ne tester que les méthodes publiques -:white_check_mark: **À faire:** Tester les composants internes apporte beaucoup de complexité pour presque rien. Si ton code/API délivre les bon resultats, est-ce que tu dois vraiment passer les 3 prochaines heures à tester COMMENT il fonctionne et maintenir ces tests ? À chaque fois qu'un comportement publique est testé, l'implementation privée est aussi testé implicitement, et test tests n'échoueront que si il y a un certain problème (par exemple: mauvais retour). Cette approche est aussi appelé `behavioral testing` (test de comportement). De l'autre coté, si tu dois tester les éléments internes (approche de la boîte blanche) - l'objectif passe de planifier le résultat du composant à des détails de bases, et votre test peut échouer à cause de refactoring mineurs alors que le résultat est toujours bon - cela augmente la charge de maintenance. +:white_check_mark: **À faire:** Tester les composants internes apporte beaucoup de complexité pour presque rien. Si ton code/API délivre les bon résultats, est-ce que tu dois vraiment passer les 3 prochaines heures à tester COMMENT il fonctionne et maintenir ces tests ? À chaque fois qu'un comportement publique est testé, l'implémentation privée est aussi testé implicitement, et test tests n'échoueront que si il y a un certain problème (par exemple: mauvais retour). Cette approche est aussi appelée `behavioral testing` (test de comportement). De l'autre côté, si tu dois tester les éléments internes (approche de la boîte blanche) - l'objectif passe de planifier le résultat du composant à des détails de bases, et votre test peut échouer à cause de refactoring mineurs alors que le résultat est toujours bon - cela augmente la charge de maintenance.
    -❌ **Autrement:** Tes tests se comportent comme [l'enfant qui criait au loup](https://fr.wikipedia.org/wiki/L%27Enfant_qui_criait_au_loup): crier des faux positifs (par exemple, un test échoue parce qu'un nom de variable privé à été changé). Sans surprise, les gens vont rapidement ignorer les notifications, jusqu'à ce qu'un jour, un vrai beug soit ignoré +❌ **Autrement:** Tes tests se comportent comme [l'enfant qui criait au loup](https://fr.wikipedia.org/wiki/L%27Enfant_qui_criait_au_loup): crier des faux positifs (par exemple, un test échoue parce qu'un nom de variable privé a été changé). Sans surprise, les gens vont rapidement ignorer les notifications, jusqu'à ce qu'un jour, un vrai bug soit ignoré
    Exemple de code @@ -314,12 +314,12 @@ it("White-box test: When the internal methods get 0 vat, it return 0 response", ## ⚪ ️ ️1.5 Choisir les bons "test doubles": Éviter les mocks en faveur des stubs et spies -:white_check_mark: **À faire:** Les "test doubles" sont un mal nécéssaire parce qu'il sont couplé aux composants internes mais apportent néanmoins beaucoup de valeur ([Retrouve ici un rappel à propos des "test doubles": mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)). +:white_check_mark: **À faire:** Les "test doubles" sont un mal nécessaire parce qu'ils sont couplés aux composants internes mais apportent néanmoins beaucoup de valeur ([Retrouve ici un rappel à propos des "test doubles": mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)). -Avant d'utiliser des "test doubles", pose toi une question trés simple: Est-ce que je l'utilise pour tester une fonctionnalité qui apparait, ou peut apparaitre, dans le document de spécification ? Si non, ça sent le test de boite blanche. +Avant d'utiliser des "test doubles", pose toi une question très simple: Est-ce que je l'utilise pour tester une fonctionnalité qui apparaît, ou peut apparaître, dans le document de spécification ? Si non, ça sent le test de boite blanche. -Par exemple, si tu veux tester que ton application se comporte correctement quand le service de paiement est coupé, tu peux faire un stub du service de paiement et déclencher une réponse de type 'No Response' pour vérifier que l'unité testée retourne la bonne valeur. Cela vérifie le comportement/réponse de notre application suivant un certain scénario. Tu peux aussi utiliser un spy pour vérifier qu'un email a bien été envoyé quand ce service était coupé - il s'agit encore une fois d'un test de comportement qui pourrait apparaitre dans les spécification ("Envoyer un email si le paiement n'as pas pu être enregistré"). -D'un autre coté, si tu mock le service de paiement pour vérifié qu'il a bien été appelé avec le bon type Javascript, alors ton test est orienté sur des comportements internes qui n'ont rien à voir avec les fonctionnalités de l'application et changeront probablement fréquemment. +Par exemple, si tu veux tester que ton application se comporte correctement quand le service de paiement est coupé, tu peux faire un stub du service de paiement et déclencher une réponse de type 'No Response' pour vérifier que l'unité testée retourne la bonne valeur. Cela vérifie le comportement/réponse de notre application suivant un certain scénario. Tu peux aussi utiliser un spy pour vérifier qu'un email a bien été envoyé quand ce service était coupé - il s'agit encore une fois d'un test de comportement qui pourrait apparaître dans les spécifications ("Envoyer un email si le paiement n'as pas pu être enregistré"). +D'un autre côté, si tu mock le service de paiement pour vérifier qu'il a bien été appelé avec le bon type Javascript, alors ton test est orienté sur des comportements internes qui n'ont rien à voir avec les fonctionnalités de l'application et changeront probablement fréquemment.
    ❌ **Autrement:** Chaque refactoring du code implique de chercher l'ensemble des mock dans le code afin de les mettre à jour. Les tests deviennent une corvée plutôt qu'un ami aidant. @@ -349,7 +349,7 @@ it("When a valid product is about to be deleted, ensure data access DAL was call
    -### :clap: Faire les choses bien, exemple : Les spies se concentrent sur les fonctionnalités requises mais touchent les composants internes par effet de bord +### :clap: Bien faire les choses, exemple : Les spies se concentrent sur les fonctionnalités requises mais touchent les composants internes par effet de bord ```javascript it("When a valid product is about to be deleted, ensure an email is sent", async () => { @@ -371,12 +371,12 @@ it("When a valid product is about to be deleted, ensure an email is sent", async

    -## ⚪ ️1.6 Utilise des données réalistes +## ⚪ ️1.6 Utiliser des données réalistes -:white_check_mark: **À faire:** Souvent les beugs de production sont révélés par des entrées tres spécifiques et surprenantes. Plus les entrées de tests seront réalistes, plus il y a de chance de détecter les beugs tôt. Utilise une librairie dédiée comme [Faker](https://www.npmjs.com/package/faker) pour générer des pseudo-vrais données qui resemble aux données de production. Par exemple, ce type de librairie peut générer de façon réaliste des numéros de téléphones, noms d'utilisateur, cartes de crédit, nom de société et même du 'Lorem ipsum'. Tu peux aussi créer des tests (en plus des tests unitaires, par à leur place) qui utilise des fausses données randomisées pour pousser test tests, ou même importer de vrais données depuis ton environnement de production. Envie de passer au niveau supérieur ? Regarde le prochain point (property-based testing). +:white_check_mark: **À faire:** Souvent les bugs de production sont révélés par des entrées très spécifiques et surprenantes. Plus les entrées de tests seront réalistes, plus il y a de chance de détecter les bugs tôt. Utilise une librairie dédiée comme [Faker](https://www.npmjs.com/package/faker) pour générer des pseudo-vrais données qui ressemble aux données de production. Par exemple, ce type de librairie peut générer de façon réaliste des numéros de téléphone, noms d'utilisateur, cartes de crédit, nom de société et même du 'Lorem ipsum'. Tu peux aussi créer des tests (en plus des tests unitaires, par à leur place) qui utilise des fausses données randomisées pour pousser test tests, ou même importer de vraies données depuis ton environnement de production. Envie de passer au niveau supérieur ? Regarde le prochain point (property-based testing).
    -❌ **Autrement:** Tout vos tests de développement vont montrer du vert à tord avec des entrées tels que "Foo", mais en production ils passeront au rouge lorsqu'un hacker passera une chaine de caractère tel que “@3e2ddsf . ##’ 1 fdsfds . fds432 AAAA” +❌ **Autrement:** Tout vos tests de développement vont montrer du vert à tort avec des entrées tels que "Foo", mais en production ils passeront au rouge lorsqu'un hacker passera une chaine de caractère tel que “@3e2ddsf . ##’ 1 fdsfds . fds432 AAAA”
    Exemple de code @@ -423,12 +423,12 @@ it("Better: When adding new valid product, get successful confirmation", async (

    -## ⚪ ️ 1.7 Teste plusieurs combinaisons d'input avec le Property-based testing +## ⚪ ️ 1.7 Tester plusieurs combinaisons d'input avec le Property-based testing -:white_check_mark: **À faire:** En règle général, on choisit quelques valeurs d'entrées pour chaque test. Même lorsque le format des inputs est réaliste ( voir le point 'Utilise des données réalistes' ), on couvre seulement quelques combinaisons d'entrées. En revanche, en production, une API appelée avec 5 paramètres peut être invoquée avec des milliers de permutations différentes, l'une d'entre elle peut faire échouer notre processus ([voir le Fuzz testing](https://fr.wikipedia.org/wiki/Fuzzing)). Et si tu pouvais écrire un seul test qui envoie 1000 permutations d'entrées automatiquement et détecte pour lequel d'entre eux notre processus ne retourne pas la bonne valeur ? Le Property-based testing c'est une méthode qui fait exactement ça : En testant toute les combinaisons d'entrées possible on augmente les chance de détecter un beug. Par exemple, prenom une méthode : addNewProduct(id, name, isDiscount), la librairie appelera cette méthode avec plusieurs combinaisons de (number, string, boolean) tel que (1, “iPhone”, false), (2, “Galaxy”, true). Tu peux utiliser le property-based testing avec ta librairie de test préféré (Mocha, Jest ...etc) à l'aide de librairie tel que [js-verify](https://github.com/jsverify/jsverify) ou [testcheck](https://github.com/leebyron/testcheck-js) (meilleure documentation). MAJ: Nicolas Dubien à suggéré dans les commentaire de [regarder fast-check](https://github.com/dubzzz/fast-check#readme) qui semble offrir des fonctionnalitées supplémentaire et être activement maintenue. +:white_check_mark: **À faire:** En règle général, on choisit quelques valeurs d'entrées pour chaque test. Même lorsque le format des inputs est réaliste (voir le point 'Utiliser des données réalistes'), on couvre seulement quelques combinaisons d'entrées. En revanche, en production, une API appelée avec 5 paramètres peut être invoquée avec des milliers de permutations différentes, l'une d'entre elle peut faire échouer notre processus ([voir le Fuzz testing](https://fr.wikipedia.org/wiki/Fuzzing)). Et si tu pouvais écrire un seul test qui envoie 1000 permutations d'entrées automatiquement et détecte pour lequel d'entre eux notre processus ne retourne pas la bonne valeur ? Le Property-based testing c'est une méthode qui fait exactement ça : En testant toutes les combinaisons d'entrées possible on augmente les chance de détecter un bug. Par exemple, prenons une méthode : addNewProduct(id, name, isDiscount), la librairie appellera cette méthode avec plusieurs combinaisons de (number, string, boolean) tel que (1, “iPhone”, false), (2, “Galaxy”, true). Tu peux utiliser le property-based testing avec ta librairie de test préféré (Mocha, Jest ...etc) à l'aide de librairie tel que [js-verify](https://github.com/jsverify/jsverify) ou [testcheck](https://github.com/leebyron/testcheck-js) (meilleure documentation). MAJ: Nicolas Dubien à suggéré dans les commentaire de [regarder fast-check](https://github.com/dubzzz/fast-check#readme) qui semble offrir des fonctionnalitées supplémentaire et être activement maintenue.
    -❌ **Autrement:** Inconsciemment, tu choisis des entrées de test qui ne couvrent que les cas qui fonctionnent correctement. Malheuresement, cela réduit l'efficacité tests et leur capacité a détecter des beugs. +❌ **Autrement:** Inconsciemment, tu choisis des entrées de test qui ne couvrent que les cas qui fonctionnent correctement. Malheureusement, cela réduit l'efficacité tests et leur capacité a détecter des bugs.
    Exemple de code @@ -459,24 +459,24 @@ describe("Product service", () => {

    -## ⚪ ️ 1.8 Si besoin, n'utilise que des snapshots courts et inline +## ⚪ ️ 1.8 Si besoin, n'utiliser que des snapshots courts et inline -:white_check_mark: **Do:** Quand il y a un besoin pour du [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), utilise seulement des snapshots courts ( 3-7 lignes ) qui sont inclut dans le test ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)) et pas dans des fichiers externes. Respecter cette règle permettra à vos tests de rester auto-explicatif et moins fragile. +:white_check_mark: **Do:** Quand il y a un besoin pour du [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), utilise seulement des snapshots courts (3-7 lignes) qui sont inclut dans le test ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)) et pas dans des fichiers externes. Respecter cette règle permettra à vos tests de rester auto-explicatif et moins fragile. -D'un autre coté, les tutoriels et outils 'classique' encouragent à stocker de gros fichiers (résultats d'API JSON, markup d'un composant) sur un emplacement externe et de s'assurer à chaque fois que le test est lancé, de comparer le résultat reçu avec la version sauvegardée. Cela peux, par exemple, implicitement coupler notre test à 1000 lignes avec 3000 valeurs que le lecteur du test ne verra jamais et auquel il ne pensera pas. Pourquoi est-ce que c'est mauvais ? En faisant ça, il y a 1000 raisons pour votre test d'échouer - Il suffit qu'une seule ligne change pour que le snapshot soit invalide, et celà arrivera probablement souvent. A quelle frequence ? Pour chaque espace, commentaire ou changement mineur dans le HTML/CSS. De plus, le nom du test ne donnera pas la moindre indication à propos de l'erreur vu qu'il vérifie simplement que les 1000 lignes n'ont pas changé. Cela encourage aussi celui qui écrit les tests à accepter comme valeur de success un long document qu'il ne pourra pas inspecter et vérifier. Tout ces points sont des symptomes d'un test obscure qui n'est pas ciblé et cherche à en faire trop. +D'un autre côté, les tutoriels et outils 'classique' encouragent à stocker de gros fichiers (résultats d'API JSON, markup d'un composant) sur un emplacement externe et de s'assurer à chaque fois que le test est lancé, de comparer le résultat reçu avec la version sauvegardée. Cela peut, par exemple, implicitement coupler notre test à 1000 lignes avec 3000 valeurs que le lecteur du test ne verra jamais et auquel il ne pensera pas. Pourquoi est-ce que c'est mauvais ? En faisant ça, il y a 1000 raisons pour votre test d'échouer - Il suffit qu'une seule ligne change pour que le snapshot soit invalide, et cela arrivera probablement souvent. À quelle fréquence ? Pour chaque espace, commentaire ou changement mineur dans le HTML/CSS. De plus, le nom du test ne donnera pas la moindre indication à propos de l'erreur vu qu'il vérifie simplement que les 1000 lignes n'ont pas changé. Cela encourage aussi celui qui écrit les tests à accepter comme valeur de succès un long document qu'il ne pourra pas inspecter et vérifier. Tous ces points sont des symptômes d'un test obscure qui n'est pas ciblé et cherche à en faire trop. -Il faut noter qu'il y a quelques cas ou de long snapshots externes sont acceptable - Pour valideer un schema et pas des données ou concernant des documents qui ne changent presque jamais +Il faut noter qu'il y a quelques cas ou de long snapshots externes sont acceptable - Pour valider un schéma et pas des données ou concernant des documents qui ne changent presque jamais
    -❌ **Sinon:** Un test UI échoue. Le code semble bon, l'écran rends parfaitement les pixels, que s'est-il passé ? Ton test de snapshot a trouvé une différence entre le document original et le document actuel - un simple espace à été ajouté dans le markdown... +❌ **Sinon:** Un test UI échoue. Le code semble bon, l'écran rend parfaitement les pixels, que s'est-il passé ? Ton test de snapshot a trouvé une différence entre le document original et le document actuel - un simple espace a été ajouté dans le markdown...
    -
    Exemples de code +
    Exemple de code
    -### :thumbsdown: Exemple d'anti pattern: Coupler nos test à 2000 lignes de code qu'on ne voit pas +### :thumbsdown: Exemple d'anti pattern: Coupler nos tests à 2000 lignes de code qu'on ne voit pas ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") @@ -528,8 +528,8 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => { ## ⚪ ️1.9 Éviter les fixtures et seeds globals, ajouter les données par test -:white_check_mark: **À faire:** En suivant la règle d'or (point 0), chaque test doit ajouter et agir sur son propre jeu d'entrée en base de donnée pour éviter d'être couplés et faciliter le raisonnement à propos de la logique du test. En réalité, cette règle est souvent violée par les testeurs qui remplissent la base de donnée avant de lancer les tests ([aussi connu sous le nom ‘test fixture’](https://en.wikipedia.org/wiki/Test_fixture)) afin d'améliorer les performances. Même si la performance est effectivement une inquiétude valide, elle peut être atténuée (voir "Component testing"), en revanche, la compléxité des tests est un chagrin bien plus douloureux qui devrait régir les autres considérations la plupart du temps. -En pratique, chaque cas testé doit explicitement ajouter les entrée en base de donnée dont il a besoin et n'agir que sur ces entrées. Si la performance devient une inquiétude critique - un compromis peut se trouver sous la forme de seeds pour les jeux de tests qui ne modifient pas les données (queries). +:white_check_mark: **À faire:** En suivant la règle d'or (point 0), chaque test doit ajouter et agir sur son propre jeu d'entrée en base de données pour éviter d'être couplés et faciliter le raisonnement à propos de la logique du test. En réalité, cette règle est souvent violée par les testeurs qui remplissent la base de données avant de lancer les tests ([aussi connu sous le nom ‘test fixture’](https://en.wikipedia.org/wiki/Test_fixture)) afin d'améliorer les performances. Même si la performance est effectivement une inquiétude valide, elle peut être atténuée (voir "Component testing"), en revanche, la complexité des tests est une peine bien plus douloureuse qui devrait régir les autres considérations la plupart du temps. +En pratique, chaque cas testé doit explicitement ajouter les entrées en base de données dont il a besoin et n'agir que sur ces entrées. Si la performance devient une inquiétude critique - un compromis peut se trouver sous la forme de seeds pour les jeux de tests qui ne modifient pas les données (queries).
    @@ -585,9 +585,9 @@ it("When updating site name, get successful confirmation", async () => {
    -## ⚪ ️ 1.10 Ne catch pas les erreurs, prevois les +## ⚪ ️ 1.10 Ne pas catcher les erreurs, les prévoir -:white_check_mark: **À faire:** Lorsqu'on essaye de detecter que certaines entrées déclenchent une erreur, il peut sembler être une bonne idée d'utiliser try-catch-finally et de vérifier qu'on est passé dans le catch. Le résultat est un test étrange et verbeux (exemple plus bas) qui cache l'intention simple du test et le résultat attendu. +:white_check_mark: **À faire:** Lorsqu'on essaye de détecter que certaines entrées déclenchent une erreur, il peut sembler être une bonne idée d'utiliser try-catch-finally et de vérifier qu'on est passé dans le catch. Le résultat est un test étrange et verbeux (exemple plus bas) qui cache l'intention simple du test et le résultat attendu. Une alternative plus élégante est d'utiliser l'assertion Chai dédiée : expect(method).to.throw (ou en Jest: expect(method).toThrow()). Il est également obligatoire de vérifier que l'exception contient une propriété qui indique le type d'erreur, sinon, en recevant un message d'erreur générique, l'application ne sera pas capable de faire beaucoup plus que de montrer un message décevant à l'utilisateur.
    @@ -635,20 +635,20 @@ it("When no product name, it throws error 400", async () => {

    -## ⚪ ️ 1.11 Tag tes tests +## ⚪ ️ 1.11 Taguer tes tests :white_check_mark: **À faire:** Des tests différents doivent être lancés dans différents scénarios. Les tests de fumée (quick smoke), IO-less, doivent tourner à chaque fois qu'un développeur sauvegarde ou commit un fichier, les tests complets end-to-end sont en général lancés quand une nouvelle pull-request est soumise, etc. -On peux réaliser ça en taggant les tests avec des mots clefs comme #cold #api #sanity pour pouvoir utiliser grep et sélectionner les tests qui nous interesse. Par exemple, voila comment invoquer uniquement le groupe de test sanity avec Mocha : mocha - grep 'sanity' +On peut réaliser ça en taggant les tests avec des mots clefs comme #cold #api #sanity pour pouvoir utiliser grep et sélectionner les tests qui nous interesse. Par exemple, voilà comment invoquer uniquement le groupe de test 'sanity' avec Mocha : mocha - grep 'sanity'
    -❌ **Autrement:** Lancer tout les tests, y compris ceux qui éxecutent des dizaines de requetes DB, a chaque fois qu'un développeur fait un petit changement peut être extremement lent et pousser les développeurs a ne pas utiliser les tests. +❌ **Autrement:** Lancer tous les tests, y compris ceux qui exécutent des dizaines de requêtes DB, à chaque fois qu'un développeur fait un petit changement peut être extrêmement lent et pousser les développeurs a ne pas utiliser les tests.
    Exemple de code
    -### :clap: Bien faire les choses, exemple: Tagger des tests avec '#cold-test' permet à celui qui les lance de n'executer que les tests rapide (cold = tests rapides qui ne font pas d'opérations IO et peuvent être executés souvent, meme pendant que le développeur code) +### :clap: Bien faire les choses, exemple: Taguer des tests avec '#cold-test' permet à celui qui les lance de n'executer que les tests rapide (cold = tests rapides qui ne font pas d'opérations IO et peuvent être executés souvent, meme pendant que le développeur code) ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") @@ -668,13 +668,13 @@ describe("Order service", function() {

    -## ⚪ ️ 1.12 Catégorise tes tests sous au moins 2 niveaux +## ⚪ ️ 1.12 Catégoriser tes tests sous au moins 2 niveaux -:white_check_mark: **À faire:** Applique une structure à ta suite de test pour qu'un visiteur occasionnel puisse facilement comprendre les attentes (Les tests sont la meilleure documentation) et les différents scénarios testés. Une méthode fréquence pour ça est de placer au moins 2 blocs 'describe' au dessus de vos tests : Le premier est pour le nom de l'unité testé et le deuxieme pour un niveau supplémentaire de catégorisation comme le scénario ou une catégorie (voir l'exemple de code plus bas). Cette organisation améliorera grandement vos rapports de tests: Le lecteur comprendra simplement les catégories de tests, examinera la section voulu et verra les corrélations entre les tests qui échouent. De plus, ce sera bien plus simple pour un développeur de naviguer dans le code d'une suite avec de nombreux tests. Il y a plusieurs structures alternatives pour les suites de tests que tu peux envisager comme [given-when-then](https://github.com/searls/jasmine-given) et [RITE](https://github.com/ericelliott/riteway) +:white_check_mark: **À faire:** Applique une structure à ta suite de tests pour qu'un visiteur occasionnel puisse facilement comprendre les attentes (Les tests sont la meilleure documentation) et les différents scénarios testés. Une méthode fréquence pour ça est de placer au moins 2 blocs 'describe' au-dessus de vos tests : Le premier est pour le nom de l'unité testé et le deuxième pour un niveau supplémentaire de catégorisation comme le scénario ou une catégorie (voir l'exemple de code plus bas). Cette organisation améliorera grandement vos rapports de tests: Le lecteur comprendra simplement les catégories de tests, examinera la section voulue et verra les corrélations entre les tests qui échouent. De plus, ce sera bien plus simple pour un développeur de naviguer dans le code d'une suite avec de nombreux tests. Il y a plusieurs structures alternatives pour les suites de tests que tu peux envisager comme [given-when-then](https://github.com/searls/jasmine-given) et [RITE](https://github.com/ericelliott/riteway)
    -❌ **Autrement:** En regardant un rapport avec une longue liste de tests a plat, le lecteur devra lire un long texte pour comprendre les scénarios majeur et comprendre les liens entre les tests qui échouent. Imagine le cas suivant : Quand 7/100 tests échouent, regarder une liste à plat nécéssitera d'aller lire le contenu des tests qui échouent pour comprendre le lien entre eux. En revanche, dans un rapport hiérarchique ils pourrait tous etre au sein du même scénario ou d'une catégorie et le lecteur pourra rapidement déduire ce qui est, ou du moins où est, la cause de l'erreur. +❌ **Autrement:** En regardant un rapport avec une longue liste de tests a plat, le lecteur devra lire un long texte pour comprendre les scénarios majeurs et comprendre les liens entre les tests qui échouent. Imagine le cas suivant : Quand 7/100 tests échouent, regarder une liste à plat nécessitera d'aller lire le contenu des tests qui échouent pour comprendre le lien entre eux. En revanche, dans un rapport hiérarchique, ils pourraient tous être au sein du même scénario ou d'une catégorie et le lecteur pourra rapidement déduire ce qui est, ou du moins où est, la cause de l'erreur.
    @@ -725,9 +725,9 @@ test("Then there should not be a new transfer record", () => {}); ## ⚪ ️1.13 Autre bonnes pratiques génériques -:white_check_mark: **À faire:** Ce post se concentre sur des conseils de tests qui sont en rapport, ou au moins peuvent être présentés, avec Node JS. ce point, cependant, regroupe quelques conseils sans rapport avec Node qui sont bien connus. +:white_check_mark: **À faire:** Ce post se concentre sur des conseils de tests qui sont en rapport, ou au moins peuvent être présentés, avec Node JS. Ce point, cependant, regroupe quelques conseils sans rapport avec Node qui sont bien connus. -Apprend et pratique [les principes TDD](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) - ils ont beaucoup de valeurs pour la plupart mais ne soit pas intimidés s'ils ne correspondent pas à ton style, tu n'es pas le seul. Envisage d'écrire les tests avec le code dans un [red-green-refactor style](https://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html), vérifie que chaque test vérifie exactement une chose, quand tu trouves un bug - avant de le fixer, écrit un test qui détectera le bug à l'avenir, laisse chaque test échouer au moins une fois avant de devenir vert, commence un module en écrivant du code simple et rapide qui valident le test - puis refactor graduellement et passe le code a un niveau de production, évite toute dépendance à l'environnement (paths, OS, etc) +Apprends et pratique [les principes TDD](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) - ils ont beaucoup de valeurs pour la plupart, mais ne soit pas intimidés s'ils ne correspondent pas à ton style, tu n'es pas le seul. Envisage d'écrire les tests avec le code dans un [red-green-refactor style](https://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html), vérifie que chaque test vérifie exactement une chose, quand tu trouves un bug - avant de le fixer, écrit un test qui détectera le bug à l'avenir, laisse chaque test échouer au moins une fois avant de devenir vert, commence un module en écrivant du code simple et rapide qui valide le test - puis refactor graduellement et passe le code a un niveau de production, évite toute dépendance à l'environnement (paths, OS, etc)
    ❌ **Autrement:** Tu manqueras les perles de sagesses recueillies pendant des décennies. @@ -738,11 +738,11 @@ Apprend et pratique [les principes TDD](https://www.sm-cloud.com/book-review-tes ## ⚪ ️2.1 Enrichis ton portefeuille de test: Vois plus loin que les tests unitaire et la pyramide -:white_check_mark: **À faire:** La [pyramide de tests](https://martinfowler.com/bliki/TestPyramid.html), bien que vielle de plus de 10 ans, est un bon model qui suggère trois types de tests et influence la plupart des stratégies de tests des développeurs. Dans un même temps, une poignée de nouvelles techniques de tests brillantes ont émergés et sont dans l'ombre de la pyramide de tests. Étant donné l'étendu des changements que l'on a vu ces 10 dernières années (micro-services, cloud, serverless), est-il seulement possible qu'un vieux modèle soit adapté à *tout* les types d'applications ? Le monde du test ne devrait-il pas accueillir de nouvelles techniques ? +:white_check_mark: **À faire:** La [pyramide de tests](https://martinfowler.com/bliki/TestPyramid.html), bien que vielle de plus de 10 ans, est un bon modèle qui suggère trois types de tests et influence la plupart des stratégies de tests des développeurs. Dans un même temps, une poignée de nouvelles techniques de tests brillantes ont émergé et sont dans l'ombre de la pyramide de tests. Étant donné l'étendu des changements que l'on a vu ces 10 dernières années (micro-services, cloud, serverless), est-il seulement possible qu'un vieux modèle soit adapté à *tout* les types d'applications ? Le monde du test ne devrait-il pas accueillir de nouvelles techniques ? -Ne vous méprenez pas, en 2019, la pyramide de tests, le TDD et les tests unitaires sont toujours une technique puissante et sont probablement le meilleur choix pour beaucoup d'applications. Seulement, comme les autres modèles, malgrés qu'il soit utile, [il doit être faux parfois](https://en.wikipedia.org/wiki/All_models_are_wrong). Par exemple, imagine une application IoT qui traite de nombreux évènement dans une queue (message-bus) comme Kafka/RabbitMQ, qui vont ensuite dans un entrepot de donnée puis sont lus par une UI d'analyse. Est-ce qu'on devrait vraiment dépenser 50% de notre budget de test pour écrire des tests unitaire sur une application qui est centrée sur l'intégration et n'as presque aucune logique ? Plus la diversité des applications augmente (bots, crypto, Alexa-skills) plus les chances sont grandes de trouver un scénario ou la pyramide de test n'est pas le meilleur choix. +Ne vous méprenez pas, en 2019, la pyramide de tests, le TDD et les tests unitaires sont toujours une technique puissante et sont probablement le meilleur choix pour beaucoup d'applications. Seulement, comme les autres modèles, malgré qu'il soit utile, [il doit être faux parfois](https://en.wikipedia.org/wiki/All_models_are_wrong). Par exemple, imagine une application IoT qui traite de nombreux événements dans une queue (message-bus) comme Kafka/RabbitMQ, qui vont ensuite dans un entrepot de donnée puis sont lus par une UI d'analyse. Est-ce qu'on devrait vraiment dépenser 50% de notre budget de test pour écrire des tests unitaires sur une application qui est centrée sur l'intégration et n'a presque aucune logique ? Plus la diversité des applications augmente (bots, crypto, Alexa-skills) plus les chances sont grandes de trouver un scénario ou la pyramide de test n'est pas le meilleur choix. -Il est temps d'enrichir ton portefeuille de test et de devenir familier avec plus de types de tests (les prochains points suggèrent quelques idées), de modèles tels que celui de la pyramide de tests mais aussi d'associer les types de tests aux problèmes que tu rencontres dans le monde réel ('Hey, notre API est cassé, écrivons des consumer-driven contract testing!'), diversifie tes tests comme un investisseur qui construit sont portefeuille en se basant sur l'analyse des risques - estime où les problèmes risquent de se poser et applique des mesures de prévention pour réduire ces risques. +Il est temps d'enrichir ton portefeuille de test et de devenir familier avec plus de types de tests (les prochains points suggèrent quelques idées), des modèles tels que celui de la pyramide de tests mais aussi d'associer les types de tests aux problèmes que tu rencontres dans le monde réel ('Hey, notre API est cassé, écrivons des consumer-driven contract testing!'), diversifie tes tests comme un investisseur qui construit son portefeuille en se basant sur l'analyse des risques - estime où les problèmes risquent de se poser et applique des mesures de prévention pour réduire ces risques. Un mot d'avertissement: l'argument du TDD dans le monde du développement à un visage typique de fausse dichotomie, certains disent de l'utiliser de partout, d'autres pensent que c'est le diable. Tous ceux qui parlent en absolu ont tord :] @@ -756,7 +756,7 @@ Un mot d'avertissement: l'argument du TDD dans le monde du développement à un
    -### :clap: Bien faire les choses, exemple: Cindy Sridharan propose un portefeuille de tests riche dans ton excellent post 'Testing Microservices - the same way' +### :clap: Bien faire les choses, exemple: Cindy Sridharan propose un portefeuille de tests riche dans son excellent post 'Testing Microservices - the same way' ![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") @@ -770,11 +770,11 @@ Un mot d'avertissement: l'argument du TDD dans le monde du développement à un

    -## ⚪ ️2.2 Les tests de composant pourrait être ta meilleure affaire +## ⚪ ️2.2 Les tests de composant pourrait être ton meilleur arrangement -:white_check_mark: **À faire:** Chaque test unitaire couvre une petite portion de l'application et il est couteux de couvrir l'ensemble, alors que les tests end-to-end couvrent facilement une grande partie mais sont lent, pourquoi ne pas appliquer une approche intermédiaire et écrire des tests qui sont plus gros que les tests unitaire mais plus petit que les tests end-to-end ? Les tests de composant (Component testing) sont méconnus du monde de test mais ils offrent le meilleur des deux mondes: des performances raisonnable et la possibilité d'appliquer le pattern TDD + une couverture correct et réaliste +:white_check_mark: **À faire:** Chaque test unitaire couvre une petite portion de l'application et il est coûteux de couvrir l'ensemble, alors que les tests end-to-end couvrent facilement une grande partie mais sont lent, pourquoi ne pas appliquer une approche intermédiaire et écrire des tests qui sont plus gros que les tests unitaires mais plus petits que les tests end-to-end ? Les tests de composant (Component testing) sont méconnus du monde de test mais ils offrent le meilleur des deux mondes: des performances raisonnable et la possibilité d'appliquer le pattern TDD + une couverture correcte et réaliste -Les tests de composant se concentre sur "l'unité" du microservice, ils fonctionnent sur l'API, ne mock rien qui appartient au microservice lui même (une vrai DB, ou au moins une version in-memory de cette DB) mais stub tout ce qui est externe, comme les appels à d'autres microservices. En fasant ça, on test ce que l'on déploie, on approche l'application de l'extérieur vers l'intérieur et on gagne en confiance dans un laps de temps raisonnable. +Les tests de composant se concentrent sur "l'unité" du microservice, ils fonctionnent sur l'API, ne mock rien qui appartient au microservice lui-même (une vrai DB, ou au moins une version in-memory de cette DB) mais stub tout ce qui est externe, comme les appels à d'autres microservices. En faisant ça, on test ce que l'on déploie, on approche l'application de l'extérieur vers l'intérieur et on gagne en confiance dans un laps de temps raisonnable.
    @@ -796,9 +796,9 @@ Les tests de composant se concentre sur "l'unité" du microservice, ils fonction

    -## ⚪ ️2.3 Vérifie que les nouvelles versions ne cassent pas l'API avec les tests de contrat +## ⚪ ️2.3 Vérifier que les nouvelles versions ne cassent pas l'API avec les tests de contrat -:white_check_mark: **À faire:** Ton microservice a plusieurs clients, et tu exécutes plusieurs versions du service pour des raisons de compatibilité (pour que tout le monde soit content). Puis tu changes un champs et 'boom!', un client important qui compte sur ce champs est en colère. C'est le Catch-22 du monde de l'intégration : Il est trés difficilé pour le coté serveur de considérer toute les attentes des clients. D'un autre coté, les clients ne peuvent pas réaliser de tests puisque le serveur controles les dates de sorties. [Les "consumer-driven contracts" et le framework PACT](https://docs.pact.io) sont nés pour formaliser ce processus avec une approche disruptive - ce n'est pas le serveur qui défini ses propres plan de test, mais le client qui défini les tests du ...serveur! PACT peut enregistrer les attentes du client et les placer dans un emplacement partagé, "broker", afin que le serveur puisse extraire les attentes et s'éxécuter sur chaque version en utilisant la librairie PACT pour détecter les contrats rompus - une attente du client qui n'est pas satisfaite. En faisant ça, toutes les incompatibilités d'API server-client sont repérés tôt pendant le build/CI et peuvent vous éviter beaucoup de frustration. +:white_check_mark: **À faire:** Ton microservice a plusieurs clients, et tu exécutes plusieurs versions du service pour des raisons de compatibilité (pour que tout le monde soit content). Puis tu changes un champ et 'boom!', un client important qui compte sur ce champ est en colère. C'est le Catch-22 du monde de l'intégration : Il est très difficile pour le coté serveur de considérer toutes les attentes des clients. D'un autre coté, les clients ne peuvent pas réaliser de tests puisque le serveur contrôles les dates de sorties. [Les "consumer-driven contracts" et le framework PACT](https://docs.pact.io) sont nés pour formaliser ce processus avec une approche disruptive - ce n'est pas le serveur qui définit ses propres plans de test, mais le client qui définit les tests du ...serveur! PACT peut enregistrer les attentes du client et les placer dans un emplacement partagé, "broker", afin que le serveur puisse extraire les attentes et s'exécuter sur chaque version en utilisant la librairie PACT pour détecter les contrats rompus - une attente du client qui n'est pas satisfaite. En faisant ça, toutes les incompatibilités d'API server-client sont repérés tôt pendant le build/CI et peuvent vous éviter beaucoup de frustration.
    ❌ **Autrement:** L'alternative sont les tests manuels épuisants ou la peur du déploiement @@ -818,9 +818,9 @@ Les tests de composant se concentre sur "l'unité" du microservice, ils fonction

    -## ⚪ ️ 2.4 Test tes middlewares de manière isolée +## ⚪ ️ 2.4 Tester tes middlewares de manière isolée -:white_check_mark: **À faire:** Beaucoup évitent les tests de Middleware parce qu'ils représentent une petite portion du systeme et requièrent un serveur express live. Ce sont deux mauvaises raisons - les Middlewares sont petit mais affectent toute ou la plupart des requetes et peuveunt être testés simplement en tant que fonction qui reçoit un objet JS {req,res}. Pour tester un middleware, il suffit de l'invoquer et d'espionner ([avec Sinon par exemple](https://www.npmjs.com/package/sinon) l'interaction avec l'object {req,res} pour s'assurer que la fonction a effectuée la bonne action. La librairie [node-mock-http](https://www.npmjs.com/package/node-mocks-http) va encore plus loin et prend en compte l'object {req,res} tout en surveillant son comportement. Par exemple, il peut vérifier que le status http qui à été défini sur l'objet res correspond aux attentes (voir l'exemple ci-dessous) +:white_check_mark: **À faire:** Beaucoup évitent les tests de Middleware parce qu'ils représentent une petite portion du système et requièrent un serveur express live. Ce sont deux mauvaises raisons - les Middlewares sont petits, mais affectent toute ou la plupart des requêtes et peuvent être testés simplement en tant que fonction qui reçoit un objet JS {req,res}. Pour tester un middleware, il suffit de l'invoquer et d'espionner ([avec Sinon par exemple](https://www.npmjs.com/package/sinon) l'interaction avec l'objet {req,res} pour s'assurer que la fonction a effectuée la bonne action. La librairie [node-mock-http](https://www.npmjs.com/package/node-mocks-http) va encore plus loin et prend en compte l'objet {req,res} tout en surveillant son comportement. Par exemple, il peut vérifier que le status http qui à été défini sur l'objet res correspond aux attentes (voir l'exemple ci-dessous)
    ❌ **Autrement:** Un bug dans un middleware Express === un bug dans toutes ou la plupart des requêtes @@ -857,15 +857,15 @@ test("A request without authentication header, should return http status 403", (

    -## ⚪ ️2.5 Mesure et refactorise en utilisant des outils d'analyse statique +## ⚪ ️2.5 Mesurer et refactoriser en utilisant des outils d'analyse statique -:white_check_mark: **À faire:** Utiliser des outils d'analye statique donne des moyens objectif d'améliorer la qualité et de garder le code maintenable. Tu peux ajouter un outil d'analyse statique à ton build CI pour l'annuler si il détecte un "code smell". Ses arguments de vente par rapport au linting simple sont la capacité d'inspecter la qualité dans le contexte de plusieurs fichiers (e.g. détécter des duplication), effectuer des analyses avancer (e.g. complexité du code) et suivre l'histoire et le progrés d'un problème de code. Deux exemples d'outils que tu peux utiliser sont [SonarQube](https://www.sonarqube.org/) (4,900+ [stars](https://github.com/SonarSource/sonarqube)) et [Code Climate](https://codeclimate.com/) (2,000+ [stars](https://github.com/codeclimate/codeclimate)) +:white_check_mark: **À faire:** Utiliser des outils d'analyse statique donne des moyens objectif d'améliorer la qualité et de garder le code maintenable. Tu peux ajouter un outil d'analyse statique à ton build CI pour l'annuler si il détecte un "code smell". Ses arguments de vente par rapport au linting simple sont la capacité d'inspecter la qualité dans le contexte de plusieurs fichiers (e.g. détecter des duplications), effectuer des analyses avancées (e.g. complexité du code) et suivre l'histoire et le progrés d'un problème de code. Deux exemples d'outils que tu peux utiliser sont [SonarQube](https://www.sonarqube.org/) (4,900+ [stars](https://github.com/SonarSource/sonarqube)) et [Code Climate](https://codeclimate.com/) (2,000+ [stars](https://github.com/codeclimate/codeclimate)) Credit: [Keith Holliday](https://github.com/TheHollidayInn)
    -❌ **Autrement:** Avec du code de mauvaise qualité, les beugs et la performance seront toujours un problème qu'aucune nouvelle librairie ou fonctionnalitée de pointe ne peux corriger +❌ **Autrement:** Avec du code de mauvaise qualité, les bugs et la performance seront toujours un problème qu'aucune nouvelle librairie ou fonctionnalité de pointe ne peux corriger
    @@ -883,10 +883,10 @@ Credit: ❌ **Autrement:** Certains tests échoue, le déploiement est annulé, l'équipe va dépenser un temps précieux maintenant, est-ce qu'on a un bug ? Investiguons, oh non - il semble que deux tests modifiaient les même données @@ -963,10 +963,10 @@ it("When updating site name, get successful confirmation", async () => { ## ⚪ ️ 3.1 Separer l'UI des fonctionnalités -:white_check_mark: **À faire:** Lorsqu'on veux tester la logique d'un composant, les détail UI deviennent du bruit qui devrait être extrait, afin que les tests se concentrent purement sur les données. En pratique, extrait les donnée désirés du markup d'un facon abstrait qui n'est pas torop complée avec l'iplémentation graphique, assert seulement les donnée (vs des détails graphiques HTML/CSS) et désactive les animations qui ralentissent. Tu peux être tenté d'éviter le rendu et ne tester que les parties derrière l'UI (e.g. services, actions, store) mais ils s'agira de tests fictionnels qui ne ressemblent pas à la réalité et ne révèleront pas les cas ou la bonne donnée n'arrive pas à l'UI. +:white_check_mark: **À faire:** Lorsqu'on veut tester la logique d'un composant, les détails UI deviennent du bruit qui devrait être extrait, afin que les tests se concentrent purement sur les données. En pratique, extrait les données désirées du markup d'une façon abstraite qui n'est pas trop couplée avec l'implémentation graphique, assert seulement les données (vs des détails graphiques HTML/CSS) et désactive les animations qui ralentissent. Tu peux être tenté d'éviter le rendu et ne tester que les parties derrière l'UI (e.g. services, actions, store) mais il s'agira de tests fictionnels qui ne ressemblent pas à la réalité et ne révéleront pas les cas ou la bonne donnée n'arrive pas à l'UI.
    -❌ **Autrement:** Les donnée calculée de ton tests peuvent être prêtes en 10ms, mais l'ensemble du tests durera 500ms (100 tests = 1 min) à cause d'animation qui ne nous concerne pas dans le cadre du test. +❌ **Autrement:** Les données calculées de ton test peuvent être prêtes en 10ms, mais l'ensemble du test durera 500ms (100 tests = 1 min) à cause d'animation qui ne nous concerne pas dans le cadre du test.
    Exemple de code @@ -1015,7 +1015,7 @@ test("When flagging to show only VIP, should display only VIP members", () => { ## ⚪ ️ 3.2 Query les éléments HTML en te basant sur des attributs qui ont peu de chance de changer -:white_check_mark: **À faire:** Query les éléments HTML en te basant sur des attributs qui ont de grande chances de survivre à un changement graphique, contrairement aux selecteurs CSS ou aux labels des forms. Si l'élément n'as pas d'attribut de ce type, creer un attribut dédié au test comme 'test-id-submit-sutton'. Utiliser cette méthode permet non seulement d'être sur que vos tests fonctionnels/logique ne cassent pas à cause d'un changement visuel mais il devient également plus clair pour toute votre équipe que cet élément et son attribut sont utilisés par les tests et ne devraient pas être supprimés. +:white_check_mark: **À faire:** Query les éléments HTML en te basant sur des attributs qui ont de grandes chances de survivre à un changement graphique, contrairement aux sélecteurs CSS ou aux labels des forms. Si l'élément n'as pas d'attribut de ce type, crée un attribut dédié au test comme 'test-id-submit-sutton'. Utiliser cette méthode permet non seulement d'être sûr que vos tests fonctionnels/logique ne cassent pas à cause d'un changement visuel mais il devient également plus clair pour toute votre équipe que cet élément et son attribut sont utilisés par les tests et ne devraient pas être supprimés.
    ❌ **Autrement:** Tu veux tester la fonctionnalité de connexion qui couvre de nombreux composants, logiques et services, tout est configuré parfaitement - subs, spies, les appels Ajax sont isolés. Tout semble parfait. Puis le test échoue car le designer à changé la class CSS du div de 'thick-border' à 'thin-border' @@ -1076,16 +1076,16 @@ test("Whenever no data is passed, error metric shows zero", () => {
    -## ⚪ ️ 3.3 Lorsque c'est possible, test avec un composant réaliste et totalement rendu +## ⚪ ️ 3.3 Lorsque c'est possible, tester avec un composant réaliste et totalement rendu -:white_check_mark: **Do:** Lorsqu'ils sont de taille raisonnable, tests tes composants de l'exterieur comme le font tes utilisateurs, rend complètement l'UI, agit dessus, et vérifie que l'UI rendu se comporte comme on l'attend. -Évite toute sorte de mocking, de rendu partiels ou superficiel - cette approche peut résulter en bugs non détéctés à cause du manque de détails et rendre plus difficile la maintenance des tests puisque les tests modifie les propiétés interne (voir le point 'Privilégier les tests blackbox'). Si l'un des composants enfants ralenti significativement (e.g animations) ou complique la configuration - considère de le remplacer explicitement avec un faux. +:white_check_mark: **Do:** Lorsqu'ils sont de taille raisonnable, tests tes composants de l'extérieur comme le font tes utilisateurs, rend complètement l'UI, agit dessus, et vérifie que l'UI rendu se comporte comme on l'attend. +Évite toute sorte de mocking, de rendu partiels ou superficiel - cette approche peut résulter en bugs non détectés à cause du manque de détails et rendre plus difficile la maintenance des tests puisque les tests modifient les propriétés interne (voir le point 'Privilégier les tests blackbox'). Si l'un des composants enfants ralentis significativement (e.g animations) ou complique la configuration - considère de le remplacer explicitement avec un faux. -Maintenant que c'est dit, une mise en garde s'impose: cette technique fonctionne pour des petit/moyens composants qui ont un nombre raisonnable de composants enfants. Rendre complètement un composants avec trop d'enfant compliquera le raisonnement à propos des échecs de tests (analyse de la cause originelle) et peut être trop lent. Dans ces cas, écrit seulement quelques tests pour ce parent, et plus de tests pour ses enfants. +Maintenant que c'est dit, une mise en garde s'impose: cette technique fonctionne pour des petit/moyens composants qui ont un nombre raisonnable de composants enfants. Rendre complètement un composant avec trop d'enfants compliquera le raisonnement à propos des échecs de tests (analyse de la cause originelle) et peut être trop lent. Dans ces cas, écrit seulement quelques tests pour ce parent, et plus de tests pour ses enfants.
    -❌ **Autrement:** Lorsque tu fouilles dans les détails interne du composants en invoquant ses méthodes privée, et en vérifiant l'état interne - tu devra refactorer tout les tests lorsque tu refactorera l'implémentation du composants. Est-ce que tu as vraiment la capacité de tenir ce niveau de maintenance ? +❌ **Autrement:** Lorsque tu fouilles dans les détails internes du composant en invoquant ses méthodes privées, et en vérifiant l'état interne - tu devras refactoriser tous les tests lorsque tu refactorisera l'implémentation du composant. Est-ce que tu as vraiment la capacité de tenir ce niveau de maintenance ?
    @@ -1149,14 +1149,14 @@ test("Shallow/mocked approach: When clicked to show filters, filters are display
    -## ⚪ ️ 3.4 N'attend pas, utilise la gestion des évènements asynchrone implémenté dans les frameworks. Essayes aussi d'accélérer les choses +## ⚪ ️ 3.4 Ne pas attendre, utiliser la gestion des évènements asynchrone implémenté dans les frameworks. Essayer aussi d'accélérer les choses -:white_check_mark: **À faire:** Souvent, le temps de complétion de l'unité qu'on test est inconnu (e.g animation qui suspendent l'apparition d'éléments) - Dans ce cas, évite d'attendre (e.g. setTimeOut ) et préfére des méthodes déterministe que la plupart des frameworks fournissent. Certaines librairies permettent d'attendre certaines opérations (e.g. [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), d'autres fournissent une API pour attendre comme [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). -Parfois il est plus élégant de stub la ressource lente, comme une API, une fois que le moment de réponse devient déterminé, le composant peut être re-rendu explicitement. Lorsque l'on dépend d'un composant externe qui attent, il peut être utile d'[accélérer l'horloge](https://jestjs.io/docs/en/timer-mocks). -Attendre est un pattern à éviter puisqu'il force tes tests à être lent ou risqué ( s'ils n'attendent pas assez longtemps ). A chaque fois qu'attendre ou requêter sont inévitable et qu'il n'y a pas de support de la part du framework de test, des librairies comme [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) peuvent aider avec une solution demi-déterministe. +:white_check_mark: **À faire:** Souvent, le temps de complétion de l'unité qu'on test est inconnu (e.g animations qui suspendent l'apparition d'éléments) - Dans ce cas, évite d'attendre (e.g. setTimeOut ) et préfère des méthodes déterministe que la plupart des frameworks fournissent. Certaines librairies permettent d'attendre certaines opérations (e.g. [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), d'autres fournissent une API pour attendre comme [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). +Parfois il est plus élégant de stub la ressource lente, comme une API, une fois que le moment de réponse devient déterminé, le composant peut être re-rendu explicitement. Lorsque l'on dépend d'un composant externe qui attend, il peut être utile d'[accélérer l'horloge](https://jestjs.io/docs/en/timer-mocks). +Attendre est un pattern à éviter puisqu'il force tes tests à être lent ou risqué ( s'ils n'attendent pas assez longtemps ). À chaque fois qu'attendre ou requêter sont inévitable et qu'il n'y a pas de support de la part du framework de test, des librairies comme [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) peuvent aider avec une solution demi-déterministe.
    -❌ **Autrement:** En attendant pour un long moment, les tests seront plus lent. En attendant trop peu, les tests échoueront si l'unité testé n'as pas répondu dans les temps. Cela se résume donc entre un compromis entre l'instabilité et les mauvaise performances. +❌ **Autrement:** En attendant pour un long moment, les tests seront plus lent. En attendant trop peu, les tests échoueront si l'unité testée n'a pas répondu dans les temps. Cela se résume donc à un compromis entre l'instabilité et les mauvaises performances.
    @@ -1217,11 +1217,11 @@ test("movie title appears", async () => {
    -## ⚪ ️ 3.5 Regarde comment le contenu est servi sur le réseau +## ⚪ ️ 3.5 Regarder comment le contenu est servi sur le réseau ![](https://img.shields.io/badge/🔧%20Example%20using%20Google%20LightHouse-blue.svg "Examples with Lighthouse") -✅ **À faire:** Applique un monitoring active qui s'assure que le chargement de la page sur un vrai réseau est optimisé - ça inclue les questions UX comme un chargement lent ou un bundle non minifié. Le marché des outils d'inspection n'est pas petit: des outils basique comme pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) peuvent être configuré rapidement pour vérifier sur le server est disponible et répond sous un délai raisonnable. Cela ne fait qu'effleurer la surface de ce qui pourrait aller mal, il est donc préférable de choisir des outils spécialisés pour le frontend (e.g [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) et d'effectuer une analyse plus complète. L'attention doit être portée sur les symptomes, les métriques qui affectent directement l'experience utilisateur, comme le temps de chargement d'une page, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [le temps jusqu'à ce que la page devienne intéractive (TTI)](https://calibreapp.com/blog/time-to-interactive/). En plus de ça, on peut également surveiller les cause techniques, comme s'assurer que le contenu est complet, le temps jusqu'au premier byte, l'optimisation des images, s'assurer d'une taille de DOM raisonnable, SSL et autres. Il est recommandable d'avoir ces monitoring complet à la fois pendant le développement, dans le processus CI et surtout - 24h/24 7j/7 sur les serveurs/CDN de production +✅ **À faire:** Applique un monitoring active qui s'assure que le chargement de la page sur un vrai réseau est optimisé - ça inclue les questions UX comme un chargement lent ou un bundle non minifié. Le marché des outils d'inspection n'est pas petit: des outils basiques comme pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) peuvent être configuré rapidement pour vérifier sur le server est disponible et répond sous un délai raisonnable. Cela ne fait qu'effleurer la surface de ce qui pourrait aller mal, il est donc préférable de choisir des outils spécialisés pour le frontend (e.g [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) et d'effectuer une analyse plus complète. L'attention doit être portée sur les symptômes, les métriques qui affectent directement l'expérience utilisateur, comme le temps de chargement d'une page, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [le temps jusqu'à ce que la page devienne intéractive (TTI)](https://calibreapp.com/blog/time-to-interactive/). En plus de ça, on peut également surveiller les causes techniques, comme s'assurer que le contenu est complet, le temps jusqu'au premier byte, l'optimisation des images, s'assurer d'une taille de DOM raisonnable, SSL et autres. Il est recommandable d'avoir ces monitorings complets à la fois pendant le développement, dans le processus CI et surtout - 24h/24 7j/7 sur les serveurs/CDN de production
    ❌ **Autrement:** Il doit être décevant de se rendre compte qu'après tout le soin apporté à la création d'une interface utilisateur, des tests 100% fonctionnels réussis et des bundles sophistiqué - l'expérience utilisateur est horrible et lente à cause d'une mauvaise configuration du CDN. @@ -1240,10 +1240,10 @@ test("movie title appears", async () => { ## ⚪ ️ 3.6 Stub les ressources lente ou incertaine comme l'API backend -:white_check_mark: **À faire:** Lorsque tu code tes tests mainstream ( pas les tests E2E ), évite d'impliquer toute ressources qui n'est pas sous ta responsabilité et sous ton controle comme l'API et utilise des stubs à la place (i.e. test double). en pratique, à la place de vrais appels à une API, utilise une librairie de tests double ( comme [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble), etc) pour simuler la réponse. L'avantage principal est d'éviter les comportements incertains - les APIs de tests ou de staging par définition ne sont pas toujours stable et de temps en temps peuvent faire échouer tes tests même si ton composant se comporte bien ( l'environnement de production n'a pas été fait pour les tests et limite généralement les requêtes ). Faire ça permettra de simuler plusieurs comportements d'API qui devrait diriger le comportement de ton composant, comme lorsqu'aucune donnée n'est trouvé ou que l'API emet une erreur. Enfin et surtout, les appels réseau vont énormément ralentir les tests. +:white_check_mark: **À faire:** Lorsque tu codes tes tests mainstream ( pas les tests E2E ), évite d'impliquer toute ressource qui n'est pas sous ta responsabilité et sous ton contrôle comme l'API et utilise des stubs à la place (i.e. test double). En pratique, à la place de vrais appels à une API, utilise une librairie de tests double ( comme [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble), etc) pour simuler la réponse. L'avantage principal est d'éviter les comportements incertains - les APIs de tests ou de staging par définition ne sont pas toujours stable et de temps en temps peuvent faire échouer tes tests même si ton composant se comporte bien (l'environnement de production n'a pas été fait pour les tests et limite généralement les requêtes). Faire ça permettra de simuler plusieurs comportements d'API qui devrait diriger le comportement de ton composant, comme lorsqu'aucune donnée n'est trouvée ou que l'API émet une erreur. Enfin et surtout, les appels réseau vont énormément ralentir les tests.
    -❌ **Autrement:** Le test moyen ne tourne pas plus de quelques ms, un API call moyen dure environ 100ms. Çela rend les tests ~20x plus lent. +❌ **Autrement:** Le test moyen ne tourne pas plus de quelques ms, un API call moyen dure environ 100ms. Cela rend les tests ~20x plus lent.
    Exemple de code @@ -1291,16 +1291,16 @@ test("When no products exist, show the appropriate message", () => { ## ⚪ ️ 3.7 Avoir quelques tests end-to-end qui lancent le système entier -:white_check_mark: **À faire:** Même si E2E (end-to-end) veux généralement dire test UI avec un vrai navigateur (voir point 3.6), pour d'autre ils signifient des tests qui englobent le système entier, en incluant le vrai backend. Ce type de tests ont beaucoup de valeurs puisqu'ils couvrent les erreurs d'intégrations entre le frontend et le backend à cause d'une mauvaise compréhension des schémas d'échanges. Ils sont aussi un moyen efficace de découvrir des erreurs d'intégrations entre backends (e.g. le microservice A qui envoie le mauvais message au microservice B) et même de détecter des erreurs de déploiement - Il n'y a pas de framework backend pour les tests E2E qui soit aussi simple et mature que les frameworks UI comme [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). Le point négatif de ces tests, c'est le haut cout de configuration pour un environnement avec autant de composants, et surtout leur fragilité - avec 50 microservices, même si un seul échoue l'ensemble du test E2E échoue. Pour cette raison, cette technique doit être utilisée avec parcimonie, il ne faut pas avoir plus de 1-10 tests de ce type. Ceci dit, même un petit nombre de tests E2E sont susceptibles de détecter les problèmes pour lesquels ils sont en place - les défauts de déploiement et d'intégration. Il est conseillé de les exécuter sur un environnement de pré-production. +:white_check_mark: **À faire:** Même si E2E (end-to-end) veut généralement dire test UI avec un vrai navigateur (voir point 3.6), pour d'autre ils signifient des tests qui englobent le système entier, en incluant le vrai backend. Ce type de tests a beaucoup de valeurs puisqu'ils couvrent les erreurs d'intégrations entre le frontend et le backend à cause d'une mauvaise compréhension des schémas d'échanges. Ils sont aussi un moyen efficace de découvrir des erreurs d'intégrations entre backends (e.g. le microservice A qui envoie le mauvais message au microservice B) et même de détecter des erreurs de déploiement - Il n'y a pas de framework backend pour les tests E2E qui soit aussi simple et mature que les frameworks UI comme [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). Le point négatif de ces tests, c'est le haut cout de configuration pour un environnement avec autant de composants, et surtout leur fragilité - avec 50 microservices, même si un seul échoue l'ensemble du test E2E échoue. Pour cette raison, cette technique doit être utilisée avec parcimonie, il ne faut pas avoir plus de 1-10 tests de ce type. Ceci dit, même un petit nombre de tests E2E sont susceptibles de détecter les problèmes pour lesquels ils sont en place - les défauts de déploiement et d'intégration. Il est conseillé de les exécuter sur un environnement de pré-production.
    -❌ **Autrement:** L'UI peut investir beaucoup en testant ces fonctionnalités seulement pour réaliser que les donnée retournée par le backend sont différentes de ce qui était attendu +❌ **Autrement:** L'UI peut investir beaucoup en testant ces fonctionnalités seulement pour réaliser que les données retournées par le backend sont différentes de ce qui était attendu
    -## ⚪ ️ 3.8 Accélérer les tests E2E en réutilisants les informations d'authentification +## ⚪ ️ 3.8 Accélérer les tests E2E en réutilisant les informations d'authentification -:white_check_mark: **à faire:** Dans des tests E2E qui incluent un vrai backend et utilisent un token utilisteur valide pour les appels API, ce n'est pas rentable d'isoler les tests à un niveau ou l'utilisateur est créé et authentifié à chaque requete. A la place, authentifie l'utilisateur une seule fois avant que l'execution des tests commencent (i.e before-all hook), enregistre le token en local et réutilise le dans les requetes. Ça semble violer un des principes de test principal - garder les tests autonomes sans associers les ressources. Même si c'est une inquiétude valide, dans les tests E2E la performance est une inquiétude clé et créer 1-3 requête API avant chaque test peut mener a un temps d'execution horrible. Réutiliser les informations d'authentification ne veux pas dire que les tests doivent agir sur la même entrée utilisateur - si le test compte sur les entrée utilisateur (e.g. test l'historique de paiement d'un utilisateur) alors assure toi de générer ces entrées dans le test et évite de les partager avec d'autres tests. Rappelles-toi aussi que le backend peut être simulé - Si les tests se concentrent sur le frontend, il vaux mieux les isoler et simuler l'API backend (voir point 3.6). +:white_check_mark: **à faire:** Dans des tests E2E qui incluent un vrai backend et utilisent un token utilisateur valide pour les appels API, ce n'est pas rentable d'isoler les tests à un niveau ou l'utilisateur est créé et authentifié à chaque requete. À la place, authentifie l'utilisateur une seule fois avant que l'exécution des tests commence (i.e before-all hook), enregistre le token en local et réutilise le dans les requetes. Ça semble violer un des principes de test principal - garder les tests autonomes sans associer les ressources. Même si c'est une inquiétude valide, dans les tests E2E la performance est une inquiétude clé et créer 1-3 requêtes API avant chaque test peut mener a un temps d'execution horrible. Réutiliser les informations d'authentification ne veut pas dire que les tests doivent agir sur la même entrée utilisateur - si le test compte sur les entrées utilisateur (e.g. test l'historique de paiement d'un utilisateur) alors assure toi de générer ces entrées dans le test et évite de les partager avec d'autres tests. Rappelle-toi aussi que le backend peut être simulé - Si les tests se concentrent sur le frontend, il vaut mieux les isoler et simuler l'API backend (voir point 3.6).
    ❌ **Autrement:** Si on prend 200 cas de tests et qu'on estime l'authentification à 100ms = 20 secondes simplement pour s'authentifier encore et encore @@ -1346,11 +1346,11 @@ beforeEach(setUser => () { ## ⚪ ️ 3.9 Avoir un test E2E qui parcours juste les pages du site -:white_check_mark: **À faire:** Pour le suivi de production et la vérification pendant le développement, lance un seul test E2E qui visite toute ou la plupart des pages du site et vérifie qu'aucune n'échoue. Ce type de test apporte un bon retour sur investissement puisqu'il est trés simple à écrire et maintenir, mais peut détecter tout type d'erreur en incluant les problèmes fonctionnels, de réseau ou de déploiement. Les autres types de smoke test et sanity check ne sont pas aussi fiable et exhaustifs - certaines équipes opérationnelles ne font que ping la page d'accueil (production) ou les développeurs qui lancent plusieurs tests d'intégrations qui ne révèlent pas les problèmes de packaging ou liés au navigateur. Il est évident que ce smoke test ne remplace pas les test fonctionnels, mais il sert à détecter rapidement les problèmes. +:white_check_mark: **À faire:** Pour le suivi de production et la vérification pendant le développement, lance un seul test E2E qui visite toute ou la plupart des pages du site et vérifie qu'aucune n'échoue. Ce type de test apporte un bon retour sur investissement puisqu'il est très simple à écrire et maintenir, mais peut détecter tout type d'erreur en incluant les problèmes fonctionnels, de réseau ou de déploiement. Les autres types de smoke test et sanity check ne sont pas aussi fiable et exhaustifs - certaines équipes opérationnelles ne font que ping la page d'accueil (production) ou les développeurs qui lancent plusieurs tests d'intégrations qui ne révèlent pas les problèmes de packaging ou liés au navigateur. Il est évident que ce smoke test ne remplace pas les tests fonctionnels, mais il sert à détecter rapidement les problèmes.
    -❌ **Autrement:** Tout peu sembler parfait, tout les tests passent, le health-check de production est également positif mais le composant de paiement a eu des erreurs de packaging et suel la route /payment ne s'affiche pas +❌ **Autrement:** Tout peut sembler parfait, tous les tests passent, le health-check de production est également positif, mais le composant de paiement a eu des erreurs de packaging et seul la route /payment ne s'affiche pas
    @@ -1381,11 +1381,11 @@ it("When doing smoke testing over all page, should load them all successfully", ## ⚪ ️ 3.10 Exposer les tests comme un document collaboratif -:white_check_mark: **À faire:** En plus d'améliorer la stabilité de l'application, les tests apportent une autre opportunitée intéressante - ils servent comment une documentation de l'app. -Puisque les tests parlent naturellement à un niveau moins technique avec un language plus produit/UX, en utilisant les bons outils, ils peuvent être utilisés comme un outil de communication qui aligne toute l'équipe - les développeurs et les clients. -Par exemple, certains frameworks permettent d'exprimer les parcours et les attentes (i.e les plans de tests) en utilisant un language lisible par l'humain, donc chaque personne impliquée, y compris les product manager, peuvent lire, approuver et communiquer sur les tests qui sont juste devenu le document de spécification. Cette technique s'appelle aussi 'test d'acceptance' puisqu'il permet au client de définir ses critères de validité en language simple. Il s'agit de [BDD (behavior-driven testing)](https://en.wikipedia.org/wiki/Behavior-driven_development) dans sa forme la plus pure. L'un des frameworks populaire qui permet ça est [Cucumber qui a un goût de Javascript](https://github.com/cucumber/cucumber-js), voir l'exemple ci-dessous. Une autre opportunité similaire, [StoryBook](https://storybook.js.org/) permet d'exposer les composants UI comme un catalogue graphique dans lequel on peux se promener à travers les différents états de chaque composant (e.g afficher une grille avec ou sans filtre, l'afficher avec plusieurs lignes ou aucune, etc), voir à quoi il ressemble, et comment déclencher cet état - cela peut servir aux équipe produit mais sert surtout de documentation aux développeurs qui utilisent ces composants +:white_check_mark: **À faire:** En plus d'améliorer la stabilité de l'application, les tests apportent une autre opportunité intéressante - ils servent comment une documentation de l'app. +Puisque les tests parlent naturellement à un niveau moins technique avec un langage plus produit/UX, en utilisant les bons outils, ils peuvent être utilisés comme un outil de communication qui aligne toute l'équipe - les développeurs et les clients. +Par exemple, certains frameworks permettent d'exprimer les parcours et les attentes (i.e les plans de tests) en utilisant un langage lisible par l'humain, donc chaque personne impliquée, y compris les product manager, peuvent lire, approuver et communiquer sur les tests qui sont juste devenu le document de spécification. Cette technique s'appelle aussi 'test d'acceptance' puisqu'il permet au client de définir ses critères de validité en langage simple. Il s'agit de [BDD (behavior-driven testing)](https://en.wikipedia.org/wiki/Behavior-driven_development) dans sa forme la plus pure. L'un des frameworks populaire qui permet ça est [Cucumber qui a un goût de Javascript](https://github.com/cucumber/cucumber-js), voir l'exemple ci-dessous. Une autre opportunité similaire, [StoryBook](https://storybook.js.org/) permet d'exposer les composants UI comme un catalogue graphique dans lequel on peut se promener à travers les différents états de chaque composant (e.g afficher une grille avec ou sans filtre, l'afficher avec plusieurs lignes ou aucune, etc), voir à quoi il ressemble, et comment déclencher cet état - cela peut servir aux équipe produit mais sert surtout de documentation aux développeurs qui utilisent ces composants -❌ **Autrement:** Aprés avoir investi des ressources dans les tests, ce serait juste dommage de ne pas se servir de cet investissement pour apporter encore plus de valeur +❌ **Autrement:** Après avoir investi des ressources dans les tests, ce serait juste dommage de ne pas se servir de cet investissement pour apporter encore plus de valeur
    @@ -1424,11 +1424,11 @@ Feature: Twitter new tweet ## ⚪ ️ 3.11 Détecter les problèmes visuels avec des outils automatisés -:white_check_mark: **À faire:** Configure des outils automatisés pour capturer des screenshots de l'UI quand des changements sont présentés et détecter les problèmes visuels comme du contenu qui se superpose ou qui est cassé. Cela permet de vérifier que non seulement les bonnes données sont présente mais également que l'utilisateur peut les voir correctement. Cette technique n'est pas trés courante, notre état d'esprit quand on pense aux tests est tourné sur les tests fonctionnels mais c'est le visuel que l'utilisateur expérimente et avec le nombre d'appareils différents disponible il est simple de rater un bug UI important. Certains outils gratuit procurent les bases - générer et enregistrer les screenshots pour qu'ils soient inspectés par un humain. Même si cette approche peut être suffisante pour de petites apps, son défaut comme tout test manuel est qu'il demande une intervention humaine à chaque fois que quelque chose change. D'un autre coté, il est assez difficile de détecter des problèmes UI automatiquement à cause du manque de définition claire - C'est ici que le domaine de 'Visual Regression' entre en jeu et résout ce problème en comparant d'ancienne UI avec les changements les plus récent pour détecter les différences. Certains outils gratuits peuvent fournir certaines de ces fonctionnalités (e.g [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>)) mais peuvent demander un temps de configuration considérable. Les outils commerciaux (e.g. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) vont un peu plus loin en simplifiant l'installation et en apportant des fonctionnalités avancés comme la gestion de l'UI, des alertes, de la capture automatique en éliminant le "bruit visuel" (e.g. pubs, animations) et même l'analyse du changement DOM/CSS qui a provoqué ce problème. +:white_check_mark: **À faire:** Configure des outils automatisés pour capturer des screenshots de l'UI quand des changements sont présentés et détecter les problèmes visuels comme du contenu qui se superpose ou qui est cassé. Cela permet de vérifier que non seulement les bonnes données sont présente mais également que l'utilisateur peut les voir correctement. Cette technique n'est pas très courante, notre état d'esprit quand on pense aux tests est tourné sur les tests fonctionnels mais c'est le visuel que l'utilisateur expérimente et avec le nombre d'appareils différents disponible il est simple de rater un bug UI important. Certains outils gratuits procurent les bases - générer et enregistrer les screenshots pour qu'ils soient inspectés par un humain. Même si cette approche peut être suffisante pour de petites apps, son défaut comme tout test manuel est qu'il demande une intervention humaine à chaque fois que quelque chose change. D'un autre côté, il est assez difficile de détecter des problèmes UI automatiquement à cause du manque de définition claire - C'est ici que le domaine de 'Visual Regression' entre en jeu et résout ce problème en comparant d'ancienne UI avec les changements les plus récent pour détecter les différences. Certains outils gratuits peuvent fournir certaines de ces fonctionnalités (e.g [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>)) mais peuvent demander un temps de configuration considérable. Les outils commerciaux (e.g. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) vont un peu plus loin en simplifiant l'installation et en apportant des fonctionnalités avancés comme la gestion de l'UI, des alertes, de la capture automatique en éliminant le "bruit visuel" (e.g. pubs, animations) et même l'analyse du changement DOM/CSS qui a provoqué ce problème.
    -❌ **Autrement:** Quelle est la qualité d'une page qui affiche un bon contenu (100% des tests passent), charge instantanément mais dont la moitié du contenu est caché ? +❌ **Autrement:** Quelle est la qualité d'une page qui affiche un bon contenu (100% des tests passent), charge instantanément mais dont la moitié du contenu est cachée ?
    @@ -1498,15 +1498,15 @@ describe("visual validation", () => {

    -# Section 4️⃣: Mesurer l'éfficacité des tests +# Section 4️⃣: Mesurer l'efficacité des tests

    ## ⚪ ️ 4.1 Avoir assez de couverture pour être confiant, ~80% semble être le nombre magique -:white_check_mark: **À faire:** Le but des tests est d'être assez confiant pour avancer rapidement, évidemment, plus le code est testé plus l'équipe peut être confiante. La couverture (coverage) est une mesure du nombre de lignes de code (et branches, statements, etc) sont atteint par les tests. À partir de quand est-ce suffisant ? 10-30% est évidemment trop bas pour avoir le moindre idée de la validité du build, d'un autre coté 100% est vraiment couteux et peut dévier votre intêret des parties importantes pour des coints exotiques du code. La réponse longue est que ça dépend de plusieurs facteurs comme le type de l'application - si tu construis la prochaine génération d'Airbus A380 alors 100% est obligatoire, pour un site d'image de dessin animé 50% peut être déjà trop. Même si la plupart des amateurs de tests assurent que le bon seuil dépend du contexte, la plupart d'entre eux mentionnent également le nombre 80% est une bonne règle générale ([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)) qui devrait répondre au besoin de la plupart des applications. +:white_check_mark: **À faire:** Le but des tests est d'être assez confiant pour avancer rapidement, évidemment, plus le code est testé plus l'équipe peut être confiante. La couverture (coverage) est une mesure du nombre de lignes de code (et branches, statements, etc) sont atteint par les tests. À partir de quand est-ce suffisant ? 10-30% est évidemment trop bas pour avoir la moindre idée de la validité du build, d'un autre côté 100% est vraiment coûteux et peut dévier votre intérêt des parties importantes pour des coins exotiques du code. La réponse longue est que ça dépend de plusieurs facteurs comme le type de l'application - si tu construis la prochaine génération d'Airbus A380 alors 100% est obligatoire, pour un site d'image de dessin animé 50% peut être déjà trop. Même si la plupart des amateurs de tests assurent que le bon seuil dépend du contexte, la plupart d'entre eux mentionnent également le nombre 80% est une bonne règle générale ([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)) qui devrait répondre au besoin de la plupart des applications. -Conseil d'implémentation: Tu peux vouloir configurer ton intégration continu pour qu'elle ai un seuil de couverture ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) et arrêter les builds qui ne répondent pas à ce standard (il est également possible de configurer un seuil par composant, voir l'exemple ci-dessous). En plus de ça, envisage de détecter les baisse de couverture (quand un nouveau commit à une couverture infèrieure) - cela poussera les développeurs à augmenter ou au moins à conserver la même quantité de code testé. Maintenant que c'est dit, la couverture n'est qu'une mesure, une quantitative, ce n'est pas assez pour dire si vos tests sont robustes. Et il peut aussi être biaisé comme on le verra dans le point suivant +Conseil d'implémentation: Tu peux vouloir configurer ton intégration continue pour qu'elle ait un seuil de couverture ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) et arrêter les builds qui ne répondent pas à ce standard (il est également possible de configurer un seuil par composant, voir l'exemple ci-dessous). En plus de ça, envisage de détecter les baisses de couverture (quand un nouveau commit à une couverture inférieure) - cela poussera les développeurs à augmenter ou au moins à conserver la même quantité de code testé. Maintenant que c'est dit, la couverture n'est qu'une mesure, une quantitative, ce n'est pas assez pour dire si vos tests sont robustes. Et il peut aussi être biaisé comme on le verra dans le point suivant
    @@ -1536,10 +1536,10 @@ Conseil d'implémentation: Tu peux vouloir configurer ton intégration continu p ## ⚪ ️ 4.2 Inspecter les rapports de couverture pour détecter les sections qui ne sont pas testées et autres bizarreries -:white_check_mark: **À faire:** Certains problèmes passent juste sous le radar et sont difficile à détecter en utilisants des outils traditionnels. Ce ne sont pas vraiment des beugs mais plutot des comportement surprenants de l'application qui peuvent avoir un impact important. Par exemple, souvent certaines parties du code sont rarement voir jamais invoquées - tu penses que la classe 'PricingCalculator' s'occupe toujours de déterminer le prix du produit mais il se trouve qu'elle n'est jamais invoquée alors qu'on a plus de 10000 produits en base de donnée et de nombreuses ventes ... Les rapports de couvertures t'aide à déterminer si l'application se comporte comme tu penses qu'elle le fait. En plus de ça, ils peuvent aussi montrer le type de code qui n'est pas testé - Être informé que 80% du code est testé n'indique pas si les parties critiques sont couvertes. Générer des rapports est simple - lance juste ton application en production ou pendant les tests avec le tracking de couverture activé et récupère des rapports qui montrent à quel fréquence chaque partie du code est invoquée. Si tu prend ton temps pour regarder ces donnée, tu pourras trouver des pièges +:white_check_mark: **À faire:** Certains problèmes passent juste sous le radar et sont difficiles à détecter en utilisant des outils traditionnels. Ce ne sont pas vraiment des bugs mais plutôt des comportement surprenants de l'application qui peuvent avoir un impact important. Par exemple, souvent certaines parties du code sont rarement voir jamais invoquées - tu penses que la classe 'PricingCalculator' s'occupe toujours de déterminer le prix du produit mais il se trouve qu'elle n'est jamais invoquée alors qu'on a plus de 10000 produits en base de données et de nombreuses ventes ... Les rapports de couvertures t'aident à déterminer si l'application se comporte comme tu penses qu'elle le fait. En plus de ça, ils peuvent aussi montrer le type de code qui n'est pas testé - Être informé que 80% du code est testé n'indique pas si les parties critiques sont couvertes. Générer des rapports est simple - lance juste ton application en production ou pendant les tests avec le tracking de couverture activé et récupère des rapports qui montrent à quelle fréquence chaque partie du code est invoquée. Si tu prends ton temps pour regarder ces données, tu pourras trouver des pièges
    -❌ **Autrement:** Si tu ne sais pas quelles parties du code ne sont pas couvertes par les tests, tu ne sais pas d'ou peuvent venir les problèmes +❌ **Autrement:** Si tu ne sais pas quelles parties du code ne sont pas couvertes par les tests, tu ne sais pas d'où peuvent venir les problèmes
    @@ -1559,18 +1559,18 @@ Basé sur un scénario réel, où nous avont tracké l'usage de notre applicatio ## ⚪ ️ 4.3 Mesurer la couverture logique en utilisant les tests de mutations -:white_check_mark: **À faire:** Les données de couverture traditionnelles mentent souvent: elles peuvent montrer 100% de couverture, mais aucune de tes fonctions, pas même une seule, ne retourne la bonne réponse. Pourquoi ? Il mesure simplement le nombre de ligne de code que les tests ont visités, mais il ne vérifie pas si les tests ont effectivement testé quelque chose et vérifié la réponse. Comme quelqu'un qui effectuerai un voyage d'affaire et qui montre les tampons sur son passeport - Cela ne prouve pas qu'il a travaillé, seulement qu'il a visité quelques aéroports et hotels. +:white_check_mark: **À faire:** Les données de couverture traditionnelles mentent souvent: elles peuvent montrer 100% de couverture, mais aucune de tes fonctions, pas même une seule, ne retourne la bonne réponse. Pourquoi ? Il mesure simplement le nombre de lignes de code que les tests ont visitées, mais ils ne vérifient pas si les tests ont effectivement testé quelque chose et vérifié la réponse. Comme quelqu'un qui effectuerai un voyage d'affaires et qui montre les tampons sur son passeport - Cela ne prouve pas qu'il a travaillé, seulement qu'il a visité quelques aéroports et hôtels. -Les tests de mutations sont la pour aider à mesurer la quantité de code qui a effectivement été TESTÉ et pas juste VISITé. [Stryker](https://stryker-mutator.io/) est une librairie Javascript pour les teests de mutation et son implémentation est très soignée : +Les tests de mutations sont là pour aider à mesurer la quantité de code qui a effectivement été TESTÉ et pas juste VISITÉ. [Stryker](https://stryker-mutator.io/) est une librairie Javascript pour les tests de mutation et son implémentation est très soignée : -(1) Il change volontairement le code et "implante des beugs". Par exemple, le code newOrder.price === 0 devient newOrder.price != 0. Ces "beugs" sont appelés des mutations +(1) Il change volontairement le code et "implante des bugs". Par exemple, le code newOrder.price === 0 devient newOrder.price != 0. Ces "bugs" sont appelés des mutations -(2) Il lance les tests, si tous réussissent, alors on a un problème - Les tests n'ont pas remplis leur rôle en découvrant les beugs, les mutations sont dites survivantes. Si les tests échouent, c'est bon, les mutations ont été tués. +(2) Il lance les tests, si tous réussissent, alors on a un problème - Les tests n'ont pas remplis leur rôle en découvrant les bugs, les mutations sont dites survivantes. Si les tests échouent, c'est bon, les mutations ont été tuées. Savoir que toute ou la plupart des mutations ont été tués donne une meilleure confiance qu'un rapport de couverture traditionnel et le temps de configuration est similaire.
    -❌ **Autrement:** Tu seras dupé en croyant que 85% de couverture de code signifie que tes tests détecteront les beugs dans 85% du code +❌ **Autrement:** Tu seras dupé en croyant que 85% de couverture de code signifie que tes tests détecteront les bugs dans 85% du code
    @@ -1608,10 +1608,10 @@ it("Test addNewOrder, don't use such test names", () => { ## ⚪ ️4.4 Éviter les problèmes dans le code de test avec les Test linters -:white_check_mark: **À faire:** Un groupe de plugins ESLint ont été développés spécifiquement pour inspecter le code de test et détecter les problèmes. Par exemple, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) t'avertira lorsqu'un test est écrit à un niveau global (pas un enfant d'une déclaration describe()) ou lorsque les tests sont [sautés](https://mochajs.org/#inclusive-tests), ce qui peut conduire à une fausse croyance que les tests passent. De façon similaire, [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) peut avertir lorsqu'un test n'as pas d'assertion (ne vérifie rien) +:white_check_mark: **À faire:** Un groupe de plugins ESLint ont été développés spécifiquement pour inspecter le code de test et détecter les problèmes. Par exemple, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) t'avertiras lorsqu'un test est écrit à un niveau global (pas un enfant d'une déclaration describe()) ou lorsque les tests sont [sautés](https://mochajs.org/#inclusive-tests), ce qui peut conduire à une fausse croyance que les tests passent. De façon similaire, [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) peut avertir lorsqu'un test n'a pas d'assertion (ne vérifie rien)
    -❌ **Autrement:** Voir 90% de couverture de code et 100% de tests verts fera apparaitre un grand sourire sur ton visage, jusqu'à ce que tu réalises que de nombreux tests ne vérifient rien et que plusieurs suites de tests ont été sautées. Avec un peu de chance, tu n'as rien déployé basé sur de fausses observations +❌ **Autrement:** Voir 90% de couverture de code et 100% de tests verts fera apparaître un grand sourire sur ton visage, jusqu'à ce que tu réalises que de nombreux tests ne vérifient rien et que plusieurs suites de tests ont été sautées. Avec un peu de chance, tu n'as rien déployé basé sur de fausses observations
    Exemple de code @@ -1644,11 +1644,11 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test ## ⚪ ️ 5.1 Enrichir ses linter et annuler les builds qui ont des problèmes de lint -:white_check_mark: **À faire:** Les linters sont un repas gratuit, avec 5 minutes de configurations, tu as gratuitement un auto-pilote qui surveille ton code et repère les problèmes pendant que tu tapes. Les jours ou les linters était reservés a l'esthetique sont terminés (pas de point-virgules!). De nos jours, les linters peuvent détecté des problèmes serieux comme des erreurs qui ne sont pas thrown correctement et les pertes d'informations. En plus de ta liste de règles basiques (like [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) or [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), considère d'ajouter des linters spécialisés comme [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) qui peux détecter les tests sans assertions, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) qui détecte les promesses qui ne se resolvent pas (le code ne va jamais continuer), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) qui peut découvrir les regex qui peuvent être utilisé pour des attaques DOS, et [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) qui est capable de t'indiquer lorsque le code utilise une méthode de librairie qui fait partie des méthodes du coeur V8 comme Lodash.\_map(...) +:white_check_mark: **À faire:** Les linters sont un bonus gratuit, avec 5 minutes de configurations, tu as gratuitement un auto-pilote qui surveille ton code et repère les problèmes pendant que tu tapes. Les jours où les linters étaient réservés à l'esthétique sont terminés (pas de point-virgules!). De nos jours, les linters peuvent détecter des problèmes sérieux comme des erreurs qui ne sont pas thrown correctement et les pertes d'informations. En plus de ta liste de règles basiques (like [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) or [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), considère d'ajouter des linters spécialisés comme [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) qui peux détecter les tests sans assertions, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) qui détecte les promesses qui ne se resolvent pas (le code ne va jamais continuer), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) qui peut découvrir les regex qui peuvent être utilisé pour des attaques DOS, et [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) qui est capable de t'indiquer lorsque le code utilise une méthode de librairie qui fait partie des méthodes du cœur V8 comme Lodash.\_map(...)
    -❌ **Autrement:** Imagine un jour de pluie ou ta production n'arrête pas de crasher mais les logs ne montrent aucune stack trace d'erreur. Qu'est-ce qu'il s'est passé ? Ton code a malencontreusement émit un objet qui n'était pas une erreur et la stack trace a été perdu, une bonne raison de se taper la tête contre les murs. 5 minutes de configurations d'un linter pourrait permettre de détecter cette erreur et sauver la journée +❌ **Autrement:** Imagine un jour de pluie ou ta production n'arrête pas de crasher mais les logs ne montrent aucune stack trace d'erreur. Qu'est-ce qu'il s'est passé ? Ton code a malencontreusement émis un objet qui n'était pas une erreur et la stack trace a été perdu, une bonne raison de se taper la tête contre les murs. 5 minutes de configuration d'un linter pourraient permettre de détecter cette erreur et sauver la journée
    @@ -1666,12 +1666,12 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test ## ⚪ ️ 5.2 Raccourcir la boucle de retours avec du CI local pour les développeurs -:white_check_mark: **À faire:** Tu utilises un outil de CI avec une bonne inspection de qualité comme des tests, du linting, des checks de vulnérabilités, etc ? Aide les développeurs à lancer également cette pipeline en local pour solliciter un retour instantané et raccourcir la [boucle de feedback](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). Pourquoi ? Un processus de tests efficace constitue de nombreuses boucles itératives: (1) essai -> (2) retours -> (3) refactor. Plus le retour est rapide, plus le développeur peut effectuer d'itérations d'améliorations par modules et perfonctionner le résultat. D'un autre coté, lorsque les retours sont lent à arriver, moins d'améliorations peuvent être effectuée au sein d'une journée, l'équipe peut être déjà passé à un autre sujet/tache/module et peut ne pas être prête a affiner ce module. +:white_check_mark: **À faire:** Tu utilises un outil de CI avec une bonne inspection de qualité comme des tests, du linting, des checks de vulnérabilités, etc ? Aide les développeurs à lancer également cette pipeline en local pour solliciter un retour instantané et raccourcir la [boucle de feedback](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). Pourquoi ? Un processus de tests efficace constitue de nombreuses boucles itératives: (1) essai -> (2) retours -> (3) refactoriser. Plus le retour est rapide, plus le développeur peut effectuer d'itérations d'améliorations par modules et perfectionner le résultat. D'un autre côté, lorsque les retours sont lent à arriver, moins d'améliorations peuvent être effectuées au sein d'une journée, l'équipe peut être déjà passée à un autre sujet/tache/module et peut ne pas être prête a affiner ce module. -En pratique, certains fournisseurs de CI (Exemple: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) autorisent le lancement de la pipeline en local. Certains outils commerciaux comme [wallaby fournissent des informations de valeur et des tests](https://wallabyjs.com/) pendant que le développeur prototype (pas d'affiliation). Alternativement, tu peux simplement ajouter un script npm au package.json qui lance toute les commandes de qualités (e.g. tests, lint, vulnérabilités) - utilise des outils comme [concurrently](https://www.npmjs.com/package/concurrently) pour la parallélisation et des code de retour différents de 0 si l'un des outils échoue. Maintenant le développeur peut juste lancer une commande - e.g. 'npm run quality' - pour recevoir un retour instantané. Envisage également d'annuler un commit si le controle de qualité ne passe pas en utilisant githook ([husky can help](https://github.com/typicode/husky)) +En pratique, certains fournisseurs de CI (Exemple: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) autorisent le lancement de la pipeline en local. Certains outils commerciaux comme [wallaby fournissent des informations de valeur et des tests](https://wallabyjs.com/) pendant que le développeur prototype (pas d'affiliation). Alternativement, tu peux simplement ajouter un script npm au package.json qui lance toute les commandes de qualités (e.g. tests, lint, vulnérabilités) - utilise des outils comme [concurrently](https://www.npmjs.com/package/concurrently) pour la parallélisation et des code de retour différents de 0 si l'un des outils échoue. Maintenant le développeur peut juste lancer une commande - e.g. 'npm run quality' - pour recevoir un retour instantané. Envisage également d'annuler un commit si le contrôle de qualité ne passe pas en utilisant githook ([husky can help](https://github.com/typicode/husky))
    -❌ **Autrement:** Quand les résultats de qualité arrivent le jour suivant le développement, les tests ne sont pas une partie fluide du développement mais plutot une étape formelle aprés coup +❌ **Autrement:** Quand les résultats de qualité arrivent le jour suivant le développement, les tests ne sont pas une partie fluide du développement mais plutôt une étape formelle après coup
    Exemple de code @@ -1703,14 +1703,14 @@ En pratique, certains fournisseurs de CI (Exemple: [CircleCI local CLI](https://

    -## ⚪ ️5.3 Effectue des tests e2e sur un vrai mirroir de production +## ⚪ ️5.3 Effectuer des tests e2e sur un vrai miroir de production -:white_check_mark: **À faire:** Les tests end to end (E2E) sont le défi principal de chaque pipeline CI - créer un mirroir éphémère de la production à la volée avec toute les services clouds lié peut être fastidieux et couteux. Le jeu est de trouver le meilleur compromis: [Docker-compose](https://serverless.com/) permet de créer des environnement dockerisés isolés avec des containers identiques en utilisant un simple fichier text mais la technologie backend (e.g réseau, modèle de deploiement) est différents de la vrai production. Tu peux l'associer à [‘AWS Local’](https://github.com/localstack/localstack) pour travailler avec un stub des services AWS. Si tu es [serverless](https://serverless.com/), plusieurs frameworks comme serverless et [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) permettent l'invocation locale de code FaaS. +:white_check_mark: **À faire:** Les tests end to end (E2E) sont le défi principal de chaque pipeline CI - créer un miroir éphémère de la production à la volée avec tous les services clouds lié peut être fastidieux et coûteux. Le jeu est de trouver le meilleur compromis: [Docker-compose](https://serverless.com/) permet de créer des environnement dockerisés isolés avec des containers identiques en utilisant un simple fichier text mais la technologie backend (e.g réseau, modèle de déploiement) est différent de la vrai production. Tu peux l'associer à [‘AWS Local’](https://github.com/localstack/localstack) pour travailler avec un stub des services AWS. Si tu es [serverless](https://serverless.com/), plusieurs frameworks comme serverless et [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) permettent l'invocation locale de code FaaS. -Le large écosystème de Kubernetes doit encore formaliser un outils standard pour la mise en mirroir locale et CI, bien que de nombreux nouveaux outils soient lancés fréquemment. Une des approche est de lancer un 'minimized-Kubernetes' en utilisant des outils comme [Minikube](https://kubernetes.io/docs/setup/minikube/) et [MicroK8s](https://microk8s.io/). Une autre approche est de testé avec un 'vrai-Kebernetes' distant, certains fournisseurs CI (e.g. [Codefresh](https://codefresh.io/)) ont une intégration native avec l'environnement Kubernetes et rendent simple le lancement d'une pipeline CI sur le vrai environnement, d'autres permettent d'executer des scripts custom sur le Kubernetes distant. +Le large écosystème de Kubernetes doit encore formaliser un outil standard pour la mise en miroir locale et CI, bien que de nombreux nouveaux outils soient lancés fréquemment. Une des approches est de lancer un 'minimized-Kubernetes' en utilisant des outils comme [Minikube](https://kubernetes.io/docs/setup/minikube/) et [MicroK8s](https://microk8s.io/). Une autre approche est de tester avec un 'vrai-Kebernetes' distant, certains fournisseurs CI (e.g. [Codefresh](https://codefresh.io/)) ont une intégration native avec l'environnement Kubernetes et rendent simple le lancement d'une pipeline CI sur le vrai environnement, d'autres permettent d'exécuter des scripts custom sur le Kubernetes distant.
    -❌ **Autrement:** Utiliser des technologies différentes pour la production et pour les tests demande de maintenir deux modèles de déploiement et créer une séparation entre l'équipe dév et l'équipe ops. +❌ **Autrement:** Utiliser des technologies différentes pour la production et pour les tests demande de maintenir deux modèles de déploiement et créer une séparation entre l'équipe dev et l'équipe ops.
    Exemple de code @@ -1727,9 +1727,9 @@ Le large écosystème de Kubernetes doit encore formaliser un outils standard po ## ⚪ ️5.4 Paralléliser l'exécution des tests -:white_check_mark: **À faire:** Lorsque c'est fait correctement, les tests sont ton ami 24/7 en fournissant un retour quasi instantanné. En pratique, éxécuter 500 tests unitaire liés au processeur sur un seul thread peut prendre trop longtemps. Heuresement, les outils de tests et les plateformes CI moderne (comme [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) et [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) peuvent paralléliser les tests sur plusieurs processus et améliorer significativement le temps de retour. Certains fournisseurs CI font également de la parallélisation de tests à travers des containers (!) ce qui raccourcis encore plus la boucle de retour. Que ce soit locallement sur plusieurs processus, ou sur un serveur Cloud avec plusieurs machines - paralléliser demande de garder les tests autonomes puisqu'ils peuvent tourner sur différents processus. +:white_check_mark: **À faire:** Lorsque c'est fait correctement, les tests sont tes amis 24/7 en fournissant un retour quasi instantané. En pratique, exécuter 500 tests unitaires liés au processeur sur un seul thread peut prendre trop longtemps. Heureusement, les outils de tests et les plateformes CI moderne (comme [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) et [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) peuvent paralléliser les tests sur plusieurs processus et améliorer significativement le temps de retour. Certains fournisseurs CI font également de la parallélisation de tests à travers des containers (!) ce qui raccourcis encore plus la boucle de retour. Que ce soit localement sur plusieurs processus, ou sur un serveur Cloud avec plusieurs machines - paralléliser demande de garder les tests autonomes puisqu'ils peuvent tourner sur différents processus. -❌ **Autrement:** Obtenir les résultats de tests 1h aprés avoir publié du nouveau code, pendant que tu es déjà en train de coder la fonctionnalité suivante, est une bonne recette pour rendre les tests moins pertinents +❌ **Autrement:** Obtenir les résultats de tests 1h après avoir publié du nouveau code, pendant que tu es déjà en train de coder la fonctionnalité suivante, est une bonne recette pour rendre les tests moins pertinents
    Exemple de code @@ -1744,11 +1744,11 @@ Le large écosystème de Kubernetes doit encore formaliser un outils standard po

    -## ⚪ ️5.5 Reste loin des problèmes légaux en utilisants des vérification de license et de plagiat +## ⚪ ️5.5 Rester loin des problèmes légaux en utilisants des vérifications de license et de plagiat :white_check_mark: **À faire:** Les problèmes de licences et de plagiat ne sont probablement pas au centre de votre attention pour l'instant, mais pourquoi ne pas cocher également cette case en 10 minutes ? Plusieurs packages npm comme [license check](https://www.npmjs.com/package/license-checker) et [plagiarism check](https://www.npmjs.com/package/plagiarism-checker) (commerciaux avec un essai gratuit) peuvent être facilement intégré dans ta pipeline CI et inspecter les problèmes tels que les dépendances avec des licences restrictives ou du code qui a été copié-collé à partir de Stack Overflow et qui violerai certains droits d'auteur -❌ **Autrement:** Involontairement, les développeurs peuvent utiliser un packages avec une license inaproprié, ou copier/coller du code commercial et tomber sur des problèmes légaux +❌ **Autrement:** Involontairement, les développeurs peuvent utiliser un package avec une license inapproprié, ou copier/coller du code commercial et tomber sur des problèmes légaux
    Exemple de code @@ -1776,9 +1776,9 @@ license-checker --summary --failOn BSD ## ⚪ ️5.6 Inspecter constamment les dépendences vulnérables -:white_check_mark: **À faire:** Même les dépendances les plus réputés comme Express ont des vulnérabilités connues. Cela peut être apprivoisé facilement avec des outils de la communauté comme [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), ou des outils commerciaux comme [snyk](https://snyk.io/) (qui offre également une version de la communauté gratuite). Les deux peuvent être appelé depuis ton CI à chaque build +:white_check_mark: **À faire:** Même les dépendances les plus réputées comme Express ont des vulnérabilités connues. Cela peut être apprivoisé facilement avec des outils de la communauté comme [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), ou des outils commerciaux comme [snyk](https://snyk.io/) (qui offre également une version de la communauté gratuite). Les deux peuvent être appelés depuis ton CI à chaque build -❌ **Autrement:** Garder ton code exempt de vulnérabilités sans les outils appropriés demande de suivre constamment les publications en ligne à propos des nouvelles menaces. Plutot fastidieux. +❌ **Autrement:** Garder ton code exempt de vulnérabilités sans les outils appropriés demande de suivre constamment les publications en ligne à propos des nouvelles menaces. Plutôt fastidieux.
    @@ -1796,16 +1796,16 @@ license-checker --summary --failOn BSD ## ⚪ ️5.7 Automatiser les mises-à-jour de dépendences -:white_check_mark: **À faire:** L'introduction récente du package-lock.json par Yarn et npm à introduit un vrai défi (la route vers l'enfer est pavée de bonne intentions) - par défault maintenant, les packages ne sont pas mis à jour. Même une équipe qui lance plusieurs nouveaux déploiement avec 'npm install' & 'npm update' n'aura pas de nouvelles mise à jour. Cela conduit au mieux, à des dépendances à des packages de qualité infèrieur, au pire à du code vulnérable. Les équipes dépendent maintenant de la bonne volonté et de la mémoire des développeur pour mettre à jour manuellement le package.json ou utiliser des outils [comme ncu](https://www.npmjs.com/package/npm-check-updates). Une méthode plus fiable pourrait être d'automatiser le processus de récupération des versions de dépendances les plus fiables, bien qu'il n'y ai pas de solutions miracle, il y a deux possibilités d'automatisation: +:white_check_mark: **À faire:** L'introduction récente du package-lock.json par Yarn et npm à introduit un vrai défi (la route vers l'enfer est pavée de bonnes intentions) - par défaut maintenant, les packages ne sont pas mis à jour. Même une équipe qui lance plusieurs nouveaux déploiements avec 'npm install' & 'npm update' n'aura pas de nouvelles mise à jour. Cela conduit au mieux, à des dépendances à des packages de qualité inférieure, au pire à du code vulnérable. Les équipes dépendent maintenant de la bonne volonté et de la mémoire des développeur pour mettre à jour manuellement le package.json ou utiliser des outils [comme ncu](https://www.npmjs.com/package/npm-check-updates). Une méthode plus fiable pourrait être d'automatiser le processus de récupération des versions de dépendances les plus fiables, bien qu'il n'y ait pas de solutions miracle, il y a deux possibilités d'automatisation: -(1) Le CI peut faire échouer les buils qui ont des dépendances obsolètes - en utilisants des outils comme [‘npm outdated’](https://docs.npmjs.com/cli/outdated) ou 'npm-check-updates (ncu)'. Faire ça forcera les développeurs à mettre à jour les dépendances. +(1) Le CI peut faire échouer les builds qui ont des dépendances obsolètes - en utilisant des outils comme [‘npm outdated’](https://docs.npmjs.com/cli/outdated) ou 'npm-check-updates (ncu)'. Faire ça forcera les développeurs à mettre à jour les dépendances. -(2) Utiliser un outil commercial qui peut scanner le code et envoyer automatiquement une pull-request avec les dépendances mises à jour. La question intéressante restante est, quel devrait être la politique de mises à jour - Mettre à jour chaque patch génère trop de surcharge, mettre à jour juste aprés une release majeure peut introduire une version instable (de nombreuses vulnérabilités sont découverte dans les premiers jours aprés la release, [voir l'incident](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) eslint-scope). +(2) Utiliser un outil commercial qui peut scanner le code et envoyer automatiquement une pull-request avec les dépendances mises à jour. La question intéressante restante est, quel devrait être la politique de mises à jour - Mettre à jour chaque patch génère trop de surcharge, mettre à jour juste après une release majeure peut introduire une version instable (de nombreuses vulnérabilités sont découverte dans les premiers jours après la release, [voir l'incident](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) eslint-scope). -Une politique de mise à jour efficace peut autoriser une 'pèriode d'acquisition' - laisser le code en retard par rapport à @latest pour quelques temps et versions avant de considérer la copie locale comme obsolète (e.g la version locale est 1.3.1 et la version du repo est 1.3.8) +Une politique de mise à jour efficace peut autoriser une 'période d'acquisition' - laisser le code en retard par rapport à @latest pour quelque temps et versions avant de considérer la copie locale comme obsolète (e.g la version locale est 1.3.1 et la version du repo est 1.3.8)
    -❌ **Autrement:** Ta production utilisera des packages qui ont été taggé explicitement par leur auteurs comme risquées +❌ **Autrement:** Ta production utilisera des packages qui ont été taggé explicitement par leurs auteurs comme risquées
    @@ -1821,23 +1821,23 @@ Une politique de mise à jour efficace peut autoriser une 'pèriode d'acquisitio

    -## ⚪ ️ 5.8 Autre conseils CI, sans rapports avec Node +## ⚪ ️ 5.8 Autres conseils CI, sans rapports avec Node :white_check_mark: **À faire:** Ce post se concentre sur les conseils de tests qui sont en lien avec, ou peuvent être illustrés, avec Node JS. Ce point, cependant, regroupe quelques conseils sans rapports avec Node qui sont bien connus -
    1. Utilise une syntaxe déclarative. C'est la seule option pour la plupart des fournisseurs mais d'anciennes versions de Jenkins autorisent l'utilisation du code ou de l'UI
    2. Choisit un fournisseur qui à une intégration Docker native
    3. Échoue rapidement, lance les tests les plus rapide d'abord. Crée des 'tests de fumée' pour certaines étapes qui regroupe plusieurs inspections rapide (e.g liting, tests unitaires) et fourni des commentaires rapide à celui qui commit le code
    4. Facilite le parcours des informations de build, cela inclut les rapports de tests, de couverture, de mutation, les logs ..etc
    5. Crée plusieurs pipelines/jobs pour chaque évènement, réutiliser les étapes entre eux. Par exemple, configure un job pour les commits de features sur une branche et un différent pour une PR sur master. Laisse chacun réutiliser la logique en utilisants des étapes partagés (la plupart des fournisseurs ont des mécanisme pour réutiliser le code)
    6. Ne met jamais de secrets dans la déclaration du job, récupère les depuis un secret store ou depuis les configurations du job
    7. Augmente explicitement la version dans un build de release, ou au moins vérifie que le développeur l'a fait
    8. Build une fois et efféctue toute les inspections sur l'artefact de build (e.g. Docker image)
    9. Test dans un environnement ephémère qui ne change pas d'état entre les builds. Le cache des nodes peut être la seule exception
    +
    1. Utilise une syntaxe déclarative. C'est la seule option pour la plupart des fournisseurs mais d'anciennes versions de Jenkins autorisent l'utilisation du code ou de l'UI
    2. Choisis un fournisseur qui a une intégration Docker native
    3. Échoue rapidement, lance les tests les plus rapides d'abord. Crée des 'tests de fumée' pour certaines étapes qui regroupe plusieurs inspections rapide (e.g liting, tests unitaires) et fourni des commentaires rapides à celui qui commit le code
    4. Facilite le parcours des informations de build, cela inclut les rapports de tests, de couverture, de mutation, les logs ..etc
    5. Crée plusieurs pipelines/jobs pour chaque événement, réutiliser les étapes entre eux. Par exemple, configure un job pour les commits de features sur une branche et un différent pour une PR sur master. Laisse chacun réutiliser la logique en utilisant des étapes partagées (la plupart des fournisseurs ont des mécanismes pour réutiliser le code)
    6. Ne mets jamais de secrets dans la déclaration du job, récupère-les depuis un secret store ou depuis les configurations du job
    7. Augmente explicitement la version dans un build de release, ou au moins vérifie que le développeur l'a fait
    8. Build une fois et effectue toute les inspections sur l'artefact de build (e.g. Docker image)
    9. Test dans un environnement éphémère qui ne change pas d'état entre les builds. Le cache des nodes peut être la seule exception

    ❌ **Autrement:** Tu rateras des années de sagesse

    -## ⚪ ️ 5.9 Structure de build: Lance les mêmes étapes CI sur plusieurs versions de Node +## ⚪ ️ 5.9 Structure de build: Lancer les mêmes étapes CI sur plusieurs versions de Node -:white_check_mark: **À faire:** Le controle de qualité est un jeu de hasard, plus tu couvres de terrain, plus tu as de chance de détecter les problèmes rapidement. Quand tu développes des packages réutilisable ou que tu lance une production avec plusieurs clients qui ont différentes configurations et versions de Node, le CI doit lancer la pipeline de trests sur toutes les configurations possible. Par exemple, imaginons qu'on utilise MySQL pour certains clients et Postgres pour d'autres - Certains fournisseurs CI supportent une fonctionnalitée appelée 'Matrix' qui permet de lancer les tests contre toute les permutations de MySQL, Postgres et plusieurs versions de Node comme 8, 9 et 10. Cela peut se faire en utilisant seulement des configurations sans efforts supplémentaire (en considérant que tu as des tests ou d'autres controles de qualités). D'autres CIs qui ne supportent pas Matrix peuvent avoir des extensions qui permettent ça +:white_check_mark: **À faire:** Le contrôle de qualité est un jeu de hasard, plus tu couvres de terrain, plus tu as de chance de détecter les problèmes rapidement. Quand tu développes des packages réutilisable ou que tu lances une production avec plusieurs clients qui ont différentes configurations et versions de Node, le CI doit lancer la pipeline de tests sur toutes les configurations possible. Par exemple, imaginons qu'on utilise MySQL pour certains clients et Postgres pour d'autres - Certains fournisseurs CI supportent une fonctionnalitée appelée 'Matrix' qui permet de lancer les tests contre toutes les permutations de MySQL, Postgres et plusieurs versions de Node comme 8, 9 et 10. Cela peut se faire en utilisant seulement des configurations sans efforts supplémentaire (en considérant que tu as des tests ou d'autres contrôles de qualités). D'autres CIs qui ne supportent pas Matrix peuvent avoir des extensions qui permettent ça
    -❌ **Autrement:** Aprés avoir fait tout le travail d'écrire des tests, vas-t-on laisser passer des bugs seulement à cause de problèmes de configurations ? +❌ **Autrement:** Après avoir fait tout le travail d'écrire des tests, va-t-on laisser passer des bugs seulement à cause de problèmes de configurations ?
    @@ -1862,7 +1862,7 @@ Une politique de mise à jour efficace peut autoriser une 'pèriode d'acquisitio **Rôle:** Auteur -**À propos:** Je suis un consultatn indépendant qui travaille avec des entreprises Fortune 500 et des startup pour peaufiner leurs applications JS et Node.JS. Plus qu'aucun autre sujet, je suis fasciné par et vise à maitriser l'art du test. Je suis aussi l'auteur de [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices) +**À propos:** Je suis un consultant indépendant qui travaille avec des entreprises Fortune 500 et des startups pour peaufiner leurs applications JS et Node.JS. Plus qu'aucun autre sujet, je suis fasciné par et vise à maîtriser l'art du test. Je suis aussi l'auteur de [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices) **📗 Cours en ligne:** Tu aimes ce guide et tu veux pousser tes compétences de test à l'extreme ? Pense à regarder mon cours complet [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) @@ -1882,7 +1882,7 @@ Une politique de mise à jour efficace peut autoriser une 'pèriode d'acquisitio **Rôle:** Réviseur et conseiller technique -À pris soin de revoir, améliorer, linter et peaufiner tout les textes +A pris soin de revoir, améliorer, linter et peaufiner tout les textes **À propos:** Ingénieur web full-stack, passioné par Node.js et GraphQL From 08f3899ef1e501afdd37a5d7cc975d22427b4f59 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Wed, 22 Sep 2021 09:56:55 +0300 Subject: [PATCH 058/189] Update readme.md --- readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/readme.md b/readme.md index 30f800c2..c7321516 100644 --- a/readme.md +++ b/readme.md @@ -26,6 +26,9 @@ Start by understanding the ubiquitous testing practices that are the foundation - 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - My comprehensive online course with more than [10 hours of video](https://www.testjavascript.com), 14 test types and more than 40 best practices - [Follow me on Twitter](https://twitter.com/goldbergyoni/) + +👨‍🏫 [Nodeconf 2021](https://www.nodeconfremote.com/#workshops) is just around the corner, and will **host a 5 hours testing workshop with Yoni Goldberg**. [Register here](https://www.nodeconfremote.com/#workshops) +
    ### Translations - read in your own language From cbef97a0be8ec7db042ed3e42cec63680a7071e7 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Sun, 21 Nov 2021 16:35:57 +0200 Subject: [PATCH 059/189] Update readme.md --- readme.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/readme.md b/readme.md index 843e5d7e..1e7990b3 100644 --- a/readme.md +++ b/readme.md @@ -26,9 +26,6 @@ Start by understanding the ubiquitous testing practices that are the foundation - 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - My comprehensive online course with more than [10 hours of video](https://www.testjavascript.com), 14 test types and more than 40 best practices - [Follow me on Twitter](https://twitter.com/goldbergyoni/) - -👨‍🏫 [Nodeconf 2021](https://www.nodeconfremote.com/#workshops) is just around the corner, and will **host a 5 hours testing workshop with Yoni Goldberg**. [Register here](https://www.nodeconfremote.com/#workshops) -
    ### Translations - read in your own language From 993c63cc9535c8f0e481e87fe98dfc9d6b60d51a Mon Sep 17 00:00:00 2001 From: yubintw Date: Mon, 22 Nov 2021 03:00:50 +0800 Subject: [PATCH 060/189] Translate the introduction --- readme-zh-TW.md | 1981 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1981 insertions(+) create mode 100644 readme-zh-TW.md diff --git a/readme-zh-TW.md b/readme-zh-TW.md new file mode 100644 index 00000000..10a70528 --- /dev/null +++ b/readme-zh-TW.md @@ -0,0 +1,1981 @@ + + +
    + +# 👇 為什麼本指南可以幫助你將測試能力提升到下一個等級 + +
    + +## 📗 46+ 個最佳實踐:非常全面且徹底 + +這是從 A 到 Z 的 JavaScript 及 Node.js 可靠的指南。它為你總結及規劃了市場上大量的部落格文章、書籍及工具。 + +## 🚢 進階:從基礎向前邁進 10,000 英里 Advanced: Goes 10,000 miles beyond the basics + +從基礎往前邁進的旅程,包括:在生產(production)環境中測試、變異測試(mutation testing)、以屬性為基礎(property-based)的測試以及許多策略和專業工具。如果你認真閱讀本指南書,你的測試技能可能會高於平均水準。 + +## 🌐 全端:前端、後端、CI、所有部分 + +首先了解任何應用程式都通用的測試實踐。然後再深入研究你選擇的領域:前端/UI、後端、CI 或者全部。 + + +
    + +### 作者 Yoni Goldberg + +- A JavaScript & Node.js consultant +- 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - My comprehensive online course with more than [10 hours of video](https://www.testjavascript.com), 14 test types and more than 40 best practices +- [Follow me on Twitter](https://twitter.com/goldbergyoni/) + +
    + +### 翻譯 - 以你的語言來閱讀本文 + +- 🇹🇼[Traditional Chinese](readme-zh-TW.md) - Courtesy of [Yubin Hsu](https://github.com/yubinTW) +- 🇨🇳[Chinese](readme-zh-CN.md) - Courtesy of [Yves yao](https://github.com/yvesyao) +- 🇰🇷[Korean](readme.kr.md) - Courtesy of [Rain Byun](https://github.com/ragubyun) +- 🇵🇱[Polish](readme-pl.md) - Courtesy of [Michal Biesiada](https://github.com/mbiesiad) +- 🇪🇸[Spanish](readme-es.md) - Courtesy of [Miguel G. Sanguino](https://github.com/sanguino) +- 🇧🇷[Portuguese-BR](readme-pt-br.md) - Courtesy of [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) +- 🇫🇷[French](readme-fr.md) - Courtesy of [Mathilde El Mouktafi](https://github.com/mel-mouk) +- Want to translate to your own language? please open an issue 💜 + +

    + +## `目錄` + +#### [`第 0 章:黃金原則`](#section-0️⃣-the-golden-rule) + +一個激發所有人的建議 (1個特殊項目) + +#### [`第 1 章:測試剖析`](#section-1-the-test-anatomy-1) + +基礎 - 建立乾淨的測試 (12項) + +#### [`第 2 章:後端`](#section-2️⃣-backend-testing) + +有效率地撰寫後端及微服務的測試 (8項) + +#### [`第 3 章:前端`](#section-3️⃣-frontend-testing) + +為網頁 UI (包括組件及E2E) 撰寫測試 (11項) + +#### [`第 4 章:測量測試的有效程度`](#section-4️⃣-measuring-test-effectiveness) + +測量測試的品質 (4項) + +#### [`第 5 章:持續整合 (Continuous Integration)`](#section-5️⃣-ci-and-other-quality-measures) + +JavaScript 世界的 CI 指南 (9項) + +

    + +# 第 0 章:黃金原則 + +
    + +## ⚪️ 0 The Golden Rule: Design for lean testing + +:white_check_mark: **Do:** +Testing code is not like production-code - design it to be dead-simple, short, abstraction-free, flat, delightful to work with, lean. One should look at a test and get the intent instantly. + +Our minds are full with the main production code, we don't have 'headspace' for additional complexity. Should we try to squeeze yet another challenging code 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. + +The tests are an opportunity for something else - a friendly and smiley assistant, one that it's delightful to work with and delivers great value for such 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 which 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). + +This 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, strive to keep it nimble, sometimes it's even worth dropping some tests and trade reliability for agility and simplicity. + +![alt text](/assets/headspace.png "We have no head room for additional complexity") + +Most of the advice below are derivatives of this principle. + +### Ready to start? + +

    + +# Section 1: The Test Anatomy + +
    + +## ⚪ ️ 1.1 Include 3 parts in each test name + +: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: + +(1) What is being tested? For example, the ProductsService.addNewProduct method + +(2) Under what circumstances and scenario? For example, no price is passed to the method + +(3) What is the expected result? For example, the new product is not approved + +
    + +❌ **Otherwise:** A deployment just failed, a test named “Add product” failed. Does this tell you what exactly is malfunctioning? + +
    + +**👇 Note:** Each bullet has code examples and sometime also an image illustration. Click to expand +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: A test name that constitutes 3 parts + +![](https://img.shields.io/badge/🔨%20Example%20using%20Mocha-blue.svg "Using Mocha to illustrate the idea") + +```javascript +//1. unit under test +describe('Products Service', function() { + describe('Add new product', function() { + //2. scenario and 3. expectation + it('When no price is specified, then the product status is pending approval', ()=> { + const newProduct = new ProductService().add(...); + expect(newProduct.status).to.equal('pendingApproval'); + }); + }); +}); + +``` + +
    + +### :clap: Doing It Right Example: A test name that constitutes 3 parts + +![alt text](/assets/bp-1-3-parts.jpeg "A test name that constitutes 3 parts") + +
    + +
    +
    © Credits & read-more + 1. Roy Osherove - Naming standards for unit tests +
    + +

    + +## ⚪ ️ 1.2 Structure tests by the AAA pattern + +: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: + +1st 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/stubbing on objects and any other preparation code + +2nd A - Act: Execute the unit under test. Usually 1 line of code + +3rd A - Assert: Ensure that the received value satisfies the expectation. Usually 1 line of code + +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: A test structured with the AAA pattern + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +describe("Customer classifier", () => { + test("When customer spent more than 500$, should be classified as premium", () => { + //Arrange + const customerToClassify = { spent: 505, joined: new Date(), id: 1 }; + const DBStub = sinon.stub(dataAccess, "getCustomer").reply({ id: 1, classification: "regular" }); + + //Act + const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); + + //Assert + expect(receivedClassification).toMatch("premium"); + }); +}); +``` + +
    + +### :thumbsdown: Anti-Pattern Example: No separation, one bulk, harder to interpret + +```javascript +test("Should be classified as premium", () => { + const customerToClassify = { spent: 505, joined: new Date(), id: 1 }; + const DBStub = sinon.stub(dataAccess, "getCustomer").reply({ id: 1, classification: "regular" }); + const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); + expect(receivedClassification).toMatch("premium"); +}); +``` + +
    + +

    + +## ⚪ ️1.3 Describe expectations in a product language: use BDD-style assertions + +: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://jestjs.io/docs/en/expect#expectextendmatchers) or writing a [custom Chai plugin](https://www.chaijs.com/guide/plugins/) +
    + +❌ **Otherwise:** The team will write less tests and decorate the annoying ones with .skip() + +
    + +
    Code Examples
    + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +### :thumbsdown: Anti-Pattern Example: The reader must skim through not so short, and imperative code just to get the test story + +```javascript +test("When asking for an admin, ensure only ordered admins in results", () => { + //assuming we've added here two admins "admin1", "admin2" and "user1" + const allAdmins = getUsers({ adminOnly: true }); + + let admin1Found, + adming2Found = false; + + allAdmins.forEach(aSingleUser => { + if (aSingleUser === "user1") { + assert.notEqual(aSingleUser, "user1", "A user was found and not admin"); + } + if (aSingleUser === "admin1") { + admin1Found = true; + } + if (aSingleUser === "admin2") { + admin2Found = true; + } + }); + + if (!admin1Found || !admin2Found) { + throw new Error("Not all admins were returned"); + } +}); +``` + +
    + +### :clap: Doing It Right Example: Skimming through the following declarative test is a breeze + +```javascript +it("When asking for an admin, ensure only ordered admins in results", () => { + //assuming we've added here two admins + const allAdmins = getUsers({ adminOnly: true }); + + expect(allAdmins) + .to.include.ordered.members(["admin1", "admin2"]) + .but.not.include.ordered.members(["user1"]); +}); +``` + +
    + +

    + +## ⚪ ️ 1.4 Stick to black-box testing: Test only public methods + +:white_check_mark: **Do:** Testing the internals brings huge overhead for almost nothing. If your code/API 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 +
    + +❌ **Otherwise:** Your tests behave like the [boy who cried wolf](https://en.wikipedia.org/wiki/The_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… + +
    +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: A test case is testing the internals for no good reason + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") + +```javascript +class ProductService { + //this method is only used internally + //Change this name will make the tests fail + calculateVATAdd(priceWithoutVAT) { + return { finalPrice: priceWithoutVAT * 1.2 }; + //Change the result format or key name above will make the tests fail + } + //public method + getPrice(productId) { + const desiredProduct = DB.getProduct(productId); + finalPrice = this.calculateVATAdd(desiredProduct.price).finalPrice; + return finalPrice; + } +} + +it("White-box test: When the internal methods get 0 vat, it return 0 response", async () => { + //There'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 + expect(new ProductService().calculateVATAdd(0).finalPrice).to.equal(0); +}); +``` + +
    + +

    + +## ⚪ ️ ️1.5 Choose the right test doubles: Avoid mocks in favor of stubs and spies + +:white_check_mark: **Do:** Test doubles are a necessary evil because they are coupled to the application internals, yet some provide immense value (
    [Read here a reminder about test doubles: mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)). + +Before 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 no, it’s a white-box testing smell. + +For 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/response/outcome 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 +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-pattern example: Mocks focus on the internals + +![](https://img.shields.io/badge/🔧%20Example%20using%20Sinon-blue.svg "Examples with Sinon") + +```javascript +it("When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config", async () => { + //Assume we already added a product + const dataAccessMock = sinon.mock(DAL); + //hmmm BAD: testing the internals is actually our main goal here, not just a side-effect + dataAccessMock + .expects("deleteProduct") + .once() + .withArgs(DBConfig, theProductWeJustAdded, true, false); + new ProductService().deletePrice(theProductWeJustAdded); + dataAccessMock.verify(); +}); +``` + +
    + +### :clap:Doing It Right Example: spies are focused on testing the requirements but as a side-effect are unavoidably touching to the internals + +```javascript +it("When a valid product is about to be deleted, ensure an email is sent", async () => { + //Assume we already added here a product + const spy = sinon.spy(Emailer.prototype, "sendEmail"); + new ProductService().deletePrice(theProductWeJustAdded); + //hmmm OK: we deal with internals? Yes, but as a side effect of testing the requirements (sending an email) + expect(spy.calledOnce).to.be.true; +}); +``` + +
    + +

    + +## 📗 Want to learn all these practices with live video? + +### Visit my online course [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) + +

    + +## ⚪ ️1.6 Don’t “foo”, use realistic input data + +: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 [Faker](https://www.npmjs.com/package/faker) 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 card, 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). +
    + +❌ **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” + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: A test suite that passes due to non-realistic data + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +const addProduct = (name, price) => { + const productNameRegexNoSpace = /^\S*$/; //no white-space allowed + + if (!productNameRegexNoSpace.test(name)) return false; //this path never reached due to dull input + + //some logic here + return true; +}; + +test("Wrong: When adding new product with valid properties, get successful confirmation", async () => { + //The string "Foo" which is used in all tests never triggers a false result + const addProductResult = addProduct("Foo", 5); + expect(addProductResult).toBe(true); + //Positive-false: the operation succeeded because we never tried with long + //product name including spaces +}); +``` + +
    + +### :clap:Doing It Right Example: Randomizing realistic input + +```javascript +it("Better: When adding new valid product, get successful confirmation", async () => { + const addProductResult = addProduct(faker.commerce.productName(), faker.random.number()); + //Generated random input: {'Sleek Cotton Computer', 85481} + expect(addProductResult).to.be.true; + //Test failed, the random input triggered some path we never planned for. + //We discovered a bug early! +}); +``` + +
    + +

    + +## ⚪ ️ 1.7 Test many input combinations using Property-based testing + +: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://github.com/goldbergyoni/javascript-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://en.wikipedia.org/wiki/Fuzzing)). 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: by 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://github.com/jsverify/jsverify) or [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https://github.com/dubzzz/fast-check#readme) which seems to offer some additional features and also to be actively maintained +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Testing many input permutations with “fast-check” + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +import fc from "fast-check"; + +describe("Product service", () => { + describe("Adding new", () => { + //this will run 100 times with different random properties + it("Add new product with random yet valid properties, always successful", () => + fc.assert( + fc.property(fc.integer(), fc.string(), (id, name) => { + expect(addNewProduct(id, name).status).toEqual("approved"); + }) + )); + }); +}); +``` + +
    + +

    + +## ⚪ ️ 1.8 If needed, use only short & inline snapshots + +:white_check_mark: **Do:** When there is a need for [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), use only short and focused snapshots (i.e. 3-7 lines) that are included as part of the test ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)) and not within external files. Keeping this guideline will ensure your tests remain self-explanatory and less fragile. + +On the other hand, ‘classic snapshots’ tutorials and tools encourage to store big files (e.g. component rendering markup, API JSON result) over some external medium and ensure each time when the test run 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/HTML 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 to 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 + +It’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 +
    + +❌ **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 origin document to current received one - a single space character was added to the markdown... + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: Coupling our test to unseen 2000 lines of code + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +it("TestJavaScript.com is renderd correctly", () => { + //Arrange + + //Act + const receivedPage = renderer + .create( Test JavaScript ) + .toJSON(); + + //Assert + expect(receivedPage).toMatchSnapshot(); + //We now implicitly maintain a 2000 lines long document + //every additional line break or comment - will break this test +}); +``` + +
    + +### :clap: Doing It Right Example: Expectations are visible and focused + +```javascript +it("When visiting TestJavaScript.com home page, a menu is displayed", () => { + //Arrange + + //Act + const receivedPage = renderer + .create( Test JavaScript ) + .toJSON(); + + //Assert + + const menu = receivedPage.content.menu; + expect(menu).toMatchInlineSnapshot(` +
      +
    • Home
    • +
    • About
    • +
    • Contact
    • +
    +`); +}); +``` + +
    + +

    + +## ⚪ ️1.9 Avoid global test fixtures and seeds, add data per-test + +: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’](https://en.wikipedia.org/wiki/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) +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: tests are not independent and rely on some global hook to feed global DB data + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +before(async () => { + //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework + await DB.AddSeedDataFromJson('seed.json'); +}); +it("When updating site name, get successful confirmation", async () => { + //I know that site name "portal" exists - I saw it in the seed files + const siteToUpdate = await SiteService.getSiteByName("Portal"); + const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); + expect(updateNameResult).to.be(true); +}); +it("When querying by site name, get the right site", async () => { + //I know that site name "portal" exists - I saw it in the seed files + const siteToCheck = await SiteService.getSiteByName("Portal"); + expect(siteToCheck.name).to.be.equal("Portal"); //Failure! The previous test change the name :[ +}); + +``` + +
    + +### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data + +```javascript +it("When updating site name, get successful confirmation", async () => { + //test is adding a fresh new records and acting on the records only + const siteUnderTest = await SiteService.addSite({ + name: "siteForUpdateTest" + }); + + const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); + + expect(updateNameResult).to.be(true); +}); +``` + +
    + +
    + +## ⚪ ️ 1.10 Don’t catch errors, expect them + +: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 + +A 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 +
    + +❌ **Otherwise:** It will be challenging to infer from the test reports (e.g. CI reports) what went wrong + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-pattern Example: A long test case that tries to assert the existence of error with try-catch + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +it("When no product name, it throws error 400", async () => { + let errorWeExceptFor = null; + try { + const result = await addNewProduct({}); + } catch (error) { + expect(error.code).to.equal("InvalidInput"); + errorWeExceptFor = error; + } + expect(errorWeExceptFor).not.to.be.null; + //if this assertion fails, the tests results/reports will only show + //that some value is null, there won't be a word about a missing Exception +}); +``` + +
    + +### :clap: Doing It Right Example: A human-readable expectation that could be understood easily, maybe even by QA or technical PM + +```javascript +it("When no product name, it throws error 400", async () => { + await expect(addNewProduct({})) + .to.eventually.throw(AppError) + .with.property("code", "InvalidInput"); +}); +``` + +
    + +

    + +## ⚪ ️ 1.11 Tag your tests + +: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’ +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :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) + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +//this test is fast (no DB) and we're tagging it correspondigly +//now the user/CI can run it frequently +describe("Order service", function() { + describe("Add new order #cold-test #sanity", function() { + test("Scenario - no currency was supplied. Expectation - Use the default currency #sanity", function() { + //code logic here + }); + }); +}); +``` + +
    + +

    + +## ⚪ ️ 1.12 Categorize tests under at least 2 levels + +: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 additional level of categorization like the scenario or custom categories (see code examples and print screen below). Doing so will also greatly improve the test reports: The reader will easily infer the tests 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 test suite that you may consider like [given-when-then](https://github.com/searls/jasmine-given) and [RITE](https://github.com/ericelliott/riteway) + +
    + +❌ **Otherwise:** When looking at a report with flat and long list of tests, the reader have to skim-read through long texts to conclude the major scenarios and correlate the commonality of failing tests. Consider the following case: When 7/100 tests fail, looking at a flat list will demand reading the failing tests text 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 + +
    + +
    Code Examples + +
    + +### :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 + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +// Unit under test +describe("Transfer service", () => { + //Scenario + describe("When no credit", () => { + //Expectation + test("Then the response status should decline", () => {}); + + //Expectation + test("Then it should send email to admin", () => {}); + }); +}); +``` + +![alt text](assets/hierarchical-report.png) + +
    + +### :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 + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Mocha") + +```javascript +test("Then the response status should decline", () => {}); + +test("Then it should send email", () => {}); + +test("Then there should not be a new transfer record", () => {}); +``` + +![alt text](assets/flat-report.png) + +
    + +
    + +

    + +## ⚪ ️1.13 Other generic good testing hygiene + +: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 few non-Node related tips that are well-known + +Learn and practice [TDD principles](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) — 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://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.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, 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) +
    + +❌ **Otherwise:** You‘ll miss pearls of wisdom that were collected for decades + +

    + +# Section 2️⃣: Backend Testing + +## ⚪ ️2.1 Enrich your testing portfolio: Look beyond unit tests and the pyramid + +:white_check_mark: **Do:** The [testing pyramid](https://martinfowler.com/bliki/TestPyramid.html), though 10> years old, is a great and relevant model that suggests three testing types and influences most developers’ testing strategy. 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? + +Don’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://en.wikipedia.org/wiki/All_models_are_wrong). For example, consider an IoT application that ingests many events into a message-bus like Kafka/RabbitMQ, 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 increase (bots, crypto, Alexa-skills) greater are the chances to find scenarios where the testing pyramid is not the best match. + +It’s time to enrich your testing portfolio and become familiar with more testing types (the next bullets suggest 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 build a portfolio based on risk analysis — assess where problems might arise and match some prevention measures to mitigate those potential risks + +A word of caution: the TDD argument in the software world takes a typical false-dichotomy face, some preach to use it everywhere, others think it’s the devil. Everyone who speaks in absolutes is wrong :] + +
    + +❌ **Otherwise:** You’re going to miss some tools with amazing ROI, some like Fuzz, lint, and mutation can provide value in 10 minutes + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the same way’ + +![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") + +☺️Example: [YouTube: “Beyond Unit Tests: 5 Shiny Node.JS Test Types (2018)” (Yoni Goldberg)](https://www.youtube.com/watch?v=-2zP494wdUY&feature=youtu.be) + +
    + +![alt text](assets/bp-12-Yoni-Goldberg-Testing.jpeg "A test name that constitutes 3 parts") + +
    + +

    + +## ⚪ ️2.2 Component testing might be your best affair + +: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 from both worlds: reasonable performance and a possibility to apply TDD patterns + realistic and great coverage. + +Component tests focus on the Microservice ‘unit’, they work against the API, 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 outwards to inwards and gain great confidence in a reasonable amount of time. +
    + +❌ **Otherwise:** You may spend long days on writing unit tests to find out that you got only 20% system coverage + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Supertest allows approaching Express API in-process (fast and cover many layers) + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +![alt text](assets/bp-13-component-test-yoni-goldberg.png " [Supertest](https://www.npmjs.com/package/supertest) allows approaching Express API in-process (fast and cover many layers)") + +
    + +

    + +## ⚪ ️2.3 Ensure new releases don’t break the API using contract tests + +: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. [Consumer-driven contracts and the framework PACT](https://docs.pact.io/) were born to formalize this process with a very disruptive approach — not the server defines the test plan of itself rather the client defines the tests of the… server! PACT can record the client expectation and put in a shared location, “broker”, so the server can pull the expectations and run on every build using 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/CI and might save you a great deal of frustration +
    + +❌ **Otherwise:** The alternatives are exhausting manual testing or deployment fear + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: + +![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") + +![alt text](assets/bp-14-testing-best-practices-contract-flow.png) + +
    + +

    + +## ⚪ ️ 2.4 Test your middlewares in isolation + +: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://www.npmjs.com/package/sinon)) on the interaction with the {req,res} objects to ensure the function performed the right action. The library [node-mock-http](https://www.npmjs.com/package/node-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) +
    + +❌ **Otherwise:** A bug in Express middleware === a bug in all or most requests + +
    + +
    Code Examples + +
    + +### :clap:Doing It Right Example: Testing middleware in isolation without issuing network calls and waking-up the entire Express machine + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +//the middleware we want to test +const unitUnderTest = require("./middleware"); +const httpMocks = require("node-mocks-http"); +//Jest syntax, equivelant to describe() & it() in Mocha +test("A request without authentication header, should return http status 403", () => { + const request = httpMocks.createRequest({ + method: "GET", + url: "/user/42", + headers: { + authentication: "" + } + }); + const response = httpMocks.createResponse(); + unitUnderTest(request, response); + expect(response.statusCode).toBe(403); +}); +``` + +
    + +

    + +## ⚪ ️2.5 Measure and refactor using static analysis tools + +: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://www.sonarqube.org/) (4,900+ [stars](https://github.com/SonarSource/sonarqube)) and [Code Climate](https://codeclimate.com/) (2,000+ [stars](https://github.com/codeclimate/codeclimate)) + +Credit:
    [Keith Holliday](https://github.com/TheHollidayInn) + +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: CodeClimate, a commercial tool that can identify complex methods: + +![](https://img.shields.io/badge/🔧%20Example%20using%20Code%20Climate-blue.svg "Examples with CodeClimate") + +![alt text](assets/bp-16-yoni-goldberg-quality.png "CodeClimate, a commercial tool that can identify complex methods:") + +
    + +

    + +## ⚪ ️ 2.6 Check your readiness for Node-related chaos + +: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/process 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://principlesofchaos.org/) 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://github.com/Netflix/chaosmonkey), 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://github.com/asobti/kube-monkey), that kills pods). All these tools work on the hosting/platform 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://github.com/i0natan/node-chaos-monkey) (alpha) which provides all sort of Node-related chaotic acts +
    + +❌ **Otherwise:** No escape here, Murphy’s law will hit your production without mercy + +
    + +
    Code Examples + +
    + +### :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 + +![alt text](assets/bp-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") + +
    + +
    + +## ⚪ ️2.7 Avoid global test fixtures and seeds, add data per-test + +: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) +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: tests are not independent and rely on some global hook to feed global DB data + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +before(async () => { + //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework + await DB.AddSeedDataFromJson('seed.json'); +}); +it("When updating site name, get successful confirmation", async () => { + //I know that site name "portal" exists - I saw it in the seed files + const siteToUpdate = await SiteService.getSiteByName("Portal"); + const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); + expect(updateNameResult).to.be(true); +}); +it("When querying by site name, get the right site", async () => { + //I know that site name "portal" exists - I saw it in the seed files + const siteToCheck = await SiteService.getSiteByName("Portal"); + expect(siteToCheck.name).to.be.equal("Portal"); //Failure! The previous test change the name :[ +}); + +``` + +
    + +### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data + +```javascript +it("When updating site name, get successful confirmation", async () => { + //test is adding a fresh new records and acting on the records only + const siteUnderTest = await SiteService.addSite({ + name: "siteForUpdateTest" + }); + const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); + expect(updateNameResult).to.be(true); +}); +``` + +
    + +

    + +# Section 3️⃣: Frontend Testing + +## ⚪ ️ 3.1 Separate UI from functionality + +: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/CSS 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 + +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Separating out the UI details + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +test("When users-list is flagged to show only VIP, should display only VIP members", () => { + // Arrange + const allUsers = [{ id: 1, name: "Yoni Goldberg", vip: false }, { id: 2, name: "John Doe", vip: true }]; + + // Act + const { getAllByTestId } = render(); + + // Assert - Extract the data from the UI first + const allRenderedUsers = getAllByTestId("user").map(uiElement => uiElement.textContent); + const allRealVIPUsers = allUsers.filter(user => user.vip).map(user => user.name); + expect(allRenderedUsers).toEqual(allRealVIPUsers); //compare data with data, no UI here +}); +``` + +
    + +### :thumbsdown: Anti-Pattern Example: Assertion mix UI details and data + +```javascript +test("When flagging to show only VIP, should display only VIP members", () => { + // Arrange + const allUsers = [{ id: 1, name: "Yoni Goldberg", vip: false }, { id: 2, name: "John Doe", vip: true }]; + + // Act + const { getAllByTestId } = render(); + + // Assert - Mix UI & data in assertion + expect(getAllByTestId("user")).toEqual('[
  • John Doe
  • ]'); +}); +``` + +
    + +

    + +## ⚪ ️ 3.2 Query HTML elements based on attributes that are unlikely to change + +: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/logic 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 + +
    + +❌ **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' + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Querying an element using a dedicated attribute for testing + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") + +```html +// the markup code (part of React component) +

    + + {value} + + +

    +``` + +```javascript +// this example is using react-testing-library +test("Whenever no data is passed to metric, show 0 as default", () => { + // Arrange + const metricValue = undefined; + + // Act + const { getByTestId } = render(); + + expect(getByTestId("errorsLabel").text()).toBe("0"); +}); +``` + +
    + +### :thumbsdown: Anti-Pattern Example: Relying on CSS attributes + +```html + +{value} + +``` + +```javascript +// this exammple is using enzyme +test("Whenever no data is passed, error metric shows zero", () => { + // ... + + expect(wrapper.find("[className='d-flex-column']").text()).toBe("0"); +}); +``` + +
    + +
    + +## ⚪ ️ 3.3 Whenever possible, test with a realistic and fully rendered component + +: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://github.com/goldbergyoni/javascript-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 + +With all that said, a word of caution is in order: this technique works for small/medium 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 + +
    + +❌ **Otherwise:** When poking into a component's internal by invoking its private methods, and checking the inner state - you would have to refactor all tests when refactoring the components implementation. Do you really have a capacity for this level of maintenance? + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Working realistically with a fully rendered component + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Enzyme-blue.svg "Examples with Enzyme") + +```javascript +class Calendar extends React.Component { + static defaultProps = { showFilters: false }; + + render() { + return ( +
    + A filters panel with a button to hide/show filters + +
    + ); + } +} + +//Examples use React & Enzyme +test("Realistic approach: When clicked to show filters, filters are displayed", () => { + // Arrange + const wrapper = mount(); + + // Act + wrapper.find("button").simulate("click"); + + // Assert + expect(wrapper.text().includes("Choose Filter")); + // This is how the user will approach this element: by text +}); +``` + +### :thumbsdown: Anti-Pattern Example: Mocking the reality with shallow rendering + +```javascript +test("Shallow/mocked approach: When clicked to show filters, filters are displayed", () => { + // Arrange + const wrapper = shallow(); + + // Act + wrapper + .find("filtersPanel") + .instance() + .showFilters(); + // Tap into the internals, bypass the UI and invoke a method. White-box approach + + // Assert + expect(wrapper.find("Filter").props()).toEqual({ title: "Choose Filter" }); + // what if we change the prop name or don't pass anything relevant? +}); +``` + +
    + +
    + +## ⚪ ️ 3.4 Don't sleep, use frameworks built-in support for async events. Also try to speed things up + +:white_check_mark: **Do:** In many cases, the unit under test completion time is just unknown (e.g. animation suspends element appearance) - in that case, avoid sleeping (e.g. setTimeOut) and prefer more deterministic methods that most platforms provide. Some libraries allows awaiting on operations (e.g. [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), other provide API for waiting like [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). Sometimes a more elegant way is to stub the slow resource, like API for example, and then once the response moment becomes deterministic the component can be explicitly re-rendered. When depending upon some external component that sleeps, it might turn useful to [hurry-up the clock](https://jestjs.io/docs/en/timer-mocks). Sleeping is a pattern to avoid because it forces your test to be slow or risky (when waiting for a too short period). Whenever sleeping and polling is inevitable and there's no support from the testing framework, some npm libraries like [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) can help with a semi-deterministic solution +
    + +❌ **Otherwise:** When sleeping for a long time, tests will be an order of magnitude slower. When trying to sleep for small numbers, test will fail when the unit under test didn't respond in a timely fashion. So it boils down to a trade-off between flakiness and bad performance + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: E2E API that resolves only when the async operations is done (Cypress) + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") +![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +// using Cypress +cy.get("#show-products").click(); // navigate +cy.wait("@products"); // wait for route to appear +// this line will get executed only when the route is ready +``` + +### :clap: Doing It Right Example: Testing library that waits for DOM elements + +```javascript +// @testing-library/dom +test("movie title appears", async () => { + // element is initially not present... + + // wait for appearance + await wait(() => { + expect(getByText("the lion king")).toBeInTheDocument(); + }); + + // wait for appearance and return the element + const movie = await waitForElement(() => getByText("the lion king")); +}); +``` + +### :thumbsdown: Anti-Pattern Example: custom sleep code + +```javascript +test("movie title appears", async () => { + // element is initially not present... + + // custom wait logic (caution: simplistic, no timeout) + const interval = setInterval(() => { + const found = getByText("the lion king"); + if (found) { + clearInterval(interval); + expect(getByText("the lion king")).toBeInTheDocument(); + } + }, 100); + + // wait for appearance and return the element + const movie = await waitForElement(() => getByText("the lion king")); +}); +``` + +
    + +
    + +## ⚪ ️ 3.5 Watch how the content is served over the network + +![](https://img.shields.io/badge/🔧%20Example%20using%20Google%20LightHouse-blue.svg "Examples with Lighthouse") + +✅ **Do:** Apply some active monitor that ensures the page load under real network is optimized - this includes any UX concern like slow page load or un-minified bundle. The inspection tools market is no short: basic tools like [pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) can be easily configured to watch whether the server is alive and response under a reasonable SLA. This only scratches the surface of what might get wrong, hence it's preferable to opt for tools that specialize in frontend (e.g. [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) and perform richer analysis. The focus should be on symptoms, metrics that directly affect the UX, like page load time, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [time until the page gets interactive (TTI)](https://calibreapp.com/blog/time-to-interactive/). On top of that, one may also watch for technical causes like ensuring the content is compressed, time to the first byte, optimize images, ensuring reasonable DOM size, SSL and many others. It's advisable to have these rich monitors both during development, as part of the CI and most important - 24x7 over the production's servers/CDN + +
    + +❌ **Otherwise:** It must be disappointing to realize that after such great care for crafting a UI, 100% functional tests passing and sophisticated bundling - the UX is horrible and slow due to CDN misconfiguration + +
    + +
    Code Examples + +### :clap: Doing It Right Example: Lighthouse page load inspection report + +![](/assets/lighthouse2.png "Lighthouse page load inspection report") + +
    + +
    + +## ⚪ ️ 3.6 Stub flaky and slow resources like backend APIs + +:white_check_mark: **Do:** When coding your mainstream tests (not E2E tests), avoid involving any resource that is beyond your responsibility and control like backend API and use stubs instead (i.e. test double). Practically, instead of real network calls to APIs, use some test double library (like [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble), etc) for stubbing the API response. The main benefit is preventing flakiness - testing or staging APIs by definition are not highly stable and from time to time will fail your tests although YOUR component behaves just fine (production env was not meant for testing and it usually throttles requests). Doing this will allow simulating various API behavior that should drive your component behavior as when no data was found or the case when API throws an error. Last but not least, network calls will greatly slow down the tests + +
    + +❌ **Otherwise:** The average test runs no longer than few ms, a typical API call last 100ms>, this makes each test ~20x slower + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Stubbing or intercepting API calls + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +// unit under test +export default function ProductsList() { + const [products, setProducts] = useState(false); + + const fetchProducts = async () => { + const products = await axios.get("api/products"); + setProducts(products); + }; + + useEffect(() => { + fetchProducts(); + }, []); + + return products ?
    {products}
    :
    No products
    ; +} + +// test +test("When no products exist, show the appropriate message", () => { + // Arrange + nock("api") + .get(`/products`) + .reply(404); + + // Act + const { getByTestId } = render(); + + // Assert + expect(getByTestId("no-products-message")).toBeTruthy(); +}); +``` + +
    + +
    + +## ⚪ ️ 3.7 Have very few end-to-end tests that spans the whole system + +:white_check_mark: **Do:** Although E2E (end-to-end) usually means UI-only testing with a real browser (See [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)), for other they mean tests that stretch the entire system including the real backend. The latter type of tests is highly valuable as they cover integration bugs between frontend and backend that might happen due to a wrong understanding of the exchange schema. They are also an efficient method to discover backend-to-backend integration issues (e.g. Microservice A sends the wrong message to Microservice B) and even to detect deployment failures - there are no backend frameworks for E2E testing that are as friendly and mature as UI frameworks like [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). The downside of such tests is the high cost of configuring an environment with so many components, and mostly their brittleness - given 50 microservices, even if one fails then the entire E2E just failed. For that reason, we should use this technique sparingly and probably have 1-10 of those and no more. That said, even a small number of E2E tests are likely to catch the type of issues they are targeted for - deployment & integration faults. It's advisable to run those over a production-like staging environment + +
    + +❌ **Otherwise:** UI might invest much in testing its functionality only to realizes very late that the backend returned payload (the data schema the UI has to work with) is very different than expected + +
    + +## ⚪ ️ 3.8 Speed-up E2E tests by reusing login credentials + +:white_check_mark: **Do:** In E2E tests that involve a real backend and rely on a valid user token for API calls, it doesn't payoff to isolate the test to a level where a user is created and logged-in in every request. Instead, login only once before the tests execution start (i.e. before-all hook), save the token in some local storage and reuse it across requests. This seem to violate one of the core testing principle - keep the test autonomous without resources coupling. While this is a valid worry, in E2E tests performance is a key concern and creating 1-3 API requests before starting each individual tests might lead to horrible execution time. Reusing credentials doesn't mean the tests have to act on the same user records - if relying on user records (e.g. test user payments history) than make sure to generate those records as part of the test and avoid sharing their existence with other tests. Also remember that the backend can be faked - if your tests are focused on the frontend it might be better to isolate it and stub the backend API (see [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)). + +
    + +❌ **Otherwise:** Given 200 test cases and assuming login=100ms = 20 seconds only for logging-in again and again + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Logging-in before-all and not before-each + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +let authenticationToken; + +// happens before ALL tests run +before(() => { + cy.request('POST', 'http://localhost:3000/login', { + username: Cypress.env('username'), + password: Cypress.env('password'), + }) + .its('body') + .then((responseFromLogin) => { + authenticationToken = responseFromLogin.token; + }) +}) + +// happens before EACH test +beforeEach(setUser => () { + cy.visit('/home', { + onBeforeLoad (win) { + win.localStorage.setItem('token', JSON.stringify(authenticationToken)) + }, + }) +}) + +``` + +
    + +
    + +## ⚪ ️ 3.9 Have one E2E smoke test that just travels across the site map + +:white_check_mark: **Do:** For production monitoring and development-time sanity check, run a single E2E test that visits all/most of the site pages and ensures no one breaks. This type of test brings a great return on investment as it's very easy to write and maintain, but it can detect any kind of failure including functional, network and deployment issues. Other styles of smoke and sanity checking are not as reliable and exhaustive - some ops teams just ping the home page (production) or developers who run many integration tests which don't discover packaging and browser issues. Goes without saying that the smoke test doesn't replace functional tests rather just aim to serve as a quick smoke detector + +
    + +❌ **Otherwise:** Everything might seem perfect, all tests pass, production health-check is also positive but the Payment component had some packaging issue and only the /Payment route is not rendering + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Smoke travelling across all pages + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +it("When doing smoke testing over all page, should load them all successfully", () => { + // exemplified using Cypress but can be implemented easily + // using any E2E suite + cy.visit("https://mysite.com/home"); + cy.contains("Home"); + cy.contains("https://mysite.com/Login"); + cy.contains("Login"); + cy.contains("https://mysite.com/About"); + cy.contains("About"); +}); +``` + +
    + +
    + +## ⚪ ️ 3.10 Expose the tests as a live collaborative document + +:white_check_mark: **Do:** Besides increasing app reliability, tests bring another attractive opportunity to the table - serve as live app documentation. Since tests inherently speak at a less-technical and product/UX language, using the right tools they can serve as a communication artifact that greatly aligns all the peers - developers and their customers. For example, some frameworks allow expressing the flow and expectations (i.e. tests plan) using a human-readable language so any stakeholder, including product managers, can read, approve and collaborate on the tests which just became the live requirements document. This technique is also being referred to as 'acceptance test' as it allows the customer to define his acceptance criteria in plain language. This is [BDD (behavior-driven testing)](https://en.wikipedia.org/wiki/Behavior-driven_development) at its purest form. One of the popular frameworks that enable this is [Cucumber which has a JavaScript flavor](https://github.com/cucumber/cucumber-js), see example below. Another similar yet different opportunity, [StoryBook](https://storybook.js.org/), allows exposing UI components as a graphic catalog where one can walk through the various states of each component (e.g. render a grid w/o filters, render that grid with multiple rows or with none, etc), see how it looks like, and how to trigger that state - this can appeal also to product folks but mostly serves as live doc for developers who consume those components. + +❌ **Otherwise:** After investing top resources on testing, it's just a pity not to leverage this investment and win great value + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Describing tests in human-language using cucumber-js + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Examples using Cucumber") + +```javascript +// this is how one can describe tests using cucumber: plain language that allows anyone to understand and collaborate + +Feature: Twitter new tweet + + I want to tweet something in Twitter + + @focus + Scenario: Tweeting from the home page + Given I open Twitter home + Given I click on "New tweet" button + Given I type "Hello followers!" in the textbox + Given I click on "Submit" button + Then I see message "Tweet saved" + +``` + +### :clap: Doing It Right Example: Visualizing our components, their various states and inputs using Storybook + +![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") + +![alt text](assets/story-book.jpg "Storybook") + +
    + +

    + +## ⚪ ️ 3.11 Detect visual issues with automated tools + +:white_check_mark: **Do:** Setup automated tools to capture UI screenshots when changes are presented and detect visual issues like content overlapping or breaking. This ensures that not only the right data is prepared but also the user can conveniently see it. This technique is not widely adopted, our testing mindset leans toward functional tests but it's the visuals what the user experience and with so many device types it's very easy to overlook some nasty UI bug. Some free tools can provide the basics - generate and save screenshots for the inspection of human eyes. While this approach might be sufficient for small apps, it's flawed as any other manual testing that demands human labor anytime something changes. On the other hand, it's quite challenging to detect UI issues automatically due to the lack of clear definition - this is where the field of 'Visual Regression' chime in and solve this puzzle by comparing old UI with the latest changes and detect differences. Some OSS/free tools can provide some of this functionality (e.g. [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>) but might charge significant setup time. The commercial line of tools (e.g. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) takes is a step further by smoothing the installation and packing advanced features like management UI, alerting, smart capturing by eliminating 'visual noise' (e.g. ads, animations) and even root cause analysis of the DOM/CSS changes that led to the issue + +
    + +❌ **Otherwise:** How good is a content page that display great content (100% tests passed), loads instantly but half of the content area is hidden? + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: A typical visual regression - right content that is served badly + +![alt text](assets/amazon-visual-regression.jpeg "Amazon page breaks") + +
    + +### :clap: Doing It Right Example: Configuring wraith to capture and compare UI snapshots + +![](https://img.shields.io/badge/🔨%20Example%20using%20Wraith-blue.svg "Using Wraith") + +``` +​# Add as many domains as necessary. Key will act as a label​ + +domains: + english: "http://www.mysite.com"​ + +​# Type screen widths below, here are a couple of examples​ + +screen_widths: + + - 600​ + - 768​ + - 1024​ + - 1280​ + +​# Type page URL paths below, here are a couple of examples​ +paths: + about: + path: /about + selector: '.about'​ + subscribe: + selector: '.subscribe'​ + path: /subscribe +``` + +### :clap: Doing It Right Example: Using Applitools to get snapshot comparison and other advanced features + +![](https://img.shields.io/badge/🔨%20Example%20using%20AppliTools-blue.svg "Using Applitools") ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +import * as todoPage from "../page-objects/todo-page"; + +describe("visual validation", () => { + before(() => todoPage.navigate()); + beforeEach(() => cy.eyesOpen({ appName: "TAU TodoMVC" })); + afterEach(() => cy.eyesClose()); + + it("should look good", () => { + cy.eyesCheckWindow("empty todo list"); + todoPage.addTodo("Clean room"); + todoPage.addTodo("Learn javascript"); + cy.eyesCheckWindow("two todos"); + todoPage.toggleTodo(0); + cy.eyesCheckWindow("mark as completed"); + }); +}); +``` + +
    + +

    + +# Section 4️⃣: Measuring Test Effectiveness + +

    + +## ⚪ ️ 4.1 Get enough coverage for being confident, ~80% seems to be the lucky number + +:white_check_mark: **Do:** The purpose of testing is to get enough confidence for moving fast, obviously the more code is tested the more confident the team can be. Coverage is a measure of how many code lines (and branches, statements, etc) are being reached by the tests. So how much is enough? 10–30% is obviously too low to get any sense about the build correctness, on the other side 100% is very expensive and might shift your focus from the critical paths to the exotic corners of the code. The long answer is that it depends on many factors like the type of application — if you’re building the next generation of Airbus A380 than 100% is a must, for a cartoon pictures website 50% might be too much. Although most of the testing enthusiasts claim that the right coverage threshold is contextual, most of them also mention the number 80% as a thumb of a rule ([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)) that presumably should satisfy most of the applications. + +Implementation tips: You may want to configure your continuous integration (CI) to have a coverage threshold ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) and stop a build that doesn’t stand to this standard (it’s also possible to configure threshold per component, see code example below). On top of this, consider detecting build coverage decrease (when a newly committed code has less coverage) — this will push developers raising or at least preserving the amount of tested code. All that said, coverage is only one measure, a quantitative based one, that is not enough to tell the robustness of your testing. And it can also be fooled as illustrated in the next bullets + +
    + +❌ **Otherwise:** Confidence and numbers go hand in hand, without really knowing that you tested most of the system — there will also be some fear and fear will slow you down + +
    + +
    Code Examples + +
    + +### :clap: Example: A typical coverage report + +![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "A typical coverage report") + +
    + +### :clap: Doing It Right Example: Setting up coverage per component (using Jest) + +![](https://img.shields.io/badge/🔨%20Example%20using%20Jest-blue.svg "Using Jest") + +![alt text](assets/bp-18-code-coverage2.jpeg "Setting up coverage per component (using Jest)") + +
    + +

    + +## ⚪ ️ 4.2 Inspect coverage reports to detect untested areas and other oddities + +:white_check_mark: **Do:** Some issues sneak just under the radar and are really hard to find using traditional tools. These are not really bugs but more of surprising application behavior that might have a severe impact. For example, often some code areas are never or rarely being invoked — you thought that the ‘PricingCalculator’ class is always setting the product price but it turns out it is actually never invoked although we have 10000 products in DB and many sales… Code coverage reports help you realize whether the application behaves the way you believe it does. Other than that, it can also highlight which types of code is not tested — being informed that 80% of the code is tested doesn’t tell whether the critical parts are covered. Generating reports is easy — just run your app in production or during testing with coverage tracking and then see colorful reports that highlight how frequent each code area is invoked. If you take your time to glimpse into this data — you might find some gotchas +
    + +❌ **Otherwise:** If you don’t know which parts of your code are left un-tested, you don’t know where the issues might come from + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: What’s wrong with this coverage report? + +Based on a real-world scenario where we tracked our application usage in QA and find out interesting login patterns (Hint: the amount of login failures is non-proportional, something is clearly wrong. Finally it turned out that some frontend bug keeps hitting the backend login API) + +![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report?") + +
    + +

    + +## ⚪ ️ 4.3 Measure logical coverage using mutation testing + +:white_check_mark: **Do:** The Traditional Coverage metric often lies: It may show you 100% code coverage, but none of your functions, even not one, return the right response. How come? it simply measures over which lines of code the test visited, but it doesn’t check if the tests actually tested anything — asserted for the right response. Like someone who’s traveling for business and showing his passport stamps — this doesn’t prove any work done, only that he visited few airports and hotels. + +Mutation-based testing is here to help by measuring the amount of code that was actually TESTED not just VISITED. [Stryker](https://stryker-mutator.io/) is a JavaScript library for mutation testing and the implementation is really neat: + +(1) it intentionally changes the code and “plants bugs”. For example the code newOrder.price===0 becomes newOrder.price!=0. This “bugs” are called mutations + +(2) it runs the tests, if all succeed then we have a problem — the tests didn’t serve their purpose of discovering bugs, the mutations are so-called survived. If the tests failed, then great, the mutations were killed. + +Knowing that all or most of the mutations were killed gives much higher confidence than traditional coverage and the setup time is similar +
    + +❌ **Otherwise:** You’ll be fooled to believe that 85% coverage means your test will detect bugs in 85% of your code + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: 100% coverage, 0% testing + +![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Using Stryker") + +```javascript +function addNewOrder(newOrder) { + logger.log(`Adding new order ${newOrder}`); + DB.save(newOrder); + Mailer.sendMail(newOrder.assignee, `A new order was places ${newOrder}`); + + return { approved: true }; +} + +it("Test addNewOrder, don't use such test names", () => { + addNewOrder({ assignee: "John@mailer.com", price: 120 }); +}); //Triggers 100% code coverage, but it doesn't check anything +``` + +
    + +### :clap: Doing It Right Example: Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations) + +![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations)") + +
    + +

    + +## ⚪ ️4.4 Preventing test code issues with Test linters + +:white_check_mark: **Do:** A set of ESLint plugins were built specifically for inspecting the tests code patterns and discover issues. For example, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) will warn when a test is written at the global level (not a son of a describe() statement) or when tests are [skipped](https://mochajs.org/#inclusive-tests) which might lead to a false belief that all tests are passing. Similarly, [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) can, for example, warn when a test has no assertions at all (not checking anything) + +
    + +❌ **Otherwise:** Seeing 90% code coverage and 100% green tests will make your face wear a big smile only until you realize that many tests aren’t asserting for anything and many test suites were just skipped. Hopefully, you didn’t deploy anything based on this false observation + +
    +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: A test case full of errors, luckily all are caught by Linters + +```javascript +describe("Too short description", () => { + const userToken = userService.getDefaultToken() // *error:no-setup-in-describe, use hooks (sparingly) instead + it("Some description", () => {});//* error: valid-test-description. Must include the word "Should" + at least 5 words +}); + +it.skip("Test name", () => {// *error:no-skipped-tests, error:error:no-global-tests. Put tests only under describe or suite + expect("somevalue"); // error:no-assert +}); + +it("Test name", () => {*//error:no-identical-title. Assign unique titles to tests +}); +``` + +
    + +

    + +# Section 5️⃣: CI and Other Quality Measures + +

    + +## ⚪ ️ 5.1 Enrich your linters and abort builds that have linting issues + +:white_check_mark: **Do:** Linters are a free lunch, with 5 min setup you get for free an auto-pilot guarding your code and catching significant issue as you type. Gone are the days where linting was about cosmetics (no semi-colons!). Nowadays, Linters can catch severe issues like errors that are not thrown correctly and losing information. On top of your basic set of rules (like [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) or [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), consider including some specializing Linters like [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) that can discover tests without assertions, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) can discover promises with no resolve (your code will never continue), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) which can discover eager regex expressions that might get used for DOS attacks, and [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) is capable of alarming when the code uses utility library methods that are part of the V8 core methods like Lodash.\_map(…) +
    + +❌ **Otherwise:** Consider a rainy day where your production keeps crashing but the logs don’t display the error stack trace. What happened? Your code mistakenly threw a non-error object and the stack trace was lost, a good reason for banging your head against a brick wall. A 5 min linter setup could detect this TYPO and save your day + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug + +![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug") + +
    + +

    + +## ⚪ ️ 5.2 Shorten the feedback loop with local developer-CI + +:white_check_mark: **Do:** Using a CI with shiny quality inspections like testing, linting, vulnerabilities check, etc? Help developers run this pipeline also locally to solicit instant feedback and shorten the [feedback loop](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). Why? an efficient testing process constitutes many and iterative loops: (1) try-outs -> (2) feedback -> (3) refactor. The faster the feedback is, the more improvement iterations a developer can perform per-module and perfect the results. On the flip, when the feedback is late to come fewer improvement iterations could be packed into a single day, the team might already move forward to another topic/task/module and might not be up for refining that module. + +Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) allow running the pipeline locally. Some commercial tools like [wallaby provide highly-valuable & testing insights](https://wallabyjs.com/) as a developer prototype (no affiliation). Alternatively, you may just add npm script to package.json that runs all the quality commands (e.g. test, lint, vulnerabilities) — use tools like [concurrently](https://www.npmjs.com/package/concurrently) for parallelization and non-zero exit code if one of the tools failed. Now the developer should just invoke one command — e.g. ‘npm run quality’ — to get instant feedback. Consider also aborting a commit if the quality check failed using a githook ([husky can help](https://github.com/typicode/husky)) +
    + +❌ **Otherwise:** When the quality results arrive the day after the code, testing doesn’t become a fluent part of development rather an after the fact formal artifact + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: npm scripts that perform code quality inspection, all are run in parallel on demand or when a developer is trying to push new code + +```javascript +"scripts": { + "inspect:sanity-testing": "mocha **/**--test.js --grep \"sanity\"", + "inspect:lint": "eslint .", + "inspect:vulnerabilities": "npm audit", + "inspect:license": "license-checker --failOn GPLv2", + "inspect:complexity": "plato .", + + "inspect:all": "concurrently -c \"bgBlue.bold,bgMagenta.bold,yellow\" \"npm:inspect:quick-testing\" \"npm:inspect:lint\" \"npm:inspect:vulnerabilities\" \"npm:inspect:license\"" + }, + "husky": { + "hooks": { + "precommit": "npm run inspect:all", + "prepush": "npm run inspect:all" + } +} + +``` + +
    + +

    + +## ⚪ ️5.3 Perform e2e testing over a true production-mirror + +:white_check_mark: **Do:** End to end (e2e) testing are the main challenge of every CI pipeline — creating an identical ephemeral production mirror on the fly with all the related cloud services can be tedious and expensive. Finding the best compromise is your game: [Docker-compose](https://serverless.com/) allows crafting isolated dockerized environment with identical containers using a single plain text file but the backing technology (e.g. networking, deployment model) is different from real-world productions. You may combine it with [‘AWS Local’](https://github.com/localstack/localstack) to work with a stub of the real AWS services. If you went [serverless](https://serverless.com/) multiple frameworks like serverless and [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) allows the local invocation of FaaS code. + +The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for local and CI-mirroring though many new tools are launched frequently. One approach is running a ‘minimized-Kubernetes’ using tools like [Minikube](https://kubernetes.io/docs/setup/minikube/) and [MicroK8s](https://microk8s.io/) which resemble the real thing only come with less overhead. Another approach is testing over a remote ‘real-Kubernetes’, some CI providers (e.g. [Codefresh](https://codefresh.io/)) has native integration with Kubernetes environment and make it easy to run the CI pipeline over the real thing, others allow custom scripting against a remote Kubernetes. +
    + +❌ **Otherwise:** Using different technologies for production and testing demands maintaining two deployment models and keeps the developers and the ops team separated + +
    + +
    Code Examples + +
    + +### :clap: Example: a CI pipeline that generates Kubernetes cluster on the fly ([Credit: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/)) + +
    deploy:
    stage: deploy
    image: registry.gitlab.com/gitlab-examples/kubernetes-deploy
    script:
    - ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN
    - kubectl create ns $NAMESPACE
    - kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL"
    - mkdir .generated
    - echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF"
    - sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml"
    - kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml
    - kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml
    environment:
    name: test-for-ci
    + +
    + +

    + +## ⚪ ️5.4 Parallelize test execution + +:white_check_mark: **Do:** When done right, testing is your 24/7 friend providing almost instant feedback. In practice, executing 500 CPU-bounded unit test on a single thread can take too long. Luckily, modern test runners and CI platforms (like [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) and [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) can parallelize the test into multiple processes and achieve significant improvement in feedback time. Some CI vendors do also parallelize tests across containers (!) which shortens the feedback loop even further. Whether locally over multiple processes, or over some cloud CLI using multiple machines — parallelizing demand keeping the tests autonomous as each might run on different processes + +❌ **Otherwise:** Getting test results 1 hour long after pushing new code, as you already code the next features, is a great recipe for making testing less relevant + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) + +![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization (Credit: JavaScript Test-Runners Benchmark)") + +
    + +

    + +## ⚪ ️5.5 Stay away from legal issues using license and plagiarism check + +:white_check_mark: **Do:** Licensing and plagiarism issues are probably not your main concern right now, but why not tick this box as well in 10 minutes? A bunch of npm packages like [license check](https://www.npmjs.com/package/license-checker) and [plagiarism check](https://www.npmjs.com/package/plagiarism-checker) (commercial with free plan) can be easily baked into your CI pipeline and inspect for sorrows like dependencies with restrictive licenses or code that was copy-pasted from Stack Overflow and apparently violates some copyrights + +❌ **Otherwise:** Unintentionally, developers might use packages with inappropriate licenses or copy paste commercial code and run into legal issues + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: + +```javascript +//install license-checker in your CI environment or also locally +npm install -g license-checker + +//ask it to scan all licenses and fail with exit code other than 0 if it found unauthorized license. The CI system should catch this failure and stop the build +license-checker --summary --failOn BSD + +``` + +
    + +![alt text](assets/bp-25-nodejs-licsense.png) + +
    + +

    + +## ⚪ ️5.6 Constantly inspect for vulnerable dependencies + +:white_check_mark: **Do:** Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using community tools such as [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), or commercial tools like [snyk](https://snyk.io/) (offer also a free community version). Both can be invoked from your CI on every build + +❌ **Otherwise:** Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online publications about new threats. Quite tedious + +
    + +
    Code Examples + +
    + +### :clap: Example: NPM Audit result + +![alt text](assets/bp-26-npm-audit-snyk.png "NPM Audit result") + +
    + +

    + +## ⚪ ️5.7 Automate dependency updates + +:white_check_mark: **Do:** Yarn and npm latest introduction of package-lock.json introduced a serious challenge (the road to hell is paved with good intentions) — by default now, packages are no longer getting updates. Even a team running many fresh deployments with ‘npm install’ & ‘npm update’ won’t get any new updates. This leads to subpar dependent packages versions at best or to vulnerable code at worst. Teams now rely on developers goodwill and memory to manually update the package.json or use tools [like ncu](https://www.npmjs.com/package/npm-check-updates) manually. A more reliable way could be to automate the process of getting the most reliable dependency versions, though there are no silver bullet solutions yet there are two possible automation roads: + +(1) CI can fail builds that have obsolete dependencies — using tools like [‘npm outdated’](https://docs.npmjs.com/cli/outdated) or ‘npm-check-updates (ncu)’ . Doing so will enforce developers to update dependencies. + +(2) Use commercial tools that scan the code and automatically send pull requests with updated dependencies. One interesting question remaining is what should be the dependency update policy — updating on every patch generates too many overhead, updating right when a major is released might point to an unstable version (many packages found vulnerable on the very first days after being released, [see the](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) eslint-scope incident). + +An efficient update policy may allow some ‘vesting period’ — let the code lag behind the @latest for some time and versions before considering the local copy as obsolete (e.g. local version is 1.3.1 and repository version is 1.3.8) +
    + +❌ **Otherwise:** Your production will run packages that have been explicitly tagged by their author as risky + +
    + +
    Code Examples + +
    + +### :clap: Example: [ncu](https://www.npmjs.com/package/npm-check-updates) can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions + +![alt text](assets/bp-27-yoni-goldberg-npm.png "ncu can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions") + +
    + +

    + +## ⚪ ️ 5.8 Other, non-Node related, CI tips + +: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 few non-Node related tips that are well-known + +
    1. Use a declarative syntax. This is the only option for most vendors but older versions of Jenkins allows using code or UI
    2. Opt for a vendor that has native Docker support
    3. Fail early, run your fastest tests first. Create a ‘Smoke testing’ step/milestone that groups multiple fast inspections (e.g. linting, unit tests) and provide snappy feedback to the code committer
    4. Make it easy to skim-through all build artifacts including test reports, coverage reports, mutation reports, logs, etc
    5. Create multiple pipelines/jobs for each event, reuse steps between them. For example, configure a job for feature branch commits and a different one for master PR. Let each reuse logic using shared steps (most vendors provide some mechanism for code reuse)
    6. Never embed secrets in a job declaration, grab them from a secret store or from the job’s configuration
    7. Explicitly bump version in a release build or at least ensure the developer did so
    8. Build only once and perform all the inspections over the single build artifact (e.g. Docker image)
    9. Test in an ephemeral environment that doesn’t drift state between builds. Caching node_modules might be the only exception
    +
    + +❌ **Otherwise:** You‘ll miss years of wisdom + +

    + +## ⚪ ️ 5.9 Build matrix: Run the same CI steps using multiple Node versions + +:white_check_mark: **Do:** Quality checking is about serendipity, the more ground you cover the luckier you get in detecting issues early. When developing reusable packages or running a multi-customer production with various configuration and Node versions, the CI must run the pipeline of tests over all the permutations of configurations. For example, assuming we use MySQL for some customers and Postgres for others — some CI vendors support a feature called ‘Matrix’ which allow running the suit of testing against all permutations of MySQL, Postgres and multiple Node version like 8, 9 and 10. This is done using configuration only without any additional effort (assuming you have testing or any other quality checks). Other CIs who doesn’t support Matrix might have extensions or tweaks to allow that +
    + +❌ **Otherwise:** So after doing all that hard work of writing testing are we going to let bugs sneak in only because of configuration issues? + +
    + +
    Code Examples + +
    + +### :clap: Example: Using Travis (CI vendor) build definition to run the same test over multiple Node versions + +
    language: node_js
    node_js:
    - "7"
    - "6"
    - "5"
    - "4"
    install:
    - npm install
    script:
    - npm run test
    +
    + +

    + +# Team + +## Yoni Goldberg + +
    + +
    + +**Role:** Writer + +**About:** I'm an independent consultant who works with Fortune 500 companies and garage startups on polishing their JS & Node.js applications. More than any other topic I'm fascinated by and aims to master the art of testing. I'm also the author of [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices) + +**📗 Online Course:** Liked this guide and wish to take your testing skills to the extreme? Consider visiting my comprehensive course [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) + +
    + +**Follow:** + +- [🐦 Twitter](https://twitter.com/goldbergyoni/) +- [📞 Contact](https://testjavascript.com/contact-2/) +- [✉️ Newsletter](https://testjavascript.com/newsletter//) + +
    +
    +
    + +## [Bruno Scheufler](https://github.com/BrunoScheufler) + +**Role:** Tech reviewer and advisor + +Took care to revise, improve, lint and polish all the texts + +**About:** full-stack web engineer, Node.js & GraphQL enthusiast + +
    +
    + +## [Ido Richter](https://github.com/idori) + +**Role:** Concept, design and great advice + +**About:** A savvy frontend developer, CSS expert and emojis freak + +## [Kyle Martin](https://github.com/js-kyle) + +**Role:** Helps keep this project running, and reviews security related practices + +**About:** Loves working on Node.js projects and web application security. + +## Contributors ✨ + +Thanks goes to these wonderful people who have contributed to this repository! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Scott Davis

    🖋

    Adrien REDON

    🖋

    Stefano Magni

    🖋

    Yeoh Joer

    🖋

    Jhonny Moreira

    🖋

    Ian Germann

    🖋

    Hafez

    🖋

    Ruxandra Fediuc

    🖋

    Jack

    🖋

    Peter Carrero

    🖋

    Huhgawz

    🖋

    Haakon Borch

    🖋

    Jaime Mendoza

    🖋

    Cameron Dunford

    🖋

    John Gee

    🖋

    Aurelijus Rožėnas

    🖋

    Aaron

    🖋

    Tom Nagle

    🖋

    Yves yao

    🖋

    Userbit

    🖋

    Glaucia Lemos

    🚧

    koooge

    🖋

    Michal

    🖋

    roywalker

    🖋

    dangen

    🖋

    biesiadamich

    🖋

    Yanlin Jiang

    🖋

    sanguino

    🖋

    Morgan

    🖋

    Lukas Bischof

    ⚠️ 🖋

    JuanMa Ruiz

    🖋

    Luís Ângelo Rodrigues Jr.

    🖋

    José Fernández

    🖋

    Alejandro Gutierrez Barcenilla

    🖋

    Jason

    🖋

    Otavio Araujo

    ⚠️ 🖋

    Alex Ivanov

    🖋

    Yiqiao Xu

    🖋
    + + + + + From d1e81eeb9e340788ddc9d6d2e079db836daa06c5 Mon Sep 17 00:00:00 2001 From: yubintw Date: Sat, 27 Nov 2021 22:24:35 +0800 Subject: [PATCH 061/189] Translate Section 0 --- readme-zh-TW.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 10a70528..450db107 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -74,22 +74,22 @@ JavaScript 世界的 CI 指南 (9項)
    -## ⚪️ 0 The Golden Rule: Design for lean testing +## ⚪️ 0 黃金原則:Design for lean testing -:white_check_mark: **Do:** -Testing code is not like production-code - design it to be dead-simple, short, abstraction-free, flat, delightful to work with, lean. One should look at a test and get the intent instantly. +:white_check_mark: **建議:** +測試程式與生產環境的程式不同,要把他設計的極其簡單、簡短、具體、扁平、使人愉悅的去使用及學習。一段測試程式應該要可以讓人一眼就看懂其目的。 -Our minds are full with the main production code, we don't have 'headspace' for additional complexity. Should we try to squeeze yet another challenging code 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. +我們的思考空間被主要的程式邏輯所占滿,並沒有額外的腦容量去處理複雜的東西。如果把其他複雜的程式塞進我們可憐的大腦,將會使得整個團隊的運作變慢,而這個部分正是用來解決我們需要測試的問題。這也是大部分團隊放棄測試的原因。 -The tests are an opportunity for something else - a friendly and smiley assistant, one that it's delightful to work with and delivers great value for such 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 which 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). +另一方面,測試是一個友好的助手,一個讓你樂意與他合作、投資小但回報大的助手。科學證明我們有兩套大腦系統:系統 1 用於無須努力的活動,如在空曠的路上開車;系統 2 用於複雜和繁瑣的工作,如計算一道數學式。把你的測試程式設計成如系統 1 一般,當你看著你的測試,要像修改 HTML 文件一樣的簡單,而不是像計算 2 x (17 x 24)。 -This 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, strive to keep it nimble, sometimes it's even worth dropping some tests and trade reliability for agility and simplicity. +為了達到這個目標,我們可以選擇具有成本效益和高投資報酬率的的技術、工具和測試目標。只測試需要的內容,努力保持他的靈活性,某些時候甚至得捨棄一些測試來換取靈活性和簡潔性。 ![alt text](/assets/headspace.png "We have no head room for additional complexity") -Most of the advice below are derivatives of this principle. +以下大部分的建議衍生自這一原則。 -### Ready to start? +### 準備好了嗎?

    From e28ea8378fb966016b9a28fb08e129443e27428c Mon Sep 17 00:00:00 2001 From: yubintw Date: Sat, 27 Nov 2021 22:29:26 +0800 Subject: [PATCH 062/189] Improve the terms --- readme-zh-TW.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 450db107..568faf1d 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -77,11 +77,11 @@ JavaScript 世界的 CI 指南 (9項) ## ⚪️ 0 黃金原則:Design for lean testing :white_check_mark: **建議:** -測試程式與生產環境的程式不同,要把他設計的極其簡單、簡短、具體、扁平、使人愉悅的去使用及學習。一段測試程式應該要可以讓人一眼就看懂其目的。 +測試程式與主要生產環境的程式不同,要把他設計的極其簡單、簡短、具體、扁平、使人愉悅的去使用及學習。一段測試程式應該要可以讓人一眼就看懂其目的。 -我們的思考空間被主要的程式邏輯所占滿,並沒有額外的腦容量去處理複雜的東西。如果把其他複雜的程式塞進我們可憐的大腦,將會使得整個團隊的運作變慢,而這個部分正是用來解決我們需要測試的問題。這也是大部分團隊放棄測試的原因。 +我們的思考空間被主要的程式邏輯所占滿,並沒有額外的腦容量去處理複雜的東西。如果把其他複雜的程式塞進我們可憐的大腦,將會使得整個團隊的運作變慢,而這些複雜的程式正是用來解決我們需要測試的問題。這也是許多團隊放棄測試的原因。 -另一方面,測試是一個友好的助手,一個讓你樂意與他合作、投資小但回報大的助手。科學證明我們有兩套大腦系統:系統 1 用於無須努力的活動,如在空曠的路上開車;系統 2 用於複雜和繁瑣的工作,如計算一道數學式。把你的測試程式設計成如系統 1 一般,當你看著你的測試,要像修改 HTML 文件一樣的簡單,而不是像計算 2 x (17 x 24)。 +另一方面,測試是一個友好的助手,一個讓你樂意與他合作、投資小且回報大的助手。科學證明我們有兩套大腦系統:系統 1 用於無須努力的活動,如在空曠的路上開車;系統 2 用於複雜和繁瑣的工作,如計算一道數學式。把你的測試程式設計成如系統 1 一般,當你看著你的測試,要像修改 HTML 文件一樣的簡單,而不是像計算 2 x (17 x 24)。 為了達到這個目標,我們可以選擇具有成本效益和高投資報酬率的的技術、工具和測試目標。只測試需要的內容,努力保持他的靈活性,某些時候甚至得捨棄一些測試來換取靈活性和簡潔性。 From f8009d219594b5c3116ea0514e3b3f1f58a5cdcb Mon Sep 17 00:00:00 2001 From: yubintw Date: Wed, 1 Dec 2021 23:51:59 +0800 Subject: [PATCH 063/189] Translate Section 1.1 ~ 1.3 --- readme-zh-TW.md | 66 ++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 568faf1d..590b835f 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -97,50 +97,49 @@ JavaScript 世界的 CI 指南 (9項)
    -## ⚪ ️ 1.1 Include 3 parts in each test name +## ⚪ ️ 1.1 每個測試的名稱要包含的三個部分 -: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: +:white_check_mark: **建議:** 一份測試報告應該告訴那些不一定熟悉程式的人,目前應用程式的修訂版本是否符合他們的要求,包括:測試人員、DevOps 工程師和兩年後的你。如果測試能包含這三個需求面的描述,就能很好的實現這一點: -(1) What is being tested? For example, the ProductsService.addNewProduct method +(1) 測試的對象是什麼? 例如,ProductsService.addNewProduct 這個方法。 -(2) Under what circumstances and scenario? For example, no price is passed to the method +(2) 在什麼情況或場景下? 例如,價格沒有傳給該方法。 -(3) What is the expected result? For example, the new product is not approved +(3) 預期的結果是什麼? 例如,新的產品沒有被批准。
    -❌ **Otherwise:** A deployment just failed, a test named “Add product” failed. Does this tell you what exactly is malfunctioning? +❌ **否則:** 一個名叫"新增產品"的測試失敗了。這有確切地告訴你到底是什麼地方出問題嗎?
    -**👇 Note:** Each bullet has code examples and sometime also an image illustration. Click to expand +**👇 Note:** 每個項目都會有一個程式範例,有時候還會搭配圖片。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: A test name that constitutes 3 parts +### :clap: 正例:一個包含這三部分的測試名稱 ![](https://img.shields.io/badge/🔨%20Example%20using%20Mocha-blue.svg "Using Mocha to illustrate the idea") ```javascript -//1. unit under test +// 1. unit under test describe('Products Service', function() { describe('Add new product', function() { - //2. scenario and 3. expectation + // 2. scenario and 3. expectation it('When no price is specified, then the product status is pending approval', ()=> { const newProduct = new ProductService().add(...); expect(newProduct.status).to.equal('pendingApproval'); }); }); }); - ```
    -### :clap: Doing It Right Example: A test name that constitutes 3 parts +### :clap: 正例:一個包含這三部分的測試名稱 ![alt text](/assets/bp-1-3-parts.jpeg "A test name that constitutes 3 parts") @@ -153,41 +152,41 @@ describe('Products Service', function() {

    -## ⚪ ️ 1.2 Structure tests by the AAA pattern +## ⚪ ️ 1.2 以 AAA 模式來建構測試 -: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: +:white_check_mark: **建議:** 用三個部分來組織你的測試:Arrange 安排、Act 執行、Assert 斷言 (AAA)。依照這個結構,可以確保讀者不用花費腦力去理解你的測試。 -1st 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/stubbing on objects and any other preparation code +第一個 A - Arrange 安排:所有使系統達到測試所要模擬的情境的程式。這可能包含實體化某個待測單元的建構子、新增 DB 的資料、mocking/stubbing 物件和其他準備程式。 -2nd A - Act: Execute the unit under test. Usually 1 line of code +第二個 A - Act 執行:執行測試單元。通常為一行程式。 -3rd A - Assert: Ensure that the received value satisfies the expectation. Usually 1 line of code +第三個 A - Assert 斷言:確保得到的值符合期待。通常為一行程式。
    -❌ **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 +❌ **否則:** 你不僅需要花很多時間去理解主要程式,而且本應是最簡單的部分 - 測試,也會讓你腦力耗盡。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: A test structured with the AAA pattern +### :clap: 正例:以 AAA 模式來建構測試 ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") ```javascript describe("Customer classifier", () => { test("When customer spent more than 500$, should be classified as premium", () => { - //Arrange + // Arrange const customerToClassify = { spent: 505, joined: new Date(), id: 1 }; const DBStub = sinon.stub(dataAccess, "getCustomer").reply({ id: 1, classification: "regular" }); - //Act + // Act const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); - //Assert + // Assert expect(receivedClassification).toMatch("premium"); }); }); @@ -195,7 +194,7 @@ describe("Customer classifier", () => {
    -### :thumbsdown: Anti-Pattern Example: No separation, one bulk, harder to interpret +### :thumbsdown: 反例:沒有分隔、一大坨、難以理解 ```javascript test("Should be classified as premium", () => { @@ -210,24 +209,25 @@ test("Should be classified as premium", () => {

    -## ⚪ ️1.3 Describe expectations in a product language: use BDD-style assertions +## ⚪ ️1.3 用產品語言來描述預期:使用 BDD 風格的斷言 + +:white_check_mark: **建議:** 使用聲明的方式撰寫測試,可以使讀者無腦的 get 到重點。如果你的程式使用各種條件邏輯包起來,會增加讀者的理解難度。因此,我們應該盡量使用類似人類語言的描述與言如 ```expect``` 或 ```should``` 而不是自己寫程式。如果 Chai 或 Jest 沒有你想要用的斷言,且這個斷言可以被頻繁的重複利用的話,可以考慮 [擴充 Jest 的匹配器 (Jest)](https://jestjs.io/docs/en/expect#expectextendmatchers) 或是寫一個 [客製化的 Chai 插件](https://www.chaijs.com/guide/plugins/)。 -: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://jestjs.io/docs/en/expect#expectextendmatchers) or writing a [custom Chai plugin](https://www.chaijs.com/guide/plugins/)
    -❌ **Otherwise:** The team will write less tests and decorate the annoying ones with .skip() +❌ **否則:** 團隊的測試會越寫越少,且會用 .skip() 把討厭的測試略過。
    -
    Code Examples
    +
    程式範例
    ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") -### :thumbsdown: Anti-Pattern Example: The reader must skim through not so short, and imperative code just to get the test story +### :thumbsdown: 反例:讀者必須快速的看完冗長且複雜的程式碼,才能理解該測試的目的 ```javascript test("When asking for an admin, ensure only ordered admins in results", () => { - //assuming we've added here two admins "admin1", "admin2" and "user1" + // assuming we've added here two admins "admin1", "admin2" and "user1" const allAdmins = getUsers({ adminOnly: true }); let admin1Found, @@ -253,11 +253,11 @@ test("When asking for an admin, ensure only ordered admins in results", () => {
    -### :clap: Doing It Right Example: Skimming through the following declarative test is a breeze +### :clap: 正例:快速瀏覽以下的聲明式測試非常輕鬆 ```javascript it("When asking for an admin, ensure only ordered admins in results", () => { - //assuming we've added here two admins + // assuming we've added here two admins const allAdmins = getUsers({ adminOnly: true }); expect(allAdmins) From 726cd4bb9ec46304e8f09f046075a9ba54b50710 Mon Sep 17 00:00:00 2001 From: yubintw Date: Thu, 2 Dec 2021 22:04:36 +0800 Subject: [PATCH 064/189] Translate Section 1.4 ~ 1.6 --- readme-zh-TW.md | 77 ++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 590b835f..ad5be727 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -270,31 +270,31 @@ it("When asking for an admin, ensure only ordered admins in results", () => {

    -## ⚪ ️ 1.4 Stick to black-box testing: Test only public methods +## ⚪ ️ 1.4 堅持黑箱測試:只測試公開方法 -:white_check_mark: **Do:** Testing the internals brings huge overhead for almost nothing. If your code/API 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 +:white_check_mark: **建議:** 測試內部邏輯是無意義且浪費時間的。如果你的程式/API 回傳了正確的結果,你真的需要花三個小時的時間去測試它內部究竟如何實現的,並且在之後維護這一堆脆弱的測試嗎?每當測試一個公開方法時,其私有方法的實作也會被隱性地測試,只有當存在某個問題(例如錯誤的輸出)時測試才會中斷。這種方法也稱為 ```行為測試```。另一方面,如果你測試內部方法 (白箱方法) — 你的關注點將從組件的輸出結果轉移到具體的實作細節上,如果某天內部邏輯改變了,即使結果依然正確,你也要花精力去維護之前的測試邏輯,這無形中增加了維護成本。
    -❌ **Otherwise:** Your tests behave like the [boy who cried wolf](https://en.wikipedia.org/wiki/The_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… +❌ **否則:** 你的測試會像[狼來了](https://en.wikipedia.org/wiki/The_Boy_Who_Cried_Wolf)一樣,總是叫喚著出問題了 (例如一個因為內部變數名稱改變而導致的測試失敗)。不出所料,人們很快就會開始忽視 CI 的通知,直到某天,一個真正的 bug 被忽視...
    -
    Code Examples +
    程式範例
    -### :thumbsdown: Anti-Pattern Example: A test case is testing the internals for no good reason +### :thumbsdown: 反例:一個無腦測試內部方法的測試 ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") ```javascript class ProductService { - //this method is only used internally - //Change this name will make the tests fail + // this method is only used internally + // Change this name will make the tests fail calculateVATAdd(priceWithoutVAT) { return { finalPrice: priceWithoutVAT * 1.2 }; - //Change the result format or key name above will make the tests fail + // Change the result format or key name above will make the tests fail } - //public method + // public method getPrice(productId) { const desiredProduct = DB.getProduct(productId); finalPrice = this.calculateVATAdd(desiredProduct.price).finalPrice; @@ -303,7 +303,7 @@ class ProductService { } it("White-box test: When the internal methods get 0 vat, it return 0 response", async () => { - //There'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 + // There'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 expect(new ProductService().calculateVATAdd(0).finalPrice).to.equal(0); }); ``` @@ -312,32 +312,31 @@ it("White-box test: When the internal methods get 0 vat, it return 0 response",

    -## ⚪ ️ ️1.5 Choose the right test doubles: Avoid mocks in favor of stubs and spies +## ⚪ ️ ️1.5 使用正確的測試替身 (Test Double):避免總是使用 stub 和 spy -:white_check_mark: **Do:** Test doubles are a necessary evil because they are coupled to the application internals, yet some provide immense value ([Read here a reminder about test doubles: mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)). +:white_check_mark: **建議:** 測試替身是把雙刃劍,他們在提供巨大價值的同時,耦合了應用的內部邏輯 ([一篇關於測試替身的文章: mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)) 在使用測試替身前,問自己一個很簡單的問題:我是用它來測試需求文件中定義的可見的功能或者可能可見的功能嗎?如果不是,那就可能是白盒測試了。 -Before 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 no, it’s a white-box testing smell. +舉例來說,如果你想測試你的應用程式在支付服務當機時的預期行為,你可以 stub 支付服務並觸發一些"沒有回應"的回傳行為,以確保被測試的單元回傳正確的值。這可以測試特定場景下應用程式的行為、回應及輸出結果。你也可以使用一個 spy 來斷言當服務當機時是否有發送電子郵件 - 這又是一個針對可能出現在需求文件中行為的檢查 ("如果無法儲存付款資訊,發送電子郵件")。反過來說,如果你 mock 的支付服務,能確保它被正確呼叫並傳入正確的 JavaScript 型別,那麼你的測試重點是內部的邏輯,它與應用程式的功能關係不大,而且可能會經常變化。 -For 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/response/outcome 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
    -❌ **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 +❌ **否則:** 任何程式的重構都會需要程式中所有的 mock 進行相對應的更新。測試變成了一種負擔,而不是一個助力。
    -
    Code Examples +
    程式範例
    -### :thumbsdown: Anti-pattern example: Mocks focus on the internals +### :thumbsdown: 反例:關注內部實作的 mock ![](https://img.shields.io/badge/🔧%20Example%20using%20Sinon-blue.svg "Examples with Sinon") ```javascript it("When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config", async () => { - //Assume we already added a product + // Assume we already added a product const dataAccessMock = sinon.mock(DAL); - //hmmm BAD: testing the internals is actually our main goal here, not just a side-effect + // hmmm BAD: testing the internals is actually our main goal here, not just a side-effect dataAccessMock .expects("deleteProduct") .once() @@ -349,14 +348,14 @@ it("When a valid product is about to be deleted, ensure data access DAL was call
    -### :clap:Doing It Right Example: spies are focused on testing the requirements but as a side-effect are unavoidably touching to the internals +### :clap: 正例:Spy 專注於測試需求,但身為一個 side effect,無可避免地會接觸到內部程式結構 ```javascript it("When a valid product is about to be deleted, ensure an email is sent", async () => { - //Assume we already added here a product + // Assume we already added here a product const spy = sinon.spy(Emailer.prototype, "sendEmail"); new ProductService().deletePrice(theProductWeJustAdded); - //hmmm OK: we deal with internals? Yes, but as a side effect of testing the requirements (sending an email) + // hmmm OK: we deal with internals? Yes, but as a side effect of testing the requirements (sending an email) expect(spy.calledOnce).to.be.true; }); ``` @@ -365,59 +364,59 @@ it("When a valid product is about to be deleted, ensure an email is sent", async

    -## 📗 Want to learn all these practices with live video? +## 📗 想要透過影片來學習這些做法嗎? -### Visit my online course [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) +### 歡迎來我的線上課程網站 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com)

    -## ⚪ ️1.6 Don’t “foo”, use realistic input data +## ⚪ ️1.6 不要 "foo", 使用真實的資料 -: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 [Faker](https://www.npmjs.com/package/faker) 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 card, 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). +:white_check_mark: **建議:** 生產環境中的 bug 通常是在一些特殊或者意外的輸入下出現的 — 所以測試的輸入資料越真實,越容易在早期抓住問題。使用現有的一些函式庫(比如 [Faker](https://www.npmjs.com/package/faker))去造"假"真實數據來模擬生產環境數據的多樣性和形式。比如,這些函示庫可以產生真實的電話號碼、用戶名稱、信用卡、公司名稱等等。你還可以創建一些測試(在單元測試之上,而不是替代)生產隨機 fakers 數據來擴充你的測試單元,甚至從生產環境中導入真實的資料。如果想要更進階的話,請看下一個項目:基於屬性的測試 (property-based testing)。
    -❌ **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” +❌ **否則:** 你要部屬的程式都在 "foo" 之類的輸入值中正確的通過測試,結果上線之後收到像是 ```@3e2ddsf . ##’ 1 fdsfds . fds432 AAAA``` 之類的輸入值後掛掉了。
    -
    Code Examples +
    程式範例
    -### :thumbsdown: Anti-Pattern Example: A test suite that passes due to non-realistic data +### :thumbsdown: 反例: 一個測試案例使用非真實資料去通過測試 ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ```javascript const addProduct = (name, price) => { - const productNameRegexNoSpace = /^\S*$/; //no white-space allowed + const productNameRegexNoSpace = /^\S*$/; // no white-space allowed - if (!productNameRegexNoSpace.test(name)) return false; //this path never reached due to dull input + if (!productNameRegexNoSpace.test(name)) return false; // this path never reached due to dull input - //some logic here + // some logic here return true; }; test("Wrong: When adding new product with valid properties, get successful confirmation", async () => { - //The string "Foo" which is used in all tests never triggers a false result + // The string "Foo" which is used in all tests never triggers a false result const addProductResult = addProduct("Foo", 5); expect(addProductResult).toBe(true); - //Positive-false: the operation succeeded because we never tried with long - //product name including spaces + // Positive-false: the operation succeeded because we never tried with long + // product name including spaces }); ```
    -### :clap:Doing It Right Example: Randomizing realistic input +### :clap:正例:使用隨機產生的真實資料來輸入 ```javascript it("Better: When adding new valid product, get successful confirmation", async () => { const addProductResult = addProduct(faker.commerce.productName(), faker.random.number()); - //Generated random input: {'Sleek Cotton Computer', 85481} + // Generated random input: {'Sleek Cotton Computer', 85481} expect(addProductResult).to.be.true; - //Test failed, the random input triggered some path we never planned for. - //We discovered a bug early! + // Test failed, the random input triggered some path we never planned for. + // We discovered a bug early! }); ``` From 2d3bfdce228e9d2d7e07e7d3e417f90a6a57e7d7 Mon Sep 17 00:00:00 2001 From: yubintw Date: Fri, 3 Dec 2021 23:41:18 +0800 Subject: [PATCH 065/189] Translate Section 1.7 --- readme-zh-TW.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index ad5be727..bca73f44 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -424,20 +424,27 @@ it("Better: When adding new valid product, get successful confirmation", async (

    -## ⚪ ️ 1.7 Test many input combinations using Property-based testing +## ⚪ ️ 1.7 Property-based testing 基於屬性的測試:測試輸入的多種組合 + +:white_check_mark: **建議:** 通常我們只會選擇少部分的輸入樣本去做測試。 即使是使用了上一項提到的工具去模擬真實數據,我們也只覆蓋到了一部分輸入的組合 (```method('', true, 1)```, ```method('string', false , 0)```)。然而在生產環境中,一個擁有 5 個參數的 API,可能會遇到上千種排列組合的輸入,而其中的某一種可能會把你的程式搞掛(可參考 [Fuzz Testing](https://en.wikipedia.org/wiki/Fuzzing))。 + +如何撰寫一個測試,可以自動發送 1000 種不同輸入的排列組合,並捕捉到使我們的程式不能正確回傳的輸入?基於屬性的測試 (Property-based testing) 就是這樣一種技術:透過發送所有可能的輸入組合到你的測試單元中,它增加了發現 bug 的可能性。 + +例如,給定一個方法 — ```addNewProduct(id, name, isDiscount)``` — 函示庫將使用許多 ```(number, string, boolean)``` 的組合來呼叫這個方法,比如 ```(1, 'iPhone', false)```,```(2, 'Galaxy', true)```。您可以使用您喜歡的測試運行器(Mocha、Jest等),使用 [js-verify](https://github.com/jsverify/jsverify) 或者 [testcheck](https://github.com/leebyron/testcheck-js) (文件寫得比較好) 來執行基於屬性的測試。 + +更新:Nicolas Dubien 在下面的回復中建議使用 [fast-check](https://github.com/dubzzz/fast-check#readme),它似乎提供了更多的功能,且有被積極維護。 -: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://github.com/goldbergyoni/javascript-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://en.wikipedia.org/wiki/Fuzzing)). 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: by 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://github.com/jsverify/jsverify) or [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https://github.com/dubzzz/fast-check#readme) which seems to offer some additional features and also to be actively maintained
    -❌ **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 +❌ **否則:** 你無意中選擇的測試輸入只涵蓋到運作正常的程式片段。不幸的是,他沒有發現真正的錯誤,這也降低了把測試當作發現錯誤的工具的成效。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: Testing many input permutations with “fast-check” +### :clap: 正例: 使用 fast-check 來測試許多的輸入組合 ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") @@ -446,7 +453,7 @@ import fc from "fast-check"; describe("Product service", () => { describe("Adding new", () => { - //this will run 100 times with different random properties + // this will run 100 times with different random properties it("Add new product with random yet valid properties, always successful", () => fc.assert( fc.property(fc.integer(), fc.string(), (id, name) => { From 93f420533a3305cd845373055201009852c6bd3a Mon Sep 17 00:00:00 2001 From: yubintw Date: Sun, 5 Dec 2021 13:33:50 +0800 Subject: [PATCH 066/189] Translate Section 1.8 --- readme-zh-TW.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index bca73f44..a5e93bd9 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -468,57 +468,58 @@ describe("Product service", () => {

    -## ⚪ ️ 1.8 If needed, use only short & inline snapshots +## ⚪ ️ 1.8 如果需要,只使用簡短的行內快照 (inline snapshots) -:white_check_mark: **Do:** When there is a need for [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), use only short and focused snapshots (i.e. 3-7 lines) that are included as part of the test ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)) and not within external files. Keeping this guideline will ensure your tests remain self-explanatory and less fragile. +:white_check_mark: **建議:** 如果你需要進行 快照測試 ([snapshot testing](https://jestjs.io/docs/en/snapshot-testing)),只使用短而集中的快照 (如3~7行),該快照是測試程式的一部份,而不是在外部文件中。保持好這一原則,將會確保你的測試的自我解釋性且不會那麼脆弱。 -On the other hand, ‘classic snapshots’ tutorials and tools encourage to store big files (e.g. component rendering markup, API JSON result) over some external medium and ensure each time when the test run 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/HTML 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 to 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 +另一方面,"classic snapshots"的教學和工具鼓勵將大文件 (如組件的渲染結果、API 的 JSON 結果) 存儲在一些外部媒介上,並確保每次測試運行時,將收到的結果與保存的版本進行比較。舉個例子,這將會隱性地將我們的測試與包含3000個數值的1000行內容耦合在一起,而測試者從未閱讀和推理過這些數據。為什麼這樣是不對的? 這樣做,將會有1000個原因讓你的測試失敗 - 只要有一行改變,快照比對就會 fail,而這可能會經常發生。多頻繁?當有每一個空格、註解或一點 CSS/HTML 的變化。不僅如此,測試名稱也不會提供關於失敗的線索,因為它只是檢查這1000行是否有變化,而且它還鼓勵測試者去接受一個他無法檢查和驗證的大文件作為期望的結果。所有這些都是測試目標不明確、測試目標過多的症狀。 + +值得注意的是,在少數情況下,大型的外部快照是可以接受的 - 當斷言的對象是 schema 而不是所有內容時 (提取出要的值並專注在某個欄位上),或者當收到的文件內容幾乎不會改變時。 -It’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
    -❌ **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 origin document to current received one - a single space character was added to the markdown... +❌ **否則:** 一個 UI 的測試失敗了。程式看起來是對的,畫面上也完美渲染了每個像素,但怎麼了? 你的測試程式發現收到的內容與期望的不同,或許只是多了一個空格...
    -
    Code Examples +
    程式範例
    -### :thumbsdown: Anti-Pattern Example: Coupling our test to unseen 2000 lines of code +### :thumbsdown: 反例: 將看不到的 2000 行程式耦合進我們的測試案例中 ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ```javascript it("TestJavaScript.com is renderd correctly", () => { - //Arrange + // Arrange - //Act + // Act const receivedPage = renderer .create( Test JavaScript ) .toJSON(); - //Assert + // Assert expect(receivedPage).toMatchSnapshot(); - //We now implicitly maintain a 2000 lines long document - //every additional line break or comment - will break this test + // We now implicitly maintain a 2000 lines long document + // every additional line break or comment - will break this test }); ```
    -### :clap: Doing It Right Example: Expectations are visible and focused +### :clap: 正例:期望是可見且集中的 ```javascript it("When visiting TestJavaScript.com home page, a menu is displayed", () => { - //Arrange + // Arrange - //Act + // Act const receivedPage = renderer .create( Test JavaScript ) .toJSON(); - //Assert + // Assert const menu = receivedPage.content.menu; expect(menu).toMatchInlineSnapshot(` From 91fa65721f695294b2cdf0f6558be883c15f03ac Mon Sep 17 00:00:00 2001 From: yubintw Date: Sun, 5 Dec 2021 23:23:11 +0800 Subject: [PATCH 067/189] Translate Section 1.9 --- readme-zh-TW.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index a5e93bd9..ee237cc0 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -536,49 +536,50 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => {

    -## ⚪ ️1.9 Avoid global test fixtures and seeds, add data per-test +## ⚪ ️1.9 避免使用全域的 test fixtures 或 seeds,而是放進每個測試中 + +:white_check_mark: **建議:** 參照黃金原則,每個測試需要在它自己的 DB 中進行操作避免互相污染。但現實中,這條規則經常被打破:為了性能的提升而在執行測試前初始化全域資料庫 (也被稱為"[test fixture](https://en.wikipedia.org/wiki/Test_fixture)")。儘管性能很重要,但是它可以通過後面講的「組件測試」來做取捨。為了減輕複雜度,我們可以在每個測試中只初始化自己需要的數據。除非性能問題真的非常嚴重,那還是可以做一定程度的妥協 - 僅在全域放不會改變的數據 (比如 query)。 -: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’](https://en.wikipedia.org/wiki/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)
    -❌ **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 +❌ **否則:** 有一些測試 fail 了,團隊花了許多時間後發現,只是因為兩個測試同時改變了同一個 seed。
    -
    Code Examples +
    程式範例
    -### :thumbsdown: Anti-Pattern Example: tests are not independent and rely on some global hook to feed global DB data +### :thumbsdown: 反例:測試案例之間不是獨立的。而是相依於全域的 DB 資料 ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") ```javascript before(async () => { - //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework + // adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework await DB.AddSeedDataFromJson('seed.json'); }); it("When updating site name, get successful confirmation", async () => { - //I know that site name "portal" exists - I saw it in the seed files + // I know that site name "portal" exists - I saw it in the seed files const siteToUpdate = await SiteService.getSiteByName("Portal"); const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); expect(updateNameResult).to.be(true); }); it("When querying by site name, get the right site", async () => { - //I know that site name "portal" exists - I saw it in the seed files + // I know that site name "portal" exists - I saw it in the seed files const siteToCheck = await SiteService.getSiteByName("Portal"); - expect(siteToCheck.name).to.be.equal("Portal"); //Failure! The previous test change the name :[ + expect(siteToCheck.name).to.be.equal("Portal"); // Failure! The previous test change the name :[ }); ```
    -### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data +### :clap: 正例:每個測試案例只操作他自己的資料 ```javascript it("When updating site name, get successful confirmation", async () => { - //test is adding a fresh new records and acting on the records only + // test is adding a fresh new records and acting on the records only const siteUnderTest = await SiteService.addSite({ name: "siteForUpdateTest" }); From 31efe9e7deae8d3e45507e1cfdb5e2123c07b039 Mon Sep 17 00:00:00 2001 From: yubintw Date: Mon, 6 Dec 2021 22:03:21 +0800 Subject: [PATCH 068/189] Translate Section 1.10 --- readme-zh-TW.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index ee237cc0..87f34443 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -594,22 +594,23 @@ it("When updating site name, get successful confirmation", async () => {
    -## ⚪ ️ 1.10 Don’t catch errors, expect them +## ⚪ ️ 1.10 不要 catch 錯誤,expect 他們 -: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 +:white_check_mark: **建議:** 當你要測試一些輸入是否有觸發錯誤時,使用 ```try-catch-finally``` 來檢查他是否會進入到 catch 區塊,看起來沒什麼問題。但會變成一個笨拙且冗長的測試案例 (如下面程式範例),他會隱藏簡單的測試意圖和預期的結果。 + +一個更為優雅的作法是使用專用的單行斷言:如 Chai 中的 ```expect(method).to.throw``` 或是 Jest 中的 ```expect(method).toThrow()```。必須要確保這個 expection 包含某個預期的 error type,如果只得到一個通用的錯誤型態,那應用程式將無法表明更多訊息給使用者。 -A 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
    -❌ **Otherwise:** It will be challenging to infer from the test reports (e.g. CI reports) what went wrong +❌ **否則:** 從測試報告 (如 CI 報告) 中要看出哪裡有錯會非常困難。
    -
    Code Examples +
    程式範例
    -### :thumbsdown: Anti-pattern Example: A long test case that tries to assert the existence of error with try-catch +### :thumbsdown: 反例:一個很長的測試案例,嘗試使用 ```try-catch``` 來斷言錯誤 ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") @@ -623,14 +624,14 @@ it("When no product name, it throws error 400", async () => { errorWeExceptFor = error; } expect(errorWeExceptFor).not.to.be.null; - //if this assertion fails, the tests results/reports will only show - //that some value is null, there won't be a word about a missing Exception + // if this assertion fails, the tests results/reports will only show + // that some value is null, there won't be a word about a missing Exception }); ```
    -### :clap: Doing It Right Example: A human-readable expectation that could be understood easily, maybe even by QA or technical PM +### :clap: 正例:一個容易閱讀及被了解的 expection,甚至能被 QA 或 PM 理解 ```javascript it("When no product name, it throws error 400", async () => { From 08db05bc29ec51760b2a0a19bab22a7817031505 Mon Sep 17 00:00:00 2001 From: yubintw Date: Tue, 7 Dec 2021 23:56:20 +0800 Subject: [PATCH 069/189] Translate Section 1.11 --- readme-zh-TW.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 87f34443..3e1c17dd 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -645,30 +645,30 @@ it("When no product name, it throws error 400", async () => {

    -## ⚪ ️ 1.11 Tag your tests +## ⚪ ️ 1.11 為測試案例打上標籤 -: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’ +:white_check_mark: **建議:** 不同的測試需要在不同的情境下執行:快速冒煙測試、無 IO 的測試、開發者儲存或提交檔案的測試、送出一個 PR 後的 end-to-end 測試等等。 可以用一些 ```#cold``` ```#api``` ```#sanity``` 之類的標籤來標註這些測試,這樣就可以在測試時只執行特定的子集合。例如在 Mocha 中可以這樣來執行:```mocha -- grep 'sanity'```。
    -❌ **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 +❌ **否則:** 執行所有測試案例,包括執行大量查詢 DB 的測試,開發者做的任何微小的變更都需要花很長的時間去跑完所有的測試,將會導致開發者不想再執行測試。
    -
    Code Examples +
    程式範例:
    -### :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) +### :clap: 正例:將測試案例標記為 '#cold-test' 讓執行測試的人可以只執行速度快的測試案例 (cold 指的是沒有 IO 的快速測試,甚至可以在開發人員打字時頻繁地執行) ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ```javascript -//this test is fast (no DB) and we're tagging it correspondigly -//now the user/CI can run it frequently +// this test is fast (no DB) and we're tagging it correspondigly +// now the user/CI can run it frequently describe("Order service", function() { describe("Add new order #cold-test #sanity", function() { test("Scenario - no currency was supplied. Expectation - Use the default currency #sanity", function() { - //code logic here + // code logic here }); }); }); From f8c457546e95e25cdc806b47bc8f3cf0198b212b Mon Sep 17 00:00:00 2001 From: yubintw Date: Wed, 8 Dec 2021 23:55:39 +0800 Subject: [PATCH 070/189] Translate Section 1.12 --- readme-zh-TW.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 3e1c17dd..9fd054ca 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -678,33 +678,33 @@ describe("Order service", function() {

    -## ⚪ ️ 1.12 Categorize tests under at least 2 levels +## ⚪ ️ 1.12 把測試案例進行至少兩個層次的分類 -: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 additional level of categorization like the scenario or custom categories (see code examples and print screen below). Doing so will also greatly improve the test reports: The reader will easily infer the tests 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 test suite that you may consider like [given-when-then](https://github.com/searls/jasmine-given) and [RITE](https://github.com/ericelliott/riteway) +:white_check_mark: **建議:** 對測試案例套用一些結構,讓每個看到這個測試案例的人都可以很容易得理解需求 (測試是最好的文件) 和正在測試的各種情境。一個常見的方法是在測試上方寫至少兩個用來"描述"的區塊:第一個是測試單元的名稱,第二個是額外的分類名稱,如情境或自定義的類別 (參考下面的程式範例和畫面輸出)。這樣的做法也會大幅的改善測試報告的呈現。讀者將會很容易的推斷出測試的類別,讀懂該測試的內容並與失敗的測試關聯起來。此外,對開發者來說,瀏覽這一連串的測試也變得更加容易。有許多額外的結構也是可以考慮使用的,像是 [given-when-then](https://github.com/searls/jasmine-given) 或 [RITE](https://github.com/ericelliott/riteway)。
    -❌ **Otherwise:** When looking at a report with flat and long list of tests, the reader have to skim-read through long texts to conclude the major scenarios and correlate the commonality of failing tests. Consider the following case: When 7/100 tests fail, looking at a flat list will demand reading the failing tests text 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 +❌ **否則** 當看到一份毫無結構且數量眾多的測試報告時,讀者只能透過粗略地閱讀整份報告來總結,並將失敗的錯誤案例關聯起來。思考一個情況,當100個測試案例中有7個失敗時,看一個分層結構良好的測試報告與看一個扁平的測試結果清單相比,那些錯誤的測試案例很有可能都在同一個流程或分類底下,讀者將可以很快的推斷出錯誤的地方或看出哪部分是他們失敗的原因。
    -
    Code Examples +
    程式範例
    -### :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 +### :clap: 正例:利用測試案例的名稱和情境來組織,可以產生良好的測試報告,如下所示 ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ```javascript // Unit under test describe("Transfer service", () => { - //Scenario + // Scenario describe("When no credit", () => { - //Expectation + // Expectation test("Then the response status should decline", () => {}); - //Expectation + // Expectation test("Then it should send email to admin", () => {}); }); }); @@ -714,7 +714,7 @@ describe("Transfer service", () => {
    -### :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 +### :thumbsdown: 反例:扁平的測試列表會使讀者很難去看懂 user story 和失敗的測試之間的關係 ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Mocha") From a73ae88fb488bebcf2e9c9abb9574c5a121a67df Mon Sep 17 00:00:00 2001 From: yubintw Date: Thu, 9 Dec 2021 23:01:38 +0800 Subject: [PATCH 071/189] Translate Section 1.13 --- readme-zh-TW.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 9fd054ca..3bcd751a 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -734,14 +734,15 @@ test("Then there should not be a new transfer record", () => {});

    -## ⚪ ️1.13 Other generic good testing hygiene +## ⚪ ️1.13 其他通用且良好的測試習慣 -: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 few non-Node related tips that are well-known +:white_check_mark: **建議:** 本篇文章的重點是與 NodeJS 相關的測試建議或至少可以用 NodeJS 來舉例說明的內容。然而,這裡有幾個與 NodeJS 無關的建議,且是眾所皆知的。 + +學習並實現 [TDD原則](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) - 他對許多人來說非常有價值,但如果他不適合你的風格,不要被嚇到,不是只有你這樣。試著在寫程式之前使用 [red-green-refactor](https://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html) 的風格來撰寫測試,並確保每個測試案例只檢查一個測試目標。當你發現一個 bug 時,在修復它之前先新增一個可以檢測到它的測試案例,讓每個測試案例在變綠之前至少失敗一次,接著快速撰寫簡單的程式讓這個測試通過 - 然後逐步重構這些程式到可以上 production 的水準,避免對環境 (如路徑或作業系統等) 有任何相依性。 -Learn and practice [TDD principles](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) — 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://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.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, 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)
    -❌ **Otherwise:** You‘ll miss pearls of wisdom that were collected for decades +❌ **否則:** 你會錯過這數十年來的智慧結晶

    From c55ae81ea9d5115066fcc5a4afe514521a17beef Mon Sep 17 00:00:00 2001 From: yubintw Date: Fri, 10 Dec 2021 23:59:26 +0800 Subject: [PATCH 072/189] Translate Section 2.1 --- readme-zh-TW.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 3bcd751a..d726fa05 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -10,7 +10,7 @@ 這是從 A 到 Z 的 JavaScript 及 Node.js 可靠的指南。它為你總結及規劃了市場上大量的部落格文章、書籍及工具。 -## 🚢 進階:從基礎向前邁進 10,000 英里 Advanced: Goes 10,000 miles beyond the basics +## 🚢 進階:從基礎向前邁進 10,000 英里 從基礎往前邁進的旅程,包括:在生產(production)環境中測試、變異測試(mutation testing)、以屬性為基礎(property-based)的測試以及許多策略和專業工具。如果你認真閱讀本指南書,你的測試技能可能會高於平均水準。 @@ -93,7 +93,7 @@ JavaScript 世界的 CI 指南 (9項)

    -# Section 1: The Test Anatomy +# 第 1 章:測試剖析
    @@ -746,29 +746,29 @@ test("Then there should not be a new transfer record", () => {});

    -# Section 2️⃣: Backend Testing +# 第 2 章:後端測試 -## ⚪ ️2.1 Enrich your testing portfolio: Look beyond unit tests and the pyramid +## ⚪ ️2.1 豐富您的測試組合:不局限於單元測試和測試金字塔 -:white_check_mark: **Do:** The [testing pyramid](https://martinfowler.com/bliki/TestPyramid.html), though 10> years old, is a great and relevant model that suggests three testing types and influences most developers’ testing strategy. 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? +:white_check_mark: **建議:** 雖然 [測試金字塔](https://martinfowler.com/bliki/TestPyramid.html) 已經有超過十年的歷史了,但他仍然是個很好的模型,他提出了三種測試類型,並影響了大多數開發者的測試策略。與此同時,大量閃亮的新測試技術出現了,並隱藏在測試金字塔的陰影下。考慮到近十年來我們所看到的所有巨變 (Microservices, cloud, serverless),這個非常老的模型是否仍能適用於所有類型的應用?測試界不應該考慮新的測試技術嗎? -Don’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://en.wikipedia.org/wiki/All_models_are_wrong). For example, consider an IoT application that ingests many events into a message-bus like Kafka/RabbitMQ, 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 increase (bots, crypto, Alexa-skills) greater are the chances to find scenarios where the testing pyramid is not the best match. +不要誤會,在 2019 年,測試金字塔、TDD、單元測試仍然是強大的技術,且對於大多數應用仍是最佳選擇。但是像其他模型一樣,儘管它有用,但是一定[會在某些時候出問題](https://en.wikipedia.org/wiki/All_models_are_wrong)。例如,我們有一個 IoT 的應用程式,將許多事件傳入一個 Kafka/RabbitMQ 這樣的 message-bus 中,然後這些事件流入資料庫並被經由 UI 來做查詢。我們真的需要花費 50% 的測試預算去為這個幾乎沒有邏輯的中心化的整合應用程式寫單元測試嗎?隨著應用類型 (bots, crypto, Alexa-skills) 的多樣增長,測試金字塔可能將不再是某些場景的最佳選擇了。 -It’s time to enrich your testing portfolio and become familiar with more testing types (the next bullets suggest 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 build a portfolio based on risk analysis — assess where problems might arise and match some prevention measures to mitigate those potential risks +是時候豐富你的測試組合並了解更多的測試類型了(下一節會給你一些小建議),這些類似於測試金字塔的思維模型與你所面臨的現實問題會更加匹配("嘿,我們的 API 掛了,我們來寫 consumer-driven contract testing 吧!")。讓您的測試多樣化,比如建立基於風險分析的檢查模型 — 評估可能出現問題的地方,並提供一些預防措施以減輕這些潛在風險。 -A word of caution: the TDD argument in the software world takes a typical false-dichotomy face, some preach to use it everywhere, others think it’s the devil. Everyone who speaks in absolutes is wrong :] +需要注意的是:軟體世界中的 TDD 模型面臨兩個極端的態度,一些人鼓吹到處使用它,另一些人則認為它是魔鬼。每個說絕對的人都是錯的 :]
    -❌ **Otherwise:** You’re going to miss some tools with amazing ROI, some like Fuzz, lint, and mutation can provide value in 10 minutes +❌ **否則:** 你將錯過一些超高 CP 值的工具,比如 Fuzz、lint、mutation,這些工具只需 10 分鐘設定就能為你提供許多好處。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the same way’ +### :clap: 正例:Cindy Sridharan 在她的文章 "Testing Microservices — the sane way" 中提出了一個豐富的測試組合 ![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") From 06a869734bc47b537aa2b832bbcd1f8b2d72b681 Mon Sep 17 00:00:00 2001 From: yubintw Date: Sat, 11 Dec 2021 10:05:56 +0800 Subject: [PATCH 073/189] Translate Section 2.2 ~ 2.4 --- readme-zh-TW.md | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index d726fa05..182d862c 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -782,22 +782,23 @@ test("Then there should not be a new transfer record", () => {});

    -## ⚪ ️2.2 Component testing might be your best affair +## ⚪ ️2.2 組件化測試可能是最有效的利器 -: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 from both worlds: reasonable performance and a possibility to apply TDD patterns + realistic and great coverage. +:white_check_mark: **建議:** 應用程式中的每個單元測試僅能覆蓋整個程式的一小部分,要覆蓋全部會非常麻煩,而端到端測試可以很輕鬆地覆蓋大量區域,但是比較脆弱而且很慢。何不找一個平衡點:寫一些比單元測試大,但是比端到端測試小的測試。組件測試是測試世界的一顆遺珠 — 它找到了兩個模式的最佳平衡點:不錯的性能和使用 TDD 模式的可能性與真實且強大的覆蓋率。 + +組件測試關注於微服務"單元",他們針對 API 來做事,不 mock 任何屬於微服務本身的東西(像是真實的 DB,甚至是該 DB 的 in-memory 版本)但是 stub 所有外部的東西,像是呼叫其他的微服務。藉由這種方式,我們可以測試我們部署的部分,由外而內地覆蓋應用程式,可以節省大量時間並獲得信心。 -Component tests focus on the Microservice ‘unit’, they work against the API, 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 outwards to inwards and gain great confidence in a reasonable amount of time.
    -❌ **Otherwise:** You may spend long days on writing unit tests to find out that you got only 20% system coverage +❌ **否則:** 你可能花了好幾天來寫單元測試,卻發現只得到了 20% 的覆蓋率。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: Supertest allows approaching Express API in-process (fast and cover many layers) +### :clap: 正例:使用 Supertest 來測試 Express API (快速且覆蓋多個層次) ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") @@ -807,20 +808,22 @@ Component tests focus on the Microservice ‘unit’, they work against the API,

    -## ⚪ ️2.3 Ensure new releases don’t break the API using contract tests +## ⚪ ️2.3 利用 contract tests 來確保新的 release 不會破壞 API 的使用 -: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. [Consumer-driven contracts and the framework PACT](https://docs.pact.io/) were born to formalize this process with a very disruptive approach — not the server defines the test plan of itself rather the client defines the tests of the… server! PACT can record the client expectation and put in a shared location, “broker”, so the server can pull the expectations and run on every build using 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/CI and might save you a great deal of frustration +:white_check_mark: **建議:** 你的微服務有許多客戶,而你為了兼容性而運行著很多種版本 (keeping everyone happy)。當你改了某些程式後 "砰!",某些使用該服務的重要客戶生氣了。伺服端要滿足所有客戶的期望是非常困難的 - 另一方面,客戶端無法執行任何測試,因為 release 的日期是伺服端決定的。 + +[Consumer-driven contracts and the framework PACT](https://docs.pact.io/) 誕生了,它以一種破壞性的方式規範了這一流程 — 不再由伺服端定義測試計劃,而是客戶端決定伺服端的測試! PACT 可以記錄客戶端的期望並存放在一個共享的位置 — 中間人(Broker),伺服端可以 pull 下這些期望並利用 PACT 的函示庫在所有版本中檢測是否有被破壞的契約,也就是客戶端的期望沒有被滿足。通過這種方式,所有 伺服端-用戶端 沒對好的 API 將會在 build/CI 階段被發現,從而減少你的煩惱。
    -❌ **Otherwise:** The alternatives are exhausting manual testing or deployment fear +❌ **否則:** 所有的變更都將會造成繁瑣的人工測試,導致開發者害怕部屬
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: +### :clap: 正例: ![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") @@ -830,28 +833,28 @@ Component tests focus on the Microservice ‘unit’, they work against the API,

    -## ⚪ ️ 2.4 Test your middlewares in isolation +## ⚪ ️2.4 單獨測試你的 middlewares -: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://www.npmjs.com/package/sinon)) on the interaction with the {req,res} objects to ensure the function performed the right action. The library [node-mock-http](https://www.npmjs.com/package/node-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) +:white_check_mark: **建議:** 許多人拒絕測試 middleware,因為它們只佔系統的一小部分而且相依於真實的 Express server。這兩個原因都不正確 — middleware 雖然小,但是影響著所有或至少大部分請求,而且可以被簡單地作為純函數測試 (參數為 ```{req,res}``` 的 JavaScript 物件)。要測試 middleware 函數,只需要呼叫它,並且監看 ([如使用 Sinon](https://www.npmjs.com/package/sinon)) 與 ```{req,res}``` 的互動來確保函數有執行正確的行為。 [node-mock-http](https://www.npmjs.com/package/node-mocks-http) 函示庫則更進一步:它還監聽了 ```{req,res}``` 物件的行為。例如,它可以斷言 res 物件上的 http 狀態是否符合預期。(看下面的程式範例)
    -❌ **Otherwise:** A bug in Express middleware === a bug in all or most requests +❌ **否則:** Express middlewares 的 bug === 所有或大部分 request 的 bug
    -
    Code Examples +
    程式範例
    -### :clap:Doing It Right Example: Testing middleware in isolation without issuing network calls and waking-up the entire Express machine +### :clap: 正例:單獨測試 middleware,不發出網路請求或啟動整個 Express 伺服器 ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ```javascript -//the middleware we want to test +// the middleware we want to test const unitUnderTest = require("./middleware"); const httpMocks = require("node-mocks-http"); -//Jest syntax, equivelant to describe() & it() in Mocha +// Jest syntax, equivelant to describe() & it() in Mocha test("A request without authentication header, should return http status 403", () => { const request = httpMocks.createRequest({ method: "GET", From 7f94c393bfb564a7fe015a7324edb1a9b0d840fe Mon Sep 17 00:00:00 2001 From: yubintw Date: Sun, 12 Dec 2021 21:08:06 +0800 Subject: [PATCH 074/189] Translate Section 2.5 --- readme-zh-TW.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 182d862c..f839cbcf 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -873,23 +873,23 @@ test("A request without authentication header, should return http status 403", (

    -## ⚪ ️2.5 Measure and refactor using static analysis tools +## ⚪ ️2.5 使用靜態分析工具來測量與重構 -: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://www.sonarqube.org/) (4,900+ [stars](https://github.com/SonarSource/sonarqube)) and [Code Climate](https://codeclimate.com/) (2,000+ [stars](https://github.com/codeclimate/codeclimate)) +:white_check_mark: **建議:** 使用靜態分析工具可以幫助你客觀地提升程式品質並保持可維護性。你可以將靜態分析工具放在你的 CI 中。除了普通的 linting 外,它的主要賣點是查看多個檔案的上下文來檢查程式碼品質 (例如:發現程式有沒有重複定義的地方)、執行進階的分析 (例如:程式複雜度) 以及追蹤 code issue 的歷史和進度。有兩個工具供你使用:[SonarQube](https://www.sonarqube.org/) (6,300+ [stars](https://github.com/SonarSource/sonarqube)) 和 [Code Climate](https://codeclimate.com/) (2,300+ [stars](https://github.com/codeclimate/codeclimate))。 Credit: [Keith Holliday](https://github.com/TheHollidayInn)
    -❌ **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 +❌ **否則;** 程式碼的品質過差,再新的函式庫或功能都無法拯救你的 bug 和性能
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: CodeClimate, a commercial tool that can identify complex methods: +### :clap: 正例:CodeClimate,一個可以發現複雜方法的商業工具 ![](https://img.shields.io/badge/🔧%20Example%20using%20Code%20Climate-blue.svg "Examples with CodeClimate") From 146725bd88cc7c54a64894b7c08f7511ee6f54d0 Mon Sep 17 00:00:00 2001 From: yubintw Date: Mon, 13 Dec 2021 23:12:22 +0800 Subject: [PATCH 075/189] Translate Section 2.6 --- readme-zh-TW.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index f839cbcf..f712eef3 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -899,20 +899,21 @@ Credit: Date: Tue, 14 Dec 2021 00:08:43 +0800 Subject: [PATCH 076/189] Remove Section 2.7 (duplicate with Section 1.9) --- readme-zh-TW.md | 55 ------------------------------------------------- 1 file changed, 55 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index f712eef3..feadd24c 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -919,61 +919,6 @@ Credit: { - //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework - await DB.AddSeedDataFromJson('seed.json'); -}); -it("When updating site name, get successful confirmation", async () => { - //I know that site name "portal" exists - I saw it in the seed files - const siteToUpdate = await SiteService.getSiteByName("Portal"); - const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); - expect(updateNameResult).to.be(true); -}); -it("When querying by site name, get the right site", async () => { - //I know that site name "portal" exists - I saw it in the seed files - const siteToCheck = await SiteService.getSiteByName("Portal"); - expect(siteToCheck.name).to.be.equal("Portal"); //Failure! The previous test change the name :[ -}); - -``` - -
    - -### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data - -```javascript -it("When updating site name, get successful confirmation", async () => { - //test is adding a fresh new records and acting on the records only - const siteUnderTest = await SiteService.addSite({ - name: "siteForUpdateTest" - }); - const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); - expect(updateNameResult).to.be(true); -}); -``` - -
    -

    # Section 3️⃣: Frontend Testing From 6304e5f70fc6be0cda400672959257fabe57f0cf Mon Sep 17 00:00:00 2001 From: yubintw Date: Wed, 15 Dec 2021 23:30:47 +0800 Subject: [PATCH 077/189] Translate Section 3.1 --- readme-zh-TW.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index feadd24c..62a07a3a 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -164,7 +164,7 @@ describe('Products Service', function() {
    -❌ **否則:** 你不僅需要花很多時間去理解主要程式,而且本應是最簡單的部分 - 測試,也會讓你腦力耗盡。 +❌ **否則:** 你不僅需要花很多時間去理解主要程式,而且本應是最簡單的部分 - 測試,也會讓你腦力耗盡。
    @@ -684,7 +684,7 @@ describe("Order service", function() {
    -❌ **否則** 當看到一份毫無結構且數量眾多的測試報告時,讀者只能透過粗略地閱讀整份報告來總結,並將失敗的錯誤案例關聯起來。思考一個情況,當100個測試案例中有7個失敗時,看一個分層結構良好的測試報告與看一個扁平的測試結果清單相比,那些錯誤的測試案例很有可能都在同一個流程或分類底下,讀者將可以很快的推斷出錯誤的地方或看出哪部分是他們失敗的原因。 +❌ **否則:** 當看到一份毫無結構且數量眾多的測試報告時,讀者只能透過粗略地閱讀整份報告來總結,並將失敗的錯誤案例關聯起來。思考一個情況,當100個測試案例中有7個失敗時,看一個分層結構良好的測試報告與看一個扁平的測試結果清單相比,那些錯誤的測試案例很有可能都在同一個流程或分類底下,讀者將可以很快的推斷出錯誤的地方或看出哪部分是他們失敗的原因。
    @@ -921,23 +921,23 @@ Credit:
    uiElement.textContent); const allRealVIPUsers = allUsers.filter(user => user.vip).map(user => user.name); - expect(allRenderedUsers).toEqual(allRealVIPUsers); //compare data with data, no UI here + expect(allRenderedUsers).toEqual(allRealVIPUsers); // compare data with data, no UI here }); ```
    -### :thumbsdown: Anti-Pattern Example: Assertion mix UI details and data +### :thumbsdown: 反例:混雜了 UI 與資料的斷言 ```javascript test("When flagging to show only VIP, should display only VIP members", () => { From 80746a5fc804355652269df1460b756658c2625d Mon Sep 17 00:00:00 2001 From: yubintw Date: Sat, 18 Dec 2021 21:12:55 +0800 Subject: [PATCH 078/189] Translate Section 3.2 --- readme-zh-TW.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 62a07a3a..73f02f4e 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -977,21 +977,21 @@ test("When flagging to show only VIP, should display only VIP members", () => {

    -## ⚪ ️ 3.2 Query HTML elements based on attributes that are unlikely to change +## ⚪ ️ 3.2 使用不易改變的屬性來查询 HTML 元素 -: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/logic 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 +:white_check_mark: **建議:** 使用不太容易受畫面變更而影響的屬性來查詢 HTML 元素 (例如 form label,而不是 CSS selector)。如果指定的元素沒有這樣的屬性,則創建一個專用的測試屬性,如 `test-id-submit-button`。這樣做不僅可以確保您的功能/邏輯測試不會因為外觀變化而中斷,而且整個團隊可以清楚地看到,測試案例使用了這個元素和屬性,不應該刪除它。
    -❌ **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' +❌ **否則:** 假設你想要測試一個跨越許多組件、邏輯和服務的登入功能,一切都設置得很完美 - stub、spy、Ajax 的呼叫都是隔離的。看似一切都很完美,但卻發現測試失敗了,因為開發者將 div 的 class 從 `thick-border` 改為 `thin-border`。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: Querying an element using a dedicated attribute for testing +### :clap: 正例: 使用專用的 attribute 來查詢元素來進行測試 ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") @@ -1020,7 +1020,7 @@ test("Whenever no data is passed to metric, show 0 as default", () => {
    -### :thumbsdown: Anti-Pattern Example: Relying on CSS attributes +### :thumbsdown: 反例: 依靠於 CSS attributes ```html From e1c6f15361601df618ebe4e5397b0928228aab94 Mon Sep 17 00:00:00 2001 From: yubintw Date: Mon, 20 Dec 2021 22:15:35 +0800 Subject: [PATCH 079/189] Translate Section 3.3 --- readme-zh-TW.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 73f02f4e..b9f76e82 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1041,23 +1041,23 @@ test("Whenever no data is passed, error metric shows zero", () => {
    -## ⚪ ️ 3.3 Whenever possible, test with a realistic and fully rendered component +## ⚪ ️ 3.3 如果可以,使用真實且完全渲染的組件來進行測試 -: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://github.com/goldbergyoni/javascript-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 +:white_check_mark: **建議:** 只要尺寸合適,像使用者那樣從外部測試你的組件,完全渲染 UI,對其進行操作,並斷言對那些 UI 的行為是否符合預期。避免各種 mock、partial 和 shallow rendering - 這樣做可能會因為缺乏細節而導致有未捕捉到的 bug,而且由於測試會擾亂內部的結構而使得維護變得更加困難 (參考 堅持黑箱測試)。如果其中一個子組件明顯拖慢速度 (如 動畫) 或很難去設定,可以考慮使用假的組件去替換它。 -With all that said, a word of caution is in order: this technique works for small/medium 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 +綜上所說,需要注意的是:這種技術適用於包含合理大小子組件的中小型組件。完全渲染一個有太多子組件的組件會讓他很難被看出失敗的原因 (root cause analysis),而且可能會非常慢。在這種情況下,可以對那些很肥的父組件撰寫少量的測試,並對其子組件多寫幾個測試。
    -❌ **Otherwise:** When poking into a component's internal by invoking its private methods, and checking the inner state - you would have to refactor all tests when refactoring the components implementation. Do you really have a capacity for this level of maintenance? +❌ **否則:** 呼叫組件的私有方法來測試組件的內部狀態。後續重構組件時你必須重構所有測試。你真的有能力進行這種程度的維護嗎?
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: Working realistically with a fully rendered component +### :clap: 正例: 操作一個充分渲染的真實組件 ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Enzyme-blue.svg "Examples with Enzyme") @@ -1075,7 +1075,7 @@ class Calendar extends React.Component { } } -//Examples use React & Enzyme +// Examples use React & Enzyme test("Realistic approach: When clicked to show filters, filters are displayed", () => { // Arrange const wrapper = mount(); @@ -1089,7 +1089,7 @@ test("Realistic approach: When clicked to show filters, filters are displayed", }); ``` -### :thumbsdown: Anti-Pattern Example: Mocking the reality with shallow rendering +### :thumbsdown: 反例: 使用 shallow rendering 來測試 ```javascript test("Shallow/mocked approach: When clicked to show filters, filters are displayed", () => { From d4248a8c42b068f7e433b37a845866c54d1a4d79 Mon Sep 17 00:00:00 2001 From: yubintw Date: Thu, 20 Jan 2022 22:13:17 +0800 Subject: [PATCH 080/189] Translate Section 3.4 --- readme-zh-TW.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index b9f76e82..28536e66 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1113,20 +1113,21 @@ test("Shallow/mocked approach: When clicked to show filters, filters are display
    -## ⚪ ️ 3.4 Don't sleep, use frameworks built-in support for async events. Also try to speed things up +## ⚪ ️ 3.4 不要 sleep,善用框架內建對非同步事件的支援,並試著加速他 + +:white_check_mark: **建議:** 在許多情況下,被測試單元的完成時間是未知的 (例如,因為動畫而延遲了元件的出現) — 在這種情況下,不要 sleep (例如使用 setTimeout),而是使用大多數框架提供的更靠譜的方法。一些函示庫允許等待操作 (例如 [Cypress .request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)),另一些函示庫提供用於等待的 API,如 [@testing-library/dom 的方法 wait(expect(element))](https://testing-library.com/docs/guide-disappearance)。有時後,更優雅的方法是 stub 那些比較慢的資源,像是 API,然後一旦響應時間變得確定,組件就可以顯式地重新渲染。當依賴一些 sleep 的外部組件時,[加快時鐘的速度](https://jestjs.io/docs/en/timer-mocks)或許能提供幫助。 sleep 是一種需要避免的模式,因為它會導致你的測試變得緩慢或有風險(如果等待的時間太短)。當 sleep 和輪詢不可避免且測試框架原生不支持時,一些 npm 的函示庫 (如 [wait-for-expect](https://www.npmjs.com/package/wait-for-expect)) 可以幫助解決半確定性問題。 -:white_check_mark: **Do:** In many cases, the unit under test completion time is just unknown (e.g. animation suspends element appearance) - in that case, avoid sleeping (e.g. setTimeOut) and prefer more deterministic methods that most platforms provide. Some libraries allows awaiting on operations (e.g. [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), other provide API for waiting like [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). Sometimes a more elegant way is to stub the slow resource, like API for example, and then once the response moment becomes deterministic the component can be explicitly re-rendered. When depending upon some external component that sleeps, it might turn useful to [hurry-up the clock](https://jestjs.io/docs/en/timer-mocks). Sleeping is a pattern to avoid because it forces your test to be slow or risky (when waiting for a too short period). Whenever sleeping and polling is inevitable and there's no support from the testing framework, some npm libraries like [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) can help with a semi-deterministic solution
    -❌ **Otherwise:** When sleeping for a long time, tests will be an order of magnitude slower. When trying to sleep for small numbers, test will fail when the unit under test didn't respond in a timely fashion. So it boils down to a trade-off between flakiness and bad performance +❌ **否則:** 當 sleep 的時間太長時,測試速度會慢上一個數量級。當嘗試縮短 sleep 時間時,如果被測試的單元沒有及時響應,測試將會失敗。這時你不得不在脆弱的測試和糟糕的性能之間進行權衡。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: E2E API that resolves only when the async operations is done (Cypress) +### :clap: 正例: E2E API 在非同步的處理完後 resolves (Cypress) ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") @@ -1138,7 +1139,7 @@ cy.wait("@products"); // wait for route to appear // this line will get executed only when the route is ready ``` -### :clap: Doing It Right Example: Testing library that waits for DOM elements +### :clap: 正例:測試的函示庫等待 DOM 元素 ```javascript // @testing-library/dom @@ -1155,7 +1156,7 @@ test("movie title appears", async () => { }); ``` -### :thumbsdown: Anti-Pattern Example: custom sleep code +### :thumbsdown: 反例: 自製的 sleep 程式 ```javascript test("movie title appears", async () => { From 8328c8de690fcd17e7d494f53dada141204b19a3 Mon Sep 17 00:00:00 2001 From: yubintw Date: Fri, 28 Jan 2022 22:36:13 +0800 Subject: [PATCH 081/189] Translate Section 3.5 --- readme-zh-TW.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 28536e66..7417ee20 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1180,21 +1180,21 @@ test("movie title appears", async () => {
    -## ⚪ ️ 3.5 Watch how the content is served over the network +## ⚪ ️ 3.5 觀察資源經由網路被提供的情況 ![](https://img.shields.io/badge/🔧%20Example%20using%20Google%20LightHouse-blue.svg "Examples with Lighthouse") -✅ **Do:** Apply some active monitor that ensures the page load under real network is optimized - this includes any UX concern like slow page load or un-minified bundle. The inspection tools market is no short: basic tools like [pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) can be easily configured to watch whether the server is alive and response under a reasonable SLA. This only scratches the surface of what might get wrong, hence it's preferable to opt for tools that specialize in frontend (e.g. [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) and perform richer analysis. The focus should be on symptoms, metrics that directly affect the UX, like page load time, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [time until the page gets interactive (TTI)](https://calibreapp.com/blog/time-to-interactive/). On top of that, one may also watch for technical causes like ensuring the content is compressed, time to the first byte, optimize images, ensuring reasonable DOM size, SSL and many others. It's advisable to have these rich monitors both during development, as part of the CI and most important - 24x7 over the production's servers/CDN +✅ **建議:** 使用一些活動監視器,以確保在真實網路下的頁面載入情況是最佳的 — 這包含一些使用者體驗的問題:像是緩慢的頁面載入時間或未經壓縮的資源。市面上有很豐富的檢查工具:像 [pingdom](https://www.pingdom.com/)、AWS CloudWatch、[GCP StackDriver](https://cloud.google.com/monitoring/uptime-checks/) 這些工具可以很容易地監視伺服器是否正常運作著,是否有在合理的 SLA 下回應。不過這只解決了表面上的問題,最好選擇前端專用的工具 (如 [lighthouse](https://developers.google.com/web/tools/lighthouse/)、[pagespeed](https://developers.google.com/speed/pagespeed/insights/)) 來進行更全面的分析。並聚焦在那些直接影響使用者體驗的指標上,像是頁面載入時間、[有意義的繪製](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint)、[頁面可互動時間(TTI)](https://calibreapp.com/blog/time-to-interactive/)。更重要的是,還可以關注其他原因,像是確保內容有被壓縮、[第一個 byte 的時間](https://developer.mozilla.org/en-US/docs/Glossary/time_to_first_byte)、圖片的最佳化、並確保合理的 DOM 尺寸、SSL 或其他。建議在開發期間將這些監視器納入 CI 的一部分,以及更重要的,在 24x7 的 production 伺服器/ CDN 上使用它們。
    -❌ **Otherwise:** It must be disappointing to realize that after such great care for crafting a UI, 100% functional tests passing and sophisticated bundling - the UX is horrible and slow due to CDN misconfiguration +❌ **否則:** 設計了一個精美的 UI、且通過了 100% 的功能測試與精心的包裝,使用者體驗卻因為 CDN 的錯誤設定而變得糟糕及緩慢。
    -
    Code Examples +
    程式範例 -### :clap: Doing It Right Example: Lighthouse page load inspection report +### :clap: 正例:Lighthouse 的頁面載入檢測報告 ![](/assets/lighthouse2.png "Lighthouse page load inspection report") From cf5c4bb3e6d26a3d24723d38963163a08a13bc8f Mon Sep 17 00:00:00 2001 From: yubintw Date: Sat, 29 Jan 2022 22:03:20 +0800 Subject: [PATCH 082/189] Translate Section 3.6 --- readme-zh-TW.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 7417ee20..f17400a3 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1204,19 +1204,19 @@ test("movie title appears", async () => { ## ⚪ ️ 3.6 Stub flaky and slow resources like backend APIs -:white_check_mark: **Do:** When coding your mainstream tests (not E2E tests), avoid involving any resource that is beyond your responsibility and control like backend API and use stubs instead (i.e. test double). Practically, instead of real network calls to APIs, use some test double library (like [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble), etc) for stubbing the API response. The main benefit is preventing flakiness - testing or staging APIs by definition are not highly stable and from time to time will fail your tests although YOUR component behaves just fine (production env was not meant for testing and it usually throttles requests). Doing this will allow simulating various API behavior that should drive your component behavior as when no data was found or the case when API throws an error. Last but not least, network calls will greatly slow down the tests +:white_check_mark: **建議:** 當撰寫你主要的測試 (不是 E2E 測試) 時,避免接觸任何超出你職責和控制範圍的資源,如後端 API,而是使用 stub (測試替身)。使用一些測試替身的函式庫 (如 [Sinon](https://sinonjs.org/)、[Test doubles](https://www.npmjs.com/package/testdouble) 等) 來 stub API 的回應,而不是真正的對 API 進行呼叫。最大的好處是防止出現故障 — 測試或 API 的定義常常在變動的時候,儘管組件的表現正確 (生產環境不適合進行測試,它通常對 API 的呼叫進行限制),但有時會呼叫失敗。通過 stub 來模擬各種 API 行為,比如當沒有找到資料或 API 拋出錯誤時測試組件行為。最後但並非最不重要的原因是,經過網絡的呼叫將會大大降低執行測試的速度。
    -❌ **Otherwise:** The average test runs no longer than few ms, a typical API call last 100ms>, this makes each test ~20x slower +❌ **否則:** 平均執行測試的時間不再只是幾毫秒而已,一個普通的 API 呼叫至少需要 100 毫秒,這會讓你的測試慢 20 倍以上。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: Stubbing or intercepting API calls +### :clap: 正例: Stub 或攔截 API 的呼叫 ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") From d434fe321fc2eda9cde6764b2ffd549ed669880e Mon Sep 17 00:00:00 2001 From: yubintw Date: Sun, 30 Jan 2022 18:01:09 +0800 Subject: [PATCH 083/189] Translate Section 3.7 --- readme-zh-TW.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index f17400a3..c4572a38 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1256,13 +1256,13 @@ test("When no products exist, show the appropriate message", () => {
    -## ⚪ ️ 3.7 Have very few end-to-end tests that spans the whole system +## ⚪ ️ 3.7 寫幾個跨越整個系統的 E2E 測試 -:white_check_mark: **Do:** Although E2E (end-to-end) usually means UI-only testing with a real browser (See [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)), for other they mean tests that stretch the entire system including the real backend. The latter type of tests is highly valuable as they cover integration bugs between frontend and backend that might happen due to a wrong understanding of the exchange schema. They are also an efficient method to discover backend-to-backend integration issues (e.g. Microservice A sends the wrong message to Microservice B) and even to detect deployment failures - there are no backend frameworks for E2E testing that are as friendly and mature as UI frameworks like [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). The downside of such tests is the high cost of configuring an environment with so many components, and mostly their brittleness - given 50 microservices, even if one fails then the entire E2E just failed. For that reason, we should use this technique sparingly and probably have 1-10 of those and no more. That said, even a small number of E2E tests are likely to catch the type of issues they are targeted for - deployment & integration faults. It's advisable to run those over a production-like staging environment +:white_check_mark: **建議:** 雖然 E2E (end to end,端到端) 通常代表在真實瀏覽器中進行 UI 測試 (參考 3.6 項),某些情況下,它們表示覆蓋整個系統的測試,包括連接真正的後端。後者的測試非常有價值,因為它們涵蓋那些前端和後端之間整合的問題,這些問題可能是由於溝通上,schema 產生誤會所導致。它們也是一種有效的方法來發現 backend-to-backend 的整合問題 (例如微服務 A 將錯誤的訊息發送給微服務 B) 甚至可以檢測出部署上的錯誤,目前後端沒有像前端 UI 測試工具如 [Cypress](https://www.cypress.io/) 或 [Puppeteer](https://github.com/GoogleChrome/puppeteer) 一樣友善且成熟的 E2E 框架。這種測試的缺點是,設定涵蓋這麼多組件的環境的成本很高,而且大多數組件都很脆弱 — 假設有 50 個微服務,只要其中一個死掉,整個 E2E 就會失敗。基於這個原因,我們應該少用這種技術,大概 1-10 個就夠了。也就是說,即使是少量的 E2E 測試也有機會捕獲它們 — 部署或整合的問題。建議在與生產環境相似的 stage 運行它們。
    -❌ **Otherwise:** UI might invest much in testing its functionality only to realizes very late that the backend returned payload (the data schema the UI has to work with) is very different than expected +❌ **否則:** UI 可能在功能測試上花費了大量的精力,但最後才發現後端回傳的內容 (UI 要使用的資料格式) 與預期中的不一樣。
    From 90aa6a1612ac68ccce69c7d83860abbb962301a2 Mon Sep 17 00:00:00 2001 From: yubintw Date: Mon, 31 Jan 2022 21:08:55 +0800 Subject: [PATCH 084/189] Translate Section 3.8 --- readme-zh-TW.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index c4572a38..9f5181c0 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1258,7 +1258,7 @@ test("When no products exist, show the appropriate message", () => { ## ⚪ ️ 3.7 寫幾個跨越整個系統的 E2E 測試 -:white_check_mark: **建議:** 雖然 E2E (end to end,端到端) 通常代表在真實瀏覽器中進行 UI 測試 (參考 3.6 項),某些情況下,它們表示覆蓋整個系統的測試,包括連接真正的後端。後者的測試非常有價值,因為它們涵蓋那些前端和後端之間整合的問題,這些問題可能是由於溝通上,schema 產生誤會所導致。它們也是一種有效的方法來發現 backend-to-backend 的整合問題 (例如微服務 A 將錯誤的訊息發送給微服務 B) 甚至可以檢測出部署上的錯誤,目前後端沒有像前端 UI 測試工具如 [Cypress](https://www.cypress.io/) 或 [Puppeteer](https://github.com/GoogleChrome/puppeteer) 一樣友善且成熟的 E2E 框架。這種測試的缺點是,設定涵蓋這麼多組件的環境的成本很高,而且大多數組件都很脆弱 — 假設有 50 個微服務,只要其中一個死掉,整個 E2E 就會失敗。基於這個原因,我們應該少用這種技術,大概 1-10 個就夠了。也就是說,即使是少量的 E2E 測試也有機會捕獲它們 — 部署或整合的問題。建議在與生產環境相似的 stage 運行它們。 +:white_check_mark: **建議:** 雖然 E2E (end to end,端到端) 通常代表在真實瀏覽器中進行 UI 測試 (參考 3.6 節),某些情況下,它們表示覆蓋整個系統的測試,包括連接真正的後端。後者的測試非常有價值,因為它們涵蓋那些前端和後端之間整合的問題,這些問題可能是由於溝通上,schema 產生誤會所導致。它們也是一種有效的方法來發現 backend-to-backend 的整合問題 (例如微服務 A 將錯誤的訊息發送給微服務 B) 甚至可以檢測出部署上的錯誤,目前後端沒有像前端 UI 測試工具如 [Cypress](https://www.cypress.io/) 或 [Puppeteer](https://github.com/GoogleChrome/puppeteer) 一樣友善且成熟的 E2E 框架。這種測試的缺點是,設定涵蓋這麼多組件的環境的成本很高,而且大多數組件都很脆弱 — 假設有 50 個微服務,只要其中一個死掉,整個 E2E 就會失敗。基於這個原因,我們應該少用這種技術,大概 1-10 個就夠了。也就是說,即使是少量的 E2E 測試也有機會捕獲它們 — 部署或整合的問題。建議在與生產環境相似的 stage 運行它們。
    @@ -1266,21 +1266,21 @@ test("When no products exist, show the appropriate message", () => {
    -## ⚪ ️ 3.8 Speed-up E2E tests by reusing login credentials +## ⚪ ️ 3.8 藉由重複使用登入憑證來加速 E2E 測試 -:white_check_mark: **Do:** In E2E tests that involve a real backend and rely on a valid user token for API calls, it doesn't payoff to isolate the test to a level where a user is created and logged-in in every request. Instead, login only once before the tests execution start (i.e. before-all hook), save the token in some local storage and reuse it across requests. This seem to violate one of the core testing principle - keep the test autonomous without resources coupling. While this is a valid worry, in E2E tests performance is a key concern and creating 1-3 API requests before starting each individual tests might lead to horrible execution time. Reusing credentials doesn't mean the tests have to act on the same user records - if relying on user records (e.g. test user payments history) than make sure to generate those records as part of the test and avoid sharing their existence with other tests. Also remember that the backend can be faked - if your tests are focused on the frontend it might be better to isolate it and stub the backend API (see [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)). +white_check_mark: **建議:** 在涉及真實的後端並必須使用有效的使用者 token 進行 API 呼叫的 E2E 測試中,我們沒有必要將每個測試都從「新增使用者並登錄」開始。相反的,在測試執行開始之前只登錄一次 (使用 before-all hook),將 token 儲存在本地端中,並在每個 request 之間重複使用它。雖然這似乎違反了測試的核心原則之一 — 保持測試的獨立性,不要耦合資源。這是一個合理的擔憂,但在 E2E 測試中,執行測試的性能是一個關鍵問題,在執行每個測試案例之前呼叫 1-3 個 API 可能會大大增加執行時間。重複使用憑證並不意味著測試必須基於相同的使用者資料 — 如果相依於使用者資料 (例如測試使用者付款的歷史記錄),那麼要確保產生這些資料來作為測試的一部分,並避免與其他測試共享它們。還要記住,後端是可以 fake 的 — 如果你的重點是測試前端,那麼最好隔離它,然後 stub 後端 API (參考 3.6 節)。
    -❌ **Otherwise:** Given 200 test cases and assuming login=100ms = 20 seconds only for logging-in again and again +❌ **否則:** 給定 200 個測試案例,假設登錄需要花費的時間為 100ms,則至少需要花費 20s,在這一遍遍的登錄上。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: Logging-in before-all and not before-each +### :clap: 正例: 在 before-all 中登錄,而不是 before-each ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") From a70d199278da253f8cdc3d7931d1c754ac60e7e7 Mon Sep 17 00:00:00 2001 From: "YuBin, Hsu" <31545456+yubinTW@users.noreply.github.com> Date: Tue, 1 Feb 2022 14:06:25 +0800 Subject: [PATCH 085/189] Update code example of 3.9 --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 1e7990b3..fd7e398c 100644 --- a/readme.md +++ b/readme.md @@ -1376,9 +1376,9 @@ it("When doing smoke testing over all page, should load them all successfully", // using any E2E suite cy.visit("https://mysite.com/home"); cy.contains("Home"); - cy.contains("https://mysite.com/Login"); + cy.visit("https://mysite.com/Login"); cy.contains("Login"); - cy.contains("https://mysite.com/About"); + cy.visit("https://mysite.com/About"); cy.contains("About"); }); ``` From 9aca6a1f4fb3959694c0977af625996e834d0582 Mon Sep 17 00:00:00 2001 From: yubintw Date: Tue, 1 Feb 2022 22:45:01 +0800 Subject: [PATCH 086/189] Translate Section 3.9 --- readme-zh-TW.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 9f5181c0..3a261503 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1314,21 +1314,21 @@ beforeEach(setUser => () {
    -## ⚪ ️ 3.9 Have one E2E smoke test that just travels across the site map +## ⚪ ️ 3.9 寫一個走過整個網站的 E2E 冒煙測試 -:white_check_mark: **Do:** For production monitoring and development-time sanity check, run a single E2E test that visits all/most of the site pages and ensures no one breaks. This type of test brings a great return on investment as it's very easy to write and maintain, but it can detect any kind of failure including functional, network and deployment issues. Other styles of smoke and sanity checking are not as reliable and exhaustive - some ops teams just ping the home page (production) or developers who run many integration tests which don't discover packaging and browser issues. Goes without saying that the smoke test doesn't replace functional tests rather just aim to serve as a quick smoke detector +:white_check_mark: **建議:** 為了 production 環境的監控及開發時期的完整性檢查,執行一個 E2E 測試,讓這個測試走訪過所有或大多數的網站頁面,並確保那些頁面沒有損毀。這類型的測試投資報酬率很高,因為他很容易去撰寫及維護,卻可以檢測出各種類型的故障,包括功能性、網路或佈屬的問題。其他類型的冒煙測試或完整性檢查並沒有那麼可靠及詳盡 - 有些 ops 團隊只是 ping 網站首頁 (在production環境),或開發人員執行了一些整合測試,卻沒發現到打包或瀏覽器的問題。毫無疑問的,冒煙測試並不會取代功能測試,而只是作為一個快速的煙霧偵測器。
    -❌ **Otherwise:** Everything might seem perfect, all tests pass, production health-check is also positive but the Payment component had some packaging issue and only the /Payment route is not rendering +❌ **否則:** 一切看似很完美,所有的測試都通過了,在 production 環境的健康狀態檢查也是 ok 的,但 Payment 這個組件有一些打包的問題,導致 /Paymout 這個路徑沒有被渲染。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: Smoke travelling across all pages +### :clap: 正例:一個跑過所有頁面的冒煙測試 ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") @@ -1338,9 +1338,9 @@ it("When doing smoke testing over all page, should load them all successfully", // using any E2E suite cy.visit("https://mysite.com/home"); cy.contains("Home"); - cy.contains("https://mysite.com/Login"); + cy.visit("https://mysite.com/Login"); cy.contains("Login"); - cy.contains("https://mysite.com/About"); + cy.visit("https://mysite.com/About"); cy.contains("About"); }); ``` From b5d2abd113101fbe2d2f741d3b6a918fe4f6ff33 Mon Sep 17 00:00:00 2001 From: yubintw Date: Wed, 2 Feb 2022 22:23:17 +0800 Subject: [PATCH 087/189] Translate Section 3.10 --- readme-zh-TW.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 3a261503..1602b882 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1349,19 +1349,19 @@ it("When doing smoke testing over all page, should load them all successfully",
    -## ⚪ ️ 3.10 Expose the tests as a live collaborative document +## ⚪ ️ 3.10 將測試作為一個活的協作文件來看待 -:white_check_mark: **Do:** Besides increasing app reliability, tests bring another attractive opportunity to the table - serve as live app documentation. Since tests inherently speak at a less-technical and product/UX language, using the right tools they can serve as a communication artifact that greatly aligns all the peers - developers and their customers. For example, some frameworks allow expressing the flow and expectations (i.e. tests plan) using a human-readable language so any stakeholder, including product managers, can read, approve and collaborate on the tests which just became the live requirements document. This technique is also being referred to as 'acceptance test' as it allows the customer to define his acceptance criteria in plain language. This is [BDD (behavior-driven testing)](https://en.wikipedia.org/wiki/Behavior-driven_development) at its purest form. One of the popular frameworks that enable this is [Cucumber which has a JavaScript flavor](https://github.com/cucumber/cucumber-js), see example below. Another similar yet different opportunity, [StoryBook](https://storybook.js.org/), allows exposing UI components as a graphic catalog where one can walk through the various states of each component (e.g. render a grid w/o filters, render that grid with multiple rows or with none, etc), see how it looks like, and how to trigger that state - this can appeal also to product folks but mostly serves as live doc for developers who consume those components. +:white_check_mark: **建議:** 除了提升應用程式的可靠性,測試還有一個非常誘人的應用 - 作為活的程式文件。由於測試程式本質上使用的是一種技術含量較低的產品/ UX 語言,因此使用正確的工具可以將他們轉換成一種易於溝通的媒介,方便開發人員與他們的使用者進行協調。舉例來說,有一些框架可以使用人類可閱讀的語言來表達流程與期望 (如,測試計畫),這樣一來,所有相關人員包括產品經理,都可以對測試進行閱讀、批准以及協作,如此一來.這個測試就成了活的需求文件。這樣的技術也被稱作 "驗收測試",因為它可以讓使用者用簡單的語言定義驗收標準。這是最純粹的 [BDD (行為驅動測試)](https://en.wikipedia.org/wiki/Behavior-driven_development),其中一個支援這個功能的框架是 [Cucumber](https://github.com/cucumber/cucumber-js),可以參考下面的程式範例。另一個相似但不同應用情境的是 [StoryBook](https://storybook.js.org/),它可以把 UI 的組件弄成圖形化的目錄,讓使用者可以瀏覽每個組件的各種狀態 (例如一個 grid w/o filter,讓他畫出多個 row 或沒有 row 等。),看他長得怎樣以及如何去觸發他的不同狀態 - 這也可以提供給產品相關人員,但主要是作為活的文件給使用這些組建的開發者們。 -❌ **Otherwise:** After investing top resources on testing, it's just a pity not to leverage this investment and win great value +❌ **否則:** 在測試上已經耗費了大量的資源,如果不好好利用這項投資來獲取更大的價值,非常可惜。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: Describing tests in human-language using cucumber-js +### :clap: 正例:利用 cucumber-js 以人類可閱讀的語言來描述測試 ![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Examples using Cucumber") @@ -1382,7 +1382,7 @@ Feature: Twitter new tweet ``` -### :clap: Doing It Right Example: Visualizing our components, their various states and inputs using Storybook +### :clap: 正例:利用 Storybook 來展示組件的的不同狀態及輸入 ![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") From bb7522c99b62f0cdc395074d5d5c4a9ce07e0deb Mon Sep 17 00:00:00 2001 From: yubintw Date: Fri, 4 Feb 2022 20:13:55 +0800 Subject: [PATCH 088/189] Translate Section 3.11 --- readme-zh-TW.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 1602b882..b05f8c2a 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1392,27 +1392,27 @@ Feature: Twitter new tweet

    -## ⚪ ️ 3.11 Detect visual issues with automated tools +## ⚪ ️ 3.11 使用自動化工作來偵測視覺問題 -:white_check_mark: **Do:** Setup automated tools to capture UI screenshots when changes are presented and detect visual issues like content overlapping or breaking. This ensures that not only the right data is prepared but also the user can conveniently see it. This technique is not widely adopted, our testing mindset leans toward functional tests but it's the visuals what the user experience and with so many device types it's very easy to overlook some nasty UI bug. Some free tools can provide the basics - generate and save screenshots for the inspection of human eyes. While this approach might be sufficient for small apps, it's flawed as any other manual testing that demands human labor anytime something changes. On the other hand, it's quite challenging to detect UI issues automatically due to the lack of clear definition - this is where the field of 'Visual Regression' chime in and solve this puzzle by comparing old UI with the latest changes and detect differences. Some OSS/free tools can provide some of this functionality (e.g. [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>) but might charge significant setup time. The commercial line of tools (e.g. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) takes is a step further by smoothing the installation and packing advanced features like management UI, alerting, smart capturing by eliminating 'visual noise' (e.g. ads, animations) and even root cause analysis of the DOM/CSS changes that led to the issue +:white_check_mark: **建議:** 設定自動化工具,在出現變化的時候擷取 UI 畫面,並檢測是否有內容重疊或破圖等問題。這樣做不僅可以確保資料的正確性,使用者也可以很方便的看到他們。這樣的技術沒有被廣泛的使用,我們的測試思維比較傾向於功能測試,但這代表了真實的使用者體驗,而且可以輕易地發現像是會在多個設備上展示的 UI 問題。有些免費的工具可以提供一些基本的功能 - 產生或儲存螢幕截圖,讓肉眼可以檢查。雖然這種方法對於規模較小的應用程式已經足夠,但他的缺點就跟任何手動測試一樣 - 在任何變更後都需要人力來處理。另一方面,由於缺乏清楚的定義,自動檢測 UI 問題非常有挑戰性,視覺回歸 (Visual Regression) 解決這難題的方法是,比較舊的 UI 與最新版的的差異,並顯示檢測結果。一些開源/免費的工具可以提供這樣的能力 (例如,[wraith](https://github.com/BBC-News/wraith), [PhantomCSS](https://github.com/HuddleEng/PhantomCSS)),但他們的安裝比較耗時。一些商業工具 (例如,[Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) 則更進一步,他們簡化了安裝流程,並封裝了許多進階的功能,像是管理 UI、警告、藉由過濾 "視覺噪音"(如,廣告、動畫)來進行智慧抓取,甚至可以分析出造成 DOM/CSS 發生問題的根本原因。
    -❌ **Otherwise:** How good is a content page that display great content (100% tests passed), loads instantly but half of the content area is hidden? +❌ **否則:** 一個顯示內容且通過100%的功能測試的頁面,載入速度非常快,但有一半的內容都被隱藏了,這樣的頁面是好的嗎?
    -
    Code Examples +
    程式範例
    -### :thumbsdown: Anti-Pattern Example: A typical visual regression - right content that is served badly +### :thumbsdown: 反例:一個典型的 visual regression,右側內容顯示異常 ![alt text](assets/amazon-visual-regression.jpeg "Amazon page breaks")
    -### :clap: Doing It Right Example: Configuring wraith to capture and compare UI snapshots +### :clap: 正例:設定 wraith 來抓取並比對 UI 截圖 ![](https://img.shields.io/badge/🔨%20Example%20using%20Wraith-blue.svg "Using Wraith") @@ -1441,7 +1441,7 @@ paths: path: /subscribe ``` -### :clap: Doing It Right Example: Using Applitools to get snapshot comparison and other advanced features +### :clap: 正例:使用 Applitools 來獲得截圖的比對結果以及其他進階功能 ![](https://img.shields.io/badge/🔨%20Example%20using%20AppliTools-blue.svg "Using Applitools") ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") From 4c39ab97c600f9beb0830591577f65cc46c2f382 Mon Sep 17 00:00:00 2001 From: yubintw Date: Sat, 5 Feb 2022 23:42:49 +0800 Subject: [PATCH 089/189] Translate Section 4.1 --- readme-zh-TW.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index b05f8c2a..6eab5531 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1468,33 +1468,33 @@ describe("visual validation", () => {

    -# Section 4️⃣: Measuring Test Effectiveness +# 第 4 章:測量測試效果

    -## ⚪ ️ 4.1 Get enough coverage for being confident, ~80% seems to be the lucky number +## ⚪ ️ 4.1 藉由足夠的覆蓋率來獲得信心,~80% 看起來是個幸運數 -:white_check_mark: **Do:** The purpose of testing is to get enough confidence for moving fast, obviously the more code is tested the more confident the team can be. Coverage is a measure of how many code lines (and branches, statements, etc) are being reached by the tests. So how much is enough? 10–30% is obviously too low to get any sense about the build correctness, on the other side 100% is very expensive and might shift your focus from the critical paths to the exotic corners of the code. The long answer is that it depends on many factors like the type of application — if you’re building the next generation of Airbus A380 than 100% is a must, for a cartoon pictures website 50% might be too much. Although most of the testing enthusiasts claim that the right coverage threshold is contextual, most of them also mention the number 80% as a thumb of a rule ([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)) that presumably should satisfy most of the applications. +:white_check_mark: **建議:** 測試的目的是為了得到足夠的信心去進行更快速的迭代,很顯然地,越多的程式被測試到,團隊會更為自信。測試覆蓋率是用來測量測試程式走過多少行 (或 branch, statement, ...)。那要多少才夠?10% ~ 30% 明顯無法證明專案的正確性,但 100% 則可能會過於浪費時間,而且可能會迫使你關注太多枝微末節的程式。答案是,需要參考很多因素並取決於應用程式的類型,如果你正在建立次世代的空中巴士 A380,那 100% 的覆蓋率是必須的;然而對於一個卡通圖片的網站來說,50% 的覆蓋率可能太高。雖然大部分的測試愛好者都說覆蓋率的最低門檻要依客觀因素來決定,但他們都提到,根據經驗 80% 是個不錯的數字。([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)),足夠滿足大多數的應用程式。 -Implementation tips: You may want to configure your continuous integration (CI) to have a coverage threshold ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) and stop a build that doesn’t stand to this standard (it’s also possible to configure threshold per component, see code example below). On top of this, consider detecting build coverage decrease (when a newly committed code has less coverage) — this will push developers raising or at least preserving the amount of tested code. All that said, coverage is only one measure, a quantitative based one, that is not enough to tell the robustness of your testing. And it can also be fooled as illustrated in the next bullets +實作建議:你可能會想在 CI 工具中設定測試覆蓋率的門檻 ([Jest link](https://jestjs.io/docs/configuration#collectcoverage-boolean)),並中斷那些未達覆蓋率門檻的建置 (也可以為每個組件設定覆蓋率門檻,參考下面的程式範例)。另外,也可以監測建置的覆蓋率是否下降 (當有一個新的且覆蓋率較低的程式被 commit) — 這將促使開發者去提升或至少維持一定的測試數量。說了很多,但測試覆蓋率只是一個量化出來的數值,它並不能證明你的測試是強壯的。或許你也會被他騙到 (參考下一小節的內容)。
    -❌ **Otherwise:** Confidence and numbers go hand in hand, without really knowing that you tested most of the system — there will also be some fear and fear will slow you down +❌ **否則:** 自信與數字是相輔相成的,如果無法確保測試已經覆蓋了大部分的系統,你將感到害怕,且恐懼會使你變慢。
    -
    Code Examples +
    程式範例
    -### :clap: Example: A typical coverage report +### :clap: 正例:一個典型的覆蓋率報告 ![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "A typical coverage report")
    -### :clap: Doing It Right Example: Setting up coverage per component (using Jest) +### :clap: 正例:為每個組件設定覆蓋率 (使用 Jest) ![](https://img.shields.io/badge/🔨%20Example%20using%20Jest-blue.svg "Using Jest") From aa6eabe90a6d1fff9c7d284a0ed221db0667908d Mon Sep 17 00:00:00 2001 From: yubintw Date: Sun, 6 Feb 2022 23:36:17 +0800 Subject: [PATCH 090/189] Translate Section 4.2 --- readme-zh-TW.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 6eab5531..7c4ff197 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1504,22 +1504,23 @@ describe("visual validation", () => {

    -## ⚪ ️ 4.2 Inspect coverage reports to detect untested areas and other oddities +## ⚪ ️ 4.2 檢查測試覆蓋率的報告來發現沒有被測試的區域或奇怪的地方 + +:white_check_mark: **建議:** 有些問題隱藏在雷達之下,使用傳統的工具很難發現到它們。它們通常不是真正的 bug,大多數情況下是應用程式的奇怪行為,而這些行為可能會造成嚴重影響。例如,一些程式區域幾乎不會或很少被呼叫 — 你以為 "PricingCalculator" 這個 class 只會設定產品價格,結果他幾乎不會被呼叫,即使我們的資料庫中有 10000 件商品以及很多筆交易…… 測試覆蓋率報告可以幫助你發現應用程式是否按照你的期望在執行。除此之外,它會 highlight 出哪些類型的程式沒有被測試到,80% 的程式被測試並不能代表程式中關鍵的部分有被覆蓋到。產生報告很簡單,只需要在執行測試的時候開啟覆蓋率追蹤的功能,然後讓那些花花綠綠的報告來告訴你每個程式區塊被呼叫的頻率。如果你花時間去看這些數據,你可能會發現一些問題。 -:white_check_mark: **Do:** Some issues sneak just under the radar and are really hard to find using traditional tools. These are not really bugs but more of surprising application behavior that might have a severe impact. For example, often some code areas are never or rarely being invoked — you thought that the ‘PricingCalculator’ class is always setting the product price but it turns out it is actually never invoked although we have 10000 products in DB and many sales… Code coverage reports help you realize whether the application behaves the way you believe it does. Other than that, it can also highlight which types of code is not tested — being informed that 80% of the code is tested doesn’t tell whether the critical parts are covered. Generating reports is easy — just run your app in production or during testing with coverage tracking and then see colorful reports that highlight how frequent each code area is invoked. If you take your time to glimpse into this data — you might find some gotchas
    -❌ **Otherwise:** If you don’t know which parts of your code are left un-tested, you don’t know where the issues might come from +❌ **否則:** 如果你不知道你的程式裡面有哪些地方沒有被測試到,你將無法知道問題的來源。
    -
    Code Examples +
    程式範例
    -### :thumbsdown: Anti-Pattern Example: What’s wrong with this coverage report? +### :thumbsdown: 反例:這個測試覆蓋率的報告出了什麼問題? -Based on a real-world scenario where we tracked our application usage in QA and find out interesting login patterns (Hint: the amount of login failures is non-proportional, something is clearly wrong. Finally it turned out that some frontend bug keeps hitting the backend login API) +基於一個真實世界的情境,我們在 QA 中追蹤了我們應用程式的使用情況,並發現了這個有趣的登錄模式 (提示:登入失敗的數量不成正比的,顯然是有問題的。最後發現,有一些前端的 bug 一直在打後端的登入 API) ![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report?") From a9c319608ebf22c47fe07ad5bf4ac33178a6140e Mon Sep 17 00:00:00 2001 From: yubintw Date: Mon, 7 Feb 2022 22:43:41 +0800 Subject: [PATCH 091/189] Translate Section 4.3 --- readme-zh-TW.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 7c4ff197..0def89d0 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1528,28 +1528,29 @@ describe("visual validation", () => {

    -## ⚪ ️ 4.3 Measure logical coverage using mutation testing +## ⚪ ️ 4.3 使用「變異測試」測量邏輯覆蓋率 -:white_check_mark: **Do:** The Traditional Coverage metric often lies: It may show you 100% code coverage, but none of your functions, even not one, return the right response. How come? it simply measures over which lines of code the test visited, but it doesn’t check if the tests actually tested anything — asserted for the right response. Like someone who’s traveling for business and showing his passport stamps — this doesn’t prove any work done, only that he visited few airports and hotels. +:white_check_mark: **建議:** 傳統的測試覆蓋率通常是騙人的,他可能會告訴你有 100% 的測試覆蓋率,但可能你的 function 都沒有回傳正確的值。為什麼會這樣?因為他只是很單純的測量你的測試程式走過哪幾行,而不會檢查測試案例到底測試了什麼,他到底有沒有確實去斷言正確的回應。就像有個人因公出差,他出示了他的護照,他無法證明他做了什麼工作,只能證明有去過哪幾個機場。 -Mutation-based testing is here to help by measuring the amount of code that was actually TESTED not just VISITED. [Stryker](https://stryker-mutator.io/) is a JavaScript library for mutation testing and the implementation is really neat: +基於變異的測試,是透過測量"實際測試"的程式數量而不僅僅是"訪問"過的數量來提供協助。[Stryker](https://stryker-mutator.io/) 是一個用於進行變異測試的 JavaScript 函示庫,他的實作非常巧妙: -(1) it intentionally changes the code and “plants bugs”. For example the code newOrder.price===0 becomes newOrder.price!=0. This “bugs” are called mutations +(1) 他會刻意在你的程式中「植入 bug」。例如程式 `newOrder.price === 0` 會被改成 `newOrder.price != 0`,這個 "bug" 就稱為變異。 -(2) it runs the tests, if all succeed then we have a problem — the tests didn’t serve their purpose of discovering bugs, the mutations are so-called survived. If the tests failed, then great, the mutations were killed. +(2) 他會跑過一次測試,如果測試通過了代表有些問題,這些測試案例沒有達到發現 bug 的目的,導致這些變異活了下來。如果測試失敗了,非常好,那些變異就會被殺掉。 + +相較於傳統的測試覆蓋率,如果知道所有的變異都被殺死,會讓你更有自信,而且這兩者花費的時間差不多。 -Knowing that all or most of the mutations were killed gives much higher confidence than traditional coverage and the setup time is similar
    -❌ **Otherwise:** You’ll be fooled to believe that 85% coverage means your test will detect bugs in 85% of your code +❌ **否則:** 你可能會誤以為 85% 的測試覆蓋率能發現程式中 85% 的 bug。
    -
    Code Examples +
    程式範例
    -### :thumbsdown: Anti-Pattern Example: 100% coverage, 0% testing +### :thumbsdown: 反例: 100% coverage, 0% testing ![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Using Stryker") @@ -1564,12 +1565,12 @@ function addNewOrder(newOrder) { it("Test addNewOrder, don't use such test names", () => { addNewOrder({ assignee: "John@mailer.com", price: 120 }); -}); //Triggers 100% code coverage, but it doesn't check anything +}); // Triggers 100% code coverage, but it doesn't check anything ```
    -### :clap: Doing It Right Example: Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations) +### :clap: 正例:Stryker 的報告,一個變異測試的工具,偵測並統計沒有被測試到的程式 (變異) ![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations)") From c8ffa37d7b65fd4b365432860f10c5ddcfffc12b Mon Sep 17 00:00:00 2001 From: yubintw Date: Tue, 8 Feb 2022 22:04:53 +0800 Subject: [PATCH 092/189] Translate Section 4.4 --- readme-zh-TW.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 0def89d0..69342eea 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1578,32 +1578,32 @@ it("Test addNewOrder, don't use such test names", () => {

    -## ⚪ ️4.4 Preventing test code issues with Test linters +## ⚪ ️4.4 使用 Test linter 來避免測試程式的問題 -:white_check_mark: **Do:** A set of ESLint plugins were built specifically for inspecting the tests code patterns and discover issues. For example, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) will warn when a test is written at the global level (not a son of a describe() statement) or when tests are [skipped](https://mochajs.org/#inclusive-tests) which might lead to a false belief that all tests are passing. Similarly, [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) can, for example, warn when a test has no assertions at all (not checking anything) +:white_check_mark: **建議:** 有一系列的 ESLint 外掛可以檢查測試程式的風格並發現問題。比如 [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) 會警告一個寫在 global 層的測試案例 (不是寫在 describe() 底下),或者當測試案例被 [skip](https://mochajs.org/#inclusive-tests) 時會發出警告,因為這可能會導致你誤會所有測試都通過了。類似的像,[eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) 可以在一個測試案例沒有任何斷言 (沒有檢查任何內容) 時給出警告。
    -❌ **Otherwise:** Seeing 90% code coverage and 100% green tests will make your face wear a big smile only until you realize that many tests aren’t asserting for anything and many test suites were just skipped. Hopefully, you didn’t deploy anything based on this false observation +❌ **否則:** 當你滿足於 90% 的測試覆蓋率或 100% 的綠色報告時,卻發現很多測試都沒什麼斷言,或是很多測試直接被 skip 掉了。但願你沒有把這份程式佈署出去。
    -
    Code Examples +
    程式範例
    -### :thumbsdown: Anti-Pattern Example: A test case full of errors, luckily all are caught by Linters +### :thumbsdown: 反例:一個充滿錯誤的測試案例,還好都被 Linter 抓到了 ```javascript describe("Too short description", () => { const userToken = userService.getDefaultToken() // *error:no-setup-in-describe, use hooks (sparingly) instead - it("Some description", () => {});//* error: valid-test-description. Must include the word "Should" + at least 5 words + it("Some description", () => {}); // *error: valid-test-description. Must include the word "Should" + at least 5 words }); -it.skip("Test name", () => {// *error:no-skipped-tests, error:error:no-global-tests. Put tests only under describe or suite - expect("somevalue"); // error:no-assert +it.skip("Test name", () => { // *error:no-skipped-tests, error:error:no-global-tests. Put tests only under describe or suite + expect("somevalue"); // *error:no-assert }); -it("Test name", () => {*//error:no-identical-title. Assign unique titles to tests +it("Test name", () => { // *error:no-identical-title. Assign unique titles to tests }); ``` From ceb7fc74a4b5af2b86607ffbd2b6a28db34c75af Mon Sep 17 00:00:00 2001 From: yubintw Date: Sat, 12 Feb 2022 22:07:02 +0800 Subject: [PATCH 093/189] Translate Section 5.1 --- readme-zh-TW.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 69342eea..7268d4a6 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1611,24 +1611,24 @@ it("Test name", () => { // *error:no-identical-title. Assign unique titles to te

    -# Section 5️⃣: CI and Other Quality Measures +# 第 5 章:持續整合 (CI) 或其他提高品質的手段

    -## ⚪ ️ 5.1 Enrich your linters and abort builds that have linting issues +## ⚪ ️ 5.1 豐富你的 linter 並捨棄有 linting 問題的建置 -:white_check_mark: **Do:** Linters are a free lunch, with 5 min setup you get for free an auto-pilot guarding your code and catching significant issue as you type. Gone are the days where linting was about cosmetics (no semi-colons!). Nowadays, Linters can catch severe issues like errors that are not thrown correctly and losing information. On top of your basic set of rules (like [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) or [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), consider including some specializing Linters like [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) that can discover tests without assertions, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) can discover promises with no resolve (your code will never continue), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) which can discover eager regex expressions that might get used for DOS attacks, and [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) is capable of alarming when the code uses utility library methods that are part of the V8 core methods like Lodash.\_map(…) +:white_check_mark: **建議:** 只需要 5 分鐘的設定,就可以免費得到自動保護程式碼的工具來偵測出程式中的問題。Linter 不再只是樣式工具,現在的 linter 可以抓到許多嚴重的問題,像是 error 沒有被正確的拋出或訊息的遺失。在基本的規則 (如 [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) 或 [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)) 之上,可以考慮加上一些特殊的 linter,像是 [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) 可以用來偵測測試案例有沒有寫斷言,[eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) 可以發現 Promise 有沒有 resolve (否則會導致你的程式不能繼續),[eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) 可以發現可能會導致 DOS 攻擊的正規表示式,還有 [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) 會在程式碼使用到 V8 的核心方法的時候給予警告,例如 Lodash.\_map(…)。
    -❌ **Otherwise:** Consider a rainy day where your production keeps crashing but the logs don’t display the error stack trace. What happened? Your code mistakenly threw a non-error object and the stack trace was lost, a good reason for banging your head against a brick wall. A 5 min linter setup could detect this TYPO and save your day +❌ **否則:** 想像在某個雨天中,你的程式一直 crash,而且 log 沒有顯示 stack trace 的訊息。到底發生什麼事了?你的程式錯誤地拋出了一個非 error 的物件,而且 stack trace 都不見了,這會讓你想去撞牆。只要用 5 分鐘來設定 linter 就可以幫你偵測出這種 typo 錯誤,並拯救你一整天。
    -
    Code Examples +
    程式範例
    -### :thumbsdown: Anti-Pattern Example: The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug +### :thumbsdown: 反例:Error 物件被拋出,這樣的錯誤不會出現 stack trace。幸運的是,ESLint 抓到了這個 bug。 ![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug") From 8f6a7422599fa9632bd1c221f066390e71d487bd Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Sun, 6 Mar 2022 08:51:09 +0200 Subject: [PATCH 094/189] readme-zh-CN.md updated from https://stackedit.io/ --- readme-zh-CN.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readme-zh-CN.md b/readme-zh-CN.md index 67e0bcbc..1abaa83b 100644 --- a/readme-zh-CN.md +++ b/readme-zh-CN.md @@ -68,7 +68,7 @@ JS 领域的 CI 指南(9 条) 我们的思维空间被主体生产代码充满,因此无法腾出额外的“大脑空间”存放复杂的东西。如果向可怜的大脑中塞进其他复杂代码,将会使得整个部分变慢,而这个部分正是用来解决我们需要测试的问题的。这也是大部分团队放弃测试的原因。 -另一方面,测试是一个友好的助手,一个你乐于与之合作、投资小回报大的助手。科学证明我们有两套大脑系统:系统 1 用于无需努力的活动如在一个空旷的路上开车;系统 2 用于复杂和繁琐的工作如算一道数学表达式。将你的测试为系统 1 设计,当你看一段测试代码时,需要像改 HTML 文档一样简单而不是像计算 2 × (17 × 24)。 +另一方面,测试是一个友好的助手,一个你乐于与之合作、投资小回汇报大的助手。科学证明我们有两套大脑系统:系统 1 用于无需努力的活动如在一个空旷的路上开车;系统 2 用于复杂和繁琐的工作如算一道数学表达式。将你的测试为系统 1 设计,当你看一段测试代码时,需要像改 HTML 文档一样简单而不是像计算 2 × (17 × 24)。 为了达到这个目的,我们可以通过选择性价比高、投入产出比(ROI)高的技术、工具以及测试对象。仅测试需要的内容,努力保持其灵活性,某些时候甚至值得去舍弃一些测试来换取灵活性和简洁性。 @@ -2052,3 +2052,6 @@ script: **Role:** 帮助保持本项目的运行,并审查与安全性有关的实践 **About:** 喜欢从事 Node.js 项目和 Web 应用安全性的工作。 + \ No newline at end of file From f411b594dcff2036a25031e71ef323f4ceca2ef9 Mon Sep 17 00:00:00 2001 From: yubintw Date: Wed, 30 Mar 2022 21:37:14 +0800 Subject: [PATCH 095/189] Translate Section 5.2 --- readme-zh-TW.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 7268d4a6..337ee368 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1202,7 +1202,7 @@ test("movie title appears", async () => {
    -## ⚪ ️ 3.6 Stub flaky and slow resources like backend APIs +## ⚪ ️ 3.6 stub 那些不穩定或緩慢的資源如後端 API :white_check_mark: **建議:** 當撰寫你主要的測試 (不是 E2E 測試) 時,避免接觸任何超出你職責和控制範圍的資源,如後端 API,而是使用 stub (測試替身)。使用一些測試替身的函式庫 (如 [Sinon](https://sinonjs.org/)、[Test doubles](https://www.npmjs.com/package/testdouble) 等) 來 stub API 的回應,而不是真正的對 API 進行呼叫。最大的好處是防止出現故障 — 測試或 API 的定義常常在變動的時候,儘管組件的表現正確 (生產環境不適合進行測試,它通常對 API 的呼叫進行限制),但有時會呼叫失敗。通過 stub 來模擬各種 API 行為,比如當沒有找到資料或 API 拋出錯誤時測試組件行為。最後但並非最不重要的原因是,經過網絡的呼叫將會大大降低執行測試的速度。 @@ -1636,22 +1636,22 @@ it("Test name", () => { // *error:no-identical-title. Assign unique titles to te

    -## ⚪ ️ 5.2 Shorten the feedback loop with local developer-CI +## ⚪ ️ 5.2 透過本地端的 CI 來縮短回饋循環 -:white_check_mark: **Do:** Using a CI with shiny quality inspections like testing, linting, vulnerabilities check, etc? Help developers run this pipeline also locally to solicit instant feedback and shorten the [feedback loop](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). Why? an efficient testing process constitutes many and iterative loops: (1) try-outs -> (2) feedback -> (3) refactor. The faster the feedback is, the more improvement iterations a developer can perform per-module and perfect the results. On the flip, when the feedback is late to come fewer improvement iterations could be packed into a single day, the team might already move forward to another topic/task/module and might not be up for refining that module. +:white_check_mark: **建議:** 在本地端使用一個包含測試、Lint、穩定性檢查等功能的 CI,可以幫助開發者快速得到回饋並縮短 [回饋循環](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/)。因為一個有效的測試流程包含很多迭代循環 (1) 嘗試 -> (2) 回饋 -> (3) 重構。所以回饋越快,開發者可以在每個流程中可以執行的迭代就越多,且可以得到更好的結果。反過來,如果回饋來得很慢,一天只能執行很少個迭代,那團隊可能會因為急需執行下一個主題/任務/循環,而不再優化當前的循環。 -Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) allow running the pipeline locally. Some commercial tools like [wallaby provide highly-valuable & testing insights](https://wallabyjs.com/) as a developer prototype (no affiliation). Alternatively, you may just add npm script to package.json that runs all the quality commands (e.g. test, lint, vulnerabilities) — use tools like [concurrently](https://www.npmjs.com/package/concurrently) for parallelization and non-zero exit code if one of the tools failed. Now the developer should just invoke one command — e.g. ‘npm run quality’ — to get instant feedback. Consider also aborting a commit if the quality check failed using a githook ([husky can help](https://github.com/typicode/husky)) +目前有些 CI 的服務供應商 (如:[CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) 允許在本地端執行 CI pipeline。有些商業工具像是 [wallaby](https://wallabyjs.com/) 為開發提供了非常有用的測試功能。或者你可以在 package.json 中增加 npm script 來跑一些提升程式品質的指令 — 使用工具如 [concurrently](https://www.npmjs.com/package/concurrently) 來並行執行,並在任何工具執行失敗後拋出非 0 的結束碼。開發者只需執行一個指令(如 `npm run quality` )來快速獲取回饋。也可以用 githook 來取消沒有通過程式品質檢查的提交( [husky](https://github.com/typicode/husky) 可以幫助你)。
    -❌ **Otherwise:** When the quality results arrive the day after the code, testing doesn’t become a fluent part of development rather an after the fact formal artifact +❌ **否則** 如果品質檢查的結果在程式提交後第二天才收到,那測試就不算開發的一部分了。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: npm scripts that perform code quality inspection, all are run in parallel on demand or when a developer is trying to push new code +### :clap: 正例:用來執行程式品質檢查的 npm script,在開發者主動觸發或嘗試提交新程式時執行。 ```javascript "scripts": { From 0a5e3a89ccd2cad96de23f4b3fb8b89b713f7faf Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Wed, 6 Apr 2022 11:16:10 +0300 Subject: [PATCH 096/189] Update readme.md --- readme.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 1e7990b3..7651b2b9 100644 --- a/readme.md +++ b/readme.md @@ -6,7 +6,7 @@
    -## 📗 46+ best practices: Super-comprehensive and exhaustive +## 📗 50+ best practices: Super-comprehensive and exhaustive This 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 @@ -958,6 +958,38 @@ it("When updating site name, get successful confirmation", async () => {
    +
    + +## ⚪ ️2.8 Choose a clear data clean-up strategy: After-all (recommended) or after-each + +: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. + +The 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. +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :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 + +```javascript + // After-all clean up (recommended) +// global-teardown.js +module.exports = async () => { + // ... + if (Math.ceil(Math.random() * 10) === 10) { + await new OrderRepository().cleanup(); + } +}; +``` + +
    +

    # Section 3️⃣: Frontend Testing From 5d6b470f08bc11e70f40fdea06281d3e6844ad90 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Wed, 6 Apr 2022 11:29:28 +0300 Subject: [PATCH 097/189] Update readme.md --- readme.md | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 7651b2b9..7bc1d1c1 100644 --- a/readme.md +++ b/readme.md @@ -964,7 +964,7 @@ it("When updating site name, get successful confirmation", async () => { :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. -The 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. +The 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://github.com/testjavascript/nodejs-integration-tests-best-practices/blob/master/graphics/db-clean-options.png).
    ❌ **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 @@ -990,6 +990,85 @@ module.exports = async () => {
    +
    + +## ⚪ ️2.9 Isolate the component from the world using HTTP interceptor + +: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 +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :clap: Preventing network calls to externous components allows simulating scnearios and minimizing the noise + +```javascript +// Intercept requests for 3rd party APIs and return a predefined response +beforeEach(() => { + nock('http://localhost/user/').get(`/1`).reply(200, { + id: 1, + name: 'John', + }); +});``` + +
    + +## ⚪ ️2.10 Test the response schema, mostly when there are auto-generated fields + +: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. + + +
    + +❌ **Otherwise:** Although the code/API caller relies on some field with dynamic data (e.g., ID, date), it will not come in return and break the contract + +
    + +
    Code Examples + +
    + +### :clap: Asserting that fields with dynamic value exist and have the right type + +```javascript + test('When adding a new valid order, Then should get back approval with 200 response', async () => { + // ... + //Assert + expect(receivedAPIResponse).toMatchObject({ + status: 200, + data: { + id: expect.any(Number), // Any number satisfies this test + mode: 'approved', + }, + }); +}); +``` + +
    + +
    + +## ⚪ ️2.11 Test the five potential outcomes + +: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/reactions can be put in 5 categories: + +• 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 + +• A new state - After invoking an action, some **publicly accessible** data is probably modified + +• 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 + +• Message queues - The outcome of a flow might be a message in a queue + +• 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/metrics. This information goes directly to a very important user - The ops user (i.e., production SRE/admin) + +
    +

    # Section 3️⃣: Frontend Testing From 8a57337cbf257dfa995065dbb44ece9df239bf0e Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Wed, 6 Apr 2022 11:39:06 +0300 Subject: [PATCH 098/189] Update readme.md --- readme.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 7bc1d1c1..298246a7 100644 --- a/readme.md +++ b/readme.md @@ -52,7 +52,7 @@ The foundation - structuring clean tests (12 bullets) #### [`Section 2: Backend`](#section-2️⃣-backend-testing) -Writing backend and Microservices tests efficiently (8 bullets) +Writing backend and Microservices tests efficiently (13 bullets) #### [`Section 3: Frontend`](#section-3️⃣-frontend-testing) @@ -1053,7 +1053,53 @@ beforeEach(() => {
    -## ⚪ ️2.11 Test the five potential outcomes +## ⚪ ️2.12 Check integrations corner cases and chaos + +:white_check_mark: **Do:** When checking integrations, go beyond the happy and sad paths. Check not only errored 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 + + +
    + +❌ **Otherwise:** All your tests pass, it's only the production who will crash or won't report errors correctly when 3rd parties send excpetional responses + +
    + +
    Code Examples + +
    + +### :clap: Ensuring that on network failures, the circuit breaker can save the day + +```javascript + test('When users service replies with 503 once and retry mechanism is applied, then an order is added successfully', async () => { + //Arrange + nock.removeInterceptor(userServiceNock.interceptors[0]) + nock('http://localhost/user/') + .get('/1') + .reply(503, undefined, { 'Retry-After': 100 }); + nock('http://localhost/user/') + .get('/1') + .reply(200); + const orderToAdd = { + userId: 1, + productId: 2, + mode: 'approved', + }; + + //Act + const response = await axiosAPIClient.post('/order', orderToAdd); + + //Assert + expect(response.status).toBe(200); +}); +``` + +
    + +
    + + +## ⚪ ️2.13 Test the five potential outcomes :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/reactions can be put in 5 categories: From 4989789a884d7a1a3e560558b1cd03d1eb6e78c5 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Wed, 6 Apr 2022 11:59:56 +0300 Subject: [PATCH 099/189] Update readme.md --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index 298246a7..5a9cc890 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,11 @@ +## 🎊 April 2022 Announcement: A new edition was just released with 5 new best practices, many more code examples and 4 new language translations +
    + + # 👇 Why this guide can take your testing skills to the next level
    From 6e62e0f81c3414e960195f8860c35528bc46a382 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Wed, 6 Apr 2022 12:09:46 +0300 Subject: [PATCH 100/189] Update readme.md --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 5a9cc890..6ca37b33 100644 --- a/readme.md +++ b/readme.md @@ -40,6 +40,7 @@ Start by understanding the ubiquitous testing practices that are the foundation - 🇪🇸[Spanish](readme-es.md) - Courtesy of [Miguel G. Sanguino](https://github.com/sanguino) - 🇧🇷[Portuguese-BR](readme-pt-br.md) - Courtesy of [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) - 🇫🇷[French](readme-fr.md) - Courtesy of [Mathilde El Mouktafi](https://github.com/mel-mouk) +- 🇯🇵[Japanese (draft)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - Courtesy of [Yuichi Yogo](https://github.com/yuichkun) and [ryo](https://github.com/kawamataryo) - Want to translate to your own language? please open an issue 💜

    From b8d091eb70c08a6288e9dc3ba00461c2514432de Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 6 Apr 2022 11:26:16 +0000 Subject: [PATCH 101/189] docs: update readme.md [skip ci] --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 6ca37b33..8f52356a 100644 --- a/readme.md +++ b/readme.md @@ -2132,6 +2132,7 @@ Thanks goes to these wonderful people who have contributed to this repository!
    Otavio Araujo

    ⚠️ 🖋

    Alex Ivanov

    🖋
    Yiqiao Xu

    🖋 +
    YuBin, Hsu

    🌍 💻 From 2401aed66e6820e0f4404e010c1ecd6ce2a2507e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 6 Apr 2022 11:26:16 +0000 Subject: [PATCH 102/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 28eecb0d..52b52910 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -350,6 +350,16 @@ "contributions": [ "content" ] + }, + { + "login": "yubinTW", + "name": "YuBin, Hsu", + "avatar_url": "https://avatars.githubusercontent.com/u/31545456?v=4", + "profile": "https://github.com/yubinTW", + "contributions": [ + "translation", + "code" + ] } ], "projectName": "javascript-testing-best-practices", From d4d879bc5327064a55c822ff42a06fd03d091f47 Mon Sep 17 00:00:00 2001 From: yubintw Date: Thu, 7 Apr 2022 01:47:15 +0800 Subject: [PATCH 103/189] Translate Section 5.3 --- readme-zh-TW.md | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 337ee368..71cdc629 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1676,24 +1676,39 @@ it("Test name", () => { // *error:no-identical-title. Assign unique titles to te

    -## ⚪ ️5.3 Perform e2e testing over a true production-mirror +## ⚪ ️5.3 在真正 production 的鏡像環境中執行 e2e 測試 -:white_check_mark: **Do:** End to end (e2e) testing are the main challenge of every CI pipeline — creating an identical ephemeral production mirror on the fly with all the related cloud services can be tedious and expensive. Finding the best compromise is your game: [Docker-compose](https://serverless.com/) allows crafting isolated dockerized environment with identical containers using a single plain text file but the backing technology (e.g. networking, deployment model) is different from real-world productions. You may combine it with [‘AWS Local’](https://github.com/localstack/localstack) to work with a stub of the real AWS services. If you went [serverless](https://serverless.com/) multiple frameworks like serverless and [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) allows the local invocation of FaaS code. +:white_check_mark: **建議:** End to end (e2e) 測試是每個 CI pipeline 會面臨的大挑戰 - 即時創建一個與真正 production 環境相同的鏡像環境並擁有所有相關的服務,是很費時費力的。你需要找到適合的折衷點:[Docker-compose](https://serverless.com/) 藉由一個純文字檔將 docker 化的環境放在獨立的 container 中,但他背後使用的技術 (例如網路與佈署模型) 仍然與真實世界有所差異。可以將其與 [AWS Local](https://github.com/localstack/localstack) 整合,在真正的 AWS服務中做使用。如果你使用 [serverless](https://serverless.com/) 框架,[AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) 可以讓你在本地端調用 FaaS 程式碼。 -The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for local and CI-mirroring though many new tools are launched frequently. One approach is running a ‘minimized-Kubernetes’ using tools like [Minikube](https://kubernetes.io/docs/setup/minikube/) and [MicroK8s](https://microk8s.io/) which resemble the real thing only come with less overhead. Another approach is testing over a remote ‘real-Kubernetes’, some CI providers (e.g. [Codefresh](https://codefresh.io/)) has native integration with Kubernetes environment and make it easy to run the CI pipeline over the real thing, others allow custom scripting against a remote Kubernetes. +龐大的 Kubernetes 生態系還沒有一個標準、方便的本地端、CI鏡像的工具,儘管現在已有許多工具的出現。有一種方法是使用像是 [Minikube](https://kubernetes.io/docs/setup/minikube/) 和 [MicroK8s](https://microk8s.io/) 這樣的工具來運行一個 "最小化的 Kubernetes",這些工具更貼近現實,且成本花費很小。另一種方法是在遠端的 "真實 Kubernetes" 環境上運行測試,一些 CI 的服務供應商 (如 [Codefresh](https://codefresh.io/)) 與 Kubernetes 環境擁有原生的整合,讓在 CI pipeline 上執行真實的環境變得更為容易。有的供應商則可以讓你針對遠端的 Kubernetes 自訂腳本。
    -❌ **Otherwise:** Using different technologies for production and testing demands maintaining two deployment models and keeps the developers and the ops team separated +❌ **否則:** 在生產環境和測試環境中使用不同的技術,就會需要維護兩種佈署模型,會使開發人員與維運人員分開。
    -
    Code Examples +
    程式範例
    -### :clap: Example: a CI pipeline that generates Kubernetes cluster on the fly ([Credit: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/)) - -
    deploy:
    stage: deploy
    image: registry.gitlab.com/gitlab-examples/kubernetes-deploy
    script:
    - ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN
    - kubectl create ns $NAMESPACE
    - kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL"
    - mkdir .generated
    - echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF"
    - sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml"
    - kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml
    - kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml
    environment:
    name: test-for-ci
    +### :clap: 正例:動態產生 Kubernetes cluster 的 CI pipeline ([Credit: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/)) + +```yaml +deploy: +stage: deploy +image: registry.gitlab.com/gitlab-examples/kubernetes-deploy +script: +- ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN +- kubectl create ns $NAMESPACE +- kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL" +- mkdir .generated +- echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF" +- sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml" +- kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml +- kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml +environment: +name: test-for-ci +```
    From 2341759ae1bb44c66454096cb9f5a34d247479df Mon Sep 17 00:00:00 2001 From: yubintw Date: Thu, 7 Apr 2022 02:06:54 +0800 Subject: [PATCH 104/189] Translate Section 5.4 --- readme-zh-TW.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 71cdc629..3167ae0b 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1714,19 +1714,19 @@ name: test-for-ci

    -## ⚪ ️5.4 Parallelize test execution +## ⚪ ️5.4 並行測試工作 -:white_check_mark: **Do:** When done right, testing is your 24/7 friend providing almost instant feedback. In practice, executing 500 CPU-bounded unit test on a single thread can take too long. Luckily, modern test runners and CI platforms (like [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) and [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) can parallelize the test into multiple processes and achieve significant improvement in feedback time. Some CI vendors do also parallelize tests across containers (!) which shortens the feedback loop even further. Whether locally over multiple processes, or over some cloud CLI using multiple machines — parallelizing demand keeping the tests autonomous as each might run on different processes +:white_check_mark: **建議:** 在合理的情況下,測試是你 24/7 的好朋友,他為你帶來即時的回饋。實際上,在單線程的 CPU 上執行 500 個單元測試可能會非常耗時。幸運的是,近代的測試執行器或 CI 平台 (如 [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) 或 [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) 可以將測試並行為多個程序來執行,藉此來大幅縮短回饋的時間。一些 CI 的廠商也支援跨容器並行測試,更進一步地縮短回饋的時間。無論是在本地端使用多個程序,或是在一些 cloud CLI 上使用多台機器來執行測試,並行化的重點是要保持測試的自主性,因為每個測試都可能在不同的程序上做執行。 -❌ **Otherwise:** Getting test results 1 hour long after pushing new code, as you already code the next features, is a great recipe for making testing less relevant +❌ **否則:** 如果送出程式碼一個小時後才收到測試結果,但你已經在開發下一個功能了,這會導致測試對你來說變的不是那麼重要。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) +### :clap: 正例:藉由測試並行化,Mocha parallel 與 Jest 可以輕易的超越傳統 Mocha ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) ![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization (Credit: JavaScript Test-Runners Benchmark)") From 1987ad1457a3bd7c989afb92c76a1102e7b3c033 Mon Sep 17 00:00:00 2001 From: yubintw Date: Thu, 7 Apr 2022 02:29:23 +0800 Subject: [PATCH 105/189] Translate Section 5.5 --- readme-zh-TW.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 3167ae0b..cb77df0c 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1734,19 +1734,19 @@ name: test-for-ci

    -## ⚪ ️5.5 Stay away from legal issues using license and plagiarism check +## ⚪ ️5.5 使用 License 和抄襲檢查來避免法務上的問題 -:white_check_mark: **Do:** Licensing and plagiarism issues are probably not your main concern right now, but why not tick this box as well in 10 minutes? A bunch of npm packages like [license check](https://www.npmjs.com/package/license-checker) and [plagiarism check](https://www.npmjs.com/package/plagiarism-checker) (commercial with free plan) can be easily baked into your CI pipeline and inspect for sorrows like dependencies with restrictive licenses or code that was copy-pasted from Stack Overflow and apparently violates some copyrights +:white_check_mark: **建議:** License 和抄襲的問題或許不是你現在關注的點,但為什麼不在 10 分鐘內把這件工作設定好呢?許多 npm 的套件,像是 [license check](https://www.npmjs.com/package/license-checker) 和 [plagiarism check](https://www.npmjs.com/package/plagiarism-checker) (商業軟體,但有免費使用版本) 可以很容易的整合進你的 CI pipeline 中,並檢查那些像是使用限制性 license 或從 Stack Overflow 複製貼上明顯侵犯版權的程式。 -❌ **Otherwise:** Unintentionally, developers might use packages with inappropriate licenses or copy paste commercial code and run into legal issues +❌ **否則:** 在不經意的情況下,開發人員可能會使用具有不適當 License 的套件,或將商業程式複製貼上,從而遇到法律上的問題。
    -
    Code Examples +
    程式範例
    -### :clap: Doing It Right Example: +### :clap: 正例: ```javascript //install license-checker in your CI environment or also locally From 669071b67c7a41d7f08b257b7e061ba9a9e2825a Mon Sep 17 00:00:00 2001 From: yubintw Date: Thu, 7 Apr 2022 02:29:42 +0800 Subject: [PATCH 106/189] Translate Section 5.6 --- readme-zh-TW.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index cb77df0c..26545245 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1765,19 +1765,19 @@ license-checker --summary --failOn BSD

    -## ⚪ ️5.6 Constantly inspect for vulnerable dependencies +## ⚪ ️5.6 持續檢查有漏洞的相依套件 -:white_check_mark: **Do:** Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using community tools such as [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), or commercial tools like [snyk](https://snyk.io/) (offer also a free community version). Both can be invoked from your CI on every build +:white_check_mark: **建議:** 即使是最有信譽的相依套件,如 Express,也有已知的漏洞。可以藉由使用社群工具 (如 [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit)) 或商業工具 (如 [snyk](https://snyk.io/) (也有免費版本)) 來輕鬆解決問題。可以在每次的建置中,透過 CI pipeline 調用他們。 -❌ **Otherwise:** Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online publications about new threats. Quite tedious +❌ **否則:** 在沒有專用工具的情況下,要保持你的程式沒有漏洞,就需要不斷追蹤網路上新發佈的漏洞威脅資訊,這會相當令人乏味。
    -
    Code Examples +
    程式範例
    -### :clap: Example: NPM Audit result +### :clap: 正例:NPM Audit 的結果 ![alt text](assets/bp-26-npm-audit-snyk.png "NPM Audit result") From 2db738746923903a1ffc99b5e302ef177d2ffc49 Mon Sep 17 00:00:00 2001 From: yubintw Date: Thu, 7 Apr 2022 02:49:27 +0800 Subject: [PATCH 107/189] Translate Section 5.7 --- readme-zh-TW.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 26545245..5c455f36 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1785,26 +1785,27 @@ license-checker --summary --failOn BSD

    -## ⚪ ️5.7 Automate dependency updates +## ⚪ ️5.7 自動升級相依套件 -:white_check_mark: **Do:** Yarn and npm latest introduction of package-lock.json introduced a serious challenge (the road to hell is paved with good intentions) — by default now, packages are no longer getting updates. Even a team running many fresh deployments with ‘npm install’ & ‘npm update’ won’t get any new updates. This leads to subpar dependent packages versions at best or to vulnerable code at worst. Teams now rely on developers goodwill and memory to manually update the package.json or use tools [like ncu](https://www.npmjs.com/package/npm-check-updates) manually. A more reliable way could be to automate the process of getting the most reliable dependency versions, though there are no silver bullet solutions yet there are two possible automation roads: +:white_check_mark: **建議:** Yarn 和 npm 的 package-lock.json 間接導入了一個嚴重的問題(本意是好的,但卻通往地獄)- 預設情況下,套件將不再得到更新。即使團隊使用 `npm install` 和 `npm update` 也不會獲得任何更新。會導致專案相依於不好的套件版本,或者最壞的情況是使用到容易被攻擊的程式。現在,團隊依靠開發人員的善意和記憶來手動更新 package.json 或手動使用像 [ncu]((https://www.npmjs.com/package/npm-check-updates)) 這樣的工具。然而更靠譜的方式是自動獲取可靠的相依套件版本,雖然沒有最佳的解決方案,但目前有兩種可能的自動化方式: -(1) CI can fail builds that have obsolete dependencies — using tools like [‘npm outdated’](https://docs.npmjs.com/cli/outdated) or ‘npm-check-updates (ncu)’ . Doing so will enforce developers to update dependencies. +(1) 使用 [npm outdated](https://docs.npmjs.com/cli/outdated) 或 npm-check-updates (ncu),當有過時的相依套件時,讓 CI 的建置失敗。這樣可以強制開發人員來更新相依套件。 -(2) Use commercial tools that scan the code and automatically send pull requests with updated dependencies. One interesting question remaining is what should be the dependency update policy — updating on every patch generates too many overhead, updating right when a major is released might point to an unstable version (many packages found vulnerable on the very first days after being released, [see the](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) eslint-scope incident). +(2) 使用商業工具,他們可以掃描程式並自動發送更新相依套件的 PR。剩下的有趣問題是相依套件的更新策略 — 若每個補丁都更新會產生太多的開銷,而大版本發佈時更新可能會指向一個不穩定的版本(許多套件在發佈後的幾天內被爆出漏洞,請參閱 [eslint-scope]((https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/)) 事件)。 + +有效的更新策略可能是允許一些 "容忍期" — 讓程式可以延後 @latest 一段時間和版本,再將本地端的副本視為過時(例如本地版本為 1.3.1 ,存儲庫版本為1.3.8)。 -An efficient update policy may allow some ‘vesting period’ — let the code lag behind the @latest for some time and versions before considering the local copy as obsolete (e.g. local version is 1.3.1 and repository version is 1.3.8)
    -❌ **Otherwise:** Your production will run packages that have been explicitly tagged by their author as risky +❌ **否則:** 你在 production 環境所使用的相依套件,可能已經被該作者標示為是有風險的。
    -
    Code Examples +
    程式範例
    -### :clap: Example: [ncu](https://www.npmjs.com/package/npm-check-updates) can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions +### :clap: 正例:[ncu](https://www.npmjs.com/package/npm-check-updates) 可以手動或在 CI pipeline 中使用,以檢測程式落後最新版本多少。 ![alt text](assets/bp-27-yoni-goldberg-npm.png "ncu can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions") From 481543e320af9c2dd382ac49c5ac563d083e54a0 Mon Sep 17 00:00:00 2001 From: yubintw Date: Thu, 7 Apr 2022 03:09:47 +0800 Subject: [PATCH 108/189] Translate Section 5.8 --- readme-zh-TW.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 5c455f36..c91094ce 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1813,14 +1813,23 @@ license-checker --summary --failOn BSD

    -## ⚪ ️ 5.8 Other, non-Node related, CI tips +## ⚪ ️ 5.8 其他,與 node 無關的 CI 建議 -: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 few non-Node related tips that are well-known +:white_check_mark: **建議:** 本文的重點是與 Node 有點關係的測試建議。但本節整理了一些眾所周知的與 Node 無關的技巧: + +1. 使用聲明式語法。這是大多數工具的唯一選擇,雖然舊版本的 Jenkins 允許使用程式或 UI。 +1. 選擇具有本地端 Docker 支援的工具。 +1. 盡快失敗,先執行最快的測試。設立一個"冒煙測試"的 step/milestone,對多個快速檢查工具(如 linting,單元測試)進行分組,為程式提交者提供快速回饋。 +1. 設法方便地瀏覽建置的所有產出,包括測試報告,覆蓋率報告,變異報告,log 等。 +1. 為每個事件創建多個 pipelines/jobs。例如,為 feature branch 的提交設定一個 job,為 master PR 設定另一個。 (大多數工具提供了一些程式重用的機制) +1. 永遠不要在 job 定義中加入機密信息,從 secret store 或 job 的設定中獲取。 +1. 在 release 中明確定義版本號。 +1. 僅建置一次,並對整個 build artifact(例如 Docker image)執行所有的檢查。 +1. 在一個臨時的環境中執行測試,在不同建置之間不會改變狀態。快取 node_modules 可能是唯一的例外。 -
    1. Use a declarative syntax. This is the only option for most vendors but older versions of Jenkins allows using code or UI
    2. Opt for a vendor that has native Docker support
    3. Fail early, run your fastest tests first. Create a ‘Smoke testing’ step/milestone that groups multiple fast inspections (e.g. linting, unit tests) and provide snappy feedback to the code committer
    4. Make it easy to skim-through all build artifacts including test reports, coverage reports, mutation reports, logs, etc
    5. Create multiple pipelines/jobs for each event, reuse steps between them. For example, configure a job for feature branch commits and a different one for master PR. Let each reuse logic using shared steps (most vendors provide some mechanism for code reuse)
    6. Never embed secrets in a job declaration, grab them from a secret store or from the job’s configuration
    7. Explicitly bump version in a release build or at least ensure the developer did so
    8. Build only once and perform all the inspections over the single build artifact (e.g. Docker image)
    9. Test in an ephemeral environment that doesn’t drift state between builds. Caching node_modules might be the only exception

    -❌ **Otherwise:** You‘ll miss years of wisdom +❌ **否則:** 你會錯過多年的智慧結晶

    From ceedfaa1bb952b6d6531360ce12e16acbf84adff Mon Sep 17 00:00:00 2001 From: yubintw Date: Thu, 7 Apr 2022 03:21:15 +0800 Subject: [PATCH 109/189] Translate Section 5.9 --- readme-zh-TW.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index c91094ce..2c901fe0 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -1833,20 +1833,21 @@ license-checker --summary --failOn BSD

    -## ⚪ ️ 5.9 Build matrix: Run the same CI steps using multiple Node versions +## ⚪ ️ 5.9 建置模型(Matrix):使用多個 Node 版本執行同一個 CI 流程 + +:white_check_mark: **建議:** 品質的檢查是用於發現意外,測試覆蓋的部分越多,你就越可能儘早地發現問題。在開發會重複使用的套件或執行具有各種設定和 Node 版本的多用戶生產環境時,CI pipeline 必須在所有設定的組合上執行測試。例如,假設我們的某些客戶使用 MySQL,另一批客戶使用 Postgres。一些 CI 工具支持一種稱為"Matrix"的功能,該功能可以針對 MySQL、Postgres 或多個 Node 版本(如8、9、10)的所有組合執行測試。只要設定即可完成而無需任何額外工作。其他不支援 Matrix 的 CI 可能可以通過安裝外掛或一定程度的調整來實現這個功能。 -:white_check_mark: **Do:** Quality checking is about serendipity, the more ground you cover the luckier you get in detecting issues early. When developing reusable packages or running a multi-customer production with various configuration and Node versions, the CI must run the pipeline of tests over all the permutations of configurations. For example, assuming we use MySQL for some customers and Postgres for others — some CI vendors support a feature called ‘Matrix’ which allow running the suit of testing against all permutations of MySQL, Postgres and multiple Node version like 8, 9 and 10. This is done using configuration only without any additional effort (assuming you have testing or any other quality checks). Other CIs who doesn’t support Matrix might have extensions or tweaks to allow that
    -❌ **Otherwise:** So after doing all that hard work of writing testing are we going to let bugs sneak in only because of configuration issues? +❌ **否則:** 在做了那麼多辛苦的測試工作之後,怎麼能讓錯誤僅僅因為設定的問題而出現。
    -
    Code Examples +
    程式範例
    -### :clap: Example: Using Travis (CI vendor) build definition to run the same test over multiple Node versions +### :clap: 正例:使用 Travis (CI 供應商) 的建置定義,在多個 Node 版本上執行相同的測試
    language: node_js
    node_js:
    - "7"
    - "6"
    - "5"
    - "4"
    install:
    - npm install
    script:
    - npm run test
    From 8a653fdfc35593159eb5030a2b202f117be59a49 Mon Sep 17 00:00:00 2001 From: yubintw Date: Thu, 7 Apr 2022 03:26:47 +0800 Subject: [PATCH 110/189] Update category anchor --- readme-zh-TW.md | 79 +++++-------------------------------------------- 1 file changed, 7 insertions(+), 72 deletions(-) diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 2c901fe0..2b20f0f0 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -44,27 +44,27 @@ ## `目錄` -#### [`第 0 章:黃金原則`](#section-0️⃣-the-golden-rule) +#### [`第 0 章:黃金原則`](#第-0-章黃金原則-1) 一個激發所有人的建議 (1個特殊項目) -#### [`第 1 章:測試剖析`](#section-1-the-test-anatomy-1) +#### [`第 1 章:測試剖析`](#第-1-章測試剖析-1) 基礎 - 建立乾淨的測試 (12項) -#### [`第 2 章:後端`](#section-2️⃣-backend-testing) +#### [`第 2 章:後端`](#第-2-章後端測試) 有效率地撰寫後端及微服務的測試 (8項) -#### [`第 3 章:前端`](#section-3️⃣-frontend-testing) +#### [`第 3 章:前端`](#第-3-章前端測試) 為網頁 UI (包括組件及E2E) 撰寫測試 (11項) -#### [`第 4 章:測量測試的有效程度`](#section-4️⃣-measuring-test-effectiveness) +#### [`第 4 章:測量測試的有效程度`](#第-4-章測量測試效果) 測量測試的品質 (4項) -#### [`第 5 章:持續整合 (Continuous Integration)`](#section-5️⃣-ci-and-other-quality-measures) +#### [`第 5 章:持續整合 (Continuous Integration)`](#第-5-章持續整合-ci-或其他提高品質的手段) JavaScript 世界的 CI 指南 (9項) @@ -1901,69 +1901,4 @@ Took care to revise, improve, lint and polish all the texts **Role:** Helps keep this project running, and reviews security related practices -**About:** Loves working on Node.js projects and web application security. - -## Contributors ✨ - -Thanks goes to these wonderful people who have contributed to this repository! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    Scott Davis

    🖋

    Adrien REDON

    🖋

    Stefano Magni

    🖋

    Yeoh Joer

    🖋

    Jhonny Moreira

    🖋

    Ian Germann

    🖋

    Hafez

    🖋

    Ruxandra Fediuc

    🖋

    Jack

    🖋

    Peter Carrero

    🖋

    Huhgawz

    🖋

    Haakon Borch

    🖋

    Jaime Mendoza

    🖋

    Cameron Dunford

    🖋

    John Gee

    🖋

    Aurelijus Rožėnas

    🖋

    Aaron

    🖋

    Tom Nagle

    🖋

    Yves yao

    🖋

    Userbit

    🖋

    Glaucia Lemos

    🚧

    koooge

    🖋

    Michal

    🖋

    roywalker

    🖋

    dangen

    🖋

    biesiadamich

    🖋

    Yanlin Jiang

    🖋

    sanguino

    🖋

    Morgan

    🖋

    Lukas Bischof

    ⚠️ 🖋

    JuanMa Ruiz

    🖋

    Luís Ângelo Rodrigues Jr.

    🖋

    José Fernández

    🖋

    Alejandro Gutierrez Barcenilla

    🖋

    Jason

    🖋

    Otavio Araujo

    ⚠️ 🖋

    Alex Ivanov

    🖋

    Yiqiao Xu

    🖋
    - - - - - +**About:** Loves working on Node.js projects and web application security. \ No newline at end of file From a9f2b2011bd6f12f433ece485038d23af61fb1dc Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Thu, 7 Apr 2022 17:13:25 +0300 Subject: [PATCH 111/189] Update readme.md --- readme.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 12274846..963d15dd 100644 --- a/readme.md +++ b/readme.md @@ -2,6 +2,8 @@ ## 🎊 April 2022 Announcement: A new edition was just released with 5 new best practices, many more code examples and 4 new language translations +## 👨‍🏫 Next workshop: Verona, Italy 🇮🇹, April 20th. [Tickets and more info here](https://2022.jsday.it/workshop/nodejs_testing.html) +
    @@ -27,8 +29,9 @@ Start by understanding the ubiquitous testing practices that are the foundation ### Written By Yoni Goldberg - A JavaScript & Node.js consultant -- 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - My comprehensive online course with more than [10 hours of video](https://www.testjavascript.com), 14 test types and more than 40 best practices +- 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - My comprehensive online course with more than [7 hours of video](https://www.testjavascript.com), 14 test types and more than 40 best practices - [Follow me on Twitter](https://twitter.com/goldbergyoni/) +- [Next workshop: Verona, Italy 🇮🇹, April 20th])(https://2022.jsday.it/workshop/nodejs_testing.html)
    From 56d762cc64171fdda5534d796e97fb5f51c485fe Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Thu, 7 Apr 2022 17:14:02 +0300 Subject: [PATCH 112/189] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 963d15dd..ca45db97 100644 --- a/readme.md +++ b/readme.md @@ -31,7 +31,7 @@ Start by understanding the ubiquitous testing practices that are the foundation - A JavaScript & Node.js consultant - 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - My comprehensive online course with more than [7 hours of video](https://www.testjavascript.com), 14 test types and more than 40 best practices - [Follow me on Twitter](https://twitter.com/goldbergyoni/) -- [Next workshop: Verona, Italy 🇮🇹, April 20th])(https://2022.jsday.it/workshop/nodejs_testing.html) +- [Next workshop: Verona, Italy 🇮🇹, April 20th](https://2022.jsday.it/workshop/nodejs_testing.html)
    From 24458e2b1d20ad4fa3e4637d0187fd84a36b2c25 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Thu, 7 Apr 2022 18:30:04 +0300 Subject: [PATCH 113/189] Update readme.md --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index ca45db97..e202c572 100644 --- a/readme.md +++ b/readme.md @@ -44,6 +44,7 @@ Start by understanding the ubiquitous testing practices that are the foundation - 🇧🇷[Portuguese-BR](readme-pt-br.md) - Courtesy of [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) - 🇫🇷[French](readme-fr.md) - Courtesy of [Mathilde El Mouktafi](https://github.com/mel-mouk) - 🇯🇵[Japanese (draft)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - Courtesy of [Yuichi Yogo](https://github.com/yuichkun) and [ryo](https://github.com/kawamataryo) +- 🇹🇼[Traditional Chinese](readme-zh-TW.md) - Courtesy of [Yubin Hsu](https://github.com/yubinTW) - Want to translate to your own language? please open an issue 💜

    From ee52b39f5f8daec36cbe364912e292d361e60f9e Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Thu, 7 Apr 2022 18:50:55 +0300 Subject: [PATCH 114/189] Update readme.md --- readme.md | 65 +++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/readme.md b/readme.md index e202c572..0916a0de 100644 --- a/readme.md +++ b/readme.md @@ -84,11 +84,11 @@ Guidelines for CI in the JS world (9 bullets) ## ⚪️ 0 The Golden Rule: Design for lean testing :white_check_mark: **Do:** -Testing code is not like production-code - design it to be dead-simple, short, abstraction-free, flat, delightful to work with, lean. One should look at a test and get the intent instantly. +Testing 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. -Our minds are full with the main production code, we don't have 'headspace' for additional complexity. Should we try to squeeze yet another challenging code 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. +See, 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. -The tests are an opportunity for something else - a friendly and smiley assistant, one that it's delightful to work with and delivers great value for such 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 which 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). +The 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 which 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). This 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, strive to keep it nimble, sometimes it's even worth dropping some tests and trade reliability for agility and simplicity. @@ -380,7 +380,7 @@ it("When a valid product is about to be deleted, ensure an email is sent", async ## ⚪ ️1.6 Don’t “foo”, use realistic input data -: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 [Faker](https://www.npmjs.com/package/faker) 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 card, 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). +: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://github.com/chancejs/chancejs) or [Faker](https://www.npmjs.com/package/faker) 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 card, 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).
    ❌ **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” @@ -536,12 +536,12 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => {

    -## ⚪ ️1.9 Avoid global test fixtures and seeds, add data per-test +## ⚪ ️Copy code, but only that's neccessary -: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’](https://en.wikipedia.org/wiki/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) +: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 mention explictly 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.
    -❌ **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 +❌ **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
    @@ -549,45 +549,41 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => {
    -### :thumbsdown: Anti-Pattern Example: tests are not independent and rely on some global hook to feed global DB data +### :thumbsdown: Anti-Pattern Example: The test failure is unclear because all the cause is external and hides within huge JSON ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") ```javascript -before(async () => { - //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework - await DB.AddSeedDataFromJson('seed.json'); -}); -it("When updating site name, get successful confirmation", async () => { - //I know that site name "portal" exists - I saw it in the seed files - const siteToUpdate = await SiteService.getSiteByName("Portal"); - const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); - expect(updateNameResult).to.be(true); -}); -it("When querying by site name, get the right site", async () => { - //I know that site name "portal" exists - I saw it in the seed files - const siteToCheck = await SiteService.getSiteByName("Portal"); - expect(siteToCheck.name).to.be.equal("Portal"); //Failure! The previous test change the name :[ -}); +test("When no credit, the declined transfer does not appear in sender history", async() => { + // Arrange + const transferRequest = testHelpers.factorMoneyTransfer() //get back 200 lines of JSON; + const transferServiceUnderTest = new TransferService(); + + // Act + const transferResponse = await transferServiceUnderTest.transfer(transferRequest); + // Assert + expect(transferResponse.status).toBe(409);// But why do we expect failure: All seems perfectly valid in the test 🤔 + }); ```
    -### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data +### :clap: Doing It Right Example: The test highlights what is the cause of the test result ```javascript -it("When updating site name, get successful confirmation", async () => { - //test is adding a fresh new records and acting on the records only - const siteUnderTest = await SiteService.addSite({ - name: "siteForUpdateTest" - }); - const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); +test("When no credit, the declined transfer does not appear in sender history", async() => { + // Arrange + const transferRequest = testHelpers.factorMoneyTransfer({userCredit:100, transferAmount:200}) //obviously there is lack of credit + const transferServiceUnderTest = new TransferService({disallowOvercharge:true}); - expect(updateNameResult).to.be(true); -}); -``` + // Act + const transferResponse = await transferServiceUnderTest.transfer(transferRequest); + + // Assert + expect(transferResponse.status).toBe(409); // Obviously if the user has no credit it should fail + });```
    @@ -784,6 +780,9 @@ A word of caution: the TDD argument in the software world takes a typical false- :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 from both worlds: reasonable performance and a possibility to apply TDD patterns + realistic and great coverage. Component tests focus on the Microservice ‘unit’, they work against the API, 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 outwards to inwards and gain great confidence in a reasonable amount of time. + +[We have a full guide that is solely dedicated to writing component tests in the right way](https://github.com/testjavascript/nodejs-integration-tests-best-practices) +
    ❌ **Otherwise:** You may spend long days on writing unit tests to find out that you got only 20% system coverage From e5e919db708ab9dfeea5f43c309261850a471972 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Thu, 7 Apr 2022 18:54:45 +0300 Subject: [PATCH 115/189] Update readme.md --- readme.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 0916a0de..1edc39f5 100644 --- a/readme.md +++ b/readme.md @@ -554,7 +554,7 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => { ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") ```javascript -test("When no credit, the declined transfer does not appear in sender history", async() => { +test("When no credit, then the transfer is declined", async() => { // Arrange const transferRequest = testHelpers.factorMoneyTransfer() //get back 200 lines of JSON; const transferServiceUnderTest = new TransferService(); @@ -573,7 +573,7 @@ test("When no credit, the declined transfer does not appear in sender history", ```javascript -test("When no credit, the declined transfer does not appear in sender history", async() => { +test("When no credit, then the transfer is declined ", async() => { // Arrange const transferRequest = testHelpers.factorMoneyTransfer({userCredit:100, transferAmount:200}) //obviously there is lack of credit const transferServiceUnderTest = new TransferService({disallowOvercharge:true}); @@ -583,11 +583,12 @@ test("When no credit, the declined transfer does not appear in sender history", // Assert expect(transferResponse.status).toBe(409); // Obviously if the user has no credit it should fail - });``` + }); + ```
    -
    +

    ## ⚪ ️ 1.10 Don’t catch errors, expect them From 6283ef1c4c52f89e90f6b2f4a54a33b4e3a17221 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Thu, 7 Apr 2022 18:59:40 +0300 Subject: [PATCH 116/189] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 1edc39f5..7ae13adb 100644 --- a/readme.md +++ b/readme.md @@ -806,7 +806,7 @@ Component tests focus on the Microservice ‘unit’, they work against the API, ## ⚪ ️2.3 Ensure new releases don’t break the API using contract tests -: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. [Consumer-driven contracts and the framework PACT](https://docs.pact.io/) were born to formalize this process with a very disruptive approach — not the server defines the test plan of itself rather the client defines the tests of the… server! PACT can record the client expectation and put in a shared location, “broker”, so the server can pull the expectations and run on every build using 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/CI and might save you a great deal of frustration +: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 are 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 it to use [PACT](https://docs.pact.io/) which were born to formalize this process with a very disruptive approach — not the server defines the test plan of itself rather the client defines the tests of the… server! PACT can record the client expectation and put in a shared location, “broker”, so the server can pull the expectations and run on every build using 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/CI and might save you a great deal of frustration
    ❌ **Otherwise:** The alternatives are exhausting manual testing or deployment fear From 2f2aa2439a6b8bbc3c82f42a417982a4d4bf38e0 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Thu, 7 Apr 2022 19:00:17 +0300 Subject: [PATCH 117/189] Update questions-answers.md --- .operations/questions-answers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.operations/questions-answers.md b/.operations/questions-answers.md index 47fcd2f4..2f71c638 100644 --- a/.operations/questions-answers.md +++ b/.operations/questions-answers.md @@ -4,7 +4,7 @@ **Answer:** -Welcome aboard! Having a Brazilian Portuguese translation would be awesome 🔥🌈👌 . I'll be glad to collaborate with you on this and help wherever I can +Welcome aboard! Having a Brazilian Portuguese translation would be awesome 🔥🌈👌💚 . I'll be glad to collaborate with you on this and help wherever I can Before you start with this, I've prepared some basic workflow guidelines: From 64a7e3fe800d62b5852a3673143dd2d1edfefa92 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Thu, 7 Apr 2022 19:01:27 +0300 Subject: [PATCH 118/189] Update index.js --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index a068a34d..e3c1c215 100644 --- a/index.js +++ b/index.js @@ -1 +1,2 @@ // This is a book for now, but code examples are coming soon +// See https://github.com/testjavascript/nodejs-integration-tests-best-practices to see an example app From 4b30fb5ea5d6e9f37f92647b248cc22ed56ceefa Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Thu, 7 Apr 2022 19:01:36 +0300 Subject: [PATCH 119/189] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dde3fe4b..daf57f48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "javascript-testing-best-practices", - "version": "1.0.0", + "version": "2.0.0", "description": "📗🌐 🚢 Comprehensive and exhaustive JavaScript & Node.js testing best practices (April 2020) https://testjavascript.com/", "main": "index.js", "scripts": { From d0ea212465ce0366a64f0cc1f5ee9bf672878bce Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Thu, 7 Apr 2022 19:03:58 +0300 Subject: [PATCH 120/189] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 7ae13adb..f5123694 100644 --- a/readme.md +++ b/readme.md @@ -536,7 +536,7 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => {

    -## ⚪ ️Copy code, but only that's neccessary +## ⚪ ️Copy code, but only what's neccessary :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 mention explictly 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.
    From 3d8d4c6ebb874419ba8c30126fe8ccb585449e51 Mon Sep 17 00:00:00 2001 From: jorbelca <76847923+jorbelca@users.noreply.github.com> Date: Sun, 10 Apr 2022 10:54:34 +0200 Subject: [PATCH 121/189] Update readme-es.md grabes to graves --- readme-es.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme-es.md b/readme-es.md index 3325f51b..c80b14b5 100644 --- a/readme-es.md +++ b/readme-es.md @@ -893,7 +893,7 @@ Crédito: {

    -## ⚪ ️Copy code, but only what's neccessary +## ⚪ ️1.9 Copy code, but only what's neccessary :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 mention explictly 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.
    From 8f84be8ebde5be9195c2caa5894f91d4ef6fd9d9 Mon Sep 17 00:00:00 2001 From: Simon Ingeson <44818+smonn@users.noreply.github.com> Date: Mon, 11 Apr 2022 17:52:19 -0400 Subject: [PATCH 124/189] Fix markdown issue This was hiding the following chapter (2.10) --- readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 631c1b29..5d2638e3 100644 --- a/readme.md +++ b/readme.md @@ -1023,7 +1023,8 @@ beforeEach(() => { id: 1, name: 'John', }); -});``` +}); +```
    From 50a00c724e7ed74f4fa57fa47bd763f01f18fea1 Mon Sep 17 00:00:00 2001 From: Simon Ingeson <44818+smonn@users.noreply.github.com> Date: Mon, 11 Apr 2022 17:53:07 -0400 Subject: [PATCH 125/189] Fix chapter numbers Chapter 2.11 did not exist, renumbered 2.12 and 2.13 to 2.11 and 2.12 respectively --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 5d2638e3..30f643d2 100644 --- a/readme.md +++ b/readme.md @@ -1063,7 +1063,7 @@ beforeEach(() => {
    -## ⚪ ️2.12 Check integrations corner cases and chaos +## ⚪ ️2.11 Check integrations corner cases and chaos :white_check_mark: **Do:** When checking integrations, go beyond the happy and sad paths. Check not only errored 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 @@ -1109,7 +1109,7 @@ beforeEach(() => {
    -## ⚪ ️2.13 Test the five potential outcomes +## ⚪ ️2.12 Test the five potential outcomes :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/reactions can be put in 5 categories: From 75f4664c7f11caab833a1790e702c3dbfef041ec Mon Sep 17 00:00:00 2001 From: Simon Ingeson <44818+smonn@users.noreply.github.com> Date: Mon, 11 Apr 2022 17:53:51 -0400 Subject: [PATCH 126/189] Minor grammar --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 30f643d2..b519587b 100644 --- a/readme.md +++ b/readme.md @@ -1065,7 +1065,7 @@ beforeEach(() => { ## ⚪ ️2.11 Check integrations corner cases and chaos -:white_check_mark: **Do:** When checking integrations, go beyond the happy and sad paths. Check not only errored 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 +: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
    From 867a2a008966e4778882fd84dae3ee7e2f8d5e84 Mon Sep 17 00:00:00 2001 From: Simon Ingeson <44818+smonn@users.noreply.github.com> Date: Mon, 11 Apr 2022 17:54:00 -0400 Subject: [PATCH 127/189] Fix typo --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index b519587b..5a91cb28 100644 --- a/readme.md +++ b/readme.md @@ -1070,7 +1070,7 @@ beforeEach(() => {
    -❌ **Otherwise:** All your tests pass, it's only the production who will crash or won't report errors correctly when 3rd parties send excpetional responses +❌ **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
    From 4070c5af27e06d340ae24eae4e55d923f7396850 Mon Sep 17 00:00:00 2001 From: Simon Ingeson <44818+smonn@users.noreply.github.com> Date: Mon, 11 Apr 2022 17:54:10 -0400 Subject: [PATCH 128/189] Use JSX lang for React --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 5a91cb28..f9d05d18 100644 --- a/readme.md +++ b/readme.md @@ -1201,7 +1201,7 @@ test("When flagging to show only VIP, should display only VIP members", () => { ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") -```html +```jsx // the markup code (part of React component)

    @@ -1228,7 +1228,7 @@ test("Whenever no data is passed to metric, show 0 as default", () => { ### :thumbsdown: Anti-Pattern Example: Relying on CSS attributes -```html +```jsx {value} From 0f14693fc8a3c931fbea01d8108aa89f5a113c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=9B=AA=E6=B6=9B?= <99980283> Date: Thu, 14 Apr 2022 17:07:31 +0800 Subject: [PATCH 129/189] image: translation some image to Chinese --- assets/header.pptx | Bin 123258 -> 123258 bytes assets/zh-CN/bp-1-3-parts.jpg | Bin 0 -> 183192 bytes assets/zh-CN/bp-12-rich-testing.jpg | Bin 0 -> 78756 bytes .../bp-13-component-test-yoni-goldberg.png | Bin 0 -> 252049 bytes ...4-testing-best-practices-contract-flow.png | Bin 0 -> 223587 bytes .../bp-20-yoni-goldberg-mutation-testing.jpg | Bin 0 -> 179509 bytes assets/zh-CN/headspace.png | Bin 0 -> 474856 bytes readme-zh-CN.md | 12 ++++++------ 8 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 assets/zh-CN/bp-1-3-parts.jpg create mode 100644 assets/zh-CN/bp-12-rich-testing.jpg create mode 100644 assets/zh-CN/bp-13-component-test-yoni-goldberg.png create mode 100644 assets/zh-CN/bp-14-testing-best-practices-contract-flow.png create mode 100644 assets/zh-CN/bp-20-yoni-goldberg-mutation-testing.jpg create mode 100644 assets/zh-CN/headspace.png diff --git a/assets/header.pptx b/assets/header.pptx index 925889c9b7d2b533109f2de5174f881dc26f7ddc..57b1eb07bc9be21a055849706e628541d2409fb9 100644 GIT binary patch literal 123258 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 BjHLho literal 123258 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 Txuq-6IFK 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 diff --git a/assets/zh-CN/bp-1-3-parts.jpg b/assets/zh-CN/bp-1-3-parts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7a90761124e415bc0d8a1b315b9214ae8e38f805 GIT binary patch literal 183192 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

    MP_#S5s=yrw7DkCTrcRg& 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

    !*RRg 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 H`9AqyQdg9Q literal 0 HcmV?d00001 diff --git a/assets/zh-CN/bp-13-component-test-yoni-goldberg.png b/assets/zh-CN/bp-13-component-test-yoni-goldberg.png new file mode 100644 index 0000000000000000000000000000000000000000..e943ddc2ea80e6ad84543290ef5568285b5fcec9 GIT binary patch literal 252049 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%0A(#F`u5t|k#> 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 Z%UQN(7%A@2yvbX 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�djPo6FvLZb5R8h7`CHRT@C@wxWP(1Lh6<|-JnH;0@=e}^c{G1Y& z{V=S<&)TzQ)I$tnJ1?ek!2u?4>Yf-zsqIflZw<$MzTMu3T{Vy+vz?h5;2^J2+2;l! zl%anRCcv<pJ~R{>|a%O{ohvH{)}@65|Zl2h^HP(wd(xYf-hn|LFvYN z+luS>(c*k~qKoEF>XNF0dyf!cVp$|w4blM5u&+_x8RVAwHeCOocTECY4V2ywq4!Io zeOt_1#D9>+B40+e%aK+-glE6B%So+{{@f1#V*X{76KX#9qt)7CX{7Qjy#FcYg#K&7 ztikQoIrgct3{IPYQ6);L&v-cvEL%8>Gr0`9brasw{xT32zWyG@9ZCww=9cr0gV%ql z;P4x$+!I`Q9Tuza71+!6&1|y?+w#)xZ`%+bq$kRLu^jfS5$$w z+>O>(B`nmSE@BnIGs7rzOrcH1%9t(Y$g1%8v*SPwr^VvyUc4x?E;N{F9Wm-Tzb62s zOtI|SW!pFL6twp)Y>+1K1|WmSqkKCWbgeuzX$t{aB^9G@#O*@0oA0goT>dv+GbmK&io857uO8oUf&%)<_SQzJh zCH;^6e7(iyY#x|O>|kUyrfxFZooGeaE{Mq7f`Wnb!}TSD7{oZZ%7AiE)@vH~$;g1G z26RD2-v+p}Tc*=QK7h?lkbVtIVbxhi`0)WoTE(D;4p9UnU_nevK%~&?fNJB7qikeqlVys=mt>iQcQJ z3c*;pCFi`J^bH;bd>t6iLg?=N*qv_Dbl7_f5E< zBJH0HY`+9}C%rRePT1aO_AQ`n$PnH!^xu;;9)V-g1{98ySJJYH8EhoGHZkqTPU< z*EyyEde3-!NthH{Qx!e;3O<3@P4BN9CwVIDB1W|_qglwolD0%H4&4VEN110qhC5zXw~+>&8he!Mq3PE1a8BrVh4I}G!}}qKmBC0{I zy%m_=QvQeXNHG2T3d15nrrn3+JG=F;rXDPjhwwo_C4Pt3T};i30^M%R;y%&yKfqKi zpNDHJFgO~WfYK}WjAROmyV5gq9I#%+x96o%7=ov|TcUIMx#A#Lkw4(w4;;rthIJHl z15mke@n_A8SBY(T8ab(PI-J)OHHO~)HzqS+6T6oglW zaX2|~PrcXAE(_2o!CS7ItOHnBh^~Ueec_OsSyed;aDGU@2W3Sz2H02f2fo<`zh<#| zwo9iZraNd$2(3Xa2;EOqkSqM8w_*j*1eN3u?#`d;xY;4X=b8M$Coi65NuoqoB;ZTM zA}CWH()q3yW0sCQ-I@A-&oZxAOz(ELPPq+Ibi__hc&B51y^W`huG%ND!aC79dWb!A z-itwD?H6aB7N3+feqj=xVB}+S$DAQUzX-gQQCOgSkR*ruS@p3rzlCg6zeJYqFwC;5W_RFmp|bz+b4dy zg2kF_*Sogor{2?kZ?t${4QR);1asqVR+z!6%5aPp&5OaynNrUue(2C}!IPu;GbJZobeO>N`jv6YHV?ysG`WZ!iJziP$uCF z6i|*$o^K%PT~%ZwS|?Wi}wkFI_KJ9~D4tW;PbqnN3P%>6QI1p0AdZ4Fv1B=Ik+-s@Kv2jp}lN7l) za~@g%DQR161)Gm|LI{-u8P6msW*UaMu#Wm5r71m-(Wy|oI*G_*jvU9*d;=7n(k2x z^yOriY7-KgjMUaU-tM4=BP7^ZK5UN-i2wWxBe5EP(Q$l$SCDjOzZva| z5B*6e<)a?v^DKZJW1GPrhBS()m7)t+*(Igus@8K@7W+FHXH~f}lIo?zz6?_Y!0#beI)exW5_<}c>W|*1Efn2eZPhlu*|Fx$6Z-ZF8EEoD?Qo>R zj#ix#c)dBL{(9+B`P~R^F8>C3a-@R|f}dzdK9(5@Jtk;c15dusT@8NGijK9 z(dq<56H*hN+{Opgle@vj1=s>Jd=`9>xri5q!5$64hw4%R>)XwLP+KS0MK=uJ_pqHQ zrst3wNe;*n&pz*6)F*l3KB2RglU!Wrs}@9~_ljLFZuPRV*@m-%}mhbaU|G-K?>OnZH3dGsOY)R^1?|$&#iG5!jeLYb;={Rx`84 ze-%0R=U!2tUYy82ZTiN;X~GHQK6~XOdMf!AklsdkNJ$LDxH-{~Bz}^$ETza%9Io6w zIBUBtM0Hq{wbp3vhHrC9$jb2t048=r48bqR3mG+!1#3d5h3ZN9J}tMM0!MOkeE|^8 zbPn2!N8eGO!%qlQC`krYsp00K3J7B#ud2aRH~qG*d}XNNqTGq(E(Yt+&a9UCzVi*!*CnK`s`j5))<&Gg+LS77R`QWp>-{%s5Vmjjx?W5s3foeT9ox50| zIY&+5;#>fI#?U z54ci(+OI$IRbP;ZHmI9@yrKY5v!EGJV>kMk=a+P?<_!tmD@Cugtu?BR{lOf zpoZHt>rwooNNp25Q_{`#q9%4}V@O#jbH$gL3~3~GZjV2@#ivfRhNBwa&cs;!Kc?P1 zo~`Wv18&E(X1-m_jOkcvscFl!S{ei)qOI04YAb4sXho}}sKy#XJ4Q{_Zct04ttA9e zRV4^rNUVt>iCSABkpw}6CYC<8^Lt*;>-o#;75AK+lY7rSpY!>=m(uM{0U!)zAqh6f zUjXESbV6(R$SlN`ac!_>xzZKdEhnDc$f8l9aGFA8!g4dlh@I;gT;i)S^#Z_ga%5LT zP$-$w_Sl-{8dn5v_}1MhDcmJ}z-*^A&6MybQqm$F4e*%Wi7K%!9;6;Uo+ax|>7_%& z*U#8cb5G#`PK9vsns4aH#f`x~{LKq|+#d4i@wwibaxY|oZRdy^K! zn-b8Gi68YhBa1DfGPn36TSARFbY@-3DeaA)w%(F>J6R~4BqGG~EeA7-fa9TT==^-`w?kT9>mE*m%htE=6;zLDO90 z{+n`NW)iCG|CQYroJcXM|!orY@>NOd3{v;h-M=T;=b7-Z>w+k#9RxQ zde8k+#9V4Ne|=>A-k$MSCzlY3^M>Ygf{r3x3(`hEV(pm4mU2TiQcY>^-z5`t<%Pg9 z_sNog_LTA&$T{O616mJdy+he6H;Q^J ziHD`^JeM%Oj#H_b2u!WOfozWsIPKsj=r`b@#rS*U!>d6Ndf4801u~sx_RUr z584eR%`V7tDKeFxcL17?@^joOop)}34IWTZ%Sfx30`=_T!pxCF8%Jh5c{0-*FVUgq zNISvx$l|E9hF0t^NZqMl6FpP`nTShf?cbWU#XEqXQ}5uQVK zpDuh`x_&am8E~t=0nKa_2}?X)-`-rxw`lvCxE1zw>5I?yx9YdeVQ<}BO6pAjn%z1% z^0BAY@EUkLV`?cEJ)x51zH4kTLRT*D?281d3i-PMeky{S?LRzC7zXVy4~`w~*{x36 zxZo=ssU-Xt#5hn#z1bM?M}}u`^v0+qGN%ZU`Ajr$o*nmKF-+gCE{bi%Le=zx8#{qR zrva>cSU$24SlsoOaNZ&O(qXeF{^$55=&UgCDf6=Qethf;2yrZZJ`m+L13)U77_7!8z4R5%90IiGKl!i|tC_$&AG0wLnyRHh0Dhcmmoe54QfiR}ZnGDtm0z+=%#k0vTLqSO8i? zSou{xiKx#wS!Xz7=3IkYFRDhJjW`qeQ8zN^vFfJ2?*Tqfm2V|5&}V%^cA~o~O*iHO z2On-Xo_sy^LHNV+LxECe(bK5$1Ip}z^`)5r&7tWaJ^+QcxNXUUFd%w+ zdJe2690?P2d2afb%A9~bPzNw%Y5`n&D5k?AXzd2RXh6jzUouu`a;tQ24Y;iX3E=$q z58LFTNUx~l1$Jd;qdWJ%$PK;zU3#Qfae!vr&;8yzqp!ox0ICp0BhSK=UFBF8=yioX3BwJ&(Laz!aZF;+%wGEax@(%_O7W=m;sFQA5GvS;bvy8m zz-jSHAs+CuR7W3P!0@2~XE^u6IwGgyh$$@al;)yUtx)3g zeqrpDrhl#;C)fI)z%ytEz>&NPgx~R-cSp>}tbGOCNgFe(5&=r?!ODaoRgUiHxoeR@ zHG3luvT?7dqvzQt16vp6U8kQ}X19{|A!k+9o#?^E?q@dl3a(l%F+FK}CvGIzur6+8 z{x&jA>RM4*Hr#w{vD69n7gcL}E!7AK30*5bBV$e>n+6KhH_GK9np(}oe(?FkVZ-Lb zW|azEwdkJ=^`@NCcS-d2j>gr|=EI{u8J0$l%j)>@-#cGGxu(x|dr-1$uw9b%{6M5&birUl+zL>H?(XLl zI#o_O7F+@KJSlQNlky5D?WKD*ruLJrX*04C$&PH0O;LDE(zV^-kAbmRufbU zbMrb!?(Z6XlMoU@%PYm|C{5t`t&Nlc0fl<;s}S>gYc3#?bIQ13xWZDh(7K_8q@tH^ zz^_TywL%Ib98mX4?+l5u;e(bN4Ve~zl`JlWFHUKb1*|oO7DU(1rUexEbr-R0Y1+P2 zv-+9iUh^IeN9vL{0L)riQ1gC+0%=Ad31kvP5574Zd8G}>PihEy61}XfjK8O=?Xa2M z>*OnglrNpCpOL=O3h|te2EQ0?dX21!7oOk%fS;^a7ZOvQ06ZNcZ8OVV&8z^K=hrYi zS?M@s6o{wRI3706lPsQ&E5t*3n-(uaxu8t4c)WgRoL0EUweC39>%Wel z7kbX8^UmqD#k?FjCz^$vSPDoL1sgVx*p6SkLtubF{7f74j^O^q%USiR<&`KcA;5Cj z3_roI!DAe*P^xY^nuAKqfdsGW`{)P-;bmMD{So$Fx^|qQlj^yQ>Ak)v$Hcw|jpf=+ zW8Al`8HVQHx3POmxoMFhBb1j;n?(y>h?--x>2W}w!WWMbx*iwYJ0t{T;(Y1X>&9r` zNMsKr8&`a;scxC-s5FwcZfWwWJ=hO0OFzy+RM||r*LWBuftK6?xsVIm2H=FzC9Yrn z)}Je>ubN=WOw179zbW0Qm=adv%3&Y*VU1r||E$8BQMrw!8ujGSEOf-uN7Yl$uGeM?2YoD{i`3mx|w=mbD*iR)IxMS-D0XyZd4%Guy`Zn zubHBflPGg}?vpq`X)`>e@D6wMKu6I)6XMVn*)q~1AY`N8GysU{b5HH3q7U(^wb}SP z+*75L7mo}B+fkP(;M__VbcLm|<;Ywqj@i}>Hv|j3^{a!1%*s(X^U}yEtIGJzhJplo zP6y?m)$iVXGp$l*@A-5*cI3e7f||@<^X=f&QzIF!$bB!uAjVkx%+ zjSLBXg8l~*vK0yC)hbESYNtTJqb>XkReP*pD`1kcf6x2bk|yTuqkhk*t&68V>K9@r zY=%3AzI7UdWiHHsO5ab?eG;KQSb)3O&Hjt*3(bFD@6p zt_s%-exg2iFTnBam|U%WdQ=WJmsN~^l@lJ!947?!md>f=NDW(~w=P1rg2hc%eqWOP zVt64l8zG|j4S`?m5dVTn&#A2H1q2qhqP4^g~(@ zw40uiE+Eeabf!%(vdvsXwpVqgEbXwt-X0K34D9h<6V(F-e;Qk#FUCrSrg@c=c ziv#!<1q(;*6IJU9<86;dLGFrNab-KFSREi+OR?*nwThkc%;P(0eBhGQrcPBLt2wFg z$%=L@?qS-4j)slT1M)jTh$YD8za0Uvtp&M;b*&xUMxgXg@hH;X{6TgRiWFde1E>^Y zulL^&2ho}_RUaHJdFspkoT!KE=}ihUDm{Ko3US)98}GbWFE^HpU&UE=uipgFG(3oOI;y{4*4yc@g zWg{iyfaD~P2Lfg{SyoPs+582I41_Ii2hn#Riv3tYu{_pht1f%pqp|$AVLS_fUs!^d z4uE#jBXoeNC4Ph-Q+gM5BG(wS{9RU5&MKk?d+rug zTmz?DVEn#N3vZ_K?o29Q0fpRJ8?S+UV?=MAP;u4yGS^1h0d|&vTJU%dgva_ph@ZbX z-qv&wy8vW4eky)Q)@_XIx47P{-!<+u9Ojca{KQY1^?J)NKkmDDWbjRo=HW*jc9H(^1Caj? zKgX7q7%Biydr)T%V0Qgy*;M59y4Qf{VbDKYA(KbRQ0=Dir6g~cKv-{#@LFR4l>MIN zfjonK!+?D|Mn8tl-2Z?g;o|vDHZ8hm(d31mW zIK>z%H_;EqJUmqp>p8zp@SISbtHh=zpw#$Ii?8TIQL@^lW6OvVrXxUaG%P=)J6PZT zYUc;N=QzVGdxwjY4ez&&fEz@@tqu?lePJyCN+g^h?C@$yqn=j&s@-w!J^BX}(9AM0 zg@#&A8x5M!-8tf0wgjUu$fgsgjYlShQ2`|^`L{Md+N|a>GV$wtCvE?w}Ro{UH=>bXn z!o^y4={i?CJtEDk*lZ^)DT?Y{uK+Q>WG=kmqxk{=jY0t^2=6|o$D5l*SZY@V%ozdv z{ko6I;LB8dYJA-Ar0my?p-hjf#XmV=S?4z$EE}51aFl!EZ@fpANrrn3 zOg@q|p4dC&Y~6fSk87;*s0kwlh8VGKQWl(6k5u1$9hTD(wanHEs!1Ak+)5b*JZ2_! z&>QyHiG%DX+mA-yOriFi*ZyUe`vl#PW)GC+13X3~{&0#_C9?2UAp=`C`!r+{V8;L_ zvW5Fz=BO@Dpp=121E>jVD+Di6mm%9M2&Wu4*KwWrfuWkoh@ofE>J_RVth?fW>c$}!W3 zaB9uN{S>|6v?b3@qF-Rm-LVXO8>)E^yI5;j+R-RS2`JH0K_B8!N~@GYB!x-twLAnP zJ3xapdLB@$!WquMA`X>jKsLWyatg?VzxQMvjea#PQGUKu0w#B^tE)R{KJfq>bnofh zG9wtXv%VHkHup3yo$lXJf?rxE{(3q4_wRoE^ZZZy`XBl0KdAAy(x7*fkgwkPS=YGz;`6_Lu>Jjy|NZ&>m5VMe+0UQ<<+;1~b=QI3CN4FZG2xb=mU1t7 zb?O)*(?oHd(P`ujSX@5yC7!b`X^^E_an;h@IkB7m$n9^CsA7{&>EOuB^Ww=l?OZyl zeBZivk~7^WWcajvA4Ef}D(jPa#)cdLn1aSMT1TdDx~y7a%vN|s)|~!dW{n8_XjGan z-tzo1#u*yqfuA;r*oUTNtY(d#H{E5*XP6oUo!Sre>2HlC{)6!h>@wQqo2)N@V|KNS z{8e$H_QtPrneSD1#-*<%e}iRBAX7c32A16G!mxCmGt6j>G8x3l(_5hpqvk=Ob$Kf| zx2L|SdQEaEa%TO-pqZuBO+C20`KG=MMn?yMnr5;eO& zwFn+LnCz)^IX`^p(oI-OT=k6fv9H(>{Pne)1V@;4-+kGyH?jQ%0MoouFVJz5I_kde zWiU(h^63-&*It{GyY;;_e#|}LD{#UQ_i1DsSC_k{ZZG7rcz1H~ViA0T%Qln5O9Ay`wvH{@mLE>OX~L5$@^C-C^2f1CPEP$z8uSvBu^5*S9-dh-N)?iTW_ zEFs$0Xe}q~I^BfAcNkH&)HAB?_SkwmIq>7xjj*q;rM$#l-YF6KRHliBNylnB!MnXs z42a_SR)Vms^7^>$%%;y5mX6MRp;l`oYRI?n9l}~6;sHZ~G^S)1a1#q}&8nbEzbOWu zV!thkZXLm8uuhLzYNSNRHAhcuf0H>`_xw(L54l{SkL4Tbiw_u$zEF5dO9OWTQf_SS zMsw%RuksqlH4OFo_#9e-*z=r8CPhPk77AO4QS%fY01V24V6v{BnQg8KUT@kH;EUe^Qwc#8?e@}n~nQuI_jD-g?a>v#Bz2jxME6?TRca2iK< z&ct_)){kjh@;bFGX(g|VP!8#hAv+}rr8#S@zT98t z--7c3*-Bl+l39TcntZy{O?;7#ODIJfltw!8EZ1y1NsidNl!f@y3cz7WL$S;(u$uP6 zCZniA!*Sk)X|FS6Yi<%&A%4Ppx@Jdl#>GWQo|bHt+qf&>Y^ZOs&`xUEJM4|QL%6SS z-^;9kI{z%Jt;Oww%bz9AOgn%H-9jtD(=I@|lWD~E-07?adYGepn#HoMT(#?rPfz=% ztI$?Bz>Gb!b+KtWS~HzO{jEV?vZfLbetvphFS>C3Hu+P41AGM}uY|9)5tm))Z->g2Y{|8nUZ#1k zd@%c7mAhvH|M(8IHk*9g%ka}6hwwPsA}-xzMY-WO?g+=%&cmASJr;WFQ@KV{)eScvrq6Ut~500)Kgb4#2JCg8t zeM|dKtDhP;pnwt1fatr-1`Yiw=e^$Co5=KqBhkM)m5W>Zl03OYSd}AK;1N(~s}OWL z%vOQ@<7T)4DIC+Hho)EQ@$cah1?K8$_Z;VYJtaf25$MTJ=fWeKvblo(Hyq#sl(oh? zblx;&M2U!5X{myq77>3lAcW6%>+S)RW)kj*zj5AO51$TWUc^`l-eTJ|3=qsDo_S_Q ztwSam*BIOo|;@k>38!-EB{Jt(cw?_WP2Q*-vCg{I~a7lC~u6 z$foCIR@|W&9LlD)TI7FzQmheOZdV7i_-J}z{=~!F-yD@8A3j}5QPcVJqC_2*$@qL` zHA~y#B}ajfQ`)%IMU(^A~ySp5G&W_;-x0)?W+q zAKU5;#hg*m&BU|lyZ5yEcJG0@yTM9vwXRAxFlu8F7itcmGz{DCL&0B$14GxLh?Ne} zR>w%=J7}>}e zh2;r8n?j$aM)t6G+!dxuNbVMAR#!0D66fygdWZXhNE`dlC#PDU`4CYRrKI2zn-<^u zR!>Zi{jyz;Vb&M}xOqbpg@lzPLW6Q$!#fEIrE9H$-fg2hS-^e7gao$q#**rNRb$61 z?eqQ_gHE5uB7V0@%QanNzK&97n|O8_U!Q5i4kK9?)HCg7OP96IHh@ZYG1f3N-u-Q4%`-YvOo~9M)`35-s_=Ph=Z4i%zN)nibn4O? z5+`c?R!{Dt&)~kAa*3X1UtiZsHpg(}y+s6Fl@!)hY_%h9`^ zLjFhPH<>%P&|~@(`4@5u)0PD*22LCJKq}%}>UpQQ9q@kx&HHW7Dmi5qUbp;0{=&%5 zy~?`MzqP*p<$;DA6!2`_z2&WgKBp<1U%d`XIDB8;(sd&nDl(k^>jB0nx}Br0lc=F9 z7z>SVn+O5y#ij#gUMnr(;cuy`^)0ih{FAw(&na6|BA9fqcM86t47%!QKPeW(9q`5G zz@|5qTT<4hHJQ<|RYp&tF=_?{O`mor=8}bPngkvonni0n`|=`ti*_yIDwbm>IKpLOdr{VVi7PCbr?AVKol2@%yn3YGU5w3|ZbJCQ+W7&#(3E5_V5Ra8q)=(Nf>8G54}Gpci(;TZ*^l-jz*;id zR)p-#=Dw5Fk|&!}NIL}92DsoOO7v5Lq{+#aa)L+>yTtNGGRX#D!N|7xn$HA9K zD=}*~PQ%ss-#vb;;W!qtSAY&yf0JC`-}=XV;Je*b<g7}L)qy)p$a$P#s99m`M*vkSgwU-pD9K>Zcb|osE{t8CZgQ5o+ z4OGjfw0+^4R#Yz4v7+w$$ozF+C2$2iWoB;Dw}37;TRtMvpB>+A3|1!~v44%Po!#?4 ztvytM6_;1F{e8o_eCExL;m7Oy`He@2y`CmfSdRl5_P|mHG=u>2R3zrNoWK1@%lP!i89p;I76FPRK31G34}HG)H&}S_aYNYwM_=3F=Qpu2;-|$G zr#{`qSM=}`a}xxsijd_uDF=)PFQ^Nz^(WkY+r9OJmx)pt^k`qViIUd>u&+IqkMuSf z+I;NIzWadsP#>hnin;Y$%c-{>ZCN8JJGUK1hhCC9ua~MN`J<(f{4bA#>9zRxJB^~c zyXm&+xfu3od0-`?-FJu5ZQQ&w)7yI@!=3daCt|coxtc%Oe_bEg{^w7j_)(uOFA`dS zZD1)9Wobc^(m6GzvNZyYPV4c;cdkjcf8d`^R37}`GFXS9flFs@Wx)NK_7jNp+xKH+ z?X%^xTf5zelcfutkFHkEo?a19$Yt33ssyKhPj4x9uNx%+A6WPLcnxyO@@}` zP&{9LD*h2~+a}=zS8jitGc`0+-zE`W9{J0J3y+1 znJMVXX>}p_+xc=^s^)IKb;1f0VEnY)hg0A|_ zU*))wYki)FJK6v(Im8+Pn`>~5`RKF>vEIM;+jM75gvjp52;l^h8Tmx@)-kNs_A}*&gi33nRgFlvY*dgY3=Kmd`uzIvo)?3ATroL);swH zmaoF8qu(?)YF3K+8h;nVNZWt&&STi~o)PF1W#cC(`ShBO=0`j&)UQI@vu?=1pu?;= zHuqOCY+&$|8_>;~BkO#{&v{>my`3pr_i0+fHk3YZ$b#J2SZ)Ak&yV_&grv)Bx+Wq^E^f5z4C;8k$0f1#CE2{=Zu7I$_ZZn zlUGF*R)lx<>4@``fc6r9(rf=vN992wxwcM_Q~NW~C82fiIZ0Z!bh7Ih`s^$J&{Z`0 z%v+vgC%k|MPOPYAY2#+|tkdp2AGuw6vLr)V@DfEC+SQ9a122>6rq|bvK=Q6NWMtp6 z+xZ8D+~s(3yyH7a8tL_CBQ<6scYJq#5smnE{!NDD57(V!e=Z75zdczmUf}-i;#gbf zk@otXgn--~u`}^oMg_OFZ>1aA^I6xrZ~UuhZ*-g_l$y`k`+P=MT0{IMN~k_7WB+7x zW!D%nKcdm0NnBDp+IRT&4zrbKlxoKY4cAsPq{#yFdQQ>T@$0V?GK_`;HS%v?w{t}F z{-LvL&epkIFk9+X0HNmH8XP~JKbmP&T9zoF1!?}iHzZlfWA1ywh^!JbzP<(x&}eO! zy(-ep))sfU%a=y`Ca)p%jWk>6KF=_jHBRt}$rfTkv+Uj05YycK;6HH|OK>ck-Qo5} zL9F127+S|W?Q621;UW~S!)%YY>*HN40uUS*O2ouKJ*dve-cFx65>?#OAh0OK-c_&K zCnHw|OtdrfU)D>HY_`|C#%Ns4m5^iMJL@G!l$gPGkEIqd#K9J&(qK8i0)hIVygS_m zOU>2uW5)TB^%Tl5*%}u?VN7;MTrr4^>3Am&c2_{yIVmk+)B0-ke`P#b2tMsFtExk3 zUvh@=)>^`T-%<^P?oknGg4f^?(uPx9CuQl&-4-fq=eS^wCZ@=>@0R=98#a!2fWKp4H}Ez!+o2r>(LJL zCMLA-ETKxB*4CRAqP^K5JcJ&rhP7EGZ(nVNus6)}Z*#|Po}CzQIutWy3>&Ho57JbQ z(<~PTo1fnCR?tCdS>T$&v&FT*7$o-X*Q@cK&l#|D8>Y7>nb#r!6<8$;Y?a`0MT*Oz zG_IPY?V4)UtiaqC?j}uJGEfLV*4!okZ@;mM)V=9r%AaznH3}r3KQSJX>b=zIXzNnd zINf1+ZQS&CpDKSJe5>*LGMQ6D+X!AZf=IWq(_Ztg~e6y7n z!?nMNdg4zocfS^eat}c=n`~Jw|5Ja0l49S5Bb&-@n9R3T`&k24B?({;_uOe>^sp}W zQl7{kl1bIre6pf8z${1np$F{@NoVk}F5Sn3td{sd!xZ z6`F!T4`Y(YO?jYHWFde->s%IVOH?U!LZf zYL_e0(I5HA>SIO>)Q+kf4B;^~tMT>giifr3{t_-QQjv^G>* zJtF)WG$4JY$WcGh)69mI=KpDD4Yh}Y2R-w=?5;Z;_HW9EmYS5b157s%&XZ}n@?uA%pU`iGG*}|oPbHx>3>s3dvtx~-_WY}&A%01Pz6q^f$CM) zVqKUQWic=`J;xMl>&wcZ3IeZ0m<9a{Y)%r~Xh4lxL~Iq64yOy5PEIQ&ck5`+i1PK} z#CSn#t4q2Sy}JFnTRj|%-!wOpkHOBncE7}DC6Qo0AG&j0EZj<;6Mc^=RzHhu#qfy< zEVlrd5IPft8-46ppqd$&UKQ`^$E=~F?l-LCoIDP=t4ARGNtJ!kwmwatKvio;d?|M| z8Ij@H(mzdzN4$gypQL{hVCAe{%-wXF`esyoX~lG&HmW9}LXP^5^9k%ce}i6&Hs%^(H(j~>v>eUHecD>CA6&Kgji5O+B*55A2CQ8asQt+(TNo$MXz zjSyN|MIy3I!LNWFm|gC)@s?tE*v4ef=?h+W4f2tuBvq=fE)f(nP`##7d{nLhjBI$F z0s5m7^ix0RjO4C^%{szPP{*>D=wpKeb31n!e-P&-infE-Tq)}%i5%=p|A ztQ=VE7Ws5+QkjK0?{26XT`Re9<{uQaNEZy0CXX9*1RP8qoPS1q5PC3Abo&p z(En%N(+yVk|L;UUWFOM`PUu0D#Z#h6x;cxLEgy96V4hBG_0Oq+z&QUfHhCC=iZ6+f zrs=CB`Ktosh;9kPWUQEZ8a(^}N1^gD=jg`Og7Xb(@57mCRDivwoa7IA$RXaCYL20@{;dmrrroh9^dKqv|HhYoV?vc0oLjNFP6wq0kEW1|KD1c1x|{6D zSB_rvR-jQTL!S7&=Z`TUjtmBfMx4Xl$*rdJnQ#%?H~|d?E<35VSv2%M ze3@p9@@`v(WFQ@S$BR(NL*M>25WCo_J;p?`!9aftJMJI z3=QW&X1CD>c_A7j!IjKV-bmJc2@SGOs+sPwD+z*8S*3K?3dw|cv4g-HEwuJ)JGIXw z4sK1KR6j5uYXehxfS+=kwd9g}(SE4Y^>WC`&$Ebheng-nwr4k~C7|*L{g~ z%Rxzwi4kI+DaVHV-sIfqxyovXH!}D`jnw5qA~tQk?6I zKO>D0a;o-LHJ-tWYWNE%Qsy1E_;3{<8)rv+Caw10O@tK!kf z53MoXB{Y7CRqd+4^l&CBN%$Vw5O6riYzdxlh%kZ-#jy({k2#*al8x39PV21c2AN~3 z`IsC@pD#E^@a5#G@yyIK&^t6fGh7V~*JP0&((QqmL{E)C3$H~x#+3*ieznYin6Y9Q zL77M#4Prx}7;{Yz&ry~V&fK6Q2i4HR_Kwri#{2{u)Y);lcOjgDQ+h)dMlg03 z=s{}&*}Uv8u_xm{q%#(I+EmL z&m%Z+Dk2i5NjG{Kw2wFSsswz|Y%wC3jk#vFxk~HfpjK2Rjgi)!(Q_|v&F!=2-SwTf z>r9QleV8d7KjJzwk-7}>nl)UDjL#rG9J^Yd(Pzbhh)xO>mmxg!cZs*0rNbEsu;WmD zrw}_6o6E9b%hNLzF_f){(lQC18C`m~DERO!AHOA%{!9cysm#sfO`Klo9bsO>Nf`PI z@=Ru5^P1+)VN;0BJkw<-zT`A%EGKp-je9JA^<;+~>s%nlql1ZrGg}J02SGMXU-|Cy zPrdyvvv}hRTP@G~bh(mX?BS+~SqU&6pZOy~mI;p^5xH)|DenWy=Ie5F&4>&|mDYy1 zpbN`Ze#Kdi00}y5J{w3Ft9pQ6b!dO+R*cBg|6(?Oxoy(l`i{mU+=8sXpB*8H9-+qj@|DEbc1D@n5X4B3|q~o40 z8~+sz)hVx@Ek)}~f<_tz4Cx7XoUH=mq!%8Rk%{(Yn*DMQ9jj&O-Hmp9*1kPOtDa@H zx|*y-yt?K`*yKUoL>j5pqLA6$wbc&l@~OE~xXk2xXy+OXzGm(361nnyBCEU_=p`-@ z<9)9WbublmaQRsYZ8Tcb7RNCgGPO{{+nBMVN-s*frtD)7b#Y%j#Wng19;NRrUhb2b z#0Y(6Fi+o|x;s`-B{Wa1P7dtsABfM9 zpPHusrx`XuNDc`$C&p7-8)(r>a>#BA1>d@n?#p>P`}3N41~5S!pqNnZI?12?eMbwq z{A{;mf4R`;<7Vss>g`&`gEd5eWybl|3f0U9!pp%qMC+J30AP!duincyOP9S9ni0*M zp%!ovIW6G<^?W8jC2}fFiz25E+!jw-p)N5@yroaaY-j`@_ zjez&J+N8ONrSr&;rQc=36?kz)ZGp9&0$ zP@l;QZUg3dxK#YQtdGIOvVQ~8$TYm24%W_%&nrQJ|0x|fZu0v6gt%NzdmCy zt$T7DC>lDHD*v<@&#V``6=#hTr?(uH{Qf5y8XT#+5PANN8~a1-f$rNEc3je3ndZI} z_Tao$lf8Iaw5IMpWqf9Jbuy>JIqkRBcpEN{dU5rn1n8op|GjOTTH1DNERXdfARV2M zT5;F_ksVn*ICdK@3A(V;B=z+agioT+@`0|knlymYQ$%cLO{Wo1!cz_cz&ofF@DI{B zy+{=M9AUFv_7M|0s^mVPrEomGin}H|jmKs;{CS)k&kMfc*!(vc!$2XF2XU((S_C71 z$q>5mwpY_z8SKHJZapbj{KnRg$&l9f$|0+Qi3x&aR5u)(x0&EBM~Xb1nd)dld_acQ zt~z(t^qL|)y>qC+a=g1Ue4t>F8w^MWs|l3o+VMSscz z0x_NR8e)6iH^E$E<% z*z7a;~H{ z(*d*?qOuvzj%Ed44=t(1A?Miq{B>a4T%5hE#^rvDJe(PAMko&BtI>0cPNLuZp;KNs z{{Aav>1Si8QQ&^GtYp>{n%ji&Y+PKvMNr)#h#PaF!Yd80pVaA?V#9W?^`k!QXn5Y+}bIy$dBn5aSyL|Nqlv! zM^ZU0zEkLd8~?vq$*;9!(TYzqxT}IE@3nmklz^ZH@)=wXeuYWGZi+?4FJKBFm!ecXlLvg8y1tZoUE06}O!|-cmk~FBHJi_lY*xdq@+3y5u zO7)2Klf!PxF|6`*^20%W{cU|eAFsz`X|z}NZz;E8Tw=}ak!Z1-8urk!?q7Q^?NnI5 z6SAELEp3`%vFEu3qd)NPIV?X*p#JTjfl_4Nnznc=<`Y&Yq3(|2wC&swu1bSLy7Sq( zEcR7DW*?!Z`X0jPgS7haX@*NW&l>i8t++TyRDk`B*jKH^(dfAC7S<=p zRJ;GuHVz-GB}RiGoeS}k`T&RKlbH_6Oms4htNARJHQM*7Wb&2sFhJ-qA|3UW1k9h!d2e5T2)!o!HG-m-uAKHGtSJ@B4Ki3k%z9QiQ1jD9upeY{7uNeC(L_DAcf&Q^|A(fpk7s)Q|F7f3 z=_t-gA~AKG(jg>PjhUoS4k~8Fa6*aYc4Wh-R3f)WntK%*V_QP*Ho9YxZ5i82ayQ$s zvTW9vyWhLd`TqX%!1mbt+I91~p0DRk7Rv4cY*Z%$j?V5`z*Q7fa`v55&uDXZ5ibor z38;>9<0kmyLXqm^II8MUKqV>HJDk9QvTgh|izqJPMK`)r zJ<~@I#b?e#@QVj7PtvQZ9|y#ToXWa0TaF@ zRclKZfNljOgmavr%{ea%HqZ06;U)f!TiQ3pW7fieB76w@SDHD>v>j`bwg zJQ_jK4<5z6pi8wEY*U&GQUspO)92JP30W;0-Vglw*TQ7q6>~`}x_^LSc|=j%z8Cw! zscubwPT++`;=RO=ZX#(%Ny(yYT(}4y-#;pFNM_ecS~U;M$28C|r{xgmD)PT(xlRPEx(qrs(f)%B< zVeeDIP9`iCvt5HIwbliM#>1MB9LKq7#|^wQX4kfMa1D>NmAB3Nki)zDR`dD(5_0LB z966>?w65lq@G&btww4gqrz4!`saQizN+g}f9~~2S1jMxSI!x)ba=w2+3@&BGy=C2J ztxggt@<>Y9blrG!M%yA=cYkM=F~)8+FL_tMhbI90`Y2iXKd$&;)lXb2Z!rMGxiC)7@k>yHSBQivD&v?!u2KHD@;rviK$)xD_KU9=Yvjxc3FFu(97H{&Plw6PpiGb zWBRe?oW{_vAhZdv?&s?_alF0SOuR|qz3sPp!aOB!J+FYil|qr~o#t7$Cm|^b$9kyV z5MGT$EKMSt)=p-?%Rw^l)*Uu9iYZ{l{o^SpX+#*f*!UE!haHj?c$J+obTbf^BaSK0 zD?dMbQX8!)f7wi)Kg^%J^Yi@$E`M`$cEbgL?3mJLJoN6MH?c(@T+r}Dk@i{ z30^i?iKRxkS47Xe#N84(;FfCK+=MT|a%iDrgtNip#W8&#T|F22Q@NG{8vSF0#~pUF=ySCmeUcaqhVuqW`YS2SwH zmGVDDTD1zQc+fMh9N)vAF&@I_9IZ|%yw$SRy_g8!0xh?cB$`&8a`GRKE7u{vqxMv` zo*8Yv0ML|DXHOuEw;N)s_xTET({tsoa3=_xa%!FAqc^3!!wKEM9rRJ18ZUjwRP}-; znK5!MsXScxZSlGMsW(6}eHm0_Kd1cvWy|6?J?Bf}mP799@G)zv#pDLPO_0CD9Rg;b8qaGf*h>=ZkIVIsu1SJgAQ3Yi z4OFOwjlHw{aj~)3%3L#)NEPiCpBtR94cGQGJZA*eteu(Vu&Byhy)zon3h+lsZagAo z!E8gs)Jc=K#~+m{bLFU-uC{6IAFi9 z^>Fn1e@|{alf8#C{~F-`$%&hIudjSbF7l`n>k0-xi57G-dx#sm9V}gFHNZfGn0Ymv zDBe4K0#!2$#gF!F7TEYD0C3*j1@uTqW$|FNrl79)tXY*m0M8!Rt9Wf!3Z8ctKm45x zFD*<@eEe%}3|8b);u98O65I%wCyA}*wJQ#=VrI}ULJ2q@yN;8Yr|XAI~Ek+NX~B%-JT??VAUybx7&#? z-u`b_`2OX08~>=%hZM832Yd|zyey^@HMYwvuK=U?8a0DLj}X{X`g)1f!MDb;<7kv; z{VUn<3)IVHa_yP&YgGgLsANZQ8?4(QnipG6-h@r{`If{~nUjEAYZo{xO=y`dd#ZSP zS$Aq;?dn`vkTE|KtcD8*q3^3P%%J8&1O`>?bOt{R$tk_paQK@|_kCl;%rOWnUT;s< zZ1(6+5C75og+=111idXxJT6jmh1w!ZWY=)ISXUJzgVqWbKXzWDBA}ntQj&6iR~~9Q z%o&|AFjAS|V@XUa)jZ^l?eFeb`K6+Zs3=60L2`a4YNMOW)`!7W{{5V<|10uZJXTsa zes0*uuMEl*J+xJYqidhnZRD6;NS!RBP)qsmZ;FV+8l0CkPUS`tuOHCLXRogPi z(Wm|N&#jEm&n{*S#7&fF&F-qR{=aE`f!Da-%V3Un}!t7-{Sp*FM~h|A0HN^3}2Jfu6H<;Mrr?VF*r}RJ`CD4{lTG* zDkkb)Ij}uGGRgo~;kv6KQ(a!*;nXnTvyGP>dn)WRp`_w@T_vNGcWD$oyG(_HpmXK^ z>hP`ac~A7@)t>%d(arv%SW61wut@tOp3KgukFHUp@Kzp6e-7ouH<>pd#|>wO)E~!& z;*!G+iV$PIhsPAiE+d+f)7joLUn=qxqizhP27dOj1N`{*ldrXJ9KT~ubP0c4c+G|6 zSf8;x0tdDGIN!c{g=f5VS}hZMP5f;ejlH7U@K{|R&9oR4hw-%{`s#d zA}!v2i<|}5`wAbqKrAotwsemEMxE?)5YpnxfYZc;mWaUSp>#=jZ{^kAQ^rUMh&-4C za=l*xgh>u`zd)T6=@Hl=X8qkJh7EuA=-QNtO~aJ{VWL38#6I#7G43<6zo_o_H!t|L zb=L2fNF;cdEOnvZ(yMu7Q1-gXxO zt>Vt<*jmG-^i0bgaA**KYcu5+)IYr$B5dMa4zJ#*IAe~wNc!{fU;w-8JTs-?6lnz2KUruJyvF5<3O|@wQ`tXR_ zmptyl4s+w1op3i52;Fk zF$Qw4F1rVL^9bO$+kPF<|AST~Pte7l0!{_5wo*r&bDW>Q*V?J-nOP#%&sT8Ki?D+T zZQXIm;{N|#Wyhv0RoeMZJtw%fMBo}Fm;j?hHG#~Up5>;48Hr`nQg|0Y270%=Q$>Mx zD@X%eSFy+7c-&b5Z|Gh%SPxM=v~TL7mu49c`J)q2L!t7AO)N(0g3{BZ1=mi2?n;PX zrS8>n?Md1SfYUQviP&)6_}@1DQt}G9-Y;?1S^nu@OV{V53>GP*M4rvH?t96GR$V4v z+l;CAE8zh=FBU`?)&YLGUk$w!e&LxgoY(Yc%E71*#eFSOi3;!`W218phf&^OVfI_W%^SoVo9bw6@rlvX#j0y_cFx~}`Uc)Tra zIwc}4mWBvva)>8zTfEg5;^v0vdS~MVG_QUOg2`#Oi4_gxQ3b%oFbUw;R_f^rLeaEw zT&@#_mWvSaSAPX2$I&)JzprfU-7F~J(?Y-ae>aU4-8{NpTA^rl@n3o|**};zxKso5 z0)k-*PZH%X)SG{k6qwAgZIoX5&B+W>QDer-;Uwl?!oY%@L5_$&-ku51antq$>em|X zvcCjeS?GAcuB=|M)DH71zo0o=XMoM9zd^L`L%A8*utp5!T9n`66^HFO3HGw%xX|$$ z|B8*{4$T?q)=|WfZ8*ZEdhb>)I>WI#t*v!sL4kBKGE7^m zKx4baC7`)4z1q@}ojM6pnS3*3q6(+wC+K$X#$79G97IG1F7Pl_owDnFA?cm64V-qh znteg+n=xhHvC%G?F0>wJ;2TB$9kA>6A^6`oI{FWKLC(rfQ;ADmsknJ_=%MmfwW>7w zpfMdL+BRiDqjVo3WNftL5Ii31>g^#tU-(C*8(z1=CR{uI&|Cucm(bg>kEOpsC{b>= zr5vAU-VKn?SImftrR_Y`qIhfaQY}{pHvRo3XnDF2B6e!#tXlG;z6mnAit$jzseg}_-ooTj{w-|<%c*nrj)_I`Z(i8&rrE^ z=Y}wjT8>KhP8DV6W;rJ;Cg8;JOe!FYi82gL^0eFk1csqOj|~si-9Ebo$`Yb(kTsfi zbT>-&6IzAulgcU94_jNV&P_x=N|?Yl!_q`2g^dy~%k$gfStEou&7(vL_?5cYK*zl$v@YbLm;>VefYRitua24lVV^$Jmxe_D|@G%HkIbOQ{!k zk6E!sO0i?h5p#)aOC`>BS=s^5AS{ttOXCrpxyT(~+CUG3PJoPWDgFHS_ec~-TD}iw z&}1K#lH&UCC`s9O3a(!n)aJVj{I8hrD#~51f*@ulmjcrnPS_HFD z6?vti4ML4b-X-#Ki4FfwLhQwf1OHT9G)HNINDTf#_Zq@yLz+dlQ4rC-oY zToFDBdDCvTDy;3kMD6J_V7f3sIkq(-OZUoe$V~ zU)54!<-|NaAyQ`KMQoSp6ETxCS*H)IlQ&BmaKTvjh4x zm-2; zfAbZ?b;@awMr8l=D{9-ugN(Qq#^_L&Wk=L;)~DH(AG{`)DCL4~jS2xr?NLjhKiB0>KWsh1U67B2F$qU-a%C$tnr z@|4Z}4BnCn3^BIn>(-g4a9~32yItBJ_Yv<+0)T8fA7(*9*-0SXS}cUwVuGFdp`JoF zC0S#;!u!)mLNmP8-D`L#E^)DX%1F zuy90qW&nfJ7HC`Bb`3&p?VM&as`36!*cTk$XbD=9B6aG9>qLO2bk>2n*0wm3zsk5& zB4a@%-_E6In2&p`?V{dq19f3n_=fG+X^7}5vvn5Wyc)x)e~dr=YyG(#+QS7-DETG> zooCv9<%gSdEqf~YIg_IR*MrtFi9p^{*^Du_zEDp_)p3g={l~D-no8sm+t}N^`!pkO7i?zHjW@}%y zMv@)e_iN(piR_cgT5TY0DL5s9mQAOTAIsoS-Y;ZX>zU6(ptZDFlct{veHKSGx3j*} zkAQF-fXn?Wl-1ah12-=GI5HO7ZK_F0E3K=Whh_o-9Pqf!03b4&JAxl;6zS>v>sR1} zO9*>Zr_tK%M%aEyaf>GT15|L)}CT37L+;-0~8I$6@FujouwUZ zi{tYpXmWcndbDWmK<8xJSlYa)CZ7Oxlu$P4LQ^G_hq_eUKAwrud}nR2d($5Pzmpk_Tze4e(S7}?tIs- zZwya1f701f%ASCiv3KY}7nUOg8 zPce5EQ}JTrmYOK+i_L`6Bqdkg;I=$2J~~pUxcjzj#3^T>+>WRH+452>awd#=J5S@; zox?Ktfsgy1By0P=9)Z4SEhc0@I)>g~cGFgo+}qm_24&X-beEpp`gOlB)@K4c(Cy@f z&4DL>>H!`lCMw>m3nm4u^`StcemTZvtzz_s3<>#3TT(0*}wT_G8gMcR-fW~f#*uVnRc2x z(H4)AxIZ<7tr2^ciSr+RiM^0d;%<1eJuQzruQvg1Q+0`aNP)Ds=`Ro!5cZ(&H@&>2 z(v&G99QQ6!wMtR=wy@{3e&Q%|!gGF=vtFV#xXeSlnq)nnP+RniUgEG?1Fo$J`=zLL z^N*z=70yu~FX1DFu(|-`s`nkO68cDr7HdV;w~kR=FQrG4p#rdyYA~)^(uhbxt`9O3 zb8*a<6I4wZ%lT*!+CIhO)v38_qSeOrL~_71P?7(dy$6+J+Lvg6TNvK1)t5+8W+eXo z)-@OeeX?W+40t|FR9h1^qSbCm61uoCzk>fj-Qwng;Ri&&_u0OAk8<70H&G>fxRGDV zE>r>(zxeI=6mlD}q^|ZGbr!nMo^{EsXE*&v|Ar(?BlqwMs?;!9%NTL;o9${6+c~uY zcmElScD*w|tnUPvotUL0myG^&Fz)aDhel@}JbRvuU*ZmV4~t{wsxjd_9keXCQ(AdD z&*RV$O5+JJYI*@B)Zb&M@I55jMr%Cb`N+oSJiz*nEqg!X&Z8!dj`nKKi2Wx)?cIhy zoqx^SIxJuPD{|-c{;sbo>+Txvd&YhO7P@Qf%aq9xM$p{%Ta2YtY^f{Lb~%b!srE`( z3Zz!e2-Xyzkl4|p!Qu`Gxqa#tW0P}0S`=5frkQw!%K3*?E><-#T{(ImXW*JGZaudY zE7RwdqQ4ws{VVsLCzEAS5BfbrA7E_RgRibI^Hd-7+lls!)XlOOU_517IC8sM{JEfS zy;U^Q%|dl_7M6s}*f_}!%uk0!ym+_qmxH_apZl`kINw^0(;7+8W(`t67K;-LGo<6pL!YS0TI!nAn6KxaxQ&oWY-i`Fb zQ*w92xHkuy`#WeH>iV<1_-q#HP*;d1GOia}V&y?&N0@(!r*4emz)M`o3m!kU2Fhxd zXK4!K!y;JEs3@h|^RU8BPQ;<-jiinnm?NcDes=V&*XbkS=(XPA7Qedz*w}eyqQs)? zf^4AW=Ta$XZEwZK7ioqOhY_GTeo;s{_R!(+Oe^;U$w&0(M?tBE&h0@NHQB~~Sf&1k7On~RioX{?Kd3NGvo)`FG zD{EpkV<(zOTI#_MYU$}5OAw44E z+Y(Z3r^1J#1+O=1)JCU&k4*82Qj>aux}qt|d|=odNMpw(%=>VVKG6x##Fcd zt|V$8jkec?9qK$WXvs$MwKsI^uE-mEjy9`xRH+1GsO;c+S+o#(F+Hcz+k#6za=|LH z`t!BV$K~{9r;t-+D4SImPfje1868?04#hJEW}uynm19>~<(}gomz>MMw4Bw@wFB!9 z?n`di3$!-?i?G~wrSJuo*}g8kn1-0)VKyC8fUl>~lAd%WZh8S8>#|?pxk1N1uo2rg zu)K^iPkE)~PM*nKHQn$XNw2qi@S@cGf6<*^L)Ek;En{77LrHL zgTxl@MaI%Pu~fg5eL9aZ{8Z-CD?l<15k6ewQG}+ zlYHuh=oC=wSSVcDM@k8eB>Uey)+0LkceOq>io7t~azz#W-AYUFchwhvNho6lld3Ov zq8mJUtxDAmW3f@sY@=J$u9_#Td>YM;>cwi>EVO?DkDdPg$gx@0?;jdP!>K{3*=n5V z;|*jB8%^CMmH7oVo~f!)#fi?^v(S(GG|-*ds3Aj+K>x9HW*T~H)(?-PeC^q(L*JR! z&**;C_ZL?VwCROmPHUNEVdW4?U!z_KvOdePz(^JC|1qtvZjf;8%{Ch4^oA+P@? z0`tuNgiw2`ojTd}eh5{MY<{1Y7L$=^z9(%oZWgs=p&FesFvE#IN8m0Oy9UY2PD?E5 z=vSiOAgUCSG#&LU`+4HZT~V^FA9RnTB+v*D=6IIm99e8lxSDTbp_y`^O1uy@5Mrnc z6xLa@A*2@ne9}MlX7bs4{ih`Jc8TQPne}7sb>!BSV9D@{u4|HK4A%^vC~{ppDNRSB z#8{#e;3|7dYMGWxh>qb?yI$Mt5&#KRv4Y_m(|Lm3xZ?`axjIT z@W|%Td=1>t`a2caLHt?iNKYZ|@2=sNKXF5>qyC^ud9$}mSFpjja%gddeO(MFkaHX? z4=VFOHnK{4nrv&R_^yMP7iWCGMZY zp0RTg>0#fhJp)_-C|eH&G{bR!WC6YXLDY$`ksvP#Y6j>6EZ{VNzBu&^66XxMN=A=R z*ugX@+0(zqBC?r?7)4F(F>B@W4@#pRU;svi=454@i%NkSU@Fv^G@_0y$sK%Ri3t~W zH17wbSmk4l1W_i#(SoK_d>#7Q$M`FtfaUtZ^|QnL7UgBM!1c?eP4OMF(5{JbnP2iI z{3IeGX)}FuMdFK~c;;&mT5hUhZkvMMcVwdmTBrPLq~Xy9Z2#-;7OP|E&#$}SkAgA` zTcOtLDeHB$1PiiU;v=lx;a2M_04l}%G@E8pCnv!iwo#ycPTsw_gon)B+U>EdJZ zT*x%^uB%uNi>dE(1xQ!Rs$m8>ZQinAH}H2|Tv+oZjj6A(?F%(7249hGClkCL-f$OT z!yjTM_43en0k4voN?dR8-XMmB=A%w)vepHanMVxq?l|`_g62lAGl50IeO2$Mv+YUe z7?p+6+~U31!!^S9Pm-!P0)pdM>Gl2&r`7&Ce_vts4R?NnS~_|S@YO5A-|@D|!3MOF2QlUViT`lSuxkC?hq2m zge}jecqV-v!{YUyFu!T;hTbaKkOoO{?M|m7n^L}~u;f3jt|{klG0<1t3-CS7MT*jz zn2!>vPaP^r2Hj7FWkOE~CiJ9XR%(5T?$~DHSD_SgOLU`DTJGteX${N`wu8|093M1` zD3P8KAoH=|%>5EnAG8hNtEvKwy4{)rw5PkT5DsjAxzGDL%w^?TMZA&sq*OO-jr8i% zHjGC9F*4;raAot`ZmVGjtxH@J9g^PPx6+4 zRP~L#3O>vg8e{OVbJiKu*QWZu+T&leH%MbC^Tuovtfq+r%@)-qd{Zt+!8HL(u^{qZ zGQ+_!(;I+h6;Y9t{0hLap!0a!!u3Ampocbss=<9jioz&OB@8iJy-8wAqzH!_MLv8Y zA-p`PPkn>?nD(~|A%ZmZ@{YE3$bpGoM9PLSVMIx_>-eSB5D<Vd7j6+PE2s51h9AM&>##`MuYs1o`P`<_@_;jViog+_`03O1NrHodWz2-q|Tgz zaC_baeMD^c=32>>fH3^>u&n=wlu?19Q zN!ewYamysLvq`!XfP*}_tD%npuGd8noC6W|vpSo%*H(g=+q17hqwUVa0q65)$-G~S>RXVG+1@_Cg ziy{8cAd)YQM~)nob(Y8onm-+A{j#}4CP@@d1fjnRsp=LDnwv)&MeVm!DCuhk>T)X$ z$c_T$k@2zI9D|%o_VPK$v9lvby7SG2fJT%6*pFbGh0nNW`xT#>{Y;VS(%OX|&j<)+ zabLV3-B1yZ9@i&29}N5*4fEb2jgC22H^0pcb6{DUje((@#G5!Fo%i4eNFGG`sCejR z(<^jt^GsPRFe38YHqXvYyLG6lVI8MFx3CWs#RK)?bWRcwG9Acld0g_YHVi*R>b5IF zTT9qDzh}(SmZ1Bo;V4m(b8It8(NQ^=Dg1mXpoQeeFIo2Dv|sM!H-)gG(VW{k?e6v) zB>&2oFoA5t;;*m3u17_WlGy9rC1{WAiFzy6htlYU)5+#5OZwNBBg&()6r1$tB;7g{ z%87I>e0X`(8t#Z@dsK@0KP)*wfbTP>9}4MhIHi|lOQV~*k$b^t@#kv+@$#?Vo9ptE zr#=C+d}|G*pQ4!`yX3u?Y%xy)8OQjS6z}as$I6&zIRLW!Nl=7}2*BC7f(U!X6?LDk z(NJwbpZ^K=$c3Jc+rJNH4=Buf&x61FDBRl5!)*zhvOap5A_?@DLAed50U2GJ(%gHG z8Cn@M@%0yu%>_CpwBI*?Rmuf7C2X;qt53f)5(FQujX}%d2MmMqY|dmJPI;nT6!fL} zJqIyQUG1I(ctfFjC_**a!K?!>_6uQOK3f|eH**p&6ZucMFX1oR=k8yJhOg4TcO zvI8n{VgOGu8KB(Y18NpI-bn~8H!c_WnVa4 zy}q_DP7a5n$!AA{{@@p=B6$Y*8_{xIS22Xb^2R`MezpjEwf44QrfYLKVvIj}EhjbK zGOKR*bX_6JNhajmrt#{yt3S7y%*kKT(W`B`Q|G5TAEQa!()l;wt7}KExI%?C0r`P} z3%bYWG%@C@5AUTDQ&L+x&d2Ue?;y4=FxkZe`suvbDjw2}khWLW3J@Q{ zw!-`Kx|B?|o)RrP3dkt@Q7GgXDbz~^ZlITgDg_*rkR|AvCu~3{k29t{+b4g|x!YE} zS9t>L+LSm7Y74W%<$tzB-zneMHTy3E8v+YMa|_aR-q4d7?|5HkzHT-?ob#8kb@pG` z;gC^<^pG0$^!Qn0d*OP7X6qH%BI>RNFGYox^{_m(B5Iw+Wg+?9%u!-9x z>Y%tap;Qgowtnn|9S?$q-e?QT1xPpNDA58VsAzQ5gQ#bWLTY{*`h{~1((TtWgbH<= zy;!1GIOxc=ApQP>+;KXfAvilT(%13oRExDn5jv$NY#VTm@#vvNkS~`&ti8VuLw2Kx zkkU5DEgpm8@~&07?Sj?k4QGDORF11Yt(rT!>?+O071n)KRzh9)UZ8`ssbV`-csN`Q zuy`4h6xjD+1fS_t}9)e0a08hFS{u>AveOSB<`bR_MfcII(UiY z`QbF;4kG4zhi>NVkQ(OzCpC-+6faawVt`M_pPH4hU?zX|o_PiCA1DFOt+fUL96Tl2 zF!T`-uKsD^M)Y^*glQ?E(&BC?wP|iz^?L59=P2}J_Fa8PB}TnAEpH#L^z7B4<6MX8 z-UQ=gIR zq?vEay%_n#MfrdF3yu%RYlX=^qF3q0ccD>&jyGTQ%op5Sz2PA*@GJ39g8vl|fxU5l;q2I_(+EHlbF?5wNd~&G z?+X9>KScU)lCctnt`hJg?42|%pzmE!w#dr(E<&Dh zW7f`lqL|zx`mOfjmy&$c(0Ln5ZyVBetl6FGieT(DG)x52mh#$ zhL^Fv%1_}vp}3)Vq;XY z{(yEl+0vhP5>Q*UQNqtVmaeU#xCce>h9OyN^cWxcIy#J3KLBwb3vWW(oG1EC!W()N zM|n@bQVBs@{TR<>OhD9GX6x&QvY9R)l<&vfhN>PgM zSLEkt^2JYBUj0Q4tl2!$MpE2tK41b939i~oirXR2{T#cCv1Qert}FO3yOj1OG;&ub zy1pnrOQOdGUK7g0TpO`a7u`KwdA=Y&1tCI_q9jA!<>|Z}>YJJK zl2U?a=nD~vJ1)CcKX7c8h!hBxOHc-!y|phgMI@$?Mv) z>m@>M_EC1cSxrw6`Q7TanLMAU3ds9dz*eQexB=;yhU&nYnvfD5n(y@4(w=>NOYMP4 z-o93pBv+H5T9kZz4fJ-Cky{#XAR#4ts0uN;oG&(D;L8E#V}+4JCAL}&_45q%lb{pE zZQ)@;3 z$LCLrEhA4Bq`4cND}g-nk>3s@4gz?4|f+Ga9m_F0d07e{tm20Zg}fAAqEfy;4rRecCjsRIXiMj4{K&g2<%U@g*Y2 zBrBJD%5VZSn&95*3^#_(RjESv9cqb%(p@Ct=@px;(LHE!QAvuIXzgLNHf7p+ZXz77 z0@yBz&)8L|dBI@U$_AJAp=Edb>m+h_t_?tUz3TyJ`KJH)b{?-b2~XaPnzi}5O*2&3 zga($$yFIGt=BG|2{Uny`vyC(MM~nkP6R;Y*Mhf@|eT><7c@7ee5Abw0d@!AZ>KxjZ zItZa}^EyJT80=@z_63BdZ=4So71!BDw66lLPGxBEUd>8~5b#ji_FN7q@ygx-D7Aks zz`{iTU=oOP(-PxwmUxeY&1Eb;N} zD|(tAu7Lm{?-i4;&zDZCqo5~5%@6W&D3ACquT3{RVeYsmO@G$)#sln*Kw!zFH1JYs zqfe?8V12+GAbI>I5xSIpJDSNwFf43R2t?M>#U@n;gZ6rs&x{S#KY7lUc)QfFy?DSU z#y}fg9LCsL$34^i;MtSsKKHDo(c#U>4R2n9-w@?qFh4usI~2R{W$A6h!H68-+tmzp zhD-|sh`ptBV$vU3LYa^5QclgRww6&vL~>LG7^^@&+hGl-)r2{f&LspylKl?&rN+|p z3`v5c{BnXOnG$GFnP4fZlzWkCpzYLIj+(;nctWJF=>zVo;)GBuNi>PZz9tVe*POFw z!@a<+NlETetNZb>^4`)k>CBOqJ8etp1fT^}RZA6pYb*1!dzReP)4#d!;O? z?B>lS{fy1!h$QoUChO*^Z}3B{K%t@u@;&Dn`ZL7EF18`B;=HYKup2?EAbARc*8yIg zDsqw+fNa(?BHU}B?!3}7*e}F_2mmC12$Xi!;+Usz)TRXep^cZPHkJYLY1_a?awMW|>FA z!MUcVe~yOkp@EsLHIsf@9=z#j`)A6N<27%tTBdfO_Cn>RNmTO%E4HJE?`3%gDl@XH z^7fiv*oj3%zb);7>$3@LR%kwx|AR){v`SA|p$p?EiJygrKpM%DhE{1Gkj3%C*FG{? zR+1xx`d#sBI?_In_2g?g;N>l(%9tgAefPow>Q+k~mz#UW&e~zfQaDZsolB?*d>{If zKex3nbV~v7=oth`E*ItG^Y$o)Rwy4Z-SEPgP;tlPCtgNrRZu#`#q0pd5LnGu-T|FRPV(yazwc!(8>WAY$N}wVd<8NxjH3-Raft824sC5=6Dh z*()zFtWQU|16SyT?nlyZg}~zx6V4!m8tysIKI~g6eX|qM{2m*!vc9~&);06zokg=q z?7Nwtf0`;o1AePM(}53LQA4c5y{+PtaAUT;*tt1-_SWp93|99)+bagcwzwvldek&M zee;?Q*Dx9DGm`5$3N`{&o;%mES`p3BnX?y}9eM!j`?1v&9L9CKbPVAeeDZ?M*af>+ z1qe({)=g9koR#r%xLL4WET0*Yet3R(Z)afb^9)nKX~i?NLph*FEc|eJYi@K!MW^`` z#C+{Xo{M!dkjg>B3QPkaSs(qCY<$GpH_i2^_HQZOrv42}C0$D;r{Z7l8jX@^NWN)! zesY*A8=WaT{KK!m4XcPxQPi?56_mAE$`k&#lF@}Hp%IIQ>--dbQo7u-r7{Q%vHlSz zb7Xx@vfkO&>lX10%S4wqw!Jo(J1DSC8at`2HFc=mlJmMW@(2&GC2anK){$_AX;)S) zM^|~Ys4Dy5%4$FxoO4p!UZ8sH=J}H!f9*N`;|R;pH?E{oapZ+NM1RQcfY6Q)SGIui z)x6>&F|T(W_Q3XeKC!*C;+Wi}0P@B(e_nqvCh!}*g#O`vqjWASp9#QPI1CfD;h?Jd z2IWD~S&rio)$ZN2p$tH43o%3hk>f-0;gi@sWq~mF944Z*OFXsJbvA#2wBj5z(7g#; zL%pve7^KMJbM}U-VW-3F2(T+#{EbF}!pmWcg|L)>qaPQ4O!*lJvk?ecWXOO?{ewr= z!r-N>@*+o3ZEHhw*#q!(a+HUARGTbn$7FjM`( zP-0icB|}}~G6eTm#Wx=pi@c>1N{Gay;%(h)+1yqLS$7GMyg<7hzG6xt#(mWfj?u8Hol4DNq^n9%@ zr>-LWoM7hlzX=4kS0_+PG0t|E_Q&&?zOiT*J_rcZvh|mE`NK`W0%+?758{iDdnIir zfa1M-7+ODoVFoSK>DQO#Yt8G>rcVwUR=u+T!lj&37Muqe83>9o z9l^d`+UZItrQ5Qqv2p_r9III9oDKu;fR~|5u>toKC$&?X(XW7)xRG7?L`wU@pKD59 zSF#KUiVZ0lTVEZkF#nEKP1X9v{U6w3sy#+FQ?WKv(lH`19~{#ukBf3z1LeE#S1VHJ zV+{HQj|RPD7#ba^J~tCRfpuX##|ETX`+Yr(-nNUA2trx`^19e@|8ej^JRl0iep|Xt zpUx421pn}$txn=RbMzVPHGr#-uNURV6a&3dQ{GH>F(7vU`c#i3OMBx2!$I6D#JJyg z2`)yA^7|8ibX7BH7TkX0LlvVRS-O}~*%Yvgq?Bi)N^Q|EnbC6=>rxAX?k?6-bhKNh zdU#mt2WQr8Yk&RqSceq;t}#q|VV8m?pJV;TAN zEzaSKnQ0hse9uLutW}mPvwGkTp}2aS&rcfyMye$BXpo>lHeUr7FAvpmTX#?_-XBz8O~25@Rh=xrNWsz z8+IAXR~p7OcVdO__YvinM(OTcz@Gf#DUcKDyeHrr4#j*KW?J1jTOQqWQb(tp(&Re3 z(G3BFG6@HR%r!wB&t;h}We26`Y%7n7eAV*q@sGEFSgbC9b5gLh}?Mm<(R30=bRh?GwW4X)*unbH{%au+stpS+0jtvIYxY$FLSw~UpeR{!O{ zZJa4O{75fmoWCIZ5H08^u9h1V8D`DA*6W%&Dji3~tRg|sYkqv< z2ZW8x=rWU^dVDcTiT~hn_K!lZA%SX`X^e>8o2Jk$FhzmlAe zqLb56jCEHklIxhQI+Z$Zl~@TYDxqRVHnt&^5~d`|Wr`@brO0h=xy*e~oYr+q%3*XQ+mJ#XsUsC!vWnMj;mG~q$$F*e-6!kD*s7fTaeh?OSPO!xpm53w;hheVZbDl z>j(2nxVa6ONW^E<~#tz`m>qepsGFU!JGC3o2`z5mXm65fPH zBs@;>4C8aZGe~n>5Oc5NSh?;?-;rbqj34g6E8C@xu;pkZqj<`8L4Zi`&43$>JmX|^#^NB)3TB!nP}sfn<_Yx5EZQkx_u^vR%HlpcY#)qY zlc07dGm1C#Os6;OolP11l2ayov&Aams>w>$HDzvpv*n86BdlXb^C2Cr*{UOZx=RF2 zk2IYr5#{dl*jHrrrRtg=)w=jaw}Pd$%~x`m-rxAIUPhPigv-8?hvnS@dG}1^YRE`b zSvFhrlsbo^Y^`@#uUFn-SbbAcGqPBdMqR9;?guI|#Tk2vE_%z2>@Mh4PK=6M`K!%Ug#8YWL~*5 z3 zMhD6UG;N0d!c1tp0XZ@<hRc6{Rc|ul8M#+S|$$rA}UHOMgL~{Mhd;PaF5j)I7L+5F5#BjG4f$K3U+SW*Ifs z6q#~R{AU(f4%cKSAahba_cmC zBU`Ci3(aVGbC*_x2r!c8>s2#f|K=v=F*uU**f58_gusJwlWHJhDALy;$ zPI|EMvjy6D`IwVHo0(mCue5DwNIP8ZXSzqtNm0TjXsd#EwY}3e%fJ!P2Y>=WQm!U*fR_G1OA4!^J86# zh(d>zFS7`}QzNl{%YWimN3>S%I}(TdXXp_}!yw`do|}lwkw4L=7p$9)2AA9NDdz&@ zG5Obq=;~ZI<%r<#GYErMI;-VR#v<#X7KYQlm0xTb`!{|G6x~%l7_a^LJxdH^pLxQ>`sMfBR8HO0+>; z3%2Of%YxX3O-{f!wG|a?wPoQ5cfsP7hTd!9vV?;4m`8{7x%A#g=wFjBj*k2jB3~RI z*|1`cnE4kOEO|tkf7H9UIUr*3hm-O0Z&AP{$ro`bORY|*W-$VqGFZ)Kr6Aq7<{L|1 zj)LW6a~=?ech;T1)aBA=FwC*-?8A}bT|4_Uqt9ks7)xH*ZI&oXXfJ==6Jl1ZLY?x9 zgfLo&eJEldSJA@e`SjxEDD2ZNPSBI2;x1Wi_s9IH($D_isD$+Hj|FKGP4WH8g=&2I zlk2x_5VjW3z2#SL2WCvt5L4%jXx&pMWDjSYZE)y7d)B%g=9x#vjy+|>jSe*8w;7Y9 zumJXuhDJBlaygJNdMra?Gz?ww6wG?|R&F&Gmo_cDhnqG9d!9r)8SWm8agS(rul0JQ z|Lbtwm`iQJXhp>G0?#QRB?jB#J0p9EIs0#EAV*h?#0|frHDLu&@N?{>1Pb3tlvVK%)_Cjz|AKoX17_} zOZh459^av|?q16BOjin_EyZ4NaqRBq4X03jxodmEe{V7EuE}j7 zznm0=jVqT3Lx{BG7!764?xpehpIoVV8*y}GC>knfb%he>q4q0#S~=dyX4%HXE&L>d zx}3FD_$pZ(s>(6x))+>XSOs$kW5i!60y~#vu=vyC5?<+qrz3*du`~DMTwXSr!Hm3@ zGdwZPo71TCvD8$*AAo?{BoI_YL_K zxCOY*$+DL+JN|uhy1zeB)%STn3e#*wHl*B4VgQ5qzYBuE3Ko%rb`j*HB%Dr1Vj!b? zN<0m_1=_q*GYdZ$T~|%RKF2`lJ2PQx;g+gn?hmof34bZ_*Ye`MyECSP^Z2w!5(5%- zVd;9Ol|21zBU2sr02WW~qY~;RiHJnc?sGsoq#Nx;I3s9;E(`fCpXG2|98AFBbpkJC z@Q0CrT}|qj>yG`dAG$e;RkDQEQ`3I1w{~cMRivpT@A0;40cQ3WDx5ek!hFuF`HOdW zW7${J@cA&--iQHMS=jbxZ8!H}&8l&C%JO=#@fOf&x~>&MEmAYC?B+)((;VwRbR8-# z$-TzTiGRFD{pQWM1@E?~#FVrAH~vGXSfGAcwqcy39v?P0d_6GV*lv;sVc~qumT$l? z&I#51kX^7>y&KlLc@!GgQBzX;^Dle?AX15&?p2#^`Ag@6IZ&b(pdOLmILEo_Ly{f$ z+QMzNO+{g355I+GRzD@li-p$Bf3y@W(=_T_Hg|OW!F=-+Q~RPvWj^fOa?6S<@;a$DFJ1;ksH5R>r*fV;drL zW~6@wf9S5eWteqiA-qUOS$=5`8EG+R*&XOuKVPQ|e-L({*lxx;tL)G;$tdUhwV#6l z6#6A|UCnuqGwJNp-FE3CTip_jtr!~#CslZd!~D1CL8z7|MT<@FFfZi*TE&x2pZdUG z+Y=JJ)#>_Pa&_?{K7B%T;VwXpK)rFSj?bI$`y?9Yg|zKXv8Uf4dTR(RP9j4|*X4#n zESuLfvhlV(sWpbs%6$PAbu*G>YNt8*NBSKd0ATzY1EHP8*mb=zO2yyX{C+9$_p(Io zS9n6L;o4aJo=1-C%-0gf8reHc#YRre3{u{Rq%AyiT6mW9wcxbV6Uh<3dpwtvS-wgJ z;%wI`B#(`evDlS^IX!uf+RM10$nmjE<=nBV?e)+r%fg_q%|C;d=O?+V-NfrK%SRUP zZ`;`TgL!O(xlY?I&kTlJkdMQZZrD%FCh8%KV8E~E%~^MB4mn$Sv#2wKRenBgJnZBR zbxMHmtvBp@>!EWm;*Bjp_#JGQ*$k|Kcgr;FW)26O^$bdOe-1u~*zPg~5a#X;O2Zv; z;)s;kYm&Mn#EwQY$_e?<&7V2bl?*~4_v*uW2m01^u_Ynkt4^SNd}=03k0JH_39UW} z{ET$Z*JebttYJ5Sn3FSjmzUoZZOI%r9ozk)MIJtW{kzlhxRc&en!|azgAI|W6#@NT zvBjHx^00*ltaxIzlg`_sFEYr8erka}(l4c_3y}N@I2Z}uy~DdHbwj-TBPU>&_RKtA z)MX{T^Uyi3EV5;FydiF3Yl(5p3`=qY>y+gLdCOa?VcbQpRl;~=Ny;fBI%3(@$s*>V@ZQu%a9l{8$22xAe~F;!fIwq4bj#E&e?kR!(00 zqJi{bNoHE_t{$stPK9~R(UNZ>>@o+v%;B4?!fkqtbutf1HxgPmFrMnK!=1b9|7S44 zwT&!qB}0B5y6c|OQn~hR&_yF|DM;ja1+Ea~VohuqL%)~-QWV?iuZk}{PCQARAlL{p zwX2=xoHg<$)U9nlRw)G?cu4UI`XC7L+^GxlO^&to>hLi~IDyybBg<$?@DB<>z+}=>)CE8sqar;QCh3x54jL zEm#$&bvy>PwbMx?*aL9kq7a8-eb)moltNm1w=Li?e~X+7(qjS$YVg05k|%3VT5WSI z%wI*t-pb>jiVqLGy8xp|U};QY32Rpsfs{x4xZzA1Ivmb!cTYBaI(fJHX;$+ z^Vzk59{t_;N*`MbEgaDd)$i*011QPz)z2k`Y!?3q-GX<~e&U&bZLtC5M)Q>qM0ewP#Oo zvTILm$SLks5coS)?1Gyn!n@nt%^rA|9TOF=J!u^ON*uEryrzlEJqP!v{j&udJwXQn z!{%h-FYi44EL_K03u48pdI#Ox%Yo~8d$JMKQ4BeJi2Jy9;&JgPwN_YJ&)m*6eGvnr z6c*6{5~%*r1;N6|hGX;1&CWDK79zQSZg32D$P=J_jd1ykGF%pW|}L zcU#D3`pykMhL-KJNw3pSdAOu`pE(ecxJbo)x{KM2%{d*QZ^l0g$L524o#YnDAUCzQ zg4{o0Jp0|WE^#f_bU1(HEay?t&y{aLih7q&wmkEfUQ)}{=7QkQW|a}I!Q|nxK4`tm z`qGtg9>H`D_vY)`+6X_`E7CNUVjUml<1a}&Jk%({0cFOgo=sD8y7{=4Dyt`p8sf{n zY|35=j@JG!ILyrj+?e)k$-7d&0{F(>WpeQAo*TgRFP^vA85pGTGUCXlH~Zwrynjd7 zf&`}J=x}BBf4#q}%N;q&dPxt8#HwHm_y_Z@^hC?~B(jrB$NlAh^~8x?%6h^`e$l_Q zmuILCMqPH&T$G^*)rZE~o_+d8LDP2VOVeq=?Wl^}o!GwAE@@qX2$zSw#VuPYK0CE2 z(9R2w+lJi+HK%~`WPHlu#AZS1U4kFs*OHFR(N}d1+b{1#GUJg+-F5qj+rK)2N$@I> zyY(q5p+9`M&C;k5P%^^ap}4*xrgjyr72e6&&K`D^Jofull3&~Y*nm>l^)a3sde|sv zrJyR`;i3N}tITjhYc)bLd>05HI9Ey^Ts71HTdRU0x0)pH2>E404Q-$O@JzDDr#ur1 z@RstBRp*M^3f3wQeLKKU; zi}9`UAq_+w3nYziGev`hH;jHJlId445fpok)HZMlL=&Chez#y=(-VuFh)<2FF`aoM#dx3F z@WF`IvS@MXMU59uRWy3vQy=y%9mU{iL;Po*g%U0R>9kF}DZ*2w-bYn*=U>l*^*(XJ z_Oau&2~?zHYhH-M8wRbPiUI4n|Mxjnl`zBiA4atMYa)t+9Fu)+#qJZZcS$@o;sPcb zh5(N{fw%v#;#3%F?5t~&T;v_Be4_ragK??VQvaVYqb=t{O7E5ocKWaPJ29Cu?##nL z?Rw+)x4JCsp7qEy#vPEv@x;3Ac?q@jYMRW?qkIpwmcjFGhEErT<9=}ZPcXMa&!g;7qik!24F*_k6e_(JKcat%6Lx;LzLxSNsT=$dlT_zDa2< z9>nCB842d8F~2~&`No^6$%c^F5RzZA6EySt3Wz`EW>YVYk5L|zWCYj9+I5k2D4O4q zR{B!FNCCl?^gp(j;%+yXicoIK~DSMH^7@Wny zCBO@1+uN=ahSM_N$&LC(rn!BtKry}>KbtIdg@N!soSFYSxj8Ptj2^AAHt6U zwxHYT+ltO0y^f&-qv?GqD?{+l zJUg3Pynm6B8M8YFje#mXZBfKDEZ*AJhAw=O=ZCEsG%a?s z#mo|c0Sy^Q4?wDo`19;V<@N%B4BVe;{53=>FelD%^UXoIU#0mar=ao}G#<_9oNBQI ze{aUclgO~{BYgHQ7F94q@nuZ~3xESTS-+HSFpU79OaXPF2859<9t+EIL5uu4Hz*<6 zpt$G1qY)F)#iD~YFQIQwBVXYr`&`Yynfz9D67z}%8bD@vLB(XoH#M?PofsQ`#xrb7 z-#$mQH)lIB{Xe6JE@5SZJ$2%pYr#>5H52Xk=K$9_A-rtx9#6%)i;X9T7o?M&ReR2h zo~R!-a_0eLQ4;H4cp;%-vEGs=digDyv7c5ewlk<<<7*#?(rWo><`mgGiWRYSCuMF$ zvB*gy&p#xmBHU9^e~(OgO0B}0pPDC<>1EeECD%NQrp~c3bgWpbZ(z#I)xK!*gIE`ipyTb)%#;HrZE15^hh5 zJ=)SRrQ0&-o?UzS0NT7c-N3NMtLN=zM0Z%r;D_2+leNtrQ#g0x_FMhAsuj-<(lcVl z5@v1;$gf8i%^6e^-P*!X}c1+k!u+w)toK_erm zc@j|=KWFz^nCsNlIO8AzSVQh(O7m&yR~A{^q<&x!WNK2&kRWtWu5xTp2l4&GXkO@+zHBByaJuO;v84LMksxxu{rNSz=O*N-ad&5 zuQI~K19wDVgydBm9oJDE3;a3;bMjO4T740|CVPODSAszsl14Ru68- z`^fq&cB;iH&CNhpqahnmI|2OBqFTh~_uon=+n3wVPF775`yJILgV@7b#%K|UfO=v~ zOjP~Sj+zQNc-4NfMfyWhc>fIX>Fj5=TjRqSVc4iKURL!t%05jvu$QOTZtRLqb8fcD zl_eAcs%f!XiaFB{L0(6`cIyP!w7(^fj^ONb`Yu=Oj7~TIFwF{4DgjIpPAQ+ zGPC#4vr62y7tsqY+!w!-gfZ~;Q>&Ssza@LQnaA8B-2YZ4-b7uyAVlNnfsnfxE${69sqIWY z>?|kfz{nd>oQsv0-K5R3b)CdoKRk{9V&x+Pu{b{Q5@$0~C{iqhdq)Ol)-+$xcnf&S zWnt=n+iBRA?8ZR-Gju(v+O4VmDy8DtSpyBM@#OfZ_Nd#aG1)q{L+9aw`$a)Xp>sz^ z>B1T*s!rC|i#j1D{=V6ShQ>`I_^YEN^L1aP2y>%WS2q@BJ2!!hEf9_x*4#CdP7B?3B^s;+~eB3b)lB$*%xe z7h%p6<07>i9L|)B-nY7z7$v`<%@rlgKN+Z;yx`=B`@ElORsm=6K4@<|2U5IB0H%;d zT(N{Y33gvA!Bsn3?e2QceMrgZq-~InZjJvRhTZ9dz*-IbQEN3WB?+Xt$ZbdBxv!{Q z-U-yxO9p$kbnL7FcCMa@Q_+wDbe~$#Mc}?!0EdTil2QM|;_X$#CyyL#b-JPFb}OO9 zuh;HshA`|Ca`7Yb2SLFU;r1ezdMzS^su6+XN4uA@#Hgv@$|sbp>)k(?eeu765a2@?Wwl)eE}hPXq{|A(d_{=&r#F`rwVZFZs7mM1O_JsH07lU!mR zXe2HUdDc-8{sddM%U{K;9S=3A>!!aWYytfXGlcjhRh!D}=L4jLVZ;y3!emg(UyFH` z>(cEd;uS@xdhZ3qbe{I|Fj(nENV)&x4q4Z-trHN(&)@?pj|vqW7TW-mZ7re&#lW4L zgiBz!WPD06;33m0!&(UlF!?>H^SYTYag`NndQ!%%hRF04JR^KK_*Kyb&e`oAve2y1 z0CWs%2Ze2DkuR(1=k@#1-sx zCC|}f|HAwF>XD`Cy!kif@FBJQ*}t4=Vtx<{|JKyS{%!3gqeP~;t*jMY7Mq7k!0LMF z;^IheRxx}%N)ag3k5_}mMcXWDRv-Do9MEDt-aH)oHx;xIs`pT6{7?fK5(lIkCzKeTQBkT*e7xBB-T!9$= z?Op5xXKzhYApJUW#*jv&)#*5`IUHjn_$-d&}X*TJR;sa~+3&XyrF7n(H5sqBqg;88tL|c4H7ZKJqgHYrVnl(BqR$I3?9BMrJ+Ipt4s`t1y))HiCt%eqKu^ZaC8i6g;sr4sf7r02bD~Ns~MTy_~u< zNc}07QCDPN-K>G;677<*XyhQR5MH@OvrUs68g5+jubcDltz;U>KO5bw1r!Kkn2}Vm z`3^uVvymi8N1ePQiA?qHMxM1VyZJ4*pSOk6fUQ&qzixcX2NEhDb}uO7K}A4s<)|)E4`ZKk8N2h|6QP)cJr57kUAkHR%A{86~;9zCbF-V zN)B0A7eB9SOOJUI-!oB|_Cqy7Xq$DK_Q<@Wt-pQ39{#9edm<(10Ni!>^)@G~>u?4fmTc3FLK|V*cv<(sb#qauPeS>iG zm(lK^XbFC_`dk{S^Xf`Z{xq1^-7E3Pphsb(7xt%=Bmg7*m+bfe0(-^)#&Rx0igzME z%#>>o~OA1~A|F@D@rPN)Cv?7gInOQ$8p{&TW%e_SBJPnngl2p3= zi29mrqNH}h%k5tm0rpGPTEdbeN97`to}Rf-ZFVH3x;JCGbm8~N^6xG@@XIr$4-)^% zp9*$C7xgnLS6Mupzc;rciCAU?dp|-c5q^Qy4mV1Jz~Wx2o4sUFC(@}i_MKm1NjGXp zA5>yalr6^^jPwEBx-6O0#ZGzq$*YYNAM}0~y69DYL22=nA1EA-yc6hveWNui%gYh{ zCSmKZmuBY{J=LgDOZd?3Z=2zwmI>1NYd^KO7(ALx7+g{H=4oGW-p2nFB|A8ucT#9ax za->u)y!m;nPkKou>#ka^byWU+1wUd0K377{P&af>73Z&VJklyTY&-0{>lVo7JjCVr z(c&XD9M2&_3X|YDEoFKg4wzA*u!NL3SWh3?s9>^%m+l#L3o88Kok0KYxguja=|@2( z@b)H@I`2#YsTPFEJn?R&x!p>?DSrNBWwvgaIpg;i0{%c}HC(SJEDbcqD@*s=vty&^ zL}&XV9De5%(zwJmSF%{X`fRq@!t=c+JATYxsP^~$nS|1sx9ij;e`Qwq5j#>_ z{0h>|Z~w=8*{~?L501O*XxFifIj~lb(NqRtT?ncqCw7&VPdZdddnpbU%DS~3uz9C) zQNFUg3TtiDtrShf9UELc?*p};{h40u@`FPx2rSB?(jCte-2`gQCIVvFg5Zp37a-NP zUFehLrm|tn8$^P8sMW&qjct`$raBfzySV&z@`(yEBtXW+kmozgtj>5DzHn@%yuI@a}L zGbO;xQ%_pKzZN_%xfzdio%vp_W<(2={0~Dy

    LD!_0Lwc%svtWyMUoGvKxteDpJ8f9Kn<-pM2pTtF7eZh z7M>ct82(4et(?men9{Q;i@fLKtU3}j39fww}dref~@(%i-C1z-ot}gsq zx;ytMeeNUZs(Uy1c3;|pWiK@wkwjd@{yo=601LR>Me~Y(3<=Kn(OXbDNZwEX&vZq) zvOLmNPW(~sfYjo+&|8*8hY9^cMLD+(pa-JO6Efhw;t;enq?aUIkDℑI_4cK2MBg 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 A0RR91 literal 0 HcmV?d00001 diff --git a/assets/zh-CN/bp-20-yoni-goldberg-mutation-testing.jpg b/assets/zh-CN/bp-20-yoni-goldberg-mutation-testing.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bd2c6589e11f9b6eb7ea13decb9697d4fd1c667c GIT binary patch literal 179509 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𝔄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

    }m8 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 ZxBnC7slUGS=dx0N+2()NHjqyP{|l-0*iirg literal 0 HcmV?d00001 diff --git a/assets/zh-CN/headspace.png b/assets/zh-CN/headspace.png new file mode 100644 index 0000000000000000000000000000000000000000..25225b18ca84209eb6bfe9f7d2404cdb487201e9 GIT binary patch literal 474856 zcmeGEcT^K=_XZ4OKZ3|nY0~tFf`BxU-YgWQ_a0i579b*!0HIk>Y2hG<2m;c32_+Fi zKoN*i1tbZC1Oe$yYUsQZea?C0S>Nyb@BQap%v$0-$xPPV*X(=mYhQcMgd6B-GBa{9 zGB7YO-?^=3#K6FfVqiG2^~X`*lLv|JQNVu(yp1$(GL&@iOaeQHop0#gU|>MSFl{*; z0rrpIzisKwz;LpW{_ns`k(1mE47=HP)NYvg+0IZT4=|iR@m}J6{rHE6kplYnd^#(D zbN;XGwp{)H^%d~>;Y8Ab|NHAF```Ws&OREyfx)nk#y%RqBk=op-!}Hq_#J`Y$NRRi zkH+r^{65~djeRtJN8tDIzHRKI@jC*)kN0h3AC2D;_&qZS14*I|9Ft_ibYz zjo%UYeY|fQ`)K@*!0+S#Z`sBxoZ?tGzw$S^t>HNSyHiV5=q8!E0gh1p_m;5(jWr$l zZzEl8E-DBK4OBa5Zyvh%qUW7Flual)HY0w_;6c=!*l3?_)*p9M*y7GA*;_oVV1aS8 z?fPe(T4GFi9RwdsnGL36clZ?Q(C--T9shB`@z~x^e&733t?}gV`+LXdpFii_`^oQn z*Z(}F`1}6eap?IAu)Uw`*}I`OvuA(r&ZFo5|C)UEC%gx({X4t|j(wBf1IPXv-UG+J z)7k^azL(wu2g80?+Jnb_9Nq)RKJnNC$3F4c1IIq`*aOEt@z?{$KJnNC$3F4c1IIq` z*bB!#@z{gMKJnNC$3F4c1IIq`*aOEt@z?{$KJnNC$3F4c1IIq`*bB!#@z{gMKJnNC z$3F4c1IIq`*aOEt@z?{$KJnNC$3F4c1IPcH#N%oe2txb+{g#k#kC&&`BNs

  • }v| zeF3Y!Soj0H{7#mR9o9%C>9wn-AbheypNyl)dPfoI7c8OjfAulEA&s57@s60BJUWUQ z#AJR<8r&}3NzSaL4hW0aD{id35$`cCjc1a2)o+M_A6W<%E|;Bpdk*-?_s_KckFJaJ zYUUDiy-OUUz4Ys|1{o^cknboIctbqAT*JfGJ{>W-Jsj6MIy@RfK1KhbzDs+WJKjGr z$u7`(os!~#fB&gh)-os=XF3Rts~;)2${Al?CNadH7EbGUEfX01RVl97rOae({^f(| zR_v$-jxTXCZE;Mo`^L(f*VpLt2DVk#3~${)&-&u@_cmuTHoY#Z5gW&nCV1{|h;1(h zU}pB82k=}$NcYJS8NONI9%eS4`#r2Q90c94c?y8rWpuuM{gtymi zEp1aoB1JGQ?cB004RQt7dfzV3tBOs}{)nC)9iu3&Ec6cvqlbc8gPR1={@+Qx^NfENdHkki*2k%yXjQH7-+);G8Y zws-kK<0?uNL$qP>oxe_De?b2DbZ`wJ%ok&N5sOF(QFP;#wJ3)~EjZfBQYQ?<*< z$$_D>^VAo4@>D;jJRja!@${`;9@|_I^?RL%31OiRwfa13+ zE(ep_la>eTcfn9xKj>qUbg?D5ZhMxJvf>G6b|*A$f6xPF`7JQ1zocq&&#VI;XJ1`e z|IkJnXlY)!DWhxelu1c@YYRT?72AXV+D5IN-d5@NzeRe#dvKa=ZtEKvK^ z4_95yVejVXi`~?Y#R=rGJfHl|)aa2PXsy*|_PVBwcTJSRW(2c)<8G`phrDeN3grC*MCcpRf``qB-C=9jn@XsZdDUzwgZ zkD1e9>BL{;hsCY8#dLek^e}#qCaU*c=C%tm<|{3IRaI40Ub7)Z6kRBg%+UHy=s~X{Tm(n3<9~w$||Ey4G*>cG0&e7VE4V523 zAy2^#w_#HX{P?FwPrMvB3)cHXhex>muu;dXao?TvPSLu*UmJgHzoDnCH`6ASI(~6Q z>TmBmQi5|SE#ueXNIrbSt4BMe{ZpS@O9%+K^$-nvE_AV)R2QB7=;0$?$bBC7{I4qC zu)EsY8sgU7)b4~z8eu$ce0QcQ0gYa@MHE-r-6zPh7jeHvCuv>G8M^?hIGa$2eh!Kq zuN|g2%j`6B`Y*e5mfQxF50kxIPhpwJ-VjY6Pcm0BnF-TF=2b+8h~&VuiXVI3C+@_O zuMeRW3Ez8+%N5XbSNJnbmgVz(-WMeHMUhr=^gwF*`pZ0LPxLl@Xs8i)|C66qKbiP3 z2y<~=Aun&tCAAB$`0*6>ZoyyJfN)aulAJ&YP9NW!>e4r0JB)IwIfWfwsDZcb>_8Fkhd&?SN&i)b_$Yg_M346Zdp)3!%Sn%;e18 zTjBJ<=dsjdH&I8~Lc=8CNRltq>QAth6B{yuZJS$)cl#`_tH=gTE0Pplz3aN|u55Hq zvhV?|XE?p=b&O=YS!2nk!Tdym%dEv2h}j@JrWhK&`dYL`x3!HYvNc5aa_1GbnHTv_ zW~MGU%2ox{WA5uvEad*ou@h1DRP3d(#x+ep72;71VB~IgpAGX~44}UN4cH_eQ>W%* zWbNdVbU7k>n0b`mfDTH8+%?1&nlX|Ai@N@DZxiNQckfei+Ue=Vnleqz%Ey*2#gXgl zKLxpaL=ytbO(5vmI%V-6!?Nt9KEtp zG*xR=(O&k7q?;D*J`>{R3l^k5)X~q*hLf_NnO~GKEotz|1Ggtx1d%;Z1=)@EAcu2< zl|id|-_QZm9bPfK7hrLm&gVX{GR5`YXe?O^mhAFYNEy!@cn&(dP}2aOpBP}bmhH5C zFZS>CyL~o@nwxbpAahOTjrq++&$jK(Qe$7q!u+Bh)TS*& z)7hO|Bj4}rZv6)L9JJt3s@BuTlCuQQwa);TJO>>Y2&ijzPsVjoC~^9oX#R!bW9Y_` zQ`6aPM5Gtr^xbLn)(^_xr|kw2Ow+!b%?*Q>?^&lL`%(VwO?_+i$JYZAL@q)RQhVtw z=$3=c04Z_zFffC}<9nH1e6b9$)Hthz9nEffel!KVt>0xg_X!V$h}~#QM6l+un!;xYGw8_RIWaFV}4bMZCN^@w_^#PMgHEo3VI@!Gr>7-&Sdsl`=GYl!Lsw&GZ z4wr_Q;inpEYiJbv zf`em&F243reJ$rmB$Ii`vMPUKS7YkTn=08;Ur@u%!Yalv zm%Q5+x#fRVg|}&Z@`$%Yl2+zOtlTu7w(+NAJHNTb&qL*3%+C_sBZEdbDkC)FggpmB zzfAn-o>)=Z7|$HB0e{qedE7M`N9iMvX--E|sjLrLowd7gLj8P~(Yh}))?l(LBi%_P zG<3~dMhiN$z{WSw$WnUyZ6T5$R-6Jt6@RxKCVd+wZD(~msXD$o5fj%=*^!H#RGW!# zAGssHQ00Z54kwx}Yz}l)3!L=qGwp}m8X|o`dBBINOOfNZ{;|lsCs#CRHzT^3Z3Q?o ze2=j>zhW?$R+|N8{kD8>-|=N~VrZ97gN}MM^VfK8E@5`dq)CgeBT{FRxuBrVfJV=m zjpDrH!^-MlRjKr-O^K`TuH6Alc-1i9&s!| zrRRBSpqGTzF@~jfgRhveCW2*G9rR8N9eEjFV`_G@3bZ-xvc|J!C3_iKc z!w14lJ|{cnAL-dH?qkwzSEWc=7h-&UwN<3eHa&RPzrNi@tZL*ZZ%)i+R(VgKc#0Jk z3d>|~e01a`w};}`kMo8sM&GBl)?JaQ6YlNMnA2>lVY(h&1erj0VV;x-S7iIZg4K*;p1mVW*8EQ-H`Eod|H%w zU72!lARe^Pkc(+vICie)&tUrNCI!&n0yjcl|DNJqKN|qARB!zepbK$cKEXtc+VY3^ z_;^MZCzD(MAV)EO_wh-INxAf@F5)mugMxqE!<)=r6nS>KD4Hf009UhaP2lWfb&Kvu z4U#-Fn!uX1Xtaez#9cDyFPSGcny#hYn zaoYLKc9v388ZjJM-L(2~5!uy*jJq{miz!>Dsr4oAW+59fe5BJ@4do6(M+r&hvzSqT zok6&VlNc-F%9&aiD^fREhCLN)IPKLiD0Bnrut~Kb)!_%+yF6;Yf(;=-&_{*ML=?*AxpMrcRLZ?W+qItdHl0;zQW4E%{-Hf7RgVB-At{<>L6 zNbPz<*Om8iM;Qz(BUP6_xYVvDS!}gJz(eIZfkMF15_=yW2rZ93&KdoO6kGV2m%LV7 z+J{tgE7|eheNREvUv!zuq^Q6o@2M!F<$Q^=Cgcc+0sd3cE+~LbL`XPR?<$jh;p& zW1oXiY3$U80FuS=r0#te-2DP>%(>HQ9M3qzA zQFZ~QY=c@+#A-3abvqkRVIQQDFBs-uJqQI8G0!P#l7)_BXa9vl$5Rrgu+@e$DAqyR z*xb8o0TlK@Cu>CoFqzP9=!Bg+2%Jd+|GK{Gc_$g%h=AYgdN=m-wpNr;nxdoE^?|SL zga2g%KM#KUD2L;P@SU!|``Rumj$Q2tN_Jz-aglJTU9qH{!g?Kalj2-RT3(2<9KSV< zSPuUCSYoqM$3mvLH%BDbRlUXntYX08(pgb3vXuT@+|sZ_WY`ECrL(MgY&<(FiQxWiIQCVk0Y*=g3Vm5G? z!S3D=ke4_-R7`O3Xcug)bow|)lCR0Rs(0B_Af7vInp%0jd7#QwtuTT@edkaW5JO@M zqKd4nMQGLvgedWclvZU*p*<)(vmU2rtts!lV3K!(`kq)|?~GN%fmSka?PNupgZ zN_XLeCAoP)F}3r#s2#lNcPNrOg=c)HSLvS&V#+S!Ys&WLa8AFSFJbpVjJ?_RybRYR znO;dZ4Rfnrb^#uQx=yLNTu*0z|7@YIlT?$K8?U;3q35{Ev<*`{j7vT&Hx5b4lDG=B zOYE3mJyP{RWiFcL^>yKbbo_)PXWdf*O7d7CX1Y5ARZuF2qUPZl0pdWN)aq=qX8PNV z&Ox8m=xQTUj7-iqv;53Yl3u$B7Us(}P59;{ifgV=)26UWv!Wk6cJ9*$#Uxp%$P6xw z|2|_6n}(*Qri=o%CPO4THFe_7$kw`?>NQ3@)~Ah(fjZ9&$jixKFq#ONh~n{8Qonp6 zj@w~3l|)U^H@BLPl}psuD^Z4>3<>Pv1NABJiiW8~+SMP-EF{_enr`Su?66O6n#!N_ z2uxI{=h0L}*zxR;X1kWc2g6^fz(bam7hT?L!OTzaC|$8X#-MXq{eI8pQw|wuJ5`$} zv1Ul8V$B8-cYD;|L~eb|^PSu0|it=QG9+tpDuU}IEtA(*@s{=T_mD&Cz^U;B$nLeA%8k0|lL)NQu z3;dVnIJ-~~(OLqHb%*-y81k{#T?KKd@-zHX7h+M;>d1d?q7&hV1x17JFJ5up)T0rOc63HaY}($&LysC5|^zEGmRsu%EY4 z5cAkgbcl9krANe^n|R;K-1BI4f(K-L&b634Da7v2t-M%xQg#fGLB9Di#$d89S>-4- z&qZ!xibNjZuHu`8G+3~*(SKY%39u$ga_a!{p?`jm^YZdcWJ)qwlUFJU+?y2mAQ8l( zGi%XnEoa7tD1Ke_+-5%Z@?r#CCIz;oZtLysuHCKlD`qsS@mC`g&hxE~zCtJX&5kjc z6b{|MvXYh8NmTc;5c?8rt*Iid!|ozlTQWO=oSQq{jO0b-d)%mGMVf-`ycCDg z{g)^8?sOT5{X~MHt(^6zy?SkZcvfyf8Kj~le-hvB@wrY%-$~~~$5_URM;Y>%h0utt zn7RaYzaGS!>(-o5%!7rrp3?pGWLL1;p%SNG3OIJ~Fk#>n1Erx*h`3u4FUQs*?Gd zM20ul1&wD4Hq9_DWn!YKtQT5x^Z6*r8qc;~2p#?dp`lsa%)P#%DHKdWWeU~@XD`oD zj4wtsEiY@(kh;E{fklSE!L{g)Hqy171>82e;Z*kX?J#1M=(HoH=5%v{C<;=`TQ!1i zsbvvT?;N^-k0e~iS~L9u$aHETyiRU=`QZe@Prr8Y{j2h~twS-C)TSxh>8%HJzr|jN zz=oXPWd`E@-_(&TnxfFxWU(H^1>pQVAhrMXGr#`o+f?VDy8>#D8#iQ8(L967>miu~m7iHNsM$u{ zqfF%W`eoj}ChkF0FI9vUiLhtBDW{UKxi2uXgUrp-{p?xeuIBE278Ja&lQv@JN^ME| zb3*$0c^j)U#uJ2J0{Qzl(;+(sZvwVH%k6x-<+WTvyN9Y_Ek=woku&FGHAj|dX`eHI zNiXRJ#Kcq2WYaVzaW80U!2C`A$Ah#CMFySOOh#%lUKU_Pq$G=1^SkvTRCJZ1)XE=i1znu@v3J$Zem5}ru$LCOszkON$>-=?-?QQ)F>s6TuE6TNkbQ`JtF7l+tYr< zxi@y)455Ds*}kHRWG8|GSY8gpCUI=Q>1}L#y-iCu7Cb__ZmelO!+nL+l!Llg^C1z` zswjzNErXo(<}dE*lfn)q=1!WQl_Qxx~! z+F=(eRBl%ZYo7BrE)yvVgT9P+F1)n~q*O+lJ0fwew&%DbcuHZ)WtsQ0vNl*FeG*i1 zGUSg~b<)(#ot=lOMC*&Uoa4AR$h=)$eQe6gg%x`iZChJq+{cU)?qU%FVJq`?J|GBg(>?!X*eC+cD zTuKq^QN36Ih3W5L#7ObZ&Xynmg+#^P?BcSqw|m{6H|TyQMKZpu_2yMYTGKi}?~=|t z$y!02^=&4;nd0V1l_eJ0ZhmdzMBHSG{osyhSNU5}n2ynpDGF9F;^NLQI-(?PnI|>v zhkVPU$JtM5P9Vh0%;XjKAn>e}?7Bkgou;&Up^4e(xw$!c?$P3gh9JsUBc&NRn|Y)Q zM9AHoNk$!hC*(Y@T|`)JMDzuRkI0e>L=lyM9NSK=bi`)Di`3mYU61T%qT|@rV)YRx zEMH#c3bDtUG@2{Fn4CcX7;!|cOMI@g*v{qum`ZNEJ%zk|XuawHLn8B}a{q$rhSk;@ z5<6VgA+EW*^lXt{Pki6@=bpC{*fSoz1yfeuboBPFb9py*6%2cZ$iQeYD&Z9Qo;x1L z5;}@MItCvRB1sFtFskUvE6>qhA`l!3t{+>bgZJQvVsCbPUvsDx38VFEF(b1JF@So- z)N)QeGc?YH%ClM1e7BX6aoTUhrm46FyqR?gb9%)+#&?>~-sN|GH34ifgaPTn3O&_Oe+! zH(?`3#56CvCtDl6_q^R-&;Au3U{T=#q#%}4Bs0>-mM?YE5i2q@XrHa@sp~CWXP&`l zBS8GkLk-n)o-~N5E=XxrD1%+|jg)JU8fNUQ1XXodAN@&Kcm4 zM3ueH!|67Z{hig9@=H%;lLf9`aC#+PSVXX(ywKOXF;4}ASSenRBG|{N#DA%SMC_3c zelH$IV6SXKI1;@fnQ(#Bg`Y;W346S z2(VaU3lzF7az2EDgcRZ0?o{&`|CU>@bsLXqD}Ya_fk6)k|!zTa8`G`3ZL`w4I3h~DFb0}NkFjbl{LiU-Z@ z_zm?~S4=Jk{|WqX&cCwuPdq~-S}#a=h>jdCvC6D~JbGt+gT2D~i_Bw5Y`!bCR#8E7 za2{DglDBowsiu3;@R9{>80wPxrqPppxTcap)3sKzxYpWt0{zq){Cjg10L z2i}-7-^lg%z^)EuRDQ!N{3Z!rsrB#^8obt4{TXGJ`gb5ejWJ8YDqC~;EFKVkw&PQnsWMTm3XAoy(^Vh$y z_6&vyM2eq?4v<{->;C-onJU$B`fmBc7?b9bHJ}SmnKBaStBSorZ|DWx(0-xI7Mjeb+ zExWfh?QE5q>22*!8Bke6P?8-#)C^VUAtw}6_3nDK`5OQ2Vdu_QbBNyupK~N^Gqv*) zFK8TpbV_4jObsJz1RbKuum_jEnK75gq+M|H5Vh8z1fQ)}&HBOP$+gOZhOIW%U6B2P z%@nmlM+ICHDn|>XiQzvy4y%`)LMzk^Z@u$QT<9VmenpV4Lt`nRV-`9CfBn;53-3y)C}lBRz&#c7lx|q+L2eFdnZ|5$W-2j#+-(T) zstKre^(_M;rs=K)aCdXEJ42y$KO9$86x0i+g(jF8u8)fDd^rZ5ES`o8*E0jl$v|1G zMSRcwZ!wDUG$ucCxdZefNGDtjn+O=*Dhma557YroMh&K!pDV$*=AJ#Lb)9=@|qN5As`c2bT$r%$?=QKNbhaPJ+WHD7EvWTMEexm?ahHiqyz}t9`JlKk*V+hJ4#Izh;UegT7@UNj z^3Gj$QBE$20U$qLH(3Gls&5T2rOKdsz;iQ^x0#YLPU-dO^rQpC3Ft|mnW6-1=p^d6MC94G6?}MvVVQ!skO?pi2oe3h3ylo%YlQ@Bmz;WByI@-yL7ScWSH1 zHUI$?4Iay|r}GZbx=%OC!`eZcy98j{Pq-lBcV%tAt0WU?$Qyi0&G79His*3*C18j}B)Idk{Y)s6rP5E|lp-?@R5J;WumdjGq7ZIWeG-jMj(>72J|e}gQ4 zDxdejvp`TNlfC+?+{MG3$g1faPlBhs_&^h5%D5Cs9A(1C)rZK}L!HCt?Q-72p)*1- zRV&%Xjee!`Ko)FpsblB6nhN0gO_EvdQ~;&OZ}g#f6J0xDipVPa^cf0o`l*xyN4$({ z_$2f~X_>mz&QUv0_x@M@%R34hCcT|U`p)3B`B?ZiK7=i-9|~bh3(QdDhR~Gaqpc); zLPX>NwC$aI@vFYpj>MgCMv3CCSiGH#e)dkc5~si7V2?CsrR!`I#aM{cUe-W)lfb&5 zwNS8-q|8fplb(^rB*_Bpg}hiG{YSt}6pj+wxmE2G9^C`a4eVUGYp!Jv zCDt54*?%|@<;&0a;Ykt^%872*69s5l(D=GseFe@5vqa_P2CLOe^qeBM*!Cz?pnF9== zeLhnQf+Jz=))lneNt`f%=ZXJXuYE`MkABg?t$?l7ILf7%V=UW08c2vr+0<#pRAx84 zfe-ZZ^+d-fA4i@v4Tr_ioww6RzlFD1KlRjHXSlmZ_{8jN3f09kCS|h&zaC^9Q@s*Z zQdwDoYycH$vQ# zng_8_WL^|$os8CZE|fnYslbO|WZnqI=G>du??Y!a6F z*a6V~>t{pdrCHDGNHz?4H8?Ibe5OnL6`B4^=!s9caRkcB*LP##l5DvU|8_&KH703)2(z?A*yyxZHvMF&pENwj`W928O zf&QL4iG+a%-q$Gpn_&xegA^|F9qP6^KHI#s4VoU1z4@B&ABdN>(jNIs$9V+`*H{FcHpy%tfpg_c8h5kG|h zhC2ta%eG=ifSSVF{%l(Dq_TT}Dw*~p)erJwUIL&Kd3OI*8%>8Tc3=CgHZDkxF|kFs&rY>9+)y6x#McEWg14u(Gr6`^5qd&uDemE!Fz*ew>LA4deCR{XSa*DAh7P zD<|qgT%oC>v$^zSVY#WkmiV{pr1EJ~%GwbIdn)!FYU7ZN33W;}$Y%hx7@1ZtAx3@x zy%rSsF$}fVT-D__E3K|6>aIN*oP(EG_M>8E2krcd%y&!4ktHz;%?7pe8O=|(2>CKX z4-Nv^@Dz{)vaiZ*^lg?W{s2ftGhIV?v$G>b?->jh1&~yp+;$)2kFotjD)K6TQk&}U z$P#cd%}~`oWv46`%HwCjehyiA6z?FsIK7o2wE7Fc*_e)*!WHraPsT*_RhD>u&K)zG zN1`)M6|o9U4;0v&pKV9^k6+7hj62MNfGbH{y-DgnJF4s(wuvbfQCO_bs;UrN)iscq znds-(Ty1|p!4)i?2-Fu`M6AjRO#;jB+w|UjeD(_$Zwlz~0;K`+aiEd~0me6r8dg@A zuR?BTS82SgRX@lOs`D|acim((i*&tMd-|TsmFm$kmzt$jrjej}?8?nX_hmmosH{IS zWhvUU*$sP*?n|GAuc1MmPQ#5rvu_6j!06)9&!V#9s7h=?Q z5(rIvr~egN^1z)dysf#RZsoAfTk81YLH}zi>uPWrm5^_x!yj&`KG#I@L^$j7#PH|p zjnRp)0l$@XCa~3ZCGC1<`-DL5-Yv3kFA&bVMXw53M+mrQ01BErds&h%PV?lL@g?C! z9+-QwmPDyCY}H4jf4L$wMKC1(!-R>sxe)liGV)8m<@bOlP3Jqu-Yy(88IIGz?~uC7 z&$C}i9J_3*kpg-~(}2Titaxf-Y)=pxrsiy}|3z7yx&V^0M8@UE>0x z{MXFhkd29V;870M5CN5w7j{0|Srn#|y$ z-Of@N=g5x0*e7Pdxla|=MCfil$hH}`!`VVd-5o`aB1=FqZ^Cc9=zvqsJd2#E9gdT5 z*)0)8c~WYGkU;AE=DqbgP~6HC2?(G^K1HxMB3#jhmg7RMk`A835nyi_5@S;t-F7XY2(f2=Wurg(PYoROC~$WnUf>ji`7%{ zH#H{J@{GI6oP1T-=#i~&6d)5(kzCvrtyX`44y*|AlBs+!chzL%tT;)JmaA|toW^};2-8XFEVPHu>yIP~zDRhQacBoy1an9{~S6TCP zx)f;>o0dw~uNj}h_5rQ%vFWq-7V*+R7i*7fX!Xi}Ai<~aJDhpCG74bj;Vb?aw^ zHjO1!6(X=w@#?#BTKY4TcO{L!3R0)Aj-^L>BHDCMmnG+ezut|Qum2CaLKd_U#krPo z;atK6*e%1Fp#wGPmq8Ei@LfBYckfnucSxJ~vkUM$>{6mpj&6TB5&;55Uu=OTSIu@^ z??G7@@>m{!sJZp{RnLj{fG5a4RRR3XW8oO3L-lj>_FQPtUd&&g+{j^DXKiDVy<*KL z3kp_ef2{*XkVO}IV=A3Trt1SB?Ds_Az!}%+MZCn@U4LxCn-UU^bfGg91D4dK@)5@5 zH6Tf?OnMy3Z2UFY+UI-RYh+12K042G7Q=>q)KG^-G=B_i<0vEo{WpkF{0uZ*v}<5M zsY$YTjiTcg-D_NHjiV$BoFugmO@{!LYg&P??@-?%fFGVXLKYTHX{+zgK5xv(noTE7 zoz07gxemQYNzKFDL?_~%TklWi9TVz!jdaz9g3@@$0ZKI=He%Nrvfjyo4A0cuPzETk za9F6m3R)H!yjmx>g(6pQ21JZA0)1ZZXXN1-;`H+7a^Nt0`0I%N&nB=u>3@mRb<^rP zSAP{#`OZ|iRQ+CbrRUS;jhF3Sozg@Qr_j#I%Vcuo$xydgBpyh1O?(D6QZz^6^nIL1 zmX7TR^C>Mq_WS-ReFlzvqwsnV2*=lt2f!Pfk2AsMN%i+YKf6cHiuA2$0R59FPof_! zm%nD!BlYp8KlxXF7Spo&!4PMN3WY1hI%ro$ylOsbskeN7&WeMH&IVjw%WWNBx+!0J z5PpU>J0WCjhVMTj zQ}chQW0DK-x@waHlJup}FYs@(yTK(-3$)Tn_jiZ^x=Gk^(u%juf$5)nC*fJM6){7L zWDd2u@BU3ki3nHXM#QW(17wmjT%plveRllQglQs;8$}GM_h~|!PrC0t8p~ow?5on-Fl-zQT z#UzjC+9hSLceh<#+6#vL)5li0k7BZs9w`3=CN)4c2HH!`a)xam3hg2^%84Htxm>#n zb&E_mUii0=z3j8nUCLlY22__&bh`HlL!#!J0pOX^P^%w6F@e3FlhGjy0On`65JmNG zJ3v9t6L19lK10==e+x``!cwO|+BYtSx-HW0J+jjVBQsY$R^y%}Hwv&Fu=>Z0EsWbB zz@!)R^X0wgW}bhd5Q1WyW9hiw5aPm=xFlw0LYylx^HD*{pf1bWyBt_Tl^Qu`uA$iE zIuvNFfP^n_%Lv(HpoBv%6^^?lq$&s_cvtO1+F1hPVvE*1@-h331y)7 zzpK}DYT^nXdkTvc8fnErcEkl(uw6cV%>%>>aHgyP_=&pJ`J{{X@L;h+=rEe#$X8!Q z&!r@wH@TRr6eo~&Ftp!f(yxH1!H@^t?mQRqAN36KGaX)2XSB=u6UcB46dM7BjlnJQ z-(KCXvEXgzVL$SzyQ0-Q^j2|2m==8LemzIzzKrdg$&B z#a^o0h+XxY$;9A+$chI~LpyK6cO7Qyc}`VxKiC-P3k3Rs?fH@}a}m4PIIO_!vnYQ% zeIGXQzNQ_}bVjy^v5$V{UEo1U{(dV$(;9QK!bwtZ-rTIU<4jL4S0P@M186cz@jm<4 zqp3AU&? z5^`gj=h#d+O{)o9FI1B2a15YcVs7rwpGp_f`(QPDQZV?#a(Ft5BoWK ztGC=g`WYbb@X@PKfMi?ZN9TFKF`-rhKY1MY?s+YX%2gMKZtX$ne$FOQ92( zX78Xgno~w=myf(C07cAh1A5N7%{sei?L{+DOD+*Ej;4EID1fPy->dpTIxq!_DAZdG zFfCzS)JCb&ujMB}F=VSI5Qb6jyk-YgF9;C&`_60%6yjELT!21d%Nsz8{|wpY+Vwa` zZ*F4r5~7QX7lZ{nBjhd9Sy6qQ(-8^FPuuRlFPW%Gtgg45kuS{y*iK0Lbvda3tgL!# zjpLoP$>ygu;GRcAsJB7`wnKHIoW6q!H68V5?iFQ8hCmd^?GyM^Skvj%QCIFwxHFhL z$s%_1+6OOJBXx9m!$TPbf{yAj_rPK8soSb;!k#t^_804_B`E07>viPP)U*k zsS5bmav_mboA@%@h@#HP+38XDGfjk$YVx<+>VtTlRX-z6PwH!O&MemzxENcOFx!|Q2AT`rVBVLoeB22AZg*&JN5~^9matu@H zXCVWrYpQp@eH#ia@TvN-k#Yj}lm(}kOB~lu5RHUqw{A&uGmK@XcTOD&BepCD$Zu2t z*^oYIJwfuy$R=948P#Dt57mZ<;KhR5Fs~ zEJo;GskVdO-3K0m=u`QyDmDAI zbAq#nb=a(e69qJJzbzA6d>!>1bdR-K|0R-S`du>N+~MSDpl{jXT&j=iIj61rldP-l zI=sL$Yt7qQepi5lUizyx^I;fs-i2hpoosH1j;5+K59SE^vs~5rJby{RaCyP3u??pW z)UTN*@6vYHfc1kIR%36zBUmRs{+(9EiaJwp=q)vyxX4;{r<}N)_U2R0vxMC9vp~y) z^cmDN(8Na9_f*VnfcVC5OXd)>P5>Rej=PiQVO%NJG~EpWkiNd*Sp<;LEsPkj0)_wj zH=>zdR-f@)A0sYRx8%Ki4tl}2I~?}vyEntv$SMS1ORjKkg6$x{^{MSnjbco%l!4-< zi;d-}wZay|Bd4%J$D(q$#)UT$H6eg*6j*M*yAxgt zdhKhbcnZr3bvtXUk)#);-8ct4PdJjS(dhXGO!=`L_@qHab;KJYhg8}DPS#6)SR-ZeAn|I-bgD*P{%x11ZKD?WD zk0Lavps;27@%6rJQfKBXUi8VU9AYrhU@!F_a)EVk&U~i<-H)oTYjPB!oqEXQ3}2DU zso&_zb4dWbPsupA{zV21kWT%?+xX#nW6ak@@7(BL?%M_yhuZFkTb9oO>GLh;PhK!} z|G&>rnZ&;SOYYk4y`*+ z#Ae>NvvQF?~84)VsiZOD7}l_BP__N zHnv1c#@_r(je^zUoy4=EsG3ZE1&yfF7;MJo_NVQ@#!sb&I(W2#f=cc?ySn+9zCl@! z2;GmGRtfXF>cq|@)0ZIeFmAOJSp0^M=4oL#>toB`F4|^%dWKf07|j zx9ZO_?VP3HOJO11^SLzTQr}>C1d9*wc-FY;kWTHn`MaeK0Ktd~ z1;~~}`m(ac#?CZdI-oxtD-Kjz?9u-=qh5bmL#Lic7*>WvWHB7PY1N({^lYZ@-Q=Q3 zIq^LkbL8S+5@|(OWHEm#!Lj^jwMAd0i`SZ_Os~Y;P+FO4?d#M_Q%tr4dPSygM_^W# z(H0vB+~mc=O?3vY4#yAR>Z4UfgWFB(bVe@ z2e#$Lx|G?KGq(%0L{R~6+MTqF4x@g&=`9)K?2{Kh?an3BEM+Li_+o5@4DdNfBgx8a zy$mQ644hTej53NDWb2=2+T0{qQ7M|->@@C*dglYx4*a66rHW<{AG5$Fol*Je=N@N{ z68gc;M8C6GSFZ7@^EmUw8U2&Z5V*#XP2a~>W-&{A_k^kbF$Wn8w4E+k#Oal>Fc`Q} z!3+}TvL>c}KJf;0j%>~Ha#u_={wiNZ=mB;)sx677H{w4cO)mXZ>i_%n?O6Eu26Eh( zK|&T_xwRATynChT-1bxRD%yIu@SJN5UL^p*L%I)FLhr0z@u8g~?6d+pl~samoN?_O zpk%cL=z&88Cmo=&plE3WM9s8t%;vF02!O4Qe#AYNAnKp= z^fFQT-?Ygf+vw{thA}K#bYwZPF{Z@*ETBp~#9nh7U0JNI1FwH=H2UT_-$lK0pQd_l zZJOyJ)=nsj^__MXcIY8Ml=D;}8C6v)4V+O`{|{U50oGLZypP9KSH-nbEC`4V=~z*z zf~XV$0i_p}qM%giC8%Hl1O;hQf+$S{1f*AyA~n)Gk=_E48cIlha{{{i{rvy;d3K-G zh2-9I=FGhF&O39zRMaI;z1Mk?8X6I}b@KEcYENP0$bsvnqt8K(A2w8*>RieU^eY(f zo=Ly6HN<W@>kR^D7N<7^&A)%RviH-Uq>@wg~jTKsq;)N*U#Vi zMV^mY)^K>zw|58TmoGGFLT$;tY83YffOL&#*3xo6(5h(;rKt3(*Oq?<2}Y6N#tq12 z_t4k3?XcugY_R8-MiV6YGH!W1GfHy=?b)C(jn`+m`8k?2Z)xh=ijp6Z8&F zMvr?=cdls56Ez$6b!M7Jb~@-H8D#rz(x({1v}K8H?{PC9VhT+Eaw{k(SX4Vvd;M!| z`g6o^=@P4k({}cOUg0f1@B`}GB-imDft*Z!vj{WQu5-PW5H76d?HRK}FkC>pHB0?& zgpV7M``2lkTc7NGR`NWVS%&5LZ`D3OL{7MI{PVQa)@5h$^N)tSCTE{iP;Uv!Z&Yo= z^Co?_x}(BP%(|t$Sm9n`Ru?;Q_z6d%Mdw?Yh9S?AT!90oCJO~H#^rrXfLd(8pnAiY zL=tgg9R_vl0O<-PE@vpYNQ-a6oEoN!;tSSKl{aoGB|ujC(Gr-a{NdKtWj82;82tUm z7b|B$2Cum{rQ$U%w)(5pP*?i`5R7Mb**HUS3K7{eIelv&{jJQH0I$yt`JRAlaYh)) zIaI5f(jiO%HIrHyuYy~`#*B8qq?YVBHcQ0rKJBKD z97EXy8@AT4V5hB0SCsM_7tCG+l>{hHHVR!RRd3(i`VUVRX%{))vdCmG65mWm?N9VI%T*vQ)(Bfz@83y^xb zps<;vV1Q~~f3iW_TMs{*M_*M)0wCx)){v&<@DHXqD)f0<_ZkHUq#e4V3S$Dsie__` zfxM+p7U;?26LBAxDd$FkC=1xooRop0C- zxuC8j)jw0GB%9^dWgV6f+gI_oqDgOV!iI6Lgcx`LWe(`%vp4wG4eLO^iZ$Lpu|;Jo ziGA{WH)5hL#Iz}2*hNMSr~YH7nGPs6Y$s~mYlBp$jW^O^eD7-nLR zlSb1``g02V7nQ1qSHJ|&CDfI}=(-1*jSl)ND$=0bNNub<0|(2_`U->rFD6+h5IW7| zOvMy;A0_DqMX0&la^tq#q-4MGWeQO@ALY5CCBS%98CsapoQC3u zv(UDH{3woB|3du&=-kSQDoy6cE$Q}k2D2Bh{AKcG$>75x4)~mSqfwFAL2?(Hym`)f zdQQd-w!eDCn<6N6iy{Qevz~RbE)G~VRj-bMAkPWCqMh0D{WUr1Q@{lEKQ*eJF}s<9 zDuV>KG?D-Rlzpu)I_m9*=iPp!Y+m?KL@q#e4hL&4=}7O!fvyynWb2!>(WY+>m^mI- z;a7;1vOl=AgMD{0#M!-r4T(3)ogs%rDJ#0);!FRzU+LZeIYvkiLmXrBgSG2FANTHz ziPH7zj2UIhhu=n*mk3miZ==jL`6T+yknN=F>!167_kdbx`XsLWozUTO9Y4Kssp{=b@saTF> zOl5sABG$95`ey01VExzV`QUP2jH4||)Ai)TbOpJ4!UZ6QVWLOQG_*U1SYLD%pywh+$jILOc}!L^98-*^-$C0GzkRU$ zxxDRvPIQe@<4cbZ0jKq#$ic^uwpQZEo*fIcvbu8z#r@;mAPQtEKQ(o^cY1>Q$Ypf) zIp6vjPfG|K#Y9<}?ra)A*_ajq9>V?Ne>P^#`j(|W3$RMy1PB4wK)oA*{E2Jh^upMc z4)FHqidRClo4SZ|ySy!Q!US)LwlL2$*W-KkAU9(ZApbS@shK*+KlIP+P1bICgH-lB zysnC@4pimYJ(s;s#GF&jLB2aspW-6ENg3-g4j(#nbBQ`Sjd!WS3d0H?|3hoU+i+v- zA!MGj9-DJWqA48U^?CQ|ySll#A8QalK6V`@s-b1l@i-_|os)Btg~VUMQGiQwMV4z> zVku|24;CQ%esw`A3OYEUx3*<2Ex+p><{zM>ly+CwtN9GmFCMdFhwP+k(9L0*(tEFGa`xRX(^RjqN2Dn<0n~P;TzXTr=RmkL> zwr!UQYh^A1h*4Tw-~?crV!_Fv!dx^AA(}>Ed*;dSNGZ8(uU8AC@fxC?_AVX0ew^d# zXDeLIXg2^LVbbp$Hw})iX&+QlDo=fMYEh};f9;5aQKtRr^Ym?L$?+e)h{Xg{7A?}l zXQnOakV&N;V6Gmh?;cU2#DSsF8ENTT3kTNCv;uum>xZ<=1S?;SCh z+Mm{t&xP5RJ^T<*8Ta7s&qZm?`^e`}xbDz{U%=>Z8j0-tE*>^61;)iF+HIdRJFa8D zJ8jGZf2jz|i&-m`& zmQEkp1;vDv@Z+7Y7WbQ^Cx>|P-Bg$QV*UlV8NXORi|@nmk>wY_Im<1Dqgc(7A%786 z16rYF6Yd>AS+2Jl%Tr=Nds?%8bUB>dW1~L50+uOR@JGNBzw7@Ku-xUY))%0l1OPNr zh7AAaEQH;Kz1ge!B5hl!h1J<{FO>+9`aLMjc(+^|zBG-TO0nT~EOFlDqbO*_FZI7Q z>)F!zqT}MVtG&66N)n6~OagJ!Y|QX68T>1GPngnCiJ!i668~Cqsq*IcyHPAeXDEAd znl~L>ca(McR^=Ts6F2!Cm2~v8b#xr`>DaKCaykMn&2F?b-@!so{Gz=3dbhg~Z@4Q@ z?k+&7n{HDxi_mUYe0B8HcX?c%1THL+DZ`ok(hMXm9DF_*iz-q3KagTTgMI0iC^x`0 zjO4snowJ*(D+2xKz(7R%2IU5MM18wp^`)3pe76xB;7f zdI)WgArEuk5AH#EE^IH2XO|JH3JI-S<)2V~02zhBA(SlxIaE8$V={-kNj>{$`hz4j zfwcYUI1h6*+)z{@s%<-v#O!7IGg=2wC^P*t|3q>dxA4=~hxT$m<%Bs#m~@kmQ=>;b z;~JOAOgKf-=pMoRBQyjfp(!ZJ9~{seGNa?osDED(fzD*>(!*etQ)oia3CmxW;_Bzc zpA~mqeNDl+k}LUi&``3O82ELe)LGIFm6}OJ1i}YOKKR#wIDZ?E^A!f&e>RSL2*6`a ziUQS#)cVk+w00*u~JG?eG`T!bLR6!dtgYx_HEAYSj z&#%VSdw+INh!u&6$lGhK9smI5zSs-OHVwPsry5Sb*zLAH}TZ0Vw@eKG(`ln7jBVPgPUtkWg|Z zzc>foZ$_?I^m&6?OXK5dBnJT)1c)Gr+Ml7R26`8)#|&YwG!XlzY0wAMVa2xUAfO^4 z#JpW)xX1qwh;H&~_etB9&`kH0XjBC%UAdTlf|$|YAbQh&v{~H*mSObGhou;;(P~hma7X!1Z{euFAJP|m7BQ-dc+mAA6 z3fGejoba)7SKkqtYTPnO4zo<+ST(O-XVD`{PK0`cFVGU1DgYNA;kG21KkYfuUWpNe zeP#J1pPKs)f-F?t#n;D0wJ5g5rc~GYoPmO=2%pYWqM( zE5N;^?3L2h#SW4Wl-9g+y6bfswTS!MpIZ|Bt27wnoSCYGd%oFT7)bl&03z2_E2KToC zhjy$w;v)C$tcCI&EaLLmBdE!#kcnsfH@UNvMK*4PA6Ksa-!NXo|HlfBxlX^B z>UZmye)K2reMp5zLOWd9`vio5=t64M5dPblw|s2S!N zE`FMaROqW$hz>tOG`3&?Z=EgX$R=NNnUdx46_=(SagLTc@)j*DB8cj~IQFZ;93Ll_ zz97xv0}|x3C`Y85eMu<{lJjomSXK;oTME6uA3k?X7nQUdv|B3>nSfl|zeBN`KKxE) zaba&|whF$uAs)__aIdi*vj+id!H>GDHP9& zIgD)bociW6$tHb0Z??OA&QqT71eqFUZUh>$O}N^VkEXMwC6>ACUdW*a>gP+)J#f=g zAaT8P_9TuMkneQ=!gILaGAe;vz5E@s2zoGbV4i5Juj0PRSOrvo8jXEGw754gd_!nLg z0edz!41*nW*Rn@qy~07gDTqu4Eo(lfCc6G>&Z%J)g~>S=^B)e6a=!5Cau|0yOyy5K zb}W-}9CaF9!UWF$e8<65zGEimBDWSwED%0qbB4Pzt^{rWpz5GJuD5}#^w$8oQ^_R8 zG*=MBCvZ@cr&Zq#tlThMX% z$l#N81>^ynCrA;6`)jX@D;1dEbj$9a*(!)GG6>q{dN%P*5YrbkfY}obCJ+G83LP>e zZ(o;})A&1QMcmH4K?_E-$7?j*tOWMB_v;%aplK^d3KMt&IYM9r7(4ThNq`W=E{K`t z%d?T@E3kE?yZ7l;SL*IK_(u!N6zMEh#}sswTQXScp>)IS54`)>=?fmhqL#sZ_S}zy zuhA$f*Ll%B?VJ9+^i>!B1hy!<&Fx#-YBQLa97b)(!#1h`iXOo&vH(&`OUMG=Far*a zNoy%vLI&m3Fid?^VuA;6FO($IUPT+E?b?<|(-glVCj0Ii@-p*mn*6R30BkVLJS*ho zSqqT{Y!(<@{OQ$m8Wl^g9y0?up6X&MBpDq2uo4ce6==!MZnJc4G#D|bOLLFPr;jp~ z017`B#?D@X@RWfyYA=f%cOK5`kdr0!yUZP)Kv@A8$%9Zlr^vdzF-uf_RgIB-oy+ve z?6}Vt@$d!Y9aUgv07o3o?U;8*OuUmdh{0MHqrpX(1YqfH8iX>%o!eV*S?eT^=ixp_*1C1%iedq~N!_-mBbUp^c(5l8-Rrf2_+A3Jyl+=tUg13%yPUD% zO;}WJlq{tibD-^iGgSAEQykKEf7vyou}xvWJf_xCtTfB+K7G9~8M-~?HrTJ1zLenU-5fla!AmNzK4MquAh)h(yABQo30&r+df!FCEG=bPs`y& zK+37OhVdByRb_CV(_4vCdWo$m_kEXJsEPDjtqLd3;92yGplmbvB*tico^@ z16Y%}xHFCMbE5d@rD;S~Xi(mXYLTnW(&?B@?a6G;8CSiS%s=)s94ARPlB|ZJ^;c=- z-_RuC;)iSQuiuI5GTDhG+Y#6+##CSI8Ne;{pJUn# zEisneP!WkwAi2X|7!+Qm74{d9y9Nmt;g70oBXVb&UaJEBXixvk7IWk7am(QHK6!x` z<6$=q-{mpoKT-M6y2!Ngs+Ifj(%kXiBYyY7j&J+4%^q*6b!B-W~< zzL$f}QNVXgi#`2)8?C@qmX7;PyhOE4L@!BZKFh7ON%DcIX4>hk9osHX_5^rNTq+MCmeN$`LdRRmBNCH=goOti^4Xq- zT{Aj*9tR=$eWVneAoO)&&d>t1+(RF(T1k1uPOhw&HzwSIY%rKk_L`RU?Qj(mSgt9c zJ^+WLd~)@8#9trvD2&5L^6L~v%8d5BXxXOsmr&93&RPrZ+xFGMMUfEn{_o<$m$}Qu zKLcY2A{L`eY9I@b!X&W>aNH6ad(HaM7)gmFiP7cA00O%Y;%P7$6Oh|xyHppnlVNZL zCSWzOb>|7ZeR@s(=ZjR786{VPVU$v|Eo$q}0>uJTHr$bb$td-@O2vp# zS!owofCX4hEa3w&Jnw>}?Pg9G*hBIWPVISw5?p#47$B~(OBV1G%EMl+*Z@TgZ4xBY z*U=351aA#DC!e^&UCZotK26yLh2KD5MBkD=We>KIb5qft4V=7baAEQ}gZkf;J-F01r{k-*Y z>d$AJV3=skFzr2W*jD^9!*!H<(65lA8GF+bj}C4iHdJApoP^RXa zw9Jkd*VYGwZC*%`!=HUrk6e?$G$9D zUZ5&g;+GO@TJ`u_sx0_LtJ8vx>SuRgg!Xt4jW2Vr%X`>2Pi0D8?s;@>WyNGVCML(J zVjfi==s{FjNo6F7UZZ(|CO-7Lc2Zr@&mX@h51u6VV^ypn*M zC`Q)ye^`Q<(AB46IsxMap?JZkVn3kvR(zicL-jiMR44;KjU7ydF#pYt+p>bVJgZN2 z6m_LE1LFNrIV0h8!+RJ=7Yxtcv=A46@c^`oTdPv;>byZd>8X5uZjoD(gp=F6F(sbF zF&)#~zjBRsL>xA*FSjHno(&_^=t1PU^RRdl2nIeadtl3>i!3!00y5(mbCW22!}KT- zrT2lf8x1=|r7tkjNy0x>!iAH zXA$aB#;GZF&)0w1t#~eK)o1^TUQiF_uexnVOS8<07eZ1kDZ9o~7Yu?wFlLdV-NJa_ z!$i?+5%xhT0ZuN)ln^F(;N^Q|7GbN@3z!gT-u)~_C-S~#cQbIA;ns2g;AKHC^f^UB`t%)c4hM0(gy@oC zGSfSybxRK+2blSaE112^lH94jcdoBB*~K1)Lx6D0--8$%s{!Mij<$}%l;?rx%~5F;F;9|?4Mm>+B{qd{s}Moi zUM1XINDV+jvV0>{~<2=**hgBTi^#$%Ol8xis z9>U0Z=5E0iz9oD?gkX}y%dLW5^SoFAw{#;}J`0TyFtHGJ&b(;_rqA+#x$fqFb~F=L zFYN8jE%QW-vw@rJuDnKq$W9AUSA$D@lVfb1^x$Qa&g*Lb5Lpi*icu`bG&VvLmku>l z3F)8_NnjwpN>@Y~M*wx^OPMufNn~Ycy)ovI3c`)Mve)xs2ch?lS@Wm4On)?evKur4 ztdL)5Lt}tTavC&~h(NaQ-Z9^r67k}SGj_kk*zz-%N=m(5dvtbzqpVJA(<|^YAs0CF z8WdPQvo^qx-AcuC`aHcL>%~NcK(>7c$~pD=d#g#I-PoBx>O8)1*)X3vQDEeXM{B11 zah7y6=s$s>Nn|zTn@TY>#VG4CppuuvSuErlR8>rr9ylGQRzdmec_nwXI8DLUF>0Qu z88y;nF2+G%McA8Rh3pk3P;@9Ws~b_hk`I>BgL|Go+g`*jvF}{4U}%xs)Nl`TRu;vD z(h*2P4QUE5Uv-ztZEHLFFB@(}uRuzkk^7pfN^m{o-C6)uZ#qB;Ilm3wa)Dw7A~leQ z9a}q|H%yM-v>%8YwYCgDZ-17?4R!EssB)sYAI|D)-MSC6;sYXr^M;MI`Sl!CP;Ex8 zg}{LrV3*;$7PCyTabu@ilTZ&v0R6^yrLYp5Sy{@v6A6c*D?!2gm97;8J^zPkWHbUn zTv+A8REIxp@~~!pa#JUYTp{;HmwjN0#ez9HOd*VDa?l{S&@$oVT133eU8NV|VJ5-_ z4KgU5(2fUafBEH)GK6f|4`qlRb z{E~{qZk`sXf-oC(mh#!+VBvzW#I6+HughUn*{&5lfwA?>8B{N+I&3JclCv(46ZJ5m z5SBLjFgn8?1of!Yi^#4Zv<_-d5K{?IP;Y@9J%@n+J)WiEyR_$v5F=>1Rs~JJ{CPV( zB{+|=xoVXk$wF^$zIoV3hJ2}9HKmXVTEE1P=?HfrO=xU&$|?XpCalMY{W2R-eutv~ zvHb31_AWnlT&661EBuzIocdA;9Rk`+wEpF=+m7E#z!^x6dJzAJuv} z6bIPSQ`ro6;{MSZihEN_cbxD1aUHfuAM;-f9ltiUxaK(k#x&(_NORESGaKWy_-=dO z`BIw8&y<;*7fJf<2T+q1J(z<7!U`_dd5dZOn1q71%V?B{*3F8dmEvcpQW~#kQdhu6 z7+JjMGC?Cd6?!D(j^m2BCbd=~Azg}kI3s2#yb5(CGvo+lB&tC#qd=REQHv|%STfL= z4|QJY1S&B8@G8Jp=tQ;a?@FrilNzXGWVgHJl&2AJ0I|?;oBfU(Y}e2#Zpz$ zN*gUjP=MMeOtnP?XN-_-#S*?W0IfPu(b0CDo#rplxdX$8Zv-$J#)s83#M;FIu`&=0(6!5=X4N$W_S&Rqd^PEheZXg3ZRrT zzbbc+Ykm^&)Q3E|5)0a5ZB!+V;44(q&&d&^Q$5IdV2_qS#LzjF@hzo7*a`bq@Lhvj z`r>fED#-#_tlTNW?`)*t>Qrt3WJ9e*1;Ra(9N$q58PgOAh~oehxCLmD@Oh@;tI&e+ zLJLe~YX)!BX7DB1=lfPjeRJL$*-|=pxEx=@`0h(B&SM)ZJpKxr+>VgWZ+z))-R44$)@N3Z&EZP1e^tKBjKNKlYkp*>YL%tP@ge+ycJ=y2Pr?;w? zPt?*x(aEQ;6huu|Xq=l^=p!8Pb4`h;3>NAHc2bq3&*IIZhn!=GM!{O{>8^E_DJ8Lj z^Z@P#E4!qLT8oL2^xaD`#Xm^YB#f!6`w( z87eF0__d@p#=%{SUI5V(hRQO^>S6rvALIkJ*Ss1CqMo7#ezhzFDHVy4x9zx1v$6pI z!U}k!DH^vy_zf7@>#5A5JqNw0YZ~CL`(Ob_Et_7*;3Y&roKpC76VYSvJCgjnQqY1Q zzXsxTt3?xWW-#nQutRs#ReD2N`qDV;hxUcgWt6NBRj2rX?416(3QRMpg(SMa;_tcv zn>*XeD2-(H$MBgM{X4KtfS^|HiC@WJOk0nUn?tHs7_Kyv(~(NSX7i$al79N)75i-A z%Q1s_;EVxKd@b4rI$@qwvsNxc-#n(iw!8}?H~3RO3V}0(#>xh4`jRk~sv$0X{-OwA zonL5aDedwWKr}LdDH)vPHn5+yA(tV9?%!eE9^{OA4C#zErdgW4&jw3KV?}e_^i@Lx<}_qjX4g z;B9N46CX&~VTv70#SDZmeW!biW2=uDXuHbh_h`8EcOV2S6uim;4E>fQ^;fFvR|)v7 z`pROLK-gd@J7Imdm?(4{l$p`26x0fg3(G}n(km&Zz99cc1sb6}h4ssg3*R{A25p*n z&=P!c+S0ad7pyuz!5)`i5jYcEiMab(b|ODuXRW<6jz3(f6<{CJaOZC3l_++%QV430&dC)-g7x%xXl zC*CPqupxP|2^R=Ls6P%4tp;A{_s8(QFr}b&J~WD*o-tvXqkd130Dxi;yBekyzW#V| zUiHf)@>r)l9pm>wEpo|Tu+rq%RCz+1NLc{>W=q3DQ%d*#qPap-?=A$#a=hJXiy0V|@` z1IqJ+8iWXf6(>{YvQW_z;i*%jj09J1dT793Pw64dD&4MlMhFInHD_M9k@$3TI|{*p ztFcgd1=TR~Ejo+*(ED>Bz7#90vVX_x5h07p@gi58-^cMp>j}xIQ{)b0PgS`X@5a*9 zK6TTi#7_mAilLV+rQ`@q>bV-}yf!8*T&Iw+^E#As%ll4E1h-HwQ!2-v7r87YEZ9H3 zo%8j<^x>lus&Rc^R|4Dgwqn!gVzb9cMf>0h3*&?Ma>NU#5=k6g&*V=}S>3gC?P8Pg zB7E}d=bMxJft*0dwb7zD*Wt2A*(Y`g3$GztgJUbbeoK9<1roKx@%HvBGvrd;L;^}C z=1dF!{{76VN9pljS^Ix^hEr?j_pi|nVTec;weMT-;Og*r3zIYQRyXI`RBt`Gz_jH- z1Zze?k&XtbNLz#S*W*E=s$khLnIc03Qn4?X0sn0e{9}MIU&<2Z;@OwVYO52UJaTMK zVeRgrR05KUD@wPVvi}QmjjQyF?2cu+k}_O;7o%ss741Z6gbe_#P!i-2;0qwgoJZsL z`fOqH8-h~^AMzpY3vvb4HNCOB+$!6!cj&k4O_5(e=Ks8#PjmlxtIi(#6m|ytmpA5J zb*x<})Ul(BH7=Gsk>@BnM6p18kXimn8!J2wj_RF2FxL%YT!8sx0S!kD(CGO^D0SX?=h(_fQDLZ3K|jfD z-p|T7vW$X~EB%GRYRF=u*f+N^bJ0C3)8SPkENUoXb_9W4*>A_1OOImij-$wdaOt~p z)3GQz-X)@(w}qd8H#s9*=E`{KV>!>^oyTsgM<@1^g}azI>V}V<9JNz`6%-zXwxSS7IN!mDllY}R z#S2p*?{||Oh+-YQ2AkCC{Ncf{6D=p#+f@cy5mIzHir(N)=yJ2%)G8LpxjmOO^|B=~ ziN>%H!<&pJKY||EO8?Y#zwozy>e)?g;k=nj{imTcBTX+v)~l8YHNlSf_iGv1OJDi{*HyjDNU zd1pdpDJ!a}cC@XFHA3=1mlgJAz>!XgH}t$G>tZ;!-2d(94HK^YP8k$!qtW#chfJ6g8DBw=2oP|g~?RaP9x28$w8Dw-nf36!=eIZr06Ez zDg0w*HA~qZx5YGo2JvV9vK!3#EulveX@f#kCbCPL{#~+z*P#XLWt?2LKOC%Aa1x?4 z=FMuGY&=%*nn4f~Bg&P-bw@##6p{#lt{CV~aKXu!e@+cdvpIcz8GcJddtoP)LyH-*i2xuCBS#tvQs zO6-{^yEd-=(`8}3C}tnbrVfX0KizwVNR$GohAtE9{}EmsuaH@UP!7^Yx!znf3lJ6O z%95NpUcykjb?Zcif{&_K#I;c5T<(19w)&}V@pAd*4j4zx+f!g@86BPM>-SGtNRO)# zrR8N-IqpNzidoUFqN1U(g_zKVfQ-H-o2f7*IFoNk^kZf!o>DZbVeQ%_mgKIRcEoL5 zeQW0wv;53rhh?*%&OVOF`!(=N%r_^8Bq5aY7_V;Rs{2WT^oihQ9CbJqoRE6<>Z1W;LUYPiRjHgSb(`aDl>!8Y2p`zw;F zMDSRBd$5!KF83xD32sfnO6xGE_&tYxB^H!XpLKtr;C(-syB{hu(ooq{&1oQPi@M*n zN$`o1D;Ge6v%LK$yfQ|R&dEp~TM-HC$IfP;nUzR2i4tIC9y&1_bqqxyYU7SVK^^td zP1I56^r@7a`GQmujabBX;w+_4BJbA>^R}0Z7RsGL<#Fcu+-|&{@Vi!;{os_(-p!nqj&5Npc0QY0l|gPz2DgP~Uus zN^(Z;OIgzfb2CTc4+uaA7<@H{)!`bMe7e z+T)dM3AQIt_*Jz|i-NI#j*A37y=FQ2NI)fY?>?=}E`*!fysx150(0d;UCXuUo0_th zo{jI0z9aB#tfgn^h9kD}`FmaJ zgsWHlT(D}kT8~}V_Ki;4)At)r=yBY6-0oc>%C5o5>$-*i>5ARObMX(%&P0YKW`FTg zut??$U~zs%1$_owl6O^7th#ch@M*CQSwzu^#>7bY+i$UoGF9SSDlB&;-dY7xT+E+F zdIoJ9eAys305XUo6|UTm)VXw(rCO3~H-}!}ylUXmsk($85nLOHlxOr9jluLvmyM4R zG%Uhh@_W0VIZ-c+ld$+)Bf?w>rYZQCvCBL*?|RDBgr-{Lbo;8I;ktyrr%0P+4*+% zhDzd-{O55{M2a;E3|+WT@- zj00OU&EI77jgCtNQdbn_bAtFZ1QOHdO3mu9H!pexUoRn!56+c{XW82Xerk7Cu9`b- zsWOo0nLc=HN4+#Tzq4m0rn29jKk!+=Y!jEM_KQzvow572uO|f{5ieF4w zMNpgdmg|};{p{}7r+;l4XCs7b9naDidEE*Kzxa8gS$ef_R(M1D&zTbb*6*KYHN>`Z z(41zsE=q8P&GJ3Ww6Tl%~6>QN8KMU7RhWl51_dRl2&T*o@xDx*Amu~r!9aqb!#r;uqq}`7@ z=w~tRyWW@BhVfPp;O1Qq339Y^IgcyKCl*L!&z?Mbsp7kRtYUE7P!FH|@PMqbPCm8f z*Y(z0ic8ID_oq+y8-@>Fd+FO*mMr1@^MqWiV#u-dim_42JAzfO@5FsjP&(@9FKT+0 zuSMtR_(#^cOCJoXTr?wlhe~hP#!OS{wH6PZtxhEv%BAVCiFXYCsO(qiN{(ZHb3@zk zQ(k9zl16C62`#%ok<2)~_b&BrUn#qtBPh$1$JDHEZA>}cRyb-yTY6d&(dW&Dh( z7ne+VWj^<@`4h0$KaPkjvr8*j-KWjGA2cgGu&La*D)_Rd;Y!X{Cz;Pz1Irq1$`U{H zMosj5n@zna!)0&&IvD?VXC@~9ePk=ggZSXADmfpv>r(ri&smr5C44j>J|H7g=;x-SQgk}ha@pI!NF^L=J*y|__?kp`?9__ z>3uJB=B8b^xvi)$vBga4Np4}5p7e9rKqa;8WJfZ40`^WpxZ^1Ka%pm-X)|uFyX|wMyl1aVg!bq4*Pv;Z&ywrb=|Ch7;JW)4Ak)*~1!ij^@3cYqR*2R$y4fe0 zzk2d}bjjiZ7OEEK&7TbK5%l+T8VheuwIDtuvQp3gz31F~lF5PPpp+srLHSxv$Fj}| zV!8iD^7(mf3#o@Z23glzKH@B2pMYZ^GstibIbqS zNHbnJ%iVCw!r_8(cFXYD&HIm8yf6Iw0a;x104tv_$+c>#AjWCC2P?C@-oppJqUUUL z6|TuPnyqg6Wxb@N8$m1&ew>d*&$ex;iHi?K)I#?E|AXf_X?Zk_H~*j`=4>nT0HQQ_j@R>A4^@3r(T!1;=b1Y zsD7sfn%yZZ>pyKhmxu>k{Mr_o+{On5Fv5rOCAK?K*mQ{cUmsHbdMbTW=dp{8>ANlw zZvEZw@2o{)_t#S;kCXQeBLU7Odd3)R3IK;LpN5Ba2seLxD80F#q z$k%H2LtW~jkLbw5b^P=i^m1x!g(~Uru_E>AGB#q2^w## z7{@zZS?MyF$M#K|+&bsDS>_Cf|Fa%~V2mlzthBC?Jh!sXZBNH85nP{ou%=OKPefY7 z?RopD6%)+^S!7k;&Q9Wk5xhgU+0ji#Nuz{%VPh$~C$}HM;y&G-YV&I-Z(U6Jbd0 z$K<>j*M1H#W=c$R4?nq(l|m}pFIQSOw7{m%`{2#=F+3i>JNioXz`$NH#?ZdKTs|)t z93(BwY`sPEiuCYO()o9^k-X050mu<`RA1+KaorpZwU4ea`F=xR|4^lVPWR}GP`{tZ8B~e+_wLT1;)f1mJz;g(6t~wbIEkg${-nkdbi!dmULu)_Z=lXM`{_9_vQ*Ew>@>&Q+^7n*Cwy4-#jqK>x-TR|) zVj%Q}UEl$K+bi9rM3w1*#YG;yVe!qwp)YWQCX-TjdGqG`4{SYhdswLSd4%AU@RJS+ zyQ-@9+|v}@^rPx2Y_jLYi8DdQN;0`j6@z2%`t37MkH0%rdqa>q=HtAg6@uKbgKWAJSzVU!Qce|iW`AXeD z=8Fw<#QCC)bDA&rY{m2T1i#hC|7JwUxzJCFlnESks{O%N8F46axI5Ma{--pV)^06V zm)SnY=de+_G+B^2b$QC?Auc80RH8S&sv_g8*w$_86*ASdLTCR-I8EyN&oZMlr1{kF ze~&`{i%%sd{&N&c-IDdjsQt|M0Dk|5aGSS}iJcrPIFjm^+YOpsrKLN z8gEPwz1Yp2zO-A%OM!p`XjRj6io88if(t9^rm;O-BC+)!zfai?{Z2g*0dcT5Jx#~` zu(Nxl><*Vn-ygUBP#yd{A`TOn_}O1rf;WDVv(M<)fqs>#-5WvPfoFff7po)gk8pXP|T7pU*nN66NW+Mr#U z+}dirdoXpMx~$9W-GXxal)$r9W)-Y+fRM9=w3G4A8v*tH^tq7g)PC4+R1?eN7DUwO zGf`|c>)JZ(t}95d5dh#06$rbAR(~aobrzy4x(=Q*qE3*HJQ&@L4i@H6#SfYwV&7qL zQ|%%%zrXG4o*sOO4bo@EUMjBJs#IIhu2!6!Tzjmjo%TYMTEFQV`)5^CHVN9k3Ov?e zT;%dqd;oW4LfU*w%HAmvAB=nqu|e9zI?X0V(y!pgE3tap;<~RYs}l; ziU+q6+D9)K2yfVUYVytSo@`CyfkhYWKR0BY?Q+jwK0iteR@KP39M?37c>PbR*u*i6^Az>*(nTIs!!;9{KtY38a|H~fu5@>R^t0{3ip;gJ_6 zdmQ%Ssh%@22x4gK26Ht@esIoFr!Z?p%n`5huGQxNbGj;L0hdJg(ImS(z435{_5$mQ z-Iew(rIzV(F?lxfM`OM-iOnj$b!mQ3T*D(``dl&8xc!)!>8wV2(*gfyEf#MA*FCon zWbZykw&>J9^B`@a(4tzR zF7L*WvEdj#n_QdV=>+-Auf>g((x+K3?X$i7yVW#{Z#Z&t5p z6RcbgDF57lkn=*vf-YmU^vs59?-DPHTe9+m9k(ACd8e*&L|Ar5#Jyzy9gq1GS%_Zq z#5cO--%U64OcK&1K2Hgld4B3nzs}y_eAO;zE89}w4ZHJhSpaa3nXTVBEParGAcZ)?M354a9kGGr;1JS`Lzp*{G zU=DXVzpgW0`@=?}({CQbx*gvvKbL|F{HQO=KM}_>w?_RO{1Q)IR+E?spNjMczd_IE zOZKeczMuXKlJPq|7^Em47Y=i$@8;a^MN$eIJYfJX_3ouUx~tv5!QA3J-54<)*MDVp z|1hBGst)ZUsqf|?foFwBU)$u!-g6r84A;?&e^#eq%Cnx;V5>ZHn)UcG$Ga=#x3=X6 zYRy+yk%cSY`b)BW`{e6-J8mj3=^@3O$U2g8u_Z`Nx97^{1AqOBi>|U>toP-=?4m7` zeZz;9zF-G`r1dclnAn*6Un7ej#CJ~{X+nlVRoHPxT^~&Ir=a%7t|H+LJ-`Z8SJ+BR zq+XJG{*-9PD6;``(BROSf8)?=nTYRskVB}eXO0#^Y;|XSEHG;BI z55MT0Y6HY}*y-6V|C8!HdZOA(IQ9&`A?aylS+9I?Y_wkQ#aczp!`_CFDekzvO7|qc zy?fqXF0~!U-1O0~cIko22b04I2Ia2PPPe=wJ&Sam^6mkM`1(c%=>+M`U zZ|@agTJJ*t8lNL`7Fg!b>A1w!HHhy1D`4v9djF{;BNQYt9>MiXhv`51+)_kI+pxKU zqpBf#TiRsX#lP&_-r&MbJ$kyfl(|PtNA^3>R<3YdP3%r?{l`xGW~K|agHKGlSd-W2 zN;>hq{h*PA;Ea2ch$)I!8pWnC>Ix)}f^WrPuB&p!1;}GHBI5 z{&%m`iG2ER6<>uZ*pAj2Qx^CBLiKyNHroS{_{xhp(SaYG`CBj6{MN2dEiF9bzHF~z z!i4v(6N%nV4c^Ii7{%eK6IvmXH(S>>a|otp_pVO`Kz(Ki}W=*X!oi>zs2vujlhI z?&ERI{l8Hj{9JqU@eU%{%pee-|2smM zVOgb?W}-(aZxjNxpoHP^MJ}9t`)tUZ@YnWGgFH}F6IegjfwOI0an#x5fRjD$1>0mS z?CA?vryfB#Sth7N#z!!5zi!>QR{SxhWbH72lO#ebCy?2j6TLaMpPA zr9=Bq{vT^wjbBG=W%LkwxlVL}w^NYq#vShq{NS@-u!|D0F^8kkOG1lJA>SjosPUo7 zBzu1$;LAz{7x=?-YQKJ{nFaq9kx@|4QmS`Ve_i9g;?t`pa}>cgebFv3xet{hmM~`; zt+_}JnymHMV-5HPUP3`O?9^JPLYl_y)70nQl!9^5$kh#nYNmf@#a*a1HC_VLx*I46 zq44nh-?s5ch)rb@{r1A8ZXJR4chZ-%PLD$m7#E%8^W{G#wT%ik7GZ#t*f#w+Gcq2W z_d^u^`)gB)g7=(kFCm_>T}wHf2=OGSdwQcRtmU@^!uVr~e(p8e+q> ze@^#CKHeJ!o0*mR{0CyPn)y7;_Ni0W(#uqIYb=*?=KcYDJz7xl)N+DuOp3uH~-nN^Q%k6r26EAtpgP});vCmSg*OH2~)ShRsn@hNRE68)P3K|Cr7B9+QR zvqwZ@3LEg#2XaKk&k^#8^ z%6(Z%IrWyM03dZ`+ckufEw2e2_>ezyQ|_#l0!R_TdaJJuMy&VKTxatXmCJV{5(436 z!Mg;!DlbL<9)P}e4fL%=Bh(}Wyk7$S2QL#?_{U$#C@-{4$}Cu9aR2r_u9LZxQw(E% zK;G;v`{x{XgnnNCxZ7(6u}pA3Jc2+T!|M`r)Ty4g-NuzbnOnv{ql|I8ZUeTLd$l}0 zzr~;;t#-LOZDas5*ZnsW_is;{f;MA`2xr9m)Fca|?nVw+c2tyTm71BIW_sv`RRF`& z>m;qaWsQa!DeCvpBj=z@Ur_?b}kwP%2<9e zbCP)E8FUSOzpwA*9Lm6X4-(R+#vxjScfoD$j?>e(1{i9j7@^3rmq;IuX^sUg4rXz} zS*3F>z^GXP7&_x49qnhSy5`lH)M#|ttoZ&GVQn1x_&{giQA81lD$r*?r_BeIHF)BT zP&IhoC&CQ>pFUCW(s>~$r~zOzySVHiF4++A$buI+_2U0M@TD98ogNldPVEgQ40z-~ z+#lXcJ6GML|2^?i4u&R)KnBFDT(_yJ87EJlvv_|<1d>HHWwe_*g@817YjvrkX@bOt%7id8zZ&PJ*&~Sj)^AK~L2IS(R@lbGCw7 zV#{rxNiJZOWfo&OzHdNVTbNg#rW)u*VXV%J!^@im1ODQI)|tYMzFj6lLJx(PF~>Wm zkul^+MyL_BvHP8?IiRBHajjv#qsG$G7@)y&tt$yCl8?khS~A^+n9anbwxcj~nAvw; z@!Xo7wL+{7Lm!#Iijw@dqRESSL%t50KSk%x`cC&(1YAk4vX2+0Zh;;WJRX3&lAWl4 z&jd*@709I!i zk(Azce2=-WYG$`V_blb3eFwANAM1+!uauva3~W4atG2OFIS`a9)KuWbXnZcKFKgY+ z)M-e(cV#)mD-W^Zvgs@n6?ci5L*0{-0zcAtM9t65ehea+R|hZ9&_Mzvkl}Aa-BUR_ zXT20effwc{L!483jrGh^G)G2u2gUa;FNXw6CmfTf_n`8%Dbm-5IzdeTvg0j@RNwU` zKbf`n6OYVrkL~`66c4EVg7Y1Tul5tW-#zx0>3;`J9y#z9p#7&W7l6L<@72X)d3u%1 zkg$sSvl@H!9Ph!`1xT}iVUQ`wLP0Vv2oLkmPX|(&a3Vz z9L^pDH=<2{8U&{<5Wx1bx94S474-V@6T|~Ox58US*r6IlL!r}ZfP(j-HfqmERiS+3 zs}EF-fW(q#D~5NM%1L|ob*bYeHgGyV{+XL&A)#{8(_0VlnD5#g^v&3Av%iX7AxuZ? zX6QjOJ)vHMd{TPuoY%RMjB&3Y;I38Dk8ySeurPtK9XmE4JoA5i&_Ub=0LPlVtaD7@ zzMPXt$_7FPz+z9)YG(@$gW2>hne}z@(Hm(w4>>?Hbzt~y{}$k4@3o6uDq*DbH;zE> zlehIt#O+GWEI=ONcb8=w@s{MKUlEikmuYq$lrcS0&(pvroO#MV$;Pl=V9ED_Qv&u5m zOL@xt*gmi3MyfPJ;P+PhP@xR>(CyOB$YqLHYvf@N8~<2~jR4HuqSvdV&npa~aP|gW z)8*Y7%2_zg`jgh5bXyg^0yxRt1v8OT1sn|jU9Uv`Qh&vLP$h0Ipn+KV^qPGwFnSMk z`CcncY^N|FHb1n;;KJ4|C{%Wws7`ITb`kLXUEc|@?-!?0N8{vkD*()O_c0NIn7dbk zS*fWbbR>^%o&a`3dO=R$^K#yu=B4WzViE*3naUGxjh9&eU=Da_II}ThKPFGJ84Q*% zne}AgWNNB9BKBYe;O->ces`7;wAQ)DEhLrAzGO5kqt=Z zrU~pm;Dld2zy02wHlPcZ=H*?K zi|lC(0C$Bi4)%yV+9wqvuFf{S#=mFo0d4xH^<@U{x~@28WY#@G4i9Fba#m{6lY2NV}y723ZGdQ z`v7y}vNtD*+i(6iW`7`D?DxW6$)gu{oEk&tNy^!|xkX+1xr8tSDmMDch)gYB4t1sk zirjqr_lto|`cbYyf_3l*$xkoxuv=zF9RE$499lI47qM3Wqfw=l#zMfR9EVSsoHYJ-)o6YWBc= zMX1XOxZ>1#tAs6im@|4gJF6=n1Mme&WsUh*@(b7xuFs9rTZ|jHI{si4aZ9}>kv~I9 zA3kBevAF5-%6N!wYe(5@u4lFMw3iOP55M%8k)Gk_A)ou-Bwf1(uQA&;nOOX@W|w-f z+;K93GBOqO`8YN!dV0iP_1c@H2RUPCydN1Y&B@vPs3cfO}}b@qUz*`u@a*IiuxqyfR;G|l#oS1s{hNkDQ9 zB0ZUwq;i=WLG;Gs6vOuy zWZ*t8ff%KkWfqlbbbM@hLQg=kzZGzb5vZma(IkP6CZKmcysD_mJIySlKp9T){S;_$ z7qYC;A3&+-r?7~Wo{`c)NvVdo2aW)l*f{b+Ob%DCsh`nqgho+#%|dHy;qvgO6;yr8 zA&yQ5lO#H8T<^8crSZ}4Mks~A zf?p|8pC8B*`*xJ?<$;KlV1yw8GqEZ!mi!mNJwbq)8XtrrJVZ@^%UvhXp~ugN>}<62a`%_>W&g;ZJRc_!I@N zZaPQ7t66#9n6b*BQZHVy2o2qvnRX{}Top7eGs!?dv_>8u{oS`g^n+>{c0tc$*{+2d zZku743Uz3*I?4-OeoripA2El2k<2`JMDtqS`}X`j*m6!zFa%K7Ek8>*t#M%_5~rYG z5U&W3{cT4jEZ`0!t2{5k@Y9W#I$I~YpA2blmN>iS)kYjHDz?8HvibX+{2{li;}Cj? zA8GNnSNjbru(akvxzrdVQ1+Q8n`W5@0-9i6^=)YrP?L~cw7tcd|0cIPL zP!)cy>ZruZnsZN}gV-Nre+=rsC94Mdg{iuMMViwUT#v8Y-}0^E&e(mCW-w_H7v_7F z%Cb}+&@{fCcgoS})5oja&Cc&jHsY?sNYY07>7W|Hc1bJnA4>aqAWiBf0&HP$T?DVO z;sNZ3I|0-4JyoYAm6?O>4TPNtsE}625B%dq3L)I~wc(~>k_53s1ck~VTNQmp-pz8?}hRH=mtS3cdyg=l&@vfR8Tqr5~=Qq%nNzd#{mbcReayJ~?p zc^X}N8-CsGRQK{_bkAy3)SlZsi55=Llp8Owjd4vq%$Xi#sP{kgrT;(OGW)zy)M&tY z51yEOCQH*iHm~?U&2k%=)>@9a`SpMi4)+68rIt3H{ox(=ui=0|4(KS>T5WIthZla1 z_g-0hrfJ|zzBs+@FYb>_#RK?fJKd3Im z3PD`{U)P-=dwDr-OgqOYAp@BpU0PO(UiPLMk707-a#}z93u0E2-E@TF@#H%=*-MeW z?l9)Sx_z$C2Cv(-L3r8xCQC=v0b6Z0$ePV;p#o!g;HX|BCLDMmR2xwqtAbE9G@-DtQ{+JK`9xL5A!d z5xfta_w8;9FM|pN`xh!=EYXBsQun>@zYtWewoH+?^*$5`rkD?xG{4x7?rZymxAcZ^ z0J8CW)$qZV{P>@Tv6`_Bd^As$@}4|#_U>3=*&nsy)n{bmXtqr(oNUc&oeLf3lfR@z zbjAm01pZ&78cWOaMBDrHfAL@?%26+M`~>kP7wrhDRjXwfOpJSJLbysQsq{+*UDt~^ z9LxXsxKq5$YbgcdO26ot0>k4Jk{7snJIB(O%&!yO*kx4kUYK+s>74n zcT*L_f!jrHu-UYML&kUwrX8D!4U7R;SS*42XE^#^AP#QY-|ASh6H_c~#jmgl76ERh zfGae*_9AA{(g9ameWm`;U@1ywkH#f8t|wh#C{Pp+jGnnoP)6M)pkHLNCaP+(LVBnY z^>VV3xUePqQeF=rHv0CsW?tx?eS=ONl4NYrv8efn6VV;$ z(;P#Lk+N8sCKN4he6TFcQmEYeAcE;^rmLX)g*;B_Sylgb3#e8VNnUy`^?sbPboBqxRBQ@@rje2o91% zLAM#^L|3n_E`-N(HTh@i*4re3zX49uzx=eSTzN|5dj{Z>ZLCRGiF23*s1bs8COhUq zp{RIug7p`9FD1K#V5~@swpGtd@se47&v{M{2nnfI7aK%3iMFj$&5beIus=Z?T`2?d zK|m9cF!;5%i|U)ZHP4BXWS17o@bFdyC?Q{s1`--{4?W#;%2-;Q-U=o{%&LM=p4rZX zn2q7;;+6#`*^tJ{Fv$kPNyjJ|FiJ-FRFrXK^khx@&hRq$@x`ESKXUGHh>Tf2fa@mI zg&&KIt;zJoP;TY|8FR4_X9saJ^cnx{*y6l1@>$|{+1dgm%mTDn>;c)5hc-q7=Vbg! z^U2g2l)Ed-Z-b1T%e>V!Bl?$FgLLFCQt1f~zf2A(1H+cSRp6()?};v z@sd$WtKpe|^5kq%6Ra9P?VCFe4t~z3M+VG^W`XH_t4Flr`_1nV9_|v6k6QE5Bm^mW zC4%0MXT$NL&|Fcvq5nW0ypSu6w(tJvRr98_OM}(>kc#o!2MiV@gfQ{8C(J+V@@W7@saeoZmn4Y3xcA$g2Gx2d>|J*L~_ z-=ycYFv4wQL{=49JADz2Xx87R?>okCO|^Lnw296=kyk)BRrDs)!mU|on3PIcG`rd7 zc!pQH$NI92uswkCb91f8sP%VG+gN3dU(qrRB{GRi)vO5udO-K4?JkDejr!uHMy#=QTi)q zT+cbnd(2b4%{=*}BeT}gV;NQq5xEedtIKQs@-&|w{d*}i|EmcY5&o-t7l>|CYuy=w zYQwjzJGfXrAD6v?k{V$bnMADHV=eFrJ{(_gce||=_HPkiOnlym%!8y35J5k`z2sLF zo(_&qwbRNSmb-7#jvvI6Nr41K5V#dqdV?s(M)dfG?T{ghO8o*)8K0Y(=CLCjM+WTB zg?9{y={WD^$iUFRi4CJv+6R(?&M|Q%;h}-da!K$L<~zgX*Mn=g@a`nvWh?WT|8u0h zSw1GaNOpGy+W7tPJThr|K0FN$QWQqLGdq-ry=-madQ`yR(V_&cqE7bzR?&D!-83e7 z7*fwdget_~y16O4smHGOGUj}G&uGWBZ{JCFq1+Pxv6~T{{?+PObM6%v(tayQjUY3%H!@m1zk@adwQTP~rr_D`y@Ers~V4wkX zVfke40Z{gUe8_IRXa?-T3SuyW7^i;)+5lXt(dxb_nJtsA?f+nlMW)osF6NEOq4C7H&axiffQ zNbHPCff0hyKiCGB*$rC-;X9EygYEGTxr6Rsp92FwMkOTzHQ>S|#)aO8J=?fp(IG#? zV1EVb&YlD4_w|2imp=rdvLUgd@>L*@iq%6RPx(Ol{P3}EL-xu>LR**ib^G@nrY}28 zV`S>56%{*TkG!~lB-uz#O!Gy4i$oe7BjaZl=5Rysspz*1+gX{}A24ieCT54L?{hm5{2g6+ROgVU=l7y8u|;Ngt?S5W$Kq=eavpXtx1^@x|DB2E9*+_I_ly;v%Aqc+CAjJ~?<+DDOvII{k-``>k`G z#Q9A8HdPrWQpAtL`-Tvcfl68kHgExSBEqLHMXtvlba>`V~*NQ97$wJZ(m6+Ar z$;lGPf)|}HTL3#5yL@s9T^4uBI8yGgfOj0B;&9+{FHtI2UE-S$BLIMs7WDMgspI&2 zWMpKFU+EM@=|M|N0y~J-5ntnRyL=CAC}LL9ptL((m5Zk+;fIRY*k;(T&*r{nq#_#Jg0J zi(9r+Lm~GE$Q069|cn^9&D`rr7*M@f7r40C(;l?#(t@b#XEeJ95?vThQ~dPW1}LL+Z`PUAhVv z<*I-KTa8+BX|_yf_WI1=S$7ODnV&!7Gs1gL%9VljWBx3Y@5us}5Txguk92!KGVF`* z6yE*=#0OC6OMz;sEB~*;ahpwdUeW7LSanG;si*adEEU(q2yp7%bI!rqzgQbQ4toEQ zeFtS3Z$AMgJm4U!D&7T-hJ~7WpfHW8yariQM$!^8eet+4K+0!;wXED$UbDeF2r!?u z8~gTvy*w(vDem}g041H*J;~fQZBS?a>g}UfmBu;B{`mnST)DBMWYV1uSS!xKrpJ-l$J%E%vhD(v2DE8QdCud5)`{F`ftE( zIu)pUqNh;LD;mQs;o0ZE6!uZ&_mBJByR(R?>65dl8;wIQjTzf|!h>MAwWU$}5Xz*a-$O-BgJc=jofiXuG+=wMeto2F2%4*Vogk!lsAJNvP7Z}bJaV>W70R(gES-}JD_j6)tc85W= z%);_wP+mHy#nx);eL($C`jTByM?xf-uUY)*31wJqv!keZOXOg#p5Ma|t_!>d@;e22 z>rz}zw*IZkdT6Vfm?8eF%eQSQde_Fwp8LKU^5k6mXi>9zmDhM0=utL|_gjA8=*f+j zmF{I8jeFB^kMtv1x~eFd#Y5YQ*$~9e!z_c+SC>QTBH|7UOWlyzG4!PGgq++)pRf8C zxFDNi%G_gh&CCNq$B!`d_g*2Q;y1=RQhaYQf|`u`%0Q2ET7H20!HVEvaG43tNLj_p zxpg|I42Ja*V2{}1VCg4liJGqy0V(JYu^K6}&gmTdPL-#6A5H;da3UC6#T$-`YM0HTY3vh^-=D$Efa?5Tcv7iIStg zg(8jOkPdz2s_edhV!U6YnfD28^igf3L4T*3rFv%!4U)+Sc+p+a<7`1_(fYR1d4pe% z2m5gE@!RJih4`}zn%4rH?~P-sb%j?7m5b&(4?2JM9FbXXg=cq|zbkUQ^Yrmcs#LN2 z3iPD{g=y|TN(BysBQ4|P!EqH^Riy~HV2GS5#u>o9v4A9r!x=(0o*P&JV3+{ZSTP#8 z^8bs6Sf6p)FUwE1Z*4y;Mn2P+l;&DgwJcj)lG?_G@tFX9K14W;>jbiCg&XI)bh7N$WWuo6H>bO5 zC$7I^im4j4xL5Wu$k&No8y==?y!VU8tme-y$z=e4%+_X*J7wENKl`9 zA`Kcz5_3kwT|m(Ix*evwT{>%QV9%510o3<9#X$61nnj&?=LaEq<#%1$2L40qv60n* zI7P@buu+k-Nv|2PQ$N};K79HON3fl#T&A-;iCM+PVl7e7fl>I&L?0KUVMEHQl&;AJ ze?Q4J#opDSWAtV$-s8N~jvoUz$AH}gm_3|NqT{ksGy|NIK8CWV&ho+w)AS;Fm?Qk; ze$YMOu88^2MtRsq8O{=M#AEAd5DEyo*G4Mg&aRswagM2d0LCq_ZP0t=^7{|!(^cvx zpuC279&Swgnl~iPIoF-m1_CTlk-tQ35wo5SlGC|8>>>>(%fQ#7%ktevf4&ZC7Hn(5 zaa=_$S%eE8x&QsHWs(UxCHbONqN(Gz;E=eJo|o(dUJevTS$*aMNtnFJNpzF_nkwVA zxaZ%*FHHIayK}|Y(UGC?%LiCOLb%g!etsm)H%OqwyHn+H%Ao>n{_niEgGG3vK_x#m z0z%@xj~$iBe;;t57qON;dF=7y3ir(ZXwoIxR@%u(m}ta7QO*GuE5sz9UV(|z`kpZs z?=h|(0F2!q-EegC@xPlSwmLIcdNNgt1D9^8RPJn(t0}o`lN}Dq(}vx218_n_^}W|M zrWbzMOB`OFTQmA7uBo1SG?i*JqaEOyFmPjxNma-#K0-kA?b0`J7U1j_y7DIvHAU6Z ztxV+-+E98vI3r9E>?2=C9fdSM^D?d@bt4TUu1zxNy`&6R(vb079Fec9xiteW(wmDWP+l$qDDR@&TkL|R>(tLU$`9id;rqXSsVFW&RfoIDzekc%k9tvl z^Mc&!{n}aPQNu8ta$peOeyRUPxsdX*Kh7XhM=M9O;3=qJfo5;1OUKqsm;=f-OyrSj z-L?C>xN!Zed+Gq-S~YmxA+NxYf>;g>x!v3+G>|F3V2g!YlUxpL_Aq?J*VAEN;Jd$K zfmVST=tu$eL8fi=8RwB>;zvotPcopV5^ZZ%^kf! z^^qfG1tprD$9>2OF(X@z-l@SdEjU` z$XmAEB#^$e$aiIpU%*i^pgf6^OtvqEGfY{={DubyQ7SKhr9{iK!Bhi{xS!=9GXOFW zx~O}R0|=Sy*9?&O=}aQVI(kcp6`KoyTafdJ9k#9oY(~idU(Y>PaJys9YvWqAafdOW zKTYXlyLvGp6Db#PWr@sVs}Hj^w=GT!>=t@WGM-zj&CS7pn|k`T+1qD8duBLhI|H5O z_T1v3xlJy`&0=g=tr!EaPW`bjc?1X}p$Dk`LP)Ocv5e1$6BLAQ%48fe?-F8>mUxmo z#ij0F!h;XOSp8roHwT?GF?2@Du94F!XD@A$+ot3QtFQaoZ^l! zO?Pzj?Uy1gCX>XZKI)OaD-84L9-A3i3tF0Ton^9JR%leR9aXsSiYR$Y#MRutRnG=+ zO$3*pKI+>*8%9)QGjhy%A=t|;`)FCBH93XqX{uUetNKpl* zD4f#NmX`sI3a;ma^7L^uT3;q6nd|zwu;(5T1(_6#pkL~nA2`4lbGTj=0Yg_4kO({m z#jeet%@ztNS^@4p>@lPPHM*pYKcVb2B=OpJ!SCB)Lg)fI_5%Y zanG0?-n;;O?hGb7QQBG=8gOv- zqVWT18ejg!hl#$jXp`~$%k6cRKCtN-M|1Amc^~Wn{ql4x*@-jv+pE+LY2vXs8?U3) zx1%2QmImG&g4)vA+cIFVg(4{-k%5PA@9Qj;>-geRgjcE>8#Ddw%Jdd`*`M_ouZ5kY zQ#vni^iS)L>zZP^f!c4!r*gbsA^UFJ*H{5GWi-9M;axB=rXia9={WWv@^zf5Dk*70 z?ihvbsQn#|mDVA>NcJ6Oo1$>A!Yl3TJI zg|mm3xKjW;*YG9T%cC*%ljSLbb`>!q6Ob*KAnh>PO94_tYw^AYmJ{bkRe!L@DiDou z(O=m)PS)8mucbY=4lo+pOl{VhwwsMJNkHr@vS}F*jJAr~9%FEfjM4O_a!N!w`^>DEn~e04U!%0O;r@vnFZ_<<8Xgm zw9o%ByA)|;NcE*HJ&k*1hfUr^2JU|#Sig2RI@<3QCG13=eh;EXfbr*vj64cpcMaFv zofDY95MDWpiyp*igbZY+0yA^A_HFN--soSq++b_;!(Vl?p0nsH_%WwLCQMAuEo#)= z=kJR3@N=14oc=OWL_!~#VKy~wP2vibV`&0Jel~Zk*iSVfNJ7f`U7yZ&Ab?u!Xl8fq zck6ug$3#=go7BW(wRh&mjY)LuAq{KlMc0l*CrQodb}P4;;HS_}Hqx-NT3`#jyIuUnyTef}3fz3(ln%uodz##I4kI5-UpkLUZ z!_m1Rba3%&u3Cybp0t!C!9c*DcX|2^8mhONem{dbybvk%I;$q!EjRkTZo#c(Du^Mo z44@ix%IBU}?82&>(y|0{#Ihsz?}}XZl@GdwZYu%DQsV2bg+6v*78jO*A-9svaK;0d z-pj`d&I8@=UodNyCL58=|JhHln92})sGEAxGpl_CF8cw@Z&kj)&khL9#Xu7@Zd}z57NV>XfMzToEb(){vexhpAPytw=IP)VW z5K)m@NF_$idTNT!cam_X11TE07ag&iJ9#OamW5>`qn1`Syrq+ayQ%XNIt9fraWiL4*$v@5F9+!H(ztt{(xkxP-+!5E_ds46~csp-5LH z^?)lWnuCBa%Iy}H3q^&JjtvI_Ub{>Tjt!lGwu$iKXe4O1LHj)zLmI0&OJ(nLR%rhC z!edCuEk|b%TAq(X;tl3o0in?}qn3TUtn1@_x1)+==Y2ab@2X9V*4Z||qPI;nLLYqN z*~sU)z;X6B7#1(uwFofRbwJSpZ4P&F;WPLiKhM}K3mVepY_tT1Q)A;4m~n=06a#DY z6Z&Ig_?G7QJeUMPxc&BLBT!mEBN_I4HfTPDL6(#!cLr>9NY<+N^FfghN}v?6Pgw$v z8Ud`gFS8Rj153)JgiWaPUo!_}Jn&GX|NMo;5d0hw*scznvQ}Ol;=Iv%57{el>-R&0 z?8jV0h@}~!ho-QcB*&+r{GKG&4co#z5zAqvcsqX6H6CDmz+Zkx7mRRlZii0jes@3!W3^UnTUDv2vf4aj!SSt8d=n!le8^h+a>|PlN%x=C zi}~LT%tGP&AEeDX-6ZFrKy7f|)NhDjlY3IM&J(Hdto`dXG_!Gbe?}+GGu#^;ef{xk zcit-itySKOz!J^)6|&o55T4xgRYNt@;EzGN$noO>JYIFR5z$rQq$xdS312F^Aqd_u zGag{Sp${r7xwo$_@DkA}7A?I>p|2BPeC_XpNu(U`ZM=KuURkE^`zf|&-{*Xylt9P8 ziBQp0F*;x)f9}S}5zgTj7q@Syb2_CQJjsL?v42%#=Sx7D`_C5-!^Zt5#0A34ZiD=V z0`L#N(w=u|_fqRo_fB1TB4nplkINrFl|3AxG1oOWTuIOBq6us(c4(HB>C49`>I-Uy zg9#9PZ>@-aDja;?u;XL$GEc6k}URQ{!K;pw=I{4d;sVf6M6MD2vR9Eb7|Qo%Wf(dAS;%vIwq^;T5M33(3? z-WSM6=JtVeX|ZyIi$Uba{6y2cZwgvhi4|xElq@;wH@M-;kLcee^6|MLZ)bcTgFvk| z7hKrIw6*4u-B=nrywjciF&be})6qi=-@;|%1qDpayDA5{&I1Ljm>`Hf z*#}!}@)Y5kaJ$`<#5h#C#aj;lE=G=Y{#&&|$&!bq7He0|X6FJ0b?NCCJLrL)`6)n! zr37etiF$9Pe=Hld{5eSF5dw^?>@qitfN8Yi3N|z26W|qFQgs8wPdLvqR zk=NE8qPiur7_z;5=M5LGiOSu_^k{4$IWW<{`F7_1w@k8ON1mLYroljWh_$TqT7Hml z$hxrHC7hB)i}w1LLyd3DwL00V24d2mD4p)jAsh#%*9tRcTO@d{L-gpKPEJ9CjBtWH zvNWKr^*=T&3_hk)rHiz%zw)vKujcnC?KsVQ?xB1Gw63jonJgvV$8oCX`U>2X=1qR4)W2tV^;zm9XWac~S!QNGXr3{$&NX{vCRD6lL;(?; zHEEKtbsWwnt|!hQ+HVrAbZQ7t z5tLcid?y_m0dMcjzIDBoD0{M{W^l}AC81rUN}$*$76BI7xOf4% z0C=vXLHDLyn z+7!db7hy;5++1P_^3~BBU%*g@zH@up$Ht11{k#R#)oCDZSuBbeyMEOheFGbhktc~* zJK~sMHla*Qm2{zDvc)!d%Ngh7uXm+f>A~l?>Tha_I!&tI%z>z=#J3CiT+YHnrXGjD zL4ok-PObv>5U!o=C*dpi7V!PfnP|CqK@z8_T zd%}^ejUPdAJ!N(2D~F29*cNY%F8$1{(-&0$cJ>XJ0F}IXCnM!pG3C7E5qtqqEjSJn zWX!~deHJ_K?ce46efkPYd(Y3)Ua!n+va=etUWNYCCBYBgg9XE}@w9J2>j5ZM=}zZ- z2z9UfT4zv#UGKOAIaU_0&EP&DL1qV+jc-BT6@t%g#zZ!5!&yNqh9>qj3{HXNE(0#V ze?AWKJP^~JFZW_Vqzp06Am)7-vOm7b?p2fwq>NGm@cq6EvP6>qRaY4l|4iuzm?S)x zXC*(xiPAQ5Iv5VgI}WZm_JOGlBpuR=g8~((wS1e{&p6j1w7}yYiUpWvAuIs$kpFPt z`iBpM9FgX$gW&;`7ZRlF_3c~=WkCV?l=vy;NZ*qnk!|T?^RrkkMGqrTi%Q5!hXRh} z!9C^<>=C5x>P7p&Y%V?}bvKN){;K7>p&8cL{D)&es}x?PeEBnW_vNYuuW;Iisuc!7 zI~Q8vfSX=lHK{M!d3D{_%QRx9qUxOzT(i;xuyuIAgGH;v-Qonnh>Awa8+b&y(Eu2F z+0+&ik}RwzH+9*@&Z0csx^%4AaZaVg<>PR% zf2R-27C_AV)5gfd-x=LzQx+ztk>4ZAKYwof;jclVZNw#PGaw;LnefZCniIoB-;aP1Su9=R}9xg3yt5I{L?M34Zm24ir%LmwiQfGNlMxkf`VicIQLFt=l z!}xO`!{TA*9ocqG>T5tV)~|hT(<1$xEm*ia{vakVgnXN)>{SZ?Zxt zE=c}mH$D>weYwF+23f$J&Uf)_(k1<5DJ z(Wh$wtNFoYxSLZn&IGB?)YhQMcHr?#d45%NPs?ADd@1Uu1e12@Fx97H;|IMd8R3kk zt(1rj0NKdo;vDl0N#5}0-;1@JdMq+(GRWrgQAY>|bbf>MQTddNufun{Z6J~5ErDP+^-~cQ%p(!F?M|m%{7-D0@B;#0 z!QscRK*4H-AbbhnOg;dfJ*{~y&)+SL|Gu|*HQXGf6LUm~t;DFCs%zGfRy+dy)^^Uo zTUnlT-?8k_V;KN@Jv8IEHzsgz%s2{(9AwK<<$w^Le?kbVfZKhF3xSW6He0%`z#D!_ z0fAeEH!?-syeZZ#_l3+pT$iivn6o~Y0{w?PV>xYOb`FRxwv3{2ve7Ngac@_bDsYCL zHVuP;LJ3)vVekneJS8?sH-&`Ki$v+sR;hedpx8akK1_BPvTn>%)Y2|jRPNNKwcjqY zP)q4vI(D7kwaC%)fw8vrR;d7N`0Y^{rk$|-+8M%$l}grN)KWEORRqF1B$Gowe#HFZ z$B*O%Qv4`I_a@EW%z`ZGmUO;j+|n;Y#nOOtpiIa?r3K^gA^#{?q^0hy%N1Fbq9ShJ zi*Mp!A37o674htfA{+62rIvg!jI}Gr!Y;#UJ0IwVzOu}-^1-XR{pCV`Qi5Cpc;t$< znw_~>nPAq*>%yg+!$A&VJ4KjInrbIiEK)4G<|QG<&DS|IAnk4{z&PGTs$=hEpwW z!mD=w{{n`!*UkaMKZB0Lx-rvQvCCSq+mzS_##F8gP5f{&QxNF+pme;2S{*iqFP3Bi zp$&XXdK@2Bvo+^jiPr(J3usgY09+=Wu6D%tvG4h%$lEO>u!8||gqTs@Cpf1Sk<%R> z1>%k>g|NMQwK;Y0>eZd_!nc`>uRMWGC)iH|niSs?GM$AYhcQbS``8v?TCg zO1+g9KpE$1eD_y9T5=4Kl@g*8A;c9_)qWG4BcJTS-q=$L%||nsd)^I#EGo=h~Tw zv80}yaF2PC<46qT8l${GBPODbxWr${N+!+7dLc&3I8K1AQE!?#q+od1 zccqt1Sw10U^0%1ZdUtl!D!brIF_~?Ta7Eu#u0gCD^?MOgL6l^J-!yI9KfS9lw6^v= zGDh_wI60t69yBNOfVz}Y(6I<$kO-%B^^Lpx3jFjnAtc@0(4llpC^fAWZY<KXQOUHbJ9T3@ma_WB99c*&(ZL6mwzg z^{f1$U`Up}8=O8*%t5}3lgPrxpuUYvU#4`I{)KUYeG@p#+u(g7<>?G)c2@V)Nhg#% zy_K`^YP)|x7ouGUK9VTZ`Bxiv^M&8mx9;qqWBK$(5@rAy)_@5`6R)nnXVkZk=c5F# z(K1O{Cb8CNT^uyxYCd*i+#Xc{P*wOB5uYIv)s9%ycwxKJ=7$tPWpntn%RCDx1>rQ( zvX-jy-p)_yWy7Z1Lg(&`GFSkZs=UIq6wyv#y@Y zcX>fz)!ZV^Rm)|Ald7rJ>ny1J1LOUte`v^-TiL$&S6eZz;xpu4liZZutEIj~K`BF; z57n=n8JH{ycxU8yAG|X+4ffxWsi1Rim!YDEjKg(ec*kzJyhGFDyCMbJKc#%oAFZ6Q zy4$9!wOqfWKd(YGY~v)*SzDPZH@>yaRQ5p}DN3zvs8RH^H>gcSA}GJ%&+&tjs*o{i z&dVDweWW+|;IkuQPD->5mCX)2;Nm(Lwo%7$92# zh>k|1T`4bn_%Ilw!6q{+9SIHCe)ly!o%^A>bV2&rm=;3PTm-*j?h~g?^8Mj7L+bAn}~nCI8ZsY$2inpPwb zi+%u4<=ICbZC2B7{z%!~{7h{SbTn3d_(@%P=>1>!xs?!TK9}O(`k9?UTOFTr}soY|ZxT?me4kQDI zhDxlR?0&p_DH%AOo2xa>j4}xqq7T>|myHsYsCl11lB<%*(WlM*wu7Wu+ zy&)OfDzM*DBFY%VFX7?g!;=>ohusfoMw4_|NZ%n5Sx$@x-EWGPB27GlHLE&nLap=~ zwX_5yy+>p0O;g$DI!M`)gZujARoqa6{fnIQ%bTmm6z)|IM0}hT1-9p-=z(i=VYQOB z3&4EFy$>t;owQpeLNcZr<|B8t9#OO$D#x_G*NAU4)OrxmUM#7b=zKDEFl_ZhiGS<& zIGTmqe+7`E)*Bz^^a=!==~Jb2FIMsTrS14oG$i^@8Ot@kFWB}QMq+EN4QxAi)_-&3 zBa>0lwhiSdD7-sjNlo-K+97Lcmw3m(q)KO$GcIlJ`J#3EE4JZJjZ)y5x6QabXG*0A z*h2ArIa?$cJ~yzNO7$%oB~NXWo~tz0@da#3bFtJO3Qw>Mtvq3*Gkjgx_$n66OQtEt zgVjh@gbf!PWcapM_P>VKIZ9Mh{=|svbkToLPqpAUPV{J6xAZgW-I_$JQ6E8AKTvVL z0E5vr)oEm1OBFiX0EZop>r<6rq(aW;CPR5Le+h15{+~KDdv7ezB@Z)g1!tcFb9$i{ zPAm@TF#7K9iMa(TAO0omt&Trc9#6M0y*YDPD#KSE&B-vtSv)CGgkA|?MJ4h+hkkMA zC(E0B>O7ORM|s_e^x4VJ%s=h>k5KDWW%OCW?OJ%GK7}kkebJbU8%CSbl)MaNAsLJ& zj58sWyGp1`JDJ9{NmD9{#Iv#GD38g1qvd3f?qidHh)DgxU4rN6c8rJ^#%tf4eWqi0 zSo~AJ##%Kti~e5ckX2u!o<{s}ZH5`gwB8dK)*Yf*WqLO^An`w2X#f68k@s26 zlr}pCg$8B=jqq2fBL+r3kG7Z1o#+D=y?YX#K8mzIK`pJeEk=F2T!Y}jOgqLa$MM!v z!(Vmu4R@(rHvSthhf?9(pR-8L?`h-?dtLH?T?>f%=L;}fKo@MC_wMalz~bU^SpTfu z!s=qb$wd=G@MbfNaBa-0ua|d_$KJEXMz)~&JrY0|=y|bSv^Vy}^iCPC*$@}3C{lMs zuOug011!6neW2HXIf7libMz6vbMMNO6Yc*;*I!0O`Mz)5=wM`UIyMMT(*DBu9kTZ3&4>!3-GZ0s$;zWE=W<%@vOknMKR;@ zm5_gK1gjGUO;-?ljSJ*J$o|z#7+|m60fJR!%5;dkU(InIY7cyHfq`#AvkyMKfeOpO$CtrBmbgj<=Fz^)O8dS>lgD>6lx#cM$(I&L%EHc+r zY#80tPNv>zyYNdK%3NDJeuh?REr#t)4b?EFH?i(o&y~koMxRFTf@Z5fVC!Bvo=8qI z9;iwt{l^Y})M?pEN5`bRgcXEuVOI@7cmo|)pzCd441G+HJ?4)`SYTmpF+^cS-r^(n zWD3>xZbEDGjar}P!u@u+4gTeAe0#Gze7LX^FVi8_UF=wwi)`%heTQ__l|eur0ZaVi zr$*?H)pyNn?rggkqM`P%mr4k4Hqx7@+I(_u)fl(gD;eYwnVId6{s)I*ny4=xfn{yt2f&QXve|HrZTD+c$cpoaQov*}VNc%KRj-x2`{6_;KO#OGDU z{FgB_q9dB$JN0h{^KK6Qj*sXvYv>Q+CNNL&;DT3 zQ$yrR81;tNHL>ust6wS#z*@`>wxhtX$E0prY*&NW*) zJIIl=e-pp{Y{0%_F;0M;s0Cr4+$U}u9GK!qK?4onJgzo!4_C8q1C#nV9*v1v9j3*f z;e?~tm^P2q{E=JL>eC;;-z2Ts=5Cs8vOYB1E-{PnrK-9>NV94lmMzh*diH3WC;+O` zLKBv=G*zM6aOUX|HhxUJeoKSB+K;bemI(LVtL!SKb>)VEq$y>Vbd5HF_` z1=xzPnz)HbSZ?5q?bSk$x8_Ycf_r*tjENXp`QjSoiY)X1kMn@QwoQbuaxKe6Wkr;; zl2G%~f39H~uVlr0LL8oIdi1Dl@A&YRMsc-Y$@3RB$1Z{pG2GXnrSU(Q+Qruay75^r z-kYea4~|b$WB1s6V}`RNy3+Uu92xs8TNQN=J_uBxSdsgm)`qJ!{yeK{^tG)igH~=l zvk;+QRw~=&Yu)K7&!Cypl;3PEhL}lp8&mh_RJ`dYnH%^SK~{!yDn7VKWzLx6RY}^&Lt8HQEz9yVnaL)iNCJhbn6Sh=5OC@ocS7@u?u2~eO%lQkK#$YfC}fS?;d(4w%*=A_d7{6$f^^>?t^~b+rzQ zaaGOfvUFI!gKX*NHa~MJAKc)z&BNxvN&CiMa+Fn`2y1@eF@g#4jvmr6Nz$Kq+94f; z*iM{R-^M9izbjJ~(lQdgTGO+sCyDIq7CcpyO#qk9ZktVaqUD@Y26pe+bz($hsGw2f zZdf8MhOK2PErz;ANhXGSQF!b$B%J?v648q@)s=?LXnm(TD?TvonbeInzj@+NMMg~b z%rzW#nu15#(IFZ?)=lJg6Y{69cajo-@WQ+W6%-of+7plX{&B7DS*m$tgL=u_x=I!Z zpvx3J)qJal%=)|3nV9Yq5LgvDOE>o9)Nfh#w}!=L(bhdXXBNI?!~9Nl?p<8{$)5e7 z3R`wAbC{jDYD{HSjsEPcSS|d0VW%{ThM;U6)YctsijTQXD?`KWy~V;D6%!UigK zD!}Rje)-;~#!S`MNgTm5Wp|`syo~J>7tp=W%>~CJeYOGZSkMl@*HVqpU$ZM*ds&qH zRlv$$d!3|EIKn(d7mKyZU%vfE;=GBVoGa|zOf6{i18PAI;$>venBD^a)@RYwyv>4C zch?MdQ31~9U>&L^;O0X9R3QgyTKt?9MM?*jVE+R)-s=S}13@MzZu>v}HJGu#xT|y) zuO&yL8s+Aq3cN8>T!mF;)JXkb7&xWre{0X0?36c)Bv5 z>skA89SewIPmo9YKQE4g*U-!i+j<0PWV7oY;c+vA-2Nm>2JSe{C#;o86rW})2s`8n zd#TwkB0R7b1?BX6f3T1=tiw?%D))z5|HfRV*&{tb9a#Bw7_b9l=hg8%ZX0Ih|t_14n_gq2KTj!N+UuSlRXYPQH15{jkN2FPM_;^u<16u62u3} z@ijOY#t^?@F$t(U$hS!>QYj8tTI|aFxFjA0CZk}(iOXg^{Yz5`wg;^ITZ{DceLneR zG1_;a-2l|0i-MRcSzb+~D4?`pKa~5i$%VF$Rl!z$8YA}$#?;nuGM3f+R3k=$@?wA( z%QO^WUUR6ee2E>|V3nL{g4H%ox+(cj?%XSG@6d@($cOD)9yvKXVGHoGJUiNxWyDhuTRJ`BP~8n?C5B#$4xDhuR)c;GBft$^IHQ*`}6P-2E3|p(ap~6iKI=JRY+F z{nvxsg#ZAk<`bhV#kO3RiT2qYOk@@H(&!X!s_3u^Fu%gOko9nOFvpQ!dYjFoE^?(B zblyh8>@lM$(} zX5{_5!%*d2Sh*ZnRNo3Z0NftyEADE)I@BNC3sgHa4f7CE{5X+FJlQ&G&zWI(;T{6E zY0?2xWHX~W0x0Y^c?LhcZT3AJHp;pQ%xfhG9n>Qt;OP2(+=j2UDQ+8u#YG{3wJAUW zx@w&!&IA&guy>`8O)ojE@rwP0wn~k~YS>{LNGY)CBKX+0 z$pmbGBZ=$$|5BQeu7f}MaPM!E{ad8g6i4SR3M&|<`j3;qJaty~yp!^RA?mhI2DQz) z68Tug_jrX=dMu7%Nl#lfbNCJ?@nLG4hpjn4i-WP>V)**}*5Rcy$*WZlO_hdwEVYHb zmD5b}8=A)3xaMGDppCvZB;e5fnn|!BG;nhg4t$|{sx&&~2+MC7`?KmirHFR2e(!rV z{G3WU;%8ZRc%sPLCq2BbUt5R5Hp6ccSOa((x6p8&b1 zaWFQ9HH(V^lsm8ok^bMF+xITjZ^fDgT?C|{VxV)lRT3jRF?JAAn3bE;o&3XG>Ih*9b{Td~KT6}3f>CDwio!8)xnudnvj1BJffzg?ELSa|%KI{H zTmDx;O1*Z4k{Y`QV%Mu$GIfzr{@?1di;1&j-Py^)rhPG>=-L?$Gd_;_Y~a5ExqWaj zZzFSYOV_liQ1x$MB>Jb_fiorY8^RpSR10RdY71l7MN2NZ9NKtF_fIFqcvYSC6zKy4 zJ~TSBxf6%zx%`!=WWj6~w1n{P7t`F{DI*bkeyv0yuQ4zox8(2J=$B7euf_BpaA_^k z#Ekt9D_>`J;Zn9qpv3J`S417Tw>jDa+tj497{v?kW796x(J)&NBD&ayzDxDg)S5yi zU5HF(R29an#&D^1xW=#d(A!pjtH*M4kD%wVIo8e_QcjI2`ZrUhbLDqt%0Vl+t zi15tI_I-P5WsJR)D=h$&eRr>$jnUb-Y!s%7`I0qDXd@XeS zV5f%STZ5_v$dF_WbsAd3!#La5>J)3iRrB;dU*L+UrJ0!c*K=7h<_3mWYVOTT2E_|^$`7L&@hz+?PUW7z8HGB1FlE1H@C6{Qu`YG} zCp}7vJTIWkFP6LZD{s?0S?z*`}O0jc)Tnp;qxNK5LEGG}iL5!WvHh&9hm5eGK$Inbv<6eafY(JKFB0WF z>HKOmjsk{S%r#!Gd%duG90KLA>GvUnkxrRxGgu#ZLIQsS_SKEIO~?eiR<%|+l)||tYZw}_&DY9y$atZolx%NsV2(*YSY=$T%?g3La2^bX70ud9D| zZhX>EPj>p%jnvxOiYK)sufvp3rNGIf&{+thoTh45B|ihBrKk6p#gK?vC+{|}fMu4W zmCfykWIR$|`-ayNESO}2qT}AO=RkK{@^^I{zVsEdFF=*k8*S_Fc%;ue={KB*4+|Y; z*p;(u8n&Bt)|#uL{_WAPr0eOI7kWu0R&V|@R135Oo@FHRUp~seYy#>5tZF{v{=DwB zr8BD6jfdHkb4M$d%4zbS-7kc;b?;Xj+fR+zoyM~>mnxgCKyY=5h+jZ*khW^j=SQzxVUe@OgU}_EXeT!E%VPo znz{UY5uhc;Epj3!iM-Gnoag_Vm6twPef)%!7~w~}%y4zDLTwC!>4KaI(!MSy(38`wG-GIru;k$64TLB2>PR=9+N6F-g8BI+&z_ts! z6$AA4)lJlUqk{2=eBI~n)m`10geu17kt)qIBc!K4XT@iArMchVt(#+q-1`n7&5P24 z)t!K@9|eqM|IK(IM_T{_qoS*sYo?hO8F;f)ee5nenVVUM3t*4>b$YsG#xi%lWH>SV zWL7VvUJeLd1Y34s)c zl)Avp8WbEcmUb2NFv5$lh{Ta*FO7OjaY21B)`ocen|B&?=YQHmHagEn&uvXmS*1W5 zN5hmeX_-Y7l_0fya2oHC%U&(@WiCv6HOpkeSGosWgn z@2O=>sb8+7`2OK5*qDTOsnM29o5c3>#Yd-zN91Z(cZt)HvrEkI0mC54RIm6d6(~Pk z)Fp7F2<2YbcW2$pwXKBndBMUVav6OU@&~In#Dbl$qU48Y-M`}w>R2}`<5g2Vn#VT@ zO_VwDoz*(~Ue-!VDk2?bFz3u*H4qd{1!n2_>gN$Zs+{cqR!jYXqxqd-li|$%mko|W zBkE}RbO@(?x!e!w1dJ+r^!q1_$5u6%tSs@?zJRt)U(as+SU8_t!Fl(==AAL^=2BS; zRk&m2)ME6);Vsj>A$ZvNm7VyTMfn|2l+cP;m)!(vEVaXfutxPe{Nz)6pzCyh8o%=W zd7Wmy*OFVkQo$q8JqasKln2Y;eyWa6%305bZ1Zr}k4YBh|E`-TEQ}9JNtQm#LSDQk zl)(0IBiwrrF7+-S$hfo4W0wyL^2Qi0p@=`;oHP+S@#){g7hv)BEQ+M)L~^1z-G!2paw z&%^9l(^3mI6KbCTMZb~Vl2S*+BMMzlg$q?%Egm9o{h(!a479q}PD;@0(t`tJ4GeKV zAlQJq@c?9Ab#kNX?jmo)Ef$PtW6imyHtL8Pk6jfqvkcsdU6R?pdL}TLd3p8(knYWmd@BMhAalldTBC3vfRXBt+cpQ8{`@8G6>KUP%Hhr^O zb@=;3IY8P`MvzQ#os~y$u^`;)-If>hd7|M^Ruww30f_X^b`cCnrBl+w2;@R}(@E@u zG>h2soLfjqI2wtsqG4rseCpPtg473&om&UjA^WWxBBjaE7V`vjd`w(vJQr!QPiIz! zlagn-Dlxm>6FnNxq>vA5o>Rm&i=-r1OFl60RGDShRjK#ugplwl-e1t|kax>3QI3jP z(nxZI>K?nFJnFDgiR6-1-uJW5cb#i>HEGRD@077lJQ@9agMfv`wmQ;6F z&fN(xsMHg3)I+}-qzve*5hPdTkOh>IaWH;(@g|_MN-q{n_E$km`bLzvzF}pjvqL?t zX{8>{?I<_vA+NF)-076ljPEXrUp_#YZ%)65Q<6d93l`5zbONutUndrJtJLuvQE!(< zogRvGsJ=BMe3BaLS;Wb=uwUoUZsNivBK&iGGcUDbVv>VDTs8dE^W{nd>`lr_!O2*E z_c0&ek>h-^eE2y#mW}jJ(nSlL23pHc9-B{AtCsw&Mm*d4ldV~OH84xpgl{U5@#JPZ zVV;{$BYk(_uK`@W2yp2Y!XrG12q!7X2x#oMZ=sy8wdZ|)CktXT?W~Xzdu+U{S*E)8 zHOPwyHx7fnEny&|XS%_sV?zqi;*cjo|7U!4BJkQ-N@IJPnNVYUUNW;iG>S9mhTFAo zp+EyRQF=rI@MOWQGtDTn4(TxlR;;N(xJgbb${Bz;ctz?@68~om(I?DvXj&(TO z8o>5Mp&9NCELPehX0;|Uh07-5v@_lPf3{Vq)`GOdnv4AW z7qxV<-YCpuUQR2hxz(Aj>2^eyKxQ1=?ukk!9<>Qp*8dO0g{?1fn z^@7e60GIGjhLuK`#Dh`qwSSux)L|gC1I#n+RV*p!;=gV11z?_I0J8X3#W$woq;Hr| z1EM4t%h(yBrjw0p=C8jfqzHc(T^7|S7-Fr8uKhAqO8>bb5r6^#dV%%z-=PP_Ay)Uy z&_9z}7LSM+REU!RyA5D^nsd_QMAKhoqE?M2#n`br=S6%n?z%H9koHL+6*RwDM6AU- zs=K=4q;Hww1qZnjz3PcshJokn_AnMluq`(*MV<90bsP|)G-jy;7vh9=qXZ7HG21Tb zlf}1U*uqhbL6lJP4Bvb6@HRVEk8V5G+x4EeAuoObf!Q+c=EXNdSqL@*JDsbo0R@qo z&NMfJtjJ23ftD1znEXtwvZWA!O6;4;ltJSdKk|ll0GWSlDhU@H33sWr3`3?rq)$sK|r55QzM)J=?*{yi|3qy>`e%0 zp2jMEf0=h$Gu8&_*i!^Sh;&5%6UFj)evA}0wfeWwaE}SAGXv&jzy6j;zi;Bh|KI~f z#Y>m9WhoEyEUbeAcBTrZXq9yTrf7R;G0+Bu{9|0MEdNR%J|5X>miaicCtH^c=4T9< zjr=%|d|0O2=GQ=N&)OF!CbcoGdyp1RVaFPPx=lqBN)6RJXTPkKSmcKIr9&t9p4p^G zKjXEgm)YEc#fo}lG<~+$jRMr2Nw7OvL}Fr z28OMNU1Z@_kI*=9mYeoV&+afi%l!e1s`7*w@EZfaC9Jz!NHJO8ZH|lQ_-*G1i&}4< zbvS!*W9+l8nHg+@JFnrxT#Jj4?CGrX5dG9;N;14J` zk8)r`$2!ehp|jUfC=GSSr-<@!>G$;`PwTnbvo|i*x{lR+{_B?b$YkhQJlpH%kOwAN z{|@ChGHR%A?raBu(R&q|(G-Ba4lI0Rm-r^c{~6&mGT?|V`=;&KzP=uj ztpx2_@3_0hGfTo_8X7A55Jy*aMU6_g@>I|Hj3TdWF09wS+xyx_n zq9%D~zudD|88ntv2~KtSWf_-|eyz1vqRK7IK&K}SJDTk8RII}=Qhl`r$Z`7Y*0$d) zP8&a)^tNQ=;-`I=wf8J!2q3?^r$b+A3vcsw1us|q?VsNx$F6ArT*EN;-VY|zWoCo1 zF|aN3^5aHttLUJrDt0R=^&@$PlNe%LOYk+82W=Lp=Bzu!rcXkl{YS(f*7R18uu9bq zZkv$`BV%H7I7wy&5(QI*6lSA#m+vjF-OX) z>Xbv}t<|uF2RFTdtW?-iE8n+Q*fj|+tf$?&O-S~ORN$@)zSF$G8GyZ5)VDqlPDL$m zonYTTu_tT7&rdUlmj8+RAn6vs$4zBw^sCwIt$@$E05Te@uD#z|$EmDbZqSFyxkL#@ z0U0jhcY>~j9E1>s8R&Y7(+oVLyd>-(B-d9HF~}{E`1fYu-=aCoTQ&xAQZT?6;S2|~ z5O4aY`O6j~AQQ{}X(~jd-mIx1^(i0Mq2zB1&MAR;hxB$K#a1L}h8CJF;s0A9@|j;> zmj_ncIYH6;J!!I1s9W|((SrSYeA^CYCLMZ}X0OI!8;bAizF!FUX4JX#6y^7}__FF= zl#rT-pF@#s;p_Xm9fOE*8^Qhe{%M~Zg4~{pU9E8!b)Adu;+SFRo6EP8T1#_zvF5jk zz6A>$zp6NY=F0UaU)}AY4si6r<;z@HFh29^!5SN1XphkU)EU%TnwqeN{VsObbFlH( z?wo04ME70?jDjBp*ARJ&W2F}x!N50Xi}`hl+4)sw!^7d}q{S`LWd^q6(+D*6g z9~)MC8~gg$^NUJgC+$*3BJ}S=cN=H@C8UDux7OSW3{t>GJL65CPN%gWjK?)d#?>!I z5A6&yB+%(!Rz*5E?Dtjx%9_;ex{89K z&k-bm_hO>IUSn&3B}Z(&3rel~yZ?jxV)2b}$TXX?(ttxVGmPzx#Ma&3j}efL?LC#K zP68$V>PHX*#^IpR{$lr$i*XYH(mG~CorRVOZZ>)Li3Dy7xrZYQ}qJd;3|y7G)UbR5YY`p;4$FBc=R3r5)?uo1_xS<)lqJV=u-#WaVmR9 zsMBL*BSJgDSN78`B9+VEs1^j2!7;6z>=nhk4G4!zieA}<-lloWpP3&PRsV6NiJUfM zT@%Q0>&s8|KJk0Tl*sUZi|N255&X+317n-_FW1pw$mVF}J5`={AU-f-WewspEp zj=tHE&LEfe+|ti@E}fx;aS1NEPQ*asKI9pFJ}4i3J~Q>n6HY0!I5TLYuikFj9}}7; z%%O^&yT)|p%^@q5if%2fQ;0qRR$vyP=QW3J3g|6~MiKrt#MMJo$Q4d!TN0fda+p__ z9mO9eW)YE<%TPH0lOs-NfZ#HK_D&X9G{Z8_E)J~t^S>K~)Gx6Ib_b|1W-(Kggc_J+ z2}=9x*9jP>ZbgUKi4(}lqMbVKuJHKgzOZ2al%7EYe);g&*MN5e|E5}? zq!kC@L*=M=8isDb5A7>>Md8y~w)53GAwjN}HM+N_mX?p+A&I6OCDOrKP%g6@m050O zQ?@(J^s8S$S`KUhT{Kzx^83xQasZe3yE1)kWYH3E@jnpG_p;W)o&;Q>} z$sU|*(SGC?_3Dr5fqL$8w`Gmyw)NP7vaL27(Ug6=(efSX1ow4j@eblb%vO9hrQ+C>l=opnyY*)ufKq=CX^kZRPdo01Ve-ZhE{duk?4wH2+8C&|K^YW)EK zifgv!tkyrI&NvYRTt~u}HvuF`@U#xlOBZIs*GuwTbOCx6zZiTu-<~kSU|u`PvB1TS zIo77o?ZsAVMy`0(;&raIRLrj!k%tY8CKRGn;uucmXc$NR+p)R1Mg|!A+*xmZJyX=W^D<<9D_A)i{KxCiK7)z4X4 z@6k&F=A#v2D)_k@N&Br~OGM<6iJNX8a2=A2G0lY5es)B2dQ1!$2Nyp(7)@;P?T+&a zX}@Ckd-`KvelOLoPBrleLU7e$<0U>E=)CBBPhIS*KRlM{oQUFZ}y%szv^~Rr^}PlZ30a>H2sb!&7<362m1^t5i*n)8LEj4 zf-B8Do*&+?yt{jGo_nePE+*lB0pkF#!!GON{>)PpvFKyr*BLQ0jaPAfO0Xgqp(n11 zsi?zmqt02?KXc54FX5NH`7eKkek_Q*u=(=$lg`!O)>`^ErxRO2@|Yfi*dFKZu!mxO zqGr%CIh|qV2XIpTYMqLbyx0xk7dFK&yMZM9#mAErEFNf6b#8p+!1*$yqR%Nb8lz22 zN4Ed-hsMj;1ENUz+`O0|W$ z(%^%H^wa=yMggoe+A8aZ3;K)V3+r>+>!1dNJdrt$XHzi^MJ`%56V`etvoCt;8>Voz z;ia>C==R& zlo7i>o;3};4Z z(2@C0UOyu)gDaF{oIcVDOgR6bHeR-B?b{qXw2XP*!An)j-w-%{tb~pKjr+-|9|1#2 z9;7Rv+51Cj|LAs?$G&?s|6FUcEa*1bKE@aPjp?6F^XX8Zz0rhG3ZbLvLSC|O=)6_k zP3E7jP5)mdHIu-(Ulj(CuD1#W+v{y?9qS+hC?e=u4 zX6`J1pDgjb>#MQEhF3W%#Lb*H&2DOrtNNlzXFq~0zj-V*Ltp2x%Jtuk<(~g}MzwjI zrG#7{Yit~z`99&SZ3&@x*`4*sw*fACW=YLl`={xgmx-Ny&|)J+n2)`s9hLv8L#H5~ zjbLnY#4WaN*z?u*dxS-|hz>9NxHMpteTB}~J4*^WMVJi^rFmeB?dwPVS9~SDGA5B# zIRN6fB`h3^F%rx3IZ8~*Dw7T3DVmn>oAzQTcP$i6d}UwB6Z808ktdA4_}z4->iPV#Vd2xoUIS z*P+q%WJy^kZPM8)5tiB1Iegdg1ua&C%O!<0R7nM%O5)mNGZYeOBa8&QH=)ECFN2;x zZY)u4-)Bs}PgwTGtYOQwrFqN5vy=U6pzacyywh1?;fu}`_Bahk;kH0+f zitl3_NKXx03Dm6(oEPXFfTn3hi?4UMH5XUnuL|; zvM?Yq<-Cz9LLywn%X6Sm}zdagzS)_h;w!zPpFL za(e~D%ZcFq8=mvTqYz~eh#+e|In+b#G4qrCoC6MZVyU=CS#|l!Ij2rJYLXjj$wd|7 zugzv^39NS=QF6}Z@6{5@bvZ2qriK_AXKsW}94BTQSl?k?T4>=PT@y5xiJ0ekQnRuQ zC5iA+y-f97tY&vFs7$%~5XwLmZ%To)zpoIyTPocp5=u0MGPwumPuo5F+`A@t4bqiK zuOy0wd9!Htg<-#NW1kKyqoH{D$sTVOM{{$y7D;R+!n`cJ>e@u~gP9eLCWalwjC1`Tv-%v*=NaZyn? z(P|3Mxr=kb=|ZM~eBRb@-!;QJ#=~v#{ePz%e*W7>Kh@3RRi9q6@W<}>DxRfgKia9J zmhJAuQx-8~g<9mt@ksMU)vaj@6IU4;#sRdxi;MV{F%0%lOOp6Hd{ONhBsrrMy6P>Ex*Nq z_}ssz?-29!_0>Uu#kqBqn4Mq7@RW-%jMmbu-4dqj-xK7&Nwog%wds|p6ZBre{*H$Hy@ zao}Q{si&AYSv2^t#pn`bHDlh10aKlBP?NEk2enDw70aP1Tn-(IOsU6bvbB&vSgi z?D83l2DBjVL^d690%SmHZ zmi7nLzAMrX>6daN%v<|xQFeCjSp_wM!KXrglDC!YNFr>!qsjGq7ML_m26nGdHtUKw zE8cbXkZuo9(RzFpLfOSdZ@m2EMO-Z-tio3B8I6I&MqxJ1SHe}-==fin<1(=OOgZt^ zQ8XSy)LV0f!Q&In2dxgGMgrGTn$Wq6N8y?;@dfF8JLu-6TG>SwYo=Mj-k9XWY1EBI z`qN{~4vYP+#H$DhDFf72 zvn}(;MH52g?@zC#ao~Fd1g3%WRcVb>qHdnAuFalgAK{U5`B^Edv*{JWeyHw7SUMa` z*EWc{NnD#Fj~??vw~xHL4vO}KC5(=PwzalUzI3P5+AfX3b>oL9=O#SGl>3u7%;<3ePb_GqpfBL;wl3&baxdvv$YL$sbtCfms4%ViTXB8A`!B^izarCZaRggt$GG_oa!F%<)AZ?i z%Tc(fjPe178f~!KImJxD^|y#IblNj^vTc|#TJK86D{zEwZ579u;CXA03ePZAacsr% z%%M#cfv4OHMF>)1=Tz{g&vKo!7g*8&#o+7jStqoV*vCv+aE=_$JDV$Mq@~G?A%!tB zM!Mc&`B?&q-aa4^p~sxZqzzyJXgoVp< z4|;M%>~aCC*=L$4(x*f4_d;bRo?ed#aPse`@r;?df3Bxo#slkZe5N#)MO*%sXopwc zjC3YBJ$0g^a%v$e%uS%2YGL`h=~=@YA@XHWvJ7ZJWz|y&mp-lSv1B8MhS%g%b5xduTzzyIDW<16j%B$W1=uR~KZ*0*mSpq4j+^i zjP5$dJ$21q@+EXLHrgKInl6*Z8>BgdlE(!#W^$!V*X8UNKbsPJQy%fXj+%@ke>Rl~ zn5sXz6u5SITq3 z>vAj6UD?gM^5!)ye?~z3=%eNca&9jQ$s^r#<8Rv`I@upg)bXr`G7*oPIF4(g-tEO} z$R4xt^_)5J$xX0TVN=NyCHu5s0bL>dVH!v$MaWj8w8+5@tk;$ayc&OH`(he!`^Dh1 zpClzc&U4cRW3-ye6HY2x?+=w}Awe3PB@$?Jc~j3v3pTUv9kmTbf5S=huzPiYO_Kuo zv~9(I_Y*wXe;GvktSt>Qg7s98{@ZNt^&AKNTJ^HlYS4N=RuaM-8722VNxhWaWi2+D zTrhL&lGp*YF-&*uEB)g4xGNhzI+0<@@OKwTrwaZXg%h%JK3xnyuZ9`Ul-kQ{>X%eL zm5}i{PHbsC3SHkhl$ReSNqIg+xFgqC;M9lW#~aX={4uTTwHjfct95O6KIqD1XMSEn z=JLxX>5a8)BN@DC^WU$Ne{Dk7vmZ>=>bk*$#&J4df?g();uM?~ADxE+!8~krR5Sro z_!dtYEyra@JoPR`2(b|DKhgcsF*JYc*ra+#xoG%PCH2*&aff~7IvlX#kF!e~Ud9WbnQ*@YCpU8Y-}8!pCg7#` z8nb%UmEnk_k-qL`a7ebx^N%14`1mq(d~+I;>N4jl4)PfAaaLoCVOZnsLfWHe{^|e_ z#VsA-As7S1W9k28^g@K~f)8(Z=a+HYuOjKRUujr>5{%cJ`O-||kO%3w&Y+a^=UKrH zIm8&gO~DlXostUv(i!uW1)0BIvV!lU!`)mte0x$MU~`y1DZiNyuK^_w4n6f~4LV#t zf?Dw5**6bwd#J}WX+fHP)tQkg?mduFQ|ebdXnk`{{zYq_h}J_B5BBNvkhgGdb9mvr zowDRgA+^iERt&$m+W@5@EHirN1jNZbyLVr6%OsdXfE17ibC_EJJ4mL+e z;4t{|vE@^h$xLxRW6VrR;d z%lHE7K;!wAJQpD`_QT48S8C(IGSyHa?gSk`{QBRTFi{xhkY99YwMN%hY5F-WlGyNO zN`AIqoUT0raet|K3L@6TJf+3L(tN_;O2z{)=l^`8wcqv2h@lr)FtpghjHgRer%vo< za4ym*QGmxfNVXWD|7!;$X7_OKa9!W7oW1nz1Fz?0|!CbBMh8U!ldvAEd-ML0Tp#%K7%%dd|F4)HVwQk&))9McGfr9DS=&kXuSN zsuN?gX;SBkgSkN&xs9!*KF{2df0&?O;TtTD*Tij%)}0Ct?#n+)CfJT3=j8Y^t#`Ux zIKc36L?uDJd7-n2(rpP6V4iPTwbtZg|af6pbKlWm?Sp9;y(dj)?SFMe{+x_L4( zOlzH{-E;u5Ss(5ayzZ#t?d~{-1#Ca`n88EHDkqccKutcHTEu}y*-k2ky8W1oqg$d? z5pP-MWvg{qtc1|HCP%@KtBqOC`AFi>9}1|r|@ zVbHt5*3#f^M@}_ltCwe>B7V+cL*H@MD{pX8!97%asN_XC1w}{1Uf;+neHFYUjXt{U z)A}C3wP@2|<(OB9(fw`SZ8k@jRY>(!N{KZ&R`hEf>#e0#LYV@RB_&~U@N-79 zj*i8h-38?6jyp1Q?E2!S{^{aQ*#hVJxrlmjNJ!RJe3)rrF-X-)QrzZ%07mgLG`PMb zid5u)1eilWxYFJT>3YtmsXfnC%c=GlG$#a&&`F~(FP=_~2)*P2Gnie7qVYKN>Oohe zUc>u^PkA*h>g%KOL)VPQONd&^Cn>B~*M25HA+Zm9{L3+@ph?>Ur;(j}?PTy?scPA` z4E}ftV)w74%}@n2kH~@vX5=CJqirkc!?ovHELlj-5;XzQxceXd?t382xvylu zQ1?BZ52VZgtUT_Ma`V24ZRm{~niJ@(VHX-*YX63>+cifC-n#@B5;lma#J)*k>K4kYT5ZV)%;Vkz-Y zRFPX~dxWJ~f z=mcJLB3OJPh|ZRWp`4Acfpx92dL_?!#p6c!dT+?-!JN}Rxlv-Uoqj#(u~!Oj6CQY( z>mTpd$A22W-sJ%|wtoFSSh~6$ANKy;I@eZ09QnjzmLV*EipLK=nhlHYADezuE;_B- zIQZiG-5}Fz8?W15(%;>e$zxkHLK%fU9O;HPCq289XZba7-Ul_qgZ{Ds9rZi{feb8Oe`k}( zjWL<+r$=Va7owE9B7?y%u#3j_Azhg4QRa=#6Uw8^;)g?In1feFvTi;C*1R*y<6O(e=BjG4-FWLAr^tSAX_!KJ5 zn1QfN^|>{J8ZGvT-vepX(}TcT;lYtvdbU4(&D!m0x3}1L4{K;?U6w7_?^Ov<33+lo zu6{x&E7pKw=Oj^as0AG{iu9&UjC)ExwY^j;UZddfmPcFAH)Lg=o__br}|&^{FL z6wxC2?W3#-9=>lYPYn2s1bdB2irW5|QC(^;n=&SaJ8XaSo4V@rpw@+&F+i}1W_eEZ z3#gBMEO=#6ArW%f6M19q8Aqlv2R~s`@X-ab&Yg&O-)z)r$m3HYF=Tg6jzd|n(lbEJ1Q|u-1SrvpxvoZ zBy31Z2>PS2cgu32h&9gT)tFi91+8D}6%oN>PI3WtCAaOA>~BCir7qi?tMnLxH6dafUQRh;=nh}% zI;*A&o|zI?*?ryoz>}ZHa}IH)Qin`KH%^z@e`MuFZ*A>w zqZ1?=F|W3*sFin{>fZn>GUK6blAO6YH8#CuX9}W{+xt0>GePup&g>Xyqqr7m}Bp+Rb(b(E&&18v{4Sm7b z&p%=ykz&izcRPJcM5+FD^eO$-CFE{VC{P;`0V$jtzx1rs#t$JP?iXCt(C*$-D}cri z9H#><`ymI;Uf!h;1gXO@6A3kRZ>%T|+vw@$9bMy*$&QNW-J1gr1fvgU+#?=WurPCs zVN-Z}>2&l>@H?cFQgGH)KG7LdvVV2sw&d7P27~Ka1L5b}T@xWhD8`DjpYAq)!;BAs z&9#UgBJZOQXQ2Q7|4?<7VNrf@w;oVbT0lUgTUtOmMM^2@?lS0RNCTx)KpN@pZj?^x z9FVR7q+=L3d;I&J_ni5}r60Iv*z@e)Uh7_Kmx71Y5QfEBcs^O}ojcI1>Ji4059lm; zXOH}%AB)dqTi@oj&#YDjZWe!{k2+h_vvCF+jOE1e3bLEli3uCg510@Byo^a*vrX?7 zB*EIwo{6u^9Nc z$e+^xTfT?kM4D^=4^kg(0MxW!VAhu%c^>U|v)<0-yuS5i;0$|4D&R~*R3uunKYlB_ zCmciK$!RCo0P^s9li-Nwd?>O>=&FRQ7JONR9+&AK=WhtjtL==2IKH0V9#L?{!BLo2 z3A0>wtA87&pJrgx=2f4(`Gp!v zApTDqy)P=f5!Lale!Jw8??yAz>vV!iHNX+u#gW5+9q56rT*OD~TYOs^B2VcSp+~u3 zQUR~P$z1J{ID7Dbz&JWru?4PlM>4$dMDLS=vpb{14-V88@mU#6ok=(nEIJ10%eH%8 zk5dU=2I$SqPSW89C6W)Wm-FD=1Dl5Yl>n$k<|k_QytLr)yemyO4I_;>R&rC|hY^7< ze9m*6sJw@tutqHDiA&TEaEa3eMTQsxA(1u`h%(7k5e){?*9eAz51w>4ixcsKIy8_D zsm>i%qn$M3lFGw5zc~g{i5iWF9AFlZ?cZe`)HyL*@p&KIX~}xx?nhkI;xcm?|LW=f zyK%2T_tP0UoxgI@WEkpgs&%c;JNy{JU_uyV!cOIabuCxjbUUierm2jb-w(9BGab^@ z+xs$}GKVvxRVybtbEy5}JM9+Pw}X3fNS&GP@d|aE?y%jXj{8=AcS2WcdIcSXO7Qr4*1|GM2cKB|gY zQzh@vVL;i%l<#|>nm?X-#r-(*%vDb|Ekkp3H8%0C*5-&oP-DtKrEEc}r&>Y5i9>kM z#&U$Up-3w4^Hs!GjN#mo4aPq`m6#C&LKXisz?rVpS*Fa=&1ZoQ-FkH!Iz(-Lt6 z5g(tN@e&MU>sQ(d{Mh$@GWU(^2eoscESLqdx7%%@UqyeO$@r18>D^3+P6PP2)lX8E z%65z%TuXRlZ@@xKX7UMUBb9%q3U1Sr zCnYXNaJl>F#l^<%@NJ##3iz@5e4+E*CPpo^`?CKGL$az{5NVQow~wRM==sQaN7UM; z`J3||lE4$N?4T8dq0nK2h&rwFRNIJNMo=f_N@WR9tn>ApPRVW8o$mYC7s zW|C8UoP^0m^yvL|}R7cEo zw|RValTInb|M6D}QFd%&c*w)jBsbF&R-p^~mUOvEjV4=1%k23wi>M2}vAotB{C(=E zF>~wVM3%o4g5Ji4kuhS1yoS5!jX<$6bAO@TFW`ws621tZo=L@4Z1e15Io%C$=mo|qbc z%^CB4%fsQ6^%-(503E1`T089?VRNT0;y*;RTUJu9Q#HQ#KNn8Q;?9!VAW@le%crD@ zBa4vF`%cyGpOQOlPr=L|kv!YNWR76>9r~I+^%4>|vF5z7x|!yyJp@Poz40kopI&o! z&T@H1naufV>|KIJ(EK&_Q%H@VJn5lWK|G;lz}MM%YQ|9?EI;;#vT5-nlwVG0UT7_H zXyT8*$fx>DW0t#S(lPYJ73bw@APWHyM=-zU1FfJ`oj}Cmv$5Zj!g}i&1d^=U+O08A zk|*lCjsuR$f&Z@N>w&Zw<12Kl`2MGAZT&B9;G+8MDezh3iH}k&< zM#raJlMUa#$&lpXJ{lTi>NdLg3~Yv01bRn`IX7wDEyUWZvC8(1yy3XAl4NzGy0F`E zkN@uHe5Ip*SVvY~O1WQCqkAu2CGU)*?=<0JV%JiG@NdsGJ{`A~$k>^kgAZ|PtzF%_7 zf8eN)7voT+mF4S5Wd}S%(~z6xCM{Nb6$PYRLZs~%?3H^yP+!Zx#FLTGUEaD|(|57x z2u#gR85y-|i*ojYqOU+|%dV@Fzj<+K*x;f&6sn^1wK}~>w7^z`kDtjNw>4Mpw1VRl z7b2-F4{l1oY|>5McxYWNahHO#D^6*Sc!D2=FANb+BbzLHxW1=h2S#Ac^WoaZ8ku_~ z&m$rcF$a$228b)EPy&&da<1(#AJY@h+biFah3~*6D({QbI`+(c!MoLUl;7(CK3t1s zBQ6LH|68e}kH(0cWWO7KluRET5@-nErmZCkFj_G(c9C3P+`kr=@#V~BNUYwY)!lDi z6gR6qdqcK2oq3l9Se;u0BHe-0fKW&W((<6b9^+1$uNqcAu#2+hmh4^o5~l8++=Kl7 zbSdVBq_*MqLp7vWu>BVxbazLBGh)Fh z7f5AoUvgI!N{_exa?~_b{r#+~z^Gmw$_Bp#Sj16G1{IkZj=RmU(a56uZyHZa00dHO zm50^Oky>K3r994{%5BqKjafz5VHRDVrCej>>J=1jpS{e_o*y(U%;2QfmGHh^=6UU0 z9jP+zr`rUuu3_db*%>=g38Gdm^Q6}!sYnLrazo=gJ)TF+nk@Sjrf}Xg zLx(b#Drk^|xC^cpZ8*Oy*ac$?AQ2vPfQ5~rp`V%!|k*YE94-)J5j z{&Gu_0;Ix<+i2+<~)9=pAr z$Te#vvo*M+vsg;sxo{dMzxdRd$rCQ zOtL3tqhT-q5YV|D(3%M-WIfhVtC>P4Xe0}qo}n|7>)?FP!);c3+InTpGN)50*K-?% zQiR{EEpDrN$gHhZ{NX(VoVKgek^r;CRf=)%R=i))%>&3`L~v!vYos|#>zWlx7p3v~ z?>Z0vr$Yaq$AJuH?aOvp5EVm@RQ5aVU5p31T!CDI^*@>g2SWHPKtC>Cds8(JHzcm- zLo~P>rqs+R=m0sjqk2e5E_;Emo4t*UU#&)>G2>UcDn#7IE2J)<E%8*QWj;O>uOTQB82HFu^#By-l8BT~i2On8|;=tb-TZmoi zDU1F`slPVORq%AcBI(P%aC#nr8dpiH$l z?S^TQK;cPJ1;GV>n}5Ro=0UcB5N4y+$))0+maJc-lf1qvNtRZ&M9SsNW_ zVhuT`4H!;~%WD;N9;o8jp4%IoL0795-;eKNuPLs3i}Kh8PN4-(H7zDb25?U3YactE7xwI&>a_}$$fgha^QpU|3pFwZe0*Kz zM3It`9j#y@(DR~@_#Btk-;;h6qJ`j?Ux}U`PUwgL`&sCQb)|e#`S&=lkty~Q%I6i1 zD{eClt{)GWelT(#;fHQ?3{cB&zSEa%8cdgPJ6w(JCeJH_3a{V71&f>DxM?52RjD1lm;iFmF zOVNqVmYrS($e}F#965Lm(jlILTq0KvQZYDiA2xq4C3rah9_;B4=X&$Str(~EALDY_ z5n*ZdkD8LmTGbab(LKR4(`S6K^ZyYiSIhiW5)CI~$_LlAQux)UU(HqB{xp%S!k&Zf zbc=+jMmO-yAxjeGjz(D_%uI^aJPrC6wr~kqPD~zfk}4Mb;f@i@un1$aQ*?|moXMQ`@%S?9)l?M(@lWtziML&CM(pGX`(7qBnFbX(-bD;-$4 zMIb$rrO29Br?;_JKOSL#>`h+Dx34PfsSHMUX{-V^n6qsDY^aqppZZBExHS!h2iJ0x z7?|9d=b=rsWmFS12)LN9U0i?MlbhjTkJriuJd%^dcO+zprAb_J9&z|xh-8<%LI>xp zbKw#rr&;{oZesgk6ZEOgP`kePLQwPK!5_XUa)iy$WB_75pcCone)0lwM@;^%_D2h; z4R$Yjw*%~l!)Z(_7rbY#gSMh)(A{MZNF>JpVz)qj2n#d}2fH2PmG3Jxs15UDGXWn1 z=BEv^9pQn7_vqZ}X~yW>Q1D(tZPm+&$QQDDvnbb642#bXrl-5H3wD{6=Rci(zf;*H zfUF9fG%6$Uj9m7`{;mkC|5*`EC^~F+$|%~;69}Ld;Xf{pvNszpz>VxgHpVxOp2u+_ zKq#W1mSD!ea)<{fGy!6vgz#U3IHO9%tqTUJ4$=K*p)&sgmG?ga ziZWpSP*eufyA(Cmw4b*3iD@;icKOcl^!ALq7nHqM(3cE2$#{wj6P7`?6;Iga*UP znSeSvC$Fs1+Bu#qE7zf?PCu^#FA2Y^v+s?gWV>TIu>6WcEe zcXn-7q7b=)4rdfaE(|%nJ#fSKIepob57m0n1&8iHqJ%&eCi@Px{(L z-wn0B@yEq+5j6gZXr*PDBa@}0b8}8DBVo#E1Ro7Ku4 zpdTsqHKIPWPT)%^mDft@Ho3^=&S{u41(Dn4@oHtmo(UFO{b&K~I}QU|mPd9Q<|yMq?`}8eq8W2iDnI zbz19pxh2cz9m<{CADC4V90My?R-nbaT&cpGNNe9hxhR54aQ<`Ki|!$(Ch1ExdGGBY z?k--cqb|f!3k+KkQlqFtvt~jF;qQjpFBVH7;$lwga3*)zj-8@BL4%3qPOEWF^$%{j zU0nkZSc3BkPidVziKbTKoQ@5<$amlC;-$0Wo&^;1`rH>htv^`E!fl4}bA?EN7iY=% zJ7zsccB{ND@fCpDs}=M^2CXH4PJ93I{pWM)joYu%E*xa4ZM8O9%#i~xvB)BFhfCvQ zY!*xK-lRDHu4}x^^7%-`kW@%}y_roTuN_#7{defZ> zpu_>%!0ELQ0KfmdAL30OMfY01^!J(j%Re)e&_mNsgnTEII}-aeMV!T&(;!mdWA{Mm+agYDE~eAWH9$CgAVk39c)RbToQ)lSFGM3 z@3IKF=tRJMTy|uI5G=I@Ms=@Bdu_In1Iv9FPCu7BQ5u3#lFtIQn3)k>J&N!F1^~hR z@+8_@^loG5Xa~D{Ukyb*Tl74{!+AKh<3_G;GhJs`V-KU_FjaY}=VR4zfy8}SyMLxK zHD$2uM7BTnj<7P5{g#`l1ih)x!W@XlbcI19&8lr-L#O5y5~Wek%r35e@l8Gxp4+Jk z5t~get@WlTN{x>zB_=S70)7driTm#zm7ZAV@)QJ6e{@3w4UKxg1R8d9i?hr8#~fmfUIJv}Fyi zmmd?b`ZDFd1CmYB8^{Q&mlD%vcdWph<@qNs$w#9iEsHHekNr-&R8A5H)L$8}cVe>w zYAOftOgGoy@E44OrF4lG)>FGMFh9jd1IxMP>du*hH(_WmyRG$AyT@q--K3A4IlRC8 zfY%8=ugh!WK7PI}&;qmxuM!!B)!s|53ol0hc@t8P5ZC2;X>i%|s>61H8f8ai;wJm- zi|wKk`b0>|pv5~!r9D3VOFB1GsbI`?7r#LdNjC`Sd499=Hwv2TZFvR_;^CRy31wU2GY^T$&$XofMoZt2L= zZM{Q=0-mJDurMGUvYm6_>C~IuAD>m1Hyz5uUfS^N=8c82)V&0fXRnqTe&?&NBd^=e z6Yp{Pc>JileexLE0el#d(mQCe_vS@aZ*CK@;^I;a^7wbw4tn#F4q672NB z0}apjHAkHkqzjb2tag>NZhyE#2R7Xcl6l*k79d>HX#Qg-36sTd zqW)Se#tSN)<4NUgMmj7Q0Rdp#ipkrYa883Is-iW%F`h#t!iC&)BK)t)n`~I6b2(XG z=BDPds@0}T`xs`lVoQo@{IX-UIh)J>l~V3)b5(S$4uPa!<6Tbgx*pb7v#^vvBuA%} zKCQXX6~A(e;gb=_*I#C~#U^@L8CIxNc|P;7hTbKEZ3EE(a4Qe=#w?X!tI9NWAu{~| zg2p^1)g%N(pqtcBp>F-Eh@<&Piw_Yo9=c)+<*f@0LI1;Db%|kuuMulrN8K7SUBBC)Vf(u1}(w!@}#Yb6OIXCG++3aBCmMTiu9a>sWXLT1c zV=4SrK-h?ezH5qznz$#R{}Nw4z2jW7{J7zTuC_SKgk_BM4kQZ(3_T~{=|Z1cR#a(p zi6guYM~cZ$66YgrpMhNh0%3Rvt-T0*4v5J+7*oDMX8eki{7|dYllJ$ef?z4I z1qG^DI(2ZuYgk^)h~G5}pO$fF?>;^!EXPJv5=5|kso1Ul8fa*z^FIeT##F53!Y95A z;LLU?a?{o-W>K+(sM*SXg<4SMV21o^*WwzoB!p0NY8!9lg zs%_LY7h}>e{3E^wb z+}&6XGSpqvX8eJyPR!#pJLmj5;p^z;S9B_8#@wq8XZqmWcw+YS4iMM3E9R~FN1g*i z%yH;Ubeu?77yOluLy(@4bYsJ351G`fEQCfZ4{y1tBXkL`h0!20R)2PB`+B|lq%uEC2SWEel&l^_mS`UZyFRgSB`opsO^YgKgs{{6H+4vuwu3y4y1t=>K z13$9C35P~MuMGA+0?T5&E|k0#EBul1urYy* zU6yK-Msj6%lItv&f1cMbad~A+wsJiz1wxfwK|J6Q1|2z*!e=zej8pEktG{R#c;s#E zX7Vc-P*AZK*+bM^Cr0lso3k(L6`OCsN=!EV#X(Bv=C*<0b#09Pap_Fvwqa*mJ429* z;G$_+2eVOrtPtWtcjIEhaaNqYBw=GH47p?Py!FiKT*Rf>bapx352bZ}G{n&$4r?_{<==2T}M zanwySP(x5oZ)VL%P)aW!CUdqx53D_%2*RDdddL5p3smx;zWHLr!p=1YP+#!ni-am% zr>hoF&DwPtfz4Dc>_5JZ;TKm#SfBQ#Tkm;x2vq4aEBjZ^SnN>ufDx4ibQ->EI53oJ zVUhJj8@7lgP9gq1_(wWPCPxlEv(Mst1`Pugi>lQIBwrOfcR&P^xH1WEPDy4@xo;*U z2ssVn-w8IJx&bb}hep?&*fiKP7#+*WE<;-u%5LkjbtS=ECDyfuFQ;uQ&+9ictkliI z+;uz8%<7TyMKxUObLCK+Vy5{@?;;{@wDgm5r4CM{nGaQ#bdR&xkom|VU-w`9Y^qN$DXagq>6PLptp$Zwv#k@K@#b0oK&2eQZ8zGqxd;bW zsq^+-c6_Uy6+shEi>>E4R`8(XMsUhRHkHAo6uFM1OGfAd3%e|}1pt_WA5CayS zl`Nb=@uAWjq6)_y4w9)Myk^!sCFadPBMmhoZV@z=NhFmLG&;1N5grJC7#pE>| z?rXhX!ahWztR)EK;LmPF!qq?}->H9!TBS@)AB0 z@Gz(IU!Zvr@rfAeVRX!y9_V<@67gRc|G?QNNgLkyQ{gpv+q&!eZvL2p<9CPS#lIlZy<2s>G$u+P8u5{})D+2LV=UZZ6)Q~7t93Rv4oousdrHQ!}rFH-wi5Nv^R?!gl^6AJ88G?7}5 zhRe|II>g(yp$$IYoHoWVEl^=7dbUS6b(~$U`pDWq&kLGm-6hkxQv|?fN5d1N1TU;s z!0TLwnYZ>IP75fe-JD%Y`I10>fYA)NnM~l*fJ828{N8D?LcU1mVR3#Ev|ed6Dm5TiYcCy<8PSJG|Ga|PbHO0+be1@ew+Fxrq30M!|-a0 z)q0~liVQWBaxo5FoZ(9Y_DkIRq8o~tke4S~GYr24S#}0#4+P z|KBy^%P39v!q4d9`_)uhOTm;y&4*<(mSh2tB&OlNMnyVl#F9U6qmoi&1^PzH9t1si zx9hLBVhc+@gLd*Ci)5vki+PAF?{>|1Entp{e0P0J`f+sfrXm^SbHVpZnv2E_mveZs zj?fKUKDN_?3!hFo4$44R?e6p*rO+#jDOsRMa2T9op*>p8M@*6IuOxfi5-YA`;>PxS zlfqlS;D21D=aUArR6e(nRBEz5@!^jL7y2^4)yt|K&b-T;e=k{KyIHkK>Kj_4YyuLF z%iF%J`F%;`Xqxvq6dF+M@3E81w2sYpUwj;(f*!1QzGvKL#aoi_=y6Qv($xAoKsww# z8En0!r)vPe;(fyE?QVTR_qX*Zve@d*?)cR2-ecb!&4BG~yP4N_c2QQUQBJq=1wPeN zbJr!1RvlFUbCly>96hGTaA#CO*>c;hla6K~M`$ApH?_sC+@{m@vv29aAkU1wck9|+ z(zjXP8;!3FNw`Z>@ybPa-+Gp~ZC||&S+gCuU=JX>xASz8mG3kyck|8H%gf6wqavtZ zV4G^wkRV;?%8KFIe8oM0N(fz zC?tV5_^oEj{P-w33%ce?HWs4AS}Vc82qjZ}I76QqQPtznKSnq&B4Q_m+({zgn`8xZ z6*XO<6Zx-Ff>j9$Zru+<*`FJe4XYq1%wsGv{w@$IrdrCz>XB;%9+Ew7s9f>QWtwrM zPp%4RiHq#D$*{ZilW^+l-SyJ17Xuv};p_U?@HomiXEmX#i+hi1^kfQfmi8(O`7J)= zzyCDwiu79iB5^~u3@6ns>BVe?l4KJlNoDQY0J7go{0-;h$PWyL1|(63OZ%TN6Nm1>}3E$}+8z7UgJ%$=}NcEZIg%U*JUPYu#T%=!a4Bz`k-#4|S_$aq)Xp_;4^@*?VkCCbvu*N=N+PU&K6xvU9SHr5ap#Xhhuf(;PK7-fCX;ub#@M?OsfP z@5J-r!daQ~^+yjM%5P(E=Q#%91kAXvA3R|}b~##m%0IOsPEtYd?B3cFkU{tzfV*cp7{c%sl0eAP!a=<=Z(a4t^iJs|9q|NOYLnLHaR>6sI~eGJ#%Uj zrEXI8rLS&-E*CwN-iu*+gzkNAYJ9n>x#(pR#h#epiFIXBRNrY$Xke2PMa8T*xmC~J zRvB%_J1zOxDYgj;6-PlyCQO`|cnNK`(P@$Qn9si< z$)1GoFs-yD9I-orO`3>9Z{8$pBYooNl$9^RxYTix=r9@GACAh_4WR> zaoeiU{PXu%;&}?3pYAURy6YKT{`r*L02I*rb%2Ig!BO|lN$#<6vZCr#);@QJ43^IP zmMg{I&i;d9Z-HF_vbqqbP?%8Vr{u<3@wCDY?{MKyFwbF!jeQ>1M#7Fm?&?;uacmJUvIo02nLx~5mgA${kmg^;^4O&0Tdhd) zAH>_``fkhCT^~Jq#vQ!Afcow!;T7Sz(48W!j}KGhM`q`lsv{=0p5=jDb?+t{^!L{W z{DmjozbH_tu=&rOzF3vEOSS!ilPC&vz(-KK&gaq2Fw1GT)cH!={dHg2D_yxCu+oRr zD=t{>159h4;Tk%?psRo{aVeO3CK#>EgL$B5Dg3_@ASV9p)A*}rnN-RNfuL=Ba}PPF$^kB|z($L)V#Dh5h8{H0MgAxaj#5C*rD zM85u~AKYmbE-iDraSehu>XJmvK#Aw@{WBc)Zfh$du2-Y0kN&hD+8quZ3fH0&5! z=a!!~FY2hppO7{K%_$~%uvsP!?)WzEt{Rt~fg4d9b1%O`DuorHX;H70>|(~NjyIJv z5^@#lp$Fam<x$FI>+qhdyLi1zE2lR(O@EJQ zO3PW#@C*QHhoVK#PEZpzf9*in49Yo-v)r+CJP>sTpEHPZ=B2}qy&8ibGU+SCqB2?+ zMo*&~^!crhk>Gzh0bG@@-Zwdt-;p9vBeG9+ePs&9;;W+J?{j`kZQF=USeLXxH;z`? z^Ly^1L&)n-zD(`2^DE3P!=4YjU;2E(*;1XHndU^Q&R--ThF;Lv#rdl=`9^VYYEM6e zef2-s_2q8yxfB2N6H>8fV59h`F7<`a=gfT9?Rj6U@Mn;jFcf7Tlp&=9<&Ne%sn{+@ zWNYAChtS3m)B46@6B0!xvZQY6Zhs1EC*$FR#u^edzG76et=N9wFf%-2Ay*$wP|iz+ zSWnn`Xw1N0Dj^LIoYvI^d6%=p{NNg$D`w#hGtOb2A5yDRFK8ypFO##vv z4{~wDqC(aahY<<=2@Lay(Km0CU??;K4HEe=nxecCku3FND7UK)2@GY&5PpcY>w@5C zTO4GOOlTTz*}Of$5XOd72WQeSOs=_g;^M-vqI$|hG3HeIm6>Qw*h;={{Lygm0LguO z=Uki3@RLex$l?3oDMqJgFfsgoRrd#e?>ED)5GJ7?70#6tEG~kTUiFDQ&Dw~)kAAdg=iDUdMApQNGcN) zIpTt*2pJd&8f$#whz=RW8!VB6-IV1?C+B&;bbtZ>rE?{J*?L$1geKMi_eJXFAX(uG zJAq^Ssw&aiAm+?qO54!3M?^y96mkFW+`niQX6Q3?NobzDe=x=;XY-SnN6X{DMjm`U z4+M5yje5xvHV!2PnkCR;<#{tM!|``0%F*~5n=o<+wsT&(*SQOoxGiE2_=SD@@5I+P zE9aeMvzC=et#3EyH$;Slo#k#f+vZ?gK_GQ~hx666pv7d)*(OLx!j3#M zgf$6Wa(or^%6z)3BbmBp*7xod?^(Ixws@*khu!A~@cn5W_>^>W37TXm2&_ONWu@U6 zaeo30)jpaA5%b^6W#BC$$%Kba7jxGjdjBA1BmbDIvb{NcIe3fzK=k=lw?$nf>~D!QYD%G-%`NacF)0TFPO3dBdo`Rf3-(XG}`tgTB=0YKnQ5WbqW+4)n}jr@|7yr zzG|F68qc@KsIvkBBC34M^L%|S3&=a3rv3b6^VgOaA%nPw(l938V8@M7OCTbx;u7y` zl=^J*9mt*esb23@rU}qL+pezoFeL?%ymK*TjPp|err+uFZ&v?Mb$Sk@&+Yp^hPEUzb7YHi4}>w(bGa_i8o%bhiCPeksI%Txh^VrbaqVXwtYq3E zf09bAw2XUnju3uMJ^VgZ_Kl4qGTYpJ`WA7`qb&Vqab@bt)RtepJCA0w*j7(y@7P5g z3t^c*5}4T~UCDQe4W_?D05hit7sx|X3a825!-}1qGFCd0ooFQ5S~;Tk(=%LAMNFue z9x#ce{+38X)?b+lfNc3Xg6ZV?MRSDOQmu>XKDqq`WjrwTw)iSxRlX@J{;(OqB!E=a zh3_kvils2PGuLx_7!A^+fUD0Tkx4U3-{=kH#=ABR!GH2_zM8Yyf?mCr4X?$jaG3pA z*2j)JVea*?@G8lewJP*cc6vHZK573oEd;_3b`56wh#HXnhd|0)HJAt&ABW6LR}O=C z)-~+JU!!=eKk(->vKKDD&dLQ^-u_znzLs5YWRlyI0hQT>I7=(n$e~jA~Cxbs`|E!IqZ9sA{|z zCy=Phu*bOA4ll5*0Co$RIdnbs4zJePkBypy?>V5`28Q#LgRAt{A}-|By6o=wPA-;T z!ITCBGP*lK|7A78=%BY{j2T3@dLH18?$+YXPFIgQ@fmBe3u zKzHQ({JG%)vF3Kf+ezNm>4B*@w6|H=wF*)qnm{+?IelJPZj6qWAnax8%@^mhV6{`1 z)~EpGI8|tyv$$xs6;dxtQXBilfkehEYjca3iwcaAzUq!Q8e-5QLU>-nKboW2ixG{l z;ZRnnf3Ms7JcA|@b8z{qWI5Ds1vqArenPE(p1fy>!$Eikm!GzEGx`Y9PI&my?#R1p?QEz)$8X^t#6$%grhRvl2$+3Q z8nG*5Vc|)1tZG6}R{B&=rPFzRCe*|-K%-g==r^A{;87!S_eLb2ubD4A_;QPgSWEPA zyAW+-c`oQkCo9PQTE|2vjnw}fJO*k{OI!ai@(yH5xuS&epNrd1yWcjWl%cM@z)3U+ z&Hp6M7m;bO?;ykskYIIoLd#!BF1>T}^Ky5askmmjZH>>OLA( zW3#e&?Ih?GlgxP)!rj-Fwu)gc~g(@j<^mHFii`X?>e8=lWJm@7}#m zK~(XMCexAp;wt=g63g#cC};vOG23@%U~O1WJZkGc6?{~5s@{Plf8txz>tPdW`{bh$ zhof|TQTPhD!mv~qV=H4?fFvRpknXbro6m&n9%bCiVvLw@1OdaZ@+!>+_n)MaDs>&1 zoi+=E|e zXh}wsV(FkaYunk7cq`S6bFnT*VH|L}03`BhO~~f?{DxC$xv=}|;4^;s(2hvcf+DPB zQ`hg#&yfq=5Zkb|qg&-^)ObfT#JPz6I(z^GL(_3_bUH5PmuoOdW#6^cT_-GyklGyp zmCYc8_Sl)5KTR`%ZPn5JQYd7)mhXhUhVRYrGe}tulY_+n7QjNX1{=OuG@tphO#Ga= zV|m=7Og2U@$6xzm*W48vnZ%UpWpH}Nl(lSGV6(_F;l9;wkU6aIJIZ?P1C`ZhB{k%7 zCgEO8NYH}ZfjsgWx79BLCcvm@Cu(N@ z5nZ(6xL@B{fo2o}oFk5R?@;A*U_eax>84f_ zC_1{aAI=>Yn+U*eqM@09JUS4=_|0LM&&UE z*A!3xBKDx{5(5>HMvbyt~RrTqg48gn1xn4iwksM_@HY_LKnh0CkAi%m#5+!KPkPAX`BTy z3x$GAvZc-gVd=Nsn>eE+ipjz>)lR;_oLOri37I-N=n=8wvhWNPumyYCP0%>tDfUC7 z&2GZ)?O5iOE2u(SMa5pJgg`IZUvC-t|A*V*|1RXgMn&73J|cA~%VK^=C1}^Td2DE> zYeRbYZnna2lpbl7j%9WTdL3kl{`qOxHI*NMODjT9bju%(Lb5InqCOs4{Xsp_BEd;Y z(y2c53{z!tvEK^=LPq!3qpwQA9Y8~wqjOn|vlY?1(hdp4<-EEwQ#SRTV-u)O=gBEs zVsC|?pER`)jDU&lP?@ymex`@h9fd{GkO8$pUoLjgL066u<&xoZm|`Ar-wqbz=Mi?yN%xUXew#v>ZH|Lvi{=Z_BGF zpVgNy6pL8N=sM06L0aw28+_YAf;sa?*MbRgc`E^dFhyxN+(HXbo~QTA`zih}x_&r^ z+TT!pYE&|^|NiLYfX=g+`Dx7m5&Rm+(!W@i(DlZgeV-q4s}TCNIT&>Pl~qZDsVZa5 za;@U1Qvc*J_w{&lc zU@Xrcc{^G)omZx2@BSc$(^9>|PLGDB1(s6rt~(Nk?B{#56)4QkJOr1#w*RzPpRVI- zIiwgPbnXn1yJODjSTFtdt=XLFR_L_u{udSiq&Yq*ouN3`)$ZgmA$2no*a^ac*+tmQ z=iOz|nw#8(3-)EcSTe(>XZ?ph8b0cl25K(F-~~Z{cl)+$?_o8M6gv?_ZBysZE#5sh z-{lWrnC|@mN|>u{5;Ptfr@V5k6ZolIkaTu%>%W4p zNV{!hZt#rE(KRpexL3FPnOth8nr-d7UDSmjG|#6~T2)-Ud$;E+NRahnh;xJSso4Cv zwZM~I8TUQdws6K3{PP6&gFWY4HECoC^nK>P4n>Q)>%wa|ppoo+ge%A zMQP?+KR(?7m8NC^$FxH9NQ%FGmb;fI3Bo`0SqEox#l`g}F}EtAsC<{6u)vh|-fMn_ zO`Ktv!S61xjZQS{C zATA^NGr_S>?f}!<<7Lb7%QPxlb(m^4xDHUSHra#{vijb9W2le3-TZJn>bceY9=y}# zI`CeO0~7){)8YdI*g!EFhH3iho63) z!4(bjTsS*FQ*PJStIK!)t$oP-UrB>+TRTKejm8N?o=Z{RoTGFj`MR{)G?ynS$;wij z#}{eXW@0&-D1tHPFTrR^juG}p*!(2%38J28Nhf5f9v>2v#k5`<(ug`&q4>;*AL_J? zASl|uWZu07wu|+KEt>c51`|P(*!XGQlf|W#)+p58g4#v=r5pElY4bgbjl~;WGn0`T z%|_VL*1m7@i}X&pkHoU{l$lR_od6YJ;A8);+Xu0q@+^-cgfG4Nz{LKU6&OysArM zlZHEK4Rn7V5&WDv5>?@7Mo7Ij6R-|3HvKJx*}z zPDaJfF`>Uft@(}DvdDv*+(94-sQ4a6gTH$n2}cxa>nC?j``U_tZ&*4Y;@7zN1$xYD z7a2ifB@w8it7s>BHvj?IDr(jCb-5v3OYnNMid~|2DDuzc$hy{s6PH}eW6d#?r23gC_*~Nk8VD{G}X;fx+j4L~(U8&yGCLk4L z$`f}C*H>*!0d`Qns84RF_R1cP5LB+ksd_Y}`szNC@i<&YYm5%*LnZd@jig>uQ*=S4 z?Bwv5KSY%nO-fry=XfvpPMX-hK^L}MEB|gv`XyB4Xb1V`J#;3y=+GDfrto*0d%Q*% z>%fVI?jQ4}%j#VsN2k`f?Pfms?oA1Jtw8r~NwTB3Z$Nbb25|gaC5w+n)*dKXKg?H| zXK}5ydCGjG-Ou_dzRy2p)~Fg*ioC)-pca+>D*?z85|`;^mXpa2iQ<`YAEmj2OA`ge&kSnz*H{WQT?E=p!k+eE_2yqW0d4)QX z_FvA&f0s)^9A5rN1D2su;d8=Z~{=E(?wtMJCZz_ZrVI)7PrYppbug_e1Ce-7X zbnL#!)#%yE*7+M2nQ{`Fvdf#d;e}7wyoqmVX?bA8o;n3uAa#B1qd9l=%|uE%xqfPO zA9vw$8&Ugf2!f7%1=Jg9>$=ih`e2dCLohbZkz}!D?y7b%9iw)%tgL&Zn51EAlzGEm z&Uq}(*sdy8rtZ@^US&Uet7ApVJ|uK+;+8&JR>3YU%SfgU!$zHA?S$G}BAe%Sbq+n( zop~-3Z<}vhdn`5$u9^xCNHi*{Oj`Nw~1Vn2F@5Eks5E8IkjKg^a3B**uM6uVDi@g zVe7l&ss7`Ck0jADLPp5U&L%UGO-5vIva>m6Ns>LXM}zDwduH#&7HZC_INY|q4D+=gCoqbGk6(v1MgLnZ%|ll z>brq^t#s<0+?STWsT)m)4y{b|NAPJM@qM`slEQe`;OI}6zzD&H*hJ~_Rc(V*hHW>=s{$5@?IIx+}jH}vz8#nhnwHI!PGAe$DybPdRswu zL-wk36=#2%j`iWJUT5}uajl*H(iPCmK&~t%FgObm9|QdZn16oL6YL4b2%ljjY3t{| z(&-q!u+Vpi`pD-~>CYN-eqMk{vPseWU1Za3+Q1~b@3-GS=dpx7tTyCLsdbEg3jpt@ z?Vz3#H7R{Wmr?8a z=pRN?T_Wzk6<^e7XkB{pC}d zO&w`B+UrEVRw`axAWr|tm&Vj|y9PJ7Q~A#V>FO@g)U@x$p}q$inG7dICTAjkyu0D$ z^Iho7?s~we#&#{la|bjJ$!EIIC}x%`3oe9&hNdiL@HoPMn??c~bgn(m@keU&`pf=M zJy-StuCjECrQp7^foIumApk|F=o^9V6`+~fakc1AoX z#(Cm>XHAVAL?MiXorzH`oZoI596qfjSmvia-IeI`yK$lq2CjpmEHC1*>g7&;o(s@Z zp1)xx* z70}?W%gvbqZ6kD>4ynDdCn-DG>lp(~V}|7RHl-2MG$l5ryIk{aue|P-mQP=+Lslid zv-zkuy%`Slz)?4E-TH7w5niw-6u8qVKL7>r$DXO}A2knbU&;aXkXe z0?D!qh#<8{4V(*G9Qd4hdmA zBM25k8Tx80JhU_RD%(!(>7l)W7Z$B4SwwrKr93b(aS^*sqX%P=g-Qx`P-*(owV_OJ zyb!*b8czMG^uB6$i1uwJrnS3sPD$|*Q3jhb=$p4O9tDHAK-&*YMRI@^F2-v{4v1;# zfd3zDi?H7TdS0=CPMgeW6eT0PuiEI2W$Vz(htVyhbhI;R;%N?oj$I%RJs zKdBQ8oMVo?0&DJR6+~I;J0R#`a#YAyI`y%|ANibOW)`hNfFw@kQ9>SG1v~Re z`J`YaG4_;9?srpNKxZtvj^P5br}v(L??Wa!=NxR8xr^v6Zt<^CVs~7ODT#S3i{DXy z4YcH;fw7)xPD-A&Q(5*M=7Hi1UL%QpEB*SF#e-Pe6oY54kr|00L|Dzb0Qr`^{4YoFv4BJeQbwuJMe z=oI|Dv6)&mZ~}dZ-KbeJ??@j#a?qA~>*S!CvFFabHvRIu142nFqe||V6^GqmuE^bX zZsO}760>KmJ_0?fN0G-eh605^fvp3o3v%Q`)nnYdECx$kucBl6e!L0+d`vcomsww8k#hRy zoJ+y#tN~&0vq|fGN4qHsDop#@HP4uB zU^{`Tk2zWufyr*Ti|P0G4y(I=mUQ5mt(3odhweq0G#M(GN6@{saqu$L1E9e}Z15)t}X<9FHczTT;DAR@J^C`|Z07yl^wHR8ZHT zzhfvxa;;M8_QY%A(xXhT4046% zeeJh8Y;ne%B-6f-_WO(jMthRGI}$j@<>LKufSf?;5mq{(m7v$#t zkxaUZ@o0BN_3sv_wY5lHald`lT@PpJ`vGRL4_Ra#wJG1!clPk7q-s82?OImjB(sTX z)-$0h^rkw7Ukyvdm@@-icBu5hiVdXH!~$=smSW#nh;t$N)Yg1%X6~(HAaIJ8w25U8 z=P}NX(?ZDqz{uzN4zZ0Xr!b6Pter@00bb`=;OkAercJun!)2s=1&AA2l9J*&{upal zu;7Gy;thrh76Xj~FJ*6Mv*&$q&5a*+gA;bCgFFT(&}Ap|G3wFqu;n$SF=1dN9p(Rz z7_CbL8y6*r?SAPFU-RYFxli=lE1*Kn9EK7*=29GEtu~YJan8=HB)B4H{1SW|3VXw@ zgK00Y^81w76q}xdbmcF|GtKYqJ-m+tyT0{*&!s-ZI%;=awPaHDmSP&Uc~zd?Y-ilL z`6$+}CR5;m97ToS)%c)6sI%i%cZNLsZ~K@i_s`j?wS~)Z_?}txuJOX#dVafh{2XVb z4_dG$OGRqopS-41mw< zm)MI*nd>Y6A34%mBFVf}tJKcDqxWB8WUFMpB0Bxb+RIH0W>VDS=2{VtHC+HhqLD5u zp#S`dZUCU`zB>G>YI+QSUD7@hQ%P_pa9UZWLic7DX^~@D6~5Eaq4bt<;MS`2;kJktn606E@#3rV{jyZV(xj z^Xd9jein@8=O-yk*;C9IIoSkKPNHwVyt#w2hgRvd{F`-;R~#FfAdWk$oDeOxSol21 zYXO}9!y>;5I$A8Vi*W?mMCZEb+5uBm6XOwv#EZQ|RZ3!Wk&wb&ayjw#MB2Y5Trlta ztO{K&U2-wHmHn?8jLLW9vJ4~o@pFBCtL1t*Wf%B=S7!ZoTl_xApHb~ijEyqbKT{_j zvHwkB=IY=ceyptQs?D{f6@F;AMu9Df2vwTR>Jm>Gydl=5m<-} z8o=)F2vk`+0D$RxHS_y`tJlcRAqosf4Ip{YO&st$yGOUUN%VZ@T#$=f;wN6a9?7;t zL}%GBSl_aQ@9@n@XmAA(qSD=sGNp+SX0>w4F)(e{a!I&_j(R9!^Zko2_h}Sk(@njD zyi1$UZlb>m8geZI90vB|C!!_Z!ILS;-6ON}p2NKPQO1WKjKAkb#~ZHS`?|-c&>&cf zdD`B@1jhYaTcmY0*oAcOHaVNz-Vx~h6dIT+Dzvk^`vr26aAgeb#0z7 z(rRsZY>e60_jn!?>VM25%o5AXb#^xFXvoCzHm<{Vo-^ajrRIB!<-E*Fiwx{YQF++^ zaKcF#1X-juOHfdb7es^RMGXIinii9wR`KY!(Hhs)GOrBH>diD?Kgb~L0*_!V>yB!d zpe%~F$y|RkuW(H4 zny*DIN0F<*M&8FhY*^GI%L=;zVfJ0o_+6KAC$*LO+LM0d9wzs7s;sE?VAE=-ZuUUa z(OCy(Kbs*jJ_Jb;RfrgPqGAM(-4+^?lTJJl_Z1)A((aV6s$gK7vNB;cx3Y`$il}1z zDQviZcJSoqn{+K}R}i!Grnb6mYyu=IX7JWftcCh`OHQA*KFD}LG^jOjflWR?A3_VA z^Z~Ez8b$10JIwF<)qGA!tNn$fdqYYBT3|$5QAMpvUV}*10eP{eqapo(6+2+bvzlki znj}?myPbU)g66QoxRDrxNQx63F4>A_3L5*|2)F#c68+p#U;d8m_`XDgZkrRE#kM(V zINs#OXC~eQfyg29AQE?0YM^(8t) z5GQHmf1F3X6n`0isa*i^FLe#I9(b_-+pZ^Y3N`^fOlU-!2%F>8$nJdE+eu_F*s}WE z2(I8Xcs>E7doXyw&B>dyyp<4tRk?`d?|3NN-m|t5L2Jsh9ey&oZ!e6XRvnKe2pAH7 zR+Do43CUjNQ>VM(8Tl~Xrls3e$LFuAxNFx-;PvP#t}9^j+UHAa=5uo+;#*0lE#Scy zjZYGLf+!@K!FM0EFf7w<5X10(>%p?P|4%Ul9dA0@{(YWISsg30I$`om4PHzd(z5^_ zp5f+GaMfpiKh*9L0H-_EZ$5Nyx`z@ERHXPhU?a5arr5p@5APhC8z&zOTK=xJs;2t> zE>$3`44}CUbr)w*uViTvx*(s~&8Yl8u3A#(49Twn2o9) zZ)ir{c`YTgevVXYN=0nf9tFub@4DSsB2Xd$LZE1Sgbw&f zibb?NvcnK(Y&AR?56OmA8;T7q^;0_*W9AGN&fGIG)kXaIfHr3V257J-`sH-*NX+yF z6&TwkQ>^$j(o&HW+d3*5XL8ZL2{24;=SnLQ&T!n`3u)@l!aX>Jernj3%V<)jJI`zy z2|F-YfSUVBq9fdI$ng&=W3k=yF4B17-(yW|JR$B^ceG7A8S}NrG4_q0_)Fx#@8ADWlFjBx6Q6xHvE=93QY{Le~MjfI4I&>B)&t^ zL>tm?Lj54JAHZ zdNDkK%&xY*O@pcXNmqp^X(-~cjl88mhcHI)DV+M}BmzGYN zUY&DlHW9NefBLfpwrAaCgu+UT82G*?Ena0Tq4k)w3-!4AxhquB{;c?Ke8<%|J?s~| zYvRE=8_mPNA`1GtAUg$<>a-VJMmX>Ty0f#lUUe2&SoBMJuy! zd;|5a=!n-;f^r@ionh-o%qMBM=r~YpZekP@I;$P~3~`&^<4-j3pBlZxD0SYXL74@hyyI*9>~~*tI5M7ZMwqGpy!Iajg zO`2P2xFF7tO5A;V`(*K{y3-+0_lx0YNqG-lMUOUNLpgsa>HN@-i@E-Q90BXP0lZ~> zAl6YNr*ZbpJxH3jw!R*of%%A7A5niIyq_PWA*_k^;~-j!I%>D|ZNCv>OoB5Y}cIt2uQI9jBJ`f!R1a zj4G})f^^a!C4eWoUmq5}w(s4)^Cr8PR8yWtEd z^`L`HExVqXB+&DokF3TtpVJKu0Sb zYZZ9^3=7v>h){$l>k?LJJbv`>Vj~9?HVM9{=2E9H~iGjIgq64O1*=7g@}1c9}Qd?zEG z`^h%g^M@X3UcF?Ew<(r~==cJa6{-pwp@zA$^&R3LNiDim3>?SIRC|sOl*vhSd+|FO z#ZOZMJ1dVlb^e^X>c$jC4}XFW4XcqOV{@wYtC5dciTThwtvxU5D{0puIO)>04ZNdI zkS)y#jjuiw{RF|5HShm{EmJM7p$(@vE>8W%`@_~=npo%Fy}L7h8}{`Hz_tVa_yXSQ zE+*@^;m8B1mjPO!_zM75i5GkFM~I8lw`ktRD*-N?c-ARN@6C;BSGsK`Sg9L?^diwa ztL;LEh3mfaMQ*EEZM*z}6nYXVb@|%5UklV2T_|}Cl|%R3m1!yfVzApuxc3p70u)e7 zG~E-VNlWj@Cmv^9CmL3`3ZuQkKiQZZAQ1z+Vc;y~IUCwTFp@jZ2}PJOI3+uQ8qxH( z5T@=Y=8LD71rlsT({mGOi1)i{dT+2T?P2RJEjAs!)jyq3Zy@dRVLcWAB+;9VV&b6yV7sx(-ReSEGc&)sMtrfDsdRjjncw?OOGaj9pjk3++_*St!HbJHc(FyT`mwC9lyM1LR0)T|jljw}uq)1j=OJ-sj-)K`rpqVsdt?QwvG{85(^>h>MchcMUv;Bfc%WX$caRhjs+b zW-|!o;c7wnx-SP&g@jDJ?)q95&-93wYq3vaiM;_wR%I1GD{)epDnV1AEZWF1PrJvb z;kr3CNpaozol0Qg2bhm(`IlT&=;q{1zrOYZT$b9;q4Eb76$=7iE_VECts0fTf~bbt z2#tLhfjnrScqhQdasMDco-R76dS%e$;I>5-6CJuFuzG?gH1Y#>WVAC36 z^Q1N>5Y-t^cifsAHgkU?7X79AhPU{n1^JP4?*WH=&zGZQ=~mNC&ed?ulJdj=R@7L< zoGpW%c)w`AE zwpt!ybOlCN<9QTgh`)8IP$wTXKL&1#wjEbAAHqI#7K=Zorzalx=9Meyv=)~y}b87m1a{X%*m$z@DH=ZBlF>< z5=Q@p)4ePo7Im;=Tyu}>_fX6-yvYrJIYn{IS#qDjziCGREs6QIf9f}*M}y#F%)>xw{|N-A0nKT7W-MlgU32^EtWNVO*v-!+rqM<|H4KoSgiDOpz2t<~)RY9NIg7BE@;^jRlj} zP>VmmxPA(a0zuPE?zx_@Ga&BY5wsuG0P3Mc!;b@hWv$x0eVXd`=I}0|?Vd^1v2`HS zb;q={Dn~Sub&)1;Qf}!*sx~;jm~$gB9(+oZ`mx@CwJm!#7;sI@gRiY_?*6f09zAl4 zbamSgK^4!t#tx%qI5=+c6N+mXpL$6LR@_4&Q7Fgr=}doCI|O2hFtT&b%UiXsqObbP z`^{YYu6#v7LWz|tW!{~scZwM{TvT9mz+T{+0g4e?Nd(_|f;aC_ZYFy+NI1`$cigJmWNTi65mVkP7DPTw4Xvc~;b)dS1X232z7CxfDgI zCnt6hL1jEtxq~uCl5g}VbisdLjNGe285ni{0$OoNfq#M=XtPtPB$$yICnu?QCge@N zKr@g#AU`sG7s`+1#qf3g3)wshe9T$^K00;jcGK)YcP`Y0%+a$M=A{uf?R5zp*kakg z#d+IVuma3kyH#r)uYUe^yK?!Bj_zlZ1SWJ@$sEW+Gb51DygJg${Z~hOzpcSn5p7cO z=*n!wFW=v*#Ii03SxicM1D$y#Z2d7E*C*70G55itkKCb@0`h zq6_0|3!aIosoP>shR1uEp1EOD7IgtthWPmS>Ymm&eGMKNBK6}@DVd55g51TsFz281 zJqmyyJWTI>qi2MyRD*cso5q5opl4O^|G=*MhiTE#K37soet=6r8Cd(BCKt51xzzUT^?^;Py;^yIyF zBD{Vokg(kR&3lK^%?V|kbx{L@VZ;hq6S4ThK0zKEEKOkJ;jK;f5kGL&KNJAfzYIdX}Tx4oK?R(DG zGpzLX0ykeHXeBGIQm@8w%SI~a6-Ebn6#wegis*UzGaY}<(RTjtgNAp10NNd^o^>3+ zrfu=dW#>O6MWa;OJqO-3-_!(FgqrZhITpFKbu47}LILiv!hgYOa)6=y4HdDt$i1_d zJpF<%17!Q0R@N6tRTdORgAT7>F5=^osL$?(Gf?Op15`-zF$ds7fc~%cxGwoKpzk!! z;9l8jr)i|M;xzna3u}HW!_d$7i&c5nbN3n6w);!mg|_k+bSj-MfL#l6uL}OyG>i+U z-n2oU+S*b6=cr1@27i#|FF**+F}BK?q+*&KT)Dzp? zC_?mhA*w( zudAG=a3w~I&>AJ090Y2ZxbIVA0Df}Dyt=?(SB4WS6`IO}Dbkq1J))>XGX`77L% zW#+@SxUrpi-@1WwYWUal*x|q0;rP>IeD}bT;TRq+l=A3s|Cmo<4rns55QsL@q;aoVRM zm2m@FH_zceqbKd3HFIL8N!VQ+tHV9S2$jt1As;FWN?VZi0Bd6db{0H4uTlV>a+%m> z_m2^Zqzb^e!&Akx5Q{~S0}A`no@l`7x1WMQ*so$ZQKoEoI4$7y)giVSVbFxqnSDY`daC(~7rRl{7s(ww#&w zf}Z1ml1$p13-SlS;_jarBNfgg<6lSa?zzc2>2cgm

    >v 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

    TpmF)(WlcY)bxmfx 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 ### :clap: 正例: 一个包含三部分的用例名 -![alt text](/assets/bp-1-3-parts.jpeg "A test name that constitutes 3 parts") +![alt text](/assets/zh-CN/bp-1-3-parts.jpg "A test name that constitutes 3 parts")

  • +4QB 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 literal 0 HcmV?d00001 diff --git a/assets/zh-CN/bp-12-rich-testing.jpg b/assets/zh-CN/bp-12-rich-testing.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d7eb34fe56e75720f936a15037f5311722ca03ad GIT binary patch literal 78756 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%0DUiqibSwBgF=XiIPPqo2f20c7Mj0vC;yrLoMtoQ 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

    @@ -732,7 +732,7 @@ describe('Order service', function() {
    ### :clap: 正例: Cindy Sridharan 在她的文章“测试微服务——理智的方式”中提出了一个丰富的测试组合 -![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") +![alt text](assets/zh-CN/bp-12-rich-testing.jpg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") ☺️Example:
    [YouTube: “Beyond Unit Tests: 5 Shiny Node.JS Test Types (2018)” (Yoni Goldberg)](https://www.youtube.com/watch?v=-2zP494wdUY&feature=youtu.be) @@ -770,7 +770,7 @@ describe('Order service', function() { ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Jest") -![alt text](assets/bp-13-component-test-yoni-goldberg.png " [Supertest](https://www.npmjs.com/package/supertest) allows approaching Express API in-process (fast and cover many layers)") +![alt text](assets/zh-CN/bp-13-component-test-yoni-goldberg.png " [Supertest](https://www.npmjs.com/package/supertest) allows approaching Express API in-process (fast and cover many layers)")
    @@ -797,7 +797,7 @@ describe('Order service', function() { ![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") -![alt text](assets/bp-14-testing-best-practices-contract-flow.png ) +![alt text](assets/zh-CN/bp-14-testing-best-practices-contract-flow.png )
    @@ -1674,7 +1674,7 @@ it("Test addNewOrder, don't use such test names", () => { ### :clap: 正例: Stryker 报告,一个编译测试工具,发现并统计没有被测试到的代码(变异) -![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations)") +![alt text](assets/zh-CN/bp-20-yoni-goldberg-mutation-testing.jpg "Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations)")
    From dbab226a9b0a62f19d1800ecf0a6f4a2ebfe86df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=9B=AA=E6=B6=9B?= <99980283> Date: Thu, 14 Apr 2022 17:23:20 +0800 Subject: [PATCH 130/189] doc: readme-zh-CN.md part 4.2 no image --- readme-zh-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme-zh-CN.md b/readme-zh-CN.md index 37f8dd7d..18b3ee5f 100644 --- a/readme-zh-CN.md +++ b/readme-zh-CN.md @@ -1625,7 +1625,7 @@ describe('visual validation', () => { ### :thumbsdown: 反例: 这份覆盖率报告有什么问题?基于一个真实的场景,我们跟踪了 QA 中的应用程序使用情况,并发现了一些有趣的登录模式(提示:登录失败的数量是不成比例的,有些地方显然有问题。最终表现为一些前端的 bug 不断触发后端登录API) -![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report? based on a real-world scenario where we tracked our application usage in QA and find out interesting login patterns (Hint: the amount of login failures is non-proportional, something is clearly wrong. Finally it turned out that some frontend bug keeps hitting the backend login API) +![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report? based on a real-world scenario where we tracked our application usage in QA and find out interesting login patterns (Hint: the amount of login failures is non-proportional, something is clearly wrong. Finally it turned out that some frontend bug keeps hitting the backend login API")
    From a88a8023e64d8ff5a2442a72a4ee24c1a047b451 Mon Sep 17 00:00:00 2001 From: Drew Wilson Date: Thu, 14 Apr 2022 12:39:35 -0400 Subject: [PATCH 131/189] Adds section number `1.9` to heading for Copy code section so it matches the pattern of the other section headings --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index f5123694..66bce7ea 100644 --- a/readme.md +++ b/readme.md @@ -536,7 +536,7 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => {

    -## ⚪ ️Copy code, but only what's neccessary +## ⚪ ️ 1.9 Copy code, but only what's neccessary :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 mention explictly 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.
    From 77c1eb687e47db37d266563d706f7220cf3d128b Mon Sep 17 00:00:00 2001 From: ramon Date: Thu, 21 Apr 2022 20:50:55 +0200 Subject: [PATCH 132/189] Fix typo in the Spanish translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces "grabes" by the adjective "graves" which means "serious", in this context "but some of the worst things that happen" Translation: "pero los errores más grabes". The word "grabes" does not make sense in this context, as it is the 2nd present indicative conjugation of verb "to record". --- readme-es.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme-es.md b/readme-es.md index 3325f51b..c80b14b5 100644 --- a/readme-es.md +++ b/readme-es.md @@ -893,7 +893,7 @@ Crédito: {

    -## ⚪ ️Copy code, but only what's neccessary +## ⚪ ️ 1.9 Copy code, but only what's neccessary :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 mention explictly 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.
    @@ -1023,9 +1023,10 @@ beforeEach(() => { id: 1, name: 'John', }); -});``` - +}); +```
    +
    ## ⚪ ️2.10 Test the response schema, mostly when there are auto-generated fields @@ -1062,7 +1063,7 @@ beforeEach(() => {
    -## ⚪ ️2.12 Check integrations corner cases and chaos +## ⚪ ️2.11 Check integrations corner cases and chaos :white_check_mark: **Do:** When checking integrations, go beyond the happy and sad paths. Check not only errored 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 @@ -1108,7 +1109,7 @@ beforeEach(() => {
    -## ⚪ ️2.13 Test the five potential outcomes +## ⚪ ️2.12 Test the five potential outcomes :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/reactions can be put in 5 categories: From 3f224c1439aec11d0b3815d7b7d70b95d5399af1 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 2 May 2022 01:38:43 +0200 Subject: [PATCH 134/189] Update readme-pl.md Initial changes & updates preparation --- readme-pl.md | 301 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 242 insertions(+), 59 deletions(-) diff --git a/readme-pl.md b/readme-pl.md index 499f5e9d..42d31596 100644 --- a/readme-pl.md +++ b/readme-pl.md @@ -1,12 +1,14 @@ +## 🎊 Ogłoszenie - Kwiecień 2022: Właśnie ukazała się nowa edycja z 5 nowymi najlepszymi praktykami, wieloma przykładami kodu i 4 nowymi tłumaczeniami językowymi +
    # 👇 Powody dla których ten przewodnik może przenieść twoje umiejętności testowania na wyższy poziom
    -## 📗 46+ najlepszych praktyk: super kompleksowe i wyczerpujące +## 📗 50+ najlepszych praktyk: super kompleksowe i wyczerpujące Jest to przewodnik po niezawodności JavaScript i Node.js od A-Z. Podsumowuje i przygotowuje dla Ciebie dziesiątki najlepszych postów na blogu, książek i narzędzi dostępnych na rynku @@ -33,6 +35,11 @@ Zacznij od zrozumienia wszechobecnych praktyk testowania, które są podstawą k - 🇨🇳[Chinese](readme-zh-CN.md) - dzięki uprzejmości [Yves yao](https://github.com/yvesyao) - 🇰🇷[Korean](readme.kr.md) - dzięki uprzejmości [Rain Byun](https://github.com/ragubyun) - 🇵🇱[Polish](readme.pl.md) - dzięki uprzejmości [Michal Biesiada](https://github.com/mbiesiad) +- - 🇪🇸[Spanish](readme-es.md) - dzięki uprzejmości [Miguel G. Sanguino](https://github.com/sanguino) +- 🇧🇷[Portuguese-BR](readme-pt-br.md) - dzięki uprzejmości [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) oraz [koooge](https://github.com/koooge) +- 🇫🇷[French](readme-fr.md) - dzięki uprzejmości [Mathilde El Mouktafi](https://github.com/mel-mouk) +- 🇯🇵[Japanese (draft)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - dzięki uprzejmości [Yuichi Yogo](https://github.com/yuichkun) oraz [ryo](https://github.com/kawamataryo) +- 🇹🇼[Traditional Chinese](readme-zh-TW.md) - dzięki uprzejmości [Yubin Hsu](https://github.com/yubinTW) - Chcesz przetłumaczyć na swój język? Proszę skorzystaj z issue 💜

    @@ -41,7 +48,7 @@ Zacznij od zrozumienia wszechobecnych praktyk testowania, które są podstawą k #### [`Sekcja 0: Złota zasada`](#sekcja-0️⃣-złota-zasada) -Jedna rada, która inspiruje wszystkich innych (1 specjalny punkt) +Jedna rada, która inspiruje wszystkie inne (1 punkt specjalny) #### [`Sekcja 1: Anatomia testu`](#sekcja-1-anatomia-testu-1) @@ -49,7 +56,7 @@ Podstawa - konstruowanie czystych testów (12 wypunktowań) #### [`Sekcja 2: Backend`](#sekcja-2️⃣-backend-testing) -Pisanie backendu i wydajne testy Mikroserwisów (8 wypunktowań) +Pisanie backendu i wydajne testy mikroserwisów (13 wypunktowań) #### [`Sekcja 3: Frontend`](#sekcja-3️⃣-frontend-testing) @@ -57,7 +64,7 @@ Pisanie testów dla webowego interfejsu użytkownika, w tym testy komponentów i #### [`Sekcja 4: Pomiary skuteczności testów`](#sekcja-4%EF%B8%8F%E2%83%A3-pomiar-skuteczno%C5%9Bci-testu) -Watching the watchman - pomiar jakości testu (4 wypunktowania) +Pilnowanie strażnika - pomiar jakości testu (4 wypunktowania) #### [`Sekcja 5: Continuous Integration`](#sekcja-5️⃣-ci-oraz-inne-miary-jakości) @@ -72,7 +79,7 @@ Wytyczne dla CI w świecie JS (9 wypunktowań) ## ⚪️ 0 Złota zasada: Projektowanie dla lean testing :white_check_mark: **Opis:** -Testowany kod nie przypomina kodu produkcyjnego - zaprojektuj go tak, by był prosty, krótki, pozbawiony abstrakcji, płaski, przyjemny w pracy, lean. Trzeba spojrzeć na test i natychmiast uzyskać cel. +Kod testowy nie jest kodem produkcyjnym - zaprojektuj go tak, aby był krótki, śmiertelnie prosty, płaski i przyjemny w pracy. Należy spojrzeć na test i natychmiast uzyskać intencję. Nasz umysł jest przepełniony głównym kodem produkcyjnym, nie mamy 'przestrzeni roboczej' na dodatkową złożoność. Jeśli spróbujemy wcisnąć kolejny trudny kod do naszego słabego mózgu, spowolni to pracę zespołu, co działa wbrew temu, co testujemy. W praktyce wiele zespołów po prostu rezygnuje z testów. @@ -518,12 +525,12 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => {

    -## ⚪ ️1.9 Unikaj globalnych test fixture i seeds, dodawaj dane na test +## ⚪ ️1.9 Kopiuj kod, ale tylko to, co niezbędne -:white_check_mark: **Opis:** Kierując się złotą zasadą (punkt 0), każdy test powinien dodawać i działać na swoim własnym zestawie wierszy BD, aby zapobiec sprzężeniu i łatwo uzasadnić przebieg testu. W rzeczywistości jest to często naruszane przez testerów, którzy zapełniają bazę danych danymi przed uruchomieniem testów ([znany również jako ‘test fixture’](https://en.wikipedia.org/wiki/Test_fixture)) w celu poprawy wydajności. Chociaż wydajność jest istotnym problemem - można ją złagodzić (patrz punkt „Testowanie komponentów”), jednak złożoność testów jest bardzo bolesnym smutkiem, który powinien rządzić innymi względami przez większość czasu. Praktycznie spraw, aby każdy przypadek testowy wyraźnie dodał potrzebne rekordy BD i działał tylko na tych rekordach. Jeśli wydajność stanie się kluczowym problemem - zrównoważony kompromis może przyjść w postaci inicjowania jedynego zestawu testów, które nie powodują mutacji danych (np. zapytania) +:white_check_mark: **Opis:** Dołącz wszystkie niezbędne szczegóły, które wpływają na wynik testu, ale nic więcej. Jako przykład rozważ test, który powinien rozłożyć na czynniki 100 wierszy wejściowego JSON - wklejanie tego w każdym teście jest nużące. Wyodrębnienie go na zewnątrz do transferFactory.getJSON() spowoduje, że test będzie niejasny. Bez danych trudno jest skorelować wynik testu z przyczyną („dlaczego ma zwracać status 400?”). Klasyczna książka wzorców x-unit nazwała ten wzorzec „tajemniczym gościem” - coś niewidocznego wpłynęło na wyniki naszych testów, nie wiemy co dokładnie. Możemy zrobić lepiej, wyodrębniając powtarzalne długie części na zewnątrz ORAZ wyraźnie wspomnij, które konkretne szczegóły mają znaczenie dla testu. Idąc z powyższym przykładem, test może przekazać parametry, które podkreślają to, co jest ważne: transferFactory.getJSON({sender: undefined}). W tym przykładzie czytelnik powinien natychmiast wywnioskować, że puste pole nadawcy jest powodem, dla którego test powinien oczekiwać błędu walidacji lub innego podobnego odpowiedniego wyniku.
    -❌ **W przeciwnym razie:** Niewiele testów kończy się niepowodzeniem, wdrożenie zostało przerwane, nasz zespół spędza teraz cenny czas, czy mamy błąd? Zbadajmy, och nie - wydaje się, że dwa testy mutowały te same dane seed +❌ **W przeciwnym razie:** Kopiowanie 500 wierszy JSON spowoduje, że Twoje testy nie będą mogły być konserwowane i będą nieczytelne. Wyniesienie wszystkiego na zewnątrz zakończy się niejasnymi testami, które są trudne do zrozumienia
    @@ -531,49 +538,46 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => {
    -### :thumbsdown: Przykład antywzorca: testy nie są niezależne i polegają na pewnym globalnym hook do zasilania globalnych danych BD +### :thumbsdown: Przykład antywzorca: niepowodzenie testu jest niejasne, ponieważ cała przyczyna jest zewnętrzna i ukryta w ogromnym formacie JSON -![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Przykłady z Mocha") ```javascript -before(() => { - //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework - await DB.AddSeedDataFromJson('seed.json'); -}); -it("When updating site name, get successful confirmation", async () => { - //I know that site name "portal" exists - I saw it in the seed files - const siteToUpdate = await SiteService.getSiteByName("Portal"); - const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); - expect(updateNameResult).to.be(true); -}); -it("When querying by site name, get the right site", async () => { - //I know that site name "portal" exists - I saw it in the seed files - const siteToCheck = await SiteService.getSiteByName("Portal"); - expect(siteToCheck.name).to.be.equal("Portal"); //Failure! The previous test change the name :[ -}); +test("When no credit, then the transfer is declined", async() => { + // Arrange + const transferRequest = testHelpers.factorMoneyTransfer() //get back 200 lines of JSON; + const transferServiceUnderTest = new TransferService(); + + // Act + const transferResponse = await transferServiceUnderTest.transfer(transferRequest); + // Assert + expect(transferResponse.status).toBe(409);// But why do we expect failure: All seems perfectly valid in the test 🤔 + }); ```
    -### :clap: Przykład robienia tego dobrze: Możemy pozostać w teście, każdy test działa na własny zestaw danych +### :clap: Przykład poprawny: Test wskazuje, co jest przyczyną wyniku testu ```javascript -it("When updating site name, get successful confirmation", async () => { - //test is adding a fresh new records and acting on the records only - const siteUnderTest = await SiteService.addSite({ - name: "siteForUpdateTest" - }); - const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); +test("When no credit, then the transfer is declined ", async() => { + // Arrange + const transferRequest = testHelpers.factorMoneyTransfer({userCredit:100, transferAmount:200}) //obviously there is lack of credit + const transferServiceUnderTest = new TransferService({disallowOvercharge:true}); - expect(updateNameResult).to.be(true); -}); -``` + // Act + const transferResponse = await transferServiceUnderTest.transfer(transferRequest); + + // Assert + expect(transferResponse.status).toBe(409); // Obviously if the user has no credit it should fail + }); + ```
    -
    +

    ## ⚪ ️ 1.10 Nie wychwytuj błędów, oczekuj ich @@ -951,6 +955,164 @@ it("When updating site name, get successful confirmation", async () => {
    +
    + +## ⚪ ️2.8 Choose a clear data clean-up strategy: After-all (recommended) or after-each + +: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. + +The 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://github.com/testjavascript/nodejs-integration-tests-best-practices/blob/master/graphics/db-clean-options.png). +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :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 + +```javascript + // After-all clean up (recommended) +// global-teardown.js +module.exports = async () => { + // ... + if (Math.ceil(Math.random() * 10) === 10) { + await new OrderRepository().cleanup(); + } +}; +``` + +
    + +
    + +## ⚪ ️2.9 Isolate the component from the world using HTTP interceptor + +: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 +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :clap: Preventing network calls to externous components allows simulating scnearios and minimizing the noise + +```javascript +// Intercept requests for 3rd party APIs and return a predefined response +beforeEach(() => { + nock('http://localhost/user/').get(`/1`).reply(200, { + id: 1, + name: 'John', + }); +}); +``` +
    +
    + +## ⚪ ️2.10 Test the response schema, mostly when there are auto-generated fields + +: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. + + +
    + +❌ **Otherwise:** Although the code/API caller relies on some field with dynamic data (e.g., ID, date), it will not come in return and break the contract + +
    + +
    Code Examples + +
    + +### :clap: Asserting that fields with dynamic value exist and have the right type + +```javascript + test('When adding a new valid order, Then should get back approval with 200 response', async () => { + // ... + //Assert + expect(receivedAPIResponse).toMatchObject({ + status: 200, + data: { + id: expect.any(Number), // Any number satisfies this test + mode: 'approved', + }, + }); +}); +``` + +
    + +
    + +## ⚪ ️2.11 Check integrations corner cases and chaos + +:white_check_mark: **Do:** When checking integrations, go beyond the happy and sad paths. Check not only errored 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 + + +
    + +❌ **Otherwise:** All your tests pass, it's only the production who will crash or won't report errors correctly when 3rd parties send excpetional responses + +
    + +
    Code Examples + +
    + +### :clap: Ensuring that on network failures, the circuit breaker can save the day + +```javascript + test('When users service replies with 503 once and retry mechanism is applied, then an order is added successfully', async () => { + //Arrange + nock.removeInterceptor(userServiceNock.interceptors[0]) + nock('http://localhost/user/') + .get('/1') + .reply(503, undefined, { 'Retry-After': 100 }); + nock('http://localhost/user/') + .get('/1') + .reply(200); + const orderToAdd = { + userId: 1, + productId: 2, + mode: 'approved', + }; + + //Act + const response = await axiosAPIClient.post('/order', orderToAdd); + + //Assert + expect(response.status).toBe(200); +}); +``` + +
    + +
    + + +## ⚪ ️2.12 Test the five potential outcomes + +: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/reactions can be put in 5 categories: + +• 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 + +• A new state - After invoking an action, some **publicly accessible** data is probably modified + +• 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 + +• Message queues - The outcome of a flow might be a message in a queue + +• 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/metrics. This information goes directly to a very important user - The ops user (i.e., production SRE/admin) + +
    +

    # Sekcja 3️⃣: Frontend Testing @@ -1918,38 +2080,59 @@ Podziękowania dla tych wspaniałych ludzi, którzy przyczynili się do tego rep - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - + + + +

    Scott Davis

    🖋

    Adrien REDON

    🖋

    Stefano Magni

    🖋

    Yeoh Joer

    🖋

    Jhonny Moreira

    🖋

    Ian Germann

    🖋

    Hafez

    🖋

    Scott Davis

    🖋

    Adrien REDON

    🖋

    Stefano Magni

    🖋

    Yeoh Joer

    🖋

    Jhonny Moreira

    🖋

    Ian Germann

    🖋

    Hafez

    🖋

    Ruxandra Fediuc

    🖋

    Jack

    🖋

    Peter Carrero

    🖋

    Huhgawz

    🖋

    Haakon Borch

    🖋

    Jaime Mendoza

    🖋

    Cameron Dunford

    🖋

    John Gee

    🖋

    Aurelijus Rožėnas

    🖋

    Aaron

    🖋

    Tom Nagle

    🖋

    Yves yao

    🖋

    Userbit

    🖋

    Glaucia Lemos

    🚧

    Ruxandra Fediuc

    🖋

    Jack

    🖋

    Peter Carrero

    🖋

    Huhgawz

    🖋

    Haakon Borch

    🖋

    Jaime Mendoza

    🖋

    Cameron Dunford

    🖋

    koooge

    🖋

    Michal

    🖋

    roywalker

    🖋

    dangen

    🖋

    biesiadamich

    🖋

    Yanlin Jiang

    🖋

    sanguino

    🖋

    John Gee

    🖋

    Aurelijus Rožėnas

    🖋

    Aaron

    🖋

    Tom Nagle

    🖋

    Yves yao

    🖋

    Userbit

    🖋

    Glaucia Lemos

    🚧

    Morgan

    🖋

    Lukas Bischof

    ⚠️ 🖋

    JuanMa Ruiz

    🖋

    Luís Ângelo Rodrigues Jr.

    🖋

    José Fernández

    🖋

    Alejandro Gutierrez Barcenilla

    🖋

    Jason

    🖋

    koooge

    🖋

    Otavio Araujo

    ⚠️ 🖋

    Alex Ivanov

    🖋

    Yiqiao Xu

    🖋

    YuBin, Hsu

    🌍 💻
    - + From 87514dbe622f1abf227d57f329e833fae97cdb70 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 2 May 2022 01:39:43 +0200 Subject: [PATCH 135/189] Update readme-pl.md Quick fix for Spanish --- readme-pl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme-pl.md b/readme-pl.md index 42d31596..74f20436 100644 --- a/readme-pl.md +++ b/readme-pl.md @@ -35,7 +35,7 @@ Zacznij od zrozumienia wszechobecnych praktyk testowania, które są podstawą k - 🇨🇳[Chinese](readme-zh-CN.md) - dzięki uprzejmości [Yves yao](https://github.com/yvesyao) - 🇰🇷[Korean](readme.kr.md) - dzięki uprzejmości [Rain Byun](https://github.com/ragubyun) - 🇵🇱[Polish](readme.pl.md) - dzięki uprzejmości [Michal Biesiada](https://github.com/mbiesiad) -- - 🇪🇸[Spanish](readme-es.md) - dzięki uprzejmości [Miguel G. Sanguino](https://github.com/sanguino) +- 🇪🇸[Spanish](readme-es.md) - dzięki uprzejmości [Miguel G. Sanguino](https://github.com/sanguino) - 🇧🇷[Portuguese-BR](readme-pt-br.md) - dzięki uprzejmości [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) oraz [koooge](https://github.com/koooge) - 🇫🇷[French](readme-fr.md) - dzięki uprzejmości [Mathilde El Mouktafi](https://github.com/mel-mouk) - 🇯🇵[Japanese (draft)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - dzięki uprzejmości [Yuichi Yogo](https://github.com/yuichkun) oraz [ryo](https://github.com/kawamataryo) From 592224962b1a2c4b07b894f2021fa5fb2aee11c1 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 2 May 2022 15:39:07 +0200 Subject: [PATCH 136/189] Update readme-pl.md Update for new added recently subpoints --- readme-pl.md | 56 ++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/readme-pl.md b/readme-pl.md index 74f20436..b53df5ef 100644 --- a/readme-pl.md +++ b/readme-pl.md @@ -957,22 +957,22 @@ it("When updating site name, get successful confirmation", async () => {
    -## ⚪ ️2.8 Choose a clear data clean-up strategy: After-all (recommended) or after-each +## ⚪ ️2.8 Wybierz przejrzystą strategię czyszczenia danych: po wszystkim (zalecane) lub po każdym -: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. +:white_check_mark: **Opis:** Moment, w którym testy czyszczą bazę danych, określa sposób pisania testów. Dwie najbardziej opłacalne opcje to czyszczenie po wszystkich testach i czyszczenie po każdym teście. Wybierając tę drugą opcję, czyszczenie po każdym teście gwarantuje czyste tabele i buduje wygodne korzyści testowe dla programisty. Na początku testu nie istnieją żadne inne rekordy, można mieć pewność, które dane są odpytywane, a nawet można pokusić się o zliczenie wierszy podczas asercji. Ma to poważne wady: podczas uruchamiania w trybie wieloprocesowym testy prawdopodobnie będą ze sobą kolidować. Podczas gdy proces-1 czyści tabele, w tej chwili proces-2 wysyła zapytania o dane i kończy się niepowodzeniem (ponieważ baza danych została nagle usunięta przez proces-1). Ponadto trudniej jest rozwiązywać problemy z testami zakończonymi niepowodzeniem — odwiedzenie bazy danych nie spowoduje wyświetlenia żadnych rekordów. -The 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://github.com/testjavascript/nodejs-integration-tests-best-practices/blob/master/graphics/db-clean-options.png). +Drugą opcją jest czyszczenie po zakończeniu wszystkich plików testowych (lub nawet codziennie!). Takie podejście oznacza, że ta sama baza danych z istniejącymi rekordami obsługuje wszystkie testy i procesy. Aby uniknąć nadepnięcia sobie nawzajem na palce, testy muszą dodawać i działać na określonych rekordach, które dodały. Chcesz sprawdzić, czy dodano jakiś rekord? Załóżmy, że istnieją inne tysiące rekordów i zapytaj o rekordy, które zostały dodane jawnie. Chcesz sprawdzić, czy rekord został usunięty? Nie można założyć, że tabela jest pusta, sprawdź, czy nie ma tam tego konkretnego rekordu. Ta technika przynosi kilka potężnych korzyści: działa natywnie w trybie wieloprocesowym, gdy programista chce zrozumieć, co się stało — dane są tam i nie są usuwane. Zwiększa również szansę na znalezienie błędów, ponieważ baza danych jest pełna rekordów i nie jest sztucznie opróżniona. [Zobacz pełną tabelę porównawczą tutaj](https://github.com/testjavascript/nodejs-integration-tests-best-practices/blob/master/graphics/db-clean-options.png).
    -❌ **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 +❌ **W przeciwnym razie:** Bez strategii oddzielania rekordów lub czyszczenia — testy będą stąpać po sobie nawzajem; Korzystanie z transakcji będzie działać tylko w przypadku relacyjnych baz danych i może się skomplikować, gdy pojawią się transakcje wewnętrzne
    -
    Code Examples +
    Przykłady kodu
    -### :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 +### :clap: Czyszczenie po WSZYSTKICH testach. Niekoniecznie po każdym uruchomieniu. Im więcej danych mamy w trakcie testów - tym bardziej przypomina to profity produkcyjne ```javascript // After-all clean up (recommended) @@ -989,20 +989,20 @@ module.exports = async () => {
    -## ⚪ ️2.9 Isolate the component from the world using HTTP interceptor +## ⚪ ️2.9 Odizoluj komponent od świata za pomocą interceptora HTTP -: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 +:white_check_mark: **Opis:** Odizoluj testowany składnik, przechwytując wszystkie wychodzące żądania HTTP i dostarczając żądaną odpowiedź, aby interfejs HTTP API współpracownika nie został trafiony. Nock jest doskonałym narzędziem do tej misji, ponieważ zapewnia wygodną składnię do definiowania zachowania usług zewnętrznych. Izolacja jest koniecznością, aby zapobiec szumowi i spowolnieniu działania, ale przede wszystkim aby symulować różne scenariusze i reakcje. Dobry symulator lotu nie polega na malowaniu czystego błękitnego nieba, ale na sprowadzaniu bezpieczeństwa podczas burz i chaosu. Jest to wzmocnione w architekturze mikrousług, w której należy zawsze koncentrować się na jednym komponencie bez angażowania reszty świata. Chociaż możliwe jest symulowanie zachowania usługi zewnętrznej za pomocą dublowania testowego (mockowanie), lepiej nie dotykać wdrożonego kodu i działać na poziomie sieci, aby testy były czysto typu black-box. Wadą izolacji jest nie wykrywanie zmian w komponencie współpracownika i brak zrozumienia nieporozumień między dwiema usługami — pamiętaj, aby zrekompensować to za pomocą kilku testów kontraktowych lub E2E
    -❌ **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 +❌ **W przeciwnym razie:** Niektóre usługi udostępniają wersję fake, która może zostać wdrożona lokalnie przez rozmówcę, zwykle za pomocą Dockera — ułatwi to konfigurację i zwiększy wydajność, ale nie pomoże w symulowaniu różnych odpowiedzi; Niektóre usługi zapewniają środowisko „piaskownicy”, więc prawdziwa usługa zostaje trafiona, ale nie są wyzwalane żadne koszty ani skutki uboczne — zmniejszy to szum związany z konfiguracją usługi innej firmy, ale nie pozwoli również na symulację scenariuszy
    -
    Code Examples +
    Przykłady kodu
    -### :clap: Preventing network calls to externous components allows simulating scnearios and minimizing the noise +### :clap: Zapobieganie połączeniom sieciowym z komponentami zewnętrznymi umożliwia tworzenie scenariuszy symulacji i minimalizowanie szumu ```javascript // Intercept requests for 3rd party APIs and return a predefined response @@ -1016,22 +1016,22 @@ beforeEach(() => {

    -## ⚪ ️2.10 Test the response schema, mostly when there are auto-generated fields +## ⚪ ️2.10 Przetestuj schemat odpowiedzi, głównie w przypadku pól generowanych automatycznie -: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. +:white_check_mark: **Opis:** Gdy nie można potwierdzić konkretnych danych, sprawdź istnienie i typy pól obowiązkowych. Czasami odpowiedź zawiera ważne pola z danymi dynamicznymi, których nie można przewidzieć podczas pisania testu, takie jak daty i rosnące liczby. Jeśli kontrakt API obiecuje, że te pola nie będą miały wartości null i będą zawierać odpowiednie typy, konieczne jest przetestowanie tego. Większość bibliotek asercji obsługuje typy sprawdzania. Jeśli odpowiedź jest mała, sprawdź dane zwrotne i wpisz razem w ramach tego samego potwierdzenia (patrz przykład kodu). Jeszcze jedną opcją jest zweryfikowanie całej odpowiedzi z dokumentem OpenAPI (Swagger). Większość programów uruchamiających testy ma rozszerzenia społeczności, które weryfikują odpowiedzi API w oparciu o ich dokumentację.
    -❌ **Otherwise:** Although the code/API caller relies on some field with dynamic data (e.g., ID, date), it will not come in return and break the contract +❌ **W przeciwnym razie:** Chociaż wywołujący kod/API opiera się na jakimś polu z danymi dynamicznymi (np. ID, data), nie wróci i nie zerwie umowy
    -
    Code Examples +
    Przykłady kodu
    -### :clap: Asserting that fields with dynamic value exist and have the right type +### :clap: Zapewnienie, że pola z wartością dynamiczną istnieją i mają właściwy typ ```javascript test('When adding a new valid order, Then should get back approval with 200 response', async () => { @@ -1051,22 +1051,22 @@ beforeEach(() => {
    -## ⚪ ️2.11 Check integrations corner cases and chaos +## ⚪ ️2.11 Sprawdź corner cases integracji i chaos -:white_check_mark: **Do:** When checking integrations, go beyond the happy and sad paths. Check not only errored 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 +:white_check_mark: **Opis:** Sprawdzając integracje wyjdź poza happy i sad paths. Sprawdź nie tylko błędne odpowiedzi (np. błąd HTTP 500), ale także anomalie na poziomie sieci, takie jak powolne i przekroczone limity czasu odpowiedzi. Udowodni to, że kod jest odporny i może obsługiwać różne scenariusze sieciowe, takie jak obieranie właściwej ścieżki po przekroczeniu limitu czasu, brak problemów z prądem i czy zawiera wyłącznik umożliwiający ponowną próbę. Renomowane narzędzia przechwytujące mogą z łatwością symulować różne zachowania sieciowe, takie jak gorączkowa usługa, która czasami kończy się niepowodzeniem. Może nawet zdać sobie sprawę, kiedy domyślna wartość limitu czasu klienta HTTP jest dłuższa niż symulowany czas odpowiedzi i natychmiast zgłosić wyjątek limitu czasu, bez czekania
    -❌ **Otherwise:** All your tests pass, it's only the production who will crash or won't report errors correctly when 3rd parties send excpetional responses +❌ **W przeciwnym razie:** Wszystkie twoje testy przechodzą pomyślnie, tylko produkcja ulegnie awarii lub nie będzie poprawnie zgłaszać błędów, gdy strony trzecie wyślą wyjątkowe odpowiedzi
    -
    Code Examples +
    Przykłady kodu
    -### :clap: Ensuring that on network failures, the circuit breaker can save the day +### :clap: Zapewnienie, że w przypadku awarii sieci wyłącznik może uratować sytuację ```javascript test('When users service replies with 503 once and retry mechanism is applied, then an order is added successfully', async () => { @@ -1097,19 +1097,19 @@ beforeEach(() => {
    -## ⚪ ️2.12 Test the five potential outcomes +## ⚪ ️2.12 Przetestuj pięć potencjalnych wyników -: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/reactions can be put in 5 categories: +:white_check_mark: **Opis:** Planując testy, rozważ uwzględnienie pięciu typowych wyników przepływu. Kiedy twój test uruchamia jakąś akcję (np. wywołanie API), dzieje się reakcja, dzieje się coś znaczącego i wzywa do testowania. Pamiętaj, że nie dbamy o to, jak wszystko działa. Skupiamy się na wynikach, rzeczach, które są zauważalne z zewnątrz i mogą mieć wpływ na użytkownika. Te wyniki/reakcje można podzielić na 5 kategorii: -• 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 +• Odpowiedź — test wywołuje akcję (np. przez API) i otrzymuje odpowiedź. Teraz zajmuje się sprawdzaniem poprawności danych odpowiedzi, schematu i statusu HTTP -• A new state - After invoking an action, some **publicly accessible** data is probably modified +• Nowy stan — po wywołaniu akcji niektóre **publicznie dostępne** dane są prawdopodobnie modyfikowane -• 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 +• Wywołania zewnętrzne — po wywołaniu akcji aplikacja może wywołać składnik zewnętrzny za pośrednictwem protokołu HTTP lub dowolnego innego transportu. Na przykład połączenie w celu wysłania SMS-a, e-maila lub obciążenia karty kredytowej -• Message queues - The outcome of a flow might be a message in a queue +• Kolejki wiadomości — wynikiem przepływu może być wiadomość w kolejce -• 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/metrics. This information goes directly to a very important user - The ops user (i.e., production SRE/admin) +• Obserwowalność — Niektóre rzeczy muszą być monitorowane, na przykład błędy lub niezwykłe wydarzenia biznesowe. Gdy transakcja się nie powiedzie, oczekujemy nie tylko właściwej reakcji, ale także poprawnej obsługi błędów i prawidłowego logowania/metryk. Informacje te trafiają bezpośrednio do bardzo ważnego użytkownika — użytkownika Ops (tj. produkcyjnego SRE/administratora)
    From b94e189101474c5be7696d483b096b2d4520f264 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 2 May 2022 16:05:35 +0200 Subject: [PATCH 137/189] Update readme-pl.md Update with new items that have recently appeared --- readme-pl.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/readme-pl.md b/readme-pl.md index b53df5ef..e929ce62 100644 --- a/readme-pl.md +++ b/readme-pl.md @@ -147,6 +147,11 @@ describe('Products Service', function() {
    +
    +
    © Credits & read-more + 1. Roy Osherove - Naming standards for unit tests +
    +

    ## ⚪ ️ 1.2 Struktura testów według wzorca AAA @@ -558,7 +563,7 @@ test("When no credit, then the transfer is declined", async() => {
    -### :clap: Przykład poprawny: Test wskazuje, co jest przyczyną wyniku testu +### :clap: Przykład robienia tego prawidłowo: Test wskazuje, co jest przyczyną wyniku testu ```javascript @@ -771,6 +776,9 @@ Słowo ostrzeżenia: argument TDD w świecie oprogramowania ma typową fałszyw :white_check_mark: **Opis:** Każdy test jednostkowy obejmuje niewielką część aplikacji i jest to kosztowne, aby pokryć całość, podczas gdy kompleksowe testy z łatwością obejmują dużo gruntu, ale są niestabilne i wolniejsze, dlaczego nie zastosować zrównoważonego podejścia i napisać testy, które są większe niż testy jednostkowe, ale mniejsze niż testy kompleksowe? Testowanie komponentów to nieoceniona piosenka świata testowego - zapewniają to, co najlepsze z obu światów: rozsądną wydajność i możliwość zastosowania wzorców TDD + realistyczne i doskonałe pokrycie. Testy komponentów koncentrują się na mikroserwisowej ‘jednostce’, działają przeciwko interfejsowi API, nie mockują niczego, co należy do samego mikroserwisu (np. prawdziwa baza danych lub przynajmniej wersja tej bazy danych w pamięci), ale usuwają wszystko, co jest zewnętrzne, jak wywołania innych mikrousług. W ten sposób testujemy to, co wdrażamy, podchodzimy do aplikacji od zewnątrz do wewnątrz i zyskujemy dużą pewność w rozsądnym czasie. + +[Mamy pełny przewodnik, który jest poświęcony wyłącznie pisaniu testów komponentów we właściwy sposób](https://github.com/testjavascript/nodejs-integration-tests-best-practices) +
    ❌ **W przeciwnym razie:** Możesz spędzać długie dni na pisaniu testów jednostkowych, aby dowiedzieć się, że masz tylko 20% zasięgu systemu From 358514e1be64ad966638be1e5708c569b7fc48d8 Mon Sep 17 00:00:00 2001 From: saseungmin Date: Mon, 9 May 2022 23:09:05 +0900 Subject: [PATCH 138/189] [Fix] Typo in README.kr.md - Remove unknown words - Fix typo in code block - Correct the wrong korean --- readme.kr.md | 334 +++++++++++++++++++++++---------------------------- 1 file changed, 153 insertions(+), 181 deletions(-) diff --git a/readme.kr.md b/readme.kr.md index a4dd1383..f2f90843 100644 --- a/readme.kr.md +++ b/readme.kr.md @@ -321,7 +321,7 @@ it("화이트박스 테스트: 내부 method가 VAT 0을 받으면 0을 반환 ```javascript it("유효한 제품을 삭제하려고 할 때, 올바른 제품과 올바른 구성 정보로 데이터 액세스 DAL을 한 번 호출했는지 확인한다", async () => { // 이미 제품을 추가했다고 가정 - const dataAccessMock = sinon.mock(DAL); + const dataAccessMock = sinon.mock(DAL); // 좋지 않음: 내부 테스트는 side-effect를 위해서가 주요 목적을 위해서 입니다. dataAccessMock.expects("deleteProduct").once().withArgs(DBConfig, theProductWeJustAdded, true, false); new ProductService().deletePrice(theProductWeJustAdded); @@ -448,7 +448,7 @@ describe("Product service", () => { :white_check_mark: **이렇게 해라:** [스냅샷 테스트](https://jestjs.io/docs/en/snapshot-testing)가 필요한 경우 외부 파일이 아닌 테스트의 일부 ([인라인 스냅샷](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots))에 포함 된 짧고 집중된 스냅샷(3~7 라인)만 사용하십시오. 이 지침을 따르면 따로 설명이 필요없고 잘 깨지지 않는 테스트가 됩니다. -반면에, '고전적인 스냅샷' 튜토리얼 및 도구는 외부에 큰 파일(예: 구성 요소 랜더링 마크업, API JSON 결과)를 저장하고, 테스트를 실행할 때 마다 수신된 결과를 저장된 버전과 비교하기를 권장합니다. 예를 들어, 이것은 1,000 라인(우리가 절대 읽지 않고 추론하지 않을 3,000개의 데이터 값을 가진)의 코드를 우리 테스트에 암시적으로 연결할 수 있습니다. 왜 이것이 잘못 되었을까요? 이렇게하면 테스트에 실패할 1,000 가지 이유가 생깁니다. 한줄만 변경되어도 스냅샷이 유효하지 않게 되고, 이런일이 일어날 가능성이 높습니다. 얼마나 자주? 모든 공백, 주석에서 혹은 사소한 CSS/HTML 변경에 대해서. 뿐만 아니라 테스트 이름은 1,000 라인이 변경되지 않았는지를 나타내기 때분에, 실패에 대한 단서를 제공하지 않습니다. 또한 테스트 작성자가 긴 문서(검사하고 확인할 수 없는)를 받아들이게끔 합니다. 이 모든 것은 초점이 맞지않고 너무 많은 것을 달성하려는 모호하고 간절한 테스트 증상입니다. +반면에, '고전적인 스냅샷' 튜토리얼 및 도구는 외부에 큰 파일(예: 구성 요소 랜더링 마크업, API JSON 결과)를 저장하고, 테스트를 실행할 때 마다 수신된 결과를 저장된 버전과 비교하기를 권장합니다. 예를 들어, 이것은 1,000 라인(우리가 절대 읽지 않고 추론하지 않을 3,000개의 데이터 값을 가진)의 코드를 우리 테스트에 암시적으로 연결할 수 있습니다. 왜 이것이 잘못 되었을까요? 이렇게하면 테스트에 실패할 1,000 가지 이유가 생깁니다. 한줄만 변경되어도 스냅샷이 유효하지 않게 되고, 이런일이 일어날 가능성이 높습니다. 얼마나 자주? 모든 공백, 주석에서 혹은 사소한 CSS/HTML 변경에 대해서. 뿐만 아니라 테스트 이름은 1,000 라인이 변경되지 않았는지를 나타내기 때분에, 실패에 대한 단서를 제공하지 않습니다. 또한 테스트 작성자가 긴 문서(검사하고 확인할 수 없는)를 받아들이게끔 합니다. 이 모든 것은 초점이 맞지않고 너무 많은 것을 달성하려는 모호하고 간절한 테스트 증상입니다. 긴 외부 스냅샷이 허용되는 경우가 거의 없다는 점은 주목할 가치가 있습니다 - 데이터가 아닌 스키마를 assert 할 때(값 추출 및 필드에 집중) 또는 수신된 문서가 거의 변경되지 않는 경우 @@ -468,20 +468,18 @@ describe("Product service", () => { "Examples with Jest") ```javascript -it('TestJavaScript.com 이 올바르게 랜더링 된다.', () => { - -//Arrange - -//Act -const receivedPage = renderer -.create( Test JavaScript < /DisplayPage>) -.toJSON(); - -//Assert -expect(receivedPage).toMatchSnapshot(); -// 이제 2,000 라인의 문서를 암묵적으로 유지합니다. -// 모든 줄바꿈 또는 주석이 테스트를 망가뜨립니다. - +it("TestJavaScript.com 이 올바르게 랜더링 된다.", () => { + //Arrange + + //Act + const receivedPage = renderer + .create( Test JavaScript ) + .toJSON(); + + //Assert + expect(receivedPage).toMatchSnapshot(); + // 이제 2,000 라인의 문서를 암묵적으로 유지합니다. + // 모든 줄바꿈 또는 주석이 테스트를 망가뜨립니다. }); ``` @@ -490,18 +488,18 @@ expect(receivedPage).toMatchSnapshot(); ### :clap: 올바른 예: expectation이 잘 보이고 집중된다. ```javascript -it('TestJavaScript.com 홈페이지를 방문하면 메뉴가 보인다.', () => { -//Arrange +it("TestJavaScript.com 홈페이지를 방문하면, 메뉴가 보인다.", () => { + //Arrange -//Act -receivedPage tree = renderer -.create( Test JavaScript < /DisplayPage>) -.toJSON(); + //Act + const receivedPage = renderer + .create( Test JavaScript ) + .toJSON(); -//Assert + //Assert -const menu = receivedPage.content.menu; -expect(menu).toMatchInlineSnapshot(` + const menu = receivedPage.content.menu; + expect(menu).toMatchInlineSnapshot(`
    @@ -1161,40 +1162,36 @@ cy.wait('@products')// wait for route to appear ```javascript // @testing-library/dom -test('movie title appears', async () => { - // 요소는 초기에 존재 하지 않음... - - // 출현을 대기 - await wait(() => { - expect(getByText('the lion king')).toBeInTheDocument() - }) +test("영화 제목이 나타난다", async () => { + // 요소는 초기에 존재 하지 않음... - // 출현을 기다린 후 요소를 리턴 - const movie = await waitForElement(() => getByText('the lion king')) -}) + // 출현을 대기 + await wait(() => { + expect(getByText("the lion king")).toBeInTheDocument(); + }); + // 출현을 기다린 후 요소를 리턴 + const movie = await waitForElement(() => getByText("the lion king")); +}); ``` ### :thumbsdown: 잘못된 예: 사용자 정의 슬립 코드 ```javascript +test("영화 제목이 나타난다", async () => { + // 초기에 요소가 존재 하지 않음... + + // 사용자 정의 대기 로직 (주의: 매우 단순, 타임아웃이 아님) + const interval = setInterval(() => { + const found = getByText("the lion king"); + if (found) { + clearInterval(interval); + expect(getByText("the lion king")).toBeInTheDocument(); + } + }, 100); -test('movie title appears', async () => { - // 초기에 요소가 존재 하지 않음... - - // 사용자 정의 대기 로직 (주의: 매우 단순, 타임아웃이 아님) - const interval = setInterval(() => { - const found = getByText('the lion king'); - if(found){ - clearInterval(interval); - expect(getByText('the lion king')).toBeInTheDocument(); - } - - }, 100); - - // 출현을 기다린 후 요소를 리턴 - const movie = await waitForElement(() => getByText('the lion king')) -}) - + // 출현을 기다린 후 요소를 리턴 + const movie = await waitForElement(() => getByText("the lion king")); +}); ```
    @@ -1247,38 +1244,36 @@ test('movie title appears', async () => { "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with react-testing-library") -```javascript - +```jsx // unit under test -export default function ProductsList() { - const [products, setProducts] = useState(false) +export default function ProductsList() { + const [products, setProducts] = useState(false); - const fetchProducts = async() => { - const products = await axios.get('api/products') - setProducts(products); - } + const fetchProducts = async () => { + const products = await axios.get("api/products"); + setProducts(products); + }; - useEffect(() => { - fetchProducts(); - }, []); + useEffect(() => { + fetchProducts(); + }, []); - return products ?
    {products}
    :
    No products
    + return products ?
    {products}
    :
    No products
    ; } // test -test('products가 없는 경우, 적절한 메시지 표시하기', () => { - // Arrange - nock("api") - .get(`/products`) - .reply(404); +test("products가 없는 경우, 적절한 메시지 표시한다", () => { + // Arrange + nock("api") + .get(`/products`) + .reply(404); - // Act - const {getByTestId} = render(); + // Act + const { getByTestId } = render(); - // Assert - expect(getByTestId('no-products-message')).toBeTruthy(); + // Assert + expect(getByTestId("no-products-message")).toBeTruthy(); }); - ```
    @@ -1360,7 +1355,7 @@ beforeEach(setUser => () { ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") ```javascript -it('모든 페이지를 smoke 테스트 할때, 페이지들이 정상적으로 로드 되어야 한다', () => { +it('모든 페이지를 smoke 테스트 할 때, 페이지들이 정상적으로 로드되어야 한다', () => { // Cypress를 이용한 예제 입니다 // 다른 E2E 도구로도 쉽게 구현이 가능합니다 cy.visit('https://mysite.com/home'); @@ -1480,44 +1475,21 @@ paths: "Using Cypress to illustrate the idea") ```javascript -import * as todoPage from '../page-objects/todo-page'; - -describe('visual validation', () => { - -before(() => todoPage.navigate()); - -beforeEach(() => cy.eyesOpen({ appName: 'TAU TodoMVC' })); - -afterEach(() => cy.eyesClose()); - - - -it('should look good', () => { - -cy.eyesCheckWindow('empty todo list'); - - - -todoPage.addTodo('Clean room'); - - - -todoPage.addTodo('Learn javascript'); - - - -cy.eyesCheckWindow('two todos'); - - - -todoPage.toggleTodo(0); - - - -cy.eyesCheckWindow('mark as completed'); - -}); - +import * as todoPage from "../page-objects/todo-page"; + +describe("visual validation", () => { + before(() => todoPage.navigate()); + beforeEach(() => cy.eyesOpen({ appName: "TAU TodoMVC" })); + afterEach(() => cy.eyesClose()); + + it("should look good", () => { + cy.eyesCheckWindow("empty todo list"); + todoPage.addTodo("Clean room"); + todoPage.addTodo("Learn javascript"); + cy.eyesCheckWindow("two todos"); + todoPage.toggleTodo(0); + cy.eyesCheckWindow("mark as completed"); + }); }); ``` @@ -1603,7 +1575,7 @@ mutation 기반의 테스트는 단순한 '방문'이 아닌 실제로 테스트
    -❌ **그렇지 않으면:** 85%의 커버리지는 테스트에서 코드의 85%에서 버그를 감지한다는 의미입니다. +❌ **그렇지 않으면:** 85%의 커버리지는 테스트에서 코드의 85%에서 버그를 감지한다는 의미입니다.
    @@ -1611,22 +1583,22 @@ mutation 기반의 테스트는 단순한 '방문'이 아닌 실제로 테스트
    -### :thumbsdown: 올바르지 않은 예: 100% 커버리지, 0% 테스트 +### :thumbsdown: 올바르지 않은 예: 100% 커버리지, 0% 테스트 ![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Using Cypress to illustrate the idea") ```javascript function addNewOrder(newOrder) { - logger.log(`Adding new order ${newOrder}`); - DB.save(newOrder); - Mailer.sendMail(newOrder.assignee, `A new order was places ${newOrder}`); + logger.log(`Adding new order ${newOrder}`); + DB.save(newOrder); + Mailer.sendMail(newOrder.assignee, `A new order was places ${newOrder}`); - return {approved: true}; + return { approved: true }; } -it("Test addNewOrder, don't use such test names", () => { - addNewOrder({asignee: "John@mailer.com",price: 120}); +it("addNewOrder를 테스트하고, 이러한 테스트 이름을 사용하지 마십시오.", () => { + addNewOrder({ assignee: "John@mailer.com", price: 120 }); }); // 100% 커버리지가 나오지만 아무것도 확인하지 않습니다. ``` @@ -1718,7 +1690,7 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test ### :clap: 올바른 예: 코드 품질 검사를 수행하는 npm 스크립트는 요청 시 또는 개발자가 새 코드를 푸시하려고 할 때 모두 병렬로 실행됩니다. -```javascript +```json "scripts": { "inspect:sanity-testing": "mocha **/**--test.js --grep \"sanity\"", "inspect:lint": "eslint .", From 93e0d5de863637bf354a72ffe4dbe1a4661fcd87 Mon Sep 17 00:00:00 2001 From: Wralith <75392169+wralith@users.noreply.github.com> Date: Sat, 14 May 2022 06:26:06 +0300 Subject: [PATCH 139/189] Fix missing chatper 2.10 Fix missing end of the line character in line 1026 that causing chapter 2.10 to show inside the code block. --- readme.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index f5123694..f5dcca64 100644 --- a/readme.md +++ b/readme.md @@ -1014,7 +1014,7 @@ module.exports = async () => {
    -### :clap: Preventing network calls to externous components allows simulating scnearios and minimizing the noise +### :clap: Preventing network calls to externous components allows simulating scenarios and minimizing the noise ```javascript // Intercept requests for 3rd party APIs and return a predefined response @@ -1023,7 +1023,8 @@ beforeEach(() => { id: 1, name: 'John', }); -});``` +}); +```
    From 77fa951c3ca7d0a9ae341a6db95e94ad4188e0b3 Mon Sep 17 00:00:00 2001 From: wenqingl <86453680+wenqingl@users.noreply.github.com> Date: Fri, 22 Jul 2022 23:09:38 -0700 Subject: [PATCH 140/189] Update readme.md --- readme.md | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/readme.md b/readme.md index f5123694..2aa9f24e 100644 --- a/readme.md +++ b/readme.md @@ -14,15 +14,15 @@ ## 📗 50+ best practices: Super-comprehensive and exhaustive -This 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 +This 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 ## 🚢 Advanced: Goes 10,000 miles beyond the basics -Hop 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 +Hop 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 ## 🌐 Full-stack: front, backend, CI, anything -Start by understanding the ubiquitous testing practices that are the foundation for any application tier. Then, delve into your area of choice: frontend/UI, backend, CI or maybe all of them? +Start by understanding the ubiquitous testing practices that are the foundation for any application tier. Then, delve into your area of choice: frontend/UI, backend, CI, or maybe all of them?
    @@ -88,9 +88,9 @@ Testing code is not production-code - Design it to be short, dead-simple, flat, See, 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. -The 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 which 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). +The 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). -This 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, strive to keep it nimble, sometimes it's even worth dropping some tests and trade reliability for agility and simplicity. +This 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. ![alt text](/assets/headspace.png "We have no head room for additional complexity") @@ -164,7 +164,7 @@ describe('Products Service', function() { :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: -1st 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/stubbing on objects and any other preparation code +1st 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/stubbing on objects, and any other preparation code 2nd A - Act: Execute the unit under test. Usually 1 line of code @@ -172,7 +172,7 @@ describe('Products Service', function() {
    -❌ **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 +❌ **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
    @@ -323,7 +323,7 @@ it("White-box test: When the internal methods get 0 vat, it return 0 response", :white_check_mark: **Do:** Test doubles are a necessary evil because they are coupled to the application internals, yet some provide immense value (
    [Read here a reminder about test doubles: mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)). -Before 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 no, it’s a white-box testing smell. +Before 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. For 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/response/outcome 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
    @@ -380,7 +380,7 @@ it("When a valid product is about to be deleted, ensure an email is sent", async ## ⚪ ️1.6 Don’t “foo”, use realistic input data -: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://github.com/chancejs/chancejs) or [Faker](https://www.npmjs.com/package/faker) 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 card, 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). +: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://github.com/chancejs/chancejs) or [Faker](https://www.npmjs.com/package/faker) 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).
    ❌ **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” @@ -434,7 +434,7 @@ it("Better: When adding new valid product, get successful confirmation", async ( ## ⚪ ️ 1.7 Test many input combinations using Property-based testing -: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://github.com/goldbergyoni/javascript-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://en.wikipedia.org/wiki/Fuzzing)). 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: by 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://github.com/jsverify/jsverify) or [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https://github.com/dubzzz/fast-check#readme) which seems to offer some additional features and also to be actively maintained +: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://github.com/goldbergyoni/javascript-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://en.wikipedia.org/wiki/Fuzzing)). 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://github.com/jsverify/jsverify) or [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https://github.com/dubzzz/fast-check#readme) which seems to offer some additional features and also to be actively maintained
    ❌ **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 @@ -473,12 +473,12 @@ describe("Product service", () => { :white_check_mark: **Do:** When there is a need for [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), use only short and focused snapshots (i.e. 3-7 lines) that are included as part of the test ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)) and not within external files. Keeping this guideline will ensure your tests remain self-explanatory and less fragile. -On the other hand, ‘classic snapshots’ tutorials and tools encourage to store big files (e.g. component rendering markup, API JSON result) over some external medium and ensure each time when the test run 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/HTML 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 to 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 +On 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/HTML 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 It’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
    -❌ **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 origin document to current received one - a single space character was added to the markdown... +❌ **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...
    @@ -538,7 +538,7 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => { ## ⚪ ️Copy code, but only what's neccessary -: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 mention explictly 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. +: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.
    ❌ **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 @@ -675,11 +675,11 @@ describe("Order service", function() { ## ⚪ ️ 1.12 Categorize tests under at least 2 levels -: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 additional level of categorization like the scenario or custom categories (see code examples and print screen below). Doing so will also greatly improve the test reports: The reader will easily infer the tests 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 test suite that you may consider like [given-when-then](https://github.com/searls/jasmine-given) and [RITE](https://github.com/ericelliott/riteway) +: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://github.com/searls/jasmine-given) and [RITE](https://github.com/ericelliott/riteway)
    -❌ **Otherwise:** When looking at a report with flat and long list of tests, the reader have to skim-read through long texts to conclude the major scenarios and correlate the commonality of failing tests. Consider the following case: When 7/100 tests fail, looking at a flat list will demand reading the failing tests text 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 +❌ **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/100 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
    @@ -731,9 +731,9 @@ test("Then there should not be a new transfer record", () => {}); ## ⚪ ️1.13 Other generic good testing hygiene -: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 few non-Node related tips that are well-known +: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 -Learn and practice [TDD principles](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) — 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://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.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, 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) +Learn and practice [TDD principles](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) — 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://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.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)
    ❌ **Otherwise:** You‘ll miss pearls of wisdom that were collected for decades @@ -744,13 +744,13 @@ Learn and practice [TDD principles](https://www.sm-cloud.com/book-review-test-dr ## ⚪ ️2.1 Enrich your testing portfolio: Look beyond unit tests and the pyramid -:white_check_mark: **Do:** The [testing pyramid](https://martinfowler.com/bliki/TestPyramid.html), though 10> years old, is a great and relevant model that suggests three testing types and influences most developers’ testing strategy. 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? +:white_check_mark: **Do:** The [testing pyramid](https://martinfowler.com/bliki/TestPyramid.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? -Don’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://en.wikipedia.org/wiki/All_models_are_wrong). For example, consider an IoT application that ingests many events into a message-bus like Kafka/RabbitMQ, 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 increase (bots, crypto, Alexa-skills) greater are the chances to find scenarios where the testing pyramid is not the best match. +Don’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://en.wikipedia.org/wiki/All_models_are_wrong). For example, consider an IoT application that ingests many events into a message-bus like Kafka/RabbitMQ, 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. -It’s time to enrich your testing portfolio and become familiar with more testing types (the next bullets suggest 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 build a portfolio based on risk analysis — assess where problems might arise and match some prevention measures to mitigate those potential risks +It’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 -A word of caution: the TDD argument in the software world takes a typical false-dichotomy face, some preach to use it everywhere, others think it’s the devil. Everyone who speaks in absolutes is wrong :] +A 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 :]
    @@ -778,9 +778,9 @@ A word of caution: the TDD argument in the software world takes a typical false- ## ⚪ ️2.2 Component testing might be your best affair -: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 from both worlds: reasonable performance and a possibility to apply TDD patterns + realistic and great coverage. +: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. -Component tests focus on the Microservice ‘unit’, they work against the API, 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 outwards to inwards and gain great confidence in a reasonable amount of time. +Component 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. [We have a full guide that is solely dedicated to writing component tests in the right way](https://github.com/testjavascript/nodejs-integration-tests-best-practices) @@ -806,7 +806,7 @@ Component tests focus on the Microservice ‘unit’, they work against the API, ## ⚪ ️2.3 Ensure new releases don’t break the API using contract tests -: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 are 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 it to use [PACT](https://docs.pact.io/) which were born to formalize this process with a very disruptive approach — not the server defines the test plan of itself rather the client defines the tests of the… server! PACT can record the client expectation and put in a shared location, “broker”, so the server can pull the expectations and run on every build using 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/CI and might save you a great deal of frustration +: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://docs.pact.io/) 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/CI and might save you a great deal of frustration
    ❌ **Otherwise:** The alternatives are exhausting manual testing or deployment fear From 21c178135b4cab802fb92213e35845aced2bae4d Mon Sep 17 00:00:00 2001 From: Serhii Shramko Date: Sun, 31 Jul 2022 14:56:04 +0200 Subject: [PATCH 141/189] =?UTF-8?q?feat(wip):=20add=20Ukrainian=20?= =?UTF-8?q?=F0=9F=87=BA=F0=9F=87=A6=20translation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme-ua.md | 2138 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2138 insertions(+) create mode 100644 readme-ua.md diff --git a/readme-ua.md b/readme-ua.md new file mode 100644 index 00000000..aa5b9552 --- /dev/null +++ b/readme-ua.md @@ -0,0 +1,2138 @@ + + +# 👇 Чому цей посібник може вивести ваші навички тестування на новий рівень + +
    + +## 📗 50+ найкращих практик: надзвичайно комплексний і вичерпний + +Це посібник із надійності JavaScript і Node.js від А до Я. Він узагальнює та курує для вас десятки найкращих публікацій у блогах, книг та інструментів, які може запропонувати ринок + +## 🚢 Просунутий: виходить на 10 000 миль за межі основ + +Вирушайте в подорож, яка виходить далеко за межі основ і переходить до складних тем, як тестування у виробництві, мутаційне тестування, тестування на основі властивостей та багато інших стратегічних і професійних інструментів. Якщо ви прочитаєте кожне слово в цьому посібнику, ваші навички тестування, швидше за все, будуть набагато вище середнього + +## 🌐 Full-stack: front, backend, CI, та інше + +Почніть із розуміння практик тестування, які є основою для будь-якого рівня програми. Потім заглибтеся в обрану область: frontend + +
    + +### Написав Yoni Goldberg + +- JavaScript & Node.js консультант +- 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - Мій комплексний онлайн-курс із більш ніж [7 годинами відео](https://www.testjavascript.com), 14 типів тестів і більше 40 кращих практик +- [Follow me on Twitter](https://twitter.com/goldbergyoni/) + +
    + +### Переклади - читайте своєю мовою + +- 🇨🇳[Chinese](readme-zh-CN.md) - З люб'язного дозволу [Yves yao](https://github.com/yvesyao) +- 🇰🇷[Korean](readme.kr.md) - З люб'язного дозволу [Rain Byun](https://github.com/ragubyun) +- 🇵🇱[Polish](readme-pl.md) - З люб'язного дозволу [Michal Biesiada](https://github.com/mbiesiad) +- 🇺🇦[Ukrainian](readme-ua.md) - З люб'язного дозволу [Serhii Shramko](https://github.com/Shramkoweb) +- 🇪🇸[Spanish](readme-es.md) - З люб'язного дозволу [Miguel G. Sanguino](https://github.com/sanguino) +- 🇧🇷[Portuguese-BR](readme-pt-br.md) - З люб'язного дозволу [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) +- 🇫🇷[French](readme-fr.md) - З люб'язного дозволу [Mathilde El Mouktafi](https://github.com/mel-mouk) +- 🇯🇵[Japanese (draft)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - З люб'язного дозволу [Yuichi Yogo](https://github.com/yuichkun) and [ryo](https://github.com/kawamataryo) +- 🇹🇼[Traditional Chinese](readme-zh-TW.md) - З люб'язного дозволу [Yubin Hsu](https://github.com/yubinTW) +- Хочете перекласти на свою рідну мову? будь ласка, відкрийте issue 💜 + +

    + +## `Зміст` + +#### [`Розділ 0: Золоте правило`](#section-0️⃣-the-golden-rule) + +Одна порада, яка надихає всіх інших (1 спеціальний пункт) + +#### [`Розділ 1: Анатомія тесту`](#section-1-the-test-anatomy-1) + +Основа - структурування чистих тестів (12 пункт) + +#### [`Розділ 2: Backend`](#section-2️⃣-backend-testing) + +Ефективне написання backend-тестів і тестів мікросервісів (13 пунктів) + +#### [`Розділ 3: Frontend`](#section-3️⃣-frontend-testing) + +Написання тестів для веб-інтерфейсу, включаючи тести компонентів і E2E (11 пунктів) + +#### [`Розділ 4: Вимірювання ефективності тестів`](#section-4️⃣-measuring-test-effectiveness) + +Спостереження за сторожем - вимірювання якості тесту (4 пункти) + +#### [`Розділ 5: Безперервна інтеграція`](#section-5️⃣-ci-and-other-quality-measures) + +Рекомендації щодо CI у світі JS (9 пунктів) + +

    + +# Розділ 0️⃣: Золоте правило + +
    + +## ⚪️ 0 Золоте правило: дизайн для ощадливого тестування + +:white_check_mark: **Роби:** +Тестовий код – це не робочий код. Розробіть його таким, щоб він був коротким, надзвичайно простим, зрозумілим і приємним для роботи. Треба подивитися на тест і миттєво зрозуміти намір. + +Бачиш, наші уми вже зайняті основною роботою – production-кодом. Немає «простору» для додаткової складності. Якщо ми спробуємо втиснути в наш бідолашний мозок ще одну систему [sus](https://en.wikipedia.org/wiki/System_usability_scale), це сповільнить роботу команди, яка працює проти того, чому ми проводимо тестування. Практично тут, багато команд просто відмовляються від тестування. + +Випробування — це можливість для чогось іншого — доброзичливого помічника, другого пілота, який дає велику цінність за невеликі інвестиції. Наука говорить нам, що у нас є дві системи мозку: система 1 використовується для легкої діяльності, як-от водіння автомобіля по порожній дорозі, і система 2, яка призначена для складних і усвідомлених операцій, таких як розвʼязування математичного рівняння. Розробіть свій тест для системи 1. Дивлячись на тестовий код, це повинно _відчуватися_ таким же легким, як зміна HTML-документа, а не розвʼязування 2X(17 × 24). + +Цього можна досягти шляхом вибіркового вибору методів, інструментів і тестових цілей, які є економічно ефективними та забезпечують [високу рентабельність інвестицій](https://en.wikipedia.org/wiki/Return_on_investment). Тестуйте лише стільки, скільки потрібно, намагайтеся підтримувати його спритність, інколи навіть варто відмовитися від деяких тестів і поміняти надійність на швидкість і простоту. + +![alt text](/assets/headspace.png "У нас немає місця для додаткової складності") + +Більшість наведених нижче порад є похідними від цього принципу. + +### Готові почати? + +

    + +# Розділ 1: Анатомія тесту + +
    + +## ⚪ ️ 1.1 Додайте 3 частини до кожної назви тесту + +:white_check_mark: **Роби:** У звіті про тестування має бути вказано, чи задовольняє поточна версія програми вимоги до людей, які не обов’язково знайомі з кодом: тестувальника, інженера DevOps, який розгортає, і майбутнього вас через два роки. Цього можна досягти найкраще, якщо тести складатимуться на рівні вимог і включатимуть 3 частини: + +(1) Що перевіряється? Наприклад, метод ProductsService.addNewProduct + +(2) За яких обставин і сценарію? Наприклад, у метод не передається ціна + +(3) Який результат очікується? Наприклад, новий продукт не затверджено + +
    + +❌ **Інакше:** Розгортання щойно не вдалось, тест із назвою «Add product» не вдався. Чи це говорить вам про те, що саме несправно? + +
    + +**👇 Примітка:** Кожен пункт має приклади коду, а інколи також зображення. Натисніть, щоб розгорнути +
    + +
    Приклади коду + +
    + +### :clap: Роби це правильно. Приклад: ім’я тесту, яке складається з 3 частин + +![](https://img.shields.io/badge/🔨%20Example%20using%20Mocha-blue.svg "Використання Mocha для ілюстрації ідеї") + +```javascript +//1. блок тестування +describe('Products Service', function() { + describe('Add new product', function() { + //2. сценарій і 3. очікування + it('When no price is specified, then the product status is pending approval', ()=> { + const newProduct = new ProductService().add(...); + expect(newProduct.status).to.equal('pendingApproval'); + }); + }); +}); + +``` + +
    + +### :clap: Роби це правильно Приклад: назва тесту, що складається з 3 частин + +![alt text](/assets/bp-1-3-parts.jpeg "Назва тесту, яка складається з 3 частин") + +
    + +
    +
    © Credits & read-more + 1. Roy Osherove - Naming standards for unit tests +
    + +

    + +## ⚪ ️ 1.2 Структурні тести за схемою ААА + +:white_check_mark: **Роби:** Структуруйте свої тести за допомогою 3 добре відокремлених розділів «Упорядкуйте, дійте та затверджуйте» (AAA). Дотримання цієї структури гарантує, що читач не витрачатиме мозок-CPU на розуміння плану тестування: + +1st A - Arrange(Упорядкувати): Весь код налаштування, щоб привести систему до сценарію, який має імітувати тест. Це може включати створення екземпляра тестового конструктора блоку, додавання записів БД, mocking/stubbing обʼєктів та будь-який інший код підготовки + +2nd A - Act(Дія): Виконайте тестовий блок. Зазвичай 1 рядок коду + +3rd A - Assert(Стверджування): Переконайтеся, що отримане значення відповідає очікуванням. Зазвичай 1 рядок коду + +
    + +❌ **Інакше:** Ви не лише витрачаєте години на розуміння основного коду, але те, що мало бути найпростішою частиною дня (тестування), напружує ваш мозок + +
    + +
    Приклади коду + +
    + +### :clap: Роби це правильно. Приклад: тест, структурований за шаблоном AAA + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +describe("Customer classifier", () => { + test("When customer spent more than 500$, should be classified as premium", () => { + //Arrange + const customerToClassify = { spent: 505, joined: new Date(), id: 1 }; + const DBStub = sinon.stub(dataAccess, "getCustomer").reply({ id: 1, classification: "regular" }); + + //Act + const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); + + //Assert + expect(receivedClassification).toMatch("premium"); + }); +}); +``` + +
    + +### :thumbsdown: Приклад антишаблону: немає поділу, одна група, важче інтерпретувати + +```javascript +test("Should be classified as premium", () => { + const customerToClassify = { spent: 505, joined: new Date(), id: 1 }; + const DBStub = sinon.stub(dataAccess, "getCustomer").reply({ id: 1, classification: "regular" }); + const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); + expect(receivedClassification).toMatch("premium"); +}); +``` + +
    + +

    + +## ⚪ ️1.3 Опишіть очікування мовою продукту: використовуйте твердження в стилі BDD + +:white_check_mark: **Роби:** Написання ваших тестів у декларативному стилі дає змогу читачеві миттєво отримати переваги, не витрачаючи на це зусилля мозку. Коли ви пишете імперативний код, наповнений умовною логікою, читач змушений докладати більше зусиль мозку. У такому випадку закодуйте очікування мовою, схожою на людську, у декларативному стилі BDD, використовуючи `expect` або `should` і не використовуючи спеціальний код. Якщо Chai & Jest не містить потрібного твердження, і воно дуже повторюване, подумайте над [extending Jest matcher (Jest)](https://jestjs.io/docs/en/expect#expectextendmatchers) або створіть [custom Chai plugin](https://www.chaijs.com/guide/plugins/) +
    + +❌ **Інакше:** Команда буде писати менше тестів і прикрашати набридливі .skip() + +
    + +
    Приклади коду
    + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Приклади з Mocha & Chai") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +### :thumbsdown: Приклад антишаблону: читач повинен проглянути довгий код і імперативний код, щоб зрозуміти суть + +```javascript +test("When asking for an admin, ensure only ordered admins in results", () => { + // припускаючи, що ми додали сюди двох адміністраторів «admin1», «admin2» і юзера «user1» + const allAdmins = getUsers({ adminOnly: true }); + + let admin1Found, + adming2Found = false; + + allAdmins.forEach(aSingleUser => { + if (aSingleUser === "user1") { + assert.notEqual(aSingleUser, "user1", "A user was found and not admin"); + } + if (aSingleUser === "admin1") { + admin1Found = true; + } + if (aSingleUser === "admin2") { + admin2Found = true; + } + }); + + if (!admin1Found || !admin2Found) { + throw new Error("Not all admins were returned"); + } +}); +``` + +
    + +### :clap: Роби це правильно. Приклад. Перегляд наступного декларативного тесту – легкий вітер + +```javascript +it("When asking for an admin, ensure only ordered admins in results", () => { + // припускаючи, що ми додали сюди двох адміністраторів «admin1», «admin2» і юзера «user1» + const allAdmins = getUsers({ adminOnly: true }); + + expect(allAdmins) + .to.include.ordered.members(["admin1", "admin2"]) + .but.not.include.ordered.members(["user1"]); +}); +``` + +
    + +

    + +## ⚪ ️ 1.4 Дотримуйтесь тестування за допомогою чорної скриньки: перевіряйте лише публічні методи + +:white_check_mark: **Роби:** Тестування внутрішніх компонентів приносить величезні накладні витрати майже за безцінь. Якщо ваш код/API дає належні результати, чи варто вам справді витратити наступні 3 години на те, щоб перевірити, ЯК він працює всередині, а потім підтримувати ці крихкі тести? Кожного разу, коли перевіряється загальнодоступна поведінка, приватна реалізація також неявно перевіряється, і ваші тести не працюватимуть, лише якщо є певна проблема (наприклад, неправильний вихід). Цей підхід також називають «поведінковим тестуванням». З іншого боку, якщо ви тестуєте внутрішні елементи (підхід білого ящика) — ваш фокус переходить від планування результату компонента до дрібних деталей, і ваш тест може бути невдалим через незначні переписування коду, хоча результати хороші — це значно збільшує технічне обслуговування +
    + +❌ **Інакше:** Ваші тести поводяться як [хлопчик, який кричав вовк](https://en.wikipedia.org/wiki/The_Boy_Who_Cried_Wolf): вигуки хибнопозитивних криків (наприклад, Тест провалився через те, що ім’я приватної змінної було змінено). Не дивно, що незабаром люди почнуть ігнорувати сповіщення CI, поки одного дня не проігнорують справжню помилку... + +
    +
    Приклади коду + +
    + +### :thumbsdown: Приклад антишаблону: тестовий приклад тестує внутрішні компоненти без вагомої причини + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Приклади з Mocha & Chai") + +```javascript +class ProductService { + // цей метод використовується тільки внутрішньо + // зміна цієї назви призведе до невдачі тестів + calculateVATAdd(priceWithoutVAT) { + return { finalPrice: priceWithoutVAT * 1.2 }; + // Зміна формату результату або назви ключа вище призведе до невдачі тестів + } + // публічний метод + getPrice(productId) { + const desiredProduct = DB.getProduct(productId); + finalPrice = this.calculateVATAdd(desiredProduct.price).finalPrice; + return finalPrice; + } +} + +it("White-box test: When the internal methods get 0 vat, it return 0 response", async () => { + // Немає вимоги дозволяти користувачам розраховувати ПДВ, відображати лише остаточну ціну. Тим не менш, ми хибно наполягаємо тут на перевірці внутрішніх елементів класу + expect(new ProductService().calculateVATAdd(0).finalPrice).to.equal(0); +}); +``` + +
    + +

    + +## ⚪ ️ ️1.5 Вибирайте правильні тестові дублі: уникайте mocks на користь stubs і spies + +:white_check_mark: **Роби:** Подвійні тести є необхідним злом, тому що вони пов'язані з внутрішніми елементами програми, але деякі з них мають величезну цінність ([Прочитайте тут нагадування: mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)). + +Перш ніж використовувати подвійні тести, поставте дуже просте запитання: чи використовую я його для тестування функціональності, яка відображається або може з’явитися в документі з вимогами? Якщо ні, це запах тестування білої коробки. + +Наприклад, якщо ви хочете перевірити, чи ваша програма поводиться належним чином, коли платіжна служба не працює, ви можете заблокувати платіжну службу та запустити деякий повернення «Немає відповіді», щоб переконатися, що одиниця, що тестується, повертає правильне значення. Це перевіряє поведінку/відповідь/результат нашої програми за певних сценаріїв. Ви також можете використовувати шпигуна, щоб підтвердити, що електронний лист було надіслано, коли ця служба не працює — це знову перевірка поведінки, яка, ймовірно, з’явиться в документі вимог («Надіслати електронний лист, якщо платіж не вдалося зберегти»). З іншого боку, якщо ви знущаєтеся над платіжною службою та переконаєтесь, що її викликали з правильними типами JavaScript — тоді ваш тест зосереджений на внутрішніх речах, які не мають нічого спільного з функціями програми та, ймовірно, часто змінюватимуться. +
    + +❌ **Інакше:** Будь-яке переписування коду вимагає пошуку всіх макетів у коді та відповідного оновлення. Тести стають тягарем, а не корисним другом + +
    + +
    Приклади коду + +
    + +### :thumbsdown: Приклад антишаблону: Mocks імітує внутрішню реалізацію + +![](https://img.shields.io/badge/🔧%20Example%20using%20Sinon-blue.svg "Приклади з Sinon") + +```javascript +it("When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config", async () => { + // Припустимо, ми вже додали продукт + const dataAccessMock = sinon.mock(DAL); + // ПОГАНО: тестування внутрощів насправді є нашою головною метою, а не лише побічним ефектом + dataAccessMock + .expects("deleteProduct") + .once() + .withArgs(DBConfig, theProductWeJustAdded, true, false); + new ProductService().deletePrice(theProductWeJustAdded); + dataAccessMock.verify(); +}); +``` + +
    + +### :clap:Роби це правильно. Приклад: (spy) шпигуни зосереджені на перевірці вимог, але як побічний ефект неминуче торкаються внутрішніх органів + +```javascript +it("When a valid product is about to be deleted, ensure an email is sent", async () => { + // Припустимо, ми вже додали продукт + const spy = sinon.spy(Emailer.prototype, "sendEmail"); + new ProductService().deletePrice(theProductWeJustAdded); + // добре: ми маємо справу з внутрішніми кодом? Так, але як побічний ефект тестування вимог (надсилання електронного листа) + expect(spy.calledOnce).to.be.true; +}); +``` + +
    + +

    + +## 📗 Хочете навчитися всім цим практикам із живим відео? + +### Відвідайте мій онлайн-курс [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) + +

    + +## ⚪ ️1.6 Don’t “foo”, use realistic input data + +:white_check_mark: **Роби:** 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://github.com/chancejs/chancejs) or [Faker](https://www.npmjs.com/package/faker) 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 card, 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). +
    + +❌ **Інакше:** 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” + +
    + +
    Приклади коду + +
    + +### :thumbsdown: Anti-Pattern Example: A test suite that passes due to non-realistic data + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +const addProduct = (name, price) => { + const productNameRegexNoSpace = /^\S*$/; //no white-space allowed + + if (!productNameRegexNoSpace.test(name)) return false; //this path never reached due to dull input + + //some logic here + return true; +}; + +test("Wrong: When adding new product with valid properties, get successful confirmation", async () => { + //The string "Foo" which is used in all tests never triggers a false result + const addProductResult = addProduct("Foo", 5); + expect(addProductResult).toBe(true); + //Positive-false: the operation succeeded because we never tried with long + //product name including spaces +}); +``` + +
    + +### :clap:Doing It Right Example: Randomizing realistic input + +```javascript +it("Better: When adding new valid product, get successful confirmation", async () => { + const addProductResult = addProduct(faker.commerce.productName(), faker.random.number()); + //Generated random input: {'Sleek Cotton Computer', 85481} + expect(addProductResult).to.be.true; + //Test failed, the random input triggered some path we never planned for. + //We discovered a bug early! +}); +``` + +
    + +

    + +## ⚪ ️ 1.7 Test many input combinations using Property-based testing + +:white_check_mark: **Роби:** 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://github.com/goldbergyoni/javascript-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://en.wikipedia.org/wiki/Fuzzing)). 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: by 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://github.com/jsverify/jsverify) or [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https://github.com/dubzzz/fast-check#readme) which seems to offer some additional features and also to be actively maintained +
    + +❌ **Інакше:** 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 + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: Testing many input permutations with “fast-check” + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +import fc from "fast-check"; + +describe("Product service", () => { + describe("Adding new", () => { + //this will run 100 times with different random properties + it("Add new product with random yet valid properties, always successful", () => + fc.assert( + fc.property(fc.integer(), fc.string(), (id, name) => { + expect(addNewProduct(id, name).status).toEqual("approved"); + }) + )); + }); +}); +``` + +
    + +

    + +## ⚪ ️ 1.8 If needed, use only short & inline snapshots + +:white_check_mark: **Роби:** When there is a need for [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), use only short and focused snapshots (i.e. 3-7 lines) that are included as part of the test ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)) and not within external files. Keeping this guideline will ensure your tests remain self-explanatory and less fragile. + +On the other hand, ‘classic snapshots’ tutorials and tools encourage to store big files (e.g. component rendering markup, API JSON result) over some external medium and ensure each time when the test run 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/HTML 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 to 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 + +It’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 +
    + +❌ **Інакше:** A UI test fails. The code seems right, the screen renders perfect pixels, what happened? your snapshot testing just found a difference from the origin document to current received one - a single space character was added to the markdown... + +
    + +
    Приклади коду + +
    + +### :thumbsdown: Anti-Pattern Example: Coupling our test to unseen 2000 lines of code + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +it("TestJavaScript.com is renderd correctly", () => { + //Arrange + + //Act + const receivedPage = renderer + .create( Test JavaScript ) + .toJSON(); + + //Assert + expect(receivedPage).toMatchSnapshot(); + //We now implicitly maintain a 2000 lines long document + //every additional line break or comment - will break this test +}); +``` + +
    + +### :clap: Doing It Right Example: Expectations are visible and focused + +```javascript +it("When visiting TestJavaScript.com home page, a menu is displayed", () => { + //Arrange + + //Act + const receivedPage = renderer + .create( Test JavaScript ) + .toJSON(); + + //Assert + + const menu = receivedPage.content.menu; + expect(menu).toMatchInlineSnapshot(` +
      +
    • Home
    • +
    • About
    • +
    • Contact
    • +
    +`); +}); +``` + +
    + +

    + +## ⚪ ️Copy code, but only what's neccessary + +:white_check_mark: **Роби:** 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 mention explictly 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. +
    + +❌ **Інакше:** 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 + +
    + +
    Приклади коду + +
    + +### :thumbsdown: Anti-Pattern Example: The test failure is unclear because all the cause is external and hides within huge JSON + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +test("When no credit, then the transfer is declined", async() => { + // Arrange + const transferRequest = testHelpers.factorMoneyTransfer() //get back 200 lines of JSON; + const transferServiceUnderTest = new TransferService(); + + // Act + const transferResponse = await transferServiceUnderTest.transfer(transferRequest); + + // Assert + expect(transferResponse.status).toBe(409);// But why do we expect failure: All seems perfectly valid in the test 🤔 + }); +``` + +
    + +### :clap: Doing It Right Example: The test highlights what is the cause of the test result + +```javascript + +test("When no credit, then the transfer is declined ", async() => { + // Arrange + const transferRequest = testHelpers.factorMoneyTransfer({userCredit:100, transferAmount:200}) //obviously there is lack of credit + const transferServiceUnderTest = new TransferService({disallowOvercharge:true}); + + // Act + const transferResponse = await transferServiceUnderTest.transfer(transferRequest); + + // Assert + expect(transferResponse.status).toBe(409); // Obviously if the user has no credit it should fail + }); + ``` + +
    + +

    + +## ⚪ ️ 1.10 Don’t catch errors, expect them + +:white_check_mark: **Роби:** 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 + +A 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 +
    + +❌ **Інакше:** It will be challenging to infer from the test reports (e.g. CI reports) what went wrong + +
    + +
    Приклади коду + +
    + +### :thumbsdown: Anti-pattern Example: A long test case that tries to assert the existence of error with try-catch + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +it("When no product name, it throws error 400", async () => { + let errorWeExceptFor = null; + try { + const result = await addNewProduct({}); + } catch (error) { + expect(error.code).to.equal("InvalidInput"); + errorWeExceptFor = error; + } + expect(errorWeExceptFor).not.to.be.null; + //if this assertion fails, the tests results/reports will only show + //that some value is null, there won't be a word about a missing Exception +}); +``` + +
    + +### :clap: Doing It Right Example: A human-readable expectation that could be understood easily, maybe even by QA or technical PM + +```javascript +it("When no product name, it throws error 400", async () => { + await expect(addNewProduct({})) + .to.eventually.throw(AppError) + .with.property("code", "InvalidInput"); +}); +``` + +
    + +

    + +## ⚪ ️ 1.11 Tag your tests + +:white_check_mark: **Роби:** 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’ +
    + +❌ **Інакше:** 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 + +
    + +
    Приклади коду + +
    + +### :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) + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +//this test is fast (no DB) and we're tagging it correspondigly +//now the user/CI can run it frequently +describe("Order service", function() { + describe("Add new order #cold-test #sanity", function() { + test("Scenario - no currency was supplied. Expectation - Use the default currency #sanity", function() { + //code logic here + }); + }); +}); +``` + +
    + +

    + +## ⚪ ️ 1.12 Categorize tests under at least 2 levels + +:white_check_mark: **Роби:** 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 additional level of categorization like the scenario or custom categories (see Приклади коду and print screen below). Doing so will also greatly improve the test reports: The reader will easily infer the tests 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 test suite that you may consider like [given-when-then](https://github.com/searls/jasmine-given) and [RITE](https://github.com/ericelliott/riteway) + +
    + +❌ **Інакше:** When looking at a report with flat and long list of tests, the reader have to skim-read through long texts to conclude the major scenarios and correlate the commonality of failing tests. Consider the following case: When 7/100 tests fail, looking at a flat list will demand reading the failing tests text 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 + +
    + +
    Приклади коду + +
    + +### :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 + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +// Unit under test +describe("Transfer service", () => { + //Scenario + describe("When no credit", () => { + //Expectation + test("Then the response status should decline", () => {}); + + //Expectation + test("Then it should send email to admin", () => {}); + }); +}); +``` + +![alt text](assets/hierarchical-report.png) + +
    + +### :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 + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Mocha") + +```javascript +test("Then the response status should decline", () => {}); + +test("Then it should send email", () => {}); + +test("Then there should not be a new transfer record", () => {}); +``` + +![alt text](assets/flat-report.png) + +
    + +
    + +

    + +## ⚪ ️1.13 Other generic good testing hygiene + +:white_check_mark: **Роби:** This post is focused on testing advice that is related to, or at least can be exemplified with Node JS. This bullet, however, groups few non-Node related tips that are well-known + +Learn and practice [TDD principles](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) — 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://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.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, 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) +
    + +❌ **Інакше:** You‘ll miss pearls of wisdom that were collected for decades + +

    + +# Section 2️⃣: Backend Testing + +## ⚪ ️2.1 Enrich your testing portfolio: Look beyond unit tests and the pyramid + +:white_check_mark: **Роби:** The [testing pyramid](https://martinfowler.com/bliki/TestPyramid.html), though 10> years old, is a great and relevant model that suggests three testing types and influences most developers’ testing strategy. 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? + +Don’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://en.wikipedia.org/wiki/All_models_are_wrong). For example, consider an IoT application that ingests many events into a message-bus like Kafka/RabbitMQ, 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 increase (bots, crypto, Alexa-skills) greater are the chances to find scenarios where the testing pyramid is not the best match. + +It’s time to enrich your testing portfolio and become familiar with more testing types (the next bullets suggest 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 build a portfolio based on risk analysis — assess where problems might arise and match some prevention measures to mitigate those potential risks + +A word of caution: the TDD argument in the software world takes a typical false-dichotomy face, some preach to use it everywhere, others think it’s the devil. Everyone who speaks in absolutes is wrong :] + +
    + +❌ **Інакше:** You’re going to miss some tools with amazing ROI, some like Fuzz, lint, and mutation can provide value in 10 minutes + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the same way’ + +![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") + +☺️Example: [YouTube: “Beyond Unit Tests: 5 Shiny Node.JS Test Types (2018)” (Yoni Goldberg)](https://www.youtube.com/watch?v=-2zP494wdUY&feature=youtu.be) + +
    + +![alt text](assets/bp-12-Yoni-Goldberg-Testing.jpeg "A test name that constitutes 3 parts") + +
    + +

    + +## ⚪ ️2.2 Component testing might be your best affair + +:white_check_mark: **Роби:** 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 from both worlds: reasonable performance and a possibility to apply TDD patterns + realistic and great coverage. + +Component tests focus on the Microservice ‘unit’, they work against the API, 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 outwards to inwards and gain great confidence in a reasonable amount of time. + +[We have a full guide that is solely dedicated to writing component tests in the right way](https://github.com/testjavascript/nodejs-integration-tests-best-practices) + +
    + +❌ **Інакше:** You may spend long days on writing unit tests to find out that you got only 20% system coverage + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: Supertest allows approaching Express API in-process (fast and cover many layers) + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +![alt text](assets/bp-13-component-test-yoni-goldberg.png " [Supertest](https://www.npmjs.com/package/supertest) allows approaching Express API in-process (fast and cover many layers)") + +
    + +

    + +## ⚪ ️2.3 Ensure new releases don’t break the API using contract tests + +:white_check_mark: **Роби:** 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 are 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 it to use [PACT](https://docs.pact.io/) which were born to formalize this process with a very disruptive approach — not the server defines the test plan of itself rather the client defines the tests of the… server! PACT can record the client expectation and put in a shared location, “broker”, so the server can pull the expectations and run on every build using 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/CI and might save you a great deal of frustration +
    + +❌ **Інакше:** The alternatives are exhausting manual testing or deployment fear + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: + +![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") + +![alt text](assets/bp-14-testing-best-practices-contract-flow.png) + +
    + +

    + +## ⚪ ️ 2.4 Test your middlewares in isolation + +:white_check_mark: **Роби:** 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://www.npmjs.com/package/sinon)) on the interaction with the {req,res} objects to ensure the function performed the right action. The library [node-mock-http](https://www.npmjs.com/package/node-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) +
    + +❌ **Інакше:** A bug in Express middleware === a bug in all or most requests + +
    + +
    Приклади коду + +
    + +### :clap:Doing It Right Example: Testing middleware in isolation without issuing network calls and waking-up the entire Express machine + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +//the middleware we want to test +const unitUnderTest = require("./middleware"); +const httpMocks = require("node-mocks-http"); +//Jest syntax, equivelant to describe() & it() in Mocha +test("A request without authentication header, should return http status 403", () => { + const request = httpMocks.createRequest({ + method: "GET", + url: "/user/42", + headers: { + authentication: "" + } + }); + const response = httpMocks.createResponse(); + unitUnderTest(request, response); + expect(response.statusCode).toBe(403); +}); +``` + +
    + +

    + +## ⚪ ️2.5 Measure and refactor using static analysis tools + +:white_check_mark: **Роби:** 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://www.sonarqube.org/) (4,900+ [stars](https://github.com/SonarSource/sonarqube)) and [Code Climate](https://codeclimate.com/) (2,000+ [stars](https://github.com/codeclimate/codeclimate)) + +Credit: [Keith Holliday](https://github.com/TheHollidayInn) + +
    + +❌ **Інакше:** 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 + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: CodeClimate, a commercial tool that can identify complex methods: + +![](https://img.shields.io/badge/🔧%20Example%20using%20Code%20Climate-blue.svg "Examples with CodeClimate") + +![alt text](assets/bp-16-yoni-goldberg-quality.png "CodeClimate, a commercial tool that can identify complex methods:") + +
    + +

    + +## ⚪ ️ 2.6 Check your readiness for Node-related chaos + +:white_check_mark: **Роби:** 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/process 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://principlesofchaos.org/) 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://github.com/Netflix/chaosmonkey), 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://github.com/asobti/kube-monkey), that kills pods). All these tools work on the hosting/platform 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://github.com/i0natan/node-chaos-monkey) (alpha) which provides all sort of Node-related chaotic acts +
    + +❌ **Інакше:** No escape here, Murphy’s law will hit your production without mercy + +
    + +
    Приклади коду + +
    + +### :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 + +![alt text](assets/bp-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") + +
    + +
    + +## ⚪ ️2.7 Avoid global test fixtures and seeds, add data per-test + +:white_check_mark: **Роби:** 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) +
    + +❌ **Інакше:** 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 + +
    + +
    Приклади коду + +
    + +### :thumbsdown: Anti-Pattern Example: tests are not independent and rely on some global hook to feed global DB data + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +before(async () => { + //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework + await DB.AddSeedDataFromJson('seed.json'); +}); +it("When updating site name, get successful confirmation", async () => { + //I know that site name "portal" exists - I saw it in the seed files + const siteToUpdate = await SiteService.getSiteByName("Portal"); + const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); + expect(updateNameResult).to.be(true); +}); +it("When querying by site name, get the right site", async () => { + //I know that site name "portal" exists - I saw it in the seed files + const siteToCheck = await SiteService.getSiteByName("Portal"); + expect(siteToCheck.name).to.be.equal("Portal"); //Failure! The previous test change the name :[ +}); + +``` + +
    + +### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data + +```javascript +it("When updating site name, get successful confirmation", async () => { + //test is adding a fresh new records and acting on the records only + const siteUnderTest = await SiteService.addSite({ + name: "siteForUpdateTest" + }); + const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); + expect(updateNameResult).to.be(true); +}); +``` + +
    + +
    + +## ⚪ ️2.8 Choose a clear data clean-up strategy: After-all (recommended) or after-each + +:white_check_mark: **Роби:** 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. + +The 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://github.com/testjavascript/nodejs-integration-tests-best-practices/blob/master/graphics/db-clean-options.png). +
    + +❌ **Інакше:** 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 + +
    + +
    Приклади коду + +
    + +### :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 + +```javascript + // After-all clean up (recommended) +// global-teardown.js +module.exports = async () => { + // ... + if (Math.ceil(Math.random() * 10) === 10) { + await new OrderRepository().cleanup(); + } +}; +``` + +
    + +
    + +## ⚪ ️2.9 Isolate the component from the world using HTTP interceptor + +:white_check_mark: **Роби:** 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 +
    + +❌ **Інакше:** 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 + +
    + +
    Приклади коду + +
    + +### :clap: Preventing network calls to externous components allows simulating scnearios and minimizing the noise + +```javascript +// Intercept requests for 3rd party APIs and return a predefined response +beforeEach(() => { + nock('http://localhost/user/').get(`/1`).reply(200, { + id: 1, + name: 'John', + }); +});``` + +
    + +## ⚪ ️2.10 Test the response schema, mostly when there are auto-generated fields + +:white_check_mark: **Роби:** 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. + + +
    + +❌ **Інакше:** Although the code/API caller relies on some field with dynamic data (e.g., ID, date), it will not come in return and break the contract + +
    + +
    Приклади коду + +
    + +### :clap: Asserting that fields with dynamic value exist and have the right type + +```javascript + test('When adding a new valid order, Then should get back approval with 200 response', async () => { + // ... + //Assert + expect(receivedAPIResponse).toMatchObject({ + status: 200, + data: { + id: expect.any(Number), // Any number satisfies this test + mode: 'approved', + }, + }); +}); +``` + +
    + +
    + +## ⚪ ️2.12 Check integrations corner cases and chaos + +:white_check_mark: **Роби:** When checking integrations, go beyond the happy and sad paths. Check not only errored 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 + + +
    + +❌ **Інакше:** All your tests pass, it's only the production who will crash or won't report errors correctly when 3rd parties send excpetional responses + +
    + +
    Приклади коду + +
    + +### :clap: Ensuring that on network failures, the circuit breaker can save the day + +```javascript + test('When users service replies with 503 once and retry mechanism is applied, then an order is added successfully', async () => { + //Arrange + nock.removeInterceptor(userServiceNock.interceptors[0]) + nock('http://localhost/user/') + .get('/1') + .reply(503, undefined, { 'Retry-After': 100 }); + nock('http://localhost/user/') + .get('/1') + .reply(200); + const orderToAdd = { + userId: 1, + productId: 2, + mode: 'approved', + }; + + //Act + const response = await axiosAPIClient.post('/order', orderToAdd); + + //Assert + expect(response.status).toBe(200); +}); +``` + +
    + +
    + + +## ⚪ ️2.13 Test the five potential outcomes + +:white_check_mark: **Роби:** 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/reactions can be put in 5 categories: + +• 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 + +• A new state - After invoking an action, some **publicly accessible** data is probably modified + +• 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 + +• Message queues - The outcome of a flow might be a message in a queue + +• 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/metrics. This information goes directly to a very important user - The ops user (i.e., production SRE/admin) + +
    + +

    + +# Section 3️⃣: Frontend Testing + +## ⚪ ️ 3.1 Separate UI from functionality + +:white_check_mark: **Роби:** 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/CSS 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 + +
    + +❌ **Інакше:** 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 + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: Separating out the UI details + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +test("When users-list is flagged to show only VIP, should display only VIP members", () => { + // Arrange + const allUsers = [{ id: 1, name: "Yoni Goldberg", vip: false }, { id: 2, name: "John Doe", vip: true }]; + + // Act + const { getAllByTestId } = render(); + + // Assert - Extract the data from the UI first + const allRenderedUsers = getAllByTestId("user").map(uiElement => uiElement.textContent); + const allRealVIPUsers = allUsers.filter(user => user.vip).map(user => user.name); + expect(allRenderedUsers).toEqual(allRealVIPUsers); //compare data with data, no UI here +}); +``` + +
    + +### :thumbsdown: Anti-Pattern Example: Assertion mix UI details and data + +```javascript +test("When flagging to show only VIP, should display only VIP members", () => { + // Arrange + const allUsers = [{ id: 1, name: "Yoni Goldberg", vip: false }, { id: 2, name: "John Doe", vip: true }]; + + // Act + const { getAllByTestId } = render(); + + // Assert - Mix UI & data in assertion + expect(getAllByTestId("user")).toEqual('[
  • John Doe
  • ]'); +}); +``` + +
    + +

    + +## ⚪ ️ 3.2 Query HTML elements based on attributes that are unlikely to change + +:white_check_mark: **Роби:** 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/logic 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 + +
    + +❌ **Інакше:** 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' + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: Querying an element using a dedicated attribute for testing + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") + +```html +// the markup code (part of React component) +

    + + {value} + + +

    +``` + +```javascript +// this example is using react-testing-library +test("Whenever no data is passed to metric, show 0 as default", () => { + // Arrange + const metricValue = undefined; + + // Act + const { getByTestId } = render(); + + expect(getByTestId("errorsLabel").text()).toBe("0"); +}); +``` + +
    + +### :thumbsdown: Anti-Pattern Example: Relying on CSS attributes + +```html + +{value} + +``` + +```javascript +// this exammple is using enzyme +test("Whenever no data is passed, error metric shows zero", () => { + // ... + + expect(wrapper.find("[className='d-flex-column']").text()).toBe("0"); +}); +``` + +
    + +
    + +## ⚪ ️ 3.3 Whenever possible, test with a realistic and fully rendered component + +:white_check_mark: **Роби:** 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://github.com/goldbergyoni/javascript-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 + +With all that said, a word of caution is in order: this technique works for small/medium 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 + +
    + +❌ **Інакше:** When poking into a component's internal by invoking its private methods, and checking the inner state - you would have to refactor all tests when refactoring the components implementation. Do you really have a capacity for this level of maintenance? + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: Working realistically with a fully rendered component + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Enzyme-blue.svg "Examples with Enzyme") + +```javascript +class Calendar extends React.Component { + static defaultProps = { showFilters: false }; + + render() { + return ( +
    + A filters panel with a button to hide/show filters + +
    + ); + } +} + +//Examples use React & Enzyme +test("Realistic approach: When clicked to show filters, filters are displayed", () => { + // Arrange + const wrapper = mount(); + + // Act + wrapper.find("button").simulate("click"); + + // Assert + expect(wrapper.text().includes("Choose Filter")); + // This is how the user will approach this element: by text +}); +``` + +### :thumbsdown: Anti-Pattern Example: Mocking the reality with shallow rendering + +```javascript +test("Shallow/mocked approach: When clicked to show filters, filters are displayed", () => { + // Arrange + const wrapper = shallow(); + + // Act + wrapper + .find("filtersPanel") + .instance() + .showFilters(); + // Tap into the internals, bypass the UI and invoke a method. White-box approach + + // Assert + expect(wrapper.find("Filter").props()).toEqual({ title: "Choose Filter" }); + // what if we change the prop name or don't pass anything relevant? +}); +``` + +
    + +
    + +## ⚪ ️ 3.4 Don't sleep, use frameworks built-in support for async events. Also try to speed things up + +:white_check_mark: **Роби:** In many cases, the unit under test completion time is just unknown (e.g. animation suspends element appearance) - in that case, avoid sleeping (e.g. setTimeOut) and prefer more deterministic methods that most platforms provide. Some libraries allows awaiting on operations (e.g. [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), other provide API for waiting like [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). Sometimes a more elegant way is to stub the slow resource, like API for example, and then once the response moment becomes deterministic the component can be explicitly re-rendered. When depending upon some external component that sleeps, it might turn useful to [hurry-up the clock](https://jestjs.io/docs/en/timer-mocks). Sleeping is a pattern to avoid because it forces your test to be slow or risky (when waiting for a too short period). Whenever sleeping and polling is inevitable and there's no support from the testing framework, some npm libraries like [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) can help with a semi-deterministic solution +
    + +❌ **Інакше:** When sleeping for a long time, tests will be an order of magnitude slower. When trying to sleep for small numbers, test will fail when the unit under test didn't respond in a timely fashion. So it boils down to a trade-off between flakiness and bad performance + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: E2E API that resolves only when the async operations is done (Cypress) + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") +![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +// using Cypress +cy.get("#show-products").click(); // navigate +cy.wait("@products"); // wait for route to appear +// this line will get executed only when the route is ready +``` + +### :clap: Doing It Right Example: Testing library that waits for DOM elements + +```javascript +// @testing-library/dom +test("movie title appears", async () => { + // element is initially not present... + + // wait for appearance + await wait(() => { + expect(getByText("the lion king")).toBeInTheDocument(); + }); + + // wait for appearance and return the element + const movie = await waitForElement(() => getByText("the lion king")); +}); +``` + +### :thumbsdown: Anti-Pattern Example: custom sleep code + +```javascript +test("movie title appears", async () => { + // element is initially not present... + + // custom wait logic (caution: simplistic, no timeout) + const interval = setInterval(() => { + const found = getByText("the lion king"); + if (found) { + clearInterval(interval); + expect(getByText("the lion king")).toBeInTheDocument(); + } + }, 100); + + // wait for appearance and return the element + const movie = await waitForElement(() => getByText("the lion king")); +}); +``` + +
    + +
    + +## ⚪ ️ 3.5 Watch how the content is served over the network + +![](https://img.shields.io/badge/🔧%20Example%20using%20Google%20LightHouse-blue.svg "Examples with Lighthouse") + +✅ **Роби:** Apply some active monitor that ensures the page load under real network is optimized - this includes any UX concern like slow page load or un-minified bundle. The inspection tools market is no short: basic tools like [pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) can be easily configured to watch whether the server is alive and response under a reasonable SLA. This only scratches the surface of what might get wrong, hence it's preferable to opt for tools that specialize in frontend (e.g. [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) and perform richer analysis. The focus should be on symptoms, metrics that directly affect the UX, like page load time, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [time until the page gets interactive (TTI)](https://calibreapp.com/blog/time-to-interactive/). On top of that, one may also watch for technical causes like ensuring the content is compressed, time to the first byte, optimize images, ensuring reasonable DOM size, SSL and many others. It's advisable to have these rich monitors both during development, as part of the CI and most important - 24x7 over the production's servers/CDN + +
    + +❌ **Інакше:** It must be disappointing to realize that after such great care for crafting a UI, 100% functional tests passing and sophisticated bundling - the UX is horrible and slow due to CDN misconfiguration + +
    + +
    Приклади коду + +### :clap: Doing It Right Example: Lighthouse page load inspection report + +![](/assets/lighthouse2.png "Lighthouse page load inspection report") + +
    + +
    + +## ⚪ ️ 3.6 Stub flaky and slow resources like backend APIs + +:white_check_mark: **Роби:** When coding your mainstream tests (not E2E tests), avoid involving any resource that is beyond your responsibility and control like backend API and use stubs instead (i.e. test double). Practically, instead of real network calls to APIs, use some test double library (like [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble), etc) for stubbing the API response. The main benefit is preventing flakiness - testing or staging APIs by definition are not highly stable and from time to time will fail your tests although YOUR component behaves just fine (production env was not meant for testing and it usually throttles requests). Doing this will allow simulating various API behavior that should drive your component behavior as when no data was found or the case when API throws an error. Last but not least, network calls will greatly slow down the tests + +
    + +❌ **Інакше:** The average test runs no longer than few ms, a typical API call last 100ms>, this makes each test ~20x slower + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: Stubbing or intercepting API calls + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +// unit under test +export default function ProductsList() { + const [products, setProducts] = useState(false); + + const fetchProducts = async () => { + const products = await axios.get("api/products"); + setProducts(products); + }; + + useEffect(() => { + fetchProducts(); + }, []); + + return products ?
    {products}
    :
    No products
    ; +} + +// test +test("When no products exist, show the appropriate message", () => { + // Arrange + nock("api") + .get(`/products`) + .reply(404); + + // Act + const { getByTestId } = render(); + + // Assert + expect(getByTestId("no-products-message")).toBeTruthy(); +}); +``` + +
    + +
    + +## ⚪ ️ 3.7 Have very few end-to-end tests that spans the whole system + +:white_check_mark: **Роби:** Although E2E (end-to-end) usually means UI-only testing with a real browser (See [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)), for other they mean tests that stretch the entire system including the real backend. The latter type of tests is highly valuable as they cover integration bugs between frontend and backend that might happen due to a wrong understanding of the exchange schema. They are also an efficient method to discover backend-to-backend integration issues (e.g. Microservice A sends the wrong message to Microservice B) and even to detect deployment failures - there are no backend frameworks for E2E testing that are as friendly and mature as UI frameworks like [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). The downside of such tests is the high cost of configuring an environment with so many components, and mostly their brittleness - given 50 microservices, even if one fails then the entire E2E just failed. For that reason, we should use this technique sparingly and probably have 1-10 of those and no more. That said, even a small number of E2E tests are likely to catch the type of issues they are targeted for - deployment & integration faults. It's advisable to run those over a production-like staging environment + +
    + +❌ **Інакше:** UI might invest much in testing its functionality only to realizes very late that the backend returned payload (the data schema the UI has to work with) is very different than expected + +
    + +## ⚪ ️ 3.8 Speed-up E2E tests by reusing login credentials + +:white_check_mark: **Роби:** In E2E tests that involve a real backend and rely on a valid user token for API calls, it doesn't payoff to isolate the test to a level where a user is created and logged-in in every request. Instead, login only once before the tests execution start (i.e. before-all hook), save the token in some local storage and reuse it across requests. This seem to violate one of the core testing principle - keep the test autonomous without resources coupling. While this is a valid worry, in E2E tests performance is a key concern and creating 1-3 API requests before starting each individual tests might lead to horrible execution time. Reusing credentials doesn't mean the tests have to act on the same user records - if relying on user records (e.g. test user payments history) than make sure to generate those records as part of the test and avoid sharing their existence with other tests. Also remember that the backend can be faked - if your tests are focused on the frontend it might be better to isolate it and stub the backend API (see [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)). + +
    + +❌ **Інакше:** Given 200 test cases and assuming login=100ms = 20 seconds only for logging-in again and again + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: Logging-in before-all and not before-each + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +let authenticationToken; + +// happens before ALL tests run +before(() => { + cy.request('POST', 'http://localhost:3000/login', { + username: Cypress.env('username'), + password: Cypress.env('password'), + }) + .its('body') + .then((responseFromLogin) => { + authenticationToken = responseFromLogin.token; + }) +}) + +// happens before EACH test +beforeEach(setUser => () { + cy.visit('/home', { + onBeforeLoad (win) { + win.localStorage.setItem('token', JSON.stringify(authenticationToken)) + }, + }) +}) + +``` + +
    + +
    + +## ⚪ ️ 3.9 Have one E2E smoke test that just travels across the site map + +:white_check_mark: **Роби:** For production monitoring and development-time sanity check, run a single E2E test that visits all/most of the site pages and ensures no one breaks. This type of test brings a great return on investment as it's very easy to write and maintain, but it can detect any kind of failure including functional, network and deployment issues. Other styles of smoke and sanity checking are not as reliable and exhaustive - some ops teams just ping the home page (production) or developers who run many integration tests which don't discover packaging and browser issues. Goes without saying that the smoke test doesn't replace functional tests rather just aim to serve as a quick smoke detector + +
    + +❌ **Інакше:** Everything might seem perfect, all tests pass, production health-check is also positive but the Payment component had some packaging issue and only the /Payment route is not rendering + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: Smoke travelling across all pages + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +it("When doing smoke testing over all page, should load them all successfully", () => { + // exemplified using Cypress but can be implemented easily + // using any E2E suite + cy.visit("https://mysite.com/home"); + cy.contains("Home"); + cy.visit("https://mysite.com/Login"); + cy.contains("Login"); + cy.visit("https://mysite.com/About"); + cy.contains("About"); +}); +``` + +
    + +
    + +## ⚪ ️ 3.10 Expose the tests as a live collaborative document + +:white_check_mark: **Роби:** Besides increasing app reliability, tests bring another attractive opportunity to the table - serve as live app documentation. Since tests inherently speak at a less-technical and product/UX language, using the right tools they can serve as a communication artifact that greatly aligns all the peers - developers and their customers. For example, some frameworks allow expressing the flow and expectations (i.e. tests plan) using a human-readable language so any stakeholder, including product managers, can read, approve and collaborate on the tests which just became the live requirements document. This technique is also being referred to as 'acceptance test' as it allows the customer to define his acceptance criteria in plain language. This is [BDD (behavior-driven testing)](https://en.wikipedia.org/wiki/Behavior-driven_development) at its purest form. One of the popular frameworks that enable this is [Cucumber which has a JavaScript flavor](https://github.com/cucumber/cucumber-js), see example below. Another similar yet different opportunity, [StoryBook](https://storybook.js.org/), allows exposing UI components as a graphic catalog where one can walk through the various states of each component (e.g. render a grid w/o filters, render that grid with multiple rows or with none, etc), see how it looks like, and how to trigger that state - this can appeal also to product folks but mostly serves as live doc for developers who consume those components. + +❌ **Інакше:** After investing top resources on testing, it's just a pity not to leverage this investment and win great value + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: Describing tests in human-language using cucumber-js + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Examples using Cucumber") + +```javascript +// this is how one can describe tests using cucumber: plain language that allows anyone to understand and collaborate + +Feature: Twitter new tweet + + I want to tweet something in Twitter + + @focus + Scenario: Tweeting from the home page + Given I open Twitter home + Given I click on "New tweet" button + Given I type "Hello followers!" in the textbox + Given I click on "Submit" button + Then I see message "Tweet saved" + +``` + +### :clap: Doing It Right Example: Visualizing our components, their various states and inputs using Storybook + +![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") + +![alt text](assets/story-book.jpg "Storybook") + +
    + +

    + +## ⚪ ️ 3.11 Detect visual issues with automated tools + +:white_check_mark: **Роби:** Setup automated tools to capture UI screenshots when changes are presented and detect visual issues like content overlapping or breaking. This ensures that not only the right data is prepared but also the user can conveniently see it. This technique is not widely adopted, our testing mindset leans toward functional tests but it's the visuals what the user experience and with so many device types it's very easy to overlook some nasty UI bug. Some free tools can provide the basics - generate and save screenshots for the inspection of human eyes. While this approach might be sufficient for small apps, it's flawed as any other manual testing that demands human labor anytime something changes. On the other hand, it's quite challenging to detect UI issues automatically due to the lack of clear definition - this is where the field of 'Visual Regression' chime in and solve this puzzle by comparing old UI with the latest changes and detect differences. Some OSS/free tools can provide some of this functionality (e.g. [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>) but might charge significant setup time. The commercial line of tools (e.g. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) takes is a step further by smoothing the installation and packing advanced features like management UI, alerting, smart capturing by eliminating 'visual noise' (e.g. ads, animations) and even root cause analysis of the DOM/CSS changes that led to the issue + +
    + +❌ **Інакше:** How good is a content page that display great content (100% tests passed), loads instantly but half of the content area is hidden? + +
    + +
    Приклади коду + +
    + +### :thumbsdown: Anti-Pattern Example: A typical visual regression - right content that is served badly + +![alt text](assets/amazon-visual-regression.jpeg "Amazon page breaks") + +
    + +### :clap: Doing It Right Example: Configuring wraith to capture and compare UI snapshots + +![](https://img.shields.io/badge/🔨%20Example%20using%20Wraith-blue.svg "Using Wraith") + +``` +​# Add as many domains as necessary. Key will act as a label​ + +domains: + english: "http://www.mysite.com"​ + +​# Type screen widths below, here are a couple of examples​ + +screen_widths: + + - 600​ + - 768​ + - 1024​ + - 1280​ + +​# Type page URL paths below, here are a couple of examples​ +paths: + about: + path: /about + selector: '.about'​ + subscribe: + selector: '.subscribe'​ + path: /subscribe +``` + +### :clap: Doing It Right Example: Using Applitools to get snapshot comparison and other advanced features + +![](https://img.shields.io/badge/🔨%20Example%20using%20AppliTools-blue.svg "Using Applitools") ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +import * as todoPage from "../page-objects/todo-page"; + +describe("visual validation", () => { + before(() => todoPage.navigate()); + beforeEach(() => cy.eyesOpen({ appName: "TAU TodoMVC" })); + afterEach(() => cy.eyesClose()); + + it("should look good", () => { + cy.eyesCheckWindow("empty todo list"); + todoPage.addTodo("Clean room"); + todoPage.addTodo("Learn javascript"); + cy.eyesCheckWindow("two todos"); + todoPage.toggleTodo(0); + cy.eyesCheckWindow("mark as completed"); + }); +}); +``` + +
    + +

    + +# Section 4️⃣: Measuring Test Effectiveness + +

    + +## ⚪ ️ 4.1 Get enough coverage for being confident, ~80% seems to be the lucky number + +:white_check_mark: **Роби:** The purpose of testing is to get enough confidence for moving fast, obviously the more code is tested the more confident the team can be. Coverage is a measure of how many code lines (and branches, statements, etc) are being reached by the tests. So how much is enough? 10–30% is obviously too low to get any sense about the build correctness, on the other side 100% is very expensive and might shift your focus from the critical paths to the exotic corners of the code. The long answer is that it depends on many factors like the type of application — if you’re building the next generation of Airbus A380 than 100% is a must, for a cartoon pictures website 50% might be too much. Although most of the testing enthusiasts claim that the right coverage threshold is contextual, most of them also mention the number 80% as a thumb of a rule ([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)) that presumably should satisfy most of the applications. + +Implementation tips: You may want to configure your continuous integration (CI) to have a coverage threshold ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) and stop a build that doesn’t stand to this standard (it’s also possible to configure threshold per component, see code example below). On top of this, consider detecting build coverage decrease (when a newly committed code has less coverage) — this will push developers raising or at least preserving the amount of tested code. All that said, coverage is only one measure, a quantitative based one, that is not enough to tell the robustness of your testing. And it can also be fooled as illustrated in the next bullets + +
    + +❌ **Інакше:** Confidence and numbers go hand in hand, without really knowing that you tested most of the system — there will also be some fear and fear will slow you down + +
    + +
    Приклади коду + +
    + +### :clap: Example: A typical coverage report + +![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "A typical coverage report") + +
    + +### :clap: Doing It Right Example: Setting up coverage per component (using Jest) + +![](https://img.shields.io/badge/🔨%20Example%20using%20Jest-blue.svg "Using Jest") + +![alt text](assets/bp-18-code-coverage2.jpeg "Setting up coverage per component (using Jest)") + +
    + +

    + +## ⚪ ️ 4.2 Inspect coverage reports to detect untested areas and other oddities + +:white_check_mark: **Роби:** Some issues sneak just under the radar and are really hard to find using traditional tools. These are not really bugs but more of surprising application behavior that might have a severe impact. For example, often some code areas are never or rarely being invoked — you thought that the ‘PricingCalculator’ class is always setting the product price but it turns out it is actually never invoked although we have 10000 products in DB and many sales… Code coverage reports help you realize whether the application behaves the way you believe it does. Other than that, it can also highlight which types of code is not tested — being informed that 80% of the code is tested doesn’t tell whether the critical parts are covered. Generating reports is easy — just run your app in production or during testing with coverage tracking and then see colorful reports that highlight how frequent each code area is invoked. If you take your time to glimpse into this data — you might find some gotchas +
    + +❌ **Інакше:** If you don’t know which parts of your code are left un-tested, you don’t know where the issues might come from + +
    + +
    Приклади коду + +
    + +### :thumbsdown: Anti-Pattern Example: What’s wrong with this coverage report? + +Based on a real-world scenario where we tracked our application usage in QA and find out interesting login patterns (Hint: the amount of login failures is non-proportional, something is clearly wrong. Finally it turned out that some frontend bug keeps hitting the backend login API) + +![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report?") + +
    + +

    + +## ⚪ ️ 4.3 Measure logical coverage using mutation testing + +:white_check_mark: **Роби:** The Traditional Coverage metric often lies: It may show you 100% code coverage, but none of your functions, even not one, return the right response. How come? it simply measures over which lines of code the test visited, but it doesn’t check if the tests actually tested anything — asserted for the right response. Like someone who’s traveling for business and showing his passport stamps — this doesn’t prove any work done, only that he visited few airports and hotels. + +Mutation-based testing is here to help by measuring the amount of code that was actually TESTED not just VISITED. [Stryker](https://stryker-mutator.io/) is a JavaScript library for mutation testing and the implementation is really neat: + +(1) it intentionally changes the code and “plants bugs”. For example the code newOrder.price===0 becomes newOrder.price!=0. This “bugs” are called mutations + +(2) it runs the tests, if all succeed then we have a problem — the tests didn’t serve their purpose of discovering bugs, the mutations are so-called survived. If the tests failed, then great, the mutations were killed. + +Knowing that all or most of the mutations were killed gives much higher confidence than traditional coverage and the setup time is similar +
    + +❌ **Інакше:** You’ll be fooled to believe that 85% coverage means your test will detect bugs in 85% of your code + +
    + +
    Приклади коду + +
    + +### :thumbsdown: Anti-Pattern Example: 100% coverage, 0% testing + +![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Using Stryker") + +```javascript +function addNewOrder(newOrder) { + logger.log(`Adding new order ${newOrder}`); + DB.save(newOrder); + Mailer.sendMail(newOrder.assignee, `A new order was places ${newOrder}`); + + return { approved: true }; +} + +it("Test addNewOrder, don't use such test names", () => { + addNewOrder({ assignee: "John@mailer.com", price: 120 }); +}); //Triggers 100% code coverage, but it doesn't check anything +``` + +
    + +### :clap: Doing It Right Example: Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations) + +![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations)") + +
    + +

    + +## ⚪ ️4.4 Preventing test code issues with Test linters + +:white_check_mark: **Роби:** A set of ESLint plugins were built specifically for inspecting the tests code patterns and discover issues. For example, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) will warn when a test is written at the global level (not a son of a describe() statement) or when tests are [skipped](https://mochajs.org/#inclusive-tests) which might lead to a false belief that all tests are passing. Similarly, [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) can, for example, warn when a test has no assertions at all (not checking anything) + +
    + +❌ **Інакше:** Seeing 90% code coverage and 100% green tests will make your face wear a big smile only until you realize that many tests aren’t asserting for anything and many test suites were just skipped. Hopefully, you didn’t deploy anything based on this false observation + +
    +
    Приклади коду + +
    + +### :thumbsdown: Anti-Pattern Example: A test case full of errors, luckily all are caught by Linters + +```javascript +describe("Too short description", () => { + const userToken = userService.getDefaultToken() // *error:no-setup-in-describe, use hooks (sparingly) instead + it("Some description", () => {});//* error: valid-test-description. Must include the word "Should" + at least 5 words +}); + +it.skip("Test name", () => {// *error:no-skipped-tests, error:error:no-global-tests. Put tests only under describe or suite + expect("somevalue"); // error:no-assert +}); + +it("Test name", () => {*//error:no-identical-title. Assign unique titles to tests +}); +``` + +
    + +

    + +# Section 5️⃣: CI and Other Quality Measures + +

    + +## ⚪ ️ 5.1 Enrich your linters and abort builds that have linting issues + +:white_check_mark: **Роби:** Linters are a free lunch, with 5 min setup you get for free an auto-pilot guarding your code and catching significant issue as you type. Gone are the days where linting was about cosmetics (no semi-colons!). Nowadays, Linters can catch severe issues like errors that are not thrown correctly and losing information. On top of your basic set of rules (like [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) or [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), consider including some specializing Linters like [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) that can discover tests without assertions, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) can discover promises with no resolve (your code will never continue), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) which can discover eager regex expressions that might get used for DOS attacks, and [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) is capable of alarming when the code uses utility library methods that are part of the V8 core methods like Lodash.\_map(…) +
    + +❌ **Інакше:** Consider a rainy day where your production keeps crashing but the logs don’t display the error stack trace. What happened? Your code mistakenly threw a non-error object and the stack trace was lost, a good reason for banging your head against a brick wall. A 5 min linter setup could detect this TYPO and save your day + +
    + +
    Приклади коду + +
    + +### :thumbsdown: Anti-Pattern Example: The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug + +![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug") + +
    + +

    + +## ⚪ ️ 5.2 Shorten the feedback loop with local developer-CI + +:white_check_mark: **Роби:** Using a CI with shiny quality inspections like testing, linting, vulnerabilities check, etc? Help developers run this pipeline also locally to solicit instant feedback and shorten the [feedback loop](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). Why? an efficient testing process constitutes many and iterative loops: (1) try-outs -> (2) feedback -> (3) refactor. The faster the feedback is, the more improvement iterations a developer can perform per-module and perfect the results. On the flip, when the feedback is late to come fewer improvement iterations could be packed into a single day, the team might already move forward to another topic/task/module and might not be up for refining that module. + +Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) allow running the pipeline locally. Some commercial tools like [wallaby provide highly-valuable & testing insights](https://wallabyjs.com/) as a developer prototype (no affiliation). Alternatively, you may just add npm script to package.json that runs all the quality commands (e.g. test, lint, vulnerabilities) — use tools like [concurrently](https://www.npmjs.com/package/concurrently) for parallelization and non-zero exit code if one of the tools failed. Now the developer should just invoke one command — e.g. ‘npm run quality’ — to get instant feedback. Consider also aborting a commit if the quality check failed using a githook ([husky can help](https://github.com/typicode/husky)) +
    + +❌ **Інакше:** When the quality results arrive the day after the code, testing doesn’t become a fluent part of development rather an after the fact formal artifact + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: npm scripts that perform code quality inspection, all are run in parallel on demand or when a developer is trying to push new code + +```javascript +"scripts": { + "inspect:sanity-testing": "mocha **/**--test.js --grep \"sanity\"", + "inspect:lint": "eslint .", + "inspect:vulnerabilities": "npm audit", + "inspect:license": "license-checker --failOn GPLv2", + "inspect:complexity": "plato .", + + "inspect:all": "concurrently -c \"bgBlue.bold,bgMagenta.bold,yellow\" \"npm:inspect:quick-testing\" \"npm:inspect:lint\" \"npm:inspect:vulnerabilities\" \"npm:inspect:license\"" + }, + "husky": { + "hooks": { + "precommit": "npm run inspect:all", + "prepush": "npm run inspect:all" + } +} + +``` + +
    + +

    + +## ⚪ ️5.3 Perform e2e testing over a true production-mirror + +:white_check_mark: **Роби:** End to end (e2e) testing are the main challenge of every CI pipeline — creating an identical ephemeral production mirror on the fly with all the related cloud services can be tedious and expensive. Finding the best compromise is your game: [Docker-compose](https://serverless.com/) allows crafting isolated dockerized environment with identical containers using a single plain text file but the backing technology (e.g. networking, deployment model) is different from real-world productions. You may combine it with [‘AWS Local’](https://github.com/localstack/localstack) to work with a stub of the real AWS services. If you went [serverless](https://serverless.com/) multiple frameworks like serverless and [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) allows the local invocation of FaaS code. + +The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for local and CI-mirroring though many new tools are launched frequently. One approach is running a ‘minimized-Kubernetes’ using tools like [Minikube](https://kubernetes.io/docs/setup/minikube/) and [MicroK8s](https://microk8s.io/) which resemble the real thing only come with less overhead. Another approach is testing over a remote ‘real-Kubernetes’, some CI providers (e.g. [Codefresh](https://codefresh.io/)) has native integration with Kubernetes environment and make it easy to run the CI pipeline over the real thing, others allow custom scripting against a remote Kubernetes. +
    + +❌ **Інакше:** Using different technologies for production and testing demands maintaining two deployment models and keeps the developers and the ops team separated + +
    + +
    Приклади коду + +
    + +### :clap: Example: a CI pipeline that generates Kubernetes cluster on the fly ([Credit: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/)) + +
    deploy:
    stage: deploy
    image: registry.gitlab.com/gitlab-examples/kubernetes-deploy
    script:
    - ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN
    - kubectl create ns $NAMESPACE
    - kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL"
    - mkdir .generated
    - echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF"
    - sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml"
    - kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml
    - kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml
    environment:
    name: test-for-ci
    + +
    + +

    + +## ⚪ ️5.4 Parallelize test execution + +:white_check_mark: **Роби:** When done right, testing is your 24/7 friend providing almost instant feedback. In practice, executing 500 CPU-bounded unit test on a single thread can take too long. Luckily, modern test runners and CI platforms (like [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) and [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) can parallelize the test into multiple processes and achieve significant improvement in feedback time. Some CI vendors do also parallelize tests across containers (!) which shortens the feedback loop even further. Whether locally over multiple processes, or over some cloud CLI using multiple machines — parallelizing demand keeping the tests autonomous as each might run on different processes + +❌ **Інакше:** Getting test results 1 hour long after pushing new code, as you already code the next features, is a great recipe for making testing less relevant + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) + +![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization (Credit: JavaScript Test-Runners Benchmark)") + +
    + +

    + +## ⚪ ️5.5 Stay away from legal issues using license and plagiarism check + +:white_check_mark: **Роби:** Licensing and plagiarism issues are probably not your main concern right now, but why not tick this box as well in 10 minutes? A bunch of npm packages like [license check](https://www.npmjs.com/package/license-checker) and [plagiarism check](https://www.npmjs.com/package/plagiarism-checker) (commercial with free plan) can be easily baked into your CI pipeline and inspect for sorrows like dependencies with restrictive licenses or code that was copy-pasted from Stack Overflow and apparently violates some copyrights + +❌ **Інакше:** Unintentionally, developers might use packages with inappropriate licenses or copy paste commercial code and run into legal issues + +
    + +
    Приклади коду + +
    + +### :clap: Doing It Right Example: + +```javascript +//install license-checker in your CI environment or also locally +npm install -g license-checker + +//ask it to scan all licenses and fail with exit code other than 0 if it found unauthorized license. The CI system should catch this failure and stop the build +license-checker --summary --failOn BSD + +``` + +
    + +![alt text](assets/bp-25-nodejs-licsense.png) + +
    + +

    + +## ⚪ ️5.6 Constantly inspect for vulnerable dependencies + +:white_check_mark: **Роби:** Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using community tools such as [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), or commercial tools like [snyk](https://snyk.io/) (offer also a free community version). Both can be invoked from your CI on every build + +❌ **Інакше:** Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online publications about new threats. Quite tedious + +
    + +
    Приклади коду + +
    + +### :clap: Example: NPM Audit result + +![alt text](assets/bp-26-npm-audit-snyk.png "NPM Audit result") + +
    + +

    + +## ⚪ ️5.7 Automate dependency updates + +:white_check_mark: **Роби:** Yarn and npm latest introduction of package-lock.json introduced a serious challenge (the road to hell is paved with good intentions) — by default now, packages are no longer getting updates. Even a team running many fresh deployments with ‘npm install’ & ‘npm update’ won’t get any new updates. This leads to subpar dependent packages versions at best or to vulnerable code at worst. Teams now rely on developers goodwill and memory to manually update the package.json or use tools [like ncu](https://www.npmjs.com/package/npm-check-updates) manually. A more reliable way could be to automate the process of getting the most reliable dependency versions, though there are no silver bullet solutions yet there are two possible automation roads: + +(1) CI can fail builds that have obsolete dependencies — using tools like [‘npm outdated’](https://docs.npmjs.com/cli/outdated) or ‘npm-check-updates (ncu)’ . Doing so will enforce developers to update dependencies. + +(2) Use commercial tools that scan the code and automatically send pull requests with updated dependencies. One interesting question remaining is what should be the dependency update policy — updating on every patch generates too many overhead, updating right when a major is released might point to an unstable version (many packages found vulnerable on the very first days after being released, [see the](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) eslint-scope incident). + +An efficient update policy may allow some ‘vesting period’ — let the code lag behind the @latest for some time and versions before considering the local copy as obsolete (e.g. local version is 1.3.1 and repository version is 1.3.8) +
    + +❌ **Інакше:** Your production will run packages that have been explicitly tagged by their author as risky + +
    + +
    Приклади коду + +
    + +### :clap: Example: [ncu](https://www.npmjs.com/package/npm-check-updates) can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions + +![alt text](assets/bp-27-yoni-goldberg-npm.png "ncu can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions") + +
    + +

    + +## ⚪ ️ 5.8 Other, non-Node related, CI tips + +:white_check_mark: **Роби:** This post is focused on testing advice that is related to, or at least can be exemplified with Node JS. This bullet, however, groups few non-Node related tips that are well-known + +
    1. Use a declarative syntax. This is the only option for most vendors but older versions of Jenkins allows using code or UI
    2. Opt for a vendor that has native Docker support
    3. Fail early, run your fastest tests first. Create a ‘Smoke testing’ step/milestone that groups multiple fast inspections (e.g. linting, unit tests) and provide snappy feedback to the code committer
    4. Make it easy to skim-through all build artifacts including test reports, coverage reports, mutation reports, logs, etc
    5. Create multiple pipelines/jobs for each event, reuse steps between them. For example, configure a job for feature branch commits and a different one for master PR. Let each reuse logic using shared steps (most vendors provide some mechanism for code reuse)
    6. Never embed secrets in a job declaration, grab them from a secret store or from the job’s configuration
    7. Explicitly bump version in a release build or at least ensure the developer did so
    8. Build only once and perform all the inspections over the single build artifact (e.g. Docker image)
    9. Test in an ephemeral environment that doesn’t drift state between builds. Caching node_modules might be the only exception
    +
    + +❌ **Інакше:** You‘ll miss years of wisdom + +

    + +## ⚪ ️ 5.9 Build matrix: Run the same CI steps using multiple Node versions + +:white_check_mark: **Роби:** Quality checking is about serendipity, the more ground you cover the luckier you get in detecting issues early. When developing reusable packages or running a multi-customer production with various configuration and Node versions, the CI must run the pipeline of tests over all the permutations of configurations. For example, assuming we use MySQL for some customers and Postgres for others — some CI vendors support a feature called ‘Matrix’ which allow running the suit of testing against all permutations of MySQL, Postgres and multiple Node version like 8, 9 and 10. This is done using configuration only without any additional effort (assuming you have testing or any other quality checks). Other CIs who doesn’t support Matrix might have extensions or tweaks to allow that +
    + +❌ **Інакше:** So after doing all that hard work of writing testing are we going to let bugs sneak in only because of configuration issues? + +
    + +
    Приклади коду + +
    + +### :clap: Example: Using Travis (CI vendor) build definition to run the same test over multiple Node versions + +
    language: node_js
    node_js:
    - "7"
    - "6"
    - "5"
    - "4"
    install:
    - npm install
    script:
    - npm run test
    +
    + +

    + +# Team + +## Yoni Goldberg + +
    + +
    + +**Role:** Writer + +**About:** I'm an independent consultant who works with Fortune 500 companies and garage startups on polishing their JS & Node.js applications. More than any other topic I'm fascinated by and aims to master the art of testing. I'm also the author of [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices) + +**📗 Online Course:** Liked this guide and wish to take your testing skills to the extreme? Consider visiting my comprehensive course [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) + +
    + +**Follow:** + +- [🐦 Twitter](https://twitter.com/goldbergyoni/) +- [📞 Contact](https://testjavascript.com/contact-2/) +- [✉️ Newsletter](https://testjavascript.com/newsletter//) + +
    +
    +
    + +## [Bruno Scheufler](https://github.com/BrunoScheufler) + +**Role:** Tech reviewer and advisor + +Took care to revise, improve, lint and polish all the texts + +**About:** full-stack web engineer, Node.js & GraphQL enthusiast + +
    +
    + +## [Ido Richter](https://github.com/idori) + +**Role:** Concept, design and great advice + +**About:** A savvy frontend developer, CSS expert and emojis freak + +## [Kyle Martin](https://github.com/js-kyle) + +**Role:** Helps keep this project running, and reviews security related practices + +**About:** Loves working on Node.js projects and web application security. + +## Contributors ✨ + +Thanks goes to these wonderful people who have contributed to this repository! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Scott Davis

    🖋

    Adrien REDON

    🖋

    Stefano Magni

    🖋

    Yeoh Joer

    🖋

    Jhonny Moreira

    🖋

    Ian Germann

    🖋

    Hafez

    🖋

    Ruxandra Fediuc

    🖋

    Jack

    🖋

    Peter Carrero

    🖋

    Huhgawz

    🖋

    Haakon Borch

    🖋

    Jaime Mendoza

    🖋

    Cameron Dunford

    🖋

    John Gee

    🖋

    Aurelijus Rožėnas

    🖋

    Aaron

    🖋

    Tom Nagle

    🖋

    Yves yao

    🖋

    Userbit

    🖋

    Glaucia Lemos

    🚧

    koooge

    🖋

    Michal

    🖋

    roywalker

    🖋

    dangen

    🖋

    biesiadamich

    🖋

    Yanlin Jiang

    🖋

    sanguino

    🖋

    Morgan

    🖋

    Lukas Bischof

    ⚠️ 🖋

    JuanMa Ruiz

    🖋

    Luís Ângelo Rodrigues Jr.

    🖋

    José Fernández

    🖋

    Alejandro Gutierrez Barcenilla

    🖋

    Jason

    🖋

    Otavio Araujo

    ⚠️ 🖋

    Alex Ivanov

    🖋

    Yiqiao Xu

    🖋

    YuBin, Hsu

    🌍 💻
    + + + + + From f9f0a51b82d36103ee85da7e0daf604cdce4372a Mon Sep 17 00:00:00 2001 From: Serhii Shramko Date: Sun, 31 Jul 2022 16:41:07 +0200 Subject: [PATCH 142/189] feat: implement 1 chapter --- readme-ua.md | 231 +++++++++++++++++++++++++-------------------------- 1 file changed, 115 insertions(+), 116 deletions(-) diff --git a/readme-ua.md b/readme-ua.md index aa5b9552..56f5fd4b 100644 --- a/readme-ua.md +++ b/readme-ua.md @@ -21,8 +21,8 @@ ### Написав Yoni Goldberg - JavaScript & Node.js консультант -- 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - Мій комплексний онлайн-курс із більш ніж [7 годинами відео](https://www.testjavascript.com), 14 типів тестів і більше 40 кращих практик -- [Follow me on Twitter](https://twitter.com/goldbergyoni/) +- 📗 [Тестування Node.js і JavaScript від А до Я](https://www.testjavascript.com) - Мій комплексний онлайн-курс із більш ніж [7 годинами відео](https://www.testjavascript.com), 14 типів тестів і більше 40 кращих практик +- [Слідкуйте за мною в Twitter](https://twitter.com/goldbergyoni/)
    @@ -174,7 +174,7 @@ describe('Products Service', function() { ### :clap: Роби це правильно. Приклад: тест, структурований за шаблоном AAA -![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Приклади з Jest") ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Приклади з Mocha") ```javascript describe("Customer classifier", () => { @@ -220,7 +220,7 @@ test("Should be classified as premium", () => {
    Приклади коду
    -![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Приклади з Mocha & Chai") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Приклади з Mocha & Chai") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Приклади з Jest") ### :thumbsdown: Приклад антишаблону: читач повинен проглянути довгий код і імперативний код, щоб зрозуміти суть @@ -370,12 +370,12 @@ it("When a valid product is about to be deleted, ensure an email is sent", async

    -## ⚪ ️1.6 Don’t “foo”, use realistic input data +## ⚪ ️1.6 Використовуйте реалістичні вхідні дані -:white_check_mark: **Роби:** 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://github.com/chancejs/chancejs) or [Faker](https://www.npmjs.com/package/faker) 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 card, 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). +:white_check_mark: **Роби:** Часто production помилки виявляються під час дуже специфічних і несподіваних вхідних даних — ««чим реалістичнішими є тестові вхідні дані, тим більші шанси виявити помилки на ранній стадії. Використовуйте спеціальні бібліотеки, як-от [Chance](https://github.com/chancejs/chancejs) або [Faker](https://www.npmjs.com/package/faker), щоб генерувати псевдореальні дані. Наприклад, такі бібліотеки можуть створювати реалістичні номери телефонів, імена користувачів, кредитні картки, назви компаній і навіть текст «lorem ipsum». Ви також можете створити деякі тести (на додаток до модульних тестів, а не як заміну), які рандомізують дані фальсифікаторів, щоб розширити тестований блок або навіть імпортувати реальні дані з вашого робочого середовища. Хочете перейти на новий рівень? Дивіться наступний пункт (тестування на основі властивостей).
    -❌ **Інакше:** 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” +❌ **Інакше:** Усе ваше тестування розробки хибно показуватиме зелений колір, якщо ви використовуєте синтетичні вхідні дані, як-от «Foo», але тоді production може стати червоним, коли хакер передасть неприємний рядок, як-от «@3e2ddsf». ##’ 1 fdsfds . fds432 AAAA”
    @@ -383,40 +383,40 @@ it("When a valid product is about to be deleted, ensure an email is sent", async
    -### :thumbsdown: Anti-Pattern Example: A test suite that passes due to non-realistic data +### :thumbsdown: Приклад антишаблону: набір тестів, який проходить через нереалістичні дані -![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Приклади з Jest") ```javascript const addProduct = (name, price) => { - const productNameRegexNoSpace = /^\S*$/; //no white-space allowed + const productNameRegexNoSpace = /^\S*$/; // white-space не допускаються - if (!productNameRegexNoSpace.test(name)) return false; //this path never reached due to dull input + if (!productNameRegexNoSpace.test(name)) return false; // цей шлях не досягнуто через рінній вихід - //some logic here + // Логіка тут return true; }; test("Wrong: When adding new product with valid properties, get successful confirmation", async () => { - //The string "Foo" which is used in all tests never triggers a false result + // Рядок "Foo", який використовується в усіх тестах, ніколи не викликає хибний результат const addProductResult = addProduct("Foo", 5); expect(addProductResult).toBe(true); - //Positive-false: the operation succeeded because we never tried with long - //product name including spaces + // Позитивний-хибний: операція вдалася, тому що ми ніколи не намагалися використати + // назву продукту з пробілами }); ```
    -### :clap:Doing It Right Example: Randomizing realistic input +### :clap:Роби це правильно. Приклад: рандомізація реалістичного введення ```javascript it("Better: When adding new valid product, get successful confirmation", async () => { const addProductResult = addProduct(faker.commerce.productName(), faker.random.number()); - //Generated random input: {'Sleek Cotton Computer', 85481} + // Згенеровані випадкові данні: {'Sleek Cotton Computer', 85481} expect(addProductResult).to.be.true; - //Test failed, the random input triggered some path we never planned for. - //We discovered a bug early! + // Тест провалився, випадковий вхід ініціював певний шлях, який ми не планували. + // Ми рано виявили помилку! }); ``` @@ -424,12 +424,12 @@ it("Better: When adding new valid product, get successful confirmation", async (

    -## ⚪ ️ 1.7 Test many input combinations using Property-based testing +## ⚪ ️ 1.7 Перевірте багато вхідних комбінацій за допомогою тестування на основі властивостей -:white_check_mark: **Роби:** 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://github.com/goldbergyoni/javascript-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://en.wikipedia.org/wiki/Fuzzing)). 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: by 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://github.com/jsverify/jsverify) or [testcheck](https://github.com/leebyron/testcheck-js) (much better documentation). Update: Nicolas Dubien suggests in the comments below to [checkout fast-check](https://github.com/dubzzz/fast-check#readme) which seems to offer some additional features and also to be actively maintained +:white_check_mark: **Роби:** Зазвичай ми обираємо кілька вхідних зразків для кожного тесту. Навіть якщо формат введення нагадує реальні дані (дивись [‘Don’t foo’](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F16-dont-foo-use-realistic-input-data)), ми розглядаємо лише кілька комбінацій вводу (method(‘’, true, 1), method(“string” , false , 0)), Однак production API, який викликається з 5 параметрами, може бути викликаний із тисячами різних перестановок, одна з яких може призвести до зупинки нашого процесу ([дивись Fuzz тестування](https://en.wikipedia.org/wiki/Fuzzing)). Що, якби ви могли написати один тест, який автоматично надсилає 1000 перестановок різних вхідних даних і виявляє, для якого вхідного сигналу наш код не повертає правильну відповідь? Тестування на основі властивостей — це техніка, яка робить саме це: надсилаючи всі можливі комбінації вхідних даних до вашого тестованого пристрою, це збільшує ймовірність виявлення помилки. Наприклад, задано метод — addNewProduct(id, name, isDiscount) — бібліотеки, що підтримують, викличуть цей метод із багатьма комбінаціями (число, рядок, логічний вираз), наприклад (1, «iPhone», false), (2, «Galaxy» », правда). Ви можете запустити тестування на основі властивостей за допомогою улюбленого засобу виконання тестів (Mocha, Jest тощо), використовуючи такі бібліотеки, як [js-verify](https://github.com/jsverify/jsverify) чи [testcheck](https://github.com/leebyron/testcheck-js) (значно краща документація). Оновлення: Nicolas Dubien пропонує в коментарях нижче [checkout fast-check](https://github.com/dubzzz/fast-check#readme) який, здається, пропонує деякі додаткові функції та також активно підтримується
    -❌ **Інакше:** 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 +❌ **Інакше:** Несвідомо ви обираєте тестові вхідні дані, які охоплюють лише шляхи коду, які добре працюють. На жаль, це знижує ефективність тестування як засобу виявлення помилок
    @@ -437,16 +437,16 @@ it("Better: When adding new valid product, get successful confirmation", async (
    -### :clap: Doing It Right Example: Testing many input permutations with “fast-check” +### :clap: Приклад правильного виконання: Тестування багатьох вхідних перестановок за допомогою “fast-check” -![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Приклади з Jest") ```javascript import fc from "fast-check"; describe("Product service", () => { describe("Adding new", () => { - //this will run 100 times with different random properties + // буде виконано 100 разів з різними випадковими властивостями it("Add new product with random yet valid properties, always successful", () => fc.assert( fc.property(fc.integer(), fc.string(), (id, name) => { @@ -461,16 +461,15 @@ describe("Product service", () => {

    -## ⚪ ️ 1.8 If needed, use only short & inline snapshots +## ⚪ ️ 1.8 За потреби використовуйте лише короткі та вбудовані знімки -:white_check_mark: **Роби:** When there is a need for [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), use only short and focused snapshots (i.e. 3-7 lines) that are included as part of the test ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)) and not within external files. Keeping this guideline will ensure your tests remain self-explanatory and less fragile. +:white_check_mark: **Роби:** Коли є потреба в [снепшот тестуванні](https://jestjs.io/docs/en/snapshot-testing), використовуйте лише короткі та цілеспрямовані снепшоти (3-7 рядків) які входять до складу тесту ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)) а не в зовнішніх файлах. Дотримуючись цієї вказівки, ваші тести залишатимуться зрозумілими та менш крихкими. -On the other hand, ‘classic snapshots’ tutorials and tools encourage to store big files (e.g. component rendering markup, API JSON result) over some external medium and ensure each time when the test run 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/HTML 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 to 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 +З іншого боку, навчальні посібники та інструменти «класичних знімків» заохочують зберігати великі файли (наприклад, розмітку візуалізації компонентів, результат JSON API) на зовнішньому носії та забезпечувати порівняння отриманого результату зі збереженою версією під час кожного тестового запуску. Це, наприклад, може неявно поєднати наш тест із 1000 рядками з 3000 значеннями даних, які автор тесту ніколи не читав і не міркував. Чому це неправильно? Таким чином, є 1000 причин невдачі вашого тесту - достатньо змінити один рядок, щоб знімок став недійсним, і це, ймовірно, станеться часто. Як часто? для кожного пробілу, коментаря або незначної зміни CSS/HTML. Крім того, назва тесту не дасть підказки про помилку, оскільки вона лише перевіряє, чи не змінилися 1000 рядків, а також заохочує автора тесту прийняти за бажаний істинний довгий документ, який він не міг перевірити та перевірити. Усе це симптоми незрозумілого та жадібного випробування, яке не є зосередженим і спрямоване на досягнення занадто багато -It’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 -
    +Варто зазначити, що є кілька випадків, коли довгі та зовнішні снепшоти є прийнятними - коли стверджується на схемі, а не на даних (вилучення значень і фокусування на полях) або коли отриманий документ рідко змінюється
    -❌ **Інакше:** A UI test fails. The code seems right, the screen renders perfect pixels, what happened? your snapshot testing just found a difference from the origin document to current received one - a single space character was added to the markdown... +❌ **Інакше:** UI тести впали. Код виглядає правильним, екран відображає ідеально все, що сталося? Ваше тестування снепшотів щойно виявило різницю між вихідним документом і поточним отриманим документом – до розмітки додано один пробіл...
    @@ -478,9 +477,9 @@ It’s worth noting that there are few cases where long & external snapshots are
    -### :thumbsdown: Anti-Pattern Example: Coupling our test to unseen 2000 lines of code +### :thumbsdown: Приклад антишаблону: Поєднання нашого тесту з невидимими 2000 рядками коду -![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Приклади з Jest") ```javascript it("TestJavaScript.com is renderd correctly", () => { @@ -493,14 +492,14 @@ it("TestJavaScript.com is renderd correctly", () => { //Assert expect(receivedPage).toMatchSnapshot(); - //We now implicitly maintain a 2000 lines long document - //every additional line break or comment - will break this test + //Тепер ми неявно підтримуємо документ довжиною 2000 рядків + //кожен додатковий розрив рядка або коментар - порушить цей тест }); ```
    -### :clap: Doing It Right Example: Expectations are visible and focused +### :clap: Приклад правильного виконання: Очікування помітні та цілеспрямовані ```javascript it("When visiting TestJavaScript.com home page, a menu is displayed", () => { @@ -528,12 +527,12 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => {

    -## ⚪ ️Copy code, but only what's neccessary +## ⚪ ️Скопіюйте код, але тільки необхідний -:white_check_mark: **Роби:** 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 mention explictly 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. +:white_check_mark: **Роби:** Включіть усі необхідні деталі, які впливають на результат тесту, але не більше того. Як приклад, розглянемо тест, який має розраховувати 100 рядків вхідного JSON - Вставляти це в кожен тест утомливо. Якщо витягти його за межі transferFactory.getJSON(), тест залишиться невизначеним - Без даних важко співвіднести результат тесту з причиною («чому він має повертати статус 400?»). Класичні книжкові шаблони x-unit назвали цей шаблон «таємничим гостем» - Щось невидиме вплинуло на наші результати тестування, ми не знаємо, що саме. Ми можемо досягти кращих результатів, витягнувши повторювані довгі частини назовні І чітко зазначивши, які конкретні деталі мають значення для тесту. Переходячи до наведеного вище прикладу, тест може передавати параметри, які підкреслюють важливість: transferFactory.getJSON({sender: undefined}). У цьому прикладі читач повинен негайно зробити висновок, що порожнє поле відправника є причиною, чому тест повинен очікувати помилку перевірки або будь-який інший подібний адекватний результат.
    -❌ **Інакше:** 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 +❌ **Інакше:** Копіювання 500 рядків JSON зробить ваші тести непридатними для обслуговування та читання. Перенесення всього назовні закінчиться нечіткими тестами, які важко зрозуміти
    @@ -541,40 +540,40 @@ it("When visiting TestJavaScript.com home page, a menu is displayed", () => {
    -### :thumbsdown: Anti-Pattern Example: The test failure is unclear because all the cause is external and hides within huge JSON +### :thumbsdown: Приклад антишаблону: Помилка тесту незрозуміла, оскільки вся причина зовнішня і ховається у величезному JSON -![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Приклади з Mocha") ```javascript test("When no credit, then the transfer is declined", async() => { // Arrange - const transferRequest = testHelpers.factorMoneyTransfer() //get back 200 lines of JSON; + const transferRequest = testHelpers.factorMoneyTransfer() // повертає 200 рядків JSON; const transferServiceUnderTest = new TransferService(); // Act const transferResponse = await transferServiceUnderTest.transfer(transferRequest); // Assert - expect(transferResponse.status).toBe(409);// But why do we expect failure: All seems perfectly valid in the test 🤔 + expect(transferResponse.status).toBe(409);// Але чому ми очікуємо невдачі: у тесті все здається абсолютно дійсним 🤔 }); ```
    -### :clap: Doing It Right Example: The test highlights what is the cause of the test result +### :clap: Приклад правильного виконання: Тест підкреслює, що є причиною результату тесту ```javascript test("When no credit, then the transfer is declined ", async() => { // Arrange - const transferRequest = testHelpers.factorMoneyTransfer({userCredit:100, transferAmount:200}) //obviously there is lack of credit + const transferRequest = testHelpers.factorMoneyTransfer({userCredit:100, transferAmount:200}) // очевидно, брак кредитів const transferServiceUnderTest = new TransferService({disallowOvercharge:true}); // Act const transferResponse = await transferServiceUnderTest.transfer(transferRequest); // Assert - expect(transferResponse.status).toBe(409); // Obviously if the user has no credit it should fail + expect(transferResponse.status).toBe(409); // Очевидно, що якщо у користувача немає кредиту, тест впаде }); ``` @@ -582,14 +581,14 @@ test("When no credit, then the transfer is declined ", async() => {

    -## ⚪ ️ 1.10 Don’t catch errors, expect them +## ⚪ ️ 1.10 Не ловіть помилки, очікуйте їх -:white_check_mark: **Роби:** 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 +:white_check_mark: **Роби:** Під час спроби стверджувати, що якийсь вхід викликає помилку, може виглядати правильним використання try-catch-finally і підтверджує, що було введено пропозицію catch. Результатом є незручний і багатослівний тестовий приклад (приклад нижче), який приховує простий намір тесту та очікування результату -A 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 +Більш елегантною альтернативою є використання однорядкового виділеного твердження Chai: expect(method).to.throw (або Jest: expect(method).toThrow()). Абсолютно обовʼязково також переконатися, що виняток містить властивість, яка повідомляє тип помилки, інакше, враховуючи лише загальну помилку і покаже користувачеві невтішне повідомлення
    -❌ **Інакше:** It will be challenging to infer from the test reports (e.g. CI reports) what went wrong +❌ **Інакше:** Буде складно зробити висновок зі звітів про випробування (наприклад, звітів CI), що пішло не так
    @@ -597,9 +596,9 @@ A more elegant alternative is the using the one-line dedicated Chai assertion: e
    -### :thumbsdown: Anti-pattern Example: A long test case that tries to assert the existence of error with try-catch +### :thumbsdown: Приклад антишаблону: Довгий тестовий приклад, який намагається підтвердити існування помилки за допомогою try-catch -![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Приклади з Mocha") ```javascript it("When no product name, it throws error 400", async () => { @@ -611,14 +610,14 @@ it("When no product name, it throws error 400", async () => { errorWeExceptFor = error; } expect(errorWeExceptFor).not.to.be.null; - //if this assertion fails, the tests results/reports will only show - //that some value is null, there won't be a word about a missing Exception + // якщо це твердження не виконується, відображатимуться лише результати тестів/звіти + // якщо якесь значення дорівнює нулю, не буде жодного слова про відсутній виняток }); ```
    -### :clap: Doing It Right Example: A human-readable expectation that could be understood easily, maybe even by QA or technical PM +### :clap: Приклад правильного виконання: Очікування, зрозумілі людині, які можуть бути легко зрозумілі, можливо, навіть спеціалістам QA або PM ```javascript it("When no product name, it throws error 400", async () => { @@ -632,12 +631,12 @@ it("When no product name, it throws error 400", async () => {

    -## ⚪ ️ 1.11 Tag your tests +## ⚪ ️ 1.11 Позначте свої тести -:white_check_mark: **Роби:** 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’ +:white_check_mark: **Роби:** Різні тести повинні виконуватися за різними сценаріями: quick smoke, без IO, тести мають запускатися, коли розробник зберігає або фіксує файл, повні наскрізні тести (e2e) зазвичай запускаються, коли надсилається новий запит на отримання тощо. Цього можна досягти позначаючи тести ключовими словами, як-от #cold #api #sanity, щоб ви могли працювати зі своїм пакетом тестування та викликати потрібну підмножину. Наприклад, ось як ви можете викликати лише групу перевірки розумності за допомогою Mocha: mocha — grep ‘sanity’
    -❌ **Інакше:** 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 +❌ **Інакше:** Виконання всіх тестів, у тому числі тестів, які виконують десятки запитів до БД, щоразу, коли розробник вносить невеликі зміни, може бути надзвичайно повільним і утримувати розробників від виконання тестівВиконання всіх тестів, у тому числі тестів, які виконують десятки запитів до БД, щоразу, коли розробник вносить невеликі зміни, може бути надзвичайно повільним і утримувати розробників від виконання тестів
    @@ -645,17 +644,17 @@ it("When no product name, it throws error 400", async () => {
    -### :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) +### :clap: Приклад правильного виконання: Позначення тестів як «#cold-test» дозволяє тестувальнику виконувати лише швидкі тести (Cold===швидкі тести, які не виконують введення-виведення (IO) та можуть виконуватися часто, навіть коли розробник вводить текст) -![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Приклади з Jest") ```javascript -//this test is fast (no DB) and we're tagging it correspondigly -//now the user/CI can run it frequently +// цей тест швидкий (без БД), і ми позначаємо його відповідним чином +// тепер користувач/CI може запускати його часто describe("Order service", function() { describe("Add new order #cold-test #sanity", function() { test("Scenario - no currency was supplied. Expectation - Use the default currency #sanity", function() { - //code logic here + // Логіка тут }); }); }); @@ -665,13 +664,13 @@ describe("Order service", function() {

    -## ⚪ ️ 1.12 Categorize tests under at least 2 levels +## ⚪ ️ 1.12 Класифікуйте тести принаймні за 2 рівнями -:white_check_mark: **Роби:** 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 additional level of categorization like the scenario or custom categories (see Приклади коду and print screen below). Doing so will also greatly improve the test reports: The reader will easily infer the tests 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 test suite that you may consider like [given-when-then](https://github.com/searls/jasmine-given) and [RITE](https://github.com/ericelliott/riteway) +:white_check_mark: **Роби:** Застосуйте певну структуру до свого набору тестів, щоб випадковий відвідувач міг легко зрозуміти вимоги (тести — найкраща документація) і різні сценарії, які тестуються. Звичайним методом для цього є розміщення принаймні 2 блоків «describe» над вашими тестами: 1-й призначений для назви тестованого блоку, а 2-й для додаткового рівня категоризації, як-от сценарій або спеціальні категорії (дивись Приклади коду). Це також значно покращить звіти про тести: читач легко визначить категорії тестів, заглибиться в потрібний розділ і порівнює невдалі тести. Крім того, розробнику стане набагато легше орієнтуватися в коді набору з багатьма тестами. Існує кілька альтернативних структур для набору тестів, які ви можете розглянути, наприклад [given-when-then](https://github.com/searls/jasmine-given) і [RITE](https://github.com/ericelliott/riteway)
    -❌ **Інакше:** When looking at a report with flat and long list of tests, the reader have to skim-read through long texts to conclude the major scenarios and correlate the commonality of failing tests. Consider the following case: When 7/100 tests fail, looking at a flat list will demand reading the failing tests text 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 +❌ **Інакше:** Дивлячись на звіт із плоским і довгим списком тестів, читач повинен побіжно прочитати довгі тексти, щоб зробити висновок про основні сценарії та співвіднести загальність невдалих тестів. Розглянемо наступний випадок: коли 7/100 тестів не вдаються, перегляд плоского списку потребує прочитання тексту невдалих тестів, щоб побачити, як вони пов’язані один з одним. Однак в ієрархічному звіті всі вони можуть входити до одного потоку або категорії, і читач швидко зрозуміє, що або принаймні де є основна причина збою
    @@ -679,19 +678,19 @@ describe("Order service", function() {
    -### :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 +### :clap: Приклад правильного виконання: Структурування набору з назвою блоку, що тестується, і сценаріями призведе до зручного звіту, який показано нижче -![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Приклади з Jest") ```javascript -// Unit under test +// Тестуєма одиниця describe("Transfer service", () => { - //Scenario + // Сценарій describe("When no credit", () => { - //Expectation + // Очікування test("Then the response status should decline", () => {}); - //Expectation + // Очікування test("Then it should send email to admin", () => {}); }); }); @@ -701,9 +700,9 @@ describe("Transfer service", () => {
    -### :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 +### :thumbsdown: Приклад антишаблону: Плоский список тестів ускладнить читачеві ідентифікацію історій користувачів і співвіднесення невдалих тестів -![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Mocha") +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Приклади з Mocha") ```javascript test("Then the response status should decline", () => {}); @@ -721,14 +720,14 @@ test("Then there should not be a new transfer record", () => {});

    -## ⚪ ️1.13 Other generic good testing hygiene +## ⚪ ️1.13 Інша загальна хороша гігієна тестування -:white_check_mark: **Роби:** This post is focused on testing advice that is related to, or at least can be exemplified with Node JS. This bullet, however, groups few non-Node related tips that are well-known +:white_check_mark: **Роби:** Ця публікація зосереджена на порадах щодо тестування, які пов’язані з Node JS або, принаймні, можуть бути представлені на прикладі Node JS. Однак у цьому розділі згруповано кілька добре відомих порад, не повʼязаних з Node -Learn and practice [TDD principles](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) — 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://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.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, 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) +Навчайтеся і практикуйтеся [TDD принципи](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) — вони надзвичайно цінні для багатьох, але не лякайтеся, якщо вони не відповідають вашому стилю, ви не єдині. Розгляньте можливість написання тестів перед кодом у [red-green-refactor style](https://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html), переконайтеся, що кожен тест перевіряє саме одну річ, якщо ви знайдете помилку — перед виправленням напишіть тест, який виявить цю помилку в майбутньому, дайте кожному тесту принаймні один раз помилитися, перш ніж стати зеленим, запустіть модуль, написавши швидкий і спрощений код, який задовольняє тест - потім поступово рефакторинг і переведіть його до рівня виробництва, уникайте будь-якої залежності від середовища (шляхи, ОС тощо)
    -❌ **Інакше:** You‘ll miss pearls of wisdom that were collected for decades +❌ **Інакше:** Ви пропустите перлини мудрості, які збиралися десятиліттями

    @@ -754,7 +753,7 @@ A word of caution: the TDD argument in the software world takes a typical false-
    -### :clap: Doing It Right Example: Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the same way’ +### :clap: Приклад правильного виконання: Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the same way’ ![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") @@ -786,9 +785,9 @@ Component tests focus on the Microservice ‘unit’, they work against the API,
    -### :clap: Doing It Right Example: Supertest allows approaching Express API in-process (fast and cover many layers) +### :clap: Приклад правильного виконання: Supertest allows approaching Express API in-process (fast and cover many layers) -![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Приклади з Mocha") ![alt text](assets/bp-13-component-test-yoni-goldberg.png " [Supertest](https://www.npmjs.com/package/supertest) allows approaching Express API in-process (fast and cover many layers)") @@ -809,7 +808,7 @@ Component tests focus on the Microservice ‘unit’, they work against the API,
    -### :clap: Doing It Right Example: +### :clap: Приклад правильного виконання: ![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") @@ -832,9 +831,9 @@ Component tests focus on the Microservice ‘unit’, they work against the API,
    -### :clap:Doing It Right Example: Testing middleware in isolation without issuing network calls and waking-up the entire Express machine +### :clap:Приклад правильного виконання: Testing middleware in isolation without issuing network calls and waking-up the entire Express machine -![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Приклади з Jest") ```javascript //the middleware we want to test @@ -875,7 +874,7 @@ Credit: { @@ -944,7 +943,7 @@ it("When querying by site name, get the right site", async () => {
    -### :clap: Doing It Right Example: We can stay within the test, each test acts on its own set of data +### :clap: Приклад правильного виконання: We can stay within the test, each test acts on its own set of data ```javascript it("When updating site name, get successful confirmation", async () => { @@ -1134,7 +1133,7 @@ beforeEach(() => {
    -### :clap: Doing It Right Example: Separating out the UI details +### :clap: Приклад правильного виконання: Separating out the UI details ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") @@ -1155,7 +1154,7 @@ test("When users-list is flagged to show only VIP, should display only VIP membe
    -### :thumbsdown: Anti-Pattern Example: Assertion mix UI details and data +### :thumbsdown: Приклад антишаблону: Assertion mix UI details and data ```javascript test("When flagging to show only VIP, should display only VIP members", () => { @@ -1188,7 +1187,7 @@ test("When flagging to show only VIP, should display only VIP members", () => {
    -### :clap: Doing It Right Example: Querying an element using a dedicated attribute for testing +### :clap: Приклад правильного виконання: Querying an element using a dedicated attribute for testing ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") @@ -1217,7 +1216,7 @@ test("Whenever no data is passed to metric, show 0 as default", () => {
    -### :thumbsdown: Anti-Pattern Example: Relying on CSS attributes +### :thumbsdown: Приклад антишаблону: Relying on CSS attributes ```html @@ -1254,7 +1253,7 @@ With all that said, a word of caution is in order: this technique works for smal
    -### :clap: Doing It Right Example: Working realistically with a fully rendered component +### :clap: Приклад правильного виконання: Working realistically with a fully rendered component ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Enzyme-blue.svg "Examples with Enzyme") @@ -1286,7 +1285,7 @@ test("Realistic approach: When clicked to show filters, filters are displayed", }); ``` -### :thumbsdown: Anti-Pattern Example: Mocking the reality with shallow rendering +### :thumbsdown: Приклад антишаблону: Mocking the reality with shallow rendering ```javascript test("Shallow/mocked approach: When clicked to show filters, filters are displayed", () => { @@ -1323,7 +1322,7 @@ test("Shallow/mocked approach: When clicked to show filters, filters are display
    -### :clap: Doing It Right Example: E2E API that resolves only when the async operations is done (Cypress) +### :clap: Приклад правильного виконання: E2E API that resolves only when the async operations is done (Cypress) ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") @@ -1335,7 +1334,7 @@ cy.wait("@products"); // wait for route to appear // this line will get executed only when the route is ready ``` -### :clap: Doing It Right Example: Testing library that waits for DOM elements +### :clap: Приклад правильного виконання: Testing library that waits for DOM elements ```javascript // @testing-library/dom @@ -1352,7 +1351,7 @@ test("movie title appears", async () => { }); ``` -### :thumbsdown: Anti-Pattern Example: custom sleep code +### :thumbsdown: Приклад антишаблону: custom sleep code ```javascript test("movie title appears", async () => { @@ -1390,7 +1389,7 @@ test("movie title appears", async () => {
    Приклади коду -### :clap: Doing It Right Example: Lighthouse page load inspection report +### :clap: Приклад правильного виконання: Lighthouse page load inspection report ![](/assets/lighthouse2.png "Lighthouse page load inspection report") @@ -1412,7 +1411,7 @@ test("movie title appears", async () => {
    -### :clap: Doing It Right Example: Stubbing or intercepting API calls +### :clap: Приклад правильного виконання: Stubbing or intercepting API calls ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") @@ -1476,7 +1475,7 @@ test("When no products exist, show the appropriate message", () => {
    -### :clap: Doing It Right Example: Logging-in before-all and not before-each +### :clap: Приклад правильного виконання: Logging-in before-all and not before-each ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") @@ -1524,7 +1523,7 @@ beforeEach(setUser => () {
    -### :clap: Doing It Right Example: Smoke travelling across all pages +### :clap: Приклад правильного виконання: Smoke travelling across all pages ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") @@ -1557,7 +1556,7 @@ it("When doing smoke testing over all page, should load them all successfully",
    -### :clap: Doing It Right Example: Describing tests in human-language using cucumber-js +### :clap: Приклад правильного виконання: Describing tests in human-language using cucumber-js ![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Examples using Cucumber") @@ -1578,7 +1577,7 @@ Feature: Twitter new tweet ``` -### :clap: Doing It Right Example: Visualizing our components, their various states and inputs using Storybook +### :clap: Приклад правильного виконання: Visualizing our components, their various states and inputs using Storybook ![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") @@ -1602,13 +1601,13 @@ Feature: Twitter new tweet
    -### :thumbsdown: Anti-Pattern Example: A typical visual regression - right content that is served badly +### :thumbsdown: Приклад антишаблону: A typical visual regression - right content that is served badly ![alt text](assets/amazon-visual-regression.jpeg "Amazon page breaks")
    -### :clap: Doing It Right Example: Configuring wraith to capture and compare UI snapshots +### :clap: Приклад правильного виконання: Configuring wraith to capture and compare UI snapshots ![](https://img.shields.io/badge/🔨%20Example%20using%20Wraith-blue.svg "Using Wraith") @@ -1637,7 +1636,7 @@ paths: path: /subscribe ``` -### :clap: Doing It Right Example: Using Applitools to get snapshot comparison and other advanced features +### :clap: Приклад правильного виконання: Using Applitools to get snapshot comparison and other advanced features ![](https://img.shields.io/badge/🔨%20Example%20using%20AppliTools-blue.svg "Using Applitools") ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") @@ -1690,7 +1689,7 @@ Implementation tips: You may want to configure your continuous integration (CI)
    -### :clap: Doing It Right Example: Setting up coverage per component (using Jest) +### :clap: Приклад правильного виконання: Setting up coverage per component (using Jest) ![](https://img.shields.io/badge/🔨%20Example%20using%20Jest-blue.svg "Using Jest") @@ -1713,7 +1712,7 @@ Implementation tips: You may want to configure your continuous integration (CI)
    -### :thumbsdown: Anti-Pattern Example: What’s wrong with this coverage report? +### :thumbsdown: Приклад антишаблону: What’s wrong with this coverage report? Based on a real-world scenario where we tracked our application usage in QA and find out interesting login patterns (Hint: the amount of login failures is non-proportional, something is clearly wrong. Finally it turned out that some frontend bug keeps hitting the backend login API) @@ -1744,7 +1743,7 @@ Knowing that all or most of the mutations were killed gives much higher confiden
    -### :thumbsdown: Anti-Pattern Example: 100% coverage, 0% testing +### :thumbsdown: Приклад антишаблону: 100% coverage, 0% testing ![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Using Stryker") @@ -1764,7 +1763,7 @@ it("Test addNewOrder, don't use such test names", () => {
    -### :clap: Doing It Right Example: Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations) +### :clap: Приклад правильного виконання: Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations) ![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations)") @@ -1785,7 +1784,7 @@ it("Test addNewOrder, don't use such test names", () => {
    -### :thumbsdown: Anti-Pattern Example: A test case full of errors, luckily all are caught by Linters +### :thumbsdown: Приклад антишаблону: A test case full of errors, luckily all are caught by Linters ```javascript describe("Too short description", () => { @@ -1822,7 +1821,7 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test
    -### :thumbsdown: Anti-Pattern Example: The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug +### :thumbsdown: Приклад антишаблону: The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug ![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug") @@ -1845,7 +1844,7 @@ Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com
    -### :clap: Doing It Right Example: npm scripts that perform code quality inspection, all are run in parallel on demand or when a developer is trying to push new code +### :clap: Приклад правильного виконання: npm scripts that perform code quality inspection, all are run in parallel on demand or when a developer is trying to push new code ```javascript "scripts": { @@ -1905,7 +1904,7 @@ The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for
    -### :clap: Doing It Right Example: Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) +### :clap: Приклад правильного виконання: Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) ![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization (Credit: JavaScript Test-Runners Benchmark)") @@ -1925,7 +1924,7 @@ The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for
    -### :clap: Doing It Right Example: +### :clap: Приклад правильного виконання: ```javascript //install license-checker in your CI environment or also locally From fb28fdb58f1653ee74fc1923c968aa7c5a02817d Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Mon, 22 Aug 2022 19:18:10 +0300 Subject: [PATCH 143/189] Update readme.md --- readme.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index f5123694..57a818c0 100644 --- a/readme.md +++ b/readme.md @@ -1,13 +1,8 @@ -## 🎊 April 2022 Announcement: A new edition was just released with 5 new best practices, many more code examples and 4 new language translations - -## 👨‍🏫 Next workshop: Verona, Italy 🇮🇹, April 20th. [Tickets and more info here](https://2022.jsday.it/workshop/nodejs_testing.html)
    - - # 👇 Why this guide can take your testing skills to the next level
    @@ -26,6 +21,8 @@ Start by understanding the ubiquitous testing practices that are the foundation
    +## 🚀 We have an [official Node.js starter - Practica.js](https://github.com/practicajs/practica). Use it to generate a new solution skeleton with testing baked in, Or just it to learn by testing code examples + ### Written By Yoni Goldberg - A JavaScript & Node.js consultant From 09795e10d894cf59b820addc84796f7a5a056f12 Mon Sep 17 00:00:00 2001 From: Serhii Shramko Date: Sat, 3 Sep 2022 14:31:58 +0200 Subject: [PATCH 144/189] feat: implement 2 chapter --- readme-ua.md | 166 +++++++++++++++++++++++++-------------------------- 1 file changed, 83 insertions(+), 83 deletions(-) diff --git a/readme-ua.md b/readme-ua.md index 56f5fd4b..05ec2ac6 100644 --- a/readme-ua.md +++ b/readme-ua.md @@ -720,7 +720,7 @@ test("Then there should not be a new transfer record", () => {});

    -## ⚪ ️1.13 Інша загальна хороша гігієна тестування +## ⚪ ️1.13 Інша загальна гігієна тестування :white_check_mark: **Роби:** Ця публікація зосереджена на порадах щодо тестування, які пов’язані з Node JS або, принаймні, можуть бути представлені на прикладі Node JS. Однак у цьому розділі згруповано кілька добре відомих порад, не повʼязаних з Node @@ -731,21 +731,20 @@ test("Then there should not be a new transfer record", () => {});

    -# Section 2️⃣: Backend Testing +# Section 2️⃣: Backend тестування -## ⚪ ️2.1 Enrich your testing portfolio: Look beyond unit tests and the pyramid +## ⚪ ️2.1 Збагачуйте своє портфоліо тестування: подивіться за межі модульних тестів і піраміди -:white_check_mark: **Роби:** The [testing pyramid](https://martinfowler.com/bliki/TestPyramid.html), though 10> years old, is a great and relevant model that suggests three testing types and influences most developers’ testing strategy. 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? +:white_check_mark: **Роби:** [Піраміда тестування](https://martinfowler.com/bliki/TestPyramid.html), Хоча їй понад 10 років, це чудова та релевантна модель, яка пропонує три типи тестування та впливає на стратегію тестування більшості розробників. Водночас з’явилося більше кількох блискучих нових методів тестування, які ховаються в тіні піраміди тестування. Враховуючи всі драматичні зміни, які ми спостерігаємо за останні 10 років (мікросервіси, хмарні сервіси, безсерверний доступ), чи можливо, що одна досить стара модель підійде для *всіх* типів програм? Чи не варто світу тестування розглянути можливість вітати нові методи тестування? -Don’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://en.wikipedia.org/wiki/All_models_are_wrong). For example, consider an IoT application that ingests many events into a message-bus like Kafka/RabbitMQ, 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 increase (bots, crypto, Alexa-skills) greater are the chances to find scenarios where the testing pyramid is not the best match. +Не зрозумійте мене неправильно, у 2019 році піраміда тестування, TDD і модульні тести все ще залишаються потужною технікою та, мабуть, найкраще підходять для багатьох програм. Тільки, як і будь-яка інша модель, попри її корисність, [інколи вона може помилятися](https://en.wikipedia.org/wiki/All_models_are_wrong). Наприклад, розглянемо IoT-додаток, який приймає багато подій у шину повідомлень, як-от Kafka/RabbitMQ, які потім надходять у якесь сховище даних і в кінцевому підсумку запитуються деяким інтерфейсом користувача аналітики. Чи справді ми повинні витрачати 50% нашого бюджету на тестування на написання модульних тестів для програми, яка орієнтована на інтеграцію та майже не містить логіки? Зі збільшенням різноманітності типів додатків (ботів, крипто, навичок Alexa) зростає ймовірність знайти сценарії, де піраміда тестування не найкраще підходить. -It’s time to enrich your testing portfolio and become familiar with more testing types (the next bullets suggest 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 build a portfolio based on risk analysis — assess where problems might arise and match some prevention measures to mitigate those potential risks - -A word of caution: the TDD argument in the software world takes a typical false-dichotomy face, some preach to use it everywhere, others think it’s the devil. Everyone who speaks in absolutes is wrong :] +Настав час збагатити ваше портфоліо тестування та ознайомитися з більшою кількістю типів тестування (наступні пункти пропонують кілька ідей), моделями розуму, як-от піраміда тестування, а також зіставити типи тестування з реальними проблемами, з якими ви стикаєтесь («Гей, наш API зламано, напишімо тестування контрактів, орієнтоване на споживача!'), диверсифікуйте свої тести, як інвестор, який створює портфель на основі аналізу ризиків — оцініть, де можуть виникнути проблеми, і підберіть деякі запобіжні заходи для помʼякшення цих потенційних ризиків +Застереження: аргумент TDD у світі програмного забезпечення приймає типове обличчя хибної дихотомії, деякі проповідують використовувати його всюди, інші вважають, що це диявол. Кожен, хто говорить в абсолюті, помиляється :]
    -❌ **Інакше:** You’re going to miss some tools with amazing ROI, some like Fuzz, lint, and mutation can provide value in 10 minutes +❌ **Інакше:** Ви пропустите деякі інструменти з неймовірною рентабельністю інвестицій, деякі, як-от Fuzz, lint і mutation, можуть надати цінність за 10 хвилин
    @@ -753,31 +752,31 @@ A word of caution: the TDD argument in the software world takes a typical false-
    -### :clap: Приклад правильного виконання: Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the same way’ +### :clap: Приклад правильного виконання: Cindy Sridharan пропонує багате портфоліо тестування у своїй дивовижній публікації «Тестування мікросервісів — таким же чином» -![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") +![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan пропонує багате портфоліо тестування у своїй дивовижній публікації «Тестування мікросервісів — таким же чином»") -☺️Example:
    [YouTube: “Beyond Unit Tests: 5 Shiny Node.JS Test Types (2018)” (Yoni Goldberg)](https://www.youtube.com/watch?v=-2zP494wdUY&feature=youtu.be) +☺️Приклад: [YouTube: “За межами модульних тестів: 5 блискучих типів тестів Node.JS (2018)” (Yoni Goldberg)](https://www.youtube.com/watch?v=-2zP494wdUY&feature=youtu.be)
    -![alt text](assets/bp-12-Yoni-Goldberg-Testing.jpeg "A test name that constitutes 3 parts") +![alt text](assets/bp-12-Yoni-Goldberg-Testing.jpeg "Назва тесту, яка складається з 3 частин")


    -## ⚪ ️2.2 Component testing might be your best affair +## ⚪ ️2.2 Тестування компонентів може бути вашим найкращим заходом -:white_check_mark: **Роби:** 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 from both worlds: reasonable performance and a possibility to apply TDD patterns + realistic and great coverage. +:white_check_mark: **Роби:** Кожен модульний тест охоплює невелику частину програми, і це дорого, щоб охопити цілу, тоді як наскрізне(end-to-end) тестування легко охоплює велику частину, але є нестабільним і повільним, чому б не застосувати збалансований підхід і написати тести, більші за модульні тести, але менші, ніж наскрізне тестування? Тестування компонентів – це неоспівана пісня світу тестування — вони забезпечують найкраще з обох світів: прийнятну продуктивність і можливість застосовувати шаблони TDD + реалістичне та велике покриття. -Component tests focus on the Microservice ‘unit’, they work against the API, 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 outwards to inwards and gain great confidence in a reasonable amount of time. +Тести компонентів зосереджуються на «блоку» мікросервісу, вони працюють проти API, не мокають(mock) нічого, що належить самому мікросервісу (наприклад, справжню БД або принаймні версію цієї БД у пам’яті), але заглушують усе, що є зовнішнім як виклики до інших мікросервісів. Роблячи це, ми перевіряємо те, що розгортаємо, підходимо до програми ззовні всередину та отримуємо велику впевненість за прийнятний проміжок часу. -[We have a full guide that is solely dedicated to writing component tests in the right way](https://github.com/testjavascript/nodejs-integration-tests-best-practices) +[У нас є повний посібник, присвячений виключно правильному написанню компонентних тестів](https://github.com/testjavascript/nodejs-integration-tests-best-practices)
    -❌ **Інакше:** You may spend long days on writing unit tests to find out that you got only 20% system coverage +❌ **Інакше:** Ви можете витратити довгі дні на написання модульних тестів, щоб дізнатися, що ви отримали лише 20% покриття системи
    @@ -785,22 +784,22 @@ Component tests focus on the Microservice ‘unit’, they work against the API,
    -### :clap: Приклад правильного виконання: Supertest allows approaching Express API in-process (fast and cover many layers) +### :clap: Приклад правильного виконання: Supertest дозволяє підходити до Express API в процесі (швидко та охоплює багато рівнів) ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Приклади з Mocha") -![alt text](assets/bp-13-component-test-yoni-goldberg.png " [Supertest](https://www.npmjs.com/package/supertest) allows approaching Express API in-process (fast and cover many layers)") +![alt text](assets/bp-13-component-test-yoni-goldberg.png " [Supertest](https://www.npmjs.com/package/supertest) дозволяє підходити до Express API в процесі (швидко та охоплює багато рівнів)")


    -## ⚪ ️2.3 Ensure new releases don’t break the API using contract tests +## ⚪ ️2.3 Переконайтеся, що нові релізи не порушують API, використовуючи тести контракту -:white_check_mark: **Роби:** 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 are 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 it to use [PACT](https://docs.pact.io/) which were born to formalize this process with a very disruptive approach — not the server defines the test plan of itself rather the client defines the tests of the… server! PACT can record the client expectation and put in a shared location, “broker”, so the server can pull the expectations and run on every build using 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/CI and might save you a great deal of frustration +:white_check_mark: **Роби:** Отже, ваш мікросервіс має кілька клієнтів, і ви запускаєте кілька версій сервісу з міркувань сумісності (щоб усі були задоволені). Потім ви змінюєте якесь поле і «бум!», якийсь важливий клієнт, який покладається на це поле, сердиться. Це 22-й підступ світу інтеграції: серверній стороні дуже складно врахувати всі численні очікування клієнтів — З іншого боку, клієнти не можуть проводити жодного тестування, оскільки сервер контролює дати випуску. Існує цілий спектр методів, які можуть помʼякшити проблему контракту, деякі з них прості, інші є багатшими на функції та вимагають крутішої кривої навчання. У простому та рекомендованому підході постачальник API публікує пакет npm із типом API (наприклад, JSDoc, TypeScript). Тоді споживачі зможуть отримати цю бібліотеку та отримати вигоду від аналізу часу кодування та перевірки. Вигадливіший підхід — використання [PACT](https://docs.pact.io/), створеного для формалізації цього процесу за допомогою дуже руйнівного підходу —«не сервер сам визначає план тестування, а клієнт визначає тести. PACT може записувати очікування клієнта та розміщувати в спільному місці, «посереднику», щоб сервер міг отримати очікування та запускати кожну збірку за допомогою бібліотеки PACT для виявлення порушених контрактів — очікування клієнта, яке не відповідають. Завдяки цьому всі невідповідності API сервера та клієнта виявляються на ранній стадії збирання/CI, що може позбавити вас від розчарування
    -❌ **Інакше:** The alternatives are exhausting manual testing or deployment fear +❌ **Інакше:** Альтернативами є виснажливе ручне тестування або страх розгортання
    @@ -810,7 +809,7 @@ Component tests focus on the Microservice ‘unit’, they work against the API, ### :clap: Приклад правильного виконання: -![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") +![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Приклад з PACT") ![alt text](assets/bp-14-testing-best-practices-contract-flow.png) @@ -818,12 +817,12 @@ Component tests focus on the Microservice ‘unit’, they work against the API,

    -## ⚪ ️ 2.4 Test your middlewares in isolation +## ⚪ ️ 2.4 Тестуйте мідлвари(middlewares) окремо -:white_check_mark: **Роби:** 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://www.npmjs.com/package/sinon)) on the interaction with the {req,res} objects to ensure the function performed the right action. The library [node-mock-http](https://www.npmjs.com/package/node-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) +:white_check_mark: **Роби:** Багато хто уникає мідлвари, оскільки воно представляє невелику частину системи та потребує активного сервера Express. Обидві причини неправильні — Проміжні програми невеликі, але впливають на всі або більшість запитів і можуть бути легко перевірені як чисті функції, які отримують {req,res} обʼєкти JS. Щоб перевірити функцію мідлвари, потрібно просто викликати її та перевірити ([використовуючи, наприклад, Sinon](https://www.npmjs.com/package/sinon)) взаємодію з об’єктами {req,res}, щоб переконатися, що функція виконала правильну дію. Бібліотека [node-mock-http](https://www.npmjs.com/package/node-mocks-http) йде ще далі й враховує об’єкти {req,res} разом зі спостереженням за їхньою поведінкою. Наприклад, він може стверджувати, чи статус http, встановлений для об’єкта res, відповідає очікуванням (див. приклад нижче)
    -❌ **Інакше:** A bug in Express middleware === a bug in all or most requests +❌ **Інакше:** Помилка в мідлварі Express === помилка в усіх або більшості запитів
    @@ -831,7 +830,7 @@ Component tests focus on the Microservice ‘unit’, they work against the API,
    -### :clap:Приклад правильного виконання: Testing middleware in isolation without issuing network calls and waking-up the entire Express machine +### :clap:Приклад правильного виконання: Тестування мідлвари в ізоляції без здійснення мережевих викликів і пробудження всієї машини Express ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Приклади з Jest") @@ -839,7 +838,7 @@ Component tests focus on the Microservice ‘unit’, they work against the API, //the middleware we want to test const unitUnderTest = require("./middleware"); const httpMocks = require("node-mocks-http"); -//Jest syntax, equivelant to describe() & it() in Mocha +// Синтаксис Jest, еквівалентний describe() і it() у Mocha test("A request without authentication header, should return http status 403", () => { const request = httpMocks.createRequest({ method: "GET", @@ -858,15 +857,15 @@ test("A request without authentication header, should return http status 403", (

    -## ⚪ ️2.5 Measure and refactor using static analysis tools +## ⚪ ️2.5 Вимірювання та ре факторинг за допомогою інструментів статичного аналізу -:white_check_mark: **Роби:** 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://www.sonarqube.org/) (4,900+ [stars](https://github.com/SonarSource/sonarqube)) and [Code Climate](https://codeclimate.com/) (2,000+ [stars](https://github.com/codeclimate/codeclimate)) +:white_check_mark: **Роби:** Використання інструментів статичного аналізу допомагає, надаючи об’єктивні способи покращити якість коду та зберегти ваш код придатним для обслуговування. Ви можете додати інструменти статичного аналізу до збірки CI, щоб перервати її, коли вона виявить запах коду. Його головні переваги над звичайним лінтуванням — це можливість перевіряти якість у контексті кількох файлів (наприклад, виявляти дублікати), виконувати розширений аналіз (наприклад, складності коду) і стежити за історією та прогресом проблем із кодом. Два приклади інструментів, які ви можете використовувати, це [SonarQube](https://www.sonarqube.org/) (4900+ [зірочок](https://github.com/SonarSource/sonarqube)) і [Code Climate](https ://codeclimate.com/) (2000+ [зірочок](https://github.com/codeclimate/codeclimate)) Credit: [Keith Holliday](https://github.com/TheHollidayInn)
    -❌ **Інакше:** 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 +❌ **Інакше:** З низькою якістю коду помилки та продуктивність завжди будуть проблемою, яку не зможе вирішити жодна блискуча нова бібліотека чи сучасні функції
    @@ -874,22 +873,22 @@ Credit:

    -## ⚪ ️ 2.6 Check your readiness for Node-related chaos +## ⚪ ️ 2.6 Перевірте свою готовність до хаосу, пов’язаного з Node -:white_check_mark: **Роби:** 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/process 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://principlesofchaos.org/) 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://github.com/Netflix/chaosmonkey), 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://github.com/asobti/kube-monkey), that kills pods). All these tools work on the hosting/platform 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://github.com/i0natan/node-chaos-monkey) (alpha) which provides all sort of Node-related chaotic acts +:white_check_mark: **Роби:** Дивно, але більшість тестувань програмного забезпечення стосуються лише логіки та даних, але деякі з найгірших речей, які трапляються (і їх справді важко мігрувати), — це проблеми з інфраструктурою. Наприклад, ви коли-небудь перевіряли, що відбувається, коли пам’ять вашого процесу перевантажується, або коли сервер/процес вмирає, чи ваша система моніторингу розуміє, коли API стає на 50% повільнішим?. Щоб перевірити та пофіксити такі погані речі — [Інженерія хаосу](https://principlesofchaos.org/ua/) створена Netflix. Він має на меті забезпечити обізнаність, структуру та інструменти для перевірки стійкості нашої програми до хаотичних проблем. Наприклад, один із його відомих інструментів, [мавпа хаосу](https://github.com/Netflix/chaosmonkey), випадково вимикає сервери, щоб гарантувати, що наш сервіс усе ще може обслуговувати користувачів і не покладатися на один сервер (є також версія Kubernetes, [kube-monkey](https://github.com/asobti/kube-monkey), яка вбиває модулі). Усі ці інструменти працюють на рівні хостингу/платформи, але що, якщо ви хочете перевірити та створити чистий хаос Node, наприклад перевірити, як ваш процес Node справляється з неперехопленими помилками, необробленим відхиленням обіцянок, перевантаженням пам’яті v8 із максимально допустимим 1,7 ГБ чи чи ваш UX залишається задовільним, коли цикл подій часто блокується? щоб вирішити цю проблему, я написав [node-chaos](https://github.com/i0natan/node-chaos-monkey) (альфа), який надає всілякі хаотичні дії, пов’язані з Node
    -❌ **Інакше:** No escape here, Murphy’s law will hit your production without mercy +❌ **Інакше:** Тут немає виходу, закон Мерфі вдарить по вашому виробництву без жалю
    @@ -897,20 +896,20 @@ Credit:

    -## ⚪ ️2.7 Avoid global test fixtures and seeds, add data per-test +## ⚪ ️2.7 Уникайте глобальних фікстур сідів, додавайте данні для кожного тесту -:white_check_mark: **Роби:** 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) +:white_check_mark: **Роби:** Дотримуючись золотого правила (Розділ 0), кожен тест повинен додавати власний набір рядків БД і діяти на них, щоб запобігти зчепленню та легко обґрунтувати потік тесту. Насправді це часто порушується тестувальниками, які заповнюють БД даними перед запуском тестів (також відомих як «test fixture») заради підвищення продуктивності. Хоча продуктивність справді є обґрунтованою проблемою —«її можна пофіксити (див. пункт «Тестування компонентів»), однак складність тесту є дуже болісним сумом, який у більшості випадків повинен керувати іншими міркуваннями. На практиці зробіть так, щоб кожен тестовий приклад явно додавав необхідні записи БД і діяв лише з цими записами. Якщо продуктивність стає критичною проблемою — збалансований компроміс може прийти у формі заповнення єдиного набору тестів, які не змінюють дані (наприклад, запити)
    -❌ **Інакше:** 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 +❌ **Інакше:** Кілька тестів зазнають невдач, розгортання перервано, наша команда витрачатиме дорогоцінний час зараз, у нас є помилка? дослідім, о ні — схоже, що два тести мутували однакові вихідні дані
    @@ -918,36 +917,36 @@ Credit:
    { - //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework + //додавання даних про сайти та адмінів до нашої БД. Де дані? назовні. У якомусь зовнішньому фреймворку json або міграції await DB.AddSeedDataFromJson('seed.json'); }); it("When updating site name, get successful confirmation", async () => { - //I know that site name "portal" exists - I saw it in the seed files + //Я знаю, що сайт з назвою "портал" існує - я бачив це в початкових файлах const siteToUpdate = await SiteService.getSiteByName("Portal"); const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); expect(updateNameResult).to.be(true); }); it("When querying by site name, get the right site", async () => { - //I know that site name "portal" exists - I saw it in the seed files + //Я знаю, що сайт з назвою "портал" існує - я бачив це в початкових файлах const siteToCheck = await SiteService.getSiteByName("Portal"); - expect(siteToCheck.name).to.be.equal("Portal"); //Failure! The previous test change the name :[ + expect(siteToCheck.name).to.be.equal("Portal"); //Невдача! Попередній тест змінив назву :[ }); ```
    -### :clap: Приклад правильного виконання: We can stay within the test, each test acts on its own set of data +### :clap: Приклад правильного виконання: Ми можемо залишатися в межах тесту, кожен тест діє на власний набір даних ```javascript it("When updating site name, get successful confirmation", async () => { - //test is adding a fresh new records and acting on the records only + //тест додає свіжі нові записи та діє лише на основі записів const siteUnderTest = await SiteService.addSite({ name: "siteForUpdateTest" }); @@ -960,14 +959,14 @@ it("When updating site name, get successful confirmation", async () => {
    -## ⚪ ️2.8 Choose a clear data clean-up strategy: After-all (recommended) or after-each +## ⚪ ️2.8 Виберіть чітку стратегію очищення даних: після всього (рекомендовано) або після кожного -:white_check_mark: **Роби:** 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. +:white_check_mark: **Роби:** Час, коли тести очищають базу даних, визначає спосіб написання тестів. Два найбільш життєздатних варіанти: очищення після всіх тестів і очищення після кожного тесту. Вибираючи останній варіант, очищення після кожного окремого тесту гарантує чисті таблиці та створює зручні переваги тестування для розробника. На момент початку тесту не існує інших записів, можна бути впевненим, які дані запитуються, і навіть може виникнути спокуса підрахувати рядки під час тверджень. Це має серйозні недоліки: під час роботи в багатопроцесному режимі тести можуть заважати один одному. Поки процес-1 очищає таблиці, у той самий момент процес-2 запитує дані та зазнає помилки (оскільки БД раптово видалено процесом-1). Крім того, важче усунути невдалі тести – відвідування БД не покаже жодних записів. -The 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://github.com/testjavascript/nodejs-integration-tests-best-practices/blob/master/graphics/db-clean-options.png). +Другий варіант — очищення після завершення всіх тестових файлів (або навіть щодня!). Такий підхід означає, що та сама БД з наявними записами обслуговує всі тести та процеси. Щоб не наступати один одному на ноги, тести повинні додавати та діяти на основі конкретних записів, які вони додали. Потрібно перевірити, чи додано якийсь запис? Припустімо, що є інші тисячі записів і запит на записи, які були додані явно. Потрібно перевірити, чи видалено запис? Неможливо припустити, що таблиця порожня, перевірте, чи немає цього конкретного запису. Ця техніка дає кілька значних переваг: вона працює нативно в багатопроцесному режимі, коли розробник хоче зрозуміти, що сталося – дані є, а не видаляються. Це також збільшує ймовірність виявлення помилок, оскільки БД заповнена записами, а не штучно порожня. [Перегляньте повну порівняльну таблицю тут](https://github.com/testjavascript/nodejs-integration-tests-best-practices/blob/master/graphics/db-clean-options.png).
    -❌ **Інакше:** 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 +❌ **Інакше:** Без стратегії розділення записів або очищення - Тести будуть наступати один на одного; Використання транзакцій працюватиме лише для реляційної БД і, ймовірно, ускладниться, коли з’являться внутрішні транзакції
    @@ -975,11 +974,11 @@ The second option is to clean up after all the test files have finished (or even
    -### :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 +### :clap: Прибирання після ВСІХ перевірок. Не обов'язково після кожного запуску. Чим більше даних ми маємо під час виконання тестів, тим більше це нагадує переваги виробництва ```javascript - // After-all clean up (recommended) -// global-teardown.js + // Після всього прибрати (рекомендовано) + // global-teardown.js module.exports = async () => { // ... if (Math.ceil(Math.random() * 10) === 10) { @@ -992,12 +991,12 @@ module.exports = async () => {
    -## ⚪ ️2.9 Isolate the component from the world using HTTP interceptor +## ⚪ ️2.9 Ізолюйте компонент від світу за допомогою перехоплювача HTTP -:white_check_mark: **Роби:** 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 +:white_check_mark: **Роби:** Ізолюйте тестований компонент, перехоплюючи будь-який вихідний HTTP-запит і надаючи потрібну відповідь, щоб HTTP API співавтора не постраждав. Nock є чудовим інструментом для цієї місії, оскільки він забезпечує зручний синтаксис для визначення поведінки зовнішніх служб. Ізоляція є обов’язковою для запобігання шуму та повільної продуктивності, але здебільшого для імітації різних сценаріїв і реакцій. Хороший симулятор польоту — це не малювання чистого блакитного неба, а створення безпечних штормів і хаосу. Це посилюється в архітектурі мікросервісу, де фокус завжди має бути зосереджений на одному компоненті без залучення решти світу. Хоча можна імітувати поведінку зовнішнього сервісу за допомогою повторюваних тестів (mocking), бажано не торкатися розгорнутого коду та діяти на рівні мережі, щоб тести залишалися чисто чорною скринькою. Негативною стороною ізоляції є відсутність виявлення змін компонента співавтора та непорозуміння між двома службами. Обов’язково компенсуйте це за допомогою кількох контрактів або тестів E2E
    -❌ **Інакше:** 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 +❌ **Інакше:** Деякі служби надають фальшиву версію, яку абонент може розгорнути локально, зазвичай за допомогою Docker. Це полегшить налаштування та підвищить продуктивність, але не допоможе з симуляцією різних відповідей; Деякі служби надають середовище «пісочниці», тому справжня служба зазнає удару, але не спричиняє жодних витрат або побічних ефектів. Це зменшить шум під час налаштування сторонньої служби, але також не дозволить імітувати сценарії
    @@ -1005,27 +1004,28 @@ module.exports = async () => {
    -### :clap: Preventing network calls to externous components allows simulating scnearios and minimizing the noise +### :clap: Запобігання мережевим викликам зовнішніх компонентів дозволяє імітувати сценарії та мінімізувати шум ```javascript -// Intercept requests for 3rd party APIs and return a predefined response +// Перехоплювати запити для сторонніх API і повертати попередньо визначену відповідь beforeEach(() => { nock('http://localhost/user/').get(`/1`).reply(200, { id: 1, name: 'John', }); -});``` +}); +```
    -## ⚪ ️2.10 Test the response schema, mostly when there are auto-generated fields +## ⚪ ️2.10 Перевірте схему відповіді, коли є автоматично згенеровані поля -:white_check_mark: **Роби:** 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. +:white_check_mark: **Роби:** Якщо неможливо підтвердити певні дані, перевірте наявність і типи обов’язкових полів. Іноді відповідь містить важливі поля з динамічними даними, які неможливо передбачити під час написання тесту, як-от дати та числа, що збільшуються. Якщо договір API обіцяє, що ці поля не будуть нульовими і містять правильні типи, обов’язково перевірте це. Більшість бібліотек тверджень підтримують типи перевірки. Якщо відповідь невелика, перевірте дані, що повертаються, і введіть разом в одному твердженні (див. приклад коду). Ще один варіант — перевірити всю відповідь за документом OpenAPI (Swagger). Більшість тестувальників мають розширення спільноти, які перевіряють відповіді API на їхню документацію.
    -❌ **Інакше:** Although the code/API caller relies on some field with dynamic data (e.g., ID, date), it will not come in return and break the contract +❌ **Інакше:** Хоча програма виклику коду/API покладається на деякі поля з динамічними даними (наприклад, ідентифікатор, дата), вона не прийде у відповідь і не порушить контракт
    @@ -1033,16 +1033,16 @@ beforeEach(() => {
    -### :clap: Asserting that fields with dynamic value exist and have the right type +### :clap: Стверджуючи, що поля з динамічним значенням існують і мають правильний тип ```javascript test('When adding a new valid order, Then should get back approval with 200 response', async () => { // ... - //Assert + // Стверджування expect(receivedAPIResponse).toMatchObject({ status: 200, data: { - id: expect.any(Number), // Any number satisfies this test + id: expect.any(Number), // Будь-яке число задовольняє цей тест mode: 'approved', }, }); @@ -1053,14 +1053,14 @@ beforeEach(() => {
    -## ⚪ ️2.12 Check integrations corner cases and chaos +## ⚪ ️2.12 Перевірте крайні випадки інтеграції та хаос -:white_check_mark: **Роби:** When checking integrations, go beyond the happy and sad paths. Check not only errored 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 +:white_check_mark: **Роби:** Перевіряючи інтеграції, виходьте за рамки щасливих і сумних шляхів. Перевіряйте не лише відповіді з помилками (наприклад, помилка HTTP 500), а й аномалії на рівні мережі, як-от повільні відповіді та відповіді, що закінчилися. Це доведе, що код стійкий і може обробляти різні мережеві сценарії, як-от вибір правильного шляху після тайм-ауту, відсутність крихких умов змагання та містить автоматичний вимикач для повторних спроб. Інструменти перехоплення з авторитетним досвідом можуть легко імітувати різні поведінки мережі, як-от неспокійне обслуговування, яке час від часу дає збій. Він навіть може зрозуміти, коли значення тайм-ауту HTTP-клієнта за замовчуванням перевищує змодельований час відповіді, і відразу, не чекаючи, викликати виняток часу очікування
    -❌ **Інакше:** All your tests pass, it's only the production who will crash or won't report errors correctly when 3rd parties send excpetional responses +❌ **Інакше:** Усі ваші тести проходять успішно, тільки виробництво буде аварійно або неправильно повідомляти про помилки, коли треті сторони надсилатимуть виняткові відповіді
    @@ -1068,11 +1068,11 @@ beforeEach(() => {
    -### :clap: Ensuring that on network failures, the circuit breaker can save the day +### :clap: Забезпечення того, що в разі збоїв у мережі автоматичний вимикач може врятувати ситуацію ```javascript test('When users service replies with 503 once and retry mechanism is applied, then an order is added successfully', async () => { - //Arrange + // Упорядкування nock.removeInterceptor(userServiceNock.interceptors[0]) nock('http://localhost/user/') .get('/1') @@ -1086,10 +1086,10 @@ beforeEach(() => { mode: 'approved', }; - //Act + // Дія const response = await axiosAPIClient.post('/order', orderToAdd); - //Assert + // Стверджування expect(response.status).toBe(200); }); ``` @@ -1099,19 +1099,19 @@ beforeEach(() => {
    -## ⚪ ️2.13 Test the five potential outcomes +## ⚪ ️2.13 Перевірте п’ять потенційних результатів -:white_check_mark: **Роби:** 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/reactions can be put in 5 categories: +:white_check_mark: **Роби:** Плануючи свої тести, подумайте про охоплення п’яти типових виходів потоку. Коли ваш тест запускає певну дію (наприклад, виклик API), відбувається реакція, відбувається щось значуще та вимагає тестування. Зауважте, що нам байдуже, як все працює. Ми зосереджені на результатах, речах, які помітні ззовні та можуть вплинути на користувача. Ці результати/реакції можна розділити на 5 категорій: -• 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 +• Відповідь - Тест викликає дію (наприклад, через API) і отримує відповідь. Тепер він займається перевіркою правильності даних відповіді, схеми та статусу HTTP -• A new state - After invoking an action, some **publicly accessible** data is probably modified +• Новий стан - Після виклику дії деякі **загальнодоступні** дані, ймовірно, змінюються -• 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 +• Зовнішні виклики - Після виклику дії програма може викликати зовнішній компонент через HTTP або будь-який інший транспорт. Наприклад, дзвінок для відправки SMS, електронної пошти або стягнення коштів з кредитної картки -• Message queues - The outcome of a flow might be a message in a queue +• Message queues - Результатом потоку може бути повідомлення в черзі -• 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/metrics. This information goes directly to a very important user - The ops user (i.e., production SRE/admin) +• Спостережливість - Деякі речі необхідно відстежувати, як-от помилки чи значні ділові події. Коли транзакція зазнає невдачі, ми очікуємо не лише правильної відповіді, але й правильної обробки помилок і належного журналювання/метрик. Ця інформація надходить безпосередньо до дуже важливого користувача – користувача ops (SRE/адміністратора)
    From 0044847cca0bdb00ba204ad4d49b3362a6e17b99 Mon Sep 17 00:00:00 2001 From: Serhii Shramko Date: Sat, 3 Sep 2022 14:38:56 +0200 Subject: [PATCH 145/189] docs: add ukrainian links --- readme-es.md | 1 + readme-fr.md | 3 ++- readme-pl.md | 1 + readme-pt-br.md | 1 + readme-ua.md | 18 +++++++++--------- readme-zh-TW.md | 3 ++- readme.md | 1 + 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/readme-es.md b/readme-es.md index 3325f51b..920b71d9 100644 --- a/readme-es.md +++ b/readme-es.md @@ -35,6 +35,7 @@ Empieza por comprender las técnicas de testing ubicuas que son la base de cualq - 🇵🇱[Polaco](readme-pl.md) - cortesía de [Michal Biesiada](https://github.com/mbiesiad) - 🇪🇸[Español](readme-es.md) - cortesía de [Miguel G. Sanguino](https://github.com/sanguino) - 🇧🇷[Portugués-BR](readme-pt-br.md) - cortesía de [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante), [Douglas Mariano Valero](https://github.com/DouglasMV) y [koooge](https://github.com/koooge) +- 🇺🇦[Ukrainian](readme-ua.md) - cortesía de [Serhii Shramko](https://github.com/Shramkoweb) - ¿Quieres traducir a tu propio lenguaje? por favor abre una issue 💜

    diff --git a/readme-fr.md b/readme-fr.md index fb8011e8..e03b122f 100644 --- a/readme-fr.md +++ b/readme-fr.md @@ -35,6 +35,7 @@ Commence par comprendre les pratiques de tests omniprésentes qui sont à la bas - 🇵🇱[Polonais](readme-pl.md) - Traduit par [Michal Biesiada](https://github.com/mbiesiad) - 🇪🇸[Espagnol](readme-es.md) - Traduit par [Miguel G. Sanguino](https://github.com/sanguino) - 🇧🇷[Portugais brésilien](readme-pt-br.md) - Traduit par [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) et [koooge](https://github.com/koooge) +- 🇺🇦[Ukrainian](readme-ua.md) - Traduit par [Serhii Shramko](https://github.com/Shramkoweb) - Envie de traduire dans ta propre langue ? Ouvres une issue 💜

    @@ -1963,4 +1964,4 @@ Merci à ces merveilleuses personnes qui ont contribué à ce repo! - \ No newline at end of file + diff --git a/readme-pl.md b/readme-pl.md index 499f5e9d..019ec2c4 100644 --- a/readme-pl.md +++ b/readme-pl.md @@ -33,6 +33,7 @@ Zacznij od zrozumienia wszechobecnych praktyk testowania, które są podstawą k - 🇨🇳[Chinese](readme-zh-CN.md) - dzięki uprzejmości [Yves yao](https://github.com/yvesyao) - 🇰🇷[Korean](readme.kr.md) - dzięki uprzejmości [Rain Byun](https://github.com/ragubyun) - 🇵🇱[Polish](readme.pl.md) - dzięki uprzejmości [Michal Biesiada](https://github.com/mbiesiad) +- 🇺🇦[Ukrainian](readme-ua.md) - dzięki uprzejmości [Serhii Shramko](https://github.com/Shramkoweb) - Chcesz przetłumaczyć na swój język? Proszę skorzystaj z issue 💜

    diff --git a/readme-pt-br.md b/readme-pt-br.md index e127ab7d..225e7410 100644 --- a/readme-pt-br.md +++ b/readme-pt-br.md @@ -31,6 +31,7 @@ Comece entendendo as práticas de teste onipresentes que são a base para qualqu ### Traduções - leia em seu próprio idioma * 🇨🇳[Chinese](readme-zh-CN.md) - cortesia de [Yves yao](https://github.com/yvesyao) * 🇰🇷[Korean](readme.kr.md) - cortesia de [Rain Byun](https://github.com/ragubyun) +* 🇺🇦[Ukrainian](readme-ua.md) - cortesia de [Serhii Shramko](https://github.com/Shramkoweb) * Deseja traduzir para o seu próprio idioma? abra uma issue 💜 diff --git a/readme-ua.md b/readme-ua.md index 05ec2ac6..86019764 100644 --- a/readme-ua.md +++ b/readme-ua.md @@ -28,15 +28,15 @@ ### Переклади - читайте своєю мовою -- 🇨🇳[Chinese](readme-zh-CN.md) - З люб'язного дозволу [Yves yao](https://github.com/yvesyao) -- 🇰🇷[Korean](readme.kr.md) - З люб'язного дозволу [Rain Byun](https://github.com/ragubyun) -- 🇵🇱[Polish](readme-pl.md) - З люб'язного дозволу [Michal Biesiada](https://github.com/mbiesiad) -- 🇺🇦[Ukrainian](readme-ua.md) - З люб'язного дозволу [Serhii Shramko](https://github.com/Shramkoweb) -- 🇪🇸[Spanish](readme-es.md) - З люб'язного дозволу [Miguel G. Sanguino](https://github.com/sanguino) -- 🇧🇷[Portuguese-BR](readme-pt-br.md) - З люб'язного дозволу [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) -- 🇫🇷[French](readme-fr.md) - З люб'язного дозволу [Mathilde El Mouktafi](https://github.com/mel-mouk) -- 🇯🇵[Japanese (draft)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - З люб'язного дозволу [Yuichi Yogo](https://github.com/yuichkun) and [ryo](https://github.com/kawamataryo) -- 🇹🇼[Traditional Chinese](readme-zh-TW.md) - З люб'язного дозволу [Yubin Hsu](https://github.com/yubinTW) +- 🇨🇳[Chinese](readme-zh-CN.md) - Завдяки [Yves yao](https://github.com/yvesyao) +- 🇰🇷[Korean](readme.kr.md) - Завдяки [Rain Byun](https://github.com/ragubyun) +- 🇵🇱[Polish](readme-pl.md) - Завдяки [Michal Biesiada](https://github.com/mbiesiad) +- 🇪🇸[Spanish](readme-es.md) - Завдяки [Miguel G. Sanguino](https://github.com/sanguino) +- 🇧🇷[Portuguese-BR](readme-pt-br.md) - Завдяки [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) +- 🇫🇷[French](readme-fr.md) - Завдяки [Mathilde El Mouktafi](https://github.com/mel-mouk) +- 🇯🇵[Japanese (draft)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - Завдяки [Yuichi Yogo](https://github.com/yuichkun) and [ryo](https://github.com/kawamataryo) +- 🇹🇼[Traditional Chinese](readme-zh-TW.md) - Завдяки [Yubin Hsu](https://github.com/yubinTW) +- 🇺🇦[Ukrainian](readme-ua.md) - Завдяки [Serhii Shramko](https://github.com/Shramkoweb) - Хочете перекласти на свою рідну мову? будь ласка, відкрийте issue 💜

    diff --git a/readme-zh-TW.md b/readme-zh-TW.md index 2b20f0f0..d45796a7 100644 --- a/readme-zh-TW.md +++ b/readme-zh-TW.md @@ -38,6 +38,7 @@ - 🇪🇸[Spanish](readme-es.md) - Courtesy of [Miguel G. Sanguino](https://github.com/sanguino) - 🇧🇷[Portuguese-BR](readme-pt-br.md) - Courtesy of [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) - 🇫🇷[French](readme-fr.md) - Courtesy of [Mathilde El Mouktafi](https://github.com/mel-mouk) +- 🇺🇦[Ukrainian](readme-ua.md) - Courtesy of [Serhii Shramko](https://github.com/Shramkoweb) - Want to translate to your own language? please open an issue 💜

    @@ -1901,4 +1902,4 @@ Took care to revise, improve, lint and polish all the texts **Role:** Helps keep this project running, and reviews security related practices -**About:** Loves working on Node.js projects and web application security. \ No newline at end of file +**About:** Loves working on Node.js projects and web application security. diff --git a/readme.md b/readme.md index f5123694..f3d9bb03 100644 --- a/readme.md +++ b/readme.md @@ -45,6 +45,7 @@ Start by understanding the ubiquitous testing practices that are the foundation - 🇫🇷[French](readme-fr.md) - Courtesy of [Mathilde El Mouktafi](https://github.com/mel-mouk) - 🇯🇵[Japanese (draft)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - Courtesy of [Yuichi Yogo](https://github.com/yuichkun) and [ryo](https://github.com/kawamataryo) - 🇹🇼[Traditional Chinese](readme-zh-TW.md) - Courtesy of [Yubin Hsu](https://github.com/yubinTW) +- 🇺🇦[Ukrainian](readme-ua.md) - Courtesy of [Serhii Shramko](https://github.com/Shramkoweb) - Want to translate to your own language? please open an issue 💜

    From e68cb0eaca484422440e298fcc16020cab78073c Mon Sep 17 00:00:00 2001 From: Serhii Shramko Date: Sat, 3 Sep 2022 15:17:45 +0200 Subject: [PATCH 146/189] feat: implement 3 chapter --- readme-ua.md | 188 +++++++++++++++++++++++++-------------------------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/readme-ua.md b/readme-ua.md index 86019764..f73b5783 100644 --- a/readme-ua.md +++ b/readme-ua.md @@ -1117,15 +1117,15 @@ beforeEach(() => {

    -# Section 3️⃣: Frontend Testing +# Section 3️⃣: Frontend Тестування -## ⚪ ️ 3.1 Separate UI from functionality +## ⚪ ️ 3.1 Відокремте інтерфейс від функціональності -:white_check_mark: **Роби:** 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/CSS 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 +:white_check_mark: **Роби:** Коли ви зосереджуєтеся на тестуванні логіки компонентів, деталі інтерфейсу користувача стають шумом, який слід виділити, щоб ваші тести могли зосередитися на чистих даних. На практиці витягуйте потрібні дані з розмітки абстрактним способом, який не надто пов’язаний із графічною реалізацією, затверджуйте лише чисті дані (на відміну від графічних деталей HTML/CSS) і вимикайте анімацію, яка сповільнюється. У вас може виникнути спокуса уникнути візуалізації та протестувати лише задню частину інтерфейсу користувача (наприклад, служби, дії, магазин), але це призведе до вигаданих тестів, які не схожі на реальність, і не виявлять випадків, коли правильні дані навіть не потрапляє в інтерфейс користувача
    -❌ **Інакше:** 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 +❌ **Інакше:** Чисті обчислені дані вашого тесту можуть бути готові через 10 мс, але тоді весь тест триватиме 500 мс (100 тестів = 1 хв) через деяку фантастичну та нерелевантну анімацію
    @@ -1133,9 +1133,9 @@ beforeEach(() => {
    -### :clap: Приклад правильного виконання: Separating out the UI details +### :clap: Приклад правильного виконання: Відокремлення деталей інтерфейсу -![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Приклад з React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Приклад з react-testing-library") ```javascript test("When users-list is flagged to show only VIP, should display only VIP members", () => { @@ -1145,7 +1145,7 @@ test("When users-list is flagged to show only VIP, should display only VIP membe // Act const { getAllByTestId } = render(); - // Assert - Extract the data from the UI first + // Assert - Спочатку витягніть дані з інтерфейсу користувача const allRenderedUsers = getAllByTestId("user").map(uiElement => uiElement.textContent); const allRealVIPUsers = allUsers.filter(user => user.vip).map(user => user.name); expect(allRenderedUsers).toEqual(allRealVIPUsers); //compare data with data, no UI here @@ -1154,7 +1154,7 @@ test("When users-list is flagged to show only VIP, should display only VIP membe
    -### :thumbsdown: Приклад антишаблону: Assertion mix UI details and data +### :thumbsdown: Приклад антишаблону: Деталі та дані інтерфейсу користувача змішані ```javascript test("When flagging to show only VIP, should display only VIP members", () => { @@ -1164,7 +1164,7 @@ test("When flagging to show only VIP, should display only VIP members", () => { // Act const { getAllByTestId } = render(); - // Assert - Mix UI & data in assertion + // Assert - Змішуйте інтерфейс і дані в твердженні expect(getAllByTestId("user")).toEqual('[
  • John Doe
  • ]'); }); ``` @@ -1173,13 +1173,13 @@ test("When flagging to show only VIP, should display only VIP members", () => {

    -## ⚪ ️ 3.2 Query HTML elements based on attributes that are unlikely to change +## ⚪ ️ 3.2 Запит елементів HTML на основі атрибутів, які навряд чи зміняться -:white_check_mark: **Роби:** 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/logic 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 +:white_check_mark: **Роби:** Виконуйте запит до HTML-елементів на основі атрибутів, які, ймовірно, переживуть графічні зміни, на відміну від селекторів CSS і міток форм. Якщо призначений елемент не має таких атрибутів, створіть спеціальний тестовий атрибут, наприклад «test-id-submit-button». Виконання цього шляху не тільки гарантує, що ваші функціональні/логічні тести ніколи не зламаються через зміни зовнішнього вигляду, але також стає зрозумілим для всієї команди, що цей елемент і атрибут використовуються тестами, і їх не слід видаляти
    -❌ **Інакше:** 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' +❌ **Інакше:** Ви хочете перевірити функціональність входу, яка охоплює багато компонентів, логіку та служби, все налаштовано ідеально – заглушки, шпигуни, виклики Ajax ізольовані. Все здається ідеальним. Тоді тест не вдається, тому що дизайнер змінив клас CSS div з 'thick-border' на 'thin-border'
    @@ -1187,22 +1187,22 @@ test("When flagging to show only VIP, should display only VIP members", () => {
    -### :clap: Приклад правильного виконання: Querying an element using a dedicated attribute for testing +### :clap: Приклад правильного виконання: Запит елемента за допомогою спеціального атрибута для тестування -![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Приклад з React") ```html -// the markup code (part of React component) +// Код розмітки (React component)

    {value} - +

    ``` ```javascript -// this example is using react-testing-library +// у цьому прикладі використовується бібліотека react-testing-library test("Whenever no data is passed to metric, show 0 as default", () => { // Arrange const metricValue = undefined; @@ -1216,16 +1216,16 @@ test("Whenever no data is passed to metric, show 0 as default", () => {
    -### :thumbsdown: Приклад антишаблону: Relying on CSS attributes +### :thumbsdown: Приклад антишаблону: Покладаючись на атрибути ```html - + {value} - + ``` ```javascript -// this exammple is using enzyme +// Приклад з Еnzyme test("Whenever no data is passed, error metric shows zero", () => { // ... @@ -1237,15 +1237,15 @@ test("Whenever no data is passed, error metric shows zero", () => {
    -## ⚪ ️ 3.3 Whenever possible, test with a realistic and fully rendered component +## ⚪ ️ 3.3 За можливості тестуйте з реалістичним і повністю відтвореним компонентом -:white_check_mark: **Роби:** 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://github.com/goldbergyoni/javascript-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 +:white_check_mark: **Роби:** Щоразу, коли ваш компонент має прийнятний розмір, тестуйте свій компонент ззовні, як це роблять ваші користувачі, повністю візуалізуйте користувальницький інтерфейс, реагуйте на нього та стверджуйте, що оброблений користувальницький інтерфейс поводиться належним чином. Уникайте будь-якого знущального, часткового та поверхневого рендерингу — такий підхід може призвести до невловлених помилок через брак деталей і посилити технічне обслуговування, оскільки тести зіпсуються з внутрішніми елементами (див. маркований пункт ['Favour blackbox testing'](https://github). .com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-14-stick-to-black-box-testing-test-only-public-methods)). Якщо один із дочірніх компонентів значно уповільнює (наприклад, анімація) або ускладнює налаштування, подумайте про явну заміну його на підробку -With all that said, a word of caution is in order: this technique works for small/medium 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 +З огляду на все сказане, варто зробити одне застереження: ця техніка працює для малих/середніх компонентів, які містять дочірні компоненти розумного розміру. Повне відтворення компонента із занадто великою кількістю дочірніх компонентів ускладнить обґрунтування помилок тестування (аналіз першопричини) і може працювати надто повільно. У таких випадках напишіть лише кілька тестів проти цього жирного батьківського компонента та більше тестів щодо його дочірніх компонентів
    -❌ **Інакше:** When poking into a component's internal by invoking its private methods, and checking the inner state - you would have to refactor all tests when refactoring the components implementation. Do you really have a capacity for this level of maintenance? +❌ **Інакше:** Під час перегляду внутрішніх компонентів, викликаючи його приватні методи та перевіряючи внутрішній стан, вам доведеться виконати рефакторинг усіх тестів під час рефакторингу реалізації компонентів. Чи справді у вас є можливості для такого рівня обслуговування?
    @@ -1253,9 +1253,9 @@ With all that said, a word of caution is in order: this technique works for smal
    -### :clap: Приклад правильного виконання: Working realistically with a fully rendered component +### :clap: Приклад правильного виконання: Реалістична робота з повністю відрендереним компонентом -![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Enzyme-blue.svg "Examples with Enzyme") +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Приклад з React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Enzyme-blue.svg "Приклад з Enzyme") ```javascript class Calendar extends React.Component { @@ -1264,14 +1264,14 @@ class Calendar extends React.Component { render() { return (
    - A filters panel with a button to hide/show filters + /* Панель фільтрів із кнопкою, щоб приховати/показати фільтри */
    ); } } -//Examples use React & Enzyme +// Приклад з React & Enzyme test("Realistic approach: When clicked to show filters, filters are displayed", () => { // Arrange const wrapper = mount(); @@ -1281,11 +1281,11 @@ test("Realistic approach: When clicked to show filters, filters are displayed", // Assert expect(wrapper.text().includes("Choose Filter")); - // This is how the user will approach this element: by text + // Ось як користувач підійде до цього елемента: за текстом }); ``` -### :thumbsdown: Приклад антишаблону: Mocking the reality with shallow rendering +### :thumbsdown: Приклад антишаблону: Мокінг за допомогою неглибокого(shallow) рендерінгу ```javascript test("Shallow/mocked approach: When clicked to show filters, filters are displayed", () => { @@ -1297,11 +1297,11 @@ test("Shallow/mocked approach: When clicked to show filters, filters are display .find("filtersPanel") .instance() .showFilters(); - // Tap into the internals, bypass the UI and invoke a method. White-box approach + // Доторкніться до внутрішніх елементів, обійдіть інтерфейс і викликайте метод. Підхід білого ящика // Assert expect(wrapper.find("Filter").props()).toEqual({ title: "Choose Filter" }); - // what if we change the prop name or don't pass anything relevant? + // що, якщо ми змінимо ім’я пропу або не передамо нічого відповідного? }); ``` @@ -1309,12 +1309,12 @@ test("Shallow/mocked approach: When clicked to show filters, filters are display
    -## ⚪ ️ 3.4 Don't sleep, use frameworks built-in support for async events. Also try to speed things up +## ⚪ ️ 3.4 Не спіть, використовуйте вбудовану підтримку фреймворків для асинхронних подій. Також спробуйте прискорити процес -:white_check_mark: **Роби:** In many cases, the unit under test completion time is just unknown (e.g. animation suspends element appearance) - in that case, avoid sleeping (e.g. setTimeOut) and prefer more deterministic methods that most platforms provide. Some libraries allows awaiting on operations (e.g. [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), other provide API for waiting like [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). Sometimes a more elegant way is to stub the slow resource, like API for example, and then once the response moment becomes deterministic the component can be explicitly re-rendered. When depending upon some external component that sleeps, it might turn useful to [hurry-up the clock](https://jestjs.io/docs/en/timer-mocks). Sleeping is a pattern to avoid because it forces your test to be slow or risky (when waiting for a too short period). Whenever sleeping and polling is inevitable and there's no support from the testing framework, some npm libraries like [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) can help with a semi-deterministic solution +:white_check_mark: **Роби:** У багатьох випадках час завершення блоку, що тестується, просто невідомий (наприклад, анімація призупиняє появу елемента) - у такому випадку уникайте сплячого режиму (наприклад, setTimeOut) і віддайте перевагу більш детермінованим методам, які пропонують більшість платформ. Деякі бібліотеки дозволяють очікувати виконання операцій (наприклад, [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), інші надають API для очікування, як [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). Іноді більш елегантним способом є заглушка повільного ресурсу, наприклад API, а потім, коли момент відповіді стане детермінованим, компонент може бути явно повторно відтворений. Якщо залежно від зовнішнього компонента, який спить, може виявитися корисним [поспішити годинник](https://jestjs.io/docs/en/timer-mocks). Сон — це шаблон, якого слід уникати, оскільки він змушує ваш тест бути повільним або ризикованим (якщо ви чекаєте занадто короткий період). Щоразу, коли сплячий режим і опитування неминучі, а платформа тестування не підтримує, деякі бібліотеки npm, як-от [wait-for-expect](https://www.npmjs.com/package/wait-for-expect), можуть допомогти з напів - детерміноване рішення
    -❌ **Інакше:** When sleeping for a long time, tests will be an order of magnitude slower. When trying to sleep for small numbers, test will fail when the unit under test didn't respond in a timely fashion. So it boils down to a trade-off between flakiness and bad performance +❌ **Інакше:** При тривалому сні тести будуть на порядок повільніше. Під час спроби переходу в режим сну для невеликих чисел тест не вдасться, якщо тестований пристрій не відповів своєчасно. Отже, це зводиться до компромісу між нестабільністю та поганою продуктивністю
    @@ -1322,42 +1322,42 @@ test("Shallow/mocked approach: When clicked to show filters, filters are display
    -### :clap: Приклад правильного виконання: E2E API that resolves only when the async operations is done (Cypress) +### :clap: Приклад правильного виконання: API E2E, який вирішується лише після виконання асинхронних операцій (Cypress) -![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") -![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Використання Cypress для ілюстрації ідеї") +![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Приклад з react-testing-library") ```javascript -// using Cypress -cy.get("#show-products").click(); // navigate -cy.wait("@products"); // wait for route to appear -// this line will get executed only when the route is ready +// Використання Cypress +cy.get("#show-products").click(); // Навігація +cy.wait("@products"); // зачекайте, поки з'явиться маршрут +// цей рядок буде виконано лише тоді, коли маршрут буде готовий ``` -### :clap: Приклад правильного виконання: Testing library that waits for DOM elements +### :clap: Приклад правильного виконання: Тестування бібліотеки, яка очікує елементи DOM ```javascript // @testing-library/dom test("movie title appears", async () => { - // element is initially not present... + // елемент спочатку відсутній... - // wait for appearance + // чекати появи await wait(() => { expect(getByText("the lion king")).toBeInTheDocument(); }); - // wait for appearance and return the element + // дочекатися появи і повернути елемент const movie = await waitForElement(() => getByText("the lion king")); }); ``` -### :thumbsdown: Приклад антишаблону: custom sleep code +### :thumbsdown: Приклад антишаблону: спеціальний код сну ```javascript test("movie title appears", async () => { - // element is initially not present... + // елемент спочатку відсутній... - // custom wait logic (caution: simplistic, no timeout) + // спеціальна логіка очікування (застереження: спрощено, без часу очікування) const interval = setInterval(() => { const found = getByText("the lion king"); if (found) { @@ -1366,7 +1366,7 @@ test("movie title appears", async () => { } }, 100); - // wait for appearance and return the element + // дочекатися появи і повернути елемент const movie = await waitForElement(() => getByText("the lion king")); }); ``` @@ -1375,31 +1375,31 @@ test("movie title appears", async () => {
    -## ⚪ ️ 3.5 Watch how the content is served over the network +## ⚪ ️ 3.5 Подивіться, як вміст подається в мережі -![](https://img.shields.io/badge/🔧%20Example%20using%20Google%20LightHouse-blue.svg "Examples with Lighthouse") +![](https://img.shields.io/badge/🔧%20Example%20using%20Google%20LightHouse-blue.svg "Приклад з Lighthouse") -✅ **Роби:** Apply some active monitor that ensures the page load under real network is optimized - this includes any UX concern like slow page load or un-minified bundle. The inspection tools market is no short: basic tools like [pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) can be easily configured to watch whether the server is alive and response under a reasonable SLA. This only scratches the surface of what might get wrong, hence it's preferable to opt for tools that specialize in frontend (e.g. [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) and perform richer analysis. The focus should be on symptoms, metrics that directly affect the UX, like page load time, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [time until the page gets interactive (TTI)](https://calibreapp.com/blog/time-to-interactive/). On top of that, one may also watch for technical causes like ensuring the content is compressed, time to the first byte, optimize images, ensuring reasonable DOM size, SSL and many others. It's advisable to have these rich monitors both during development, as part of the CI and most important - 24x7 over the production's servers/CDN +✅ **Роби:** Застосуйте деякий активний монітор, який гарантує оптимізацію завантаження сторінки в реальній мережі - це стосується будь-яких проблем з UX, як-от повільне завантаження сторінки або немініфікований пакет. Ринок інструментів перевірки не короткий: такі базові інструменти, як [pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks) /) можна легко налаштувати, щоб стежити за тим, чи працює сервер і чи відповідає він відповідно до прийнятної угоди про рівень обслуговування. Це лише дряпає поверхню того, що може піти не так, тому краще вибрати інструменти, які спеціалізуються на інтерфейсі (наприклад, [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed]( https://developers.google.com/speed/pagespeed/insights/)) і виконувати детальніший аналіз. Слід зосередитися на симптомах, показниках, які безпосередньо впливають на UX, як-от час завантаження сторінки, [важливий малюнок](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next- billion-users-in-2018/fmp-first-meaningful-paint), [час, поки сторінка не стане інтерактивною (TTI)](https://calibreapp.com/blog/time-to-interactive/). Крім того, можна також спостерігати за технічними причинами, такими як забезпечення стиснення вмісту, час до першого байта, оптимізація зображень, забезпечення розумного розміру DOM, SSL та багато інших. Бажано мати ці багаті монітори як під час розробки, як частину CI, так і, що найголовніше, - 24x7 на робочих серверах/CDN
    -❌ **Інакше:** It must be disappointing to realize that after such great care for crafting a UI, 100% functional tests passing and sophisticated bundling - the UX is horrible and slow due to CDN misconfiguration +❌ **Інакше:** Мабуть, прикро усвідомлювати, що після такої ретельної роботи над створенням інтерфейсу користувача, проходження 100% функціональних тестів і складного об’єднання – UX жахливий і повільний через неправильну конфігурацію CDN
    Приклади коду -### :clap: Приклад правильного виконання: Lighthouse page load inspection report +### :clap: Приклад правильного виконання: Звіт про перевірку завантаження сторінки Lighthouse -![](/assets/lighthouse2.png "Lighthouse page load inspection report") +![](/assets/lighthouse2.png "Lighthouse звіт завантаження сторінки")

    -## ⚪ ️ 3.6 Stub flaky and slow resources like backend APIs +## ⚪ ️ 3.6 Нестабільні та повільні ресурси, як-от серверні API -:white_check_mark: **Роби:** When coding your mainstream tests (not E2E tests), avoid involving any resource that is beyond your responsibility and control like backend API and use stubs instead (i.e. test double). Practically, instead of real network calls to APIs, use some test double library (like [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble), etc) for stubbing the API response. The main benefit is preventing flakiness - testing or staging APIs by definition are not highly stable and from time to time will fail your tests although YOUR component behaves just fine (production env was not meant for testing and it usually throttles requests). Doing this will allow simulating various API behavior that should drive your component behavior as when no data was found or the case when API throws an error. Last but not least, network calls will greatly slow down the tests +:white_check_mark: **Роби:** Під час кодування основних тестів (не тестів E2E) уникайте залучення будь-яких ресурсів, які знаходяться поза межами вашої відповідальності та контролю, як-от серверний API, і використовуйте натомість заглушки (тобто test double). На практиці замість реальних мережевих викликів API використовуйте якусь тестову подвійну бібліотеку (наприклад, [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble) тощо) для заглушки відповіді API. Основною перевагою є запобігання нестабільності — API тестування або проміжної обробки за визначенням не є дуже стабільними і час від часу не проходять ваші тести, хоча ВАШ компонент поводиться нормально (виробниче середовище не призначене для тестування, і зазвичай воно гальмує запити). Це дозволить симулювати різні дії API, які повинні керувати поведінкою вашого компонента, наприклад, коли дані не знайдено або випадок, коли API видає помилку. І останнє, але не менш важливе, мережеві виклики значно сповільнюють тести
    @@ -1413,7 +1413,7 @@ test("movie title appears", async () => { ### :clap: Приклад правильного виконання: Stubbing or intercepting API calls -![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Приклад з React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Приклад з react-testing-library") ```javascript // unit under test @@ -1451,23 +1451,23 @@ test("When no products exist, show the appropriate message", () => {
    -## ⚪ ️ 3.7 Have very few end-to-end tests that spans the whole system +## ⚪ ️ 3.7 Майте дуже мало наскрізних тестів(e2e), які охоплюють всю систему -:white_check_mark: **Роби:** Although E2E (end-to-end) usually means UI-only testing with a real browser (See [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)), for other they mean tests that stretch the entire system including the real backend. The latter type of tests is highly valuable as they cover integration bugs between frontend and backend that might happen due to a wrong understanding of the exchange schema. They are also an efficient method to discover backend-to-backend integration issues (e.g. Microservice A sends the wrong message to Microservice B) and even to detect deployment failures - there are no backend frameworks for E2E testing that are as friendly and mature as UI frameworks like [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). The downside of such tests is the high cost of configuring an environment with so many components, and mostly their brittleness - given 50 microservices, even if one fails then the entire E2E just failed. For that reason, we should use this technique sparingly and probably have 1-10 of those and no more. That said, even a small number of E2E tests are likely to catch the type of issues they are targeted for - deployment & integration faults. It's advisable to run those over a production-like staging environment +:white_check_mark: **Роби:** AХоча E2E (наскрізне) зазвичай означає тестування лише інтерфейсу користувача за допомогою справжнього браузера (див. [пункт 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8% 8F-36-stub-flaky-and-slow-resources-like-backend-apis)), для інших вони означають тести, які розтягують всю систему, включаючи справжній сервер. Останній тип тестів є дуже цінним, оскільки вони охоплюють помилки інтеграції між інтерфейсом і сервером, які можуть виникнути через неправильне розуміння схеми обміну. Вони також є ефективним методом для виявлення проблем міжсервісної інтеграції (наприклад, мікросервіс A надсилає неправильне повідомлення мікросервісу B) і навіть для виявлення збоїв розгортання – для тестування E2E не існує таких дружніх і зрілих інтерфейсів, як UI. такі фреймворки, як [Cypress](https://www.cypress.io/) і [Puppeteer](https://github.com/GoogleChrome/puppeteer). Недоліком таких тестів є висока вартість налаштування середовища з такою кількістю компонентів і, здебільшого, їхня крихкість — з огляду на 50 мікросервісів, навіть якщо один зазнає невдачі, тоді зазнає невдачі весь E2E. З цієї причини ми повинні використовувати цю техніку економно і, можливо, мати 1-10 таких і не більше. Тим не менш, навіть невелика кількість тестів E2E, швидше за все, виявить тип проблем, на які вони націлені – помилки розгортання та інтеграції. Бажано запускати їх у середовищі, схожому на виробництво
    -❌ **Інакше:** UI might invest much in testing its functionality only to realizes very late that the backend returned payload (the data schema the UI has to work with) is very different than expected +❌ **Інакше:** Інтерфейс користувача може багато вкладати в тестування своєї функціональності, але дуже пізно зрозуміє, що корисне навантаження (схема даних, з якою має працювати інтерфейс користувача) сильно відрізняється від очікуваного.
    -## ⚪ ️ 3.8 Speed-up E2E tests by reusing login credentials +## ⚪ ️ 3.8 Прискоріть тестування E2E, повторно використовуючи облікові дані для входу -:white_check_mark: **Роби:** In E2E tests that involve a real backend and rely on a valid user token for API calls, it doesn't payoff to isolate the test to a level where a user is created and logged-in in every request. Instead, login only once before the tests execution start (i.e. before-all hook), save the token in some local storage and reuse it across requests. This seem to violate one of the core testing principle - keep the test autonomous without resources coupling. While this is a valid worry, in E2E tests performance is a key concern and creating 1-3 API requests before starting each individual tests might lead to horrible execution time. Reusing credentials doesn't mean the tests have to act on the same user records - if relying on user records (e.g. test user payments history) than make sure to generate those records as part of the test and avoid sharing their existence with other tests. Also remember that the backend can be faked - if your tests are focused on the frontend it might be better to isolate it and stub the backend API (see [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)). +:white_check_mark: **Роби:** У тестах E2E, які включають справжню серверну частину та покладаються на дійсний маркер користувача для викликів API, ізолювати тест до рівня, на якому користувач створюється та входить у систему під час кожного запиту, не виправдовується. Замість цього увійдіть лише один раз перед початком виконання тестів (тобто хук before-all), збережіть маркер у локальному сховищі та повторно використовуйте його для запитів. Схоже, це порушує один із основних принципів тестування — підтримувати тест автономним без зв’язку ресурсів. Хоча це обґрунтоване занепокоєння, у тестах E2E продуктивність є ключовою проблемою, і створення 1-3 запитів API перед початком кожного окремого тесту може призвести до жахливого часу виконання. Повторне використання облікових даних не означає, що тести повинні діяти з тими самими записами користувачів. Якщо ви покладаєтеся на записи користувачів (наприклад, історію платежів тестового користувача), переконайтеся, що створили ці записи як частину тесту та не повідомляли про їх існування іншим тестам. Також пам’ятайте, що бекенд може бути підробленим – якщо ваші тести зосереджені на інтерфейсі, можливо, краще ізолювати його та заглушити бекенд API (див. [пункт 3.6](https://github.com/goldbergyoni/javascript-testing- best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)).
    -❌ **Інакше:** Given 200 test cases and assuming login=100ms = 20 seconds only for logging-in again and again +❌ **Інакше:** Надано 200 тестів і припущення, що login=100ms=20 секунд лише для входу знову і знову
    @@ -1475,14 +1475,14 @@ test("When no products exist, show the appropriate message", () => {
    -### :clap: Приклад правильного виконання: Logging-in before-all and not before-each +### :clap: Приклад правильного виконання: Вхід перед усіма, а не перед кожним -![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Використання Cypress для ілюстраціі ідеї") ```javascript let authenticationToken; -// happens before ALL tests run +// відбувається перед виконанням УСІХ тестів before(() => { cy.request('POST', 'http://localhost:3000/login', { username: Cypress.env('username'), @@ -1494,8 +1494,8 @@ before(() => { }) }) -// happens before EACH test -beforeEach(setUser => () { +// відбувається перед КОЖНИМ тестом +beforeEach(setUser => { cy.visit('/home', { onBeforeLoad (win) { win.localStorage.setItem('token', JSON.stringify(authenticationToken)) @@ -1509,13 +1509,13 @@ beforeEach(setUser => () {
    -## ⚪ ️ 3.9 Have one E2E smoke test that just travels across the site map +## ⚪ ️ 3.9 Проведіть один тест "smoke" E2E, який просто пройде по карті сайту -:white_check_mark: **Роби:** For production monitoring and development-time sanity check, run a single E2E test that visits all/most of the site pages and ensures no one breaks. This type of test brings a great return on investment as it's very easy to write and maintain, but it can detect any kind of failure including functional, network and deployment issues. Other styles of smoke and sanity checking are not as reliable and exhaustive - some ops teams just ping the home page (production) or developers who run many integration tests which don't discover packaging and browser issues. Goes without saying that the smoke test doesn't replace functional tests rather just aim to serve as a quick smoke detector +:white_check_mark: **Роби:** Для моніторингу виробництва та перевірки працездатності під час розробки запустіть єдиний тест E2E, який відвідує всі/більшість сторінок сайту та гарантує, що ніхто не зламався. Цей тип тесту забезпечує високу окупність інвестицій, оскільки його дуже легко писати та підтримувати, але він може виявити будь-які збої, включаючи функціональні проблеми, проблеми з мережею та розгортання. Інші стилі перевірки диму та працездатності не такі надійні та вичерпні — деякі оперативні команди просто перевіряють домашню сторінку (виробництво) або розробники, які запускають багато інтеграційних тестів, які не виявляють проблем з пакуванням і браузером. Само собою зрозуміло, що димовий тест не замінює функціональні тести, а лише служить швидким детектором диму
    -❌ **Інакше:** Everything might seem perfect, all tests pass, production health-check is also positive but the Payment component had some packaging issue and only the /Payment route is not rendering +❌ **Інакше:** Все може здатися ідеальним, усі тести пройшли, перевірка робочого стану також позитивна, але платіжний компонент мав деякі проблеми з упаковкою, і лише маршрут /Payment не відображається
    @@ -1523,14 +1523,14 @@ beforeEach(setUser => () {
    -### :clap: Приклад правильного виконання: Smoke travelling across all pages +### :clap: Приклад правильного виконання: "Smoke" тест по всіх сторінках -![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Використання Cypress") ```javascript it("When doing smoke testing over all page, should load them all successfully", () => { - // exemplified using Cypress but can be implemented easily - // using any E2E suite + // Smoke тест на всіх сторінках + // використовуючи будь-який пакет E2E cy.visit("https://mysite.com/home"); cy.contains("Home"); cy.visit("https://mysite.com/Login"); @@ -1544,11 +1544,11 @@ it("When doing smoke testing over all page, should load them all successfully",
    -## ⚪ ️ 3.10 Expose the tests as a live collaborative document +## ⚪ ️ 3.10 Виставте тести як живий спільний документ -:white_check_mark: **Роби:** Besides increasing app reliability, tests bring another attractive opportunity to the table - serve as live app documentation. Since tests inherently speak at a less-technical and product/UX language, using the right tools they can serve as a communication artifact that greatly aligns all the peers - developers and their customers. For example, some frameworks allow expressing the flow and expectations (i.e. tests plan) using a human-readable language so any stakeholder, including product managers, can read, approve and collaborate on the tests which just became the live requirements document. This technique is also being referred to as 'acceptance test' as it allows the customer to define his acceptance criteria in plain language. This is [BDD (behavior-driven testing)](https://en.wikipedia.org/wiki/Behavior-driven_development) at its purest form. One of the popular frameworks that enable this is [Cucumber which has a JavaScript flavor](https://github.com/cucumber/cucumber-js), see example below. Another similar yet different opportunity, [StoryBook](https://storybook.js.org/), allows exposing UI components as a graphic catalog where one can walk through the various states of each component (e.g. render a grid w/o filters, render that grid with multiple rows or with none, etc), see how it looks like, and how to trigger that state - this can appeal also to product folks but mostly serves as live doc for developers who consume those components. +:white_check_mark: **Роби:** Окрім підвищення надійності додатка, тести надають ще одну привабливу можливість – слугувати живою документацією додатка. Оскільки тести за своєю суттю розмовляють менш технічною мовою та мовою продукту/UX, використання правильних інструментів може служити артефактом спілкування, який значною мірою зближує всіх колег – розробників та їхніх клієнтів. Наприклад, деякі фреймворки дозволяють виражати потік і очікування (тобто план тестування) за допомогою зрозумілої людині мови, щоб будь-яка зацікавлена ​​сторона, включаючи менеджерів із продуктів, могла читати, затверджувати та співпрацювати над тестами, які щойно стали актуальним документом вимог. Цю техніку також називають «приймальним тестом», оскільки вона дозволяє клієнту визначити свої критерії прийнятності простою мовою. Це [BDD (тестування, кероване поведінкою)](https://en.wikipedia.org/wiki/Behavior-driven_development) у чистому вигляді. Одним із популярних фреймворків, які це дозволяють, є [Cucumber, який має смак JavaScript](https://github.com/cucumber/cucumber-js), див. приклад нижче. Інша схожа, але інша можливість, [StoryBook](https://storybook.js.org/), дозволяє виставляти компоненти інтерфейсу користувача як графічний каталог, де можна переглядати різні стани кожного компонента (наприклад, візуалізувати сітку без фільтрів). , візуалізуйте цю сітку з кількома рядками або без жодного тощо), подивіться, як це виглядає та як активувати цей стан - це також може сподобатися спеціалістам із продуктів, але здебільшого служить живою документацією для розробників, які використовують ці компоненти. -❌ **Інакше:** After investing top resources on testing, it's just a pity not to leverage this investment and win great value +❌ **Інакше:** Після інвестування найкращих ресурсів у тестування просто шкода не використати ці інвестиції та отримати велику цінність
    @@ -1556,12 +1556,12 @@ it("When doing smoke testing over all page, should load them all successfully",
    -### :clap: Приклад правильного виконання: Describing tests in human-language using cucumber-js +### :clap: Приклад правильного виконання: Опис тестів людською мовою за допомогою cucumber-js -![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Examples using Cucumber") +![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Приклад з Cucumber") ```javascript -// this is how one can describe tests using cucumber: plain language that allows anyone to understand and collaborate +// ось як можна описати тести за допомогою Cucumber: проста мова, яка дозволяє будь-кому розуміти та співпрацювати Feature: Twitter new tweet @@ -1577,9 +1577,9 @@ Feature: Twitter new tweet ``` -### :clap: Приклад правильного виконання: Visualizing our components, their various states and inputs using Storybook +### :clap: Приклад правильного виконання: Візуалізація наших компонентів, їх різних станів і вхідних даних за допомогою Storybook -![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") +![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "StoryBook") ![alt text](assets/story-book.jpg "Storybook") @@ -1587,13 +1587,13 @@ Feature: Twitter new tweet

    -## ⚪ ️ 3.11 Detect visual issues with automated tools +## ⚪ ️ 3.11 Виявляйте візуальні проблеми за допомогою автоматизованих інструментів -:white_check_mark: **Роби:** Setup automated tools to capture UI screenshots when changes are presented and detect visual issues like content overlapping or breaking. This ensures that not only the right data is prepared but also the user can conveniently see it. This technique is not widely adopted, our testing mindset leans toward functional tests but it's the visuals what the user experience and with so many device types it's very easy to overlook some nasty UI bug. Some free tools can provide the basics - generate and save screenshots for the inspection of human eyes. While this approach might be sufficient for small apps, it's flawed as any other manual testing that demands human labor anytime something changes. On the other hand, it's quite challenging to detect UI issues automatically due to the lack of clear definition - this is where the field of 'Visual Regression' chime in and solve this puzzle by comparing old UI with the latest changes and detect differences. Some OSS/free tools can provide some of this functionality (e.g. [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>) but might charge significant setup time. The commercial line of tools (e.g. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) takes is a step further by smoothing the installation and packing advanced features like management UI, alerting, smart capturing by eliminating 'visual noise' (e.g. ads, animations) and even root cause analysis of the DOM/CSS changes that led to the issue +:white_check_mark: **Роби:** Налаштуйте автоматичні інструменти для створення скріншотів інтерфейсу користувача, коли представлені зміни, і виявлення візуальних проблем, як-от накладення вмісту або порушення. Це гарантує, що не тільки правильні дані підготовлені, але й користувач може їх зручно переглядати. Ця техніка не є широко поширеною, наше мислення щодо тестування схиляється до функціональних тестів, але користувач відчуває візуальні ефекти, а з такою кількістю типів пристроїв дуже легко не помітити неприємну помилку інтерфейсу користувача. Деякі безкоштовні інструменти можуть надати основи — створювати та зберігати знімки екрана для огляду очей людини. Хоча цього підходу може бути достатньо для невеликих додатків, він має недоліки, як і будь-яке інше ручне тестування, яке потребує людської праці щоразу, коли щось змінюється. З іншого боку, досить складно автоматично виявляти проблеми з інтерфейсом користувача через відсутність чіткого визначення – тут спрацьовує поле «Візуальна регресія» та розв’язує цю загадку, порівнюючи старий інтерфейс користувача з останніми змінами та виявляючи відмінності. Деякі OSS/безкоштовні інструменти можуть надавати деякі з цих функцій (наприклад, [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS] (https://github.com/HuddleEng/PhantomCSS)>), але може стягувати значний час налаштування.Комерційна лінія інструментів (наприклад, [Applitools](https://applitools.com/), [Percy.io](https ://percy.io/)) робить крок далі, згладжуючи інсталяцію та розширюючи такі функції, як інтерфейс користувача користувача, сповіщення, інтелектуальне захоплення шляхом усунення «візуального шуму» (наприклад, реклами, анімації) і навіть аналіз першопричини DOM /CSS зміни, які призвели до проблеми
    -❌ **Інакше:** How good is a content page that display great content (100% tests passed), loads instantly but half of the content area is hidden? +❌ **Інакше:** Наскільки якісною є сторінка з вмістом, яка відображає чудовий вміст (пройдено 100% тестів), завантажується миттєво, але половина області вмісту прихована?
    @@ -1601,13 +1601,13 @@ Feature: Twitter new tweet
    -### :thumbsdown: Приклад антишаблону: A typical visual regression - right content that is served badly +### :thumbsdown: Приклад антишаблону: Типова візуальна регресія – правильний контент, який подається погано -![alt text](assets/amazon-visual-regression.jpeg "Amazon page breaks") +![alt text](assets/amazon-visual-regression.jpeg "Amazon - зламана сторніка")
    -### :clap: Приклад правильного виконання: Configuring wraith to capture and compare UI snapshots +### :clap: Приклад правильного виконання: Налаштування wraith для захоплення та порівняння знімків інтерфейсу користувача ![](https://img.shields.io/badge/🔨%20Example%20using%20Wraith-blue.svg "Using Wraith") @@ -1636,9 +1636,9 @@ paths: path: /subscribe ``` -### :clap: Приклад правильного виконання: Using Applitools to get snapshot comparison and other advanced features +### :clap: Приклад правильного виконання: Використання Applitools для порівняння знімків та інших розширених функцій -![](https://img.shields.io/badge/🔨%20Example%20using%20AppliTools-blue.svg "Using Applitools") ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") +![](https://img.shields.io/badge/🔨%20Example%20using%20AppliTools-blue.svg "Використання Applitools") ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Використання Cypress") ```javascript import * as todoPage from "../page-objects/todo-page"; From b40b41246bd4146211ac30fee630684796376e5f Mon Sep 17 00:00:00 2001 From: Yugo Sakamoto Date: Fri, 16 Sep 2022 10:54:09 -0300 Subject: [PATCH 147/189] =?UTF-8?q?Adicionado=20espa=C3=A7o=20entre=20pala?= =?UTF-8?q?vras?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adicionado espaço entre palavras no título da seção 5.3 --- readme-pt-br.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme-pt-br.md b/readme-pt-br.md index e127ab7d..b97984c6 100644 --- a/readme-pt-br.md +++ b/readme-pt-br.md @@ -1800,7 +1800,7 @@ Na prática alguns fornecedores de IC (exemplo: [CircleCI local CLI](https://cir

    -# ⚪ ️5.3 Realize testes e2eem um verdadeiro espelho de produção +# ⚪ ️5.3 Realize testes e2e em um verdadeiro espelho de produção :white_check_mark: **Faça:** Os testes de ponta a ponta (e2e) são o principal desafio de cada pipeline de IC—criar um espelho efêmero idêntico de produção em tempo real com todos os serviços em nuvem relacionados pode ser entediante e caro. Encontrar o melhor comprometimento é o seu jogo: [Docker-compose](https://serverless.com/) permite criar ambiente docker isolado com contêineres idênticos usando um único arquivo de texto sem formatação, mas as tecnologias de suporte (por exemplo. rede, modelo de implantação) é diferente das produções do mundo real. Você pode combiná-lo com [‘AWS Local’](https://github.com/localstack/localstack) para trabalhar com um esboço dos serviços reais da AWS. Se você usar [serverless](https://serverless.com/) vários frameworks como serverless e [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) permite a chamada local de códigos FaaS. From 7f2761135f8085f87951d9d2db0194a79914691c Mon Sep 17 00:00:00 2001 From: Ali Azmoodeh Date: Sat, 17 Sep 2022 20:25:42 +0430 Subject: [PATCH 148/189] Fix syntax bug in readme file In this url https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F29-isolate-the-component-from-the-world-using-http-interceptor There is a syntax error in the Code Examples section that causes the next item to be included in the code example. --- readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 57a818c0..df0e4c54 100644 --- a/readme.md +++ b/readme.md @@ -1020,7 +1020,8 @@ beforeEach(() => { id: 1, name: 'John', }); -});``` +}); +```
    From 426c325e73a1b3c2a966245b070a04e16168c197 Mon Sep 17 00:00:00 2001 From: Ali Azmoodeh Date: Sun, 18 Sep 2022 19:47:20 +0430 Subject: [PATCH 149/189] Fix syntax bug in readme file The code sample type was changed and js and json syntax bugs were fixed --- readme.md | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/readme.md b/readme.md index df0e4c54..5af1226e 100644 --- a/readme.md +++ b/readme.md @@ -1120,7 +1120,6 @@ beforeEach(() => { • 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/metrics. This information goes directly to a very important user - The ops user (i.e., production SRE/admin) -


    @@ -1502,14 +1501,13 @@ before(() => { }) // happens before EACH test -beforeEach(setUser => () { - cy.visit('/home', { - onBeforeLoad (win) { +beforeEach(setUser => { + cy.visit('/home', () => { + onBeforeLoad (win => { win.localStorage.setItem('token', JSON.stringify(authenticationToken)) - }, + }) }) }) - ```
    @@ -1567,8 +1565,8 @@ it("When doing smoke testing over all page, should load them all successfully", ![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Examples using Cucumber") -```javascript -// this is how one can describe tests using cucumber: plain language that allows anyone to understand and collaborate +```text +This is how one can describe tests using cucumber: plain language that allows anyone to understand and collaborate Feature: Twitter new tweet @@ -1581,7 +1579,6 @@ Feature: Twitter new tweet Given I type "Hello followers!" in the textbox Given I click on "Submit" button Then I see message "Tweet saved" - ``` ### :clap: Doing It Right Example: Visualizing our components, their various states and inputs using Storybook @@ -1803,7 +1800,7 @@ it.skip("Test name", () => {// *error:no-skipped-tests, error:error:no-global-te expect("somevalue"); // error:no-assert }); -it("Test name", () => {*//error:no-identical-title. Assign unique titles to tests +it("Test name", () => {// *error:no-identical-title. Assign unique titles to tests }); ``` @@ -1853,14 +1850,14 @@ Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com ### :clap: Doing It Right Example: npm scripts that perform code quality inspection, all are run in parallel on demand or when a developer is trying to push new code -```javascript -"scripts": { +```json +{ + "scripts": { "inspect:sanity-testing": "mocha **/**--test.js --grep \"sanity\"", "inspect:lint": "eslint .", "inspect:vulnerabilities": "npm audit", "inspect:license": "license-checker --failOn GPLv2", "inspect:complexity": "plato .", - "inspect:all": "concurrently -c \"bgBlue.bold,bgMagenta.bold,yellow\" \"npm:inspect:quick-testing\" \"npm:inspect:lint\" \"npm:inspect:vulnerabilities\" \"npm:inspect:license\"" }, "husky": { @@ -1868,8 +1865,8 @@ Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com "precommit": "npm run inspect:all", "prepush": "npm run inspect:all" } + } } - ```
    @@ -1933,13 +1930,12 @@ The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for ### :clap: Doing It Right Example: -```javascript -//install license-checker in your CI environment or also locally +```shell +# install license-checker in your CI environment or also locally npm install -g license-checker -//ask it to scan all licenses and fail with exit code other than 0 if it found unauthorized license. The CI system should catch this failure and stop the build +# ask it to scan all licenses and fail with exit code other than 0 if it found unauthorized license. The CI system should catch this failure and stop the build license-checker --summary --failOn BSD - ```
    From 9bfce031c796e05d562b853811c73a8d7c9c1b16 Mon Sep 17 00:00:00 2001 From: Ali Azmoodeh Date: Sun, 18 Sep 2022 19:51:56 +0430 Subject: [PATCH 150/189] added chapter 1 and 2 --- readme-pr-fr.md | 2055 +++++++++++++++++++++++++++++++++++++++++++++++ readme.md | 1 + 2 files changed, 2056 insertions(+) create mode 100644 readme-pr-fr.md diff --git a/readme-pr-fr.md b/readme-pr-fr.md new file mode 100644 index 00000000..89c4fe43 --- /dev/null +++ b/readme-pr-fr.md @@ -0,0 +1,2055 @@ + + + +
    + +# 👇 چرا این راهنما می تواند مهارت های آزمایشی شما را به سطح بعدی برساند + +
    + +## 📗 50+ تا از بهترین شیوه ها: فوق العاده جامع و جامع + +این راهنمای قابلیت اطمینان JavaScript & Node.js از A-Z است. ده‌ها مورد از بهترین پست‌ها، کتاب‌ها و ابزارهایی که بازار ارائه می‌دهد را برای شما خلاصه و گردآوری می‌کند. + +## 🚢 پیشرفته: 10000 مایل فراتر از اصول اولیه می رود + +به سفری بروید که بسیار فراتر از اصول اولیه به موضوعات پیشرفته ای مانند آزمایش در تولید، آزمایش جهش، آزمایش مبتنی بر دارایی و بسیاری از ابزارهای استراتژیک و حرفه ای دیگر سفر می کند. اگر تمام کلمات این راهنما را بخوانید، احتمالاً مهارت های تست زنی شما بسیار بالاتر از حد متوسط خواهد بود + +## 🌐 Full-stack: front, backend, CI, هر چیزی + +با درک روش‌های تست همه جا حاضر که پایه و اساس هر سطح برنامه هستند، شروع کنید. سپس، به حوزه انتخابی خود بپردازید: frontend/UI، backend، CI یا شاید همه آنها؟ + +
    + +### Yoni Goldberg نوشته شده توسط + +- JavaScript & Node.js مشاوره +- 📗 [تست کردن Node.js & JavaScript از A تا Z](https://www.testjavascript.com) - دوره جامع آنلاین من با بیش از [7 ساعت ویدیو](https://www.testjavascript.com), 14 انواع تست و بیش از 40 بهترین روش +- [من را در توییتر دنبال کنید](https://twitter.com/goldbergyoni/) +- [کارگاه بعدی: ورونا، ایتالیا 🇮🇹، 20 آوریل](https://2022.jsday.it/workshop/nodejs_testing.html) + +
    + + +## `فهرست مطالب` + +#### [`بخش 0: قاعده طلایی`](#section-0️⃣-the-golden-rule) + +یک توصیه واحد که الهام بخش بقیه است (1 گلوله ویژه) + +#### [`بخش 1: آناتومی تست`](#section-1-the-test-anatomy-1) + +فونداسیون - تست های تمیز ساختاری (12 گلوله) + +#### [`Backend :بخش 2`](#section-2️⃣-backend-testing) + +نوشتن تست های backend و میکروسرویس به طور موثر (13 گلوله) + +#### [`Frontend :بخش 3`](#section-3️⃣-frontend-testing) + +نوشتن تست ها برای رابط کاربری وب شامل تست های کامپوننت و E2E +(11 گلوله) + +#### [`بخش 4: اندازه گیری اثربخشی آزمون ها`](#section-4️⃣-measuring-test-effectiveness) + +تماشای نگهبان - اندازه گیری کیفیت تست (4 گلوله) + +#### [`بخش 5: یکپارچه سازی مداوم`](#section-5️⃣-ci-and-other-quality-measures) + +دستورالعمل های CI در دنیای JS (9 گلوله) + +

    + +# بخش 0️⃣: قاعده طلایی + +
    + +## ⚪️ 0 قانون طلایی: طراحی برای تست ناب + +:white_check_mark: **انجام دادن:** + +تست کردن کد صرفا نوشتن کد نیست - آن را طوری طراحی کنید که کوتاه، ساده، مسطح، و کار کردن با آن لذت بخش باشد. باید به یک تست نگاه کرد و فوراً هدف را دریافت کرد. + +ببینید، ذهن ما از قبل مشغول کار اصلی ما - نوشتن کد است. برای پیچیدگی اضافی، هیچ فضایی وجود ندارد. اگر بخواهیم یک سیستم sus-system دیگر را در مغز ضعیف خود بفشاریم، سرعت تیم را کاهش می‌دهد که برخلاف دلیلی که ما تست می‌کنیم عمل می‌کند. عملاً اینجاست که بسیاری از تیم‌ها تست را رها می‌کنند. + +تست ها فرصتی برای چیز دیگری هستند - یک دستیار دوستانه، کمک خلبان، که ارزش زیادی برای یک سرمایه گذاری کوچک ارائه می دهد. علم به ما می گوید که ما دو سیستم مغزی داریم: سیستم 1 برای فعالیت های بی دردسر مانند رانندگی ماشین در یک جاده خالی و سیستم 2 که برای عملیات پیچیده و آگاهانه مانند حل یک معادله ریاضی استفاده می شود. تست خود را برای سیستم 1 طراحی کنید، زمانی که به کد تست نگاه می کنید، باید به راحتی یک سند HTML را تغییر دهید، نه مانند حل 2X (17 × 24). + +این را می توان با تکنیک های انتخابی انتخاب گیلاس، ابزارها و اهداف آزمایشی که مقرون به صرفه هستند و ROI عالی ارائه می دهند، به دست آورد. فقط به اندازه نیاز تست کنید، سعی کنید آن را زیرک نگه دارید، گاهی اوقات حتی ارزش آن را دارد که برخی از تست ها را کنار بگذارید و قابلیت اطمینان را برای چابکی و سادگی معامله کنید. + +![alt text](/assets/headspace.png "We have no head room for additional complexity") + +بیشتر توصیه های زیر مشتقات این اصل است. + +### آماده برای شروع؟ + +

    + +# بخش 1: آناتومی تست + +
    + +## ⚪ ️ 1.1 شامل 3 قسمت در هر نام آزمون + +:white_check_mark: **انجام دادن:** یک گزارش آزمایشی باید بگوید که آیا بازبینی برنامه فعلی الزامات افرادی را که لزوماً با کد آشنا نیستند برآورده می کند: تست کننده ، مهندس DevOps که در حال استقرار است و شما آینده دو سال بعد. اگر آزمون ها در سطح الزامات صحبت کنند و شامل 3 بخش باشند، می توان به بهترین وجه به این امر دست یافت: + +(1) چه چیزی در حال آزمایش است؟ به عنوان مثال، متد ProductsService.addNewProduct + +(2) در چه شرایط و سناریویی؟ برای مثال هیچ قیمتی به متد داده نمی شود + +(3) نتیجه ی قابل انتظار چیست؟ به عنوان مثال، محصول جدید تایید نشده است + +
    + +❌ **در غیر این صورت:** یک استقرار به‌تازگی ناموفق بود، تست با نام «افزودن محصول» ناموفق بود. آیا این به شما می گوید که دقیقاً چه چیزی خراب است؟ + +
    + +**👇 توجه داشته باشید:** هر گلوله دارای نمونه کد و گاهی اوقات یک تصویر تصویری نیز می باشد. برای گسترش کلیک کنید +
    + +
    نمونه کد + +
    + +### :clap: مثال درست: نام تستی که از 3 قسمت تشکیل شده است + +![](https://img.shields.io/badge/🔨%20Example%20using%20Mocha-blue.svg "Using Mocha to illustrate the idea") + +```javascript +//1. واحد در حال تست +describe('خدمات محصولات', function() { + describe('افزودن محصول جدید', function() { + //2. سناریو و 3. انتظار + it('هنگامی که قیمتی مشخص نشده است، وضعیت محصول در انتظار تایید است', ()=> { + const newProduct = new ProductService().add(...); + expect(newProduct.status).to.equal('pendingApproval'); + }); + }); +}); + +``` + +
    + +### :clap: مثال درست: نام آزمایشی که از 3 قسمت تشکیل شده است + +![alt text](/assets/bp-1-3-parts.jpeg "A test name that constitutes 3 parts") + +
    + + +## ⚪ ️ 1.2 تست های ساختار با الگوی AAA + +:white_check_mark: **انجام دادن:** ساختار تست های خود را با 3 بخش به خوبی جدا شده مفدار دهی کنید، اجرا کنید و مقایسه کنید (AAA). پیروی از این ساختار تضمین می کند که خواننده هیچ CPU مغزی را برای درک برنامه آزمایشی خرج نمی کند: + +اول A - مفدار دادن: تمام کدهای راه اندازی برای رساندن سیستم به سناریویی که تست هدف آن شبیه سازی است. این ممکن است شامل نمونه سازی واحد در حال آزمایش سازنده، اضافه کردن رکوردهای DB، mocking/stubbing اشیا و هر کد آماده سازی دیگر باشد. + +دوم A - اجرا: واحد تحت تست را اجرا کنید. معمولا 1 خط کد + +سوم A - مفایسه: اطمینان حاصل کنید که ارزش دریافتی انتظارات را برآورده می کند. معمولا 1 خط کد + +
    + +❌ **در غیر این صورت:** نه تنها ساعت ها برای درک کد اصلی وقت می گذارید، بلکه چیزی که باید ساده ترین قسمت روز باشد (تست) مغز شما را کش می دهد. + +
    + +
    نمونه کد + +
    + +### :clap: مثال درست: تستی که با الگوی AAA ساختار یافته است + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +describe("طبقه بندی مشتری", () => { + test("هنگامی که مشتری بیش از 500 دلار هزینه کرد، باید به عنوان حق بیمه طبقه بندی شود", () => { + //مفدار دهی کردن + const customerToClassify = { spent: 505, joined: new Date(), id: 1 }; + const DBStub = sinon.stub(dataAccess, "getCustomer").reply({ id: 1, classification: "regular" }); + + //اجرا کردن + const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); + + //مفابسه کردن + expect(receivedClassification).toMatch("premium"); + }); +}); +``` + +
    + +### :thumbsdown: مثال ضد الگو: بدون جدایی، یک انبوه، سخت تر برای تفسیر + +```javascript +test("باید به عنوان حق بیمه طبقه بندی شود", () => { + const customerToClassify = { spent: 505, joined: new Date(), id: 1 }; + const DBStub = sinon.stub(dataAccess, "getCustomer").reply({ id: 1, classification: "regular" }); + const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); + expect(receivedClassification).toMatch("premium"); +}); +``` + +
    + +

    + +## ⚪ ️1.3 انتظارات را به زبان محصول توصیف کنید: از ادعاهای سبک BDD استفاده کنید + +:white_check_mark: **انجام دادن:** کدنویسی تست‌های خود به سبک بیانی به خواننده این امکان را می‌دهد تا بدون صرف حتی یک چرخه مغز - CPU، فوراً به نتیجه برسد. وقتی کدهای ضروری را می نویسید که مملو از منطق شرطی است، خواننده مجبور می شود چرخه های مغز - CPU بیشتری اعمال کند. در این صورت، انتظارات را به زبانی شبیه به انسان، به سبک BDD اعلانی با استفاده از «انتظار» یا «باید» و بدون استفاده از کد سفارشی کدنویسی کنید. اگر Chai & Jest شامل ادعای مورد نظر نیست و بسیار قابل تکرار است، در نظر بگیرید [extending Jest matcher (Jest)](https://jestjs.io/docs/en/expect#expectextendmatchers) یا نوشتن یک [پلاگین Chai سفارشی](https://www.chaijs.com/guide/plugins/) +
    + +❌ **در غیر این صورت:** تیم تست های کمتری می نویسد و تست های مزاحم را با .skip تزئین می کند() + +
    + +
    نمونه کد
    + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +### :thumbsdown: مثال ضد الگو: خواننده فقط برای دریافت داستان تستی که باید کدهای نه چندان کوتاه و ضروری را مرور کند. + +```javascript +test("هنگام درخواست ادمین، مطمئن شوید که در نتایج فقط مدیران سفارش داده شده هستند", () => { + //با فرض اینکه ما دو ادمین "admin1"، "admin2" و "user1" را به اینجا اضافه کرده ایم. + const allAdmins = getUsers({ adminOnly: true }); + + let admin1Found, + adming2Found = false; + + allAdmins.forEach(aSingleUser => { + if (aSingleUser === "user1") { + assert.notEqual(aSingleUser, "user1", "A user was found and not admin"); + } + if (aSingleUser === "admin1") { + admin1Found = true; + } + if (aSingleUser === "admin2") { + admin2Found = true; + } + }); + + if (!admin1Found || !admin2Found) { + throw new Error("Not all admins were returned"); + } +}); +``` + +
    + +### :clap: مثال درست: مرور تست اعلانی زیر یک نسیم است + +```javascript +it("When asking for an admin, ensure only ordered admins in results", () => { + //با فرض اینکه ما به اینجا دو ادمین اضافه کرده ایم + const allAdmins = getUsers({ adminOnly: true }); + + expect(allAdmins) + .to.include.ordered.members(["admin1", "admin2"]) + .but.not.include.ordered.members(["user1"]); +}); +``` + +
    + +

    + +## ⚪ ️ 1.4 به تست جعبه سیاه پایبند باشید: فقط متد های عمومی را آزمایش کنید + +:white_check_mark: **اتجام دادن:** آزمایش قطعات داخلی تقریباً هیچ هزینه زیادی را به همراه ندارد. اگر کد/API شما نتایج درستی را ارائه می‌دهد، آیا واقعاً باید 3 ساعت آینده خود را برای آزمایش نحوه عملکرد داخلی آن سرمایه‌گذاری کنید و سپس این تست‌های شکننده را حفظ کنید؟ هر زمان که یک رفتار عمومی بررسی می‌شود، پیاده‌سازی خصوصی نیز به طور ضمنی آزمایش می‌شود و آزمایش‌های شما تنها در صورت وجود مشکل خاصی (به عنوان مثال خروجی اشتباه) شکسته می‌شوند. این رویکرد به عنوان "آزمایش رفتار" نیز نامیده می شود. از طرف دیگر، اگر قطعات داخلی را آزمایش کنید (رویکرد جعبه سفید) - تمرکز شما از برنامه ریزی نتیجه کامپوننت به جزئیات دقیق تغییر می کند و ممکن است تست شما به دلیل اصلاح کننده های جزئی کد شکسته شود، اگرچه نتایج خوب هستند - این به طور چشمگیری تعمیر و نگهداری را افزایش می دهد. بار +
    + +❌ **در غیر این صورت:** تست های شما مانند [پسری هست که عین گرگ فریاد می زند](https://en.wikipedia.org/wiki/The_Boy_Who_Cried_Wolf): فریاد زدن با فریادهای مثبت کاذب (مثلاً، یک آزمایش به دلیل تغییر نام یک متغیر خصوصی ناموفق بود). جای تعجب نیست که مردم به زودی اعلان‌های CI را نادیده می‌گیرند تا اینکه روزی یک باگ واقعی نادیده گرفته شود… + +
    +
    نمونه کد + +
    + +### :thumbsdown: مثال ضد الگو: یک مورد تستی بدون هیچ دلیل موجهی قطعات داخلی را تست می کند + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") + +```javascript +class ProductService { + //این متذ فقط در داخل استفاده می شود + //تغییر این نام باعث می شود که آزمون ها با شکست مواجه شوند + calculateVATAdd(priceWithoutVAT) { + return { finalPrice: priceWithoutVAT * 1.2 }; + //تغییر فرمت نتیجه یا نام کلید بالا باعث شکست تست ها می شود + } + //متد عمومی + getPrice(productId) { + const desiredProduct = DB.getProduct(productId); + finalPrice = this.calculateVATAdd(desiredProduct.price).finalPrice; + return finalPrice; + } +} + +it("تست جعبه سفید: هنگامی که روش های داخلی 0 vat دریافت می کنند، 0 پاسخ می دهد", async () => { + //هیچ الزامی برای اجازه دادن به کاربران برای محاسبه مالیات بر ارزش افزوده وجود ندارد، فقط قیمت نهایی را نشان می دهد. با این وجود، ما به دروغ اصرار داریم که درونی کلاس را آزمایش کنیم + expect(new ProductService().calculateVATAdd(0).finalPrice).to.equal(0); +}); +``` + +
    + +

    + +## ⚪ ️ ️1.5 دو برابر تست مناسب را انتخاب کنید: از تمسخر به نفع خرد و جاسوس خودداری کنید + +:white_check_mark: **انجام دادن:** تست های دوبل یک شر ضروری هستند زیرا با اجزای داخلی برنامه همراه هستند، اما برخی از آنها ارزش بسیار زیادی را ارائه می دهند (
    [در اینجا یک یادآوری در مورد تست دوبل بخوانید: mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)). + +قبل از استفاده از تست دوبل، یک سوال بسیار ساده بپرسید: آیا از آن برای تست عملکردی که در سند الزامات ظاهر می شود یا می تواند ظاهر شود استفاده کنم؟ اگر نه، بوی تست جعبه سفید است. + +به عنوان مثال، اگر می‌خواهید آزمایش کنید که برنامه‌تان در هنگام قطع سرویس پرداخت، رفتار معقولی دارد، ممکن است سرویس پرداخت را خاموش کنید و مقداری «بدون پاسخ» را فعال کنید تا مطمئن شوید که واحد مورد آزمایش مقدار مناسب را برمی‌گرداند. این رفتار / پاسخ / نتیجه برنامه ما را تحت سناریوهای خاصی بررسی می کند. همچنین ممکن است از جاسوسی استفاده کنید تا ادعا کنید که ایمیلی زمانی ارسال شده است که آن سرویس از کار افتاده است———این دوباره یک بررسی رفتاری است که احتمالاً در سند الزامات ظاهر می‌شود («اگر پرداخت امکان ذخیره نشد» رایانامه ارسال کنید. از طرف دیگر، اگر سرویس پرداخت را مسخره می‌کنید و مطمئن می‌شوید که با انواع جاوا اسکریپت مناسب فراخوانی شده است — آزمایش شما روی چیزهای داخلی متمرکز است که هیچ ربطی به عملکرد برنامه ندارند و احتمالاً اغلب تغییر می‌کنند. +
    + +❌ **در غیر این صورت:** هر گونه بازسازي كد، جست و جوي تمامي ساختگي هاي موجود در كد و به روز كردن آن را الزامي مي كند. تست ها به جای یک دوست مفید تبدیل به یک بار می شوند + +
    + +
    نمونه کد + +
    + +### :thumbsdown: مثال ضد الگو: mock ها بر روی داخلی تمرکز می کنند + +![](https://img.shields.io/badge/🔧%20Example%20using%20Sinon-blue.svg "Examples with Sinon") + +```javascript +it("هنگامی که یک محصول معتبر در شرف حذف است، مطمئن شوید که DAL یک بار با محصول مناسب و پیکربندی مناسب تماس گرفته شده است.", async () => { + //فرض کنید قبلاً یک محصول اضافه کرده ایم + const dataAccessMock = sinon.mock(DAL); + //هومممم بد است: تست قطعات داخلی در واقع هدف اصلی ما در اینجا است، نه فقط یک side effect + dataAccessMock + .expects("deleteProduct") + .once() + .withArgs(DBConfig, theProductWeJustAdded, true, false); + new ProductService().deletePrice(theProductWeJustAdded); + dataAccessMock.verify(); +}); +``` + +
    + +### :clap:مثال درست: جاسوسان بر روی تست الزامات متمرکز هستند، اما به عنوان یک side effect، به طور اجتناب ناپذیری به درونی ها دست می زنند. + +```javascript +it("هنگامی که یک محصول معتبر در شرف حذف است، مطمئن شوید که یک ایمیل ارسال شده است", async () => { + //فرض کنید قبلاً یک محصول را در اینجا اضافه کرده ایم + const spy = sinon.spy(Emailer.prototype, "sendEmail"); + new ProductService().deletePrice(theProductWeJustAdded); + //هومممم خوب است: ما با داخلی سروکار داریم؟ بله، اما به عنوان یک side effect تست الزامات (ارسال ایمیل) + expect(spy.calledOnce).to.be.true; +}); +``` + +
    + +

    + +## 📗 آیا می خواهید همه این تمرین ها را با ویدیوی زنده یاد بگیرید؟ + +###از دوره آنلاین من دیدن کنید [Testing Node.js & JavaScript از A تا Z](https://www.testjavascript.com) + +

    + +## ⚪ ️1.6 «گول نزنید»، از داده های ورودی واقعی استفاده کنید + +:white_check_mark: **انجام دادن:** اغلب اشکالات تولید تحت برخی ورودی‌های بسیار خاص و شگفت‌انگیز آشکار می‌شوند— هرچه ورودی آزمایش واقعی‌تر باشد، شانس تشخیص زودهنگام باگ‌ها بیشتر می‌شود. از کتابخانه‌های اختصاصی مانند [Chance](https://github.com/chancejs/chancejs) یا [Faker](https://www.npmjs.com/package/faker) برای تولید داده‌های شبه واقعی که شبیه انواع و اقسام آن‌ها هستند، استفاده کنید. شکل داده های تولید به عنوان مثال، چنین کتابخانه‌هایی می‌توانند شماره تلفن، نام کاربری، کارت اعتباری، نام شرکت و حتی متن «lorem ipsum» واقعی را تولید کنند. همچنین می‌توانید آزمایش‌هایی (در بالای آزمایش‌های واحد، نه به عنوان جایگزین) ایجاد کنید که داده‌های جعلی را تصادفی می‌کند تا واحد شما تحت آزمایش کشیده شود یا حتی داده‌های واقعی را از محیط تولید شما وارد کند. می خواهید آن را به سطح بعدی ببرید؟ گلوله بعدی (تست مبتنی بر ویژگی) را ببینید. +
    + +❌ **در غیر این صورت:** وقتی از ورودی های مصنوعی مانند "Foo" استفاده می کنید، تمام آزمایش های توسعه شما به اشتباه سبز نشان داده می شوند، اما زمانی که هکر رشته بدی مانند "@3e2ddsf" را عبور می دهد، ممکن است تولید قرمز شود. ##' 1 fdsfds . fds432 AAAA” + +
    + +
    نمونه کد + +
    + +### :thumbsdown: مثال ضد الگو: مجموعه آزمایشی که به دلیل داده های غیرواقعی قبول می شود + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +const addProduct = (name, price) => { + const productNameRegexNoSpace = /^\S*$/; //space مجاز نیست + + if (!productNameRegexNoSpace.test(name)) return false; //این شرط به دلیل ورودی نادرست هرگز اجرا نمی شود + + //بقیه کد ها + return true; +}; + +test("اشتباه: هنگام افزودن محصول جدید با ویژگی های معتبر، تأیید موفقیت آمیز دریافت کنید", async () => { + //رشته "Foo" که در همه تست ها استفاده می شود، هرگز نتیجه نادرستی را ایجاد نمی کند + const addProductResult = addProduct("Foo", 5); + expect(addProductResult).toBe(true); + //مثبت-کاذب: عملیات موفقیت آمیز بود زیرا ما هرگز تلاش زیادی نکردیم + //نام محصول شامل فاصله ها +}); +``` + +
    + +### :clap:مثال درست:تصادفی سازی ورودی واقعی + +```javascript +it("بهتر: هنگام افزودن محصول معتبر جدید، تأیید موفقیت آمیز دریافت کنید", async () => { + const addProductResult = addProduct(faker.commerce.productName(), faker.random.number()); + //ورودی تصادفی ایجاد شده: {'Sleek Cotton Computer', 85481} + expect(addProductResult).to.be.true; + //تست ناموفق بود، ورودی تصادفی مسیری را آغاز کرد که ما هرگز برای آن برنامه ریزی نکرده بودیم. + //ما یک باگ را زود کشف کردیم! +}); +``` + +
    + +

    + +## ⚪ ️ 1.7 بسیاری از ترکیبات ورودی را با استفاده از تست مبتنی بر ویژگی تست کنید + +:white_check_mark: **انجام دادن:** معمولاً برای هر آزمون چند نمونه ورودی انتخاب می کنیم. حتی زمانی که قالب ورودی شبیه داده های دنیای واقعی باشد (به گلوله مراجعه کنید [‘گول نزن’](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F16-dont-foo-use-realistic-input-data)), ما فقط چند ترکیب ورودی را پوشش می‌دهیم (method(''، true، 1)، روش ("string"، false، 0))، با این حال، در تولید، یک API که با 5 پارامتر فراخوانی می شود را می توان با هزاران پارامتر مختلف فراخوانی کرد. جایگشت، یکی از آنها ممکن است فرآیند ما را پایین بیاورد ([تست فاز را ببینید](https://en.wikipedia.org/wiki/Fuzzing)). اگر بتوانید یک تست بنویسید که 1000 جایگشت از ورودی های مختلف را به طور خودکار ارسال می کند و کد ما برای کدام ورودی پاسخ مناسب را نمی دهد؟ تست مبتنی بر ویژگی تکنیکی است که دقیقاً همین کار را انجام می دهد: با ارسال تمام ترکیبات ورودی ممکن به واحد تحت آزمایش شما، مشکل یافتن یک باگ را افزایش می دهد. به عنوان مثال، با توجه به یک متد —  addNewProduct(id, name, isDiscount)—— کتابخانه های پشتیبانی کننده این متد را با ترکیب های زیادی از (عدد، رشته، بولی) مانند (1، "iPhone"، false)، (2، "Galaxy" فراخوانی می کنند. "، درست است، واقعی). شما می توانید تست مبتنی بر ویژگی را با استفاده از برنامه آزمایشی مورد علاقه خود (موکا، جست و غیره) با استفاده از کتابخانه هایی مانند [js-verify](https://github.com/jsverify/jsverify) یا [بررسی تست](https://github.com/leebyron/testcheck-js) (مستندات خیلی بهتر). به روز رسانی: Nicolas Dubien در نظرات زیر به[تسویه حساب سریع](https://github.com/dubzzz/fast-check#readme) که به نظر می رسد برخی از ویژگی های اضافی را ارائه می دهد و همچنین به طور فعال حفظ می شود +
    + +❌ **در غیر این صورت:** ناخودآگاه، ورودی‌های تست را انتخاب می‌کنید که فقط مسیرهای کدی را پوشش می‌دهند که به خوبی کار می‌کنند. متأسفانه، این کارایی تست را به عنوان وسیله ای برای افشای اشکالات کاهش می دهد + +
    + +
    نمونه کد + +
    + +### :clap: مثال درست: آزمایش بسیاری از جایگشت های ورودی با "بررسی سریع" + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +import fc from "fast-check"; + +describe("خدمات محصول", () => { + describe("افزودن جدید", () => { + //این 100 بار با ویژگی های تصادفی مختلف اجرا می شود + it("محصول جدید با ویژگی های تصادفی و در عین حال معتبر، همیشه موفق اضافه کنید", () => + fc.assert( + fc.property(fc.integer(), fc.string(), (id, name) => { + expect(addNewProduct(id, name).status).toEqual("approved"); + }) + )); + }); +}); +``` + +
    + +

    + +## ⚪ ️ 1.8 در صورت نیاز، فقط از snapshots کوتاه و درون خطی استفاده کنید + +:white_check_mark: **انجام دادن:** زمانی که نیاز باشد [snapshot تست کردن](https://jestjs.io/docs/en/snapshot-testing), فقط از عکس های فوری کوتاه و متمرکز استفاده کنید (i.e. 3-7 خط) که به عنوان بخشی از آزمون گنجانده شده است ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)) و نه در فایل های خارجی. رعایت این دستورالعمل تضمین می‌کند که تست‌های شما قابل توضیح و کمتر شکننده هستند. + +از سوی دیگر، آموزش‌ها و ابزارهای «snapshot کلاسیک»، ذخیره فایل‌های بزرگ (مانند نشانه‌گذاری رندر مؤلفه، نتیجه API JSON) را بر روی برخی رسانه‌های خارجی تشویق می‌کنند و اطمینان حاصل می‌کنند که هر بار هنگام اجرای تست، نتیجه دریافت‌شده با نسخه ذخیره‌شده مقایسه شود. برای مثال، این می تواند به طور ضمنی آزمون ما را به 1000 خط با 3000 مقدار داده که نویسنده آزمون هرگز نخوانده و درباره آن استدلال نکرده است، مرتبط کند. چرا این اشتباه است؟ با انجام این کار، 1000 دلیل برای شکست تست شما وجود دارد - کافی است یک خط تغییر کند تا snapshot نامعتبر شود و این احتمالاً زیاد اتفاق می افتد. چند بار؟ برای هر فضا، نظر یا تغییر جزئی CSS/HTML. نه تنها این، نام آزمون سرنخی در مورد شکست نمی دهد، زیرا فقط بررسی می کند که 1000 خط تغییر نکرده است، همچنین نویسنده آزمون را تشویق می کند که سند طولانی را که نمی تواند بررسی کند، به عنوان واقعی مورد نظر بپذیرد. تایید کنید. همه اینها علائم آزمون مبهم و مشتاق است که متمرکز نیست و هدف آن دستیابی به بیش از حد است + +شایان ذکر است که موارد کمی وجود دارد که snapshotهای طولانی و خارجی قابل قبول باشد - هنگام ادعا بر روی طرح و نه داده (استخراج مقادیر و تمرکز بر روی فیلدها) یا زمانی که سند دریافتی به ندرت تغییر می‌کند. +
    + +❌ **در غیر این صورت:** تست رابط کاربری ناموفق است. به نظر می رسد کد درست است، صفحه نمایش پیکسل های عالی را ارائه می دهد، چه اتفاقی افتاده است؟ تست snapshot شما تفاوتی بین سند مبدأ با سند دریافتی فعلی پیدا کرد - یک کاراکتر فاصله به علامت گذاری اضافه شد... + +
    + +
    نمونه کد + +
    + +### :thumbsdown: مثال ضد الگو: جفت کردن تست ما به 2000 خط کد + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +it("TestJavaScript.com به درستی ارائه شده است", () => { + //مفدار دهی کردن + + //اجرا کردن + const receivedPage = renderer + .create( Test JavaScript ) + .toJSON(); + + //مقایسه کردن + expect(receivedPage).toMatchSnapshot(); + //ما اکنون به طور ضمنی یک سند 2000 خطی را حفظ می کنیم + //هر شکست خط یا comment اضافی - این تست را شکسته خواهد کرد +}); +``` + +
    + +### :clap: مثال درست: انتظارات قابل مشاهده و متمرکز هستند + +```javascript +it("هنگام بازدید از صفحه اصلی TestJavaScript.com، یک منو نمایش داده می شود", () => { + //مفدار دهی کردن + + //اجرا کردن + const receivedPage = renderer + .create( Test JavaScript ) + .toJSON(); + + //مفایسه کردن + + const menu = receivedPage.content.menu; + expect(menu).toMatchInlineSnapshot(` +
      +
    • Home
    • +
    • About
    • +
    • Contact
    • +
    +`); +}); +``` + +
    + +

    + +## ⚪ ️کد را کپی کنید، اما فقط آنچه لازم است + +:white_check_mark: **انجام دادن:** تمام جزئیات لازم را که بر نتیجه آزمایش تأثیر می گذارد، وارد کنید، اما نه بیشتر. به عنوان مثال، تستی را در نظر بگیرید که باید 100 خط ورودی JSON را در نظر بگیرید - چسباندن آن در هر تست خسته کننده است. استخراج آن از خارج به transferFactory.getJSON() باعث می‌شود تست مبهم باقی بماند - بدون داده، ارتباط نتیجه آزمایش با علت دشوار است ("چرا قرار است وضعیت 400 را برگرداند؟"). کتاب کلاسیک الگوهای واحد x نام این الگو را «مهمان اسرارآمیز» گذاشتند -  چیزی نادیده بر نتایج آزمایش ما تأثیر گذاشت، ما دقیقاً نمی‌دانیم چه چیزی. ما می‌توانیم با استخراج قطعات طولانی قابل تکرار در خارج و به صراحت اشاره کنیم که کدام جزئیات خاص برای آزمایش مهم هستند، بهتر عمل کنیم. با استفاده از مثال بالا، آزمون می‌تواند پارامترهایی را پاس کند که آنچه مهم است را برجسته می‌کند: transferFactory.getJSON({sender: undefined}). در این مثال، خواننده باید فوراً استنباط کند که قسمت خالی فرستنده دلیلی است که آزمون باید منتظر خطای اعتبارسنجی یا هر نتیجه کافی مشابه دیگری باشد. +
    + +❌ **در غیر این صورت:** کپی کردن 500 خط JSON باعث می‌شود که تست‌های شما قابل نگهداری و خواندن نباشند. جابجایی همه چیز به بیرون با آزمون های مبهمی که درک آنها سخت است به پایان می رسد + +
    + +
    نمونه کد + +
    + +### :thumbsdown: مثال ضد الگو: شکست تست نامشخص است زیرا همه علت خارجی است و در JSON بزرگ پنهان می شود + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +test("وقتی اعتباری وجود ندارد، انتقال رد می شود", async() => { + // مفدار دهی کردن + const transferRequest = testHelpers.factorMoneyTransfer() //200 خط JSON را برگردانید. + const transferServiceUnderTest = new TransferService(); + + // اجرا کردن + const transferResponse = await transferServiceUnderTest.transfer(transferRequest); + + // مفایسه کردن + expect(transferResponse.status).toBe(409);// اما چرا ما انتظار شکست را داریم: به نظر می رسد همه در آزمون کاملاً معتبر هستند 🤔 + }); +``` + +
    + +### :clap: مثال درست: آزمایش نشان می دهد که علت نتیجه آزمایش چیست + +```javascript + +test("وقتی اعتباری وجود ندارد، انتقال رد می شود", async() => { + // مفدار دهی کردن + const transferRequest = testHelpers.factorMoneyTransfer({userCredit:100, transferAmount:200}) //بدیهی است که کمبود اعتبار وجود دارد + const transferServiceUnderTest = new TransferService({disallowOvercharge:true}); + + // اجرا کردن + const transferResponse = await transferServiceUnderTest.transfer(transferRequest); + + // مقایسه کردن + expect(transferResponse.status).toBe(409); //بدیهی است که اگر کاربر اعتباری نداشته باشد، باید شکست بخورد + }); + ``` + +
    + +

    + +## ⚪ ️ 1.10 اشتباهات را متوجه نشوید، منتظر آنها باشید + +:white_check_mark: **انجام دادن:** هنگامی که می‌خواهید ادعا کنید که برخی از ورودی‌ها باعث ایجاد خطا می‌شوند، ممکن است استفاده از try-catch-finally درست به نظر برسد و ادعا کند که بند catch وارد شده است. نتیجه یک مورد تست نامناسب و مفصل است (مثال زیر) که هدف آزمون ساده و انتظارات نتیجه را پنهان می کند. + +یک جایگزین زیباتر استفاده از ادعای اختصاصی Chai یک خطی است: expect(method).to.throw (یا در Jest: expect(method).toThrow()). کاملاً اجباری است که اطمینان حاصل شود که استثنا دارای خاصیتی است که نوع خطا را بیان می کند، در غیر این صورت با توجه به یک خطای عمومی، برنامه نمی تواند به جای نمایش یک پیام ناامیدکننده به کاربر، کار زیادی انجام دهد. +
    + +❌ **در غیر این صورت:** استنتاج از گزارش‌های آزمایشی (مثلاً گزارش‌های CI) چالش برانگیز خواهد بود + +
    + +
    نمونه کد + +
    + +### :thumbsdown: مثال ضد الگو: یک مورد تست طولانی که سعی می‌کند وجود خطا را با استفاده از آزمون تأیید کند. + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +it("هنگامی که نام محصول وجود ندارد، خطای 400 را نشان می دهد", async () => { + let errorWeExceptFor = null; + try { + const result = await addNewProduct({}); + } catch (error) { + expect(error.code).to.equal("InvalidInput"); + errorWeExceptFor = error; + } + expect(errorWeExceptFor).not.to.be.null; + //اگر این مقایسه ناموفق باشد، نتایج/گزارش‌های تست فقط نشان داده می‌شوند + //که مقداری تهی است، کلمه ای در مورد یک استثنا وجود نخواهد داشت +}); +``` + +
    + +### :clap: مثال درست: انتظاری قابل خواندن برای انسان که به راحتی قابل درک است، حتی ممکن است توسط QA یا PM فنی + +```javascript +it("هنگامی که نام محصول وجود ندارد، خطای 400 را نشان می دهد", async () => { + await expect(addNewProduct({})) + .to.eventually.throw(AppError) + .with.property("code", "InvalidInput"); +}); +``` + +
    + +

    + +## ⚪ ️ 1.11 تست های خود را تگ کنید + +:white_check_mark: **انجام دادن:** تست های مختلف باید در سناریوهای مختلف اجرا شوند: دود سریع، بدون IO، تست ها باید زمانی که یک توسعه‌دهنده فایلی را ذخیره یا متعهد می‌کند، اجرا می‌شوند، تست های کامل پایان به انتها معمولاً هنگام ارسال درخواست کشش جدید اجرا می‌شوند، و غیره. با برچسب گذاری تست ها با کلمات کلیدی مانند #cold #api #sanity تا بتوانید با مهار تست خود دست بگیرید و زیر مجموعه مورد نظر را فراخوانی کنید. برای مثال، به این صورت است که فقط گروه تست سلامت عقل را با موکا فرا می‌خوانید: mocha — grep ‘sanity’ +
    + +❌ **در غیر این صورت:** اجرای تمام تست‌ها، از جمله تست‌هایی که ده‌ها پرس‌وجو در DB را انجام می‌دهند، هر زمانی که یک توسعه‌دهنده یک تغییر کوچک ایجاد کند می‌تواند بسیار کند باشد و توسعه‌دهندگان را از اجرای تست ها دور نگه دارد. + +
    + +
    نمونه کد + +
    + +### :clap: مثال درست: برچسب گذاری تست ها به عنوان "#cold-test" به اجراکننده آزمون اجازه می دهد فقط تست های سریع را اجرا کند (تست های سرد===سریع که هیچ IO انجام نمی دهند و حتی زمانی که توسعه دهنده در حال تایپ کردن است می توانند مکررا اجرا شوند) + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +//این تست سریع است (بدون DB) و ما آن را مطابق با آن برچسب گذاری می کنیم +//اکنون کاربر/CI می تواند آن را به طور مکرر اجرا کند +describe("سفارش سرویس", function() { + describe("اضافه کردن سفارش جدید #تست سرد #عقل", function() { + test("سناریو - هیچ ارزی عرضه نشد. انتظار - از ارز پیش فرض #عقل استفاده کنید", function() { + //بقیه کدها + }); + }); +}); +``` + +
    + +

    + +## ⚪ ️ 1.12 تست ها را حداقل در 2 سطح دسته بندی کنید + +:white_check_mark: **انجام دادن:** ساختاری را در مجموعه آزمایشی خود اعمال کنید تا یک بازدیدکننده گاه به گاه بتواند به راحتی الزامات (آزمون ها بهترین مستندات هستند) و سناریوهای مختلفی که در حال آزمایش هستند را درک کند. یک روش متداول برای این کار قرار دادن حداقل 2 بلوک «توضیح» در بالای تست‌هایتان است: اولی برای نام واحد تحت آزمایش و دومی برای سطح اضافی طبقه‌بندی مانند سناریو یا دسته‌های سفارشی است (نمونه‌های کد را ببینید و چاپ کنید. صفحه زیر). انجام این کار گزارش‌های آزمون را نیز بسیار بهبود می‌بخشد: خواننده به راحتی دسته‌های تست‌ها را استنباط می‌کند، در بخش مورد نظر کاوش می‌کند و تست‌های مردودی را به هم مرتبط می‌کند. علاوه بر این، پیمایش کد یک مجموعه با آزمایش های زیاد برای یک توسعه دهنده بسیار آسان تر خواهد شد. چندین ساختار جایگزین برای مجموعه آزمایشی وجود دارد که می‌توانید آنها را مانند آنها در نظر بگیرید [داده شده-وقتی-پس](https://github.com/searls/jasmine-given) و [RITE](https://github.com/ericelliott/riteway) + +
    + +❌ **در غیر این صورت:** وقتی به گزارشی با فهرستی مسطح و طولانی از آزمون‌ها نگاه می‌کنیم، خواننده باید متن‌های طولانی را به طور کامل بخواند تا سناریوهای اصلی را نتیجه‌گیری کند و مشترکات رد شدن در آزمون‌ها را به هم مرتبط کند. مورد زیر را در نظر بگیرید: هنگامی که 7/100 تست شکست می خورند، نگاه کردن به یک لیست ثابت نیاز به خواندن متن تست های مردود دارد تا ببینید چگونه آنها با یکدیگر ارتباط دارند. با این حال، در یک گزارش سلسله مراتبی، همه آنها می توانند تحت یک جریان یا دسته باشند و خواننده به سرعت استنباط می کند که علت اصلی شکست چیست یا حداقل کجاست. + +
    + +
    نمونه کد + +
    + +### :clap: مثال درست: مجموعه ساختاری با نام واحد تحت آزمایش و سناریوها به گزارش مناسبی منجر می شود که در زیر نشان داده شده است. + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +// واحد در حال تست +describe("سرویس انتقال", () => { + //سناریو + describe("زمانی که اعتباری وجود ندارد", () => { + //انتظار + test("سپس وضعیت پاسخ باید کاهش یابد", () => {}); + + //انتظار + test("سپس باید برای مدیر ایمیل ارسال شود", () => {}); + }); +}); +``` + +![alt text](assets/hierarchical-report.png) + +
    + +### :thumbsdown: مثال ضد الگو: یک لیست مسطح از تست ها شناسایی داستان های کاربر و ارتباط بین تست های شکست خورده را برای خواننده سخت تر می کند. + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Mocha") + +```javascript +test("سپس وضعیت پاسخ باید کاهش یابد", () => {}); + +test("سپس باید ایمیل بفرستد", () => {}); + +test("در این صورت نباید سابقه نقل و انتقالات جدیدی وجود داشته باشد", () => {}); +``` + +![alt text](assets/flat-report.png) + +
    + +
    + +

    + +## ⚪ ️1.13 موارد دیگر برای نوشتن یک تست خوب + +:white_check_mark: **انجام دادن:** این پست روی توصیه‌های آزمایشی متمرکز شده است، یا حداقل می‌توان آن را با Node JS مثال زد. با این حال، این گلوله، چند نکته غیر مرتبط با Node را که به خوبی شناخته شده اند، گروه بندی می کند + +یاد بگیرید و تمرین کنید [TDD principles](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) آنها برای بسیاری بسیار ارزشمند هستند، اما اگر با سبک شما سازگاری ندارند، نترسید، شما تنها نیستید. تست ها را قبل از کد در بنویسید [red-green-refactor style](https://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html), اطمینان حاصل کنید که هر تست دقیقاً یک چیز را بررسی می کند، وقتی یک باگ پیدا کردید — قبل از رفع یک تست بنویسید که این اشکال را در آینده شناسایی کند، اجازه دهید هر تست حداقل یک بار قبل از سبز شدن شکست بخورد، با نوشتن یک کد سریع و ساده، یک ماژول را شروع کنید. آزمایش را برآورده می کند - سپس به تدریج اصلاح کنید و آن را به سطح درجه تولید ببرید، از هر گونه وابستگی به محیط (مسیرها، سیستم عامل و غیره) اجتناب کنید. +
    + +❌ **در غیر این صورت:** دلت برای مرواریدهای خردی که برای چندین دهه جمع آوری شده اند را از دست خواهید داد + +

    + +# Section 2️⃣: Backend تست کردن + +## ⚪ ️2.1 مجموعه تست خود را زیاد کنید: فراتر از Unit Test و هرم تست نرم افزار نگاه کنید + +:white_check_mark: **انجام دادن:** [تست کردن هرم](https://martinfowler.com/bliki/TestPyramid.html), اگرچه 10 سال سن دارد، اما یک مدل عالی و مرتبط است که سه نوع تست را پیشنهاد می کند و بر استراتژی تست اکثر توسعه دهندگان تأثیر می گذارد. در همان زمان، بیش از تعداد انگشت شماری از تکنیک‌های آزمایشی جدید براق ظاهر شدند و در سایه‌های هرم آزمایش پنهان شدند. با توجه به تمام تغییرات چشمگیری که در 10 سال اخیر دیده ایم (سرویس های میکرو، ابر، بدون سرور)، آیا حتی ممکن است یک مدل کاملاً قدیمی برای *همه* انواع برنامه ها مناسب باشد؟ آیا دنیای تست نباید از تکنیک های تست جدید استقبال کند؟ + +اشتباه نکنید، در سال 2019 تست هرم، تست TDD و واحد هنوز یک تکنیک قدرتمند هستند و احتمالاً بهترین تطابق برای بسیاری از برنامه ها هستند. فقط مانند هر مدل دیگری با وجود مفید بودن, [گاهی اوقات باید اشتباه باشد](https://en.wikipedia.org/wiki/All_models_are_wrong). به عنوان مثال، یک برنامه IoT را در نظر بگیرید که بسیاری از رویدادها را در یک گذرگاه پیام مانند Kafka/RabbitMQ وارد می‌کند، که سپس به انبار داده سرازیر می‌شود و در نهایت توسط برخی از رابط‌های تحلیلی پرس و جو می‌شود. آیا واقعاً باید 50 درصد از بودجه تست خود را صرف نوشتن آزمون های واحد برای برنامه ای کنیم که یکپارچه محور است و تقریباً هیچ منطقی ندارد؟ با افزایش تنوع انواع برنامه ها (ربات ها، کریپتو، مهارت های الکسا) شانس بیشتری برای یافتن سناریوهایی وجود دارد که در آن هرم آزمایشی بهترین تطابق نیست. + +وقت آن رسیده است که مجموعه آزمایشی خود را غنی کنید و با انواع تست های بیشتری آشنا شوید (گلوله های بعدی ایده های کمی را پیشنهاد می کنند)، مدل های ذهنی مانند هرم آزمایش، اما همچنین انواع آزمایش را با مشکلات دنیای واقعی که با آن مواجه هستید مطابقت دهید ('Hey, API ما خراب است، بیایید تست قرارداد مبتنی بر مصرف‌کننده بنویسیم!»)، آزمایش‌های خود را مانند سرمایه‌گذاری که سبد سهامی را بر اساس تجزیه و تحلیل ریسک می‌سازد، متنوع کنید— ارزیابی کنید که در کجا ممکن است مشکلات ایجاد شوند و با برخی از اقدامات پیشگیرانه برای کاهش خطرات احتمالی مطابقت دهید. + +یک کلمه احتیاط: استدلال TDD در دنیای نرم افزار یک چهره دوگانگی کاذب معمولی دارد، برخی موعظه می کنند که از آن در همه جا استفاده کنند، برخی دیگر فکر می کنند که این شیطان است. هر کس به طور مطلق صحبت می کند اشتباه می کند:] + +
    + +❌ **در غیر این صورت:** برخی از ابزارها با ROI شگفت انگیز را از دست خواهید داد، برخی مانند Fuzz، lint و جهش می توانند در 10 دقیقه ارزش ارائه دهند. + +
    + +
    نمونه کد + +
    + +### :clap: مثال درست: سیندی سریدهان یک نمونه کار آزمایشی غنی را در پست شگفت‌انگیز خود «تست کردن میکروسرویس‌ها» پیشنهاد می‌کند - به همین روش. + +![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") + +☺️Example: [YouTube: “Beyond Unit Tests: 5 Shiny Node.JS Test Types (2018)” (Yoni Goldberg)](https://www.youtube.com/watch?v=-2zP494wdUY&feature=youtu.be) + +
    + +![alt text](assets/bp-12-Yoni-Goldberg-Testing.jpeg "A test name that constitutes 3 parts") + +
    + +

    + +## ⚪ ️2.2 تست کامپوننت ممکن است بهترین کار شما باشد + +:white_check_mark: **انجام دادن:** هر Unit test بخش کوچکی از برنامه را پوشش می‌دهد و پوشش کل آن گران است، در حالی که تست E2E به راحتی زمین زیادی را پوشش می‌دهد، اما پوسته پوسته و کندتر است، چرا یک رویکرد متعادل را اعمال نکنیم و تست‌هایی بزرگ‌تر از آن بنویسیم. Unit tests اما کوچکتر از تست E2E؟ تست کامپوننت آهنگ ناخوانده دنیای آزمایش است— آنها بهترین ها را از هر دو دنیا ارائه می دهند: عملکرد معقول و امکان اعمال الگوهای TDD + پوشش واقعی و عالی. + +تست‌های کامپوننت روی «واحد» میکروسرویس تمرکز می‌کنند، آن‌ها بر خلاف API کار می‌کنند، هر چیزی را که متعلق به خود میکروسرویس است (مثلاً DB واقعی یا حداقل نسخه درون حافظه آن DB) را مسخره نمی‌کنند، اما هر چیزی را که خارجی است، خرد نمی‌کنند. مانند تماس با سایر میکروسرویس ها. با انجام این کار، آنچه را که به کار می‌گیریم آزمایش می‌کنیم، برنامه را از بیرون به داخل نزدیک می‌کنیم و در مدت زمان معقولی اعتماد به نفس بالایی به دست می‌آوریم. + +[ما یک راهنمای کامل داریم که صرفاً به نوشتن تست های مؤلفه به روش صحیح اختصاص دارد](https://github.com/testjavascript/nodejs-integration-tests-best-practices) + +
    + +❌ **در غیر این صورت:** ممکن است روزهای طولانی را صرف نوشتن Unit test کنید تا متوجه شوید که فقط 20 درصد پوشش سیستم را دارید + +
    + +
    نمونه کد + +
    + +### :clap: مقال درست: Supertest اجازه می دهد تا نزدیک شدن به Express API در فرآیند (سریع و پوشش چندین لایه) + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +![alt text](assets/bp-13-component-test-yoni-goldberg.png " [Supertest](https://www.npmjs.com/package/supertest) allows approaching Express API in-process (fast and cover many layers)") + +
    + +

    + +## ⚪ ️2.3 اطمینان حاصل کنید که نسخه‌های جدید نرم افزار , تست هایی که برای api ها نوشته شده است را خراب نمی‌کنند + +:white_check_mark: **انجام دادن:** بنابراین Microservice شما چندین مشتری دارد و شما چندین نسخه از این سرویس را به دلایل سازگاری اجرا می کنید (راضی نگه داشتن همه). سپس مقداری فیلد را تغییر می‌دهید و «بوم!»، مشتری مهمی که به این زمینه متکی است عصبانی است. این Catch-22 دنیای یکپارچه سازی است: برای طرف سرور بسیار چالش برانگیز است که تمام انتظارات مشتری چندگانه را در نظر بگیرد— از سوی دیگر، مشتریان نمی توانند هیچ آزمایشی را انجام دهند زیرا سرور تاریخ انتشار را کنترل می کند. طیفی از تکنیک‌ها وجود دارند که می‌توانند مشکل قرارداد را کاهش دهند، برخی ساده هستند، برخی دیگر دارای ویژگی‌های غنی‌تر هستند و منحنی یادگیری تندتری را طلب می‌کنند. در یک رویکرد ساده و توصیه‌شده، ارائه‌دهنده API بسته npm را با تایپ API منتشر می‌کند (مانند JSDoc، TypeScript). سپس مصرف کنندگان می توانند این کتابخانه را دریافت کنند و از زمان هوشمندانه و اعتبارسنجی بهره مند شوند. یک رویکرد شیک تر از آن برای استفاده [PACT](https://docs.pact.io/) که برای رسمی کردن این فرآیند با رویکردی بسیار مخرب متولد شده‌اند—— نه سرور برنامه آزمایشی را از خود تعریف می‌کند، بلکه مشتری آزمایش‌های سرور را تعریف می‌کند! PACT می‌تواند انتظارات مشتری را ثبت کند و در یک مکان مشترک، «کارگزار» قرار دهد، بنابراین سرور می‌تواند انتظارات را جمع‌آوری کند و با استفاده از کتابخانه PACT روی هر ساختنی اجرا کند تا قراردادهای شکسته را شناسایی کند - یک انتظار مشتری که برآورده نشده است. با انجام این کار، همه ناهماهنگی های API سرور-کلینت در مراحل اولیه ساخت/CI شناسایی می شوند و ممکن است شما را از ناامیدی زیادی نجات دهد. +
    + +❌ **در غیر این صورت:** گزینه های جایگزین تست دستی خسته کننده یا ترس از استقرار هستند + +
    + +
    نمونه کد + +
    + +### :clap: مقال درست: + +![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") + +![alt text](assets/bp-14-testing-best-practices-contract-flow.png) + +
    + +

    + +## ⚪ ️ 2.4 middleware خود را جداگانه تست کنید + +:white_check_mark: **انجام دادن:** بسیاری از تست Middleware اجتناب می کنند زیرا آنها بخش کوچکی از سیستم را نشان می دهند و به یک سرور Express زنده نیاز دارند. هر دو دلیل اشتباه هستند——Middleware ها کوچک هستند اما بر همه یا بیشتر درخواست ها تأثیر می گذارند و می توانند به راحتی به عنوان توابع خالصی که اشیاء JS {req,res} را دریافت می کنند آزمایش شوند. برای آزمایش عملکرد میان‌افزار، فقط باید آن را فراخوانی و جاسوسی کرد ([برای مثال از Sinon استفاده کنید](https://www.npmjs.com/package/sinon)) در تعامل با دو object {req,res} برای اطمینان از انجام عملکرد صحیح عملکرد. کتابخانه [node-mock-http](https://www.npmjs.com/package/node-mocks-http) آن را حتی فراتر می برد و دو object {req,res} را همراه با جاسوسی از رفتار آنها فاکتور می کند. به عنوان مثال، می تواند ادعا کند که آیا وضعیت http که روی شی res تنظیم شده است با انتظارات مطابقت دارد یا خیر (به مثال زیر مراجعه کنید). +
    + +❌ **در غیر این صورت:** یک اشکال در میان افزار Express === یک اشکال در همه یا اکثر request ها + +
    + +
    نمونه کد + +
    + +### :clap: مقال درست: تست middleware به‌صورت مجزا بدون برقراری تماس‌های شبکه و بیدار کردن کل دستگاه Express + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +//middleware که می خواهیم تست کنیم +const unitUnderTest = require("./middleware"); +const httpMocks = require("node-mocks-http"); +//Jest syntax, equivelant to describe() & it() in Mocha +test("درخواست بدون هدر احراز هویت، باید وضعیت http 403 را برگرداند", () => { + const request = httpMocks.createRequest({ + method: "GET", + url: "/user/42", + headers: { + authentication: "" + } + }); + const response = httpMocks.createResponse(); + unitUnderTest(request, response); + expect(response.statusCode).toBe(403); +}); +``` + +
    + +

    + +## ⚪ ️2.5 اندازه گیری و بازسازی با استفاده از ابزارهای تحلیل استاتیکی + +:white_check_mark: **انجام دادن:** استفاده از ابزارهای تجزیه و تحلیل استاتیک با ارائه روش های عینی برای بهبود کیفیت کد و حفظ کد شما کمک می کند. می‌توانید ابزارهای تجزیه و تحلیل استاتیک را به ساخت CI خود اضافه کنید تا زمانی که بوی کد پیدا می‌شود، لغو شود. نقاط اصلی فروش آن نسبت به پرده‌بندی ساده، توانایی بازرسی کیفیت در زمینه فایل‌های متعدد (به عنوان مثال شناسایی موارد تکراری)، انجام تجزیه و تحلیل پیشرفته (مانند پیچیدگی کد) و پیگیری تاریخچه و پیشرفت مشکلات کد است. دو نمونه از ابزارهایی که می توانید استفاده کنید عبارتند از [SonarQube](https://www.sonarqube.org/) (4,900+ [ستاره](https://github.com/SonarSource/sonarqube)) و [کد آب و هوا](https://codeclimate.com/) (2,000+ [ستاره](https://github.com/codeclimate/codeclimate)) + +سازنده: [Keith Holliday](https://github.com/TheHollidayInn) + +
    + +❌ **در غیر این صورت:** با کیفیت پایین کد، اشکالات و عملکرد همیشه مشکلی است که هیچ کتابخانه جدید و براق جدیدی نمی تواند آن را برطرف کند. + +
    + +
    نمونه کد + +
    + +### :clap: مقال درست: CodeClimate، یک ابزار تجاری است که می تواند متد های پیچیده را شناسایی کند: + +![](https://img.shields.io/badge/🔧%20Example%20using%20Code%20Climate-blue.svg "Examples with CodeClimate") + +![alt text](assets/bp-16-yoni-goldberg-quality.png "CodeClimate, a commercial tool that can identify complex methods:") + +
    + +

    + +## ⚪ ️ 2.6 آمادگی خود را برای هرج و مرج مرتبط با Node بررسی کنید + +:white_check_mark: **انجام دادن:** به طور عجیبی، اکثر تست‌های نرم‌افزار فقط در مورد منطق و داده‌ها هستند، اما برخی از بدترین چیزهایی که اتفاق می‌افتد (و واقعاً کاهش آن سخت است) مسائل زیرساختی است. به عنوان مثال، آیا تا به حال آزمایش کرده‌اید که چه اتفاقی می‌افتد وقتی حافظه پردازش شما بیش از حد بارگیری می‌شود، یا زمانی که سرور/فرآیند از بین می‌رود، یا آیا سیستم نظارت شما متوجه می‌شود که API 50٪ کندتر می‌شود؟ برای آزمایش و کاهش این نوع چیزهای بد——[مهندسی آشوب](https://principlesofchaos.org/) توسط نتفلیکس متولد شد. هدف آن ارائه آگاهی، چارچوب ها و ابزارهایی برای آزمایش انعطاف پذیری برنامه ما در برابر مسائل آشفته است. به عنوان مثال یکی از ابزارهای معروف آن، [میمون آشوب](https://github.com/Netflix/chaosmonkey), به طور تصادفی سرورها را می کشد تا اطمینان حاصل شود که سرویس ما همچنان می تواند به کاربران سرویس دهد و به یک سرور تکیه نمی کند (نسخه Kubernetes نیز وجود دارد، [میمون کوبه](https://github.com/asobti/kube-monkey), که غلاف ها را می کشد). همه این ابزارها در سطح میزبانی/پلتفرم کار می‌کنند، اما اگر می‌خواهید آشفتگی Node خالص را آزمایش و ایجاد کنید، چه می‌کنید، مانند بررسی اینکه چگونه فرآیند Node شما با خطاهای کشف نشده، رد کردن وعده‌های کنترل نشده، حافظه v8 بارگیری شده با حداکثر مجاز 1.7 گیگابایت یا اینکه آیا کنترل می‌شود چه می‌شود. زمانی که حلقه رویداد اغلب مسدود می شود، تجربه کاربری شما رضایت بخش باقی می ماند؟ برای پرداختن به این که نوشته ام، [node-chaos](https://github.com/i0natan/node-chaos-monkey) (alpha) که انواع اعمال آشفته مرتبط با Node را فراهم می کند +
    + +❌ **در غیر این صورت:** اینجا راه گریزی نیست، قانون مورفی بدون رحم به تولید شما ضربه می زند + +
    + +
    نمونه کد + +
    + +### :clap: مقال درست: : Node-chaos می‌تواند انواع شوخی‌های Node.js را ایجاد کند، بنابراین می‌توانید میزان انعطاف‌پذیری برنامه شما در برابر هرج و مرج را آزمایش کنید. + +![alt text](assets/bp-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") + +
    + +
    + +## ⚪ ️2.7 اجتناب از تجهیزات تست جهانی و دانه، اضافه کردن داده ها در هر آزمون + +:white_check_mark: **انجام دادن:** با توجه به قانون طلایی (گلوله 0)، هر تست باید مجموعه ای از ردیف های DB خود را اضافه کرده و روی آن عمل کند تا از جفت شدن جلوگیری کند و به راحتی در مورد جریان تست استدلال کند. در واقع، این امر اغلب توسط آزمایش‌کنندگانی که قبل از اجرای آزمایش‌ها (که به عنوان «تست فیکسچر» نیز شناخته می‌شود) را با داده‌ها به منظور بهبود عملکرد می‌دانند، نقض می‌شود. در حالی که عملکرد در واقع یک نگرانی معتبر است. عملاً، هر مورد آزمایشی را به صراحت سوابق DB مورد نیاز خود را اضافه کنید و فقط روی آن رکوردها عمل کنید. اگر عملکرد به یک نگرانی حیاتی تبدیل شود - یک مصالحه متوازن ممکن است به شکل کاشت تنها مجموعه آزمایش‌هایی باشد که داده‌ها را تغییر نمی‌دهند (مثلاً درخواست‌ها) +
    + +❌ **در غیر این صورت:** تعداد کمی از تست ها شکست می خورند، استقرار متوقف می شود، تیم ما اکنون زمان گرانبهایی را صرف می کند، آیا ما باگ داریم؟ بیایید بررسی کنیم، اوه نه—به نظر می‌رسد دو تست داده‌های اولیه مشابهی را جهش می‌دادند + +
    + +
    نمونه کد + +
    + +### :thumbsdown: مثال ضد الگو: تست‌ها مستقل نیستند و برای تغذیه داده‌های DB جهانی به چند قلاب جهانی متکی هستند. + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +before(async () => { + //افزودن سایت ها و داده های مدیران به DB ما. داده ها کجاست؟ خارج از. در برخی framework های json یا مهاجرت خارجی + await DB.AddSeedDataFromJson('seed.json'); +}); +it("هنگام به روز رسانی نام سایت، تأیید موفقیت آمیز دریافت کنید", async () => { + //من می دانم که نام سایت "portal" وجود دارد - آن را در فایل های seed دیدم + const siteToUpdate = await SiteService.getSiteByName("Portal"); + const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); + expect(updateNameResult).to.be(true); +}); +it("هنگام پرس و جو بر اساس نام سایت، سایت مناسب را دریافت کنید", async () => { + //من می دانم که نام سایت "portal" وجود دارد - آن را در فایل های seed دیدم + const siteToCheck = await SiteService.getSiteByName("Portal"); + expect(siteToCheck.name).to.be.equal("Portal"); //شکست! تست قبلی نام را تغییر دهید:[ +}); + +``` + +
    + +### :clap: مقال درست: ما می توانیم در آزمون بمانیم، هر آزمون بر اساس مجموعه داده های خود عمل می کند + +```javascript +it("هنگام به روز رسانی نام سایت، تأیید موفقیت آمیز دریافت کنید", async () => { + //تست اضافه کردن یک رکورد جدید جدید و عمل کردن فقط بر روی رکوردها است + const siteUnderTest = await SiteService.addSite({ + name: "siteForUpdateTest" + }); + const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); + expect(updateNameResult).to.be(true); +}); +``` + +
    + +
    + +## ⚪ ️2.8 یک استراتژی پاکسازی داده واضح انتخاب کنید: بعد از همه (توصیه می شود) یا بعد از هر کدام + +:white_check_mark: **انجام دادن:** زمانی که تست ها پایگاه داده را تمیز می کنند، نحوه نگارش تست ها را تعیین می کند. دو گزینه مناسب، تمیز کردن بعد از همه آزمایش ها در مقابل تمیز کردن بعد از هر آزمایش است. با انتخاب گزینه دوم، تمیز کردن پس از هر آزمایش جداول تمیز را تضمین می کند و مزایای آزمایشی راحت را برای توسعه دهنده ایجاد می کند. هیچ رکورد دیگری هنگام شروع آزمایش وجود ندارد، می توان مطمئن بود که کدام داده مورد پرسش قرار می گیرد و حتی ممکن است وسوسه شود ردیف ها را در طول ادعاها بشمارد. این امر با معایب شدیدی همراه است: هنگام اجرا در حالت چند فرآیندی، آزمایش‌ها احتمالاً با یکدیگر تداخل دارند. در حالی که process-1 جداول را پاک می کند، در همان لحظه پردازش-2 برای داده ها جستجو می کند و با شکست مواجه می شود (زیرا DB به طور ناگهانی توسط فرآیند-1 حذف شده است). علاوه بر این، عیب‌یابی تست‌های شکست خورده سخت‌تر است - بازدید از DB هیچ رکوردی را نشان نمی‌دهد. + +گزینه دوم این است که پس از اتمام تمام فایل های تست (یا حتی روزانه!) پاکسازی کنید. این رویکرد به این معنی است که همان DB با رکوردهای موجود، تمام تست ها و فرآیندها را ارائه می دهد. برای جلوگیری از پا گذاشتن روی انگشتان یکدیگر، آزمون ها باید سوابق خاصی را که اضافه کرده اند اضافه کرده و بر اساس آنها عمل کنند. آیا باید بررسی کنید که رکوردی اضافه شده است؟ فرض کنید هزاران رکورد و پرس و جوی دیگر برای رکوردهایی وجود دارد که به صراحت اضافه شده اند. آیا باید بررسی کنید که یک رکورد حذف شده است؟ نمی توان جدول خالی را فرض کرد، بررسی کنید که این رکورد خاص وجود ندارد. این تکنیک دستاوردهای قدرتمند کمی را به همراه دارد: زمانی که یک توسعه‌دهنده می‌خواهد اتفاقی را که رخ داده است بفهمد - به طور بومی در حالت چند فرآیندی کار می‌کند - داده‌ها آنجا هستند و حذف نمی‌شوند. همچنین شانس یافتن باگ ها را افزایش می دهد زیرا DB پر از رکورد است و به طور مصنوعی خالی نیست. [جدول مقایسه کامل را اینجا ببینید](https://github.com/testjavascript/nodejs-integration-tests-best-practices/blob/master/graphics/db-clean-options.png). +
    + +❌ **در غیر این صورت:** بدون استراتژی برای جدا کردن رکوردها یا تمیز کردن - تست ها روی انگشتان یکدیگر قرار می گیرند. استفاده از تراکنش‌ها فقط برای DB رابطه‌ای کار می‌کند و احتمالاً زمانی که تراکنش‌های درونی وجود دارد، پیچیده می‌شود + +
    + +
    نمونه کد + +
    + +### :clap: تمیز کردن بعد از تمام آزمایشات نه لزوما بعد از هر دویدن. هرچه داده‌های بیشتری در حین انجام آزمایش‌ها داشته باشیم - بیشتر شبیه امتیازات تولید است + +```javascript + //بعد از همه پاکسازی (توصیه می شود) +// global-teardown.js +module.exports = async () => { + // ... + if (Math.ceil(Math.random() * 10) === 10) { + await new OrderRepository().cleanup(); + } +}; +``` + +
    + +
    + +## ⚪ ️2.9 با استفاده از رهگیر HTTP، جزء را از جهان جدا کنید + +:white_check_mark: **انجام دادن:** مؤلفه تحت آزمایش را با رهگیری هر درخواست HTTP خروجی و ارائه پاسخ مورد نظر جدا کنید تا HTTP API همکار آسیب نبیند. Nock یک ابزار عالی برای این ماموریت است زیرا یک نحو مناسب برای تعریف رفتار خدمات خارجی ارائه می دهد. جداسازی برای جلوگیری از نویز و عملکرد آهسته ضروری است، اما بیشتر برای شبیه‌سازی سناریوها و پاسخ‌های مختلف - یک شبیه‌ساز پرواز خوب به معنای رنگ‌آمیزی آسمان آبی شفاف نیست، بلکه ایجاد طوفان و هرج‌ومرج امن است. این در معماری Microservice که در آن تمرکز همیشه باید بر روی یک جزء واحد بدون درگیر کردن بقیه جهان باشد، تقویت شده است. اگرچه می توان رفتار سرویس خارجی را با استفاده از تست دوبل (مسخره) شبیه سازی کرد، اما ترجیحاً کد مستقر شده را لمس نکنید و در سطح شبکه عمل کنید تا تست ها را جعبه سیاه خالص نگه دارید. نقطه ضعف جداسازی عدم تشخیص زمانی که مؤلفه همکار تغییر می کند و متوجه نشدن سوء تفاهم بین دو سرویس است - مطمئن شوید که با استفاده از چند آزمایش قرارداد یا E2E این را جبران کنید. +
    + +❌ **در غیر این صورت:** برخی از سرویس‌ها یک نسخه جعلی را ارائه می‌کنند که می‌تواند توسط تماس‌گیرنده به صورت محلی، معمولاً با استفاده از Docker اجرا شود. برخی از سرویس‌ها محیط «sandbox» را ارائه می‌کنند، بنابراین سرویس واقعی ضربه می‌خورد اما هیچ هزینه یا عوارض جانبی ایجاد نمی‌شود - این کار صدای راه‌اندازی سرویس شخص ثالث را کاهش می‌دهد، اما امکان شبیه‌سازی سناریوها را نیز فراهم نمی‌کند. + +
    + +
    نمونه کد + +
    + +### :clap: جلوگیری از تماس شبکه با اجزای خارجی امکان شبیه سازی سناریوها و به حداقل رساندن نویز را فراهم می کند + +```javascript +// درخواست های API های شخص ثالث را رهگیری کنید و یک پاسخ از پیش تعریف شده را برگردانید +beforeEach(() => { + nock('http://localhost/user/').get(`/1`).reply(200, { + id: 1, + name: 'John', + }); +}); +``` + +
    + +## ⚪ ️2.10 طرح پاسخ را بیشتر در مواقعی که فیلدهای تولید خودکار وجود دارد، آزمایش کنید + +:white_check_mark: **انجام دادن:** هنگامی که ادعا کردن برای داده های خاص غیرممکن است، وجود و انواع فیلد اجباری را بررسی کنید. گاهی اوقات، پاسخ حاوی فیلدهای مهم با داده های پویا است که نمی توان آنها را هنگام نوشتن آزمون پیش بینی کرد، مانند تاریخ ها و افزایش اعداد. اگر قرارداد API وعده می دهد که این فیلدها پوچ نخواهند بود و انواع مناسب را در خود دارند، آزمایش آن ضروری است. اکثر کتابخانه های ادعا از انواع بررسی پشتیبانی می کنند. اگر پاسخ کوچک است، داده های برگشتی را بررسی کنید و با هم در همان ادعا تایپ کنید (به مثال کد مراجعه کنید). یک گزینه دیگر این است که کل پاسخ را در برابر یک سند OpenAPI (Swagger) تأیید کنید. اکثر اجراکنندگان آزمایش دارای پسوندهای جامعه هستند که پاسخ های API را در برابر اسناد آنها تأیید می کند. + + +
    + +❌ **در غیر این صورت:** اگرچه تماس‌گیرنده کد/API به فیلدهایی با داده‌های پویا (مثلاً شناسه، تاریخ) متکی است، اما در عوض نمی‌آید و قرارداد را زیر پا نمی‌گذارد. + +
    + +
    نمونه کد + +
    + +### :clap: با بیان اینکه فیلدهایی با مقدار پویا وجود دارند و نوع مناسبی دارند + +```javascript + test('هنگام اضافه کردن یک سفارش معتبر جدید، سپس باید با 200 پاسخ تأیید مجدد دریافت کنید', async () => { + // ... + //مقایسه کردن + expect(receivedAPIResponse).toMatchObject({ + status: 200, + data: { + id: expect.any(Number), // هر عددی این تست را برآورده می کند + mode: 'approved', + }, + }); +}); +``` + +
    + +
    + +## ⚪ ️2.12 موارد گوشه و آشوب ادغام ها را بررسی کنید + +:white_check_mark: **انجام دادن:** هنگام بررسی ادغام ها، از مسیرهای شاد و غم انگیز فراتر بروید. نه تنها پاسخ های خطا (به عنوان مثال، خطای HTTP 500) بلکه ناهنجاری های سطح شبکه مانند پاسخ های آهسته و به پایان رسیده را بررسی کنید. این ثابت می‌کند که کد انعطاف‌پذیر است و می‌تواند سناریوهای مختلف شبکه را مدیریت کند، مانند انتخاب مسیر درست پس از یک بازه زمانی، هیچ شرایط مسابقه شکننده‌ای ندارد، و حاوی یک قطع کننده مدار برای تلاش‌های مجدد است. ابزارهای رهگیر معتبر به راحتی می توانند رفتارهای مختلف شبکه مانند سرویس های گیج کننده را که گهگاه با شکست مواجه می شوند شبیه سازی کنند. حتی می‌تواند متوجه شود که چه زمانی مقدار زمان‌بندی پیش‌فرض مشتری HTTP از زمان پاسخ شبیه‌سازی‌شده بیشتر است و فوراً بدون انتظار، یک استثنای مهلت زمانی ایجاد کند. + + +
    + +❌ **در عیر این صورت:** تمام تست‌های شما با موفقیت انجام می‌شود، این فقط تولید است که از کار می‌افتد یا وقتی شخص ثالث پاسخ‌های استثنایی ارسال می‌کند، خطاها را به درستی گزارش نمی‌کند. + +
    + +
    نمونه کد + +
    + +### :clap: اطمینان از اینکه در خرابی شبکه، قطع کننده مدار می تواند روز را نجات دهد + +```javascript + test('هنگامی که سرویس کاربران یک بار با 503 پاسخ می دهد و مکانیسم امتحان مجدد اعمال می شود، سفارش با موفقیت اضافه می شود', async () => { + //مفدار دهی کردن + nock.removeInterceptor(userServiceNock.interceptors[0]) + nock('http://localhost/user/') + .get('/1') + .reply(503, undefined, { 'Retry-After': 100 }); + nock('http://localhost/user/') + .get('/1') + .reply(200); + const orderToAdd = { + userId: 1, + productId: 2, + mode: 'approved', + }; + + //اجرا کردن + const response = await axiosAPIClient.post('/order', orderToAdd); + + //مقایسه کردن + expect(response.status).toBe(200); +}); +``` + +
    + +
    + + +## ⚪ ️2.13 پنج نتیجه بالقوه را تست کنید + +:white_check_mark: **انجام دادن:** هنگام برنامه ریزی آزمایشات خود، پنج خروجی جریان معمولی را پوشش دهید. هنگامی که آزمایش شما در حال انجام برخی اقدامات است (به عنوان مثال، فراخوانی API)، واکنشی در حال رخ دادن است، چیزی معنادار رخ می دهد و نیاز به آزمایش دارد. توجه داشته باشید که ما به نحوه کار کردن اهمیت نمی دهیم. تمرکز ما روی نتایج است، چیزهایی که از بیرون قابل توجه هستند و ممکن است بر کاربر تأثیر بگذارند. این پیامدها/واکنش ها را می توان در 5 دسته قرار داد: + +• نتیحه - تست یک عمل را فراخوانی می کند (به عنوان مثال، از طریق API) و یک پاسخ دریافت می کند. اکنون به بررسی صحت داده های پاسخ، طرح و وضعیت HTTP می پردازد + +• state جدید - پس از فراخوانی یک عمل، برخی از داده‌های **در دسترس عموم** احتمالاً اصلاح می‌شوند + +• تماس های داخلی - پس از فراخوانی یک عمل، برنامه ممکن است یک مؤلفه خارجی را از طریق HTTP یا هر انتقال دیگر فراخوانی کند. به عنوان مثال، تماس برای ارسال پیامک، ایمیل یا شارژ کارت اعتباری + +• صفی از پیام ها - نتیجه یک جریان ممکن است یک پیام در یک صف باشد + +• قابلیت مشاهده - برخی از چیزها مانند خطاها یا رویدادهای تجاری قابل توجه باید نظارت شوند. هنگامی که یک تراکنش با شکست مواجه می شود، نه تنها ما انتظار پاسخ مناسب را داریم، بلکه مدیریت صحیح خطا و ثبت/سنجه های مناسب را نیز انتظار داریم. این اطلاعات مستقیماً به یک کاربر بسیار مهم می رود - کاربر ops (یعنی تولید SRE/admin) + + +

    + +# Section 3️⃣: Frontend Testing + +## ⚪ ️ 3.1 Separate UI from functionality + +: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/CSS 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 + +
    + +❌ **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 + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Separating out the UI details + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +test("When users-list is flagged to show only VIP, should display only VIP members", () => { + // Arrange + const allUsers = [{ id: 1, name: "Yoni Goldberg", vip: false }, { id: 2, name: "John Doe", vip: true }]; + + // Act + const { getAllByTestId } = render(); + + // Assert - Extract the data from the UI first + const allRenderedUsers = getAllByTestId("user").map(uiElement => uiElement.textContent); + const allRealVIPUsers = allUsers.filter(user => user.vip).map(user => user.name); + expect(allRenderedUsers).toEqual(allRealVIPUsers); //compare data with data, no UI here +}); +``` + +
    + +### :thumbsdown: Anti-Pattern Example: Assertion mix UI details and data + +```javascript +test("When flagging to show only VIP, should display only VIP members", () => { + // Arrange + const allUsers = [{ id: 1, name: "Yoni Goldberg", vip: false }, { id: 2, name: "John Doe", vip: true }]; + + // Act + const { getAllByTestId } = render(); + + // Assert - Mix UI & data in assertion + expect(getAllByTestId("user")).toEqual('[
  • John Doe
  • ]'); +}); +``` + +
    + +

    + +## ⚪ ️ 3.2 Query HTML elements based on attributes that are unlikely to change + +: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/logic 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 + +
    + +❌ **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' + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Querying an element using a dedicated attribute for testing + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") + +```html +// the markup code (part of React component) +

    + + {value} + + +

    +``` + +```javascript +// this example is using react-testing-library +test("Whenever no data is passed to metric, show 0 as default", () => { + // Arrange + const metricValue = undefined; + + // Act + const { getByTestId } = render(); + + expect(getByTestId("errorsLabel").text()).toBe("0"); +}); +``` + +
    + +### :thumbsdown: Anti-Pattern Example: Relying on CSS attributes + +```html + +{value} + +``` + +```javascript +// this exammple is using enzyme +test("Whenever no data is passed, error metric shows zero", () => { + // ... + + expect(wrapper.find("[className='d-flex-column']").text()).toBe("0"); +}); +``` + +
    + +
    + +## ⚪ ️ 3.3 Whenever possible, test with a realistic and fully rendered component + +: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://github.com/goldbergyoni/javascript-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 + +With all that said, a word of caution is in order: this technique works for small/medium 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 + +
    + +❌ **Otherwise:** When poking into a component's internal by invoking its private methods, and checking the inner state - you would have to refactor all tests when refactoring the components implementation. Do you really have a capacity for this level of maintenance? + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Working realistically with a fully rendered component + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Enzyme-blue.svg "Examples with Enzyme") + +```javascript +class Calendar extends React.Component { + static defaultProps = { showFilters: false }; + + render() { + return ( +
    + A filters panel with a button to hide/show filters + +
    + ); + } +} + +//Examples use React & Enzyme +test("Realistic approach: When clicked to show filters, filters are displayed", () => { + // Arrange + const wrapper = mount(); + + // Act + wrapper.find("button").simulate("click"); + + // Assert + expect(wrapper.text().includes("Choose Filter")); + // This is how the user will approach this element: by text +}); +``` + +### :thumbsdown: Anti-Pattern Example: Mocking the reality with shallow rendering + +```javascript +test("Shallow/mocked approach: When clicked to show filters, filters are displayed", () => { + // Arrange + const wrapper = shallow(); + + // Act + wrapper + .find("filtersPanel") + .instance() + .showFilters(); + // Tap into the internals, bypass the UI and invoke a method. White-box approach + + // Assert + expect(wrapper.find("Filter").props()).toEqual({ title: "Choose Filter" }); + // what if we change the prop name or don't pass anything relevant? +}); +``` + +
    + +
    + +## ⚪ ️ 3.4 Don't sleep, use frameworks built-in support for async events. Also try to speed things up + +:white_check_mark: **Do:** In many cases, the unit under test completion time is just unknown (e.g. animation suspends element appearance) - in that case, avoid sleeping (e.g. setTimeOut) and prefer more deterministic methods that most platforms provide. Some libraries allows awaiting on operations (e.g. [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), other provide API for waiting like [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). Sometimes a more elegant way is to stub the slow resource, like API for example, and then once the response moment becomes deterministic the component can be explicitly re-rendered. When depending upon some external component that sleeps, it might turn useful to [hurry-up the clock](https://jestjs.io/docs/en/timer-mocks). Sleeping is a pattern to avoid because it forces your test to be slow or risky (when waiting for a too short period). Whenever sleeping and polling is inevitable and there's no support from the testing framework, some npm libraries like [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) can help with a semi-deterministic solution +
    + +❌ **Otherwise:** When sleeping for a long time, tests will be an order of magnitude slower. When trying to sleep for small numbers, test will fail when the unit under test didn't respond in a timely fashion. So it boils down to a trade-off between flakiness and bad performance + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: E2E API that resolves only when the async operations is done (Cypress) + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") +![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +// using Cypress +cy.get("#show-products").click(); // navigate +cy.wait("@products"); // wait for route to appear +// this line will get executed only when the route is ready +``` + +### :clap: Doing It Right Example: Testing library that waits for DOM elements + +```javascript +// @testing-library/dom +test("movie title appears", async () => { + // element is initially not present... + + // wait for appearance + await wait(() => { + expect(getByText("the lion king")).toBeInTheDocument(); + }); + + // wait for appearance and return the element + const movie = await waitForElement(() => getByText("the lion king")); +}); +``` + +### :thumbsdown: Anti-Pattern Example: custom sleep code + +```javascript +test("movie title appears", async () => { + // element is initially not present... + + // custom wait logic (caution: simplistic, no timeout) + const interval = setInterval(() => { + const found = getByText("the lion king"); + if (found) { + clearInterval(interval); + expect(getByText("the lion king")).toBeInTheDocument(); + } + }, 100); + + // wait for appearance and return the element + const movie = await waitForElement(() => getByText("the lion king")); +}); +``` + +
    + +
    + +## ⚪ ️ 3.5 Watch how the content is served over the network + +![](https://img.shields.io/badge/🔧%20Example%20using%20Google%20LightHouse-blue.svg "Examples with Lighthouse") + +✅ **Do:** Apply some active monitor that ensures the page load under real network is optimized - this includes any UX concern like slow page load or un-minified bundle. The inspection tools market is no short: basic tools like [pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) can be easily configured to watch whether the server is alive and response under a reasonable SLA. This only scratches the surface of what might get wrong, hence it's preferable to opt for tools that specialize in frontend (e.g. [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) and perform richer analysis. The focus should be on symptoms, metrics that directly affect the UX, like page load time, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [time until the page gets interactive (TTI)](https://calibreapp.com/blog/time-to-interactive/). On top of that, one may also watch for technical causes like ensuring the content is compressed, time to the first byte, optimize images, ensuring reasonable DOM size, SSL and many others. It's advisable to have these rich monitors both during development, as part of the CI and most important - 24x7 over the production's servers/CDN + +
    + +❌ **Otherwise:** It must be disappointing to realize that after such great care for crafting a UI, 100% functional tests passing and sophisticated bundling - the UX is horrible and slow due to CDN misconfiguration + +
    + +
    Code Examples + +### :clap: Doing It Right Example: Lighthouse page load inspection report + +![](/assets/lighthouse2.png "Lighthouse page load inspection report") + +
    + +
    + +## ⚪ ️ 3.6 Stub flaky and slow resources like backend APIs + +:white_check_mark: **Do:** When coding your mainstream tests (not E2E tests), avoid involving any resource that is beyond your responsibility and control like backend API and use stubs instead (i.e. test double). Practically, instead of real network calls to APIs, use some test double library (like [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble), etc) for stubbing the API response. The main benefit is preventing flakiness - testing or staging APIs by definition are not highly stable and from time to time will fail your tests although YOUR component behaves just fine (production env was not meant for testing and it usually throttles requests). Doing this will allow simulating various API behavior that should drive your component behavior as when no data was found or the case when API throws an error. Last but not least, network calls will greatly slow down the tests + +
    + +❌ **Otherwise:** The average test runs no longer than few ms, a typical API call last 100ms>, this makes each test ~20x slower + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Stubbing or intercepting API calls + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +// unit under test +export default function ProductsList() { + const [products, setProducts] = useState(false); + + const fetchProducts = async () => { + const products = await axios.get("api/products"); + setProducts(products); + }; + + useEffect(() => { + fetchProducts(); + }, []); + + return products ?
    {products}
    :
    No products
    ; +} + +// test +test("When no products exist, show the appropriate message", () => { + // Arrange + nock("api") + .get(`/products`) + .reply(404); + + // Act + const { getByTestId } = render(); + + // Assert + expect(getByTestId("no-products-message")).toBeTruthy(); +}); +``` + +
    + +
    + +## ⚪ ️ 3.7 Have very few end-to-end tests that spans the whole system + +:white_check_mark: **Do:** Although E2E (end-to-end) usually means UI-only testing with a real browser (See [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)), for other they mean tests that stretch the entire system including the real backend. The latter type of tests is highly valuable as they cover integration bugs between frontend and backend that might happen due to a wrong understanding of the exchange schema. They are also an efficient method to discover backend-to-backend integration issues (e.g. Microservice A sends the wrong message to Microservice B) and even to detect deployment failures - there are no backend frameworks for E2E testing that are as friendly and mature as UI frameworks like [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). The downside of such tests is the high cost of configuring an environment with so many components, and mostly their brittleness - given 50 microservices, even if one fails then the entire E2E just failed. For that reason, we should use this technique sparingly and probably have 1-10 of those and no more. That said, even a small number of E2E tests are likely to catch the type of issues they are targeted for - deployment & integration faults. It's advisable to run those over a production-like staging environment + +
    + +❌ **Otherwise:** UI might invest much in testing its functionality only to realizes very late that the backend returned payload (the data schema the UI has to work with) is very different than expected + +
    + +## ⚪ ️ 3.8 Speed-up E2E tests by reusing login credentials + +:white_check_mark: **Do:** In E2E tests that involve a real backend and rely on a valid user token for API calls, it doesn't payoff to isolate the test to a level where a user is created and logged-in in every request. Instead, login only once before the tests execution start (i.e. before-all hook), save the token in some local storage and reuse it across requests. This seem to violate one of the core testing principle - keep the test autonomous without resources coupling. While this is a valid worry, in E2E tests performance is a key concern and creating 1-3 API requests before starting each individual tests might lead to horrible execution time. Reusing credentials doesn't mean the tests have to act on the same user records - if relying on user records (e.g. test user payments history) than make sure to generate those records as part of the test and avoid sharing their existence with other tests. Also remember that the backend can be faked - if your tests are focused on the frontend it might be better to isolate it and stub the backend API (see [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)). + +
    + +❌ **Otherwise:** Given 200 test cases and assuming login=100ms = 20 seconds only for logging-in again and again + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Logging-in before-all and not before-each + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +let authenticationToken; + +// happens before ALL tests run +before(() => { + cy.request('POST', 'http://localhost:3000/login', { + username: Cypress.env('username'), + password: Cypress.env('password'), + }) + .its('body') + .then((responseFromLogin) => { + authenticationToken = responseFromLogin.token; + }) +}) + +// happens before EACH test +beforeEach(setUser => { + cy.visit('/home', () => { + onBeforeLoad (win => { + win.localStorage.setItem('token', JSON.stringify(authenticationToken)) + }) + }) +}) +``` + +
    + +
    + +## ⚪ ️ 3.9 Have one E2E smoke test that just travels across the site map + +:white_check_mark: **Do:** For production monitoring and development-time sanity check, run a single E2E test that visits all/most of the site pages and ensures no one breaks. This type of test brings a great return on investment as it's very easy to write and maintain, but it can detect any kind of failure including functional, network and deployment issues. Other styles of smoke and sanity checking are not as reliable and exhaustive - some ops teams just ping the home page (production) or developers who run many integration tests which don't discover packaging and browser issues. Goes without saying that the smoke test doesn't replace functional tests rather just aim to serve as a quick smoke detector + +
    + +❌ **Otherwise:** Everything might seem perfect, all tests pass, production health-check is also positive but the Payment component had some packaging issue and only the /Payment route is not rendering + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Smoke travelling across all pages + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +it("When doing smoke testing over all page, should load them all successfully", () => { + // exemplified using Cypress but can be implemented easily + // using any E2E suite + cy.visit("https://mysite.com/home"); + cy.contains("Home"); + cy.visit("https://mysite.com/Login"); + cy.contains("Login"); + cy.visit("https://mysite.com/About"); + cy.contains("About"); +}); +``` + +
    + +
    + +## ⚪ ️ 3.10 Expose the tests as a live collaborative document + +:white_check_mark: **Do:** Besides increasing app reliability, tests bring another attractive opportunity to the table - serve as live app documentation. Since tests inherently speak at a less-technical and product/UX language, using the right tools they can serve as a communication artifact that greatly aligns all the peers - developers and their customers. For example, some frameworks allow expressing the flow and expectations (i.e. tests plan) using a human-readable language so any stakeholder, including product managers, can read, approve and collaborate on the tests which just became the live requirements document. This technique is also being referred to as 'acceptance test' as it allows the customer to define his acceptance criteria in plain language. This is [BDD (behavior-driven testing)](https://en.wikipedia.org/wiki/Behavior-driven_development) at its purest form. One of the popular frameworks that enable this is [Cucumber which has a JavaScript flavor](https://github.com/cucumber/cucumber-js), see example below. Another similar yet different opportunity, [StoryBook](https://storybook.js.org/), allows exposing UI components as a graphic catalog where one can walk through the various states of each component (e.g. render a grid w/o filters, render that grid with multiple rows or with none, etc), see how it looks like, and how to trigger that state - this can appeal also to product folks but mostly serves as live doc for developers who consume those components. + +❌ **Otherwise:** After investing top resources on testing, it's just a pity not to leverage this investment and win great value + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Describing tests in human-language using cucumber-js + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Examples using Cucumber") + +```text +This is how one can describe tests using cucumber: plain language that allows anyone to understand and collaborate + +Feature: Twitter new tweet + + I want to tweet something in Twitter + + @focus + Scenario: Tweeting from the home page + Given I open Twitter home + Given I click on "New tweet" button + Given I type "Hello followers!" in the textbox + Given I click on "Submit" button + Then I see message "Tweet saved" +``` + +### :clap: Doing It Right Example: Visualizing our components, their various states and inputs using Storybook + +![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") + +![alt text](assets/story-book.jpg "Storybook") + +
    + +

    + +## ⚪ ️ 3.11 Detect visual issues with automated tools + +:white_check_mark: **Do:** Setup automated tools to capture UI screenshots when changes are presented and detect visual issues like content overlapping or breaking. This ensures that not only the right data is prepared but also the user can conveniently see it. This technique is not widely adopted, our testing mindset leans toward functional tests but it's the visuals what the user experience and with so many device types it's very easy to overlook some nasty UI bug. Some free tools can provide the basics - generate and save screenshots for the inspection of human eyes. While this approach might be sufficient for small apps, it's flawed as any other manual testing that demands human labor anytime something changes. On the other hand, it's quite challenging to detect UI issues automatically due to the lack of clear definition - this is where the field of 'Visual Regression' chime in and solve this puzzle by comparing old UI with the latest changes and detect differences. Some OSS/free tools can provide some of this functionality (e.g. [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>) but might charge significant setup time. The commercial line of tools (e.g. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) takes is a step further by smoothing the installation and packing advanced features like management UI, alerting, smart capturing by eliminating 'visual noise' (e.g. ads, animations) and even root cause analysis of the DOM/CSS changes that led to the issue + +
    + +❌ **Otherwise:** How good is a content page that display great content (100% tests passed), loads instantly but half of the content area is hidden? + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: A typical visual regression - right content that is served badly + +![alt text](assets/amazon-visual-regression.jpeg "Amazon page breaks") + +
    + +### :clap: Doing It Right Example: Configuring wraith to capture and compare UI snapshots + +![](https://img.shields.io/badge/🔨%20Example%20using%20Wraith-blue.svg "Using Wraith") + +``` +​# Add as many domains as necessary. Key will act as a label​ + +domains: + english: "http://www.mysite.com"​ + +​# Type screen widths below, here are a couple of examples​ + +screen_widths: + + - 600​ + - 768​ + - 1024​ + - 1280​ + +​# Type page URL paths below, here are a couple of examples​ +paths: + about: + path: /about + selector: '.about'​ + subscribe: + selector: '.subscribe'​ + path: /subscribe +``` + +### :clap: Doing It Right Example: Using Applitools to get snapshot comparison and other advanced features + +![](https://img.shields.io/badge/🔨%20Example%20using%20AppliTools-blue.svg "Using Applitools") ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +import * as todoPage from "../page-objects/todo-page"; + +describe("visual validation", () => { + before(() => todoPage.navigate()); + beforeEach(() => cy.eyesOpen({ appName: "TAU TodoMVC" })); + afterEach(() => cy.eyesClose()); + + it("should look good", () => { + cy.eyesCheckWindow("empty todo list"); + todoPage.addTodo("Clean room"); + todoPage.addTodo("Learn javascript"); + cy.eyesCheckWindow("two todos"); + todoPage.toggleTodo(0); + cy.eyesCheckWindow("mark as completed"); + }); +}); +``` + +
    + +

    + +# Section 4️⃣: Measuring Test Effectiveness + +

    + +## ⚪ ️ 4.1 Get enough coverage for being confident, ~80% seems to be the lucky number + +:white_check_mark: **Do:** The purpose of testing is to get enough confidence for moving fast, obviously the more code is tested the more confident the team can be. Coverage is a measure of how many code lines (and branches, statements, etc) are being reached by the tests. So how much is enough? 10–30% is obviously too low to get any sense about the build correctness, on the other side 100% is very expensive and might shift your focus from the critical paths to the exotic corners of the code. The long answer is that it depends on many factors like the type of application — if you’re building the next generation of Airbus A380 than 100% is a must, for a cartoon pictures website 50% might be too much. Although most of the testing enthusiasts claim that the right coverage threshold is contextual, most of them also mention the number 80% as a thumb of a rule ([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)) that presumably should satisfy most of the applications. + +Implementation tips: You may want to configure your continuous integration (CI) to have a coverage threshold ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) and stop a build that doesn’t stand to this standard (it’s also possible to configure threshold per component, see code example below). On top of this, consider detecting build coverage decrease (when a newly committed code has less coverage) — this will push developers raising or at least preserving the amount of tested code. All that said, coverage is only one measure, a quantitative based one, that is not enough to tell the robustness of your testing. And it can also be fooled as illustrated in the next bullets + +
    + +❌ **Otherwise:** Confidence and numbers go hand in hand, without really knowing that you tested most of the system — there will also be some fear and fear will slow you down + +
    + +
    Code Examples + +
    + +### :clap: Example: A typical coverage report + +![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "A typical coverage report") + +
    + +### :clap: Doing It Right Example: Setting up coverage per component (using Jest) + +![](https://img.shields.io/badge/🔨%20Example%20using%20Jest-blue.svg "Using Jest") + +![alt text](assets/bp-18-code-coverage2.jpeg "Setting up coverage per component (using Jest)") + +
    + +

    + +## ⚪ ️ 4.2 Inspect coverage reports to detect untested areas and other oddities + +:white_check_mark: **Do:** Some issues sneak just under the radar and are really hard to find using traditional tools. These are not really bugs but more of surprising application behavior that might have a severe impact. For example, often some code areas are never or rarely being invoked — you thought that the ‘PricingCalculator’ class is always setting the product price but it turns out it is actually never invoked although we have 10000 products in DB and many sales… Code coverage reports help you realize whether the application behaves the way you believe it does. Other than that, it can also highlight which types of code is not tested — being informed that 80% of the code is tested doesn’t tell whether the critical parts are covered. Generating reports is easy — just run your app in production or during testing with coverage tracking and then see colorful reports that highlight how frequent each code area is invoked. If you take your time to glimpse into this data — you might find some gotchas +
    + +❌ **Otherwise:** If you don’t know which parts of your code are left un-tested, you don’t know where the issues might come from + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: What’s wrong with this coverage report? + +Based on a real-world scenario where we tracked our application usage in QA and find out interesting login patterns (Hint: the amount of login failures is non-proportional, something is clearly wrong. Finally it turned out that some frontend bug keeps hitting the backend login API) + +![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report?") + +
    + +

    + +## ⚪ ️ 4.3 Measure logical coverage using mutation testing + +:white_check_mark: **Do:** The Traditional Coverage metric often lies: It may show you 100% code coverage, but none of your functions, even not one, return the right response. How come? it simply measures over which lines of code the test visited, but it doesn’t check if the tests actually tested anything — asserted for the right response. Like someone who’s traveling for business and showing his passport stamps — this doesn’t prove any work done, only that he visited few airports and hotels. + +Mutation-based testing is here to help by measuring the amount of code that was actually TESTED not just VISITED. [Stryker](https://stryker-mutator.io/) is a JavaScript library for mutation testing and the implementation is really neat: + +(1) it intentionally changes the code and “plants bugs”. For example the code newOrder.price===0 becomes newOrder.price!=0. This “bugs” are called mutations + +(2) it runs the tests, if all succeed then we have a problem — the tests didn’t serve their purpose of discovering bugs, the mutations are so-called survived. If the tests failed, then great, the mutations were killed. + +Knowing that all or most of the mutations were killed gives much higher confidence than traditional coverage and the setup time is similar +
    + +❌ **Otherwise:** You’ll be fooled to believe that 85% coverage means your test will detect bugs in 85% of your code + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: 100% coverage, 0% testing + +![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Using Stryker") + +```javascript +function addNewOrder(newOrder) { + logger.log(`Adding new order ${newOrder}`); + DB.save(newOrder); + Mailer.sendMail(newOrder.assignee, `A new order was places ${newOrder}`); + + return { approved: true }; +} + +it("Test addNewOrder, don't use such test names", () => { + addNewOrder({ assignee: "John@mailer.com", price: 120 }); +}); //Triggers 100% code coverage, but it doesn't check anything +``` + +
    + +### :clap: Doing It Right Example: Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations) + +![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations)") + +
    + +

    + +## ⚪ ️4.4 Preventing test code issues with Test linters + +:white_check_mark: **Do:** A set of ESLint plugins were built specifically for inspecting the tests code patterns and discover issues. For example, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) will warn when a test is written at the global level (not a son of a describe() statement) or when tests are [skipped](https://mochajs.org/#inclusive-tests) which might lead to a false belief that all tests are passing. Similarly, [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) can, for example, warn when a test has no assertions at all (not checking anything) + +
    + +❌ **Otherwise:** Seeing 90% code coverage and 100% green tests will make your face wear a big smile only until you realize that many tests aren’t asserting for anything and many test suites were just skipped. Hopefully, you didn’t deploy anything based on this false observation + +
    +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: A test case full of errors, luckily all are caught by Linters + +```javascript +describe("Too short description", () => { + const userToken = userService.getDefaultToken() // *error:no-setup-in-describe, use hooks (sparingly) instead + it("Some description", () => {});//* error: valid-test-description. Must include the word "Should" + at least 5 words +}); + +it.skip("Test name", () => {// *error:no-skipped-tests, error:error:no-global-tests. Put tests only under describe or suite + expect("somevalue"); // error:no-assert +}); + +it("Test name", () => {// *error:no-identical-title. Assign unique titles to tests +}); +``` + +
    + +

    + +# Section 5️⃣: CI and Other Quality Measures + +

    + +## ⚪ ️ 5.1 Enrich your linters and abort builds that have linting issues + +:white_check_mark: **Do:** Linters are a free lunch, with 5 min setup you get for free an auto-pilot guarding your code and catching significant issue as you type. Gone are the days where linting was about cosmetics (no semi-colons!). Nowadays, Linters can catch severe issues like errors that are not thrown correctly and losing information. On top of your basic set of rules (like [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) or [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), consider including some specializing Linters like [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) that can discover tests without assertions, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) can discover promises with no resolve (your code will never continue), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) which can discover eager regex expressions that might get used for DOS attacks, and [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) is capable of alarming when the code uses utility library methods that are part of the V8 core methods like Lodash.\_map(…) +
    + +❌ **Otherwise:** Consider a rainy day where your production keeps crashing but the logs don’t display the error stack trace. What happened? Your code mistakenly threw a non-error object and the stack trace was lost, a good reason for banging your head against a brick wall. A 5 min linter setup could detect this TYPO and save your day + +
    + +
    Code Examples + +
    + +### :thumbsdown: Anti-Pattern Example: The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug + +![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug") + +
    + +

    + +## ⚪ ️ 5.2 Shorten the feedback loop with local developer-CI + +:white_check_mark: **Do:** Using a CI with shiny quality inspections like testing, linting, vulnerabilities check, etc? Help developers run this pipeline also locally to solicit instant feedback and shorten the [feedback loop](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). Why? an efficient testing process constitutes many and iterative loops: (1) try-outs -> (2) feedback -> (3) refactor. The faster the feedback is, the more improvement iterations a developer can perform per-module and perfect the results. On the flip, when the feedback is late to come fewer improvement iterations could be packed into a single day, the team might already move forward to another topic/task/module and might not be up for refining that module. + +Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) allow running the pipeline locally. Some commercial tools like [wallaby provide highly-valuable & testing insights](https://wallabyjs.com/) as a developer prototype (no affiliation). Alternatively, you may just add npm script to package.json that runs all the quality commands (e.g. test, lint, vulnerabilities) — use tools like [concurrently](https://www.npmjs.com/package/concurrently) for parallelization and non-zero exit code if one of the tools failed. Now the developer should just invoke one command — e.g. ‘npm run quality’ — to get instant feedback. Consider also aborting a commit if the quality check failed using a githook ([husky can help](https://github.com/typicode/husky)) +
    + +❌ **Otherwise:** When the quality results arrive the day after the code, testing doesn’t become a fluent part of development rather an after the fact formal artifact + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: npm scripts that perform code quality inspection, all are run in parallel on demand or when a developer is trying to push new code + +```json +{ + "scripts": { + "inspect:sanity-testing": "mocha **/**--test.js --grep \"sanity\"", + "inspect:lint": "eslint .", + "inspect:vulnerabilities": "npm audit", + "inspect:license": "license-checker --failOn GPLv2", + "inspect:complexity": "plato .", + "inspect:all": "concurrently -c \"bgBlue.bold,bgMagenta.bold,yellow\" \"npm:inspect:quick-testing\" \"npm:inspect:lint\" \"npm:inspect:vulnerabilities\" \"npm:inspect:license\"" + }, + "husky": { + "hooks": { + "precommit": "npm run inspect:all", + "prepush": "npm run inspect:all" + } + } +} +``` + +
    + +

    + +## ⚪ ️5.3 Perform e2e testing over a true production-mirror + +:white_check_mark: **Do:** End to end (e2e) testing are the main challenge of every CI pipeline — creating an identical ephemeral production mirror on the fly with all the related cloud services can be tedious and expensive. Finding the best compromise is your game: [Docker-compose](https://serverless.com/) allows crafting isolated dockerized environment with identical containers using a single plain text file but the backing technology (e.g. networking, deployment model) is different from real-world productions. You may combine it with [‘AWS Local’](https://github.com/localstack/localstack) to work with a stub of the real AWS services. If you went [serverless](https://serverless.com/) multiple frameworks like serverless and [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) allows the local invocation of FaaS code. + +The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for local and CI-mirroring though many new tools are launched frequently. One approach is running a ‘minimized-Kubernetes’ using tools like [Minikube](https://kubernetes.io/docs/setup/minikube/) and [MicroK8s](https://microk8s.io/) which resemble the real thing only come with less overhead. Another approach is testing over a remote ‘real-Kubernetes’, some CI providers (e.g. [Codefresh](https://codefresh.io/)) has native integration with Kubernetes environment and make it easy to run the CI pipeline over the real thing, others allow custom scripting against a remote Kubernetes. +
    + +❌ **Otherwise:** Using different technologies for production and testing demands maintaining two deployment models and keeps the developers and the ops team separated + +
    + +
    Code Examples + +
    + +### :clap: Example: a CI pipeline that generates Kubernetes cluster on the fly ([Credit: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/)) + +
    deploy:
    stage: deploy
    image: registry.gitlab.com/gitlab-examples/kubernetes-deploy
    script:
    - ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN
    - kubectl create ns $NAMESPACE
    - kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL"
    - mkdir .generated
    - echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF"
    - sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml"
    - kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml
    - kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml
    environment:
    name: test-for-ci
    + +
    + +

    + +## ⚪ ️5.4 Parallelize test execution + +:white_check_mark: **Do:** When done right, testing is your 24/7 friend providing almost instant feedback. In practice, executing 500 CPU-bounded unit test on a single thread can take too long. Luckily, modern test runners and CI platforms (like [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) and [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) can parallelize the test into multiple processes and achieve significant improvement in feedback time. Some CI vendors do also parallelize tests across containers (!) which shortens the feedback loop even further. Whether locally over multiple processes, or over some cloud CLI using multiple machines — parallelizing demand keeping the tests autonomous as each might run on different processes + +❌ **Otherwise:** Getting test results 1 hour long after pushing new code, as you already code the next features, is a great recipe for making testing less relevant + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) + +![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization (Credit: JavaScript Test-Runners Benchmark)") + +
    + +

    + +## ⚪ ️5.5 Stay away from legal issues using license and plagiarism check + +:white_check_mark: **Do:** Licensing and plagiarism issues are probably not your main concern right now, but why not tick this box as well in 10 minutes? A bunch of npm packages like [license check](https://www.npmjs.com/package/license-checker) and [plagiarism check](https://www.npmjs.com/package/plagiarism-checker) (commercial with free plan) can be easily baked into your CI pipeline and inspect for sorrows like dependencies with restrictive licenses or code that was copy-pasted from Stack Overflow and apparently violates some copyrights + +❌ **Otherwise:** Unintentionally, developers might use packages with inappropriate licenses or copy paste commercial code and run into legal issues + +
    + +
    Code Examples + +
    + +### :clap: Doing It Right Example: + +```shell +# install license-checker in your CI environment or also locally +npm install -g license-checker + +# ask it to scan all licenses and fail with exit code other than 0 if it found unauthorized license. The CI system should catch this failure and stop the build +license-checker --summary --failOn BSD +``` + +
    + +![alt text](assets/bp-25-nodejs-licsense.png) + +
    + +

    + +## ⚪ ️5.6 Constantly inspect for vulnerable dependencies + +:white_check_mark: **Do:** Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using community tools such as [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), or commercial tools like [snyk](https://snyk.io/) (offer also a free community version). Both can be invoked from your CI on every build + +❌ **Otherwise:** Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online publications about new threats. Quite tedious + +
    + +
    Code Examples + +
    + +### :clap: Example: NPM Audit result + +![alt text](assets/bp-26-npm-audit-snyk.png "NPM Audit result") + +
    + +

    + +## ⚪ ️5.7 Automate dependency updates + +:white_check_mark: **Do:** Yarn and npm latest introduction of package-lock.json introduced a serious challenge (the road to hell is paved with good intentions) — by default now, packages are no longer getting updates. Even a team running many fresh deployments with ‘npm install’ & ‘npm update’ won’t get any new updates. This leads to subpar dependent packages versions at best or to vulnerable code at worst. Teams now rely on developers goodwill and memory to manually update the package.json or use tools [like ncu](https://www.npmjs.com/package/npm-check-updates) manually. A more reliable way could be to automate the process of getting the most reliable dependency versions, though there are no silver bullet solutions yet there are two possible automation roads: + +(1) CI can fail builds that have obsolete dependencies — using tools like [‘npm outdated’](https://docs.npmjs.com/cli/outdated) or ‘npm-check-updates (ncu)’ . Doing so will enforce developers to update dependencies. + +(2) Use commercial tools that scan the code and automatically send pull requests with updated dependencies. One interesting question remaining is what should be the dependency update policy — updating on every patch generates too many overhead, updating right when a major is released might point to an unstable version (many packages found vulnerable on the very first days after being released, [see the](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) eslint-scope incident). + +An efficient update policy may allow some ‘vesting period’ — let the code lag behind the @latest for some time and versions before considering the local copy as obsolete (e.g. local version is 1.3.1 and repository version is 1.3.8) +
    + +❌ **Otherwise:** Your production will run packages that have been explicitly tagged by their author as risky + +
    + +
    Code Examples + +
    + +### :clap: Example: [ncu](https://www.npmjs.com/package/npm-check-updates) can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions + +![alt text](assets/bp-27-yoni-goldberg-npm.png "ncu can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions") + +
    + +

    + +## ⚪ ️ 5.8 Other, non-Node related, CI tips + +: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 few non-Node related tips that are well-known + +
    1. Use a declarative syntax. This is the only option for most vendors but older versions of Jenkins allows using code or UI
    2. Opt for a vendor that has native Docker support
    3. Fail early, run your fastest tests first. Create a ‘Smoke testing’ step/milestone that groups multiple fast inspections (e.g. linting, unit tests) and provide snappy feedback to the code committer
    4. Make it easy to skim-through all build artifacts including test reports, coverage reports, mutation reports, logs, etc
    5. Create multiple pipelines/jobs for each event, reuse steps between them. For example, configure a job for feature branch commits and a different one for master PR. Let each reuse logic using shared steps (most vendors provide some mechanism for code reuse)
    6. Never embed secrets in a job declaration, grab them from a secret store or from the job’s configuration
    7. Explicitly bump version in a release build or at least ensure the developer did so
    8. Build only once and perform all the inspections over the single build artifact (e.g. Docker image)
    9. Test in an ephemeral environment that doesn’t drift state between builds. Caching node_modules might be the only exception
    +
    + +❌ **Otherwise:** You‘ll miss years of wisdom + +

    + +## ⚪ ️ 5.9 Build matrix: Run the same CI steps using multiple Node versions + +:white_check_mark: **Do:** Quality checking is about serendipity, the more ground you cover the luckier you get in detecting issues early. When developing reusable packages or running a multi-customer production with various configuration and Node versions, the CI must run the pipeline of tests over all the permutations of configurations. For example, assuming we use MySQL for some customers and Postgres for others — some CI vendors support a feature called ‘Matrix’ which allow running the suit of testing against all permutations of MySQL, Postgres and multiple Node version like 8, 9 and 10. This is done using configuration only without any additional effort (assuming you have testing or any other quality checks). Other CIs who doesn’t support Matrix might have extensions or tweaks to allow that +
    + +❌ **Otherwise:** So after doing all that hard work of writing testing are we going to let bugs sneak in only because of configuration issues? + +
    + +
    Code Examples + +
    + +### :clap: Example: Using Travis (CI vendor) build definition to run the same test over multiple Node versions + +
    language: node_js
    node_js:
    - "7"
    - "6"
    - "5"
    - "4"
    install:
    - npm install
    script:
    - npm run test
    +
    + +

    + +# Team + +## Yoni Goldberg + +
    + +
    + +**Role:** Writer + +**About:** I'm an independent consultant who works with Fortune 500 companies and garage startups on polishing their JS & Node.js applications. More than any other topic I'm fascinated by and aims to master the art of testing. I'm also the author of [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices) + +**📗 Online Course:** Liked this guide and wish to take your testing skills to the extreme? Consider visiting my comprehensive course [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) + +
    + +**Follow:** + +- [🐦 Twitter](https://twitter.com/goldbergyoni/) +- [📞 Contact](https://testjavascript.com/contact-2/) +- [✉️ Newsletter](https://testjavascript.com/newsletter//) + +
    +
    +
    + +## [Bruno Scheufler](https://github.com/BrunoScheufler) + +**Role:** Tech reviewer and advisor + +Took care to revise, improve, lint and polish all the texts + +**About:** full-stack web engineer, Node.js & GraphQL enthusiast + +
    +
    + +## [Ido Richter](https://github.com/idori) + +**Role:** Concept, design and great advice + +**About:** A savvy frontend developer, CSS expert and emojis freak + +## [Kyle Martin](https://github.com/js-kyle) + +**Role:** Helps keep this project running, and reviews security related practices + +**About:** Loves working on Node.js projects and web application security. diff --git a/readme.md b/readme.md index 57a818c0..3c0269d7 100644 --- a/readme.md +++ b/readme.md @@ -42,6 +42,7 @@ Start by understanding the ubiquitous testing practices that are the foundation - 🇫🇷[French](readme-fr.md) - Courtesy of [Mathilde El Mouktafi](https://github.com/mel-mouk) - 🇯🇵[Japanese (draft)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - Courtesy of [Yuichi Yogo](https://github.com/yuichkun) and [ryo](https://github.com/kawamataryo) - 🇹🇼[Traditional Chinese](readme-zh-TW.md) - Courtesy of [Yubin Hsu](https://github.com/yubinTW) +- 🇹🇼[Persian](readme-pr-fr.md) - Courtesy of [Ali Azmoodeh](https://github.com/TREER00T) - Want to translate to your own language? please open an issue 💜

    From 53f041d161f498ef019a68bacfae1bb586682671 Mon Sep 17 00:00:00 2001 From: Ali Azmoodeh Date: Sun, 18 Sep 2022 19:57:52 +0430 Subject: [PATCH 151/189] fix writing bug --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 07507247..71ef9d96 100644 --- a/readme.md +++ b/readme.md @@ -42,7 +42,7 @@ Start by understanding the ubiquitous testing practices that are the foundation - 🇫🇷[French](readme-fr.md) - Courtesy of [Mathilde El Mouktafi](https://github.com/mel-mouk) - 🇯🇵[Japanese (draft)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - Courtesy of [Yuichi Yogo](https://github.com/yuichkun) and [ryo](https://github.com/kawamataryo) - 🇹🇼[Traditional Chinese](readme-zh-TW.md) - Courtesy of [Yubin Hsu](https://github.com/yubinTW) -- 🇹🇼[Persian](readme-pr-fr.md) - Courtesy of [Ali Azmoodeh](https://github.com/TREER00T) +- 🇮🇷[Persian](readme-pr-fr.md) - Courtesy of [Ali Azmoodeh](https://github.com/TREER00T) - Want to translate to your own language? please open an issue 💜

    From 8bef8a158a8073e6342c9aef32dfc47af8b520f4 Mon Sep 17 00:00:00 2001 From: Ali Azmoodeh Date: Sun, 18 Sep 2022 23:33:27 +0430 Subject: [PATCH 152/189] started chapter 3 --- readme-pr-fr.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/readme-pr-fr.md b/readme-pr-fr.md index 89c4fe43..4ee19591 100644 --- a/readme-pr-fr.md +++ b/readme-pr-fr.md @@ -1060,7 +1060,7 @@ beforeEach(() => { ```javascript test('هنگامی که سرویس کاربران یک بار با 503 پاسخ می دهد و مکانیسم امتحان مجدد اعمال می شود، سفارش با موفقیت اضافه می شود', async () => { - //مفدار دهی کردن + //مقدار دهی کردن nock.removeInterceptor(userServiceNock.interceptors[0]) nock('http://localhost/user/') .get('/1') @@ -1104,54 +1104,54 @@ beforeEach(() => {

    -# Section 3️⃣: Frontend Testing +# بخش 3️⃣: Frontend تست کردن -## ⚪ ️ 3.1 Separate UI from functionality +## ⚪ ️ 3.1 UI را از لاجیک برنامه جدا کنید -: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/CSS 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 +:white_check_mark: **انجام دادن:** هنگام تمرکز بر روی تست منطق مؤلفه، جزئیات UI تبدیل به نویز می شود که باید استخراج شود، بنابراین آزمایشات شما می توانند بر روی داده های خالص تمرکز کنند. عملاً داده‌های مورد نظر را از نشانه‌گذاری به روشی انتزاعی استخراج کنید که خیلی با پیاده‌سازی گرافیکی همراه نباشد، فقط روی داده‌های خالص (در مقابل جزئیات گرافیکی HTML/CSS) ادعا کنید و انیمیشن‌هایی را که کند می‌شوند غیرفعال کنید. ممکن است وسوسه شوید که از رندر کردن خودداری کنید و فقط قسمت پشتی رابط کاربری (مانند سرویس‌ها، اقدامات، فروشگاه) را آزمایش کنید، اما این منجر به آزمایش‌های تخیلی می‌شود که به واقعیت شباهت ندارند و مواردی را که داده‌های مناسب وجود ندارد را نشان نمی‌دهد. حتی وارد UI شوید
    -❌ **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 +❌ **در غیر این صورت:** داده‌های محاسباتی خالص آزمون شما ممکن است در 10 میلی‌ثانیه آماده باشد، اما پس از آن کل آزمون به دلیل برخی انیمیشن‌های فانتزی و نامربوط، 500 میلی‌ثانیه (100 تست = 1 دقیقه) طول خواهد کشید.
    -
    Code Examples +
    نمونه کد
    -### :clap: Doing It Right Example: Separating out the UI details +### :clap: متال درست: جدا کردن جزئیات UI ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") ```javascript -test("When users-list is flagged to show only VIP, should display only VIP members", () => { - // Arrange +test("هنگامی که لیست کاربران برای نشان دادن فقط VIP پرچم گذاری می شود، باید فقط اعضای VIP نمایش داده شود", () => { + // مقدار دهی کردن const allUsers = [{ id: 1, name: "Yoni Goldberg", vip: false }, { id: 2, name: "John Doe", vip: true }]; - // Act + // اجرا کردن const { getAllByTestId } = render(); - // Assert - Extract the data from the UI first + // مفایسه کردن - ابتدا داده ها را از UI استخراج کنید const allRenderedUsers = getAllByTestId("user").map(uiElement => uiElement.textContent); const allRealVIPUsers = allUsers.filter(user => user.vip).map(user => user.name); - expect(allRenderedUsers).toEqual(allRealVIPUsers); //compare data with data, no UI here + expect(allRenderedUsers).toEqual(allRealVIPUsers); //داده ها را با داده ها مقایسه کنید، اینجا رابط کاربری وجود ندارد }); ```
    -### :thumbsdown: Anti-Pattern Example: Assertion mix UI details and data +### :thumbsdown: مثال ضد الگو: جزئیات و داده های رابط کاربری ترکیبی ادعا ```javascript -test("When flagging to show only VIP, should display only VIP members", () => { - // Arrange +test("هنگام پرچم گذاری برای نمایش فقط VIP، باید فقط اعضای VIP نمایش داده شود", () => { + // مقداری دهی کردن const allUsers = [{ id: 1, name: "Yoni Goldberg", vip: false }, { id: 2, name: "John Doe", vip: true }]; - // Act + // اجرا کردن const { getAllByTestId } = render(); - // Assert - Mix UI & data in assertion + // مقابسه کردن - ترکیب ui و data در این قسمت expect(getAllByTestId("user")).toEqual('[
  • John Doe
  • ]'); }); ``` From e96d72014330d391097f7bb05329ee53fdec5aaa Mon Sep 17 00:00:00 2001 From: alex_p Date: Tue, 4 Oct 2022 15:27:31 +0300 Subject: [PATCH 153/189] docs: update README.md --- readme-ru.md | 2190 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2190 insertions(+) create mode 100644 readme-ru.md diff --git a/readme-ru.md b/readme-ru.md new file mode 100644 index 00000000..95ce4435 --- /dev/null +++ b/readme-ru.md @@ -0,0 +1,2190 @@ + + +
    + +# 👇 Почему это руководство выведет ваши навыки тестирования на новый уровень + +
    + +## 📗 46+ наилучших способов: исчерпывающих и информативных + +Данное руководство гарантирует надежность JavaScript и Node.JS от A до Я. В качестве источника в данном руководстве используется обобщенная информация, взятая из самых надежных книг, статей и блогов, которые можно найти на рынке в данный момент. + +## 🚢 Продвинутый уровень: Выходит далеко за пределы основ + +Отправляйтесь в путешествие, которое выходит далеко за пределы базовых практик тестирования и включает в себя такие продвинутые темы, как: тестирование в рабочей среде (TIP), мутационное тестирование (mutation testing), тестирование на основе свойств (property-based testing) и многие другие профессиональные подходы. После прочтения данного руководства, ваши навыки тестирования станут намного выше среднего. + +## 🌐 Full-stack: frontend, backend, CI и другое + +Начните с понимания общеиспользуемых способов тестирования, являющиеся основными для приложений любого уровня, а затем углубитесь в выбранную вами область: frontend/UI, backend, CI или всё вместе. + +
    + +## 🚀 Для отработки изученных в процессе чтения навыков тестирования Вы можете использовать наш [Node.js starter - Practica.js](https://github.com/practicajs/practica). Вы сможете использовать его как для создания нового шаблона, так и для практики с примерами кода. + +### Автор руководства - Yoni Goldberg + +- Консультант по вопросам JavaScript & Node.js +- 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - Мой полный онлайн-курс, включающий более, чем [7 часов видео](https://www.testjavascript.com), 14 типов тестирования и 40+ практических занятий +- [Мой твиттер](https://twitter.com/goldbergyoni/) +- [Следующий workshop: Verona, Italy 🇮🇹, April 20th](https://2022.jsday.it/workshop/nodejs_testing.html) + +
    + +### Доступные переводы + +- 🇨🇳[Китайский](readme-zh-CN.md) - Переведено [Yves yao](https://github.com/yvesyao) +- 🇰🇷[Koрейский](readme.kr.md) - Переведено [Rain Byun](https://github.com/ragubyun) +- 🇵🇱[Польский](readme-pl.md) - Переведено [Michal Biesiada](https://github.com/mbiesiad) +- 🇪🇸[Испанский](readme-es.md) - Переведено [Miguel G. Sanguino](https://github.com/sanguino) +- 🇧🇷[Португальский](readme-pt-br.md) - Переведено [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) +- 🇫🇷[Французский](readme-fr.md) - Переведено [Mathilde El Mouktafi](https://github.com/mel-mouk) +- 🇯🇵[Японский (черновик)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - Переведено of [Yuichi Yogo](https://github.com/yuichkun) and [ryo](https://github.com/kawamataryo) +- 🇹🇼[Традиционный китайский](readme-zh-TW.md) - Переведено [Yubin Hsu](https://github.com/yubinTW) +- 🇷🇺 [Русский](ссылка) - Переведено [Alex Popov](https://github.com/Saimon398) +- Хотите перевести на собственный язык? Переходите в Issues 💜 + +

    + +## `Содержание` + +#### [`Раздел 0: Золотое правило`](#section-0️⃣-the-golden-rule) + +Ключевое правило для написания качественных тестов (1 пункт) + +#### [`Раздел 1: Анатомия тестов`](#section-1-the-test-anatomy-1) + +Фундамент - структура чистых тестов (12 пунктов) + +#### [`Раздел 2: Backend`](#section-2️⃣-backend-testing) + +Разработка эффективных Backend and Microservices тестов (13 пунктов) + +#### [`Раздел 3: Frontend`](#section-3️⃣-frontend-testing) + +Написание тестов для UI, включая тестирование компонентов и E2E тесты (11 пунктов) + +#### [`Раздел 4: Измерение эффективности тестов`](#section-4️⃣-measuring-test-effectiveness) + +Измерение качества тестов (4 пункта) + +#### [`Раздел 5: Continuous Integration`](#section-5️⃣-ci-and-other-quality-measures) + +Руководство для CI в мире JS (9 пунктов) + +

    + +# Раздел 0️⃣: Золотое правило + +
    + +## ⚪️ 0 Золотое правило: Как проектировать тесты + +:white_check_mark: **Сделать:** +Тесты - это не продакшн-код. Тестовый код должен быть коротким, плоским и простым, чтобы с ним было приятно работать. Он должен быть таким, чтобы взглянув на него, можно было сразу понять замысел разработчика. + +Во время разработки, наш разум полностью сфокусирован на продакшн-коде. Наш интеллект полностью погружен в работу и, как правило, введение дополнительной сложности может привести к "перегрузке". Если мы попытаемся добавить еще одну комплексную систему, это может привести к торможению целого рабочего процесса, что противоречит самой идее тестирования. На практике, многие команды разработчиков пренебрегают тестированием. + +Тестирование нужно рассматривать, как личного помощника, второго пилота, который за небольшую плату предоставляет бесценные услуги и пользу. Ученые утверждают, что у человека есть 2 типа мышления: тип 1 используется при выполнении простых задач, не требующих усилий, таких как вождение автомобиля по пустой дороге, и тип 2, предназначенный для сложных мыслительных процессов, как, например, решение математических уравнений. +Тесты должны быть написаны так, чтобы при просмотре на код использовался 1 тип мышления, и это было похоже на простое изменение HTML-документа, а не решение математического уравнения 2 × (17 × 24). + +Этого можно достичь путем тщательного выбора способов, инструментов и целей тестирования, которые будут одновременно и эффективными и "окупаемыми". Тестируйте только то, что необходимо. Старайтесь увеличить скорость разработки. Иногда даже стоит отказаться от некоторых тестов, чтобы сделать код более простым и гибким. + +![alt text](/assets/headspace.png "We have no head room for additional complexity") + +Большинство дальнейших советов являются производными от этого принципа. + +### Готовы? + +

    + +# Раздел 1: Анатомия тестов + +
    + +## ⚪ ️ 1.1 Каждое описание теста включает в себя 3 части + +:white_check_mark: **Сделать:** Отчет о тестировании должен предоставлять информацию о том, удовлетворяет ли текущая версия приложения требованиям человека, который часто незнаком с кодом или забыл его: тестировщик, DevOps-инженер, который разворачивает проект, а также Вы сами через 2 года. +Наилучший способ добиться этого, если тесты будут проводиться на уровне требований, а его описание состоять из 3-х частей: + +(1) Что именно тестируется? Например: ProductsService.addNewProduct method + +(2) При каких обстоятельствах? Например: no price is passed to the method + +(3) Какой ожидаемый результат? Например: the new product is not approved + +
    + +❌ **Иначе:** A deployment just failed, a test named “Add product” failed. Говорит ли это вам о том, в чем именно заключается сбой? +
    + +**👇 Обрати внимание:** Каждый пункт содержит примеры кода, а иногда и иллюстрацию к нему. Нажмите, чтобы открыть +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Описание теста содержит 3 части + +![](https://img.shields.io/badge/🔨%20Example%20using%20Mocha-blue.svg "Using Mocha to illustrate the idea") + +```javascript +//1. Тестируемый блок +describe('Products Service', function() { + describe('Add new product', function() { + //2. сценарий and 3. ожидание + it('When no price is specified, then the product status is pending approval', ()=> { + const newProduct = new ProductService().add(...); + expect(newProduct.status).to.equal('pendingApproval'); + }); + }); +}); + +``` + +
    + +### :clap: Правильно: Описание теста содержит 3 части + +![alt text](/assets/bp-1-3-parts.jpeg "Описание теста содержит 3 части") + +
    + +
    +
    © Читать далее... + 1. Roy Osherove - Naming standards for unit tests +
    + +

    + +## ⚪ ️ 1.2 Разделите тесты по AAA-структуре + +:white_check_mark: **Сделать:** Разделите написанные тесты согласно 3 категориям: Arrange, Act & Assert (AAA). Следование данной структуре позволит человеку, анализирующему тесты, быстрее разобраться в стратегии тестирования. + +1. A - Организуйте (Arrange): В данную категорию входит настройки, которые приведут код к тому сценарию, который должен быть имитирован. Они включают в себя организация трестируемого блока, добавления записей в БД, mocking/stubbing и многое другое. + +2. A - Действуйте (Act): Выполните тестируемый блок кода. Как правило, занимает 1 строку кода. + +3. A - Утвердите (Assert): Убедитесь, что полученный результат соответствует ожидаемому. Как правило, занимает 1 строку кода. + +
    + +❌ **Иначе:** Вы не только тратите время на то, чтобы понять, как работает основной код, но и на то, как функционируют тесты, несмотря на то, что это должно быть простой задачей. +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Тест, оформленный по структуре AAA + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") ![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +describe("Customer classifier", () => { + test("When customer spent more than 500$, should be classified as premium", () => { + // Arrange + const customerToClassify = { spent: 505, joined: new Date(), id: 1 }; + const DBStub = sinon + .stub(dataAccess, "getCustomer") + .reply({ id: 1, classification: "regular" }); + + // Act + const receivedClassification = + customerClassifier.classifyCustomer(customerToClassify); + + // Assert + expect(receivedClassification).toMatch("premium"); + }); +}); +``` + +
    + +### :thumbsdown: Неправильно: Разделение отсутствует, сплошной код, тяжело разобрать написанное + +```javascript +test("Should be classified as premium", () => { + const customerToClassify = { spent: 505, joined: new Date(), id: 1 }; + const DBStub = sinon + .stub(dataAccess, "getCustomer") + .reply({ id: 1, classification: "regular" }); + const receivedClassification = + customerClassifier.classifyCustomer(customerToClassify); + expect(receivedClassification).toMatch("premium"); +}); +``` + +
    + +

    + +## ⚪ ️1.3 Опишите ожидания на языке продукта: используйте утверждения в стиле BDD + +:white_check_mark: **Сделать:** Написание тестов в декларативном стиле позволяет читателю мгновенно понять смысл происходящего, особо не напрягаясь. Когда вы пишете код в императивном стиле, наполненный условными конструкциями, необходимо прикладывать некоторые усилия, чтобы его разобрать. В этом случае необходимо писать код в стиле "человеческой" речи, применяя BDD-подход с использованием `expect` или `should` и избегая пользовательских конструкций. В случае, если Chai & Jest не содержат нужные assertions, которые часто повторяются при написании, то рассмотрите [extending Jest matcher (Jest)](https://jestjs.io/docs/en/expect#expectextendmatchers) или написание [custom Chai plugin](https://www.chaijs.com/guide/plugins/) +
    + +❌ **Иначе:** При разработке будет написано меньше тестов, а ненужные тесты будут проигнорированы с помощью .skip(). + +
    + +
    Примеры кода
    + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") ![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +### :thumbsdown: Неправильно: Чтобы просмотреть реализацию тестов, разработчик должен просмотреть весь объёмный и императивный код + +```javascript +test("When asking for an admin, ensure only ordered admins in results", () => { + // предположим, что мы добавили здесь "admin1", "admin2" and "user1" + const allAdmins = getUsers({ adminOnly: true }); + + let admin1Found, + adming2Found = false; + + allAdmins.forEach((aSingleUser) => { + if (aSingleUser === "user1") { + assert.notEqual(aSingleUser, "user1", "A user was found and not admin"); + } + if (aSingleUser === "admin1") { + admin1Found = true; + } + if (aSingleUser === "admin2") { + admin2Found = true; + } + }); + + if (!admin1Found || !admin2Found) { + throw new Error("Not all admins were returned"); + } +}); +``` + +
    + +### :clap: Правильно: Просмотреть данный код в декларативном стиле не составляет труда + +```javascript +it("When asking for an admin, ensure only ordered admins in results", () => { + // предположим, что мы добавили здесь 2-х администраторов + const allAdmins = getUsers({ adminOnly: true }); + + expect(allAdmins) + .to.include.ordered.members(["admin1", "admin2"]) + .but.not.include.ordered.members(["user1"]); +}); +``` + +
    + +

    + +## ⚪ ️ 1.4 Придерживайтесь black-box тестирования: Тестируйте только public-методы + +:white_check_mark: **Сделать:** Тестирование внутренних компонентов сопровождается большими затратами. Если ваш код/API работает корректно, целесообразно ли будет потратить следующие 3 часа на написание тестов для внутренней реализации и потом все это поддерживать? Каждый раз, когда тестируется внешнее поведение, внутренняя реализация также проверяется неявным образом. Тесты могут упасть только при возникновении определенной проблемы (например, неправильный вывод). Такой подход также называют `поведенческое тестирование (behavioral testing)`. С другой стороны, если вы тестируете внутренние компоненты (white-box тестирование), ваш фокус может сместиться с планирования результата работы данного компонента на мелкие детали. Как следствие, тест может упасть из-за незначительных исправлений в коде, несмотря на то, что результат работы компонента будет удовлетворительны - это усложняет поддержку такого кода. +
    + +❌ **Иначе:** Ваши тесты начинают работать словно [мальчик, который кричал: "Волк!"](https://ru.wikipedia.org/wiki/Мальчик,_который_кричал:_«Волк!»), сигнализируя о ложных срабатываниях (например, A test fails because a private variable name was changed). Неудивительно, что люди вскоре начнут игнорировать CI-уведомления, пока в один прекрасный день не проигнорируют настоящую ошибку... + +
    +
    Примеры кода + +
    + +### :thumbsdown: Неправильно: Тестирование внутренних компонентов без причины + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha & Chai") + +```javascript +class ProductService { + // этот метод используется только внутри + // изменение имени приведет к падению тестов + calculateVATAdd(priceWithoutVAT) { + return { finalPrice: priceWithoutVAT * 1.2 }; + // изменение формата результата или ключа выше приведет падению тестов + } + // public method + getPrice(productId) { + const desiredProduct = DB.getProduct(productId); + finalPrice = this.calculateVATAdd(desiredProduct.price).finalPrice; + return finalPrice; + } +} + +it("White-box test: When the internal methods get 0 vat, it return 0 response", async () => { + // нет никаких требований, чтобы пользователи могли рассчитать НДС, только показать конечную цену. Тем не менее, мы ошибочно настаиваем на этом, чтобы протестировать внутреннее устройство класса + expect(new ProductService().calculateVATAdd(0).finalPrice).to.equal(0); +}); +``` + +
    + +

    + +## ⚪ ️ ️1.5 Выбирайте правильные имитации: предпочитайте stubs и spies вместо mocks + +:white_check_mark: **Сделать:** Имитации, которые используются в тестах, можно назвать злом во благо. Они связаны с внутренними компонентами, но некоторые из них приносят огромную пользу ([Читайте здесь напоминание о двойниках тестов: mocks vs stubs vs spies](https://martinfowler.com/articles/mocksArentStubs.html)). + +Прежде чем использовать объекты-имитации, вы должны спросить себя: используется ли он для тестирования функциональности, которая требуется в процессе разработки?. Если нет, то это появление предпосылок white-box тестирования. + +Например, если вы хотите протестировать корректную работу вашего приложения, в то время, как платежный сервис не работает, то можете поставить заглушку `(stub)` на платежный сервис и вернуть несколько 'No Response', чтобы убедится в том, что тестируемый модуль возвращает правильное значение. Такой подход проверяет поведение/ответ/результат работы нашего приложения при определённых сценариях. Также можно использовать `spy` для подтверждения того, что письмо было отправлено в ситуациях, когда сервис упал. Такая проверка поведения также может быть указана в техническом задании (“Send an email if payment couldn’t be saved”). C другой стороны, мокинг платежного сервиса и дальнейший его вызов с корректными типами данных говорит о том, что ваш тест предназначен для проверки внутренней реализации, которая не имеет отношения к функциональности приложения и может часто подвергаться изменениям. +
    + +❌ **Иначе:** Любой рефакторинг кода требует поиска всех `mocks` в коде и последующего обновления. Тесты начинают вредить, нежели, чем приносить пользу + +
    + +
    Примеры кода + +
    + +### :thumbsdown: Неправильно: Мокинг используется для тестирования внутренней реализации + +![](https://img.shields.io/badge/🔧%20Example%20using%20Sinon-blue.svg "Examples with Sinon") + +```javascript +it("When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config", async () => { + // предположим, что мы уже добавили продукт + const dataAccessMock = sinon.mock(DAL); + // тестирование внутренних компонентов является нашей главной целью, а не просто побочным эффектом + dataAccessMock + .expects("deleteProduct") + .once() + .withArgs(DBConfig, theProductWeJustAdded, true, false); + new ProductService().deletePrice(theProductWeJustAdded); + dataAccessMock.verify(); +}); +``` + +
    + +### :clap: Правильно: spies сосредоточены на проверке требований, но в качестве побочного эффекта неизбежно затрагивают внутренние компоненты + +```javascript +it("When a valid product is about to be deleted, ensure an email is sent", async () => { + // предположим, что мы уже добавили продукт + const spy = sinon.spy(Emailer.prototype, "sendEmail"); + new ProductService().deletePrice(theProductWeJustAdded); + // мы имеем дело с внутренними компонентами, но как побочный эффект тестирования + expect(spy.calledOnce).to.be.true; +}); +``` + +
    + +

    + +## 📗 Хочешь изучить данные подходы на видео? + +### Переходи по ссылке на мой онлайн-курс [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) + +

    + +## ⚪ ️1.6 Не используй "foo". Используй реалистичные входные данные + +:white_check_mark: **Делать:** Часто производственные ошибки обнаруживаются при очень специфических и неожиданных входных данных - чем реалистичнее тестовые данные, тем больше шансов обнаружить ошибки на ранней стадии. Используйте специальные библиотеки, такие как [Chance](https://github.com/chancejs/chancejs) или [Faker](https://www.npmjs.com/package/faker), для генерации псевдореальных данных, напоминающих по разнообразию и форме производственные данные. Например, такие библиотеки могут генерировать реалистичные телефонные номера, имена пользователей, кредитные карты, названия компаний и даже текст "lorem ipsum". Вы также можете создать несколько тестов (поверх модульных тестов, а не в качестве замены), которые рандомизируют поддельные данные, чтобы растянуть тестируемый модуль или даже импортировать реальные данные из производственной среды. Хотите перейти на новый уровень? Смотрите следующий пункт (тестирование на основе свойств). +
    + +❌ **Иначе:** Все тесты при разработке могут ложно показать зеленый цвет при использовании данных типа "Foo". Однако, все может упасть, если на вход попадет строка вида "@3e2ddsf . ##' 1 fdsfds . fds432 AAAA". + +
    + +
    Примеры кода + +
    + +### :thumbsdown: Неправильно: Набор тестов, который проходит из-за нереалистичных данных + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +const addProduct = (name, price) => { + const productNameRegexNoSpace = /^\S*$/; //no white-space allowed + + if (!productNameRegexNoSpace.test(name)) return false; //this path never reached due to dull input + + // здесь какая-то логика + return true; +}; + +test("Wrong: When adding new product with valid properties, get successful confirmation", async () => { + // строка "Foo", которая используется во всех тестах, никогда не вызывает ложного результата + const addProductResult = addProduct("Foo", 5); + expect(addProductResult).toBe(true); + // positive-false: операция прошла успешно, так как мы не пробовали использовать длинное название продукта, включающее пробелы +}); +``` + +
    + +### :clap: Правильно: Генерация реалистичных входных данных + +```javascript +it("Better: When adding new valid product, get successful confirmation", async () => { + const addProductResult = addProduct( + faker.commerce.productName(), + faker.random.number() + ); + // случайно сгенерированные входные данные: {'Sleek Cotton Computer', 85481} + expect(addProductResult).to.be.true; + // тест провалился: данные, которые мы подали на вход, сработали не так, как планировалось + // мы обнаружили ошибку +}); +``` + +
    + +

    + +## ⚪ ️ 1.7 Тестирование множества комбинаций входных данных с помощью тестирования на основе свойств + +:white_check_mark: **Сделать:** Обычно для тестирования выбирается несколько комбинаций входных данных. Даже когда они напоминают реальные данные (смотри пункт [‘1.6’](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F16-dont-foo-use-realistic-input-data)), мы охватываем только несколько наборов входных данных (method(‘’, true, 1), method(“string” , false , 0)), Однако, в продакшене, API вызываемый с 5 параметрами, может быть вызван с тысячами различных перестановок, одна из которых может уронить весь процесс ([см. Fuzz Testing](https://en.wikipedia.org/wiki/Fuzzing)). Представьте, что вы бы могли написать тест, который автоматически генерирует 1000 перестановок различных входных данных и отслеживает те данные, на которых код падает? Тестирование на основе свойств позволяет это сделать: отправляя на вход множество комбинации различных данных, вы увеличиваете вероятность случайного обнаружения ошибки. Например, при наличии метода addNewProduct(id, name, isDiscount) поддерживающие библиотеки будут вызывать этот метод со многими комбинациями (number, string, boolean), например (1, "iPhone", false), (2, "Galaxy", true). Такой тип тестирования может быть организован, используя разные тестовые фреймворки (Mocha, Jest, etc) с различными библиотеками [js-verify](https://github.com/jsverify/jsverify) или [testcheck](https://github.com/leebyron/testcheck-js) (имеет документацию лучше). Обновление: Nicolas Dubien предлагает ниже такую библиотеку, как [checkout fast-check](https://github.com/dubzzz/fast-check#readme), которая имеет дополнительные возможности и также активно поддерживается. +
    + +❌ **Иначе:** Неосознанно вы отправляете на вход различные данные, с которыми код, как правило, работает. К сожалению, это снижает эффективность тестирования, как инструмента для выявления ошибок. + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Тестирование множества входных данных с помощью библиотеки “fast-check” + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +import fc from "fast-check"; + +describe("Product service", () => { + describe("Adding new", () => { + // запуститься 100 раз с разными свойствами + it("Add new product with random yet valid properties, always successful", () => + fc.assert( + fc.property(fc.integer(), fc.string(), (id, name) => { + expect(addNewProduct(id, name).status).toEqual("approved"); + }) + )); + }); +}); +``` + +
    + +

    + +## ⚪ ️ 1.8 При необходимости используйте только короткие и последовательные snapshots + +:white_check_mark: **Сделать:** Если существует необходимость в [snapshot testing](https://jestjs.io/docs/en/snapshot-testing), используйте короткие снимки (i.e. 3-7 lines), которые являются частью теста ([Inline Snapshot](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)), а не во внешних файлах. Соблюдение этого правила позволит вашим тестам оставаться понятными и надежными. + +С другой стороны, руководства по "классическим снимкам" призывают хранить большие файлы (например, разметку рендеринга компонента, результат API JSON) на каком-то внешнем носителе и каждый раз при выполнении теста сравнивать полученный результат с сохраненной версией. Это может привести к тому, что, тест будет привязан к огромному количеству данных (например, 1000 строк), о которых разработчик никогда не задумывался. Почему так нельзя делать? аким образом, существует 1000 причин, по которым ваш тест может не пройти - достаточно изменения одной строки, чтобы снимок стал недействительным, а это, скорее всего, будет происходить часто. Как часто? Каждый пробел, комментарий или незначительное изменение HTML/CSS. Мало того, что название теста не дает представления о том, что пошло не так, поскольку он просто проверяет, что 1000 срок кода остались неизменны, так еще и вводит разработчика в заблуждение, заставляя принимать за желаемую истину документ, который он не сможет проверить. Все это является признаками теста, который стремиться захватить сразу многое. + +Стоит отметить, что иногда, такие большие снимки приемлемы - когда проверяется схема, а не данные (извлечение значений и фокус на определенном поле) или при редком изменении документа. +
    + +❌ **Иначе:** UI тест провалился. Код кажется правильным, а на экране отображаются идеальные пиксели. Так что же случилось? Ваше snapshot-тестирование просто обнаружило разницу между исходным документом и текущим полученным - в разметку был добавлен 1 пробел... + +
    + +
    Примеры кода + +
    + +### :thumbsdown: Неправильно: Тестируем невидимые 2000 строк кода + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +it("TestJavaScript.com is renderd correctly", () => { + // Arrange + + // Act + const receivedPage = renderer + .create( + + {" "} + Test JavaScript{" "} + + ) + .toJSON(); + + // Assert + expect(receivedPage).toMatchSnapshot(); + // теперь мы неявно поддерживаем документ длиной в 2000 строк + // каждый дополнительный перенос строки или комментарий приведет к падению этого теста +}); +``` + +
    + +### :clap: Правильно: Здесь все на виду + +```javascript +it("When visiting TestJavaScript.com home page, a menu is displayed", () => { + // Arrange + + // Act + const receivedPage = renderer + .create( + + {" "} + Test JavaScript{" "} + + ) + .toJSON(); + + // Assert + + const menu = receivedPage.content.menu; + expect(menu).toMatchInlineSnapshot(` +
      +
    • Home
    • +
    • About
    • +
    • Contact
    • +
    +`); +}); +``` + +
    + +

    + +## ⚪ ️Копируйте только необходимый код + +:white_check_mark: **Сделать:** Включайте в тест только необходимое, что влияет на результат теста, но не более того. В качестве примера, рассмотрим тест, который должен учитывать 100 строк JSON. Тащить за собой столько строк в каждый тест - утомительно. Если извлекать строки за пределы transferFactory.getJSON(), то тест станет неясным, так как без данных трудно соотнести результат теста и причину (почему он должен вернуть статус 400?). В книге x-unit patterns, такой паттерн называется "таинственный гость" - что-то скрытое повлияло на результат наших тестов, но мы не знаем, что именно. +Для улучшения ситуации, мы можем извлечь повторяющиеся детали, оставляя только то, что имеет значение для теста. Как, например, в данной ситуации: transferFactory.getJSON({sender: undefined}). Здесь видно, что пустое поле отправителя является той самой причиной, которая приведет к ошибке валидации. +
    + +❌ **Иначе:** Копирование огромного количества строк JSON приведет к тому, что ваши тесты станут нечитаемыми и трудно поддерживаемыми. + +
    + +
    Примеры кода + +
    + +### :thumbsdown: Неправильно: Тяжело понять причину ошибки, так как она скрыта от глаз пользователя в большом количестве строк JSON + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +test("When no credit, then the transfer is declined", async () => { + // Arrange + const transferRequest = testHelpers.factorMoneyTransfer(); // вернемся к 200 строкам JSON; + const transferServiceUnderTest = new TransferService(); + + // Act + const transferResponse = await transferServiceUnderTest.transfer( + transferRequest + ); + + // Assert + expect(transferResponse.status).toBe(409); + // Почему мы ждем, что тест упадет, ведь все выглядит корректным 🤔? +}); +``` + +
    + +### :clap: Правильно: В данном случае тест выявляет то, что является причиной конечного результата + +```javascript +test("When no credit, then the transfer is declined ", async () => { + // Arrange + const transferRequest = testHelpers.factorMoneyTransfer({ + userCredit: 100, + transferAmount: 200, + }); // очевидно, что здесь недостаток средств + const transferServiceUnderTest = new TransferService({ + disallowOvercharge: true, + }); + + // Act + const transferResponse = await transferServiceUnderTest.transfer( + transferRequest + ); + + // Assert + expect(transferResponse.status).toBe(409); // Очевидно, что если у пользователя не хватает средств, то все упадет +}); +``` + +
    + +

    + +## ⚪ ️ 1.10 Не отлавливайте ошибки - ожидайте их + +:white_check_mark: **Сделать:** При попытке отловить, что некоторый ввод данных приводит к ошибке, может показаться правильным использование конструкции try-catch-finally и утверждать, что было введено catch. В результате, получается неудобный и объемный тест (пример ниже), который скрывает саму идею теста и получения результата. + +Более элегантной альтернативой является использование однострочного матчера Chai: expect(method).to.throw (или в Jest: expect(method).toThrow()). Обязательно убедитесь, что исключение содержит свойство, которое указывает на тип ошибки, иначе, просто получив общую ошибку, пользователю будет показано сообщение, которое его разочарует. +
    + +❌ **Иначе:** Из отчетов о тестировании (например, отчетов CI) будет сложно сделать вывод о том, что пошло не так + +
    + +
    Примеры кода + +
    + +### :thumbsdown: Неправильно: Объемный тест, который пытается проверить ошибку через try-catch + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +it("When no product name, it throws error 400", async () => { + let errorWeExceptFor = null; + try { + const result = await addNewProduct({}); + } catch (error) { + expect(error.code).to.equal("InvalidInput"); + errorWeExceptFor = error; + } + expect(errorWeExceptFor).not.to.be.null; + // если это утверждение не сработает, то результаты тестов покажут, + // что какое-то значение равно null, а об отсутствующем исключении не будет ни слова +}); +``` + +
    + +### :clap: Правильно: Тест, который может легко понять даже QA или product-менеджер + +```javascript +it("When no product name, it throws error 400", async () => { + await expect(addNewProduct({})) + .to.eventually.throw(AppError) + .with.property("code", "InvalidInput"); +}); +``` + +
    + +

    + +## ⚪ ️ 1.11 Маркируй свои тесты + +:white_check_mark: **Сделать:** Разные тесты должны запускаться по-разному: quick smoke, IO-less, тесты должны запускаться, когда разработчик сохраняет код или делает коммит. Сквозные тесты запускаются при попытке нового pull-request и многое другое. Этого можно достичь, если помечать тесты ключевыми словами #cold, #api, #sanity, чтобы вы могли искать их с помощью вашей системы тестирования и вызывать сразу нужное количество определенных тестов. Например, вот как можно вызвать группу тестов с помощью Mocha: mocha — grep ‘sanity’. +
    + +❌ **Иначе:** Запуск всех существующих тестов, включая тесты, которые выполняют десятки запросов к БД, каждый раз когда разработчик вносит небольшое изменение, может быть медленным и отвлекать разработчиков от тестирования + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Пометка тестов как '#cold-test' позволяет программе выполнять только быстрые тесты (cold===быстрые тесты, которые не делают IO и могут выполняться часто, даже пока разработчик набирает текст). + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +// это быстрый тест, который помечен соотвествующим образом, +// чтобы пользователь или CI могли часто его запускать +describe("Order service", function () { + describe("Add new order #cold-test #sanity", function () { + test("Scenario - no currency was supplied. Expectation - Use the default currency #sanity", function () { + // здесь логика + }); + }); +}); +``` + +
    + +

    + +## ⚪ ️ 1.12 Categorize tests under at least 2 levels + +:white_check_mark: **Сделать:** Придайте набору тестов некую структуру, чтобы любой, кто посмотрит на них, мог легко понять, что происходит (тесты - лучшая документация). Общим методом для этого является размещение как минимум двух блоков "describe" над тестами: первый - для названия тестируемого блока, а второй - для дополнительного разделения тестов, например, сценария или пользовательских категорий (см. примеры кода и скриншот ниже). +Данное разделение также улучшить финальные отчеты по тестированию. Читатель сможет легко разобраться с категориями тестов, найти нужный раздел и понять, где могла возникнуть ошибка. Более того, разработчику будет легче ориентироваться в случае большого количества тестов. Существует несколько способов придать тестам структуру, которое можно найти здесь [given-when-then](https://github.com/searls/jasmine-given) и здесь [RITE](https://github.com/ericelliott/riteway) + +
    + +❌ **Иначе:** При просмотре отчета с длинным и плоским списком тестов приходиться бегло просматривать длинные тексты, чтобы понять основные сценарии и выяснить причину неудачи определенных тестов. Рассмотрим следующий случай: если при наборе в 100 тестов 7 из них окажутся неудачными, то придется прочитать их описание, чтобы понять, как они друг с другом связаны. Однако, если существует разделение на структуры, то причина падения тестов, может быть общей для них и разработчик быстро сделает вывод о том, что стало причиной или, по крайне мере, где она находится. +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Разделение на структуры набора тестов приводит к удобному отчету + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +// тестируемый блок +describe("Transfer service", () => { + // сценарий + describe("When no credit", () => { + // ожидание + test("Then the response status should decline", () => {}); + + // ожидание + test("Then it should send email to admin", () => {}); + }); +}); +``` + +![alt text](assets/hierarchical-report.png) + +
    + +### :thumbsdown: Неправильно: Плоский список тестов усложняет поиск ошибки + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Mocha") + +```javascript +test("Then the response status should decline", () => {}); + +test("Then it should send email", () => {}); + +test("Then there should not be a new transfer record", () => {}); +``` + +![alt text](assets/flat-report.png) + +
    + +
    + +

    + +## ⚪ ️1.13 Дополнительные общие правила по написанию тестов + +:white_check_mark: **Сделать:** Эта заметка посвящена советам по тестированию, которые связаны с Node JS или, по крайней мере, могут быть проиллюстрированы на его примере. Однако в этом пункте сгруппировано несколько советов, не связанных с Node, которые хорошо известны + +Изучайте и практикуйте [принципы TDD](https://www.sm-cloud.com/book-review-test-driven-development-by-example-a-tldr/) — они являются очень ценным инструментов для многих разработчиков, однако не пугайтесь, если они вам не подойдут. Рассмотрите возможность написания тестов до начала разработки в стиле [red-green-refactor style](https://blog.cleancoder.com/uncle-bob/2014/12/17/TheCyclesOfTDD.html), убедитесь, что каждый тест проверяет ровно один смысловой элемент и после того, как вы найдете ошибку, перед тем как ее исправить - напишите тест, который обнаружит эту ошибку в будущем. Пусть каждый тест упадет хотя бы один раз, прежде его цвет станет зеленым. Начните разработку модуля с написания простого и быстрого кода, удовлетворяющего тесту, а после постепенно рефакторите и доведите его до уровня продакшн-кода. Избегайте любой зависимости от окружения (файловые пути, ОС и другое). +
    + +❌ **Иначе:** Мудрость, которая копилась десятилетиями, пройдет мимо вас + +

    + +# Раздел 2️⃣: Тестирование Backend + +## ⚪ ️2.1 Увеличьте разнообразие своих тестов. Не ограничивайте себя только юнит-тестами и пирамидой + +:white_check_mark: **Сделать:** [Пирамида тестирования](https://martinfowler.com/bliki/TestPyramid.html), несмотря на то, что ей уже более 10 лет, является отличной и актуальной моделью, которая предлагает 3 типа тестирования и влияет на стратегию тестирования большинства разработчиков. В то же время, появились методы тестирования, которые скрываются в тени данной пирамиды. Принимая во внимание все кардинальные изменения, которые наблюдались в течение последних 10 лет (микросервисы, облака, бессерверные технологии), встает вопрос: возможно ли применить одну модель тестирования для всех типов приложений? Или может быть лучше рассмотреть возможность внедрения новых практик? + +Не поймите меня неправильно, в 2019 году пирамида тестирования, TDD и юнит-тесты по-прежнему являются мощной техникой и, вероятно, лучше всего подходят для многих приложений. Только, как и любая другая модель, несмотря на свою ценность, [иногда она дает сбои](https://en.wikipedia.org/wiki/All_models_are_wrong). Например, рассмотрим IoT-приложение, которое получает множество событий типа Kafka/RabbitMQ, которые затем попадают в хранилище данных и в конечном итоге запрашиваются аналитическим пользовательским интерфейсом. Действительно ли мы должны тратить 50% бюджета на тестирование на написание модульных тестов для приложения, которое ориентировано на интеграцию и почти не имеет логики. По мере увеличения разнообразия типов приложений (боты, криптовалюты, Alexa-skills) также растут шансы найти такие сценарии, в которых пирамида тестирования не является идеальным решением. + +Пришло время увеличить свое портфолио тестировщика и познакомиться еще большим количеством подходов к написанию тестов (следующие пункты содержат определенные идеи), начать использовать модели тестирования, подобные пирамиде и также научится сопоставлять типы тестирования с реальными проблемами, с которыми вы можете столкнуться ("Эй, наш API сломан, давайте напишем тестирование контрактов, ориентированное на потребителя!"). Необходимо также научиться диверсифицировать свои тесты, как инвестор, который создает портфель на основе анализа рисков - оценить, где могут возникнуть проблемы, и подобрать превентивные меры для снижения этих потенциальных рисков. + +Предостережение: спор о TDD в мире программного обеспечения принимает типичный облик ложной дихотомии: одни проповедуют его повсеместное использование, другие считают, что это дьявол. Каждый, кто абсолютно уверен в чем то одном - ошибается :] +
    + +❌ **Иначе:** Вы можете пропустить такие инструменты, как Fuzz, Lint и мутации, которые могут принести пользу за 10 минут. + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Синди Шридхаран предлагает большое разнообразие подходов к тестированию в своем замечательном посте ‘Testing Microservices — the same way’. + +![alt text](assets/bp-12-rich-testing.jpeg "Cindy Sridharan suggests a rich testing portfolio in her amazing post ‘Testing Microservices — the sane way’") + +☺️Пример: [YouTube: “Beyond Unit Tests: 5 Shiny Node.JS Test Types (2018)” (Yoni Goldberg)](https://www.youtube.com/watch?v=-2zP494wdUY&feature=youtu.be) + +
    + +![alt text](assets/bp-12-Yoni-Goldberg-Testing.jpeg "A test name that constitutes 3 parts") + +
    + +

    + +## ⚪ ️2.2 Тестирование компонентов может стать вашим лучшим другом + +:white_check_mark: **Сделать:** Каждый модульный тест покрывает небольшую часть приложения. Покрыть его целиком является дорогим удовольствием, в то время как сквозное тестирование легко покрывает большую часть приложения, но является нестабильным и медленным. Почему бы не применить сбалансированный подход, и не писать тесты, которые по размеру больше, чем модульные, но меньше, чем сквозное тестирование. Компонентное тестирование - это то, что вобрало в себя лучшее из двух перечисленных подходов. Одно сочетает в себе разумную производительность и возможность применения паттернов TDD, а также реалистичное и большое покрытие. + +Компонентные тесты фокусируются на "единице" микросервиса, они работают с API, не имитируют ничего, что принадлежит самому микросервису (например, реальную БД или, по крайней мере, ее версию в памяти), но затыкают все, что является внешним, например, вызовы других микросервисов. Поступая таким образом, мы тестируем то, что развертываем, подходим к приложению от внешнего к внутреннему и обретаем большую уверенность за разумное время. + +[У нас есть полное руководство, которое посвящено исключительно написанию компонентных тестов правильным способом](https://github.com/testjavascript/nodejs-integration-tests-best-practices) + +
    + +❌ **Иначе:** Вы можете потратить огромное количество времени на написание модульных тестов и обнаружить, что покрытие системы составляет всего 20%. + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Supertest позволяет приближаться к Express API в процессе (с высокой скоростью и широким охватом уровней) + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +![alt text](assets/bp-13-component-test-yoni-goldberg.png " [Supertest](https://www.npmjs.com/package/supertest) allows approaching Express API in-process (fast and cover many layers)") + +
    + +

    + +## ⚪ ️2.3 Убедитесь, что новые релизы не нарушают API, используя контрактные тесты + +:white_check_mark: **Сделать:** Итак, у вашего микросервиса есть несколько клиентов, и вы запускаете несколько версий сервиса из соображений совместимости (чтобы все были довольны). Затем вы изменяете какое-то поле и "бум!", какой-то важный клиент, который полагается на это поле, возмущен. Это и есть Catch-22 в мире интеграции: Для серверной стороны очень сложно учесть все многочисленные ожидания клиентов— С другой стороны, клиенты не могут провести никакого тестирования, потому что сервер контролирует даты выпуска. Существует целый ряд методов, которые могут смягчить проблему контрактов, некоторые из них просты, другие более функциональны и требуют более сложного обучения. +При простом подходе, API предоставляется вместе с npm-пакетом с типизацией (JSDoc, TypeScript). Потребители данного пакета могут получить библиотеку и воспользоваться преимуществами автодополнения (IntelliSense) и валидация во время разработки. Более сложный подход включает в себя [PACT](https://docs.pact.io/), который был создан для формализации этого процесса с помощью очень разрушительного подхода - не сервер определяет план тестирования для себя, а клиент определяет тесты для... сервера! PACT может записывать ожидания клиента и помещать их в общее место, "broker", так что сервер может извлекать эти ожидания и запускать на каждой сборке, используя библиотеку PACT, чтобы обнаружить нарушенные контракты - ожидания клиента, которые не выполнены. Таким образом, все несоответствия API сервера и клиента будут обнаружены на ранних стадиях сборки и могут уберечь разработчика от больших проблем. +
    + +❌ **Иначе:** Альтернативой является ручное тестирование или развертывание + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: + +![](https://img.shields.io/badge/🔧%20Example%20using%20PACT-blue.svg "Examples with PACT") + +![alt text](assets/bp-14-testing-best-practices-contract-flow.png) + +
    + +

    + +## ⚪ ️ 2.4 Тестируйте middlewares изолированно + +:white_check_mark: **Сделать:** Большинство разработчиков пренебрегают тестированием Middleware, потому что они являются небольшой частью системы и требуют живого сервера Express. Обе причины ошибочны, так как Middleware, несмотря на свой размер, имеют огромное влияние на все или большинство запросов и могут быть легко протестированы, как чистые функции. Для тестирования функции middleware нужно просто вызвать ее и "шпионить" ([например, с помощью Sinon](https://www.npmjs.com/package/sinon)) за взаимодействием с объектами {req,res}, чтобы убедиться, что функция отработала корректно. Библиотека [node-mock-http](https://www.npmjs.com/package/node-mocks-http) идет еще дальше и анализирует объекты {req,res}, а также следит за их поведением. Например, он может утверждать, соответствует ли статус http, который был установлен на объекте res, ожидаемому (см. пример ниже). +
    + +❌ **Иначе:** Ошибка в middleware Express === ошибка большинства/всех запросов + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Тестирование middleware изолированно без выполнения сетевых запросов и включения Express полностью + +![](https://img.shields.io/badge/🔧%20Example%20using%20Jest-blue.svg "Examples with Jest") + +```javascript +// middleware, которое мы хотим протестировать +const unitUnderTest = require("./middleware"); +const httpMocks = require("node-mocks-http"); +// синтаксис в Jest, равный describe() и it() в Mocha +test("A request without authentication header, should return http status 403", () => { + const request = httpMocks.createRequest({ + method: "GET", + url: "/user/42", + headers: { + authentication: "", + }, + }); + const response = httpMocks.createResponse(); + unitUnderTest(request, response); + expect(response.statusCode).toBe(403); +}); +``` + +
    + +

    + +## ⚪ ️2.5 Измерение и рефакторинг с использованием инструментов статистического анализа + +:white_check_mark: **Сделать:** Использование инструментов статического анализа помогает объективно улучшить качество кода и сохранить его работоспособность. Вы можете добавить инструменты статистического анализа в сборку CI, чтобы отследить "запахи" вашего кода на этапе сборки. Основными преимуществами статического анализа перед обычным линтингом являются возможность проверки качества в контексте нескольких файлов (например, обнаружение дубликатов), выполнение расширенного анализа (например, сложности кода) и отслеживание истории и прогресса проблем кода. Вы можете использовать следующие сервисы: [SonarQube](https://www.sonarqube.org/) (4,900+ [stars](https://github.com/SonarSource/sonarqube)) и [Code Climate](https://codeclimate.com/) (2,000+ [stars](https://github.com/codeclimate/codeclimate)) + +Благодарность: [Keith Holliday](https://github.com/TheHollidayInn) + +
    + +❌ **Иначе:** При низком качестве кода ошибки и производительность всегда будут проблемой, которую не смогут исправить ни новые библиотеки, ни современный функционал. + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: CodeClimate - это инструмент, который предоставляет комплексные методы анализа + +![](https://img.shields.io/badge/🔧%20Example%20using%20Code%20Climate-blue.svg "Examples with CodeClimate") + +![alt text](assets/bp-16-yoni-goldberg-quality.png "CodeClimate, a commercial tool that can identify complex methods:") + +
    + +

    + +## ⚪ ️ 2.6 Check your readiness for Node-related chaos + +:white_check_mark: **Сделать:** Странно, но большинство тестов направлено на проверку логики и данных, в то время как иногда наибольшей проблемой (и это правда трудно исправить) может стать вопросы, касающиеся инфраструктуры. Например, вы когда-нибудь тестировали перегрузку памяти, падение сервера? Ваша система отслеживания понимает, когда ваш API становится в половину медленнее? Для того, чтобы протестировать и исправить такие ситуации Netflix придумали [Chaos engineering](https://principlesofchaos.org/). Его целью является осведомленность для тестирования устойчивости приложения к chaos-проблемам, а также различные фреймворки, чтобы это можно было протестировать. Например, один из его известных инструментов, [the chaos monkey](https://github.com/Netflix/chaosmonkey), случайным образом кладет серверы, чтобы убедиться, что наш сервис все еще может обслуживать пользователей и не полагается на один сервер (есть также версия для Kubernetes, [kube-monkey](https://github.com/asobti/kube-monkey)). Все эти инструменты работают на уровне хостинга или платформы, но что, если вы хотите протестировать чистейший Node-хаос. Например, вы хотите проверить, как ваш Node справляется с ошибками, которые были не пойманы, ошибками промисов, перегрузкой v8 при максимально допустимых 1.7GB. Вдруг вы хотите проверить, остается ли ваш UX удовлетворительных при частых блокировках цикла событий? Для решения данной проблемы я написал [node-chaos](https://github.com/i0natan/node-chaos-monkey) (alpha), который генерирует все возможные виды хаоса, связанных с Node. +
    + +❌ **Иначе:** От этого не спрятаться. Закон Мерфи будет преследовать вас везде. + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Генерация всевозможных вариантов Node-хаоса для проверки устойчивости приложения + +![alt text](assets/bp-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") + +
    + +
    + +## ⚪ ️2.7 Избегайте использования глобальных фикстур и seeds. Для каждого теста должны быть свои собственные данные + +:white_check_mark: **Сделать:** Согласно золотому правилу (пункт 0), каждый тест должен использовать свой собственный набор строк в БД, чтобы избежать перекрытия данных. На деле же, данное правило часто нарушается тестировщиками, которые загружают данные в БД перед запуском тестов (фикстуры), чтобы улучшить производительность. Хотя производительность является реальной причиной для беспокойства - она далеко не главная (см. пункт "Компонентное тестирование"). Сложность тестирования - гораздо более болезненная проблема, решение которой в большинстве случаев определяется другими соображениями. На практике, нужно сделать так, чтобы каждый тест явным образом добавляет нужные ему записи в БД и работал только с ними. Если производительность становится критической проблемой - компромиссом может быть реализация тестов, которые не изменяют данные (например, запросы). +
    + +❌ **Иначе:** Какие-то тесты не сработали, развертывание проекта прервано и разработчики тратят время на выяснение ошибки. А есть ли она? Кажется, что нет, ведь два теста просто изменили одни и те же seed-данные. + +
    + +
    Примеры кода + +
    + +### :thumbsdown: Неправильно: тесты не являются независимыми и полагаются на некий глобальный хук для получения глобальных данных + +![](https://img.shields.io/badge/🔧%20Example%20using%20Mocha-blue.svg "Examples with Mocha") + +```javascript +before(async () => { + // добавление данных о сайтах и администраторах в БД. Где они сейчас находятся? Снаружи, во внешнем JSON или фреймворке + await DB.AddSeedDataFromJson("seed.json"); +}); +it("When updating site name, get successful confirmation", async () => { + // я знаю, что название сайта "portal" существует - я видел его в seed-файлах + const siteToUpdate = await SiteService.getSiteByName("Portal"); + const updateNameResult = await SiteService.changeName( + siteToUpdate, + "newName" + ); + expect(updateNameResult).to.be(true); +}); +it("When querying by site name, get the right site", async () => { + // я знаю, что название сайта "portal" существует - я видел его в seed-файлах + const siteToCheck = await SiteService.getSiteByName("Portal"); + expect(siteToCheck.name).to.be.equal("Portal"); // Неудача! Предыдущий тест меняет название :[ +}); +``` + +
    + +### :clap: Правильно: Каждый тест действует на своем собственном наборе данных, что позволяет оставаться в рамках теста + +```javascript +it("When updating site name, get successful confirmation", async () => { + // тест добавляет новые записи и работает только с ними + const siteUnderTest = await SiteService.addSite({ + name: "siteForUpdateTest", + }); + const updateNameResult = await SiteService.changeName( + siteUnderTest, + "newName" + ); + expect(updateNameResult).to.be(true); +}); +``` + +
    + +
    + +## ⚪ ️2.8 Выберите четкую стратегию очистки данных: After-all (рекомендуется) или after-each + +:white_check_mark: **Сделать:** Время, когда тесты начинают удаление данных, определяет способ их написания. Наиболее жизнеспособные варианты: after-all и after-each. При выборе второго варианта, удаление данных гарантирует полную очистку и создает преимущества для разработчика. В начале теста не существует других записей. Можно быть уверенным, какие данные запрашиваются. Иногда даже возникает соблазн посчитать строки при проверке assertions. Однако, существуют и серьезные недостатки. При работе в мульти-процессном режиме тесты могут мешать друг другу. Пока процесс-1 очищает таблицы, процесс-2 в тот же момент запрашивает данные и падает (потому что БД была внезапно удалена процессом-1). Кроме того, сложнее исправить проблемы в неудачных тестах - при посещении БД не будет обнаружено никаких записей. + +Второй вариант - это after-all - удаление данных после завершения всех тестов (или даже ежедневно!). Такой подход означает, что одна и та же БД с существующими записями служит для всех процессов и тестов. Чтобы не наступать друг другу на пятки, тесты должны работать с конкретными записями, которые они добавили. Нуждаетесь в проверке, какая запись была добавлена? Предположите, что есть еще тысячи записей, и сделайте запрос к записи, которая была добавлена явно. Нужно проверить, что запись удалена? Нельзя предполагать, что таблица пуста - проверьте, что этой конкретной записи там нет. Такая техника дает несколько преимуществ: она работает мульти-процессном режиме, когда разработчик хочет понять, что произошло - данные есть и не удалены. Также это увеличивает шанс найти ошибки так как БД полна записей. [Смотрите полную таблицу сравнений здесь](https://github.com/testjavascript/nodejs-integration-tests-best-practices/blob/master/graphics/db-clean-options.png). +
    . + +❌ **Иначе:** При отсутствии разделения записей или удаления - тесты будут наступать на пятки сами себе. Использование транзакций работает только в реляционных БД и, при появлении внутренних транзакций, может стать сложнее. + +
    + +
    Примеры кода + +
    + +### :clap: After-all: Необязательно удалять данные после каждого запуска. Чем больше данных у нас есть во время выполнения тестов, тем больше это похоже на продакшн. + +```javascript +// after-all очистка (рекомендуется) +// global-teardown.js +module.exports = async () => { + // ... + if (Math.ceil(Math.random() * 10) === 10) { + await new OrderRepository().cleanup(); + } +}; +``` + +
    + +
    + +## ⚪ ️2.9 Изолируйте компонент с помощью HTTP-перехватчика + +:white_check_mark: **Сделать:** Изолируйте тестируемый компонент, перехватывая любой исходящий HTTP-запрос и предоставляя желаемый ответ, чтобы HTTP API не пострадал. Nock - отличный инструмент для этой задачи, поскольку он предоставляет удобный синтаксис для определения поведения внешних сервисов. Изоляция необходима для предотвращения шума и снижения производительности, но в основном для моделирования различных сценариев и ответов - хороший симулятор полета не рисует чистое голубое небо, а приносит спокойные бури. Это усиливается в микросервисной архитектуре, где фокус всегда должен быть сосредоточен на одном компоненте без привлечения остальных. Хотя можно имитировать поведение внешнего сервиса с помощью тестов-двойников (mocking), предпочтительнее не трогать развернутый код и действовать на сетевом уровне, чтобы тесты были чисто "черным ящиком". Недостатком изоляции является невозможность обнаружения изменений в компоненте коллаборатора и недопонимания между двумя сервисами - обязательно компенсируйте это с помощью нескольких контрактных или E2E-тестов. +
    + +❌ **Иначе:** Некоторые сервисы предоставляют фейк-версию, которая может быть развернута локально, обычно с помощью Docker-Это сделает настройку легче и увеличит производительность. Однако, это не решит проблему моделирования различных responses. Некоторые сервисы предоставляют "песочницу" таким образом, что реальный сервис работает, но без побочных эффектов. Такой вариант не поможет моделировать различные сценарии и снизить шум. + +
    + +
    Примеры кода + +
    + +### :clap: Предотвращение сетевых обращений к внешним компонентам позволяет моделировать сценарии и минимизировать шум + +````javascript +// перехват запросов к стороннему API и возврат заранее определенного ответа +beforeEach(() => { + nock('http://localhost/user/').get(`/1`).reply(200, { + id: 1, + name: 'John', + }); +});``` +```` + +
    + +
    + +## ⚪ ️2.10 Тестируйте схему ответа в основном при наличии автоматически генерируемых полей + +:white_check_mark: **Сделать:** Если невозможно подтвердить наличие определенных данных, проверяйте наличие и типы обязательных полей. Иногда ответ может содержать важные поля с динамическими данными, которые невозможно предугадать при написании теста, такие как даты. В случае, когда точно известно, что поля не будут иметь значения null, а также будут содержать правильные типы, то все равно нужно обязательно это проверить. Большинство библиотек поддерживают проверку типов. Если ответ - небольшой, то можно выполнить проверку в рамках одного утверждения (см. пример кода). Другой вариант - проверка полного ответа по OpenAPI (Swagger). Большинство фреймворков для тестирования имеют расширения, которые проверяют ответы API, согласно их документации. + +
    + +❌ **Иначе:** Несмотря на то, что вызывающий код или API полагается на некоторое поле с динамическими данными (например, ID или дата), оно может не вернуться в ответе + +
    + +
    Примеры кода + +
    + +### :clap: Проверка, что поля с динамическим значением существуют и имеют правильный тип + +```javascript +test("When adding a new valid order, Then should get back approval with 200 response", async () => { + // ... + // Assert + expect(receivedAPIResponse).toMatchObject({ + status: 200, + data: { + id: expect.any(Number), // Any number satisfies this test + mode: "approved", + }, + }); +}); +``` + +
    + +
    + +## ⚪ ️2.12 Проверка крайних случаев интеграции + +:white_check_mark: **Сделать:** При проверке интеграций нельзя ограничиваться только проверками либо "happy", либо "sad" вариантов. Помимо проверки на ошибки (например, HTTP 500), нужно так же смотреть на аномалии на уровне сети или скорость ответов таймера. Это демонстрирует то, что ваш код устойчив и может обрабатывать различные сетевые сценарии. Надежные перехватчики могут легко имитировать различное поведение сетевого взаимодействия. Он даже может понять, когда стандартное значение тайм-аута HTTP-клиента больше, чем смоделированное время ответа, и сразу же бросить исключение по тайм-ауту, не дожидаясь ответа. + +
    + +❌ **Иначе:** Все тесты пройдут, однако, продакшн не сможет корректно сообщить об ошибке, когда со стороны будут приходить исключения + +
    + +
    Примеры кода + +
    + +### :clap: Подтверждение, что при сбоях в сети, автоматический выключатель может спасти ситуацию + +```javascript +test("When users service replies with 503 once and retry mechanism is applied, then an order is added successfully", async () => { + // Arrange + nock.removeInterceptor(userServiceNock.interceptors[0]); + nock("http://localhost/user/") + .get("/1") + .reply(503, undefined, { "Retry-After": 100 }); + nock("http://localhost/user/").get("/1").reply(200); + const orderToAdd = { + userId: 1, + productId: 2, + mode: "approved", + }; + + // Act + const response = await axiosAPIClient.post("/order", orderToAdd); + + // Assert + expect(response.status).toBe(200); +}); +``` + +
    + +
    + +## ⚪ ️2.13 Тестируйте не менее 5 потенциально возможных результатов + +:white_check_mark: **Сделать:** При разработке тестов, продумайте, как минимум, охватить 5 потоков вывода. Когда ваш тест вызывает какой-то действие (например, вызов API), возникает ситуация, когда нужно протестировать результат этого действия. Важно понимать, что нас не интересует, как все работает. Наше внимание сосредоточено на конечном результате, на том, что может повлиять на пользователя. Конечные результаты можно разделить на следующие категории: + +• Ответ - Тест вызывает действие (например, через API) и получает ответ. Теперь он занимается проверкой корректности данных ответа, схемы и статуса HTTP. + +• Новое состояние - После вызова действия некоторые **общедоступные** данные, вероятно, будут изменены. + +• Внешние вызовы - После вызова действия приложение может вызвать внешний компонент через HTTP или любой другой транспорт. Например, вызов для отправки SMS, электронной почты или списания средств с кредитной карты. + +• Очереди сообщений - Результатом потока может быть сообщение в очереди. + +• Наблюдаемость - Некоторые вещи необходимо отслеживать, например, ошибки или значимые бизнес-события. Когда транзакция терпит неудачу, мы ожидаем не только правильного ответа, но и корректной обработки ошибок и правильного протоколирования/метрики. Эта информация поступает непосредственно к очень важному пользователю - оперативному пользователю (т.е. производственному SRE/админу). + +
    + +

    + +# Раздел 3️⃣: Тестирование Frontend + +## ⚪ ️ 3.1 Отделите пользовательский интерфейс от функциональности + +:white_check_mark: **Сделать:** Когда вы фокусируетесь на тестировании логики компонентов, детали пользовательского интерфейса становятся шумом, который необходимо удалить, чтобы ваши тесты могли сосредоточиться на чистых данных. Извлекайте нужные данные из разметки абстрактным способом, не слишком связанным с графической реализацией, тестируйте только чистые данные (в отличие от графических деталей HTML/CSS) и отключайте анимацию, которая замедляет работу. У вас может возникнуть соблазн избежать рендеринга и тестировать только заднюю часть пользовательского интерфейса (например, сервисы, действия, магазин), но это приведет к фиктивным тестам, которые не похожи на реальность и не выявят случаи, когда нужные данные даже не попадают в пользовательский интерфейс. + +
    + +❌ **Иначе:** Чистые расчетные данные вашего теста могут быть готовы за 10 мс, но тогда весь тест будет длиться 500 мс (100 тестов = 1 мин) из-за не имеющей отношения к делу анимации. + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Разделение пользовательского интерфейса + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +test("When users-list is flagged to show only VIP, should display only VIP members", () => { + // Arrange + const allUsers = [ + { id: 1, name: "Yoni Goldberg", vip: false }, + { id: 2, name: "John Doe", vip: true }, + ]; + + // Act + const { getAllByTestId } = render( + + ); + + // Assert - сперва извлеките данные из UI + const allRenderedUsers = getAllByTestId("user").map( + (uiElement) => uiElement.textContent + ); + const allRealVIPUsers = allUsers + .filter((user) => user.vip) + .map((user) => user.name); + expect(allRenderedUsers).toEqual(allRealVIPUsers); // сравнение данных +}); +``` + +
    + +### :thumbsdown: Неправильно: Совместное тестирование компонентов UI и данных + +```javascript +test("When flagging to show only VIP, should display only VIP members", () => { + // Arrange + const allUsers = [ + { id: 1, name: "Yoni Goldberg", vip: false }, + { id: 2, name: "John Doe", vip: true }, + ]; + + // Act + const { getAllByTestId } = render( + + ); + + // Assert - использование UI и данных в assertion + expect(getAllByTestId("user")).toEqual( + '[
  • John Doe
  • ]' + ); +}); +``` + +
    + +

    + +## ⚪ ️ 3.2 Запрашивать элементы HTML на основе атрибутов, которые вряд ли изменятся + +:white_check_mark: **Сделать:** Запрашивайте элементы HTML на основе атрибутов, которые, скорее всего, переживут графические изменения, в отличие от селекторов CSS и, например, меток формы. Если заданный элемент не имеет таких атрибутов, создайте специальный тестовый атрибут, например 'test-id-submit-button'. Такой путь не только гарантирует, что ваши функциональные/логические тесты никогда не сломаются из-за изменений внешнего вида, но и даст понять, что данный элемент и атрибут используются тестами и не должны быть удалены. + +
    + +❌ **Иначе:** Вы хотите протестировать функциональность входа в систему, которая охватывает множество компонентов, логики и сервисов, все настроено идеально - stubs, spies, вызовы Ajax изолированы. Все кажется идеальным. Затем тест не проходит, потому что дизайнер изменил CSS-класс div с "thick-border" на "thin-border". + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Запрос элемента с использованием специального атрибута для тестирования + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") + +```html +// код разметки (часть компонента React) +

    + + {value} + + +

    +``` + +```javascript +// в данном примере используется react-testing-library +test("Whenever no data is passed to metric, show 0 as default", () => { + // Arrange + const metricValue = undefined; + + // Act + const { getByTestId } = render(); + + expect(getByTestId("errorsLabel").text()).toBe("0"); +}); +``` + +
    + +### :thumbsdown: Неправильно: Надежда на CSS-атрибуты + +```html + +{value} + +``` + +```javascript +// в данном примере используется enzyme +test("Whenever no data is passed, error metric shows zero", () => { + // ... + + expect(wrapper.find("[className='d-flex-column']").text()).toBe("0"); +}); +``` + +
    + +
    + +## ⚪ ️ 3.3 По возможности тестируйте с реалистичным компонентом, после рендеринга + +:white_check_mark: **Сделать:** При любом разумном размере нужно тестировать компонент снаружи, как это делают пользователи. Полностью рендерите UI и проверяйте, что он ведет себя, как ожидается. Избегайте мокинга и частичного рендеринга - такой подход может привести к невыявленным ошибкам из-за недостатка деталей и сделать поддержку сложнее, так как тесты начинают влиять на внутренние компоненты (смотри пункт ['Favour blackbox testing'](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-14-stick-to-black-box-testing-test-only-public-methods)). Если один из дочерних компонентов значительно замедляет работу (например, анимация) или усложняет настройку - подумайте о явной замене его на фейковый. + +Учитывая все вышесказанное, следует сказать: эта техника работает для небольших/средних компонентов, которые содержат разумное количество дочерних компонентов. Полный рендеринг компонента со слишком большим количеством дочерних компонентов повлечет за собой трудности в анализе (анализ первопричины) и может стать слишком медленным. В таких случаях пишите несколько тестов на один большой родительский компонент и больше тестов на дочерние компоненты. + +
    + +❌ **Иначе:** Если залезть во внутренности компонента, вызывая его приватные методы, и проверить - вам придется рефакторить все тесты в случае изменения реализации компонента. У вас действительно есть возможности для такого уровня сопровождения? + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Полностью реалистичные компоненты после рендеринга + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Enzyme-blue.svg "Examples with Enzyme") + +```javascript +class Calendar extends React.Component { + static defaultProps = { showFilters: false }; + + render() { + return ( +
    + A filters panel with a button to hide/show filters + +
    + ); + } +} + +// в примерах используются React & Enzyme +test("Realistic approach: When clicked to show filters, filters are displayed", () => { + // Arrange + const wrapper = mount(); + + // Act + wrapper.find("button").simulate("click"); + + // Assert + expect(wrapper.text().includes("Choose Filter")); + // так пользователь будет обращаться к этому элементу +}); +``` + +### :thumbsdown: Неправильно: Мокинг данных и частичный рендеринг + +```javascript +test("Shallow/mocked approach: When clicked to show filters, filters are displayed", () => { + // Arrange + const wrapper = shallow( + + ); + + // Act + wrapper.find("filtersPanel").instance().showFilters(); + // обратитесь к внутренним компонентам, не затрагивая UI и вызовите метод (white-box) + + // Assert + expect(wrapper.find("Filter").props()).toEqual({ title: "Choose Filter" }); + // что если мы изменим имя свойства или ничего не передадим +}); +``` + +
    + +
    + +## ⚪ ️ 3.4 Используйте встроенную по фреймворки поддержку асинхронного кода. Постарайтесь ускорить работу. + +:white_check_mark: **Сделать:** Во многих случаях время завершения тестируемого блока просто неизвестно (например, анимация приостанавливает появление элемента) - в этом случае предпочитайте детерминированные методы, которые предоставляют большинство платформ. Некоторые библиотеки позволяют ожидать выполнение операций (например, [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), другие предоставляют API для ожидания, например [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). Иногда более элегантным способом является заглушка, использованная вместо медленно выполняющегося компонента, например, API, а затем, когда момент получения ответа станет детерминированным, компонент можно отрендерить явным способом. Если существует зависимость от какого-то "спящего" компонента, то может оказаться полезным [поторопить часы](https://jestjs.io/docs/en/timer-mocks). Спящий компонент - это паттерн, которого следует избегать, поскольку он заставляет ваш тест быть медленным (при слишком коротком периоде ожидания). Когда спящий режим неизбежен, а поддержка со стороны фреймворка для тестировании отсутствует, некоторые библиотеки npm, такие как [wait-for-expect](https://www.npmjs.com/package/wait-for-expect), могут помочь с полудетерминированным решением. +
    + +❌ **Иначе:** При длительном спящем режиме тесты будут работать на порядок медленнее. Попытка "заснуть" на небольшое количество времени приведет к тому, что тест будет падать, каждый раз, когда тестируемый модуль не отреагировал вовремя. Таким образом, все сводится к компромиссу между хрупкостью и плохой производительностью. +
    + +
    Примеры кода + +
    + +### :clap: Правильно: E2E API, который разрешается только после выполнения асинхронных операций (Cypress) + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") +![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +// используем Cypress +cy.get("#show-products").click(); // перейдите по ссылке +cy.wait("@products"); // дождитесь появления маршрута +// эта строка будет выполнена только тогда, когда маршрут будет готов +``` + +### :clap: Правильно: Библиотека для тестирования, которая ожидает элементы DOM + +```javascript +// @testing-library/dom +test("movie title appears", async () => { + // элемент изначально отсуствует... + + // ожидайте появления + await wait(() => { + expect(getByText("the lion king")).toBeInTheDocument(); + }); + + // дождаться появления и вернуть элемент + const movie = await waitForElement(() => getByText("the lion king")); +}); +``` + +### :thumbsdown: Неправильно: Пользовательский код + +```javascript +test("movie title appears", async () => { + // элемент изначально отсуствует... + + // пользовательская логика (внимание: упрощенная, без timeout) + const interval = setInterval(() => { + const found = getByText("the lion king"); + if (found) { + clearInterval(interval); + expect(getByText("the lion king")).toBeInTheDocument(); + } + }, 100); + + // дождаться появления и вернуть элемент + const movie = await waitForElement(() => getByText("the lion king")); +}); +``` + +
    + +
    + +## ⚪ ️ 3.5 Наблюдайте за тем, как контент передается по сети + +![](https://img.shields.io/badge/🔧%20Example%20using%20Google%20LightHouse-blue.svg "Examples with Lighthouse") + +✅ **Сделать:** Примените какой-нибудь активный монитор, который обеспечит оптимизацию загрузки страницы а сети - это включает любые проблемы UX, такие как медленная загрузка страницы. Существует большое количество инструментов для проверки, таких как: [pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/). Они могут быть легко настроены для наблюдения за тем, жив ли сервер и отвечает ли он в рамках SLA. Это лишь поверхностный обзор того, что может пойти не так, поэтому предпочтительнее выбирать инструменты, специализирующиеся на фронтенде (например, [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)), которые выполняют более качественный анализ. В центре внимания должны быть метрики, которые непосредственно влияют на UX, такие как время загрузки страницы, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [время, пока страница не станет интерактивной (TTI)](https://calibreapp.com/blog/time-to-interactive/). Кроме того, можно также следить за техническими причинами, такими как cжатие контента, время до первого байта, оптимизация изображений, обеспечение разумного размера DOM, SSL и многие другие. Желательно придерживаться этого правила, как во время разработки, так и в рамках CI и, самое главное, постоянно на продакшн-серверах/CDN. +
    + +❌ **Иначе:** Будет обидно осознавать, что после такой тщательной проработки пользовательского интерфейса, 100% прохождения функциональных тестов и сложной комплектации - UX ужасен и медлителен из-за неправильной настройки CDN. + +
    + +
    Примеры кода + +### :clap: Правильно: Использование Lighthouse для проверки загрузки страницы + +![](/assets/lighthouse2.png "Lighthouse page load inspection report") + +
    + +
    + +## ⚪ ️ 3.6 Заглушите нестабильные и медленные ресурсы, как backend API + +:white_check_mark: **Сделать:** При написании основных тестов (не E2E-тестов) избегайте привлечения ресурсов, которые находятся вне вашей ответственности и контроля, таких как бэкенд API, и используйте вместо них заглушки (т.е. test double). Вместо реальных сетевых вызовов API, используйте какую-нибудь библиотеку test double (например, [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble) и т.д.) для создания заглушки ответа API. Основным преимуществом является предотвращение флейкинга - тестовые или staging API по определению не очень стабильны и время от времени будут проваливать ваши тесты, хотя компонент ведет себя просто отлично (production env не был предназначен для тестирования и обычно ограничивает запросы). Это позволит смоделировать различное поведение API, которое должно определять поведение вашего компонента, например, когда данные не найдены или когда API выдает ошибку. И последнее, но не менее важное: сетевые вызовы значительно замедлят работу тестов + +
    + +❌ **Иначе:** Средний тест длится не более нескольких мс, типичный вызов API длится 100 мс>, это делает каждый тест в ~20 раз медленнее. + +
    + +
    Примеры кода + +
    + +### :clap: Doing It Right Example: Stubbing or intercepting API calls + +![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") + +```javascript +// Тестируемый блок +export default function ProductsList() { + const [products, setProducts] = useState(false); + + const fetchProducts = async () => { + const products = await axios.get("api/products"); + setProducts(products); + }; + + useEffect(() => { + fetchProducts(); + }, []); + + return products ? ( +
    {products}
    + ) : ( +
    No products
    + ); +} + +// тест +test("When no products exist, show the appropriate message", () => { + // Arrange + nock("api").get(`/products`).reply(404); + + // Act + const { getByTestId } = render(); + + // Assert + expect(getByTestId("no-products-message")).toBeTruthy(); +}); +``` + +
    + +
    + +## ⚪ ️ 3.7 Используйте мало сквозных тестов, которые охватывают всю систему + +:white_check_mark: **Сделать:** Несмотря на то, что E2E (end-to-end) обычно означает тестирование только пользовательского интерфейса с помощью реального браузера (см. [пункт 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)), для других - это означает тесты, которые охватывают всю систему, включая реальный backend. Последний тип тестов является очень ценным, так как он покрывает ошибки интеграции между frontend и backend, которые могут возникнуть из-за неправильного понимания схемы обмена. Они также являются эффективным методом обнаружения проблем интеграции между бэкендами (например, микросервис A посылает неверное сообщение микросервису B) и даже выявления сбоев развертывания - не существует бэкенд-фреймворков для тестирования E2E, которые были бы настолько же дружественными и зрелыми, как UI-фреймворки, такие как [Cypress](https://www.cypress.io/) и [Puppeteer](https://github.com/GoogleChrome/puppeteer). Недостатком таких тестов является высокая стоимость настройки среды с таким количеством компонентов, а также их хрупкость - при наличии 50 микросервисов, даже если один из них откажет, то весь E2E просто не работает. По этой причине мы должны использовать данный подход очень экономно и, вероятно, иметь 1-10 таких тестов и не более. Тем не менее, даже небольшое количество тестов E2E, скорее всего, выявит те проблемы, на которые они нацелены - ошибки развертывания и интеграции. Рекомендуется запускать такие тесты на продакшене. + +
    + +❌ **Иначе:** Пользовательский интерфейс может хорошо справляться с тестированием своей функциональности, но поздно понять, что схема данных, с которой должен работать UI, отличается от ожидаемой. + +
    + +## ⚪ ️ 3.8 Ускорение тестов E2E за счет использования повторного использования данных для входа в систему + +:white_check_mark: **Сделать:** В тестах E2E, которые задействуют реальный backend и полагаются на валидный пользовательский токен для вызовов API, не нужно изолировать тест до уровня, на котором пользователь создается и регистрируется при каждом запросе. Вместо этого, авторизуйтесь только один раз перед началом выполнения теста (т.е. before-all hook), сохраните токен в каком-нибудь локальном хранилище и используйте его повторно во всех запросах. Может казаться, что это нарушает один из основных принципов тестирования - сохранять автономность теста без привязки к ресурсам. Хотя это обоснованное беспокойство, в тестах E2E производительность является ключевым фактором, и создание 1-3 запросов API перед запуском каждого отдельного теста может привести к большому времени выполнения. Повторное использование учетных данных не означает, что тесты должны работать с одними и теми же пользовательскими записями - если вы полагаетесь на пользовательские записи (например, история платежей пользователя), убедитесь, что эти записи создаются в рамках теста, и не делитесь их существованием с другими тестами. Также помните, что на backend может стоять заглушка - если ваши тесты сосредоточены на фронтенде, возможно, лучше изолировать его и заглушить API бэкенда (см. [пункт 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)). + +
    + +❌ **Иначе:** При наличии 200 тестов и, предполагая, что каждый login = 100 ms, что в сумме каждый раз дает 20 секунд только для входа в систему + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Вход в систему before-all, а не before-each + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +let authenticationToken; + +// происходит до выполнения ВСЕХ тестов +before(() => { + cy.request('POST', 'http://localhost:3000/login', { + username: Cypress.env('username'), + password: Cypress.env('password'), + }) + .its('body') + .then((responseFromLogin) => { + authenticationToken = responseFromLogin.token; + }) +}) + +// происходит перед КАЖДЫМ тестом +beforeEach(setUser => () { + cy.visit('/home', { + onBeforeLoad (win) { + win.localStorage.setItem('token', JSON.stringify(authenticationToken)) + }, + }) +}) + +``` + +
    + +
    + +## ⚪ ️ 3.9 Проведите один E2E smoke-тест, который просто бегает по карте сайта + +:white_check_mark: **Сделать:** Для того, чтобы протестировать код в продакшн-среде, запустите еще один тест E2E, который посещает большинство или все станицы сайта и гарантирует, что все работает исправно. Данный вид теста приносит большую пользу, так как его легко написать и поддерживать, в то время, как он может обнаружить любую проблему, включая сетевые сбои и проблемы при развертывании. Другие виды smoke-тестов не такие надёжные и информативные - иногда просто пингуют домашнюю страницу или запускают множество интеграционных тестов, которые не находят проблем. Очевидно, что данный вид тестов не может полностью заменить функциональные тесты. + +
    + +❌ **Иначе:** Все может казаться идеальным, все тесты пройдены, однако, у компонента Payment возникли проблемы с упаковкой или не маршрут может не рендериться + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Запуск smoke-теста по всей странице + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +it("When doing smoke testing over all page, should load them all successfully", () => { + // пример с использованием Cypress, но может быть реализован + // с другим набором E2E + cy.visit("https://mysite.com/home"); + cy.contains("Home"); + cy.visit("https://mysite.com/Login"); + cy.contains("Login"); + cy.visit("https://mysite.com/About"); + cy.contains("About"); +}); +``` + +
    + +
    + +## ⚪ ️ 3.10 Expose the tests as a live collaborative document + +:white_check_mark: **Сделать:** Помимо повышения надежности приложения, тесты также предоставляют возможность служить в качестве документации для кода. Поскольку тесты говорят на менее техническом языке, а скорее на языке UX, при использовании правильных инструментов они могут служить в качестве определенного коммуникатора, который выравнивает всех участников проекта - разработчиков и клиентов. Некоторые фреймворки, позволяют выразить план тестов на "человекоподобном" языке так, что любая заинтересованная сторона, включая менеджеров продукта, также может читать и понимать тесты, которые превратились в документацию. Этот подход также называют "acceptance test", поскольку она позволяет заказчику выразить свои требования к продукту на простом языке. Это [BDD (behavior-driven testing)] (https://en.wikipedia.org/wiki/Behavior-driven_development) в чистом виде. Одним из популярных фреймворков, позволяющих это сделать, является [Cucumber](https://github.com/cucumber/cucumber-js), см. пример ниже. Еще одна похожая, но другая возможность, [StoryBook](https://storybook.js.org/), позволяет представить компоненты пользовательского интерфейса в виде графического каталога, где можно пройтись по различным состояниям каждого компонента (например, отобразить сетку без фильтров, отобразить сетку с несколькими рядами или без них и т.д.), посмотреть, как это выглядит, и как вызвать это состояние - это может понравиться и product-менеджерам, но в основном это документация для разработчиков, которые используют эти компоненты. + +❌ **Иначе:** После огромного количества усилий, потраченного на разработку тестов, будет жаль не использовать его возможности + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Описание тестов на человекоподобном языке при помощи cucumber-js + +![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Examples using Cucumber") + +```javascript +// так можно описывать тесты с помощью Cucumber: простым языком, который любой может понять + +Feature: Twitter new tweet + + I want to tweet something in Twitter + + @focus + Scenario: Tweeting from the home page + Given I open Twitter home + Given I click on "New tweet" button + Given I type "Hello followers!" in the textbox + Given I click on "Submit" button + Then I see message "Tweet saved" + +``` + +### :clap: Правильно: Визуализация компонентов и их состояний с помощью Storybook + +![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") + +![alt text](assets/story-book.jpg "Storybook") + +
    + +

    + +## ⚪ ️ 3.11 Поиск визуальных проблем с помощью автоматизированных инструментов + +:white_check_mark: **Сделать:** Настройте автоматизированные инструменты для создания скриншотов пользовательского интерфейса при представлении изменений и обнаружения визуальных проблем, таких как перекрытие или разрыв контента. Это гарантирует, что не только правильные данные будут подготовлены, но и пользователь сможет удобно их посмотреть. Эта техника не получила широкого распространения, так как мы привыкли к функциональным тестам, но именно визуальные тесты являются тем, что испытывает пользователь, а с таким количеством типов устройств очень легко упустить из виду какую-нибудь неприятную ошибку пользовательского интерфейса. Некоторые бесплатные инструменты могут обеспечить основы - генерировать и сохранять скриншоты для визуальной проверки. Хотя такой подход может быть оправданным для небольших приложений, он несовершенен, как и любое другое ручное тестирование, требующее человеческого труда при каждом изменении. С другой стороны, довольно сложно обнаружить проблемы пользовательского интерфейса автоматически из-за отсутствия четкого определения - именно здесь вступает в дело область "визуальной регрессии", которая решает эту головоломку, сравнивая старый пользовательский интерфейс с последними изменениями и обнаруживая различия. Некоторые бесплатные инструменты могут предоставить некоторые из этих функций (например, [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>), но могут потребовать значительного времени на настройку. Коммерческая линейка инструментов (например, [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) делает шаг вперед, сглаживая установку и предоставляет расширенные возможности, такие как управление пользовательским интерфейсом, оповещение, интеллектуальный захват путем устранения "визуального шума" (например, рекламы, анимации) и даже анализ первопричины изменений DOM/CSS, которые привели к проблеме. + +
    + +❌ **Иначе:** Является ли хорошей страница с контентом, которая все отображает, 100% тестов проходит, быстро загружается, но половина области контента скрыта? + +
    + +
    Примеры кода + +
    + +### :thumbsdown: Неправильно: Типичная визуальная регрессия - контент, который плохо облуживается + +![alt text](assets/amazon-visual-regression.jpeg "Amazon page breaks") + +
    + +### :clap: Правильно: Настройка для получения и сравнения снимков UI + +![](https://img.shields.io/badge/🔨%20Example%20using%20Wraith-blue.svg "Using Wraith") + +``` + # Добавьте столько доменов, сколько нужно. Ключ действует, как метка + +domains: + english: "http://www.mysite.com" + + # Введите ширину экрана ниже, вот несколько примеров + +screen_widths: + + - 600 + - 768 + - 1024 + - 1280 + + # Введите URL страницы, вот несколько примеров: + about: + path: /about + selector: '.about' + subscribe: + selector: '.subscribe' + path: /subscribe +``` + +### :clap: Правильно: Использование Applitools для получения результата сравнения снимков и других возможностей + +![](https://img.shields.io/badge/🔨%20Example%20using%20AppliTools-blue.svg "Using Applitools") ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") + +```javascript +import * as todoPage from "../page-objects/todo-page"; + +describe("visual validation", () => { + before(() => todoPage.navigate()); + beforeEach(() => cy.eyesOpen({ appName: "TAU TodoMVC" })); + afterEach(() => cy.eyesClose()); + + it("should look good", () => { + cy.eyesCheckWindow("empty todo list"); + todoPage.addTodo("Clean room"); + todoPage.addTodo("Learn javascript"); + cy.eyesCheckWindow("two todos"); + todoPage.toggleTodo(0); + cy.eyesCheckWindow("mark as completed"); + }); +}); +``` + +
    + +

    + +# Раздел 4️⃣: Измерение эффективности тестов + +

    + +## ⚪ ️ 4.1 Получите достаточное покрытие тестами. Около 80% будет вполне достаточно + +:white_check_mark: **Сделать:** Цель тестирования - получить достаточно уверенность для того, чтобы двигаться дальше. Очевидно, что чем больше кода протестировано, тем больше уверенность, что можно идти вперед. Покрытие - это мера того, сколько строк кода охвачена тестами. Возникает вопрос: сколько достаточно? Очевидно, что 10-30% слишком мало, чтобы получить хоть какое-то представление о корректности сборки, с другой стороны, 100% - это очень дорого и может сместить фокус с критических путей на очень "экзотические уголки кода". Ответ заключается в том, что это зависит от многих факторов, таких как, например, тип приложения. Если вы создаете следующее поколения Airbus A380, то 100% должно быть обязательным условием, а если сайт с картинками - 50% может быть слишком много. Хотя большинство энтузиастов тестирования утверждает, что правильный порог покрытия зависит от контекста, большинство из них также упоминают число 80% ([Fowler: "в верхних 80-х или 90-х"] (https://martinfowler.com/bliki/TestCoverage.html)), которое предположительно должно удовлетворять большинству приложений. + +Советы: Можно настроить непрерывную интеграцию (CI) на порог покрытия ([ссылка на Jest](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) и останавливать сборку, которая не соответствует этому стандарту (также можно настроить порог для каждого компонента, см. пример кода ниже). +В дополнение к этому, рассмотрите возможность обнаружения снижения покрытия сборки (когда только что зафиксированный код имеет меньшее покрытие) - это подтолкнет разработчиков к увеличению или, по крайней мере, сохранению количества тестируемого кода. При всем этом, покрытие - это только одна из мер, основанная на количественных показателях, которой недостаточно для определения надежности вашего тестирования. Помимо всего прочего, его можно обмануть, как будет продемонстрировано в следующих пунктах. + +
    + +❌ **Иначе:** Уверенность и цифры идут рука об руку, не зная, что вы протестировали большую часть системы - будет присутствовать сомнение, которое будет вас тормозить. + +
    + +
    Примеры кода + +
    + +### :clap: Пример: Отчет о покрытии тестами + +![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "A typical coverage report") + +
    + +### :clap: Правильно: Настройка покрытия каждого компонента, используя Jest + +![](https://img.shields.io/badge/🔨%20Example%20using%20Jest-blue.svg "Using Jest") + +![alt text](assets/bp-18-code-coverage2.jpeg "Setting up coverage per component (using Jest)") + +
    + +

    + +## ⚪ ️ 4.2 Просмотрите отчеты о покрытии, чтобы найти непротестированные участи кода + +:white_check_mark: **Сделать:** Некоторые проблемы с кодом иногда остаются незамеченными. Их действительно трудно обнаружить даже с помощью традиционных инструментов. Они не всегда являются ошибками, а иногда это скорее неожиданное поведение приложения, которое может иметь серьезные последствия. Например, часто некоторые области кода редко или почти никогда не вызываются - вы думали, что класс 'PricingCalculator' всегда устанавливает цену продукта, но оказалось, что он фактически никогда не вызывается, хотя у нас 10000 продуктов в БД и много продаж... Отчеты о покрытии кода помогут вам понять, ведет ли приложение себя так, как вы считаете. Кроме того, они могут показать, какие типы кода не протестированы - если вам сообщают, что 80% кода протестировано, это еще не говорит о том, покрыты ли критические части. Для генерации отчетов нужно просто запустить приложения либо в продакшн, либо во время тестирования, а затем их просмотреть. Они показывают, как часто вызывается, каждая область кода и, если вы потратите время на их изучение, то сможете обнаружить некоторые проблемы с кодом. +
    + +❌ **Иначе:** Если вы не знаете, какая часть кода у вас не протестирована, то вы не сможете узнать, откуда могут возникнуть проблемы + +
    + +
    Примеры кода + +
    + +### :thumbsdown: Неправильно: Что не так с этим отчетом? + +На основе реального сценария, когда мы отслеживали использование нашего приложения в QA и обнаружили интересные закономерности входа в систему (подсказка: количество отказов входа непропорционально, что-то явно не так. В итоге выяснилось, что какая-то ошибка во фронтенде постоянно бьет по API входа в бэкенд). + +![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report?") + +
    + +

    + +## ⚪ ️ 4.3 Измерение покрытия с помощью mutation-тестирования + +:white_check_mark: **Сделать:** Традиционная метрика Coverage часто лжет: Она может показать вам 100% покрытие кода, но ни одна из ваших функций, даже одна, не возвращает правильный ответ. Как так? Она просто измеряет, в каких строках кода побывал тест, но не проверяет, действительно ли тесты что-то тестировали. Как человек, который путешествует по делам и показывает свои штампы в паспорте - это не доказывает ничего кроме того, что он посетил несколько аэропортов и отелей. + +Тестирование на основе мутаций призвано помочь в этом, измеряя количество кода, который был действительно ПРОВЕРЕН, а не просто ПОСМОТРЕН. [Stryker](https://stryker-mutator.io/) - это JavaScript-библиотека для мутационного тестирования, и ее реализация действительно хороша: + +((1) он специально изменяет код и "закладывает ошибки". Например, код newOrder.price===0 становится newOrder.price!=0. Такие "ошибки" называются мутациями. + +(2) он запускает тесты, если все они успешны, то у нас проблема - тесты не выполнили свою задачу по обнаружению ошибок, мутации выжили. Если тесты провалились, то отлично, мутации были устранены. + +Знание того, что все или большинство мутаций были устранены, дает гораздо большую уверенность, чем традиционное покрытие, а время настройки почти не отличается +
    + +❌ **Иначе:** Вы будете введены в заблуждение, полагая, что 85% покрытие означает, что ваш тест обнаружит ошибки в 85% кода. + +
    + +
    Примеры кода + +
    + +### :thumbsdown: Неправильно: 100% покрытие, 0% протестировано + +![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Using Stryker") + +```javascript +function addNewOrder(newOrder) { + logger.log(`Adding new order ${newOrder}`); + DB.save(newOrder); + Mailer.sendMail(newOrder.assignee, `A new order was places ${newOrder}`); + + return { approved: true }; +} + +it("Test addNewOrder, don't use such test names", () => { + addNewOrder({ assignee: "John@mailer.com", price: 120 }); +}); // Запускает 100% покрытие кода, но ничего не проверяет +``` + +
    + +### :clap: Правильно: Stryker reports, инструмент для тестирования мутаций, обнаруживает и подсчитывает количество кода, который не прошел проверку (Мутации) + +![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations)") + +
    + +

    + +## ⚪ ️4.4 Поиск проблем с тестами при помощи Test Linters + +:white_check_mark: **Сделать:** Набор плагинов ESLint был создан специально для проверки шаблонов тестового кода и обнаружения проблем. Например, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) предупредит, когда тест написан на глобальном уровне (не дочерний элемент describe()) или когда тесты [пропущены](https://mochajs.org/#inclusive-tests) что может привести к ложному убеждению, что все тесты пройдены. Аналогично, [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) может, например, предупредить, когда тест вообще ничего не проверяет. + +
    + +❌ **Иначе:** При виде 90% покрытия кода и 100% зеленых тестов на вашем лице появится широкая улыбка только до тех пор, пока вы не поймете, что многие тесты ничего не проверяют, а многие тестовые наборы были просто пропущены. Надеюсь, вы ничего не развернули, основываясь на этом ошибочном наблюдении. + +
    +
    Примеры кода + +
    + +### :thumbsdown: Неправильно: Пример теста, который полный ошибок и все они пойманы линтерами + +```javascript +describe("Too short description", () => { + const userToken = userService.getDefaultToken(); // ошибка:no-setup-in-describe, вместо этого используйте hooks (экономно) + it("Some description", () => {}); // ошибка: valid-test-description. Должно включать "Should" + не менее 5 слов +}); + +it.skip("Test name", () => { + // ошибка:no-skipped-tests, ошибка:no-global-tests. Поместите тесты только в describe или suite + expect("somevalue"); // ошибка:no-assert +}); + +it("Test name", () => { + // ошибка:no-identical-title. Присваивайте тестам уникальные названия +}); +``` + +
    + +

    + +# Раздел 5️⃣: CI and другие показатели качества + +

    + +## ⚪ ️ 5.1 Расширяйте линтеры и останавливайте сборки, в которых есть проблемы линтинга + +:white_check_mark: **Сделать:** Линтинг - это бесплатный обед, за 5 минут настройки вы получаете бесплатный автопилот, охраняющий ваш код и отлавливающий существенные проблемы по мере набора текста. Прошли те времена, когда линтинг сводился к косметике (никаких полутонов!). Сегодня линтеры могут отлавливать серьезные проблемы, такие как неправильно брошенные ошибки и потеря информации. Помимо основного набора правил (например, [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) или [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), включите несколько специализированных линтеров, например [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect), который может обнаружить тесты, которые ничего не проверяют, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) может обнаружить промисы без разрешения (your code will never continue), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) который может обнаружить регулярные выражения, которые могут быть использованы для DOS атак, и [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore), способный предупредить, когда код использует методы библиотеки утилит, которые являются частью методов ядра V8, например Lodash.\_map(...). +
    + +❌ **Иначе:** Подумайте о том дне, когда ваш код упал, но ваш лог не отображает трассировку стека ошибок. Что произошло? Ваш код по ошибке выбросил объект, не являющийся ошибкой, и трассировка стека была потеряна - хорошая причина для того, чтобы биться головой о кирпичную стену. 5-минутная настройка линтера может обнаружить эту ошибку и спасти ваш день + +
    + +
    Примеры кода + +
    + +### :thumbsdown: Неправильно: Ошибочно выбрасывается неправильный объект Error, для этой ошибки не появляется стек-трейс. К счастью, ESLint ее отлавливает + +![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug") + +
    + +

    + +## ⚪ ️ 5.2 Сократите цикл обратной связи с локальным разработчиком-CI + +:white_check_mark: **Сделать:** Внедрение CI с блестящими проверками качества, такими как тестирование, линтинг, проверка на уязвимости и другое. Помогите разработчикам запустить этот конвейер также локально, чтобы получить мгновенную обратную связь и сократить [петлю обратной связи](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). Почему? Эффективный процесс тестирования состоит из множества итеративных циклов: (1) пробное тестирование -> (2) обратная связь -> (3) рефакторинг. Чем быстрее обратная связь, тем больше итераций улучшения разработчик может провести в каждом модуле и улучшить результаты. С другой стороны, когда обратная связь приходит с запозданием, разработчик может перейти уже к другой теме или задаче и он будет не готов к доработке предыдущего. + +Некоторые разработчики CI (пример: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) позволяют запускать конвейер локально: коммерческие сервисы, такие как [wallaby provide highly-valuable & testing insights](https://wallabyjs.com/) в качестве прототипа для разработчиков. В качестве альтернативы можно просто добавить в package.json скрипт npm, запускающий все команды на проверку качества (например, test, lint, vulnerabilities), используйте инструменты вроде [concurrently](https://www.npmjs.com/package/concurrently) для распараллеливания и ненулевого кода выхода в случае сбоя одного из инструментов. Теперь разработчику достаточно вызвать одну команду - например, 'npm run quality' - чтобы получить мгновенную обратную связь. Также существует возможность прерывания коммита, если проверка качества не удалась, с помощью githook ([husky can help](https://github.com/typicode/husky)). +
    + +❌ **Иначе:** Когда результаты приходят на следующей день после кода, тестирование не становится неотъемлемой частью разработки + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Скрипты npm, которые выполняют проверку качества кода, запускаются параллельно по требованию или когда разработчик пытается запушить новый код. + +```javascript +"scripts": { + "inspect:sanity-testing": "mocha **/**--test.js --grep \"sanity\"", + "inspect:lint": "eslint .", + "inspect:vulnerabilities": "npm audit", + "inspect:license": "license-checker --failOn GPLv2", + "inspect:complexity": "plato .", + + "inspect:all": "concurrently -c \"bgBlue.bold,bgMagenta.bold,yellow\" \"npm:inspect:quick-testing\" \"npm:inspect:lint\" \"npm:inspect:vulnerabilities\" \"npm:inspect:license\"" + }, + "husky": { + "hooks": { + "precommit": "npm run inspect:all", + "prepush": "npm run inspect:all" + } +} + +``` + +
    + +

    + +## ⚪ ️5.3 Выполните e2e тестирование в настоящей продакшн-среде + +:white_check_mark: **Сделать:** Конечное тестирование (e2e) является основной проблемой любого CI-конвейера - создание похожего продакшн-зеркала со всеми сопутствующими облачными сервисами может быть утомительным. Ваша цель - это поиск наилучшего компромисса: [Docker-compose](https://serverless.com/) позволяет создать изолированное окружение с идентичными контейнерами при помощи одного текстового файла, однако технология поддержки отличается от реальной продакшн-среды. Вы можете комбинировать его с ['AWS Local'](https://github.com/localstack/localstack) для работы с заглушкой реальных сервисов AWS. Если вы пошли по пути [serverless](https://serverless.com/), то несколько фреймворков типа serverless и [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) позволяют локально вызывать код FaaS. +
    + +❌ **Иначе:** Использование разных технологий для тестирования требует поддержки 2-х моделей развертывания, разделяя разработчиков и OC. + +
    + +
    Примеры кода + +
    + +### :clap: Пример: CI-конвейер, создающий кластер Kubernetes ([Благодарность: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/)) + +
    deploy:
    stage: deploy
    image: registry.gitlab.com/gitlab-examples/kubernetes-deploy
    script:
    - ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN
    - kubectl create ns $NAMESPACE
    - kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL"
    - mkdir .generated
    - echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF"
    - sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml"
    - kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml
    - kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml
    environment:
    name: test-for-ci
    + +
    + +

    + +## ⚪ ️5.4 Параллельное выполнение тестов + +:white_check_mark: **Сделать:** Если все сделано правильно, тестирование - это ваш друг 24/7, обеспечивающий практически мгновенную обратную связь. На практике выполнение 500 юнит-тестов на одном процессоре в один поток может занять слишком много времени. К счастью, современные программы для запуска тестов и CI-платформы (такие как [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) и [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) могут распараллелить тест на несколько процессов и добиться значительного улучшения времени обратной связи. Некоторые поставщики CI также распараллеливают тесты по контейнерам (!), что еще больше сокращает цикл обратной связи. Будь то локально на нескольких процессах или через облачный CLI с использованием нескольких машин - распараллеливание требует сохранения автономности тестов, поскольку каждый из них может выполняться на разных процессах. + +❌ **Иначе:** Получение результатов тестирования через час после внедрения нового кода, когда вы уже пишете следующие функции - отличный рецепт для того, чтобы сделать тестирование менее актуальным + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: Mocha parallel & Jest легко обгоняют традиционную Mocha благодаря распараллеливанию тестирования ([Благодарность: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) + +![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization (Credit: JavaScript Test-Runners Benchmark)") + +
    + +

    + +## ⚪ ️5.5 Держитесь подальше от проблем, связанных с правовым полем, используя проверку на лицензию и антиплагиат + +:white_check_mark: **Сделать:** Вопросы лицензирования и плагиата, вероятно, не являются сейчас вашей главной заботой, но почему бы не поставить галочку и в этой графе за 10 минут? Куча пакетов npm, таких как [проверка лицензии](https://www.npmjs.com/package/license-checker) и [проверка на плагиат](https://www.npmjs.com/package/plagiarism-checker) (коммерческий и бесплатный план), могут быть легко встроены в ваш CI-конвейер и проверены на наличие таких проблем, как зависимости с ограничительными лицензиями или код, который был скопирован из Stack Overflow и, очевидно, нарушает авторские права. + +❌ **Иначе:** Непреднамеренно разработчики могут использовать пакеты с несоответствующими лицензиями или копировать коммерческий код и столкнуться с юридическими проблемами + +
    + +
    Примеры кода + +
    + +### :clap: Правильно: + +```javascript +// установите license-checker в CI или локально +npm install -g license-checker + +// попросите его просканировать все лицензии и выдать ошибку с кодом выхода, отличным от 0, в случае обнаружения неавторизованной лицензии. Система CI должна уловить этот сбой и остановить сборку +license-checker --summary --failOn BSD + +``` + +
    + +![alt text](assets/bp-25-nodejs-licsense.png) + +
    + +

    + +## ⚪ ️5.6 Постоянная проверка на наличие уязвимых зависимостей + +:white_check_mark: **Сделать:** Даже самые авторитетные зависимости, такие как Express, имеют известные уязвимости. Это можно легко устранить с помощью инструментов сообщества, таких как [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), или коммерческих инструментов, таких как [snyk](https://snyk.io/) (предлагается также бесплатная версия для сообщества). Оба инструмента могут быть вызваны из вашего CI при каждой сборке + +❌ **Иначе:** Для поддержания кода чистым от уязвимостей без специальных инструментов придется постоянно следить за публикациями в Интернете о новых угрозах. Довольно утомительно + +
    + +
    Примеры кода + +
    + +### :clap: Example: Результат NPM Audit + +![alt text](assets/bp-26-npm-audit-snyk.png "NPM Audit result") + +
    + +

    + +## ⚪ ️5.7 Автоматизируйте обновление зависимостей + +:white_check_mark: **Сделать:** Последнее внедрение в Yarn и npm package-lock.json создало серьезную проблему (дорога в ад вымощена благими намерениями) - по умолчанию пакеты больше не получают обновлений. Разработчик, выполняющий множество свежих развертываний с помощью 'npm install' и 'npm update', не получит никаких новых обновлений. Это приводит в лучшем случае к некачественным версиям зависимых пакетов, а в худшем - к уязвимому коду. Сейчас команды разработчиков полагаются на добрую волю и память разработчиков, чтобы вручную обновлять package.json или использовать инструменты [например, ncu](https://www.npmjs.com/package/npm-check-updates) вручную. +Более надежным способом может быть автоматизация процесса получения наиболее надежных версий зависимых пакетов, хотя пока не существует идеальных решений, есть два возможных пути автоматизации: + +(1) CI может отклонять сборки с устаревшими зависимостями - с помощью таких инструментов, как ['npm outdated'](https://docs.npmjs.com/cli/outdated) или 'npm-check-updates (ncu)'. Это заставит разработчиков обновить зависимости. + +(2) Использовать коммерческие инструменты, которые сканируют код и автоматически отправляют запросы на обновление зависимостей. Остается один интересный вопрос: какой должна быть политика обновления зависимостей - обновление при каждом патче создает слишком много накладных расходов, обновление сразу после выхода мажора может указывать на нестабильную версию (многие пакеты обнаруживают уязвимость в первые же дни после выхода, [см. инцидент с eslint-scope](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/)). + +Эффективная политика обновления может допускать некоторый "период" - пусть код отстает от @latest на некоторое время и версии, прежде чем считать локальную копию устаревшей (например, локальная версия - 1.3.1, а версия хранилища - 1.3.8). +
    + +❌ **Иначе:** Будут запускаться зависимости, которые были отмечены, как рискованные + +
    + +
    Примеры кода + +
    + +### :clap: Пример: [ncu](https://www.npmjs.com/package/npm-check-updates) можно использовать вручную или в рамках конвейера CI для определения степени отставания кода от последних версий + +![alt text](assets/bp-27-yoni-goldberg-npm.png "ncu can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions") + +
    + +

    + +## ⚪ ️ 5.8 Другие, не связанные с Node, советы по CI + +:white_check_mark: **Сделать:** Эта заметка посвящена советам по тестированию, которые связаны с Node JS или, по крайней мере, могут быть проиллюстрированы на его примере. Однако в этом пункте сгруппировано несколько советов, не связанных с Node, которые хорошо известны + +
    1. Используйте декларативный синтаксис. Это единственный вариант для большинства поставщиков, но старые версии Jenkins позволяют использовать код или UI
    2. Выбирайте продукт, который имеет встроенную поддержку Docker
    3. Запускайте сначала самые быстрые тесты. Создайте шаг/этап "Smoke testing", который группирует несколько быстрых проверок (например, линтинг, модульные тесты) и обеспечивает быструю обратную связь с коммиттером кода.
    4. Упростить просмотр сборки, включая отчеты о тестировании, отчеты о покрытии, отчеты о мутациях, журналы и т.д.
    5. Создайте несколько заданий для каждого события, повторно используя шаги между ними. Например, настройте одно задание для коммитов ветки функций и другое - для PR мастера. Пусть каждый из них повторно использует логику, используя общие шаги (большинство продуктов предоставляют некоторые механизмы для повторного использования кода).
    6. Никогда не вставляйте секреты в объявление задания, берите их из хранилища секретов или из конфигурации задания
    7. Явно повышайте версию в сборке релиза или, по крайней мере, убедитесь, что разработчик это сделал
    8. Сборка только один раз и выполнение всех проверок над единственным артефактом сборки (например, образом Docker)
    9. Тестируйте в эфемерной среде, которая не переносит состояние между сборками. Кэширование модулей node_modules может быть единственным исключением
    +
    + +❌ **Иначе:** Вы можете многое упустить + +

    + +## ⚪ ️ 5.9 Матрица сборки: Выполнение одних и тех же шагов CI с использованием нескольких версий Node + +:white_check_mark: **Сделать:** Проверка качества - это случайность, чем больше места вы охватываете тем больше шанс обнаружить проблемы на ранней стадии. При разработке многократно используемых пакетов или работе с несколькими клиентами с различными конфигурации и версиями Node, CI должен выполнят конвейер тестов для различных перестановок этих конфигураций. Например, если мы используем MySQL для одних клиентов и Postgres для других, некоторые поставщики СI поддёргивают функцию 'matrix', которая позволяет запустить конвейер тестов для всех вариантов MySQL, Postgres и нескольких версий Node (8, 9, 10). Это делается только с помощью конфигурации без каких-либо дополнительных усилий (при условии, что у вас есть тестирование или любые другие проверки качества). Другие CI, не поддерживающие Matrix, могут иметь расширения для этого. +
    + +❌ **Иначе:** Так неужели после всей этой тяжелой работы по написанию тестов мы позволим ошибкам прокрасться только из-за проблем с конфигурацией? + +
    + +
    Примеры кода + +
    + +### :clap: Пример: Использование Travis (содержит CI) для запуска одного и того же теста на нескольких версиях Node + +
    language: node_js
    node_js:
    - "7"
    - "6"
    - "5"
    - "4"
    install:
    - npm install
    script:
    - npm run test
    +
    + +

    + +# Команда + +## Yoni Goldberg + +
    + +
    + +**Роль:** Автор + +**Информация:** Я независимый консультант, который работает с компаниями Fortune 500 и гаражными стартапами над совершенствованием их JS и Node.js приложений. Больше других тем я увлекаюсь и стремлюсь овладеть искусством тестирования. Я также являюсь автором книги [Node.js Best Practices] (https://github.com/goldbergyoni/nodebestpractices). + +**📗 Онлайн-курс:** Понравилось это руководство и вы хотите довести свои навыки тестирования до совершенства? Посетите мой комплексный курс [Testing Node.js & JavaScript From A To Z] (https://www.testjavascript.com). + +
    + +**Follow:** + +- [🐦 Twitter](https://twitter.com/goldbergyoni/) +- [📞 Contact](https://testjavascript.com/contact-2/) +- [✉️ Newsletter](https://testjavascript.com/newsletter//) + +
    +
    +
    + +## [Bruno Scheufler](https://github.com/BrunoScheufler) + +**Роль:** Консультант и технический рецензент + +Пересмотреть, улучшить, и отшлифовать все тексты. + +**Информация:** full-stack web-разработчик, Node.js & GraphQL любитель + +
    +
    + +## [Ido Richter](https://github.com/idori) + +**Роль:** Концепция, дизайн и отличные советы + +**Информация:** Мастерский frontend-разработчик, CSS-эксперт и любитель эмоджи + +## [Kyle Martin](https://github.com/js-kyle) + +**Роль:** Помогает поддерживать проект в рабочем состоянии и анализирует методы, связанные с безопасностью + +**About:** Любит работать с Node.js проектами и безопасностью веб-приложений. + +## Contributors ✨ + +Thanks goes to these wonderful people who have contributed to this repository! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Scott Davis

    🖋

    Adrien REDON

    🖋

    Stefano Magni

    🖋

    Yeoh Joer

    🖋

    Jhonny Moreira

    🖋

    Ian Germann

    🖋

    Hafez

    🖋

    Ruxandra Fediuc

    🖋

    Jack

    🖋

    Peter Carrero

    🖋

    Huhgawz

    🖋

    Haakon Borch

    🖋

    Jaime Mendoza

    🖋

    Cameron Dunford

    🖋

    John Gee

    🖋

    Aurelijus Rožėnas

    🖋

    Aaron

    🖋

    Tom Nagle

    🖋

    Yves yao

    🖋

    Userbit

    🖋

    Glaucia Lemos

    🚧

    koooge

    🖋

    Michal

    🖋

    roywalker

    🖋

    dangen

    🖋

    biesiadamich

    🖋

    Yanlin Jiang

    🖋

    sanguino

    🖋

    Morgan

    🖋

    Lukas Bischof

    ⚠️ 🖋

    JuanMa Ruiz

    🖋

    Luís Ângelo Rodrigues Jr.

    🖋

    José Fernández

    🖋

    Alejandro Gutierrez Barcenilla

    🖋

    Jason

    🖋

    Otavio Araujo

    ⚠️ 🖋

    Alex Ivanov

    🖋

    Yiqiao Xu

    🖋

    YuBin, Hsu

    🌍 💻
    + + + + + From e3565227faeee7e6ab16d7b91840403e82628d9f Mon Sep 17 00:00:00 2001 From: alex_p Date: Tue, 4 Oct 2022 15:30:25 +0300 Subject: [PATCH 154/189] docs: update README.md --- readme-ru.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme-ru.md b/readme-ru.md index 95ce4435..239e63bc 100644 --- a/readme-ru.md +++ b/readme-ru.md @@ -698,7 +698,7 @@ describe("Order service", function () {

    -## ⚪ ️ 1.12 Categorize tests under at least 2 levels +## ⚪ ️ 1.12 Структурируйте тесты, как минимум, на 2 уровня :white_check_mark: **Сделать:** Придайте набору тестов некую структуру, чтобы любой, кто посмотрит на них, мог легко понять, что происходит (тесты - лучшая документация). Общим методом для этого является размещение как минимум двух блоков "describe" над тестами: первый - для названия тестируемого блока, а второй - для дополнительного разделения тестов, например, сценария или пользовательских категорий (см. примеры кода и скриншот ниже). Данное разделение также улучшить финальные отчеты по тестированию. Читатель сможет легко разобраться с категориями тестов, найти нужный раздел и понять, где могла возникнуть ошибка. Более того, разработчику будет легче ориентироваться в случае большого количества тестов. Существует несколько способов придать тестам структуру, которое можно найти здесь [given-when-then](https://github.com/searls/jasmine-given) и здесь [RITE](https://github.com/ericelliott/riteway) From ee14cbef4253426f042571c9a96e4c2cd96e21bf Mon Sep 17 00:00:00 2001 From: Ali Azmoodeh Date: Thu, 13 Oct 2022 14:21:45 +0330 Subject: [PATCH 155/189] finished persian translate --- readme-pr-fr.md | 370 ++++++++++++++++++++++++------------------------ 1 file changed, 185 insertions(+), 185 deletions(-) diff --git a/readme-pr-fr.md b/readme-pr-fr.md index 4ee19591..20831337 100644 --- a/readme-pr-fr.md +++ b/readme-pr-fr.md @@ -1160,41 +1160,41 @@ test("هنگام پرچم گذاری برای نمایش فقط VIP، باید

    -## ⚪ ️ 3.2 Query HTML elements based on attributes that are unlikely to change +## ⚪ ️ 3.2 پرس و جو از عناصر HTML بر اساس ویژگی هایی که بعید است تغییر کنند -: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/logic 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 +:white_check_mark: **انجام دادن:** عناصر HTML را بر اساس ویژگی هایی که احتمالاً بر خلاف انتخابگرهای CSS و مانند برچسب های فرم، در تغییرات گرافیکی باقی می مانند، پرس و جو کنید. اگر عنصر تعیین‌شده چنین ویژگی‌هایی را ندارد، یک ویژگی تست اختصاصی مانند «test-id-submit-button» ایجاد کنید. پیمودن این مسیر نه تنها تضمین می‌کند که تست‌های عملکردی/منطقی شما هرگز به دلیل تغییرات ظاهری و احساسی شکسته نمی‌شوند، بلکه برای کل تیم مشخص می‌شود که این عنصر و ویژگی توسط تست ‌ها استفاده می‌شوند و نباید حذف شوند.
    -❌ **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' +❌ **در غیر این صورت:** شما می‌خواهید عملکرد ورود به سیستم را که شامل بسیاری از مؤلفه‌ها، منطق و سرویس‌ها می‌شود، آزمایش کنید، همه چیز به‌خوبی تنظیم شده است - موارد خرد، جاسوس‌ها، تماس‌های Ajax جدا شده‌اند. همه عالی به نظر می رسند سپس تست شکست می خورد زیرا طراح کلاس div CSS را از "thick-border" به "thin-border" تغییر داده است.'
    -
    Code Examples +
    نمونه کد
    -### :clap: Doing It Right Example: Querying an element using a dedicated attribute for testing +### :clap: انجام درست مثال: پرس و جو از یک عنصر با استفاده از یک ویژگی اختصاصی برای تست ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ```html -// the markup code (part of React component) +// کد نشانه گذاری (بخشی از مؤلفه React)

    {value} - +

    ``` ```javascript -// this example is using react-testing-library -test("Whenever no data is passed to metric, show 0 as default", () => { - // Arrange +// این مثال از react-testing-library استفاده می کند +test("هر زمان که هیچ داده ای به متریک منتقل نمی شود، 0 را به عنوان پیش فرض نشان دهید", () => { + // مقدار دهی کردن const metricValue = undefined; - // Act + // اجرا کردن const { getByTestId } = render(); expect(getByTestId("errorsLabel").text()).toBe("0"); @@ -1203,17 +1203,17 @@ test("Whenever no data is passed to metric, show 0 as default", () => {
    -### :thumbsdown: Anti-Pattern Example: Relying on CSS attributes +### :thumbsdown: مثال ضد الگو: تکیه بر ویژگی های CSS ```html - + {value} - + ``` ```javascript -// this exammple is using enzyme -test("Whenever no data is passed, error metric shows zero", () => { +// این مثال استفاده از آنزیم است +test("هر زمان که هیچ داده ای ارسال نشود، معیار خطا صفر را نشان می دهد", () => { // ... expect(wrapper.find("[className='d-flex-column']").text()).toBe("0"); @@ -1224,23 +1224,23 @@ test("Whenever no data is passed, error metric shows zero", () => {
    -## ⚪ ️ 3.3 Whenever possible, test with a realistic and fully rendered component +## ⚪ ️ 3.3 در صورت امکان، با یک جزء واقعی و کاملا رندر شده تست کنید -: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://github.com/goldbergyoni/javascript-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 +:white_check_mark: **انجام دادن:** هر زمان که اندازه معقولی داشتید، مؤلفه خود را از خارج مانند کاربرانتان آزمایش کنید، UI را به طور کامل رندر کنید، بر اساس آن عمل کنید و ادعا کنید که رابط کاربری رندر شده مطابق انتظار عمل می کند. از هر گونه رندر تمسخر آمیز، جزئی و کم عمق خودداری کنید - این روش ممکن است به دلیل کمبود جزئیات منجر به اشکالات محفوظ نشده و تعمیر و نگهداری سخت تر شود زیرا آزمایش ها با اجزای داخلی به هم می خورند (به گلوله مراجعه کنید ['از تست جعبه سیاه حمایت کنید'](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-14-stick-to-black-box-testing-test-only-public-methods)). اگر یکی از اجزای کودک به طور قابل توجهی کند می شود (مثلاً انیمیشن) یا تنظیمات را پیچیده می کند - به طور واضح آن را با یک جعلی جایگزین کنید. -With all that said, a word of caution is in order: this technique works for small/medium 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 +با تمام آنچه گفته شد، یک کلمه احتیاط لازم است: این تکنیک برای اجزای کوچک/متوسط ​​که اندازه معقولی از اجزای کودک را در خود جای می دهند، کار می کند. رندر کردن کامل یک مؤلفه با تعداد زیاد فرزندان، استدلال در مورد شکست تست (تحلیل علت ریشه) را دشوار می کند و ممکن است بسیار کند شود. در چنین مواردی، فقط چند آزمایش بر روی آن جزء والد چاق بنویسید و آزمایش های بیشتری را بر روی فرزندان آن بنویسید
    -❌ **Otherwise:** When poking into a component's internal by invoking its private methods, and checking the inner state - you would have to refactor all tests when refactoring the components implementation. Do you really have a capacity for this level of maintenance? +❌ **در غیر این صورت:** هنگامی که با فراخوانی روش‌های خصوصی و بررسی وضعیت درونی یک کامپوننت به درونی آن وارد می‌شوید - باید همه آزمایش‌ها را هنگام بازسازی اجرای مؤلفه‌ها مجدداً تغییر دهید. آیا واقعاً برای این سطح از نگهداری ظرفیت دارید؟?
    -
    Code Examples +
    نمونه کد
    -### :clap: Doing It Right Example: Working realistically with a fully rendered component +### :clap: انجام درست آن مثال: کار به صورت واقع بینانه با یک جزء کاملاً رندر شده ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20Enzyme-blue.svg "Examples with Enzyme") @@ -1258,37 +1258,37 @@ class Calendar extends React.Component { } } -//Examples use React & Enzyme -test("Realistic approach: When clicked to show filters, filters are displayed", () => { - // Arrange +//برای مثال از React & Enzyme استفاده می شود +test("رویکرد واقع گرایانه: هنگامی که برای نمایش فیلترها کلیک کنید، فیلترها نمایش داده می شوند", () => { + // مقدار دهی کردن const wrapper = mount(); - // Act + // اجرا کردن wrapper.find("button").simulate("click"); - // Assert + // مقابسه کردن expect(wrapper.text().includes("Choose Filter")); - // This is how the user will approach this element: by text + // به این صورت است که کاربر به این عنصر نزدیک می شود: توسط متن }); ``` -### :thumbsdown: Anti-Pattern Example: Mocking the reality with shallow rendering +### :thumbsdown: مثال ضد الگو: تمسخر واقعیت با رندر کم عمق ```javascript -test("Shallow/mocked approach: When clicked to show filters, filters are displayed", () => { - // Arrange +test("رویکرد کم عمق/ مسخره شده: وقتی برای نمایش فیلترها کلیک کنید، فیلترها نمایش داده می شوند", () => { + // مقدار دهی کردن const wrapper = shallow(); - // Act + // اجرا کردن wrapper .find("filtersPanel") .instance() .showFilters(); // Tap into the internals, bypass the UI and invoke a method. White-box approach - // Assert + // مقایسه کردن expect(wrapper.find("Filter").props()).toEqual({ title: "Choose Filter" }); - // what if we change the prop name or don't pass anything relevant? + // اگر نام پروپوزال را تغییر دهیم یا چیزی مربوطه را پاس نکنیم چه؟ }); ``` @@ -1296,55 +1296,55 @@ test("Shallow/mocked approach: When clicked to show filters, filters are display
    -## ⚪ ️ 3.4 Don't sleep, use frameworks built-in support for async events. Also try to speed things up +## ⚪ ️ 3.4 نخوابید، از framework‌های داخلی پشتیبانی برای رویدادهای همگام استفاده کنید. همچنین سعی کنید کارها را تسریع کنید -:white_check_mark: **Do:** In many cases, the unit under test completion time is just unknown (e.g. animation suspends element appearance) - in that case, avoid sleeping (e.g. setTimeOut) and prefer more deterministic methods that most platforms provide. Some libraries allows awaiting on operations (e.g. [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), other provide API for waiting like [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). Sometimes a more elegant way is to stub the slow resource, like API for example, and then once the response moment becomes deterministic the component can be explicitly re-rendered. When depending upon some external component that sleeps, it might turn useful to [hurry-up the clock](https://jestjs.io/docs/en/timer-mocks). Sleeping is a pattern to avoid because it forces your test to be slow or risky (when waiting for a too short period). Whenever sleeping and polling is inevitable and there's no support from the testing framework, some npm libraries like [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) can help with a semi-deterministic solution +:white_check_mark: **انجام دادن:** در بسیاری از موارد، واحد تحت آزمایش زمان کامل ناشناخته است (مثلاً انیمیشن ظاهر عنصر را به حالت تعلیق در می‌آورد) - در این صورت، از خوابیدن خودداری کنید (مثلاً setTimeOut) و روش‌های قطعی‌تری را که اکثر پلتفرم‌ها ارائه می‌دهند ترجیح دهید. برخی از کتابخانه ها امکان انتظار برای عملیات را فراهم می کنند (e.g. [Cypress cy.request('url')](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting)), سایر API برای انتظار مانند [@testing-library/dom method wait(expect(element))](https://testing-library.com/docs/guide-disappearance). گاهی اوقات یک راه ظریف تر، خرد کردن منبع کند است، مانند API، و سپس زمانی که لحظه پاسخ قطعی شد، مولفه می تواند به صراحت دوباره ارائه شود. هنگامی که به برخی از اجزای خارجی که می خوابند وابسته می شوند، ممکن است مفید باشد [hurry-up the clock](https://jestjs.io/docs/en/timer-mocks). خوابیدن الگویی است که باید از آن اجتناب کنید زیرا باعث می شود آزمون شما آهسته یا پرخطر باشد (زمانی که برای مدت کوتاهی منتظر می مانید). هر زمان که خواب و نظرسنجی اجتناب ناپذیر است و هیچ پشتیبانی از چارچوب تست وجود ندارد، برخی از کتابخانه های npm مانند [wait-for-expect](https://www.npmjs.com/package/wait-for-expect) می تواند با یک راه حل نیمه قطعی کمک کند
    -❌ **Otherwise:** When sleeping for a long time, tests will be an order of magnitude slower. When trying to sleep for small numbers, test will fail when the unit under test didn't respond in a timely fashion. So it boils down to a trade-off between flakiness and bad performance +❌ **در غیر این صورت:** هنگام خواب طولانی مدت، آزمایش ها یک مرتبه کندتر خواهند بود. هنگامی که سعی می کنید برای تعداد کمی بخوابید، زمانی که واحد تحت آزمایش به موقع پاسخ ندهد، آزمایش با شکست مواجه می شود. بنابراین به یک مبادله بین پوسته پوسته شدن و عملکرد بد خلاصه می شود
    -
    Code Examples +
    نمونه کد
    -### :clap: Doing It Right Example: E2E API that resolves only when the async operations is done (Cypress) +### :clap: انجام درست مثال: API E2E که فقط زمانی که عملیات همگام‌سازی انجام شود برطرف می‌شود (Cypress) ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") ```javascript -// using Cypress +// استفاده كردن از Cypress cy.get("#show-products").click(); // navigate -cy.wait("@products"); // wait for route to appear -// this line will get executed only when the route is ready +cy.wait("@products"); // صبر کنید تا مسیر ظاهر شود +// این خط تنها زمانی اجرا می شود که مسیر آماده باشد ``` -### :clap: Doing It Right Example: Testing library that waits for DOM elements +### :clap: انجام درست مثال: آزمایش کتابخانه ای که منتظر عناصر DOM است ```javascript // @testing-library/dom test("movie title appears", async () => { - // element is initially not present... + // عنصر در ابتدا وجود ندارد ... - // wait for appearance + //منتظر ظهور باشید await wait(() => { expect(getByText("the lion king")).toBeInTheDocument(); }); - // wait for appearance and return the element + // منتظر ظاهر شدن باشید و عنصر را برگردانید const movie = await waitForElement(() => getByText("the lion king")); }); ``` -### :thumbsdown: Anti-Pattern Example: custom sleep code +### :thumbsdown: مثال ضد الگو: کد خواب سفارشی ```javascript test("movie title appears", async () => { - // element is initially not present... + // عنصر در ابتدا وجود ندارد ... - // custom wait logic (caution: simplistic, no timeout) + // منطق انتظار سفارشی (احتیاط: ساده، بدون مهلت زمانی) const interval = setInterval(() => { const found = getByText("the lion king"); if (found) { @@ -1353,7 +1353,7 @@ test("movie title appears", async () => { } }, 100); - // wait for appearance and return the element + // منتظر ظاهر شدن باشید و عنصر را برگردانید const movie = await waitForElement(() => getByText("the lion king")); }); ``` @@ -1362,21 +1362,21 @@ test("movie title appears", async () => {
    -## ⚪ ️ 3.5 Watch how the content is served over the network +## ⚪ ️ 3.5 مراقب نحوه ارائه محتوا از طریق شبکه باشید ![](https://img.shields.io/badge/🔧%20Example%20using%20Google%20LightHouse-blue.svg "Examples with Lighthouse") -✅ **Do:** Apply some active monitor that ensures the page load under real network is optimized - this includes any UX concern like slow page load or un-minified bundle. The inspection tools market is no short: basic tools like [pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) can be easily configured to watch whether the server is alive and response under a reasonable SLA. This only scratches the surface of what might get wrong, hence it's preferable to opt for tools that specialize in frontend (e.g. [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) and perform richer analysis. The focus should be on symptoms, metrics that directly affect the UX, like page load time, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [time until the page gets interactive (TTI)](https://calibreapp.com/blog/time-to-interactive/). On top of that, one may also watch for technical causes like ensuring the content is compressed, time to the first byte, optimize images, ensuring reasonable DOM size, SSL and many others. It's advisable to have these rich monitors both during development, as part of the CI and most important - 24x7 over the production's servers/CDN +✅ **انجام دادن:** برخی از مانیتورهای فعال را اعمال کنید که تضمین می‌کند بارگذاری صفحه در شبکه واقعی بهینه شده است - این شامل هر گونه نگرانی UX مانند بارگذاری صفحه آهسته یا بسته‌ای کوچک نشده می‌شود. بازار ابزار بازرسی کوتاه نیست: ابزارهای اساسی مانند [pingdom](https://www.pingdom.com/), AWS CloudWatch, [gcp StackDriver](https://cloud.google.com/monitoring/uptime-checks/) can be easily configured to watch whether the server is alive and response under a reasonable SLA. This only scratches the surface of what might get wrong, hence it's preferable to opt for tools that specialize in frontend (e.g. [lighthouse](https://developers.google.com/web/tools/lighthouse/), [pagespeed](https://developers.google.com/speed/pagespeed/insights/)) and perform richer analysis. The focus should be on symptoms, metrics that directly affect the UX, like page load time, [meaningful paint](https://scotch.io/courses/10-web-performance-audit-tips-for-your-next-billion-users-in-2018/fmp-first-meaningful-paint), [time until the page gets interactive (TTI)](https://calibreapp.com/blog/time-to-interactive/). On top of that, one may also watch for technical causes like ensuring the content is compressed, time to the first byte, optimize images, ensuring reasonable DOM size, SSL and many others. It's advisable to have these rich monitors both during development, as part of the CI and most important - 24x7 over the production's servers/CDN
    -❌ **Otherwise:** It must be disappointing to realize that after such great care for crafting a UI, 100% functional tests passing and sophisticated bundling - the UX is horrible and slow due to CDN misconfiguration +❌ **در غیر این صورت:** باید ناامید کننده باشد که متوجه شوید پس از چنین دقت زیادی برای ایجاد یک UI، تست های عملکردی 100% گذرانده شده و بسته بندی پیچیده - UX به دلیل پیکربندی اشتباه CDN وحشتناک و کند است.
    -
    Code Examples +
    نمونه کد -### :clap: Doing It Right Example: Lighthouse page load inspection report +### :clap: انجام درست مثال: گزارش بازرسی بارگذاری صفحه فانوس دریایی ![](/assets/lighthouse2.png "Lighthouse page load inspection report") @@ -1384,26 +1384,26 @@ test("movie title appears", async () => {
    -## ⚪ ️ 3.6 Stub flaky and slow resources like backend APIs +## ⚪ ️ 3.6 منابع ضعیف و کندی مانند APIهای Backend را جمع آوری کنید -:white_check_mark: **Do:** When coding your mainstream tests (not E2E tests), avoid involving any resource that is beyond your responsibility and control like backend API and use stubs instead (i.e. test double). Practically, instead of real network calls to APIs, use some test double library (like [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble), etc) for stubbing the API response. The main benefit is preventing flakiness - testing or staging APIs by definition are not highly stable and from time to time will fail your tests although YOUR component behaves just fine (production env was not meant for testing and it usually throttles requests). Doing this will allow simulating various API behavior that should drive your component behavior as when no data was found or the case when API throws an error. Last but not least, network calls will greatly slow down the tests +:white_check_mark: **انجام دادن:** هنگام کدنویسی تست‌های اصلی خود (نه تست‌های E2E)، از درگیر کردن هر منبعی که خارج از مسئولیت و کنترل شماست مانند API پشتیبان خودداری کنید و به جای آن از خرده‌ها استفاده کنید (یعنی تست دوبار). عملا، به جای تماس های شبکه واقعی با API ها، از چند کتابخانه دوتایی (مانند [Sinon](https://sinonjs.org/), [Test doubles](https://www.npmjs.com/package/testdouble), etc) برای کلفت کردن پاسخ API. مزیت اصلی جلوگیری از پوسته پوسته شدن است - آزمایش یا مرحله‌بندی APIها طبق تعریف چندان پایدار نیستند و هر از چند گاهی در تست‌های شما شکست می‌خورند، اگرچه مؤلفه شما به خوبی رفتار می‌کند (انواع تولید برای آزمایش در نظر گرفته نشده است و معمولاً درخواست‌ها را کاهش می‌دهد). انجام این کار به شبیه‌سازی رفتارهای API مختلف اجازه می‌دهد که رفتار مؤلفه شما را مانند زمانی که هیچ داده‌ای پیدا نمی‌شود یا زمانی که API خطا می‌دهد، هدایت کند. آخرین اما نه کم‌اهمیت، تماس‌های شبکه سرعت آزمایش‌ها را بسیار کند می‌کند
    -❌ **Otherwise:** The average test runs no longer than few ms, a typical API call last 100ms>, this makes each test ~20x slower +❌ **در غیر این صورت:** میانگین تست بیشتر از چند میلی ثانیه اجرا نمی شود، یک تماس API معمولی 100 میلی ثانیه طول می کشد>، این باعث می شود هر تست 20 برابر کندتر شود.
    -
    Code Examples +
    نمونه کد
    -### :clap: Doing It Right Example: Stubbing or intercepting API calls +### :clap: انجام درست مثال: قطع کردن یا رهگیری تماس‌های API ![](https://img.shields.io/badge/🔧%20Example%20using%20React-blue.svg "Examples with React") ![](https://img.shields.io/badge/🔧%20Example%20using%20React%20Testing%20Library-blue.svg "Examples with react-testing-library") ```javascript -// unit under test +// واحد در حال آزمایش export default function ProductsList() { const [products, setProducts] = useState(false); @@ -1419,17 +1419,17 @@ export default function ProductsList() { return products ?
    {products}
    :
    No products
    ; } -// test +// تست کردن test("When no products exist, show the appropriate message", () => { - // Arrange + // مقدار دهی کردن nock("api") .get(`/products`) .reply(404); - // Act + // اجرا کردن const { getByTestId } = render(); - // Assert + // مقایسه کردن expect(getByTestId("no-products-message")).toBeTruthy(); }); ``` @@ -1438,38 +1438,38 @@ test("When no products exist, show the appropriate message", () => {
    -## ⚪ ️ 3.7 Have very few end-to-end tests that spans the whole system +## ⚪ ️ 3.7 تعداد بسیار کمی از تست های سرتاسری که کل سیستم را در بر می گیرد -:white_check_mark: **Do:** Although E2E (end-to-end) usually means UI-only testing with a real browser (See [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)), for other they mean tests that stretch the entire system including the real backend. The latter type of tests is highly valuable as they cover integration bugs between frontend and backend that might happen due to a wrong understanding of the exchange schema. They are also an efficient method to discover backend-to-backend integration issues (e.g. Microservice A sends the wrong message to Microservice B) and even to detect deployment failures - there are no backend frameworks for E2E testing that are as friendly and mature as UI frameworks like [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). The downside of such tests is the high cost of configuring an environment with so many components, and mostly their brittleness - given 50 microservices, even if one fails then the entire E2E just failed. For that reason, we should use this technique sparingly and probably have 1-10 of those and no more. That said, even a small number of E2E tests are likely to catch the type of issues they are targeted for - deployment & integration faults. It's advisable to run those over a production-like staging environment +:white_check_mark: **انجام دادن:** اگرچه E2E (پایان به انتها) معمولاً به معنای آزمایش فقط UI با یک مرورگر واقعی است (نگاه کنید به [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)), برای دیگر آنها به معنای آزمایش هایی هستند که کل سیستم از جمله باطن واقعی را گسترش می دهند. تست‌های نوع دوم بسیار ارزشمند هستند، زیرا اشکالات یکپارچه‌سازی بین frontend و backend را پوشش می‌دهند که ممکن است به دلیل درک اشتباه از طرح مبادله رخ دهد. آنها همچنین یک روش کارآمد برای کشف مسائل یکپارچه سازی backend-to-backend هستند (مثلاً Microservice A پیام اشتباهی را به Microservice B ارسال می کند) و حتی برای تشخیص خرابی های استقرار - هیچ چارچوب Backend برای آزمایش E2E وجود ندارد که به اندازه UI دوستانه و بالغ باشد. چارچوب هایی مانند[Cypress](https://www.cypress.io/) و [Puppeteer](https://github.com/GoogleChrome/puppeteer). نقطه ضعف چنین آزمایش‌هایی هزینه بالای پیکربندی یک محیط با اجزای بسیار زیاد و بیشتر شکنندگی آنها است - با توجه به 50 میکروسرویس، حتی اگر یکی از آنها ناموفق باشد، کل E2E فقط از کار افتاده است. به همین دلیل، ما باید از این تکنیک کم استفاده کنیم و احتمالاً 1-10 مورد از آن‌ها را داشته باشیم و نه بیشتر. گفته می‌شود، حتی تعداد کمی از تست‌های E2E احتمالاً نوع مشکلاتی را که برای آنها هدف قرار گرفته‌اند - خطاهای استقرار و یکپارچه‌سازی را شناسایی می‌کنند. توصیه می‌شود آن‌ها را روی یک محیط صحنه‌سازی شبیه تولید اجرا کنید
    -❌ **Otherwise:** UI might invest much in testing its functionality only to realizes very late that the backend returned payload (the data schema the UI has to work with) is very different than expected +❌ **در غیر این صورت:** UI ممکن است برای آزمایش عملکرد خود سرمایه گذاری زیادی کند تا دیرتر متوجه شود که بار بازگشتی بازگشتی (شمایه داده ای که UI باید با آن کار کند) بسیار متفاوت از آنچه انتظار می رود است.
    -## ⚪ ️ 3.8 Speed-up E2E tests by reusing login credentials +## ⚪ ️ 3.8 با استفاده مجدد از اعتبارنامه ورود به سیستم، تست های E2E را افزایش دهید -:white_check_mark: **Do:** In E2E tests that involve a real backend and rely on a valid user token for API calls, it doesn't payoff to isolate the test to a level where a user is created and logged-in in every request. Instead, login only once before the tests execution start (i.e. before-all hook), save the token in some local storage and reuse it across requests. This seem to violate one of the core testing principle - keep the test autonomous without resources coupling. While this is a valid worry, in E2E tests performance is a key concern and creating 1-3 API requests before starting each individual tests might lead to horrible execution time. Reusing credentials doesn't mean the tests have to act on the same user records - if relying on user records (e.g. test user payments history) than make sure to generate those records as part of the test and avoid sharing their existence with other tests. Also remember that the backend can be faked - if your tests are focused on the frontend it might be better to isolate it and stub the backend API (see [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)). +:white_check_mark: **انجام دادن:** در تست‌های E2E که شامل یک باطن واقعی است و برای فراخوانی‌های API به یک توکن کاربر معتبر متکی است، جداسازی آزمون در سطحی که کاربر ایجاد شده و در هر درخواستی به سیستم وارد شود، سودی ندارد. در عوض، قبل از شروع اجرای آزمایش‌ها فقط یک بار وارد شوید (یعنی قبل از همه قلاب)، توکن را در برخی از حافظه‌های محلی ذخیره کنید و در درخواست‌ها مجدداً از آن استفاده کنید. به نظر می رسد که این یکی از اصول اصلی آزمایش را نقض می کند - تست را بدون جفت شدن منابع مستقل نگه دارید. در حالی که این یک نگرانی معتبر است، عملکرد در تست‌های E2E یک نگرانی کلیدی است و ایجاد 1-3 درخواست API قبل از شروع هر آزمایش ممکن است منجر به زمان اجرای وحشتناک شود. استفاده مجدد از اعتبارنامه‌ها به این معنی نیست که آزمایش‌ها باید روی سوابق کاربر یکسانی عمل کنند - اگر به سوابق کاربر (مثلاً سابقه پرداخت‌های کاربر آزمایشی) تکیه می‌کنند، مطمئن شوید که آن سوابق را به عنوان بخشی از آزمایش ایجاد کرده‌اید و از اشتراک‌گذاری وجود آنها با سایر آزمایش‌ها اجتناب کنید. همچنین به یاد داشته باشید که Backend می‌تواند جعلی باشد - اگر آزمایش‌های شما بر روی frontend متمرکز شده‌اند، بهتر است آن را ایزوله کنید و API باطن را خرد کنید (نگاه کنید به [bullet 3.6](https://github.com/goldbergyoni/javascript-testing-best-practices#-%EF%B8%8F-36-stub-flaky-and-slow-resources-like-backend-apis)).
    -❌ **Otherwise:** Given 200 test cases and assuming login=100ms = 20 seconds only for logging-in again and again +❌ **در غیر این صورت:** با توجه به 200 مورد تست و با فرض ورود = 100ms = 20 ثانیه فقط برای ورود مجدد و دوباره
    -
    Code Examples +
    نمونه کد
    -### :clap: Doing It Right Example: Logging-in before-all and not before-each +### :clap: انجام درست آن مثال: قبل از همه وارد شوید و نه قبل از هر کدام ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") ```javascript let authenticationToken; -// happens before ALL tests run +// قبل از اجرای همه آزمایشات اتفاق می افتد before(() => { cy.request('POST', 'http://localhost:3000/login', { username: Cypress.env('username'), @@ -1481,7 +1481,7 @@ before(() => { }) }) -// happens before EACH test +// قبل از هر آزمون اتفاق می افتد beforeEach(setUser => { cy.visit('/home', () => { onBeforeLoad (win => { @@ -1495,28 +1495,28 @@ beforeEach(setUser => {
    -## ⚪ ️ 3.9 Have one E2E smoke test that just travels across the site map +## ⚪ ️ 3.9 یک تست دود E2E داشته باشید که فقط در سراسر نقشه سایت حرکت می کند -:white_check_mark: **Do:** For production monitoring and development-time sanity check, run a single E2E test that visits all/most of the site pages and ensures no one breaks. This type of test brings a great return on investment as it's very easy to write and maintain, but it can detect any kind of failure including functional, network and deployment issues. Other styles of smoke and sanity checking are not as reliable and exhaustive - some ops teams just ping the home page (production) or developers who run many integration tests which don't discover packaging and browser issues. Goes without saying that the smoke test doesn't replace functional tests rather just aim to serve as a quick smoke detector +:white_check_mark: **انجام دادن:** برای نظارت بر تولید و بررسی سلامت زمان توسعه، یک تست E2E را اجرا کنید که از همه/بیشتر صفحات سایت بازدید می کند و مطمئن می شود که هیچ کس خراب نمی شود. این نوع تست بازگشت سرمایه زیادی را به ارمغان می آورد زیرا نوشتن و نگهداری آن بسیار آسان است، اما می تواند هر نوع خرابی از جمله مشکلات عملکردی، شبکه و استقرار را تشخیص دهد. سایر سبک‌های بررسی دود و سلامت عقل چندان قابل اعتماد و جامع نیستند - برخی از تیم‌های عملیاتی فقط صفحه اصلی (تولید) را پینگ می‌کنند یا توسعه‌دهندگانی که تست‌های ادغام زیادی را انجام می‌دهند که مشکلات بسته‌بندی و مرورگر را کشف نمی‌کنند. ناگفته نماند که تست دود جایگزین تست های عملکردی نمی شود، بلکه فقط به عنوان یک آشکارساز سریع دود عمل می کند.
    -❌ **Otherwise:** Everything might seem perfect, all tests pass, production health-check is also positive but the Payment component had some packaging issue and only the /Payment route is not rendering +❌ **در غیر این صورت:** ممکن است همه چیز عالی به نظر برسد، همه آزمایش‌ها با موفقیت انجام می‌شوند، بررسی سلامت تولید نیز مثبت است، اما مؤلفه پرداخت مشکلی در بسته‌بندی داشت و فقط مسیر پرداخت / رندر نمی‌شود.
    -
    Code Examples +
    نمونه کد
    -### :clap: Doing It Right Example: Smoke travelling across all pages +### :clap: انجام درست مثال: smoke در تمام صفحات حرکت می کند ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") ```javascript -it("When doing smoke testing over all page, should load them all successfully", () => { - // exemplified using Cypress but can be implemented easily - // using any E2E suite +it("هنگام انجام تست smoke در تمام صفحات، باید همه آنها را با موفقیت بارگیری کنید", () => { + // نمونه ای با استفاده از Cypress است اما می توان آن را به راحتی اجرا کرد + // با استفاده از هر مجموعه E2E cy.visit("https://mysite.com/home"); cy.contains("Home"); cy.visit("https://mysite.com/Login"); @@ -1530,24 +1530,24 @@ it("When doing smoke testing over all page, should load them all successfully",
    -## ⚪ ️ 3.10 Expose the tests as a live collaborative document +## ⚪ ️ 3.10 آزمایش ها را به عنوان یک سند مشارکتی زنده در معرض دید قرار دهید -:white_check_mark: **Do:** Besides increasing app reliability, tests bring another attractive opportunity to the table - serve as live app documentation. Since tests inherently speak at a less-technical and product/UX language, using the right tools they can serve as a communication artifact that greatly aligns all the peers - developers and their customers. For example, some frameworks allow expressing the flow and expectations (i.e. tests plan) using a human-readable language so any stakeholder, including product managers, can read, approve and collaborate on the tests which just became the live requirements document. This technique is also being referred to as 'acceptance test' as it allows the customer to define his acceptance criteria in plain language. This is [BDD (behavior-driven testing)](https://en.wikipedia.org/wiki/Behavior-driven_development) at its purest form. One of the popular frameworks that enable this is [Cucumber which has a JavaScript flavor](https://github.com/cucumber/cucumber-js), see example below. Another similar yet different opportunity, [StoryBook](https://storybook.js.org/), allows exposing UI components as a graphic catalog where one can walk through the various states of each component (e.g. render a grid w/o filters, render that grid with multiple rows or with none, etc), see how it looks like, and how to trigger that state - this can appeal also to product folks but mostly serves as live doc for developers who consume those components. +:white_check_mark: **انجام دادن:** علاوه بر افزایش قابلیت اطمینان برنامه، آزمایش‌ها فرصت جذاب دیگری را به روی میز می‌آورند - به عنوان مستندات برنامه زنده ارائه می‌شوند. از آنجایی که تست‌ها ذاتاً با زبانی کمتر فنی و محصول/UX صحبت می‌کنند، با استفاده از ابزارهای مناسب می‌توانند به عنوان یک مصنوع ارتباطی عمل کنند که تا حد زیادی همه همتایان - توسعه‌دهندگان و مشتریانشان را همسو می‌کند. برای مثال، برخی از چارچوب‌ها امکان بیان جریان و انتظارات (یعنی طرح آزمایش‌ها) را با استفاده از زبانی قابل خواندن برای انسان فراهم می‌کنند تا هر ذینفع، از جمله مدیران محصول، بتوانند آزمایش‌هایی را که به‌تازگی به سند نیازمندی‌های زنده تبدیل شده‌اند، بخوانند، تأیید کنند و در آن همکاری کنند. این تکنیک همچنین به عنوان "آزمون پذیرش" نامیده می شود زیرا به مشتری اجازه می دهد معیارهای پذیرش خود را به زبان ساده تعریف کند. این هست [BDD (behavior-driven testing)](https://en.wikipedia.org/wiki/Behavior-driven_development) در خالص ترین شکل خود یکی از فریمورک های محبوبی که این امکان را فراهم می کند این است [Cucumber which has a JavaScript flavor](https://github.com/cucumber/cucumber-js), مثال زیر را ببینید یک فرصت مشابه اما متفاوت دیگر, [StoryBook](https://storybook.js.org/), اجازه می دهد تا مؤلفه های رابط کاربری را به عنوان یک کاتالوگ گرافیکی در معرض دید قرار دهید، جایی که می توانید در حالت های مختلف هر مؤلفه قدم بزنید (مثلاً یک شبکه بدون فیلتر ارائه دهید، آن شبکه را با چندین ردیف یا با هیچ کدام و غیره ارائه کنید)، ببینید چگونه به نظر می رسد و چگونه است. برای راه اندازی آن حالت - این می تواند برای افراد محصول نیز جذاب باشد، اما بیشتر به عنوان سند زنده برای توسعه دهندگانی که آن اجزا را مصرف می کنند، عمل می کند. -❌ **Otherwise:** After investing top resources on testing, it's just a pity not to leverage this investment and win great value +❌ **در غیر این صورت:** پس از سرمایه گذاری منابع برتر در آزمایش، فقط حیف است که از این سرمایه گذاری استفاده نکنید و ارزش زیادی کسب نکنید
    -
    Code Examples +
    نمونه کد
    -### :clap: Doing It Right Example: Describing tests in human-language using cucumber-js +### :clap: انجام درست آن مثال: توصیف تست ها به زبان انسان با استفاده از cucumber-js ![](https://img.shields.io/badge/🔨%20Example%20using%20Cucumber-blue.svg "Examples using Cucumber") ```text -This is how one can describe tests using cucumber: plain language that allows anyone to understand and collaborate +اینگونه می توان تست ها را با استفاده از cucumber توصیف کرد: زبانی ساده که به هر کسی اجازه می دهد درک کند و همکاری کند. Feature: Twitter new tweet @@ -1562,7 +1562,7 @@ Feature: Twitter new tweet Then I see message "Tweet saved" ``` -### :clap: Doing It Right Example: Visualizing our components, their various states and inputs using Storybook +### :clap: انجام درست مثال: تجسم اجزای ما، حالت‌های مختلف و ورودی‌های آنها با استفاده از Storybook ![](https://img.shields.io/badge/🔨%20Example%20using%20StoryBook-blue.svg "Using StoryBook") @@ -1572,27 +1572,27 @@ Feature: Twitter new tweet

    -## ⚪ ️ 3.11 Detect visual issues with automated tools +## ⚪ ️ 3.11 مشکلات بصری را با ابزارهای خودکار تشخیص دهید -:white_check_mark: **Do:** Setup automated tools to capture UI screenshots when changes are presented and detect visual issues like content overlapping or breaking. This ensures that not only the right data is prepared but also the user can conveniently see it. This technique is not widely adopted, our testing mindset leans toward functional tests but it's the visuals what the user experience and with so many device types it's very easy to overlook some nasty UI bug. Some free tools can provide the basics - generate and save screenshots for the inspection of human eyes. While this approach might be sufficient for small apps, it's flawed as any other manual testing that demands human labor anytime something changes. On the other hand, it's quite challenging to detect UI issues automatically due to the lack of clear definition - this is where the field of 'Visual Regression' chime in and solve this puzzle by comparing old UI with the latest changes and detect differences. Some OSS/free tools can provide some of this functionality (e.g. [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>) but might charge significant setup time. The commercial line of tools (e.g. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) takes is a step further by smoothing the installation and packing advanced features like management UI, alerting, smart capturing by eliminating 'visual noise' (e.g. ads, animations) and even root cause analysis of the DOM/CSS changes that led to the issue +:white_check_mark: **انجام دادن:** ابزارهای خودکار را برای گرفتن اسکرین شات های رابط کاربری در هنگام ارائه تغییرات تنظیم کنید و مشکلات بصری مانند همپوشانی یا شکستن محتوا را شناسایی کنید. این تضمین می‌کند که نه تنها داده‌های مناسب آماده می‌شوند، بلکه کاربر نیز می‌تواند به راحتی آن‌ها را ببیند. این تکنیک به طور گسترده مورد استفاده قرار نگرفته است، طرز فکر تست ما به سمت تست‌های عملکردی گرایش دارد، اما تصاویر آن چیزی است که کاربر تجربه می‌کند و با انواع دستگاه‌های بسیار، نادیده گرفتن برخی از باگ‌های ناخوشایند UI بسیار آسان است. برخی از ابزارهای رایگان می توانند اصول اولیه را فراهم کنند - اسکرین شات ها را برای بازرسی چشم انسان تولید و ذخیره کنند. اگرچه این رویکرد ممکن است برای برنامه‌های کوچک کافی باشد، اما مانند هر آزمایش دستی دیگری که هر زمان که چیزی تغییر می‌کند به نیروی انسانی نیاز دارد، ناقص است. از سوی دیگر، به دلیل نداشتن تعریف واضح، تشخیص خودکار مسائل رابط کاربری بسیار چالش برانگیز است - اینجاست که میدان "رگرسیون بصری" به صدا در می آید و با مقایسه رابط کاربری قدیمی با آخرین تغییرات و تشخیص تفاوت ها، این معما را حل می کند. برخی از ابزارهای OSS/رایگان می توانند برخی از این قابلیت ها را ارائه دهند (e.g. [wraith](https://github.com/BBC-News/wraith), [PhantomCSS](<[https://github.com/HuddleEng/PhantomCSS](https://github.com/HuddleEng/PhantomCSS)>) اما ممکن است زمان راه اندازی قابل توجهی را شارژ کند. خط تجاری ابزار (e.g. [Applitools](https://applitools.com/), [Percy.io](https://percy.io/)) با هموارسازی نصب و بسته‌بندی ویژگی‌های پیشرفته مانند رابط کاربری مدیریت، هشدار، ضبط هوشمند با حذف نویز بصری (مانند تبلیغات، انیمیشن‌ها) و حتی تجزیه و تحلیل علت اصلی تغییرات DOM/CSS که منجر به این مشکل شده است، یک قدم بیشتر است.
    -❌ **Otherwise:** How good is a content page that display great content (100% tests passed), loads instantly but half of the content area is hidden? +❌ **در غیر این صورت:** صفحه محتوایی که محتوای عالی را نمایش می‌دهد چقدر خوب است (100٪ تست‌ها با موفقیت انجام شد)، فورا بارگیری می‌شود اما نیمی از منطقه محتوا پنهان است.?
    -
    Code Examples +
    نمونه کد
    -### :thumbsdown: Anti-Pattern Example: A typical visual regression - right content that is served badly +### :thumbsdown: مثال ضد الگو: یک رگرسیون بصری معمولی - محتوای درستی که بد ارائه می شود ![alt text](assets/amazon-visual-regression.jpeg "Amazon page breaks")
    -### :clap: Doing It Right Example: Configuring wraith to capture and compare UI snapshots +### :clap: انجام درست مثال: پیکربندی wraith برای گرفتن و مقایسه عکس های فوری UI ![](https://img.shields.io/badge/🔨%20Example%20using%20Wraith-blue.svg "Using Wraith") @@ -1621,7 +1621,7 @@ paths: path: /subscribe ``` -### :clap: Doing It Right Example: Using Applitools to get snapshot comparison and other advanced features +### :clap: انجام درست مثال: استفاده از Applitools برای مقایسه عکس فوری و سایر ویژگی های پیشرفته ![](https://img.shields.io/badge/🔨%20Example%20using%20AppliTools-blue.svg "Using Applitools") ![](https://img.shields.io/badge/🔨%20Example%20using%20Cypress-blue.svg "Using Cypress to illustrate the idea") @@ -1648,33 +1648,33 @@ describe("visual validation", () => {

    -# Section 4️⃣: Measuring Test Effectiveness +# بخش 4️⃣: اندازه گیری اثربخشی آزمون

    -## ⚪ ️ 4.1 Get enough coverage for being confident, ~80% seems to be the lucky number +## ⚪ ️ 4.1 پوشش کافی برای داشتن اعتماد به نفس داشته باشید، به نظر می رسد 80٪ عدد خوش شانس باشد -:white_check_mark: **Do:** The purpose of testing is to get enough confidence for moving fast, obviously the more code is tested the more confident the team can be. Coverage is a measure of how many code lines (and branches, statements, etc) are being reached by the tests. So how much is enough? 10–30% is obviously too low to get any sense about the build correctness, on the other side 100% is very expensive and might shift your focus from the critical paths to the exotic corners of the code. The long answer is that it depends on many factors like the type of application — if you’re building the next generation of Airbus A380 than 100% is a must, for a cartoon pictures website 50% might be too much. Although most of the testing enthusiasts claim that the right coverage threshold is contextual, most of them also mention the number 80% as a thumb of a rule ([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)) that presumably should satisfy most of the applications. +:white_check_mark: **انجام دادن:** هدف از تست گرفتن اعتماد به نفس کافی برای حرکت سریع است، بدیهی است که هر چه کد بیشتر تست شود، تیم می تواند اعتماد بیشتری داشته باشد. پوشش معیاری است از تعداد خطوط کد (و شاخه ها، دستورات و غیره) که توسط آزمایش ها به دست می آیند. پس چقدر کافی است؟ 10-30٪ واضح است که برای درک درستی ساخت بسیار کم است، از طرف دیگر 100٪ بسیار گران است و ممکن است تمرکز شما را از مسیرهای مهم به گوشه های عجیب و غریب کد تغییر دهد. پاسخ طولانی این است که به عوامل زیادی مانند نوع برنامه بستگی دارد - اگر شما در حال ساخت نسل بعدی ایرباس A380 هستید، 100٪ ضروری است، برای یک وب سایت تصاویر کارتونی 50٪ ممکن است خیلی زیاد باشد. اگرچه اکثر علاقه مندان به تست ادعا می کنند که آستانه پوشش مناسب متنی است، اکثر آنها عدد 80٪ را نیز به عنوان یک قانون ذکر می کنند. ([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)) که احتمالاً باید اکثر برنامه ها را برآورده کند. -Implementation tips: You may want to configure your continuous integration (CI) to have a coverage threshold ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) and stop a build that doesn’t stand to this standard (it’s also possible to configure threshold per component, see code example below). On top of this, consider detecting build coverage decrease (when a newly committed code has less coverage) — this will push developers raising or at least preserving the amount of tested code. All that said, coverage is only one measure, a quantitative based one, that is not enough to tell the robustness of your testing. And it can also be fooled as illustrated in the next bullets +نکات پیاده سازی: ممکن است بخواهید ادغام پیوسته (CI) خود را برای داشتن آستانه پوشش پیکربندی کنید. ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) و ساختنی را که مطابق با این استاندارد نیست متوقف کنید (همچنین می توان آستانه را برای هر جزء پیکربندی کرد، به مثال کد زیر مراجعه کنید). علاوه بر این، تشخیص کاهش پوشش ساخت را در نظر بگیرید (زمانی که یک کد جدید متعهد شده دارای پوشش کمتری است)— این باعث می‌شود توسعه‌دهندگان مقدار کد تست شده را افزایش دهند یا حداقل حفظ کنند. همه آنچه گفته شد، پوشش تنها یک معیار است، یک معیار مبتنی بر کمی، که برای نشان دادن استحکام آزمایش شما کافی نیست. و همچنین همانطور که در گلوله های بعدی نشان داده شده است می توان آن را فریب داد
    -❌ **Otherwise:** Confidence and numbers go hand in hand, without really knowing that you tested most of the system — there will also be some fear and fear will slow you down +❌ **در غیر این صورت:** اعتماد به نفس و اعداد دست به دست هم می دهند، بدون اینکه واقعاً بدانید که بیشتر سیستم را آزمایش کرده اید - همچنین مقداری ترس وجود خواهد داشت و ترس سرعت شما را کاهش می دهد.
    -
    Code Examples +
    نمونه کد
    -### :clap: Example: A typical coverage report +### :clap: مثال: یک گزارش پوشش معمولی ![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "A typical coverage report")
    -### :clap: Doing It Right Example: Setting up coverage per component (using Jest) +### :clap: انجام درست آن مثال: تنظیم پوشش برای هر جزء (با استفاده از Jest) ![](https://img.shields.io/badge/🔨%20Example%20using%20Jest-blue.svg "Using Jest") @@ -1684,22 +1684,22 @@ Implementation tips: You may want to configure your continuous integration (CI)

    -## ⚪ ️ 4.2 Inspect coverage reports to detect untested areas and other oddities +## ⚪ ️ 4.2 گزارش های پوشش را برای شناسایی مناطق آزمایش نشده و سایر موارد عجیب بازرسی کنید -:white_check_mark: **Do:** Some issues sneak just under the radar and are really hard to find using traditional tools. These are not really bugs but more of surprising application behavior that might have a severe impact. For example, often some code areas are never or rarely being invoked — you thought that the ‘PricingCalculator’ class is always setting the product price but it turns out it is actually never invoked although we have 10000 products in DB and many sales… Code coverage reports help you realize whether the application behaves the way you believe it does. Other than that, it can also highlight which types of code is not tested — being informed that 80% of the code is tested doesn’t tell whether the critical parts are covered. Generating reports is easy — just run your app in production or during testing with coverage tracking and then see colorful reports that highlight how frequent each code area is invoked. If you take your time to glimpse into this data — you might find some gotchas +:white_check_mark: **انجام دادن:** برخی از مسائل دقیقاً زیر رادار پنهان می شوند و با استفاده از ابزارهای سنتی پیدا کردن آنها واقعاً سخت است. اینها واقعاً باگ نیستند، بلکه بیشتر رفتارهای شگفت انگیز برنامه هستند که ممکن است تأثیر شدیدی داشته باشند. به عنوان مثال، اغلب برخی از مناطق کد هرگز یا به ندرت فراخوانی نمی شوند - شما فکر می کنید که کلاس "PricingCalculator" همیشه قیمت محصول را تعیین می کند، اما به نظر می رسد که در واقع هرگز فراخوانی نمی شود، اگرچه ما 10000 محصول در DB داریم و تعداد زیادی فروش... پوشش کد گزارش‌ها به شما کمک می‌کنند متوجه شوید که آیا برنامه به‌گونه‌ای که شما فکر می‌کنید رفتار می‌کند یا خیر. به غیر از آن، همچنین می‌تواند مشخص کند که کدام نوع کد آزمایش نشده است - با اطلاع از اینکه 80 درصد کد آزمایش شده است، نمی‌گوید که آیا قسمت‌های حیاتی پوشش داده شده‌اند یا خیر. ایجاد گزارش آسان است - فقط برنامه خود را در مرحله تولید یا در حین آزمایش با ردیابی پوشش اجرا کنید و سپس گزارش‌های رنگارنگی را مشاهده کنید که نشان می‌دهد تعداد دفعات فراخوانی هر ناحیه کد مشخص می‌شود. اگر وقت خود را صرف نگاهی اجمالی به این داده ها کنید - ممکن است چند اشتباه پیدا کنید
    -❌ **Otherwise:** If you don’t know which parts of your code are left un-tested, you don’t know where the issues might come from +❌ **در غیر این صورت:** اگر نمی‌دانید کدام بخش از کدتان آزمایش نشده است، نمی‌دانید این مشکلات از کجا می‌آیند.
    -
    Code Examples +
    نمونه کد
    -### :thumbsdown: Anti-Pattern Example: What’s wrong with this coverage report? +### :thumbsdown: مثال ضد الگو: این گزارش پوشش چه اشکالی دارد؟ -Based on a real-world scenario where we tracked our application usage in QA and find out interesting login patterns (Hint: the amount of login failures is non-proportional, something is clearly wrong. Finally it turned out that some frontend bug keeps hitting the backend login API) +بر اساس یک سناریوی واقعی که در آن ما استفاده از برنامه خود را در QA ردیابی کردیم و الگوهای ورود جالبی را پیدا کردیم (نکته: میزان خرابی های ورود به سیستم نامتناسب است، چیزی به وضوح اشتباه است. در نهایت مشخص شد که برخی از باگ های frontend مدام به سیستم وارد می شوند. API ورود باطن) ![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report?") @@ -1707,28 +1707,28 @@ Based on a real-world scenario where we tracked our application usage in QA and

    -## ⚪ ️ 4.3 Measure logical coverage using mutation testing +## ⚪ ️ 4.3 اندازه گیری پوشش منطقی با استفاده از تست جهش -:white_check_mark: **Do:** The Traditional Coverage metric often lies: It may show you 100% code coverage, but none of your functions, even not one, return the right response. How come? it simply measures over which lines of code the test visited, but it doesn’t check if the tests actually tested anything — asserted for the right response. Like someone who’s traveling for business and showing his passport stamps — this doesn’t prove any work done, only that he visited few airports and hotels. +:white_check_mark: **انجام دادن:** معیار پوشش سنتی اغلب دروغ می گوید: ممکن است پوشش 100٪ کد را به شما نشان دهد، اما هیچ یک از توابع شما، حتی یک مورد، پاسخ مناسب را نشان نمی دهد. چطور؟ آن را به سادگی اندازه گیری می کند که از کدام خطوط کد تست بازدید کرده است، اما بررسی نمی کند که آیا آزمون ها واقعاً چیزی را آزمایش کرده اند - برای پاسخ درست اظهار شده است. مانند کسی که برای تجارت سفر می کند و مهر پاسپورت خود را نشان می دهد - این نشان دهنده انجام هیچ کاری نیست، فقط اینکه او از تعداد کمی از فرودگاه ها و هتل ها بازدید کرده است. -Mutation-based testing is here to help by measuring the amount of code that was actually TESTED not just VISITED. [Stryker](https://stryker-mutator.io/) is a JavaScript library for mutation testing and the implementation is really neat: +آزمایش مبتنی بر جهش با اندازه‌گیری مقدار کدی که واقعاً تست شده است و نه فقط بازدید شده، به شما کمک می‌کند.. [Stryker](https://stryker-mutator.io/) یک کتابخانه جاوا اسکریپت برای آزمایش جهش است و پیاده سازی آن واقعاً منظم است: -(1) it intentionally changes the code and “plants bugs”. For example the code newOrder.price===0 becomes newOrder.price!=0. This “bugs” are called mutations +(1) به عمد کد را تغییر می دهد و "اشکالات گیاهی" را ایجاد می کند. برای مثال کد newOrder.price===0 به newOrder.price!=0 تبدیل می شود. این "اشکال" جهش نامیده می شود -(2) it runs the tests, if all succeed then we have a problem — the tests didn’t serve their purpose of discovering bugs, the mutations are so-called survived. If the tests failed, then great, the mutations were killed. +(2) تست ها را اجرا می کند، اگر همه موفق شوند، مشکل داریم - آزمایش ها به هدف خود یعنی کشف باگ ها عمل نکردند، جهش ها به اصطلاح زنده می مانند. اگر آزمایش ها شکست خوردند، عالی است، جهش ها کشته شدند. -Knowing that all or most of the mutations were killed gives much higher confidence than traditional coverage and the setup time is similar +دانستن اینکه همه یا بیشتر جهش‌ها کشته شده‌اند، اطمینان بسیار بیشتری نسبت به پوشش سنتی می‌دهد و زمان راه‌اندازی مشابه است.
    -❌ **Otherwise:** You’ll be fooled to believe that 85% coverage means your test will detect bugs in 85% of your code +❌ **در غیر این صورت:** شما فریب خواهید خورد که فکر کنید پوشش 85٪ به این معنی است که تست شما اشکالات را در 85٪ از کد شما تشخیص می دهد.
    -
    Code Examples +
    نمونه کد
    -### :thumbsdown: Anti-Pattern Example: 100% coverage, 0% testing +### :thumbsdown: مثال ضد الگو: 100% پوشش، 0% تست ![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Using Stryker") @@ -1741,14 +1741,14 @@ function addNewOrder(newOrder) { return { approved: true }; } -it("Test addNewOrder, don't use such test names", () => { +it("addNewOrder را تست کنید، از چنین نام های آزمایشی استفاده نکنید", () => { addNewOrder({ assignee: "John@mailer.com", price: 120 }); -}); //Triggers 100% code coverage, but it doesn't check anything +}); //پوشش 100٪ کد را فعال می کند، اما چیزی را بررسی نمی کند ```
    -### :clap: Doing It Right Example: Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations) +### :clap: انجام درست مثال: گزارش های Stryker، ابزاری برای آزمایش جهش، مقدار کدی را که آزمایش نشده است شناسایی و شمارش می کند (جهش) ![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations)") @@ -1756,32 +1756,32 @@ it("Test addNewOrder, don't use such test names", () => {

    -## ⚪ ️4.4 Preventing test code issues with Test linters +## ⚪ ️4.4 جلوگیری از مشکلات کد تست با لینترهای تست -:white_check_mark: **Do:** A set of ESLint plugins were built specifically for inspecting the tests code patterns and discover issues. For example, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) will warn when a test is written at the global level (not a son of a describe() statement) or when tests are [skipped](https://mochajs.org/#inclusive-tests) which might lead to a false belief that all tests are passing. Similarly, [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) can, for example, warn when a test has no assertions at all (not checking anything) +:white_check_mark: **انجام دادن:** مجموعه ای از پلاگین های ESLint به طور خاص برای بازرسی الگوهای کد تست و کشف مشکلات ساخته شده است. مثلا, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) هنگامی که یک تست در سطح جهانی نوشته می شود (نه یک عبارت describe()) یا زمانی که تست ها [پرش کرد](https://mochajs.org/#inclusive-tests) که ممکن است به این باور نادرست منجر شود که همه آزمون ها قبول شده اند. به همین ترتیب، [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) برای مثال می تواند هشدار دهد زمانی که یک آزمون اصلاً ادعایی ندارد (چک نکردن چیزی)
    -❌ **Otherwise:** Seeing 90% code coverage and 100% green tests will make your face wear a big smile only until you realize that many tests aren’t asserting for anything and many test suites were just skipped. Hopefully, you didn’t deploy anything based on this false observation +❌ **در غیر این صورت:** مشاهده 90% پوشش کد و 100% تست‌های سبز باعث می‌شود چهره شما لبخند بزرگی بزند فقط تا زمانی که متوجه شوید که بسیاری از تست‌ها برای هیچ چیزی ادعا نمی‌کنند و بسیاری از مجموعه‌های آزمایشی صرفاً نادیده گرفته شده‌اند. امیدوارم بر اساس این مشاهده نادرست چیزی را مستقر نکرده باشید
    -
    Code Examples +
    نمونه کد
    -### :thumbsdown: Anti-Pattern Example: A test case full of errors, luckily all are caught by Linters +### :thumbsdown:مثال ضد الگو: یک مورد آزمایشی پر از خطا، خوشبختانه همه توسط Linters دستگیر شدند ```javascript -describe("Too short description", () => { - const userToken = userService.getDefaultToken() // *error:no-setup-in-describe, use hooks (sparingly) instead - it("Some description", () => {});//* error: valid-test-description. Must include the word "Should" + at least 5 words +describe("توضیحات خیلی کوتاه", () => { + const userToken = userService.getDefaultToken() // *error:no-setup-in-describe، به جای آن از هوک ها (به مقدار کم) استفاده کنید + it("کمی توضیحات", () => {});//* error: valid-test-description. باید شامل کلمه "Should" + حداقل 5 کلمه باشد }); -it.skip("Test name", () => {// *error:no-skipped-tests, error:error:no-global-tests. Put tests only under describe or suite +it.skip("نام تست", () => {// *error:no-skipped-tests, error:error:no-global-tests. تست ها را فقط در قسمت توصیف یا مجموعه قرار دهید expect("somevalue"); // error:no-assert }); -it("Test name", () => {// *error:no-identical-title. Assign unique titles to tests +it("نام تست", () => {// *error:no-identical-title. عناوین منحصر به فرد را به آزمون ها اختصاص دهید }); ``` @@ -1789,24 +1789,24 @@ it("Test name", () => {// *error:no-identical-title. Assign unique titles to tes

    -# Section 5️⃣: CI and Other Quality Measures +# بخش 5️⃣: CI و سایر معیارهای کیفیت

    ## ⚪ ️ 5.1 Enrich your linters and abort builds that have linting issues -:white_check_mark: **Do:** Linters are a free lunch, with 5 min setup you get for free an auto-pilot guarding your code and catching significant issue as you type. Gone are the days where linting was about cosmetics (no semi-colons!). Nowadays, Linters can catch severe issues like errors that are not thrown correctly and losing information. On top of your basic set of rules (like [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) or [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), consider including some specializing Linters like [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) that can discover tests without assertions, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) can discover promises with no resolve (your code will never continue), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) which can discover eager regex expressions that might get used for DOS attacks, and [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) is capable of alarming when the code uses utility library methods that are part of the V8 core methods like Lodash.\_map(…) +:white_check_mark: **انجام دادن:** لینترها یک ناهار رایگان هستند، با راه اندازی 5 دقیقه ای به صورت رایگان یک خلبان خودکار از کد شما محافظت می کند و هنگام تایپ مشکل مهمی را متوجه می شوید. روزهایی که پرزها در مورد لوازم آرایشی بودند (نه نیم کولن!) گذشته است. امروزه، Linters می تواند مشکلات شدیدی مانند خطاهایی که به درستی پرتاب نمی شوند و اطلاعات از دست می دهند، بگیرند. علاوه بر مجموعه قوانین اساسی شما (مانند [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) یا [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), شامل برخی از Linters تخصصی مانند [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) که می تواند تست ها را بدون ادعا کشف کند, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) می تواند وعده ها را بدون هیچ مشکلی کشف کند (کد شما هرگز ادامه نخواهد داشت), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) که می تواند عبارات regex مشتاق را کشف کند که ممکن است برای حملات DOS استفاده شود، و [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) زمانی که کد از روش‌های کتابخانه ابزاری استفاده می‌کند که بخشی از روش‌های هسته V8 مانند Lodash هستند، می‌تواند هشدار دهد.\_map(…)
    -❌ **Otherwise:** Consider a rainy day where your production keeps crashing but the logs don’t display the error stack trace. What happened? Your code mistakenly threw a non-error object and the stack trace was lost, a good reason for banging your head against a brick wall. A 5 min linter setup could detect this TYPO and save your day +❌ **در غیر این صورت:**یک روز بارانی را در نظر بگیرید که در آن تولید شما مدام خراب می‌شود اما گزارش‌ها ردیابی پشته خطا را نشان نمی‌دهند. چی شد؟ کد شما به اشتباه یک شی بدون خطا پرتاب کرد و رد پشته از بین رفت، دلیل خوبی برای ضربه زدن سر خود به دیوار آجری است. یک راه‌اندازی 5 دقیقه‌ای لینتر می‌تواند این اشتباه تایپی را شناسایی کرده و در روز شما صرفه‌جویی کند
    -
    Code Examples +
    نمونه کد
    -### :thumbsdown: Anti-Pattern Example: The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug +### :thumbsdown: مثال Anti-Pattern: شی Error اشتباه به اشتباه پرتاب شده است، هیچ stack-trace برای این خطا ظاهر نمی شود. خوشبختانه ESLint باگ تولید بعدی را پیدا می کند ![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug") @@ -1814,22 +1814,22 @@ it("Test name", () => {// *error:no-identical-title. Assign unique titles to tes

    -## ⚪ ️ 5.2 Shorten the feedback loop with local developer-CI +## ⚪ ️ 5.2 حلقه بازخورد را با توسعه دهنده-CI محلی کوتاه کنید -:white_check_mark: **Do:** Using a CI with shiny quality inspections like testing, linting, vulnerabilities check, etc? Help developers run this pipeline also locally to solicit instant feedback and shorten the [feedback loop](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). Why? an efficient testing process constitutes many and iterative loops: (1) try-outs -> (2) feedback -> (3) refactor. The faster the feedback is, the more improvement iterations a developer can perform per-module and perfect the results. On the flip, when the feedback is late to come fewer improvement iterations could be packed into a single day, the team might already move forward to another topic/task/module and might not be up for refining that module. +:white_check_mark: **انجام دادن:** آیا از یک CI با بازرسی های کیفیت براق مانند آزمایش، پرده زدن، بررسی آسیب پذیری ها و غیره استفاده می کنید؟ به توسعه دهندگان کمک کنید تا این خط لوله را نیز به صورت محلی اجرا کنند تا بازخورد فوری دریافت کنند و زمان را کوتاه کنند [حلقه بازخورد](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). چرا؟ یک فرآیند تست کارآمد حلقه های تکراری و متعددی را تشکیل می دهد: (1) آزمایشات -> (2) بازخورد -> (3) بازساز. هرچه بازخورد سریعتر باشد، توسعه دهنده می تواند تکرارهای بهبود بیشتری را در هر ماژول انجام دهد و نتایج را کامل کند. در تلنگر، زمانی که بازخورد دیر می رسد، تکرارهای بهبود کمتری می تواند در یک روز بسته بندی شود، تیم ممکن است در حال حاضر به سمت موضوع/وظیفه/ماژول دیگری حرکت کند و ممکن است برای اصلاح آن ماژول آماده نباشد. -Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) allow running the pipeline locally. Some commercial tools like [wallaby provide highly-valuable & testing insights](https://wallabyjs.com/) as a developer prototype (no affiliation). Alternatively, you may just add npm script to package.json that runs all the quality commands (e.g. test, lint, vulnerabilities) — use tools like [concurrently](https://www.npmjs.com/package/concurrently) for parallelization and non-zero exit code if one of the tools failed. Now the developer should just invoke one command — e.g. ‘npm run quality’ — to get instant feedback. Consider also aborting a commit if the quality check failed using a githook ([husky can help](https://github.com/typicode/husky)) +در عمل، برخی از فروشندگان CI (مثال: [CLI محلی CircleCI](https://circleci.com/docs/2.0/local-cli/)) اجازه می دهد خط لوله را به صورت محلی اجرا کند. برخی از ابزارهای تجاری مانند [wallaby بینش های بسیار ارزشمند و آزمایشی را ارائه می دهد](https://wallabyjs.com/) به عنوان نمونه اولیه توسعه دهنده (بدون وابستگی). از طرف دیگر، می‌توانید اسکریپت npm را به package.json اضافه کنید که تمام دستورات کیفیت (مانند تست، پرز، آسیب‌پذیری‌ها) را اجرا می‌کند - از ابزارهایی مانند استفاده کنید. [همزمان](https://www.npmjs.com/package/concurrently) برای موازی سازی و کد خروج غیر صفر در صورت خرابی یکی از ابزارها. اکنون توسعه‌دهنده باید فقط یک دستور را فراخوانی کند - به عنوان مثال. "کیفیت اجرای npm" - برای دریافت بازخورد فوری. همچنین در صورت عدم موفقیت بررسی کیفیت با استفاده از githook، یک commit را لغو کنید ([هاسکی می تواند کمک کند](https://github.com/typicode/husky))
    -❌ **Otherwise:** When the quality results arrive the day after the code, testing doesn’t become a fluent part of development rather an after the fact formal artifact +❌ **در غیر این صورت:** هنگامی که نتایج کیفی یک روز پس از کد به دست می‌آیند، آزمایش به بخشی روان از توسعه تبدیل نمی‌شود، بلکه به یک مصنوع رسمی پس از واقعیت تبدیل می‌شود.
    -
    Code Examples +
    نمونه های کد
    -### :clap: Doing It Right Example: npm scripts that perform code quality inspection, all are run in parallel on demand or when a developer is trying to push new code +### :clap: درست انجام دادن مثال: اسکریپت‌های npm که بازرسی کیفیت کد را انجام می‌دهند، همه به‌صورت موازی اجرا می‌شوند یا زمانی که یک توسعه‌دهنده تلاش می‌کند کد جدیدی را وارد کند. ```json { @@ -1854,22 +1854,22 @@ Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com

    -## ⚪ ️5.3 Perform e2e testing over a true production-mirror +## ⚪ ️5.3 آزمایش e2e را روی یک آینه تولید واقعی انجام دهید -:white_check_mark: **Do:** End to end (e2e) testing are the main challenge of every CI pipeline — creating an identical ephemeral production mirror on the fly with all the related cloud services can be tedious and expensive. Finding the best compromise is your game: [Docker-compose](https://serverless.com/) allows crafting isolated dockerized environment with identical containers using a single plain text file but the backing technology (e.g. networking, deployment model) is different from real-world productions. You may combine it with [‘AWS Local’](https://github.com/localstack/localstack) to work with a stub of the real AWS services. If you went [serverless](https://serverless.com/) multiple frameworks like serverless and [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) allows the local invocation of FaaS code. +:white_check_mark: **انجام دادن:** آزمایش انتها به انتها (e2e) چالش اصلی هر خط لوله CI است - ایجاد یک آینه تولید زودگذر یکسان در حال پرواز با تمام خدمات ابری مرتبط می تواند خسته کننده و گران باشد. یافتن بهترین سازش بازی شماست: [Docker-compose](https://serverless.com/) اجازه می دهد تا با استفاده از یک فایل متنی ساده، محیط ایزوله شده را با کانتینرهای یکسان ایجاد کنید، اما فناوری پشتیبان (به عنوان مثال شبکه، مدل استقرار) با تولیدات دنیای واقعی متفاوت است. می توانید آن را با آن ترکیب کنید [‘AWS محلی’](https://github.com/localstack/localstack) برای کار با تعدادی از خدمات واقعی AWS. اگه رفتی [serverless](https://serverless.com/) فریمورک های متعدد مانند بدون سرور و [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) فراخوانی محلی کد FaaS را امکان پذیر می کند. -The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for local and CI-mirroring though many new tools are launched frequently. One approach is running a ‘minimized-Kubernetes’ using tools like [Minikube](https://kubernetes.io/docs/setup/minikube/) and [MicroK8s](https://microk8s.io/) which resemble the real thing only come with less overhead. Another approach is testing over a remote ‘real-Kubernetes’, some CI providers (e.g. [Codefresh](https://codefresh.io/)) has native integration with Kubernetes environment and make it easy to run the CI pipeline over the real thing, others allow custom scripting against a remote Kubernetes. +اکوسیستم عظیم Kubernetes هنوز یک ابزار مناسب استاندارد برای آینه‌کاری محلی و CI رسمی نکرده است، اگرچه ابزارهای جدید زیادی به طور مکرر راه‌اندازی می‌شوند. یک رویکرد اجرای «کوبرنت‌های کوچک‌شده» با استفاده از ابزارهایی مانند [Minikube](https://kubernetes.io/docs/setup/minikube/) and [MicroK8s](https://microk8s.io/) که شبیه چیزهای واقعی هستند فقط با سربار کمتری عرضه می شوند. روش دیگر آزمایش بر روی یک "Kubernetes واقعی" از راه دور، برخی از ارائه دهندگان CI است (e.g. [Codefresh](https://codefresh.io/)) دارای ادغام بومی با محیط Kubernetes است و اجرای خط لوله CI را بر روی چیز واقعی آسان می کند، دیگران اجازه می دهند اسکریپت سفارشی در برابر Kubernetes از راه دور انجام شود.
    -❌ **Otherwise:** Using different technologies for production and testing demands maintaining two deployment models and keeps the developers and the ops team separated +❌ **در غیر این صورت:**استفاده از فناوری های مختلف برای تولید و آزمایش مستلزم حفظ دو مدل استقرار است و توسعه دهندگان و تیم عملیات را از هم جدا نگه می دارد.
    -
    Code Examples +
    نمونه کد
    -### :clap: Example: a CI pipeline that generates Kubernetes cluster on the fly ([Credit: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/)) +### :clap: مثال: یک خط لوله CI که خوشه Kubernetes را در حال پرواز تولید می کند ([اعتبار: پویا-محیط های Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/))
    deploy:
    stage: deploy
    image: registry.gitlab.com/gitlab-examples/kubernetes-deploy
    script:
    - ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN
    - kubectl create ns $NAMESPACE
    - kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL"
    - mkdir .generated
    - echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF"
    - sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml"
    - kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml
    - kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml
    environment:
    name: test-for-ci
    @@ -1877,19 +1877,19 @@ The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for

    -## ⚪ ️5.4 Parallelize test execution +## ⚪ ️5.4 موازی کردن اجرای آزمایش -:white_check_mark: **Do:** When done right, testing is your 24/7 friend providing almost instant feedback. In practice, executing 500 CPU-bounded unit test on a single thread can take too long. Luckily, modern test runners and CI platforms (like [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) and [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) can parallelize the test into multiple processes and achieve significant improvement in feedback time. Some CI vendors do also parallelize tests across containers (!) which shortens the feedback loop even further. Whether locally over multiple processes, or over some cloud CLI using multiple machines — parallelizing demand keeping the tests autonomous as each might run on different processes +:white_check_mark: **انجام دادن:** هنگامی که آزمایش به درستی انجام شود، دوست شما 24 ساعته و تقریباً فوری بازخورد ارائه می کند. در عمل، اجرای آزمایش 500 واحد محدود به CPU بر روی یک رشته ممکن است خیلی طول بکشد. خوشبختانه، دونده های آزمایشی مدرن و پلت فرم های CI (مانند [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) و [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) می تواند آزمون را در چندین فرآیند موازی کند و به بهبود قابل توجهی در زمان بازخورد دست یابد. برخی از فروشندگان CI نیز آزمایشات را در کانتینرها موازی می کنند (!) که حلقه بازخورد را حتی بیشتر کوتاه می کند. چه به صورت محلی بر روی چندین فرآیند، یا از طریق برخی CLI ابری با استفاده از چندین ماشین - تقاضای موازی کردن تست‌ها را مستقل نگه می‌دارد زیرا هر کدام ممکن است در فرآیندهای مختلف اجرا شوند. -❌ **Otherwise:** Getting test results 1 hour long after pushing new code, as you already code the next features, is a great recipe for making testing less relevant +❌ **در غیر این صورت:** دریافت نتایج آزمون 1 ساعت پس از فشار دادن کد جدید، همانطور که قبلاً ویژگی‌های بعدی را کدنویسی کرده‌اید، یک دستور العمل عالی برای کاهش مرتبط کردن تست است.
    -
    Code Examples +
    نمونه کد
    -### :clap: Doing It Right Example: Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) +### :clap: انجام درست مثال: موازی موکا و جست به لطف آزمایش موازی سازی به راحتی از موکای سنتی پیشی می گیرند. ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) ![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization (Credit: JavaScript Test-Runners Benchmark)") @@ -1897,25 +1897,25 @@ The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for

    -## ⚪ ️5.5 Stay away from legal issues using license and plagiarism check +## ⚪ ️5.5 با استفاده از چک مجوز و سرقت ادبی از مسائل قانونی خودداری کنید -:white_check_mark: **Do:** Licensing and plagiarism issues are probably not your main concern right now, but why not tick this box as well in 10 minutes? A bunch of npm packages like [license check](https://www.npmjs.com/package/license-checker) and [plagiarism check](https://www.npmjs.com/package/plagiarism-checker) (commercial with free plan) can be easily baked into your CI pipeline and inspect for sorrows like dependencies with restrictive licenses or code that was copy-pasted from Stack Overflow and apparently violates some copyrights +:white_check_mark: **انجام دادن:** مسائل مربوط به مجوز و سرقت ادبی احتمالاً دغدغه اصلی شما در حال حاضر نیست، اما چرا این کادر را در 10 دقیقه تیک ندهید؟ یک دسته از بسته های npm مانند [بررسی مجوز](https://www.npmjs.com/package/license-checker) و [چک سرقت ادبی](https://www.npmjs.com/package/plagiarism-checker) (تجاری با طرح رایگان) را می توان به راحتی در خط لوله CI خود قرار داد و غم هایی مانند وابستگی ها را با مجوزهای محدود یا کدی که از Stack Overflow کپی شده است و ظاهراً برخی از حق چاپ را نقض می کند بررسی کرد. -❌ **Otherwise:** Unintentionally, developers might use packages with inappropriate licenses or copy paste commercial code and run into legal issues +❌ **در غیر این صورت:** به طور ناخواسته، توسعه‌دهندگان ممکن است از بسته‌هایی با مجوزهای نامناسب استفاده کنند یا کد تجاری را کپی پیست کنند و با مشکلات قانونی مواجه شوند.
    -
    Code Examples +
    نمونه کد
    -### :clap: Doing It Right Example: +### :clap: انجام درست آن مثال: ```shell -# install license-checker in your CI environment or also locally +# لایسنس چک را در محیط CI خود یا به صورت محلی نصب کنید npm install -g license-checker -# ask it to scan all licenses and fail with exit code other than 0 if it found unauthorized license. The CI system should catch this failure and stop the build +# از آن بخواهید که تمام مجوزها را اسکن کند و اگر مجوز غیرمجاز پیدا کرد با کد خروجی غیر از 0 شکست بخورد. سیستم CI باید این شکست را بگیرد و ساخت را متوقف کند license-checker --summary --failOn BSD ``` @@ -1927,19 +1927,19 @@ license-checker --summary --failOn BSD

    -## ⚪ ️5.6 Constantly inspect for vulnerable dependencies +## ⚪ ️5.6 به طور مداوم وابستگی های آسیب پذیر را بررسی کنید -:white_check_mark: **Do:** Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using community tools such as [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), or commercial tools like [snyk](https://snyk.io/) (offer also a free community version). Both can be invoked from your CI on every build +:white_check_mark: **انجام دادن:** حتی معتبرترین وابستگی ها مانند Express آسیب پذیری های شناخته شده ای دارند. این می تواند به راحتی با استفاده از ابزارهای جامعه مانند [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), یا ابزارهای تجاری مانند [snyk](https://snyk.io/) (نسخه انجمن رایگان را نیز ارائه دهید). هر دو را می توان از CI شما در هر ساختنی فراخوانی کرد -❌ **Otherwise:** Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online publications about new threats. Quite tedious +❌ **در غیر این صورت:** پاک نگه داشتن کد خود از آسیب‌پذیری‌ها بدون ابزار اختصاصی، مستلزم این است که دائماً انتشارات آنلاین در مورد تهدیدات جدید را دنبال کنید. کاملا خسته کننده
    -
    Code Examples +
    نمونه کد
    -### :clap: Example: NPM Audit result +### :clap: مقال: NPM Audit نتیجه ![alt text](assets/bp-26-npm-audit-snyk.png "NPM Audit result") @@ -1947,26 +1947,26 @@ license-checker --summary --failOn BSD

    -## ⚪ ️5.7 Automate dependency updates +## ⚪ ️5.7 به‌روزرسانی‌های وابستگی را خودکار کنید -:white_check_mark: **Do:** Yarn and npm latest introduction of package-lock.json introduced a serious challenge (the road to hell is paved with good intentions) — by default now, packages are no longer getting updates. Even a team running many fresh deployments with ‘npm install’ & ‘npm update’ won’t get any new updates. This leads to subpar dependent packages versions at best or to vulnerable code at worst. Teams now rely on developers goodwill and memory to manually update the package.json or use tools [like ncu](https://www.npmjs.com/package/npm-check-updates) manually. A more reliable way could be to automate the process of getting the most reliable dependency versions, though there are no silver bullet solutions yet there are two possible automation roads: +:white_check_mark: **انجام دادن:** Yarn و npm آخرین معرفی package-lock.json یک چالش جدی را معرفی کرد (جاده جهنم با نیت خوب هموار شده است)——به طور پیش فرض اکنون بسته ها دیگر به روز رسانی نمی شوند. حتی تیمی که بسیاری از استقرارهای جدید را با "npm install" و "npm update" اجرا می کند، هیچ به روز رسانی جدیدی دریافت نخواهد کرد. این منجر به نسخه‌های بسته‌های وابسته به پایین‌تر و در بدترین حالت به کدهای آسیب‌پذیر می‌شود. اکنون تیم ها برای به روز رسانی دستی package.json یا استفاده از ابزارها به حسن نیت و حافظه توسعه دهندگان متکی هستند [مانند ncu](https://www.npmjs.com/package/npm-check-updates) به صورت دستی یک راه قابل اطمینان تر می تواند خودکار کردن فرآیند دریافت قابل اعتمادترین نسخه های وابستگی باشد، اگرچه هیچ راه حل گلوله نقره ای وجود ندارد، اما دو راه اتوماسیون ممکن وجود دارد: -(1) CI can fail builds that have obsolete dependencies — using tools like [‘npm outdated’](https://docs.npmjs.com/cli/outdated) or ‘npm-check-updates (ncu)’ . Doing so will enforce developers to update dependencies. +(1) CI می‌تواند در ساخت‌هایی که وابستگی‌های منسوخ دارند با استفاده از ابزارهایی مانند [‘npm outdated’](https://docs.npmjs.com/cli/outdated) یا ‘npm-check-updates (ncu)’ . انجام این کار توسعه دهندگان را وادار می کند تا وابستگی ها را به روز کنند. -(2) Use commercial tools that scan the code and automatically send pull requests with updated dependencies. One interesting question remaining is what should be the dependency update policy — updating on every patch generates too many overhead, updating right when a major is released might point to an unstable version (many packages found vulnerable on the very first days after being released, [see the](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) eslint-scope incident). +(2) از ابزارهای تجاری استفاده کنید که کد را اسکن می کنند و به طور خودکار درخواست های کشش را با وابستگی های به روز ارسال می کنند. یک سوال جالب باقی مانده این است که سیاست به‌روزرسانی وابستگی چگونه باید باشد— به‌روزرسانی در هر وصله سربار زیادی ایجاد می‌کند، به‌روزرسانی درست زمانی که یک اصلی منتشر می‌شود ممکن است به یک نسخه ناپایدار اشاره کند (بسیاری از بسته‌ها در همان روزهای اول پس از انتشار آسیب‌پذیر هستند., [را ببینید](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) eslint-scope حادثه). -An efficient update policy may allow some ‘vesting period’ — let the code lag behind the @latest for some time and versions before considering the local copy as obsolete (e.g. local version is 1.3.1 and repository version is 1.3.8) +یک خط‌مشی به‌روزرسانی کارآمد ممکن است اجازه دهد تا مقداری «دوره واگذاری» وجود داشته باشد - اجازه دهید کد برای مدتی از آخرین @ و نسخه‌ها عقب بماند، قبل از اینکه نسخه محلی را منسوخ در نظر بگیرید (به عنوان مثال نسخه محلی 1.3.1 و نسخه مخزن 1.3.8 است).
    -❌ **Otherwise:** Your production will run packages that have been explicitly tagged by their author as risky +❌ **در غیر این صورت:** تولید شما بسته هایی را اجرا می کند که به صراحت توسط نویسنده آنها به عنوان خطرناک برچسب گذاری شده است
    -
    Code Examples +
    نمونه کد
    -### :clap: Example: [ncu](https://www.npmjs.com/package/npm-check-updates) can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions +### :clap: مقال: [ncu](https://www.npmjs.com/package/npm-check-updates) می تواند به صورت دستی یا در یک خط لوله CI برای تشخیص میزان عقب ماندگی کد از آخرین نسخه ها استفاده شود ![alt text](assets/bp-27-yoni-goldberg-npm.png "ncu can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions") @@ -1974,33 +1974,33 @@ An efficient update policy may allow some ‘vesting period’ — let the c

    -## ⚪ ️ 5.8 Other, non-Node related, CI tips +## ⚪ ️ 5.8 نکات دیگر، غیر مرتبط با گره، CI -: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 few non-Node related tips that are well-known +:white_check_mark: **انجام دادن:** این پست بر روی توصیه‌های آزمایشی متمرکز شده است، یا حداقل می‌توان آن را با Node JS مثال زد. با این حال، این گلوله چند نکته غیر مرتبط با Node را که به خوبی شناخته شده هستند، گروه بندی می کند -
    1. Use a declarative syntax. This is the only option for most vendors but older versions of Jenkins allows using code or UI
    2. Opt for a vendor that has native Docker support
    3. Fail early, run your fastest tests first. Create a ‘Smoke testing’ step/milestone that groups multiple fast inspections (e.g. linting, unit tests) and provide snappy feedback to the code committer
    4. Make it easy to skim-through all build artifacts including test reports, coverage reports, mutation reports, logs, etc
    5. Create multiple pipelines/jobs for each event, reuse steps between them. For example, configure a job for feature branch commits and a different one for master PR. Let each reuse logic using shared steps (most vendors provide some mechanism for code reuse)
    6. Never embed secrets in a job declaration, grab them from a secret store or from the job’s configuration
    7. Explicitly bump version in a release build or at least ensure the developer did so
    8. Build only once and perform all the inspections over the single build artifact (e.g. Docker image)
    9. Test in an ephemeral environment that doesn’t drift state between builds. Caching node_modules might be the only exception
    +
    1. از یک نحو اعلانی استفاده کنید. این تنها گزینه برای اکثر فروشندگان است اما نسخه های قدیمی Jenkins امکان استفاده از کد یا UI را می دهد
    2. فروشنده ای را انتخاب کنید که از پشتیبانی Docker بومی برخوردار باشد
    3. زود شکست بخورید، ابتدا سریع ترین تست های خود را اجرا کنید. یک مرحله / نقطه عطف "تست دود" ایجاد کنید که چندین بازرسی سریع را گروه بندی می کند (مانند پرده زدن، تست های واحد) و بازخورد سریع را به committer کد ارائه می دهد.
    4. بررسی تمام مصنوعات ساختنی از جمله گزارش‌های آزمایش، گزارش‌های پوشش، گزارش‌های جهش، گزارش‌ها و غیره را آسان کنید.
    5. چندین خط لوله/شغل برای هر رویداد ایجاد کنید، از مراحل بین آنها دوباره استفاده کنید. به عنوان مثال، یک کار را برای commit های شاخه ویژگی و یک کار دیگر را برای PR اصلی پیکربندی کنید. به هر منطق اجازه استفاده مجدد را با استفاده از مراحل مشترک بدهید (اکثر فروشندگان مکانیزمی برای استفاده مجدد از کد ارائه می دهند)
    6. هرگز اسرار را در یک اعلامیه شغلی قرار ندهید، آنها را از یک فروشگاه مخفی یا از پیکربندی شغل بگیرید.
    7. به صراحت نسخه را در یک نسخه منتشر کنید یا حداقل اطمینان حاصل کنید که توسعه دهنده این کار را انجام داده است
    8. فقط یک بار بسازید و تمام بازرسی‌ها را روی یک مصنوع ساخت (مثلاً تصویر داکر) انجام دهید.
    9. در یک محیط زودگذر که حالت رانش بین ساخت‌ها را ندارد، تست کنید. ذخیره node_modules ممکن است تنها استثنا باشد

    -❌ **Otherwise:** You‘ll miss years of wisdom +❌ **در غیر این صورت:** شما سالهای خرد را از دست خواهید داد

    -## ⚪ ️ 5.9 Build matrix: Run the same CI steps using multiple Node versions +## ⚪ ️ 5.9 ساخت ماتریس: همان مراحل CI را با استفاده از چندین نسخه Node اجرا کنید -:white_check_mark: **Do:** Quality checking is about serendipity, the more ground you cover the luckier you get in detecting issues early. When developing reusable packages or running a multi-customer production with various configuration and Node versions, the CI must run the pipeline of tests over all the permutations of configurations. For example, assuming we use MySQL for some customers and Postgres for others — some CI vendors support a feature called ‘Matrix’ which allow running the suit of testing against all permutations of MySQL, Postgres and multiple Node version like 8, 9 and 10. This is done using configuration only without any additional effort (assuming you have testing or any other quality checks). Other CIs who doesn’t support Matrix might have extensions or tweaks to allow that +:white_check_mark: **انجام دادن:** بررسی کیفیت در مورد سرندیپیتی است، هرچه زمینه بیشتری را پوشش دهید، در تشخیص زودهنگام مشکلات شانس بیشتری خواهید داشت. هنگام توسعه بسته‌های قابل استفاده مجدد یا اجرای یک تولید چند مشتری با پیکربندی‌های مختلف و نسخه‌های Node، CI باید خط لوله آزمایش‌ها را روی همه جایگشت‌های پیکربندی‌ها اجرا کند. به عنوان مثال، با فرض اینکه ما از MySQL برای برخی از مشتریان و از Postgres برای برخی دیگر استفاده می‌کنیم - برخی از فروشندگان CI از ویژگی به نام «Matrix» پشتیبانی می‌کنند که امکان اجرای مجموعه آزمایشی را در برابر همه جایگشت‌های MySQL، Postgres و چندین نسخه Node مانند 8، 9 و 10 می‌دهد. این کار فقط با استفاده از پیکربندی بدون هیچ تلاش اضافی انجام می شود (با فرض اینکه تست یا هر گونه بررسی کیفیت دیگری داشته باشید). سایر CI که از Matrix پشتیبانی نمی کنند ممکن است افزونه ها یا ترفندهایی برای اجازه دادن به آن داشته باشند
    -❌ **Otherwise:** So after doing all that hard work of writing testing are we going to let bugs sneak in only because of configuration issues? +❌ **در غیر این صورت:** بنابراین، پس از انجام این همه کار سخت در تست نوشتن، تنها به دلیل مشکلات پیکربندی، اجازه می‌دهیم باگ‌ها پنهان شوند.?
    -
    Code Examples +
    نمونه کد
    -### :clap: Example: Using Travis (CI vendor) build definition to run the same test over multiple Node versions +### :clap: مثال: استفاده از تعریف ساخت تراویس (فروشنده CI) برای اجرای همان آزمایش روی چندین نسخه Node -
    language: node_js
    node_js:
    - "7"
    - "6"
    - "5"
    - "4"
    install:
    - npm install
    script:
    - npm run test
    +
    زبان: node_js
    node_js:
    - "7"
    - "6"
    - "5"
    - "4"
    install:
    - npm install
    script:
    - npm run test


    From 690df32d37da764757853799045f40545f7cc243 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Mon, 28 Nov 2022 05:29:48 -0500 Subject: [PATCH 156/189] Update readme.md --- readme.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 57a818c0..2a8134c3 100644 --- a/readme.md +++ b/readme.md @@ -26,9 +26,8 @@ Start by understanding the ubiquitous testing practices that are the foundation ### Written By Yoni Goldberg - A JavaScript & Node.js consultant -- 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - My comprehensive online course with more than [7 hours of video](https://www.testjavascript.com), 14 test types and more than 40 best practices +- 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - My comprehensive online course with more than [7 hours of video](https://www.testjavascript.com) - [Follow me on Twitter](https://twitter.com/goldbergyoni/) -- [Next workshop: Verona, Italy 🇮🇹, April 20th](https://2022.jsday.it/workshop/nodejs_testing.html)
    From d51ab0cac7b7cdb63e18b75f4e279112f3336331 Mon Sep 17 00:00:00 2001 From: Serhii Shramko Date: Wed, 7 Dec 2022 22:42:23 +0100 Subject: [PATCH 157/189] feat: implement all chapters --- readme-ua.md | 178 +++++++++++++++++++++++++-------------------------- 1 file changed, 88 insertions(+), 90 deletions(-) diff --git a/readme-ua.md b/readme-ua.md index f73b5783..1f76d0e4 100644 --- a/readme-ua.md +++ b/readme-ua.md @@ -1663,19 +1663,19 @@ describe("visual validation", () => {

    -# Section 4️⃣: Measuring Test Effectiveness +# Section 4️⃣: Вимірювання ефективності тесту

    -## ⚪ ️ 4.1 Get enough coverage for being confident, ~80% seems to be the lucky number +## ⚪ ️ 4.1 Отримайте достатнє покриття, щоб бути впевненим, ~80%, здається, це щасливе число -:white_check_mark: **Роби:** The purpose of testing is to get enough confidence for moving fast, obviously the more code is tested the more confident the team can be. Coverage is a measure of how many code lines (and branches, statements, etc) are being reached by the tests. So how much is enough? 10–30% is obviously too low to get any sense about the build correctness, on the other side 100% is very expensive and might shift your focus from the critical paths to the exotic corners of the code. The long answer is that it depends on many factors like the type of application — if you’re building the next generation of Airbus A380 than 100% is a must, for a cartoon pictures website 50% might be too much. Although most of the testing enthusiasts claim that the right coverage threshold is contextual, most of them also mention the number 80% as a thumb of a rule ([Fowler: “in the upper 80s or 90s”](https://martinfowler.com/bliki/TestCoverage.html)) that presumably should satisfy most of the applications. +:white_check_mark: **Роби:** Мета тестування полягає в тому, щоб отримати достатню впевненість для швидкого просування; очевидно, чим більше коду тестується, тим впевненішою може бути команда. Покриття — це показник того, скільки рядків коду (і розгалужень, операторів тощо) охоплено тестами. То скільки вистачить? 10–30% — це, очевидно, занадто мало, щоб отримати будь-яке уявлення про правильність збірки, з іншого боку, 100% — це дуже дорого й може перемістити вашу увагу з критичних шляхів на екзотичні куточки коду. Довга відповідь полягає в тому, що це залежить від багатьох факторів, таких як тип застосування —«якщо ви створюєте наступне покоління Airbus A380, 100% є обов’язковим, для веб-сайту з мультфільмами 50% може бути забагато. Хоча більшість ентузіастів тестування стверджують, що правильний поріг охоплення є контекстним, більшість із них також згадує число 80% як правило ([Fowler: "in the upper 80s or 90s"](https://martinfowler. com/bliki/TestCoverage.html)), який, імовірно, повинен задовольнити більшість програм. -Implementation tips: You may want to configure your continuous integration (CI) to have a coverage threshold ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) and stop a build that doesn’t stand to this standard (it’s also possible to configure threshold per component, see code example below). On top of this, consider detecting build coverage decrease (when a newly committed code has less coverage) — this will push developers raising or at least preserving the amount of tested code. All that said, coverage is only one measure, a quantitative based one, that is not enough to tell the robustness of your testing. And it can also be fooled as illustrated in the next bullets +Поради щодо впровадження: Можливо, ви захочете налаштувати безперервну інтеграцію (CI), щоб мати поріг покриття ([Jest link](https://jestjs.io/docs/en/configuration.html#collectcoverage-boolean)) і зупинити збірку що не відповідає цьому стандарту (також можна налаштувати порогове значення для кожного компонента, див. приклад коду нижче). На додаток до цього, подумайте про виявлення зменшення покриття збірки (коли нещодавно зафіксований код має менше покриття) — це підштовхне розробників збільшити або принаймні зберегти кількість перевіреного коду. Загалом, охоплення — це лише один показник, кількісний, якого недостатньо, щоб визначити надійність вашого тестування. І його також можна обдурити, як показано в наступних пунктах
    -❌ **Інакше:** Confidence and numbers go hand in hand, without really knowing that you tested most of the system — there will also be some fear and fear will slow you down +❌ **Інакше:** Впевненість і цифри йдуть пліч-о-пліч, навіть не знаючи, що ви перевірили більшу частину системи -також буде певний страх, і страх сповільнить вас
    @@ -1683,28 +1683,28 @@ Implementation tips: You may want to configure your continuous integration (CI)
    -### :clap: Example: A typical coverage report +### :clap: Приклад: Типовий звіт про покриття -![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "A typical coverage report") +![alt text](assets/bp-18-yoni-goldberg-code-coverage.png "Типовий звіт про покриття")
    -### :clap: Приклад правильного виконання: Setting up coverage per component (using Jest) +### :clap: Приклад правильного виконання: Налаштування покриття для кожного компонента (за допомогою Jest) -![](https://img.shields.io/badge/🔨%20Example%20using%20Jest-blue.svg "Using Jest") +![](https://img.shields.io/badge/🔨%20Example%20using%20Jest-blue.svg "Jest") -![alt text](assets/bp-18-code-coverage2.jpeg "Setting up coverage per component (using Jest)") +![alt text](assets/bp-18-code-coverage2.jpeg "Налаштування покриття для кожного компонента (за допомогою Jest)")


    -## ⚪ ️ 4.2 Inspect coverage reports to detect untested areas and other oddities +## ⚪ ️ 4.2 Перевірте звіти про покриття, щоб виявити неперевірені області та інші дивацтва -:white_check_mark: **Роби:** Some issues sneak just under the radar and are really hard to find using traditional tools. These are not really bugs but more of surprising application behavior that might have a severe impact. For example, often some code areas are never or rarely being invoked — you thought that the ‘PricingCalculator’ class is always setting the product price but it turns out it is actually never invoked although we have 10000 products in DB and many sales… Code coverage reports help you realize whether the application behaves the way you believe it does. Other than that, it can also highlight which types of code is not tested — being informed that 80% of the code is tested doesn’t tell whether the critical parts are covered. Generating reports is easy — just run your app in production or during testing with coverage tracking and then see colorful reports that highlight how frequent each code area is invoked. If you take your time to glimpse into this data — you might find some gotchas +:white_check_mark: **Роби:** Деякі проблеми непомічені, і їх дуже важко знайти за допомогою традиційних інструментів. Насправді це не помилки, а скоріше дивовижна поведінка програми, яка може мати серйозні наслідки. Наприклад, часто деякі області коду ніколи або рідко викликаються — ви думали, що клас «PricingCalculator» завжди встановлює ціну продукту, але виявилося, що він насправді ніколи не викликається, хоча ми маємо 10000 продуктів у БД і багато продажів… Покриття коду звіти допомагають зрозуміти, чи працює програма так, як ви думаєте. Окрім цього, він також може підкреслити, які типи коду не перевірено —«інформація про те, що 80% коду перевірено, не говорить про те, чи охоплено критичні частини. Створювати звіти легко — просто запустіть свою програму в робочому стані або під час тестування з відстеженням покриття, а потім перегляньте кольорові звіти, у яких показано, як часто викликається кожна область коду. Якщо ви не поспішаєте зазирнути в ці дані — ви можете знайти деякі проблеми
    -❌ **Інакше:** If you don’t know which parts of your code are left un-tested, you don’t know where the issues might come from +❌ **Інакше:** Якщо ви не знаєте, які частини вашого коду залишилися необробленими, ви не знаєте, звідки можуть виникнути проблеми
    @@ -1712,30 +1712,30 @@ Implementation tips: You may want to configure your continuous integration (CI)
    -### :thumbsdown: Приклад антишаблону: What’s wrong with this coverage report? +### :thumbsdown: Приклад антишаблону: Що не так із цим звітом про покриття? -Based on a real-world scenario where we tracked our application usage in QA and find out interesting login patterns (Hint: the amount of login failures is non-proportional, something is clearly wrong. Finally it turned out that some frontend bug keeps hitting the backend login API) +На основі реального сценарію, коли ми відстежували використання нашої програми в QA та знаходили цікаві шаблони входу (Підказка: кількість помилок входу непропорційна, щось явно не так. Нарешті виявилося, що якась помилка інтерфейсу постійно вражає серверний API входу) -![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "What’s wrong with this coverage report?") +![alt text](assets/bp-19-coverage-yoni-goldberg-nodejs-consultant.png "Що не так із цим звітом про покриття?")


    -## ⚪ ️ 4.3 Measure logical coverage using mutation testing +## ⚪ ️ 4.3 Виміряйте логічне покриття за допомогою тестування на мутації -:white_check_mark: **Роби:** The Traditional Coverage metric often lies: It may show you 100% code coverage, but none of your functions, even not one, return the right response. How come? it simply measures over which lines of code the test visited, but it doesn’t check if the tests actually tested anything — asserted for the right response. Like someone who’s traveling for business and showing his passport stamps — this doesn’t prove any work done, only that he visited few airports and hotels. +:white_check_mark: **Роби:** Традиційний показник покриття часто брехня: він може показати вам 100% покриття коду, але жодна з ваших функцій, навіть жодна, не повертає правильну відповідь. Як так? він просто вимірює, які рядки коду відвідав тест, але не перевіряє, чи тести справді щось перевіряли — заявлено для правильної відповіді. Як хтось, хто подорожує у справах і показує штампи в паспорті —«це не доводить жодної роботи, лише те, що він відвідав кілька аеропортів і готелів. -Mutation-based testing is here to help by measuring the amount of code that was actually TESTED not just VISITED. [Stryker](https://stryker-mutator.io/) is a JavaScript library for mutation testing and the implementation is really neat: +Тестування на основі мутацій тут, щоб допомогти, вимірюючи кількість коду, який був фактично ПРОТЕСТОВАНИЙ, а не просто ВІДВІДАНИЙ. [Stryker](https://stryker-mutator.io/) — це бібліотека JavaScript для тестування на мутації, реалізація якої дуже гарна: -(1) it intentionally changes the code and “plants bugs”. For example the code newOrder.price===0 becomes newOrder.price!=0. This “bugs” are called mutations +(1) він навмисно змінює код і «підсаджує помилки». Наприклад, код newOrder.price===0 стає newOrder.price!=0. Ці «помилки» називаються мутаціями -(2) it runs the tests, if all succeed then we have a problem — the tests didn’t serve their purpose of discovering bugs, the mutations are so-called survived. If the tests failed, then great, the mutations were killed. +(2) він запускає тести, якщо всі вдаються, тоді у нас є проблема —«тести не виконали своєї мети виявлення помилок, мутації так звані вижили. Якщо тести провалилися, то чудово, мутації були вбиті. -Knowing that all or most of the mutations were killed gives much higher confidence than traditional coverage and the setup time is similar +Знання того, що всі або більшість мутацій були знищені, дає набагато більшу впевненість, ніж традиційне покриття, а час налаштування подібний
    -❌ **Інакше:** You’ll be fooled to believe that 85% coverage means your test will detect bugs in 85% of your code +❌ **Інакше:** Ви будете обдурені, якщо повірите, що 85% покриття означає, що ваш тест виявить помилки в 85% вашого коду
    @@ -1743,9 +1743,9 @@ Knowing that all or most of the mutations were killed gives much higher confiden
    -### :thumbsdown: Приклад антишаблону: 100% coverage, 0% testing +### :thumbsdown: Приклад антишаблону: 100% покриття, 0% тестування -![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Using Stryker") +![](https://img.shields.io/badge/🔨%20Example%20using%20Stryker-blue.svg "Використання Stryker") ```javascript function addNewOrder(newOrder) { @@ -1758,33 +1758,33 @@ function addNewOrder(newOrder) { it("Test addNewOrder, don't use such test names", () => { addNewOrder({ assignee: "John@mailer.com", price: 120 }); -}); //Triggers 100% code coverage, but it doesn't check anything +}); // Запускає 100% покриття коду, але нічого не перевіряє ```
    -### :clap: Приклад правильного виконання: Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations) +### :clap: Приклад правильного виконання: Звіти Stryker, інструмент для перевірки мутацій, виявляють і підраховують кількість коду, який не перевіряється (Мутації) -![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "Stryker reports, a tool for mutation testing, detects and counts the amount of code that is not tested (Mutations)") +![alt text](assets/bp-20-yoni-goldberg-mutation-testing.jpeg "Звіти Stryker, інструмент для перевірки мутацій, виявляють і підраховують кількість коду, який не перевіряється (Мутації)")


    -## ⚪ ️4.4 Preventing test code issues with Test linters +## ⚪ ️4.4 Запобігання проблемам тестового коду за допомогою тестових лінтерів -:white_check_mark: **Роби:** A set of ESLint plugins were built specifically for inspecting the tests code patterns and discover issues. For example, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) will warn when a test is written at the global level (not a son of a describe() statement) or when tests are [skipped](https://mochajs.org/#inclusive-tests) which might lead to a false belief that all tests are passing. Similarly, [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) can, for example, warn when a test has no assertions at all (not checking anything) +:white_check_mark: **Роби:** Набір плагінів ESLint створено спеціально для перевірки шаблонів коду тестів і виявлення проблем. Наприклад, [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) попереджатиме, коли тест написаний на глобальному рівні (а не син оператора describe()) або коли тести [skipped](https://mochajs.org/#inclusive-tests), що може призвести до хибного переконання, що всі тести успішно пройдені. Подібним чином [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) може, наприклад, попередити, коли тест взагалі не має тверджень (нічого не перевіряє)
    -❌ **Інакше:** Seeing 90% code coverage and 100% green tests will make your face wear a big smile only until you realize that many tests aren’t asserting for anything and many test suites were just skipped. Hopefully, you didn’t deploy anything based on this false observation +❌ **Інакше:** Побачивши 90% охоплення коду та 100% зелених тестів, ваше обличчя буде широко посміхатися, доки ви не зрозумієте, що багато тестів нічого не стверджують, а багато наборів тестів просто пропущено. Сподіваюся, ви нічого не розгорнули на основі цього помилкового спостереження
    Приклади коду
    -### :thumbsdown: Приклад антишаблону: A test case full of errors, luckily all are caught by Linters +### :thumbsdown: Приклад антишаблону: Тестовий приклад, повний помилок, на щастя, усі вони виявлені за допомогою лінтерів (Linters) ```javascript describe("Too short description", () => { @@ -1804,16 +1804,16 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test

    -# Section 5️⃣: CI and Other Quality Measures +# Section 5️⃣: CI та інші показники якості

    -## ⚪ ️ 5.1 Enrich your linters and abort builds that have linting issues +## ⚪ ️ 5.1 Збагачуйте ваші лінтери та припиняйте збірки, які мають проблеми з лінінгами -:white_check_mark: **Роби:** Linters are a free lunch, with 5 min setup you get for free an auto-pilot guarding your code and catching significant issue as you type. Gone are the days where linting was about cosmetics (no semi-colons!). Nowadays, Linters can catch severe issues like errors that are not thrown correctly and losing information. On top of your basic set of rules (like [ESLint standard](https://www.npmjs.com/package/eslint-plugin-standard) or [Airbnb style](https://www.npmjs.com/package/eslint-config-airbnb)), consider including some specializing Linters like [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect) that can discover tests without assertions, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) can discover promises with no resolve (your code will never continue), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme) which can discover eager regex expressions that might get used for DOS attacks, and [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) is capable of alarming when the code uses utility library methods that are part of the V8 core methods like Lodash.\_map(…) +:white_check_mark: **Роби:** Linters — це безкоштовний обід, після 5-хвилинного налаштування ви безкоштовно отримуєте автопілот, який охороняє ваш код і виявляє значні проблеми під час введення. Пройшли ті часи, коли розмови стосувалися косметики (без крапок з комою!). Сьогодні Linters може виявляти серйозні проблеми, як-от помилки, які неправильно видаються та втрачають інформацію. На додаток до вашого базового набору правил (наприклад, [стандарт ESLint](https://www.npmjs.com/package/eslint-plugin-standard) або [стиль Airbnb](https://www.npmjs.com/package /eslint-config-airbnb)), подумайте про включення деяких спеціалізованих лінтерів, таких як [eslint-plugin-chai-expect](https://www.npmjs.com/package/eslint-plugin-chai-expect), які можуть виявляти тести без твердження, [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise?activeTab=readme) може виявляти обіцянки без вирішення (ваш код ніколи не продовжиться), [eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security?activeTab=readme), який може виявити активні регулярні вирази, які можуть бути використані для атак DOS, і [eslint-plugin-you-dont-need-lodash-underscore](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore) здатний викликати тривогу, коли код використовує методи службової бібліотеки, які є частиною V8 основні методи, такі як Lodash.\_map(…)
    -❌ **Інакше:** Consider a rainy day where your production keeps crashing but the logs don’t display the error stack trace. What happened? Your code mistakenly threw a non-error object and the stack trace was lost, a good reason for banging your head against a brick wall. A 5 min linter setup could detect this TYPO and save your day +❌ **Інакше:** Уявіть собі дощовий день, коли ваша продуктивність продовжує давати збої, але журнали не відображають трасування стека помилок. Що трапилось? Ваш код помилково викинув об’єкт без помилки, і трасування стека було втрачено, що є вагомою причиною для того, щоб битися головою об цегляну стіну. 5-хвилинне налаштування Linter може виявити цю TYPO і врятувати ваш день
    @@ -1821,22 +1821,22 @@ it("Test name", () => {*//error:no-identical-title. Assign unique titles to test
    -### :thumbsdown: Приклад антишаблону: The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug +### :thumbsdown: Приклад антишаблону: Помилково створено неправильний об’єкт Error, трасування стека для цієї помилки не з’явиться. На щастя, ESLint виявляє наступну виробничу помилку -![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "The wrong Error object is thrown mistakenly, no stack-trace will appear for this error. Luckily, ESLint catches the next production bug") +![alt text](assets/bp-21-yoni-goldberg-eslint.jpeg "Помилково створено неправильний об’єкт Error, трасування стека для цієї помилки не з’явиться. На щастя, ESLint виявляє наступну виробничу помилку")


    -## ⚪ ️ 5.2 Shorten the feedback loop with local developer-CI +## ⚪ ️ 5.2 Скоротіть цикл зворотного зв’язку за допомогою локального Developer-CI -:white_check_mark: **Роби:** Using a CI with shiny quality inspections like testing, linting, vulnerabilities check, etc? Help developers run this pipeline also locally to solicit instant feedback and shorten the [feedback loop](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2-feedback-loops/). Why? an efficient testing process constitutes many and iterative loops: (1) try-outs -> (2) feedback -> (3) refactor. The faster the feedback is, the more improvement iterations a developer can perform per-module and perfect the results. On the flip, when the feedback is late to come fewer improvement iterations could be packed into a single day, the team might already move forward to another topic/task/module and might not be up for refining that module. +:white_check_mark: **Роби:** Використовуєте CI з блискучою перевіркою якості, як-от тестування, лінтування, перевірка вразливостей тощо? Допоможіть розробникам запустити цей конвеєр також локально, щоб отримати миттєвий відгук і скоротити [цикл зворотного зв’язку](https://www.gocd.org/2016/03/15/are-you-ready-for-continuous-delivery-part-2 -петлі зворотного зв'язку/). чому ефективний процес тестування складається з багатьох ітераційних циклів: (1) тестування -> (2) зворотній зв'язок -> (3) рефакторинг. Чим швидший зворотній зв’язок, тим більше ітерацій покращення може виконати розробник для кожного модуля та покращити результати. З іншого боку, коли зворотній зв’язок надходить із запізненням, менше ітерацій покращення може бути упаковано в один день, команда може вже перейти до іншої теми/завдання/модуля та не готова вдосконалювати цей модуль. -Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) allow running the pipeline locally. Some commercial tools like [wallaby provide highly-valuable & testing insights](https://wallabyjs.com/) as a developer prototype (no affiliation). Alternatively, you may just add npm script to package.json that runs all the quality commands (e.g. test, lint, vulnerabilities) — use tools like [concurrently](https://www.npmjs.com/package/concurrently) for parallelization and non-zero exit code if one of the tools failed. Now the developer should just invoke one command — e.g. ‘npm run quality’ — to get instant feedback. Consider also aborting a commit if the quality check failed using a githook ([husky can help](https://github.com/typicode/husky)) +На практиці деякі постачальники CI (Приклад: [CircleCI local CLI](https://circleci.com/docs/2.0/local-cli/)) дозволяють запускати конвеєр локально. Деякі комерційні інструменти, як-от [wallaby, надають дуже цінну інформацію для тестування](https://wallabyjs.com/) як прототип розробника (без зв’язку). Крім того, ви можете просто додати сценарій npm до package.json, який запускає всі команди якості (наприклад, test, lint, vulnerabilities) — використовуйте такі інструменти, як [concurrently](https://www.npmjs.com/package/concurrently) для розпаралелювання і ненульовий код виходу, якщо один із інструментів вийшов з ладу. Тепер розробник має просто викликати одну команду — наприклад. «Якість виконання npm» — щоб отримати миттєвий відгук. Також подумайте про переривання коміту, якщо перевірка якості не вдалася за допомогою githook ([husky може допомогти](https://github.com/typicode/husky))
    -❌ **Інакше:** When the quality results arrive the day after the code, testing doesn’t become a fluent part of development rather an after the fact formal artifact +❌ **Інакше:** Коли якісні результати надходять наступного дня після коду, тестування не стає плавною частиною розробки, а формальним артефактом.
    @@ -1844,7 +1844,7 @@ Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com
    -### :clap: Приклад правильного виконання: npm scripts that perform code quality inspection, all are run in parallel on demand or when a developer is trying to push new code +### :clap: Приклад правильного виконання: Сценарії npm, які виконують перевірку якості коду, усі виконуються паралельно на вимогу або коли розробник намагається надіслати новий код ```javascript "scripts": { @@ -1869,14 +1869,14 @@ Practically, some CI vendors (Example: [CircleCI local CLI](https://circleci.com

    -## ⚪ ️5.3 Perform e2e testing over a true production-mirror +## ⚪ ️5.3 Виконайте тестування e2e на справжньому робочому дзеркалі -:white_check_mark: **Роби:** End to end (e2e) testing are the main challenge of every CI pipeline — creating an identical ephemeral production mirror on the fly with all the related cloud services can be tedious and expensive. Finding the best compromise is your game: [Docker-compose](https://serverless.com/) allows crafting isolated dockerized environment with identical containers using a single plain text file but the backing technology (e.g. networking, deployment model) is different from real-world productions. You may combine it with [‘AWS Local’](https://github.com/localstack/localstack) to work with a stub of the real AWS services. If you went [serverless](https://serverless.com/) multiple frameworks like serverless and [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) allows the local invocation of FaaS code. +:white_check_mark: **Роби:** Наскрізне тестування (e2e) є головною проблемою кожного конвеєра CI —«створення ідентичного ефемерного робочого дзеркала на льоту з усіма пов’язаними хмарними службами може бути виснажливим і дорогим. Пошук найкращого компромісу — ваша гра: [Docker-compose](https://serverless.com/) дозволяє створювати ізольоване докеризоване середовище з ідентичними контейнерами за допомогою одного простого текстового файлу, але технологія підтримки (наприклад, мережа, модель розгортання) відрізняється з реальних виробництв. Ви можете поєднати його з [‘AWS Local’](https://github.com/localstack/localstack), щоб працювати із заглушкою справжніх служб AWS. Якщо ви використовуєте [безсерверні](https://serverless.com/) кілька фреймворків, як-от безсерверні, і [AWS SAM](https://docs.aws.amazon.com/lambda/latest/dg/serverless_app.html) дозволяє локальний виклик коду FaaS. -The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for local and CI-mirroring though many new tools are launched frequently. One approach is running a ‘minimized-Kubernetes’ using tools like [Minikube](https://kubernetes.io/docs/setup/minikube/) and [MicroK8s](https://microk8s.io/) which resemble the real thing only come with less overhead. Another approach is testing over a remote ‘real-Kubernetes’, some CI providers (e.g. [Codefresh](https://codefresh.io/)) has native integration with Kubernetes environment and make it easy to run the CI pipeline over the real thing, others allow custom scripting against a remote Kubernetes. +Величезна екосистема Kubernetes ще має формалізувати стандартний зручний інструмент для локального та CI-дзеркалювання, хоча часто запускається багато нових інструментів. Одним із підходів є запуск «мінімізованого Kubernetes» за допомогою таких інструментів, як [Minikube](https://kubernetes.io/docs/setup/minikube/) і [MicroK8s](https://microk8s.io/), які нагадують справжній річ лише з меншими накладними витратами. Інший підхід полягає в тестуванні на віддаленому «реальному Kubernetes». Деякі постачальники CI (наприклад, [Codefresh](https://codefresh.io/)) мають власну інтеграцію з середовищем Kubernetes і дозволяють легко запускати конвеєр CI через реальний інші дозволяють створювати спеціальні сценарії для віддаленого Kubernetes.
    -❌ **Інакше:** Using different technologies for production and testing demands maintaining two deployment models and keeps the developers and the ops team separated +❌ **Інакше:** Використання різних технологій для виробництва та тестування вимагає підтримки двох моделей розгортання та роз’єднує розробників і команду операцій
    @@ -1884,7 +1884,7 @@ The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for
    -### :clap: Example: a CI pipeline that generates Kubernetes cluster on the fly ([Credit: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/)) +### :clap: Приклад: конвеєр CI, який генерує кластер Kubernetes на льоту ([Авторство: Dynamic-environments Kubernetes](https://container-solutions.com/dynamic-environments-kubernetes/))
    deploy:
    stage: deploy
    image: registry.gitlab.com/gitlab-examples/kubernetes-deploy
    script:
    - ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN
    - kubectl create ns $NAMESPACE
    - kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL"
    - mkdir .generated
    - echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF"
    - sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml"
    - kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml
    - kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml
    environment:
    name: test-for-ci
    @@ -1892,11 +1892,11 @@ The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for

    -## ⚪ ️5.4 Parallelize test execution +## ⚪ ️5.4 Паралелізуйте виконання тесту -:white_check_mark: **Роби:** When done right, testing is your 24/7 friend providing almost instant feedback. In practice, executing 500 CPU-bounded unit test on a single thread can take too long. Luckily, modern test runners and CI platforms (like [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) and [Mocha extensions](https://github.com/yandex/mocha-parallel-tests)) can parallelize the test into multiple processes and achieve significant improvement in feedback time. Some CI vendors do also parallelize tests across containers (!) which shortens the feedback loop even further. Whether locally over multiple processes, or over some cloud CLI using multiple machines — parallelizing demand keeping the tests autonomous as each might run on different processes +:white_check_mark: **Роби:** Якщо все зроблено правильно, тестування стане вашим другом цілодобово та без вихідних, що надає майже миттєвий відгук. На практиці виконання 500 обмежених ЦП модульних тестів в одному потоці може тривати занадто довго. На щастя, сучасні тестувальники та платформи CI (як-от [Jest](https://github.com/facebook/jest), [AVA](https://github.com/avajs/ava) і [розширення Mocha](https ://github.com/yandex/mocha-parallel-tests)) можна розпаралелити тест на кілька процесів і значно покращити час зворотного зв’язку. Деякі постачальники CI також розпаралелюють тести між контейнерами (!), що ще більше скорочує цикл зворотного зв’язку. Незалежно від того, локально над кількома процесами чи над деяким хмарним CLI з використанням кількох машин — розпаралелювання попиту, зберігаючи автономність тестів, оскільки кожен може виконуватися на різних процесах -❌ **Інакше:** Getting test results 1 hour long after pushing new code, as you already code the next features, is a great recipe for making testing less relevant +❌ **Інакше:** Отримання результатів тестування через 1 годину після введення нового коду, оскільки ви вже кодуєте наступні функції, є чудовим рецептом для того, щоб зробити тестування менш актуальним
    @@ -1904,19 +1904,19 @@ The huge Kubernetes ecosystem is yet to formalize a standard convenient tool for
    -### :clap: Приклад правильного виконання: Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization ([Credit: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) +### :clap: Приклад правильного виконання: Mocha parallel & Jest легко випереджають традиційну Mocha завдяки розпаралелюванню тестування ([Авторство: JavaScript Test-Runners Benchmark](https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4)) -![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest easily outrun the traditional Mocha thanks to testing parallelization (Credit: JavaScript Test-Runners Benchmark)") +![alt text](assets/bp-24-yonigoldberg-jest-parallel.png "Mocha parallel & Jest легко випереджають традиційну Mocha завдяки розпаралелюванню тестування")


    -## ⚪ ️5.5 Stay away from legal issues using license and plagiarism check +## ⚪ ️5.5 Тримайтеся подалі від юридичних проблем, використовуючи ліцензію та перевірку на плагіат -:white_check_mark: **Роби:** Licensing and plagiarism issues are probably not your main concern right now, but why not tick this box as well in 10 minutes? A bunch of npm packages like [license check](https://www.npmjs.com/package/license-checker) and [plagiarism check](https://www.npmjs.com/package/plagiarism-checker) (commercial with free plan) can be easily baked into your CI pipeline and inspect for sorrows like dependencies with restrictive licenses or code that was copy-pasted from Stack Overflow and apparently violates some copyrights +:white_check_mark: **Роби:** Проблеми ліцензування та плагіату, ймовірно, не є вашою головною проблемою зараз, але чому б також не поставити галочку в цьому полі через 10 хвилин? Купа пакетів npm, таких як [перевірка ліцензії](https://www.npmjs.com/package/license-checker) і [перевірка на плагіат](https://www.npmjs.com/package/plagiarism-checker) ( рекламний ролик із безкоштовним планом) можна легко вставити у ваш конвеєр CI та перевірити на наявність таких проблем, як залежності з обмежувальними ліцензіями або код, який було скопійовано з Stack Overflow і, очевидно, порушує деякі авторські права -❌ **Інакше:** Unintentionally, developers might use packages with inappropriate licenses or copy paste commercial code and run into legal issues +❌ **Інакше:** Ненавмисно розробники можуть використати пакети з невідповідними ліцензіями або скопіювати комерційний код і зіткнутися з юридичними проблемами
    @@ -1943,11 +1943,11 @@ license-checker --summary --failOn BSD

    -## ⚪ ️5.6 Constantly inspect for vulnerable dependencies +## ⚪ ️5.6 Постійно перевіряйте наявність вразливих залежностей -:white_check_mark: **Роби:** Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using community tools such as [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), or commercial tools like [snyk](https://snyk.io/) (offer also a free community version). Both can be invoked from your CI on every build +:white_check_mark: **Роби:** Навіть найавторитетніші залежності, такі як Express, мають відомі вразливості. Це можна легко приборкати за допомогою інструментів спільноти, таких як [npm audit](https://docs.npmjs.com/getting-started/running-a-security-audit), або комерційних інструментів, таких як [snyk](https:// snyk.io/) (пропонуємо також безкоштовну версію спільноти). Обидва можна викликати з вашого КІ під час кожної збірки -❌ **Інакше:** Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online publications about new threats. Quite tedious +❌ **Інакше:** Щоб захистити ваш код від уразливостей без спеціальних інструментів, потрібно постійно стежити за публікаціями в Інтернеті про нові загрози. Досить нудно
    @@ -1955,26 +1955,25 @@ license-checker --summary --failOn BSD
    -### :clap: Example: NPM Audit result +### :clap: Приклад: Результат аудиту NPM -![alt text](assets/bp-26-npm-audit-snyk.png "NPM Audit result") +![alt text](assets/bp-26-npm-audit-snyk.png "Результат аудиту NPM")


    -## ⚪ ️5.7 Automate dependency updates +## ⚪ ️5.7 Автоматизуйте оновлення залежностей -:white_check_mark: **Роби:** Yarn and npm latest introduction of package-lock.json introduced a serious challenge (the road to hell is paved with good intentions) — by default now, packages are no longer getting updates. Even a team running many fresh deployments with ‘npm install’ & ‘npm update’ won’t get any new updates. This leads to subpar dependent packages versions at best or to vulnerable code at worst. Teams now rely on developers goodwill and memory to manually update the package.json or use tools [like ncu](https://www.npmjs.com/package/npm-check-updates) manually. A more reliable way could be to automate the process of getting the most reliable dependency versions, though there are no silver bullet solutions yet there are two possible automation roads: +:white_check_mark: **Роби:** Yarn і npm останнє представлення package-lock.json поставило серйозну проблему (дорога в пекло вимощена благими намірами) — тепер за замовчуванням пакунки більше не отримують оновлення. Навіть команда, яка виконує багато свіжих розгортань за допомогою «встановлення npm» і «оновлення npm», не отримає нових оновлень. У кращому випадку це призводить до неповноцінних версій пакунків або до вразливого коду в гіршому. Команди тепер покладаються на добру волю та пам’ять розробників, щоб вручну оновити package.json або використовувати інструменти [наприклад, ncu](https://www.npmjs.com/package/npm-check-updates) вручну. Надійнішим способом може бути автоматизація процесу отримання найнадійніших версій залежностей, хоча немає універсальних рішень, але є два можливі шляхи автоматизації: -(1) CI can fail builds that have obsolete dependencies — using tools like [‘npm outdated’](https://docs.npmjs.com/cli/outdated) or ‘npm-check-updates (ncu)’ . Doing so will enforce developers to update dependencies. +(1) CI може давати збій збіркам із застарілими залежностями — використанням таких інструментів, як [‘npm outdated’](https://docs.npmjs.com/cli/outdated) або ‘npm-check-updates (ncu)’ . Це змусить розробників оновити залежності. -(2) Use commercial tools that scan the code and automatically send pull requests with updated dependencies. One interesting question remaining is what should be the dependency update policy — updating on every patch generates too many overhead, updating right when a major is released might point to an unstable version (many packages found vulnerable on the very first days after being released, [see the](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) eslint-scope incident). +(2) Використовуйте комерційні інструменти, які сканують код і автоматично надсилають запити на отримання з оновленими залежностями. Залишається одне цікаве питання: якою має бути політика оновлення залежностей —«оновлення кожного патча створює надто багато накладних витрат, оновлення безпосередньо під час випуску основного може вказувати на нестабільну версію (багато пакетів виявляються вразливими в перші дні після випуску, [перегляньте](https://nodesource.com/blog/a-high-level-post-mortem-of-the-eslint-scope-security-incident/) інцидент eslint-scope). -An efficient update policy may allow some ‘vesting period’ — let the code lag behind the @latest for some time and versions before considering the local copy as obsolete (e.g. local version is 1.3.1 and repository version is 1.3.8) -
    +Ефективна політика оновлення може дозволити певний «період набуття прав» — нехай код відстає від @latest на деякий час і версії, перш ніж вважати локальну копію застарілою (наприклад, локальна версія — 1.3.1, а версія сховища — 1.3.8)
    -❌ **Інакше:** Your production will run packages that have been explicitly tagged by their author as risky +❌ **Інакше:** У вашому виробництві працюватимуть пакунки, які були явно позначені їх автором як ризиковані
    @@ -1982,31 +1981,31 @@ An efficient update policy may allow some ‘vesting period’ — let the c
    -### :clap: Example: [ncu](https://www.npmjs.com/package/npm-check-updates) can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions +### :clap: Приклад: [ncu](https://www.npmjs.com/package/npm-check-updates) можна використовувати вручну або в конвеєрі CI, щоб визначити, наскільки код відстає від останніх версій -![alt text](assets/bp-27-yoni-goldberg-npm.png "ncu can be used manually or within a CI pipeline to detect to which extent the code lag behind the latest versions") +![alt text](assets/bp-27-yoni-goldberg-npm.png "можна використовувати вручну або в конвеєрі CI, щоб визначити, наскільки код відстає від останніх версій")


    -## ⚪ ️ 5.8 Other, non-Node related, CI tips +## ⚪ ️ 5.8 Інші поради CI, не пов’язані з Node -:white_check_mark: **Роби:** This post is focused on testing advice that is related to, or at least can be exemplified with Node JS. This bullet, however, groups few non-Node related tips that are well-known +:white_check_mark: **Роби:** Ця публікація зосереджена на порадах щодо тестування, які пов’язані з Node JS або, принаймні, можуть бути представлені на прикладі Node JS. Однак у цьому розділі згруповано кілька добре відомих порад, не пов’язаних з Node
    1. Use a declarative syntax. This is the only option for most vendors but older versions of Jenkins allows using code or UI
    2. Opt for a vendor that has native Docker support
    3. Fail early, run your fastest tests first. Create a ‘Smoke testing’ step/milestone that groups multiple fast inspections (e.g. linting, unit tests) and provide snappy feedback to the code committer
    4. Make it easy to skim-through all build artifacts including test reports, coverage reports, mutation reports, logs, etc
    5. Create multiple pipelines/jobs for each event, reuse steps between them. For example, configure a job for feature branch commits and a different one for master PR. Let each reuse logic using shared steps (most vendors provide some mechanism for code reuse)
    6. Never embed secrets in a job declaration, grab them from a secret store or from the job’s configuration
    7. Explicitly bump version in a release build or at least ensure the developer did so
    8. Build only once and perform all the inspections over the single build artifact (e.g. Docker image)
    9. Test in an ephemeral environment that doesn’t drift state between builds. Caching node_modules might be the only exception

    -❌ **Інакше:** You‘ll miss years of wisdom +❌ **Інакше:** Ви пропустите роки мудрості

    -## ⚪ ️ 5.9 Build matrix: Run the same CI steps using multiple Node versions +## ⚪ ️ 5.9 Матриця побудови: виконуйте ті самі кроки CI, використовуючи кілька версій Node -:white_check_mark: **Роби:** Quality checking is about serendipity, the more ground you cover the luckier you get in detecting issues early. When developing reusable packages or running a multi-customer production with various configuration and Node versions, the CI must run the pipeline of tests over all the permutations of configurations. For example, assuming we use MySQL for some customers and Postgres for others — some CI vendors support a feature called ‘Matrix’ which allow running the suit of testing against all permutations of MySQL, Postgres and multiple Node version like 8, 9 and 10. This is done using configuration only without any additional effort (assuming you have testing or any other quality checks). Other CIs who doesn’t support Matrix might have extensions or tweaks to allow that +:white_check_mark: **Роби:** Перевірка якості пов’язана з інтуїцією, чим більше ви охопите, тим більше вам пощастить у виявленні проблем на ранній стадії. Під час розробки пакетів для багаторазового використання або запуску виробництва для кількох клієнтів із різними конфігураціями та версіями Node, CI має запустити конвеєр тестів для всіх перестановок конфігурацій. Наприклад, якщо припустити, що ми використовуємо MySQL для одних клієнтів, а Postgres для інших —«деякі постачальники CI підтримують функцію під назвою «Матриця», яка дозволяє виконувати тестування всіх перестановок MySQL, Postgres і кількох версій Node, таких як 8, 9 і 10. Це робиться лише за допомогою конфігурації без будь-яких додаткових зусиль (за умови, що у вас є тестування чи будь-які інші перевірки якості). Інші КІ, які не підтримують Matrix, можуть мати розширення або налаштування, щоб дозволити це
    -❌ **Інакше:** So after doing all that hard work of writing testing are we going to let bugs sneak in only because of configuration issues? +❌ **Інакше:** Отже, після всієї цієї важкої роботи з написання тестування, ми дозволимо помилкам прокрадатися лише через проблеми з конфігурацією?
    @@ -2014,7 +2013,7 @@ An efficient update policy may allow some ‘vesting period’ — let the c
    -### :clap: Example: Using Travis (CI vendor) build definition to run the same test over multiple Node versions +### :clap: Приклад: Використання визначення збірки Travis (постачальник CI) для запуску одного тесту на кількох версіях Node
    language: node_js
    node_js:
    - "7"
    - "6"
    - "5"
    - "4"
    install:
    - npm install
    script:
    - npm run test
    @@ -2029,11 +2028,11 @@ An efficient update policy may allow some ‘vesting period’ — let the c
    -**Role:** Writer +**Роль:** Письменник -**About:** I'm an independent consultant who works with Fortune 500 companies and garage startups on polishing their JS & Node.js applications. More than any other topic I'm fascinated by and aims to master the art of testing. I'm also the author of [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices) +**Опис:** Я незалежний консультант, який працює з компаніями зі списку Fortune 500 і гаражними стартапами над вдосконаленням їхніх додатків JS і Node.js. Більше ніж будь-яка інша тема мене захоплює, і я прагну оволодіти мистецтвом тестування. Я також автор [найкращих практик Node.js](https://github.com/goldbergyoni/nodebestpractices) -**📗 Online Course:** Liked this guide and wish to take your testing skills to the extreme? Consider visiting my comprehensive course [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) +**📗 Онлайн-курс:** Сподобався цей посібник і ви бажаєте вдосконалити свої навички тестування? Відвідайте мій комплексний курс [Тестування Node.js і JavaScript від А до Я](https://www.testjavascript.com)
    @@ -2049,30 +2048,29 @@ An efficient update policy may allow some ‘vesting period’ — let the c ## [Bruno Scheufler](https://github.com/BrunoScheufler) -**Role:** Tech reviewer and advisor - -Took care to revise, improve, lint and polish all the texts +**Роль:** Технічний оглядач і радник -**About:** full-stack web engineer, Node.js & GraphQL enthusiast +Подбав про те, щоб переглянути, вдосконалити, відшліфувати та відшліфувати всі тексти +**Опис:** full-stack веб-інженер, ентузіаст Node.js та GraphQL

    ## [Ido Richter](https://github.com/idori) -**Role:** Concept, design and great advice +**Роль:** Concept, design and great advice -**About:** A savvy frontend developer, CSS expert and emojis freak +**Опис:** Кмітливий розробник інтерфейсу, експерт із CSS і фанат емодзі ## [Kyle Martin](https://github.com/js-kyle) -**Role:** Helps keep this project running, and reviews security related practices +**Роль:** Допомагає підтримувати роботу цього проекту та переглядає методи безпеки -**About:** Loves working on Node.js projects and web application security. +**Опис:** Любить працювати над проектами Node.js і безпекою веб-додатків. -## Contributors ✨ +## Автори ✨ -Thanks goes to these wonderful people who have contributed to this repository! +Дякуємо цим чудовим людям, які зробили внесок у це сховище! From 96480d0a00f7702bf552702bb4713b8aea78a6e5 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:06:30 +0000 Subject: [PATCH 158/189] docs: update readme.md [skip ci] --- readme.md | 105 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 54 insertions(+), 51 deletions(-) diff --git a/readme.md b/readme.md index 2a8134c3..70dcbeb5 100644 --- a/readme.md +++ b/readme.md @@ -2083,57 +2083,60 @@ Thanks goes to these wonderful people who have contributed to this repository! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Scott Davis

    🖋

    Adrien REDON

    🖋

    Stefano Magni

    🖋

    Yeoh Joer

    🖋

    Jhonny Moreira

    🖋

    Ian Germann

    🖋

    Hafez

    🖋

    Ruxandra Fediuc

    🖋

    Jack

    🖋

    Peter Carrero

    🖋

    Huhgawz

    🖋

    Haakon Borch

    🖋

    Jaime Mendoza

    🖋

    Cameron Dunford

    🖋

    John Gee

    🖋

    Aurelijus Rožėnas

    🖋

    Aaron

    🖋

    Tom Nagle

    🖋

    Yves yao

    🖋

    Userbit

    🖋

    Glaucia Lemos

    🚧

    koooge

    🖋

    Michal

    🖋

    roywalker

    🖋

    dangen

    🖋

    biesiadamich

    🖋

    Yanlin Jiang

    🖋

    sanguino

    🖋

    Morgan

    🖋

    Lukas Bischof

    ⚠️ 🖋

    JuanMa Ruiz

    🖋

    Luís Ângelo Rodrigues Jr.

    🖋

    José Fernández

    🖋

    Alejandro Gutierrez Barcenilla

    🖋

    Jason

    🖋

    Otavio Araujo

    ⚠️ 🖋

    Alex Ivanov

    🖋

    Yiqiao Xu

    🖋

    YuBin, Hsu

    🌍 💻
    Scott Davis
    Scott Davis

    🖋
    Adrien REDON
    Adrien REDON

    🖋
    Stefano Magni
    Stefano Magni

    🖋
    Yeoh Joer
    Yeoh Joer

    🖋
    Jhonny Moreira
    Jhonny Moreira

    🖋
    Ian Germann
    Ian Germann

    🖋
    Hafez
    Hafez

    🖋
    Ruxandra Fediuc
    Ruxandra Fediuc

    🖋
    Jack
    Jack

    🖋
    Peter Carrero
    Peter Carrero

    🖋
    Huhgawz
    Huhgawz

    🖋
    Haakon Borch
    Haakon Borch

    🖋
    Jaime Mendoza
    Jaime Mendoza

    🖋
    Cameron Dunford
    Cameron Dunford

    🖋
    John Gee
    John Gee

    🖋
    Aurelijus Rožėnas
    Aurelijus Rožėnas

    🖋
    Aaron
    Aaron

    🖋
    Tom Nagle
    Tom Nagle

    🖋
    Yves yao
    Yves yao

    🖋
    Userbit
    Userbit

    🖋
    Glaucia Lemos
    Glaucia Lemos

    🚧
    koooge
    koooge

    🖋
    Michal
    Michal

    🖋
    roywalker
    roywalker

    🖋
    dangen
    dangen

    🖋
    biesiadamich
    biesiadamich

    🖋
    Yanlin Jiang
    Yanlin Jiang

    🖋
    sanguino
    sanguino

    🖋
    Morgan
    Morgan

    🖋
    Lukas Bischof
    Lukas Bischof

    ⚠️ 🖋
    JuanMa Ruiz
    JuanMa Ruiz

    🖋
    Luís Ângelo Rodrigues Jr.
    Luís Ângelo Rodrigues Jr.

    🖋
    José Fernández
    José Fernández

    🖋
    Alejandro Gutierrez Barcenilla
    Alejandro Gutierrez Barcenilla

    🖋
    Jason
    Jason

    🖋
    Otavio Araujo
    Otavio Araujo

    ⚠️ 🖋
    Alex Ivanov
    Alex Ivanov

    🖋
    Yiqiao Xu
    Yiqiao Xu

    🖋
    YuBin, Hsu
    YuBin, Hsu

    🌍 💻
    Ali Azmoodeh
    Ali Azmoodeh

    🖋
    From 91a30571e03485a282fc10dde906597c2dfb5a18 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:06:31 +0000 Subject: [PATCH 159/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 52b52910..21426a42 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -360,10 +360,20 @@ "translation", "code" ] + }, + { + "login": "TREER00T", + "name": "Ali Azmoodeh", + "avatar_url": "https://avatars.githubusercontent.com/u/76606342?v=4", + "profile": "https://github.com/TREER00T", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", "projectOwner": "goldbergyoni", "repoType": "github", - "repoHost": "https://github.com" + "repoHost": "https://github.com", + "commitConvention": "angular" } From 71c0a1681fa9d95daaac1c3c6220270dad10f7a9 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:18:07 +0000 Subject: [PATCH 160/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 21426a42..e97af5c0 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -369,6 +369,15 @@ "contributions": [ "content" ] + }, + { + "login": "Saimon398", + "name": "Alex Popov", + "avatar_url": "https://avatars.githubusercontent.com/u/71539667?v=4", + "profile": "https://github.com/Saimon398", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From 3677c165b664c3541799adaf435893fff589c4c9 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:18:15 +0000 Subject: [PATCH 161/189] docs: update readme.md [skip ci] --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 0f7ab363..e79a549e 100644 --- a/readme.md +++ b/readme.md @@ -2133,6 +2133,7 @@ Thanks goes to these wonderful people who have contributed to this repository! Yiqiao Xu
    Yiqiao Xu

    🖋 YuBin, Hsu
    YuBin, Hsu

    🌍 💻 Ali Azmoodeh
    Ali Azmoodeh

    🖋 + Alex Popov
    Alex Popov

    🖋 From c617680ebd9b8708155053f84718f65e79898ec3 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:21:34 +0000 Subject: [PATCH 162/189] docs: update readme.md [skip ci] --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index e79a549e..901516f8 100644 --- a/readme.md +++ b/readme.md @@ -2134,6 +2134,7 @@ Thanks goes to these wonderful people who have contributed to this repository! YuBin, Hsu
    YuBin, Hsu

    🌍 💻 Ali Azmoodeh
    Ali Azmoodeh

    🖋 Alex Popov
    Alex Popov

    🖋 + Serhii Shramko
    Serhii Shramko

    🖋 From 9461f420c3a34683ded778b39a11643a4c396ddc Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:21:35 +0000 Subject: [PATCH 163/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index e97af5c0..4c1850d2 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -378,6 +378,15 @@ "contributions": [ "content" ] + }, + { + "login": "Shramkoweb", + "name": "Serhii Shramko", + "avatar_url": "https://avatars.githubusercontent.com/u/42001531?v=4", + "profile": "http://shramko.dev", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From b19800c16a956fb547277d129fd11d98d5865665 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Wed, 14 Dec 2022 08:22:26 -0500 Subject: [PATCH 164/189] Update readme.md --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 901516f8..7ee8cc00 100644 --- a/readme.md +++ b/readme.md @@ -40,6 +40,7 @@ Start by understanding the ubiquitous testing practices that are the foundation - 🇧🇷[Portuguese-BR](readme-pt-br.md) - Courtesy of [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) - 🇫🇷[French](readme-fr.md) - Courtesy of [Mathilde El Mouktafi](https://github.com/mel-mouk) - 🇯🇵[Japanese (draft)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - Courtesy of [Yuichi Yogo](https://github.com/yuichkun) and [ryo](https://github.com/kawamataryo) +- 🇺🇦[Ukrainian](readme-ua.md) - Courtesy of [Serhii Shramko](https://github.com/Shramkoweb) - 🇹🇼[Traditional Chinese](readme-zh-TW.md) - Courtesy of [Yubin Hsu](https://github.com/yubinTW) - 🇮🇷[Persian](readme-pr-fr.md) - Courtesy of [Ali Azmoodeh](https://github.com/TREER00T) - Want to translate to your own language? please open an issue 💜 From e65651ffb162a8cf21502d1c27a71a03e020aef4 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:26:08 +0000 Subject: [PATCH 165/189] docs: update readme.md [skip ci] --- readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/readme.md b/readme.md index 7ee8cc00..221e0906 100644 --- a/readme.md +++ b/readme.md @@ -2137,6 +2137,9 @@ Thanks goes to these wonderful people who have contributed to this repository! Alex Popov
    Alex Popov

    🖋 Serhii Shramko
    Serhii Shramko

    🖋 + + Yugo Sakamoto
    Yugo Sakamoto

    🖋 + From 680af5af1bcae76052f0659e13936d535d1cceda Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:26:09 +0000 Subject: [PATCH 166/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 4c1850d2..14bf6871 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -387,6 +387,15 @@ "contributions": [ "content" ] + }, + { + "login": "yugoccp", + "name": "Yugo Sakamoto", + "avatar_url": "https://avatars.githubusercontent.com/u/1724114?v=4", + "profile": "https://github.com/yugoccp", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From 40994a22cc7813c11a3102f575d8678b2f2ea5dc Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:31:12 +0000 Subject: [PATCH 167/189] docs: update readme.md [skip ci] --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 221e0906..5e871081 100644 --- a/readme.md +++ b/readme.md @@ -2139,6 +2139,7 @@ Thanks goes to these wonderful people who have contributed to this repository! Yugo Sakamoto
    Yugo Sakamoto

    🖋 + Frazer Smith
    Frazer Smith

    🖋 From 21d598cb48e66b447ff26c0ef4727a74e2206e1c Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:31:13 +0000 Subject: [PATCH 168/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 14bf6871..7e4ffe2e 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -396,6 +396,15 @@ "contributions": [ "content" ] + }, + { + "login": "Fdawgs", + "name": "Frazer Smith", + "avatar_url": "https://avatars.githubusercontent.com/u/43814140?v=4", + "profile": "https://yeovilhospital.co.uk/", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From 6f9c0778bc130a9dfd305f8133050d99bb8e02ac Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:31:58 +0000 Subject: [PATCH 169/189] docs: update readme.md [skip ci] --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 2dd2f82e..d52123b3 100644 --- a/readme.md +++ b/readme.md @@ -2140,6 +2140,7 @@ Thanks goes to these wonderful people who have contributed to this repository! Yugo Sakamoto
    Yugo Sakamoto

    🖋 Frazer Smith
    Frazer Smith

    🖋 + Wralith
    Wralith

    🖋 From a4cb7f27a969530fc3bc0cafe1b0328b1ef758a6 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:31:59 +0000 Subject: [PATCH 170/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 7e4ffe2e..f24fbb49 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -405,6 +405,15 @@ "contributions": [ "content" ] + }, + { + "login": "wralith", + "name": "Wralith", + "avatar_url": "https://avatars.githubusercontent.com/u/75392169?v=4", + "profile": "https://github.com/wralith", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From d4b80e5a6f7989bbf12f6e36bf8ff200723c1abf Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:33:38 +0000 Subject: [PATCH 171/189] docs: update readme.md [skip ci] --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index f0423d74..48dfcb5f 100644 --- a/readme.md +++ b/readme.md @@ -2141,6 +2141,7 @@ Thanks goes to these wonderful people who have contributed to this repository! Yugo Sakamoto
    Yugo Sakamoto

    🖋 Frazer Smith
    Frazer Smith

    🖋 Wralith
    Wralith

    🖋 + Harang
    Harang

    🖋 From fc4495b69ae14996b697216f539bc96c891c1e23 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:33:39 +0000 Subject: [PATCH 172/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index f24fbb49..233ce6a3 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -414,6 +414,15 @@ "contributions": [ "content" ] + }, + { + "login": "saseungmin", + "name": "Harang", + "avatar_url": "https://avatars.githubusercontent.com/u/60910665?v=4", + "profile": "https://haranglog.tistory.com", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From 26dbb53b750d2a02f096b879026e62feafe1503a Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:44:10 +0000 Subject: [PATCH 173/189] docs: update readme.md [skip ci] --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 9495eea1..10b3088a 100644 --- a/readme.md +++ b/readme.md @@ -2142,6 +2142,7 @@ Thanks goes to these wonderful people who have contributed to this repository! Frazer Smith
    Frazer Smith

    🖋 Wralith
    Wralith

    🖋 Harang
    Harang

    🖋 + rcanelav
    rcanelav

    🖋 From 92e3e5aad824116d670258ae2592de9cc7172d03 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:44:11 +0000 Subject: [PATCH 174/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 233ce6a3..69c2b513 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -423,6 +423,15 @@ "contributions": [ "content" ] + }, + { + "login": "rcanelav", + "name": "rcanelav", + "avatar_url": "https://avatars.githubusercontent.com/u/64812826?v=4", + "profile": "https://github.com/rcanelav", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From c08c0e6caa12a8f0fdd7a921e69d822ac90c9052 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:46:37 +0000 Subject: [PATCH 175/189] docs: update readme.md [skip ci] --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 10b3088a..9b0612d8 100644 --- a/readme.md +++ b/readme.md @@ -2143,6 +2143,7 @@ Thanks goes to these wonderful people who have contributed to this repository! Wralith
    Wralith

    🖋 Harang
    Harang

    🖋 rcanelav
    rcanelav

    🖋 + Drew Wilson
    Drew Wilson

    🖋 From 15a37310fb0fa4140d1f348353d0b2c1407ec10f Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:46:38 +0000 Subject: [PATCH 176/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 69c2b513..7c21ad13 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -432,6 +432,15 @@ "contributions": [ "content" ] + }, + { + "login": "drewrwilson", + "name": "Drew Wilson", + "avatar_url": "https://avatars.githubusercontent.com/u/4324656?v=4", + "profile": "https://github.com/drewrwilson", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From 457de5cd1722af640a16673d2f738fd83f0bbe75 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:48:15 +0000 Subject: [PATCH 177/189] docs: update readme.md [skip ci] --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 9b0612d8..bc60e3ce 100644 --- a/readme.md +++ b/readme.md @@ -2144,6 +2144,7 @@ Thanks goes to these wonderful people who have contributed to this repository! Harang
    Harang

    🖋 rcanelav
    rcanelav

    🖋 Drew Wilson
    Drew Wilson

    🖋 + XtLee
    XtLee

    🖋 From 0ad6a9a34c1e6b38e67f466c6f6624f0070ad437 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:48:16 +0000 Subject: [PATCH 178/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 7c21ad13..9a1ce9ee 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -441,6 +441,15 @@ "contributions": [ "content" ] + }, + { + "login": "XtLee", + "name": "XtLee", + "avatar_url": "https://avatars.githubusercontent.com/u/30145777?v=4", + "profile": "https://github.com/XtLee", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From f263237cc95db5632164a797f99e7391c8ca2704 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:49:55 +0000 Subject: [PATCH 179/189] docs: update readme.md [skip ci] --- readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/readme.md b/readme.md index 393d8fa5..7d6cdfe2 100644 --- a/readme.md +++ b/readme.md @@ -2147,6 +2147,9 @@ Thanks goes to these wonderful people who have contributed to this repository! Drew Wilson
    Drew Wilson

    🖋 XtLee
    XtLee

    🖋 + + Simon Ingeson
    Simon Ingeson

    🖋 + From 1967b1dbeb0859e68e9827741cd079e6faddd774 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:49:56 +0000 Subject: [PATCH 180/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 9a1ce9ee..672bc4d2 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -450,6 +450,15 @@ "contributions": [ "content" ] + }, + { + "login": "smonn", + "name": "Simon Ingeson", + "avatar_url": "https://avatars.githubusercontent.com/u/44818?v=4", + "profile": "https://www.smonn.se", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From f8d45eb8024938376f85365892763a8a3fe6eab2 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:50:51 +0000 Subject: [PATCH 181/189] docs: update readme.md [skip ci] --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index c1a3c456..d57c7dee 100644 --- a/readme.md +++ b/readme.md @@ -2149,6 +2149,7 @@ Thanks goes to these wonderful people who have contributed to this repository! Simon Ingeson
    Simon Ingeson

    🖋 + elfacu0
    elfacu0

    🖋 From 6759ddb5b9390f08f93006999897613d85fcb05f Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:50:52 +0000 Subject: [PATCH 182/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 672bc4d2..a653d878 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -459,6 +459,15 @@ "contributions": [ "content" ] + }, + { + "login": "elfacu0", + "name": "elfacu0", + "avatar_url": "https://avatars.githubusercontent.com/u/30785449?v=4", + "profile": "https://github.com/elfacu0", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From 0cd0e2e453239ad5843faeb3ad8579654cde231c Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:51:47 +0000 Subject: [PATCH 183/189] docs: update readme.md [skip ci] --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index d57c7dee..9752d187 100644 --- a/readme.md +++ b/readme.md @@ -2150,6 +2150,7 @@ Thanks goes to these wonderful people who have contributed to this repository! Simon Ingeson
    Simon Ingeson

    🖋 elfacu0
    elfacu0

    🖋 + jorbelca
    jorbelca

    🖋 From eb154f51f963ce384ebb5ce6b0f0193c9305a3bc Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:51:48 +0000 Subject: [PATCH 184/189] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index a653d878..db0972e7 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -468,6 +468,15 @@ "contributions": [ "content" ] + }, + { + "login": "jorbelca", + "name": "jorbelca", + "avatar_url": "https://avatars.githubusercontent.com/u/76847923?v=4", + "profile": "https://github.com/jorbelca", + "contributions": [ + "content" + ] } ], "projectName": "javascript-testing-best-practices", From cff5db64fa4fcb7e206c7cb65fe3e8c32fa14048 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Wed, 14 Dec 2022 08:54:21 -0500 Subject: [PATCH 185/189] Update readme.md --- readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 9752d187..fac5f7ed 100644 --- a/readme.md +++ b/readme.md @@ -40,9 +40,11 @@ Start by understanding the ubiquitous testing practices that are the foundation - 🇧🇷[Portuguese-BR](readme-pt-br.md) - Courtesy of [Iago Angelim Costa Cavalcante](https://github.com/iagocavalcante) , [Douglas Mariano Valero](https://github.com/DouglasMV) and [koooge](https://github.com/koooge) - 🇫🇷[French](readme-fr.md) - Courtesy of [Mathilde El Mouktafi](https://github.com/mel-mouk) - 🇯🇵[Japanese (draft)](https://github.com/yuichkun/javascript-testing-best-practices/blob/master/readme-jp.md) - Courtesy of [Yuichi Yogo](https://github.com/yuichkun) and [ryo](https://github.com/kawamataryo) -- 🇺🇦[Ukrainian](readme-ua.md) - Courtesy of [Serhii Shramko](https://github.com/Shramkoweb) - 🇹🇼[Traditional Chinese](readme-zh-TW.md) - Courtesy of [Yubin Hsu](https://github.com/yubinTW) +- 🇺🇦[Ukrainian](readme-ua.md) - Courtesy of [Serhii Shramko](https://github.com/Shramkoweb) - 🇮🇷[Persian](readme-pr-fr.md) - Courtesy of [Ali Azmoodeh](https://github.com/TREER00T) +- 🇷🇺[Russian](readme-ru.md) - Courtesy of [Alex Popov](https://github.com/Saimon398) + - Want to translate to your own language? please open an issue 💜

    From cdea2444a25622d664a58f4612915961832dd933 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Sun, 23 Jul 2023 20:02:10 +0300 Subject: [PATCH 186/189] Update readme.md --- readme.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index fac5f7ed..d3bb8299 100644 --- a/readme.md +++ b/readme.md @@ -21,13 +21,9 @@ Start by understanding the ubiquitous testing practices that are the foundation
    -## 🚀 We have an [official Node.js starter - Practica.js](https://github.com/practicajs/practica). Use it to generate a new solution skeleton with testing baked in, Or just it to learn by testing code examples +### Written By Yoni Goldberg - A JavaScript & Node.js consultant -### Written By Yoni Goldberg - -- A JavaScript & Node.js consultant -- 📗 [Testing Node.js & JavaScript From A To Z](https://www.testjavascript.com) - My comprehensive online course with more than [7 hours of video](https://www.testjavascript.com) -- [Follow me on Twitter](https://twitter.com/goldbergyoni/) +## 🥳 Exciting news: After two years of recording and editing, I've just released my super-comprehensive testing course [It's now on a 🎁 limited-time sale during July](https://testjavascript.com/)
    From 5542c60d106c2e1566279155eabb37f339646a67 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Sun, 23 Jul 2023 20:03:10 +0300 Subject: [PATCH 187/189] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index d3bb8299..ac0397fa 100644 --- a/readme.md +++ b/readme.md @@ -23,7 +23,7 @@ Start by understanding the ubiquitous testing practices that are the foundation ### Written By Yoni Goldberg - A JavaScript & Node.js consultant -## 🥳 Exciting news: After two years of recording and editing, I've just released my super-comprehensive testing course [It's now on a 🎁 limited-time sale during July](https://testjavascript.com/) +### 👨‍🏫 Exciting news: After two years of recording and editing, I've just released my super-comprehensive testing course [It's now on a 🎁 limited-time sale during July](https://testjavascript.com/)
    From 3dc36fd7b60ccfda604a3164023726baceec48e5 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Sun, 23 Jul 2023 20:03:44 +0300 Subject: [PATCH 188/189] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index ac0397fa..a9b67d07 100644 --- a/readme.md +++ b/readme.md @@ -23,7 +23,7 @@ Start by understanding the ubiquitous testing practices that are the foundation ### Written By Yoni Goldberg - A JavaScript & Node.js consultant -### 👨‍🏫 Exciting news: After two years of recording and editing, I've just released my super-comprehensive testing course [It's now on a 🎁 limited-time sale during July](https://testjavascript.com/) +### 👨‍🏫 Exciting news: I've just released my super-comprehensive testing course after two years of recording and editing. [It's now on a 🎁 limited-time sale during July](https://testjavascript.com/)
    From 63a2bb07bb718d0a34a9c1249ef0df9b1266dad8 Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Tue, 8 Aug 2023 16:58:43 +0300 Subject: [PATCH 189/189] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index a9b67d07..211643f3 100644 --- a/readme.md +++ b/readme.md @@ -23,7 +23,7 @@ Start by understanding the ubiquitous testing practices that are the foundation ### Written By Yoni Goldberg - A JavaScript & Node.js consultant -### 👨‍🏫 Exciting news: I've just released my super-comprehensive testing course after two years of recording and editing. [It's now on a 🎁 limited-time sale during July](https://testjavascript.com/) +### 👨‍🏫 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://testjavascript.com/)