├── .gitignore ├── .operations ├── CONTRIBUTING.md ├── operations-manual.md └── writing-guidelines.md ├── LICENSE ├── README.md ├── assets └── images │ ├── banner-2.jpg │ ├── banner-2.psd │ ├── checkbox-sm.png │ ├── checkbox-small-blue.png │ ├── checkbox-small.PNG │ ├── checkmark-green-small.png │ ├── checkmark-green.png │ ├── checkmark-green_small.png │ ├── linkedin.png │ ├── members │ ├── member.psd │ └── noriste.png │ ├── stackoverflow.png │ ├── twitter-s.png │ ├── twitter.png │ ├── use-your-testing-tool-as-your-primary-development-tool │ ├── browser-selection.png │ ├── devtools.png │ └── skip-and-only-ui.png │ ├── viconblue.PNG │ ├── www.png │ └── www.svg ├── references.md └── sections ├── draft.md ├── generic-best-practices ├── await-dont-sleep.md ├── name-test-files-wisely.md └── use-your-testing-tool-as-your-primary-development-tool.md ├── server-communication-testing ├── monitoring-tests.md └── test-request-and-response-payload.md ├── template.md └── testing-strategy ├── avoid-perfectionism.md ├── choose-a-reference-browser.md ├── component-vs-integration-vs-e2e-testing.md └── write-test-then-fix-bug.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .idea 3 | .vscode 4 | .idea/**/* 5 | .vscode/**/* 6 | .nyc_output 7 | mochawesome-report 8 | .DS_Store 9 | npm-debug.log.* 10 | node_modules 11 | node_modules/**/* 12 | .eslintcache 13 | cert 14 | logs/* 15 | desktop.ini 16 | package-lock.json 17 | .history 18 | .env -------------------------------------------------------------------------------- /.operations/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contribution model 2 | 3 | ### Steering committee 🏆 4 | 5 | Members of the steering committee work together to provide guidance and future direction to the project. Each committee member has a particular expertise which they share their knowledge on, and work to lead further improvements to the project in that area. The steering committee members are responsible for approving new best practices, and ensuring current best practices remain relevant. 6 | 7 | ### Collaborators 👍 8 | 9 | Collaborators are members who are contributing to the repository on a regular basis, through suggesting new best practices, triaging issues, reviewing pull requests and more. Along with the steering committee, each collaborator leads a project tracked under our Github projects. 10 | 11 | The role is in place to help the steering committee ensure that the content provided is of a high standard, up-to-date with the industry, and available in many languages. Members who frequently participate in these activities will be invited to become a collaborator, based on the quality of their contributions. 12 | 13 | The steering committee periodically reviews the collaborator list to identify inactive collaborators. Inactive collaborators can choose to either continue in or step down from their role, in which case they are acknowledged as a past collaborator. They may later request that the steering committee restore them to active status. 14 | 15 | ### Flowers and stars 16 | 17 | Every addition to the project are acknowledged by the author gaining a place on the home page. A flower 🌻 marks a successful pull request. A star of honor ⭐ is assigned to contributors who propose and write a new best practice to our guide. 18 | -------------------------------------------------------------------------------- /.operations/operations-manual.md: -------------------------------------------------------------------------------- 1 | # Operations Manual - Organizing and Maximizing Our Work 2 | Building a community and knowledge by efficiently handling issues 3 | 4 | ## Handling issues and PR 5 | 6 |
7 | In a nutshell, every issue and PR should get tagged by one of our core team and routed to the person who specializes in the related topic. This person then, will warmly welcome and kick the discussion shortly (hopefully within 48 hours). The goal of each issue/PR is to learn new thing that might improve our repo and try joining the opener to our forces. 8 | 9 | There is no specific person on call who assigns inquiries rather we count on our core team to visit almost everyday and assign issues/PR - this way, the workflow is not depend upon any specific person rather on our entire team. 10 | 11 | Any new content should conform to our [writing guidelines](https://github.com/NoriSte/ui-testing-best-practices/blob/master/.operations/writing-guidelines.md) 12 | 13 | ## Monthly maintenance 14 | 15 |
16 | Each month, a maintainer on call will open an issue for maintenance work and record within all the actions to perform by the end of the month (e.g. assign flower to a contributor). On the end of the corresponding month, the maintainer will run the following checklist 17 | 18 | ## Translations 19 | 20 |
21 | If the contents will be translated into other languages, take a look at how the [nodebestpractices](https://github.com/i0natan/nodebestpractices/blob/master/.operations/operations-manual.md) members organize their maintenance. 22 | 23 | --- 24 | 25 | **Maintainer on call**: @someone 26 | 27 | **Updates** 28 | 29 | - [ ] Update top badges with best practices item count and last update 30 | - [ ] Update the 'Latest Best Practices and News' section 31 | - [ ] Update the Welcome message 32 | - [ ] Update the Table of Contents 33 | - [ ] Update 'thank you' stars & flowers 34 | - [ ] Notify and thanks the contributors of the month 35 | 36 | **Flowers** 37 | - @someone2 38 | - @someone1 39 | 40 | **Stars** 41 | - @someone1 42 | 43 | **Core Team** 44 | - @someone1 45 | 46 | -- 47 | 48 | | Month | Maintainer on call | 49 | |---------|--------------------| 50 | | 03/2018 | NoriSte | 51 | | 04/2018 | NoriSte | 52 | | 05/2018 | NoriSte | 53 | | 06/2019 | NoriSte | 54 | | 07/2019 | NoriSte | 55 | | 08/2019 | NoriSte | 56 | | 09/2019 | NoriSte | 57 | | 10/2019 | NoriSte | 58 | | 11/2019 | NoriSte | 59 | | 12/2019 | NoriSte | 60 | | 13/2019 | NoriSte | 61 | 62 | 63 |
64 | 65 | ## Routing by areas of expertise 66 | 67 | | Topic | Examples | Assignee | 68 | |------------|------------|----------| 69 | | Everything | Everything | NoriSte | 70 | -------------------------------------------------------------------------------- /.operations/writing-guidelines.md: -------------------------------------------------------------------------------- 1 | # Our content writing manifest 2 | How we enhance the reading and learning experience for our visitors 3 | 4 | ## 1. Simple is better than better 5 | 6 |
7 | Making it easy to read and absorb knowledge is our mission, we curate content. As such we focus on transforming complex and exhausting topics into a simplified list, trade overloaded information with shortened and less-accurate details, avoid ‘flammable’ and controversial topics and escape subjective ideas in favor of generally accepted practices 8 | 9 |
10 | 11 | ## 2. Be evidence-based and reliable 12 | 13 |
14 | Our readers should have great confidence that the content they skim through is reliable. We achieve this by including evidence like references, data and other resources available to this topic. Practically, strive to include quotes from reliable sources, show benchmarks, related design patterns or any scientific measure to prove your claims 15 | 16 | 17 | ## 3. MECE (Mutually Exclusive and Collectively Exhaustive) 18 | Apart from the content being greatly edited and reliable, skimming through it should also provide full coverage of the topic. No important sub-topic should be left out 19 | 20 | ## 4. Consistent formatting 21 | The content is presented using fixed templates. Any future content must conform to the same template. If you wish to add new bullets copy a bullet format from an existing bullet and extend it to your needs. For additional information please view [this template](https://github.com/NoriSte/ui-testing-best-practices/blob/master/sections/template.md) 22 | 23 | ## 5. It's About UI testing 24 | Each advice should be related directly to UI testing and not to software development in general. UI testing will be mostly related to web UI testing but also to mobile UI testing, CLI UI testing etc. The content should focus at least on one testing framework implementation (Cypress, Puppeteer, Selenium, TestCafè, Appium...) but, if applicable, it should be declined to other frameworks too. If the content can't be declined, both because it's strictly related to a specific context or because the author doesn't know how to decline it, the members will speak and manage it into the PR. 25 | If a topic hasn't a specific implementation use the [nodebestpractices item 6.5](https://github.com/i0natan/nodebestpractices/blob/master/sections/security/commonsecuritybestpractices.md) as an example. 26 | 27 | ## 6. Leading vendors only 28 | Sometimes it's useful to include names of vendors that can address certain challenges and problems like npm packages, open source tools or even commercial products. To avoid overwhelmingly long lists or recommending non-reputable and unstable projects, the nodebestpractices members came up with the following rules (we will verify time by time if they're applicable to UI testing too): 29 | 30 | - Only the top 3 vendors should be recommended – a vendor that appears in the top 3 results of a search engine (Google or GitHub sorted by popularity) for a given relevant keyword can be included in our recommendation 31 | - If it’s a npm package it must also be downloaded at least 750 times a day on average 32 | - If it’s an open-source project, it must have been updated at least once in the last 6 months 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ## creative commons 2 | 3 | # Attribution-ShareAlike 4.0 International 4 | 5 | Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. 6 | 7 | ### Using Creative Commons Public Licenses 8 | 9 | Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. 10 | 11 | * __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors). 12 | 13 | * __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees). 14 | 15 | ## Creative Commons Attribution-ShareAlike 4.0 International Public License 16 | 17 | By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. 18 | 19 | ### Section 1 – Definitions. 20 | 21 | a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. 22 | 23 | b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. 24 | 25 | c. __BY-SA Compatible License__ means a license listed at [creativecommons.org/compatiblelicenses](http://creativecommons.org/compatiblelicenses), approved by Creative Commons as essentially the equivalent of this Public License. 26 | 27 | d. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. 28 | 29 | e. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. 30 | 31 | f. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. 32 | 33 | g. __License Elements__ means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution and ShareAlike. 34 | 35 | h. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License. 36 | 37 | i. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. 38 | 39 | j. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License. 40 | 41 | k. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. 42 | 43 | l. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. 44 | 45 | m. __You__ means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. 46 | 47 | ### Section 2 – Scope. 48 | 49 | a. ___License grant.___ 50 | 51 | 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: 52 | 53 | A. reproduce and Share the Licensed Material, in whole or in part; and 54 | 55 | B. produce, reproduce, and Share Adapted Material. 56 | 57 | 2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 58 | 59 | 3. __Term.__ The term of this Public License is specified in Section 6(a). 60 | 61 | 4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 62 | 63 | 5. __Downstream recipients.__ 64 | 65 | A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. 66 | 67 | B. __Additional offer from the Licensor – Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply. 68 | 69 | C. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 70 | 71 | 6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). 72 | 73 | b. ___Other rights.___ 74 | 75 | 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 76 | 77 | 2. Patent and trademark rights are not licensed under this Public License. 78 | 79 | 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. 80 | 81 | ### Section 3 – License Conditions. 82 | 83 | Your exercise of the Licensed Rights is expressly made subject to the following conditions. 84 | 85 | a. ___Attribution.___ 86 | 87 | 1. If You Share the Licensed Material (including in modified form), You must: 88 | 89 | A. retain the following if it is supplied by the Licensor with the Licensed Material: 90 | 91 | i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); 92 | 93 | ii. a copyright notice; 94 | 95 | iii. a notice that refers to this Public License; 96 | 97 | iv. a notice that refers to the disclaimer of warranties; 98 | 99 | v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; 100 | 101 | B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and 102 | 103 | C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 104 | 105 | 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 106 | 107 | 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 108 | 109 | b. ___ShareAlike.___ 110 | 111 | In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. 112 | 113 | 1. The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-SA Compatible License. 114 | 115 | 2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. 116 | 117 | 3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. 118 | 119 | ### Section 4 – Sui Generis Database Rights. 120 | 121 | Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: 122 | 123 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; 124 | 125 | b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and 126 | 127 | c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. 128 | 129 | For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. 130 | 131 | ### Section 5 – Disclaimer of Warranties and Limitation of Liability. 132 | 133 | a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__ 134 | 135 | b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__ 136 | 137 | c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. 138 | 139 | ### Section 6 – Term and Termination. 140 | 141 | a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. 142 | 143 | b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 144 | 145 | 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 146 | 147 | 2. upon express reinstatement by the Licensor. 148 | 149 | For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. 150 | 151 | c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. 152 | 153 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. 154 | 155 | ### Section 7 – Other Terms and Conditions. 156 | 157 | a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. 158 | 159 | b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.t stated herein are separate from and independent of the terms and conditions of this Public License. 160 | 161 | ### Section 8 – Interpretation. 162 | 163 | a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. 164 | 165 | b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. 166 | 167 | c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. 168 | 169 | d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. 170 | 171 | > Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. 172 | > 173 | > Creative Commons may be contacted at creativecommons.org 174 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [✔]: assets/images/checkbox-small-blue.png 2 | 3 | # UI Testing Best Practices (Work in progress) 4 | 5 |

6 | UI testing Best Practices 7 |

8 | 9 |
10 | 11 |
12 | 2 items Last update: July 23, 2019 13 |
14 | 15 |
16 | 17 | [![NoriSte](/assets/images/twitter-s.png)](https://twitter.com/NoriSte/) **Follow me on Twitter!** [**@NoriSte**](https://twitter.com/NoriSte/) 18 | 19 |
20 | 21 | ###### Built and maintained by our [Steering Committee](#steering-committee) and [Collaborators](#collaborators) 22 | 23 | # Latest Best Practices and News 24 | 25 | (Work in progress) 26 | 33 | 34 |

35 | 36 | # Welcome! 3 Things You Ought To Know First: 37 | 38 | **1. You are, in fact, reading dozens of the best UI testing articles -** this repository is a summary and curation of the top-ranked content on UI testing best practices, as well as content written here by collaborators 39 | 40 | **2. It is the largest compilation, and it is growing every week -** currently, more than XX best practices, style guides, and architectural tips are presented. New issues and pull requests are welcome to keep this live book updated. We'd love to see you contributing here, whether that is fixing code mistakes, helping with translations, or suggesting brilliant new ideas. See our [writing guidelines here](/.operations/writing-guidelines.md) 41 | 42 | **3. Most best practices have additional info -** most bullets include a **🔗Read More** link that expands on the practice with code examples, quotes from selected blogs and more information 43 | 44 |

45 | 46 | ## Table of Contents 47 | (Work in progress, take a look at the [sections draft](/sections/draft.md) file) 48 | 1. [Testing strategies (4)](#1-testing-strategies) 49 | 2. [Generic Best Practices (3)](#2-generic-best-practices) 50 | 3. [Server Communication Testing (3)](#3-server-communication-testing) 51 | 52 |

53 | 54 | # `1. Testing strategies` 55 | 56 | 57 | ## ![✔] 1.1 Component tests vs (UI) Integration tests vs E2E tests 58 | 59 | **TL;DR:** Identifying the test types is the starting point to understand and master all the UI testing strategies, the tools, and the pro/cons of them. UI Integration tests are the most effective ones (you are going to love them), E2E tests give you the highest confidence, and Component tests allow you to test the units of the UI in isolation. 60 | 61 | **Otherwise:** You end up writing a lot of E2E tests without leveraging other simpler kind of tests. E2E tests are the most confident type of tests but even the hardest, slowest and most brittle ones. 62 | 63 | 🔗 [**Read More: Component vs (UI) Integration vs E2E tests**](/sections/testing-strategy/component-vs-integration-vs-e2e-testing.md) 64 | 65 |
66 | 67 | ## ![✔] 1.2 In the beginning, avoid perfectionism 68 | 69 | **TL;DR:** Software Testing is an amazing topic but a limited experience could make you fighting with a new enemy instead of relying on a new ally. Avoid, if you can, to test every complex user flows since the beginning of your UI testing journey. The simpler your first tests are, the sooner you get the advantages. 70 | 71 | **Otherwise:** You create complex and hard to be debugged tests. This kind of tests slow down your work and do not have any kind of usefulness. 72 | 73 | 🔗 [**Read More: In the beginning, avoid perfectionism**](/sections/testing-strategy/avoid-perfectionism.md) 74 | 75 |
76 | 77 | ## ![✔] 1.3 Choose a reference browser 78 | 79 | **TL;DR:** Cross-browser testing is way overrated. It's an important topic and it's the first thing you can think while starting evaluating the right testing tool. Don't worry: start by splitting functional testing from visual testing, that's the first step to correctly evaluate the need for cross-browser support (and to choose the right testing tool, too). Visual testing can be integrated into every testing tool, thank services like Applitools and Percy. 80 | 81 | **Otherwise:** You could choose the wrong testing tool based on the cross-browser support. 82 | 83 | 🔗 [**Read More: Choose a reference browser**](/sections/testing-strategy/choose-a-reference-browser.md) 84 | 85 |
86 | 87 | ## ![✔] 1.4 Found a bug? Write the test, then fix it 88 | 89 | **TL;DR:** A test is a good ally when you need to be sure that you are able to systematically reproducing a bug. A test allows you to speed up the fixing flow and to be 100% confident that the same bug is caught forever. 90 | 91 | **Otherwise:** You could not identify correctly the bug and you can not be sure that the bug will not present again in the future. 92 | 93 | 🔗 [**Read More: Found a bug? Write the test, then fix it**](/sections/testing-strategy/write-test-then-fix-bug.md) 94 | 95 |
96 | 97 | # `2. Generic Best Practices` 98 | 99 | 100 | ## ![✔] 2.1 Await, don't sleep 101 | 102 | **TL;DR:** When testing your UI, you define a sort of key points the app must pass through. Reaching these key 103 | points is an asynchronous process because, almost 100% of the times, your UI does not update 104 | synchronously. Those key points are called **deterministic events**, as known as something that you 105 | know that must happen. You need to wait for these events to make your tests robust. 106 | 107 | **Otherwise:** Sleeping the tests make your tests slow and brittle, it's one of the most common and biggest errors in UI testing. 108 | 109 | 🔗 [**Read More: Await, don't sleep**](/sections/generic-best-practices/await-dont-sleep.md) 110 | 111 |
112 | 113 | ## ![✔] 2.2 Name your test files wisely 114 | 115 | **TL;DR:** Lot of times you need to launch just a type of tests and it's super easy if you follow a 116 | common pattern while naming your testing files. 117 | 118 | **Otherwise:** You need to launch a long test suite just to have some of them run. 119 | 120 | 🔗 [**Read More: Name the test files 121 | wisely**](/sections/generic-best-practices/name-test-files-wisely.md) 122 | 123 |
124 | 125 | ## ![✔] 2.3 Use your testing tool as your primary development tool 126 | 127 | **TL;DR:** Leveraging your testing tool to avoid manual tests is one of the biggest improvements you 128 | could do to speed up your working flow. Testing tools are faster than you and the most modern ones include 129 | some UI utilities that make easy to use them as a development tool. 130 | 131 | **Otherwise:** You code the app the old way, losing a lot of time interacting manually with the UI itself. 132 | 133 | 🔗 [**Read More: Use your testing tool as your primary development tool**](/sections/generic-best-practices/use-your-testing-tool-as-your-primary-development-tool.md) 134 | 135 | 136 |

137 | 138 | # `3. Server Communication Testing` 139 | 140 | 141 | ## ![✔] 3.1 Test the request and response payloads 142 | 143 | **TL;DR:** The UI communicates continuously with the back-end, and usually every communication is critical. A bad request or a bed response could cause inconsistent data and inconsistent UI state. Remember that all the business is built around data and the user experience is scratched by every single UI failure. So, every single XHR request must be checked carefully. XHR request checks make your test more robust too, correct XHR management and testing are one of the most important aspects of a UI test. 144 | 145 | **Otherwise:** You could miss some relevant communication inconsistencies and when you need to debug them, you are going to waste a lot of time because the test will not drive you directly to the issue. 146 | 147 | 🔗 [**Read More: Test the request and response payloads**](/sections/server-communication-testing/test-request-and-response-payload.md) 148 | 149 |
150 | 151 | ## ![✔] 3.2 Test the server schema 152 | 153 | **TL;DR:** A lot of times, the front-end application breaks because of a change in the back-end. Ask your back-end colleagues to allow you to export every schema that describes the back-end entities and the communication with the front-end. Some examples could be the GraphQL schema, the ElasticSearch mapping, a Postman configuration, etc. more in general, everything that can warn you that something changed in the back-end. Every back-end change could impact the front-end and you must discover it as soonest as possible. You can keep the schema checked with a simple [snapshot test](https://jestjs.io/docs/en/snapshot-testing). 154 | 155 | **Otherwise:** You could miss some back-end change and your front-end application could break inadvertently. 156 | 157 |
158 | 159 | ## ![✔] 3.3 Monitoring tests 160 | 161 | **TL;DR:** The more the test suites are launched periodically, the more confident you are that everything works as expected. UI tests should be based on the user perspective but there are a lot of small tests that could give you a lot of immediate feedback without debugging the expected user flows. Monitoring small and taken-for-granted tech details helps you preventing bigger test failures. 162 | 163 | **Otherwise:** You mix tech-details tests with the user-oriented ones. 164 | 165 | 🔗 [**Read More: Monitoring tests**](/sections/server-communication-testing/monitoring-tests.md) 166 | 167 | 168 |
169 | 170 | 171 |


172 | 173 | ## Steering Committee 174 | 175 | Meet the steering committee members - the people who work together to provide guidance and future direction to the project. 176 | 177 | 178 | 179 | [Stefano Magni](https://github.com/NoriSte) 180 | 181 | 182 | 183 | 184 | A positive-minded front-end developer and Cypress Ambassador. He's a passion for good UIs, automation, testing and teaching. He's developed every kind of interface: webapps, mobile apps, smartTV apps and games. 185 | 186 |
187 | 188 | 189 | 190 | ## Collaborators 191 | 192 | Thank you to all our collaborators! 🙏 193 | 194 | Our collaborators are members who are contributing to the repository on a reguar basis, through suggesting new best practices, triaging issues, reviewing pull requests and more. If you are interested in helping us guide thousands of people to craft better UI tests, please read our [contributor guidelines](/.operations/CONTRIBUTING.md) 🎉 195 | 196 |
197 | 198 | | | 199 | | :--: | 200 | | [Anoop Kumar Gupta](https://github.com/anoop-gupt) | 201 | 202 |
203 | 204 | ## Thank You Notes 205 | 206 | We appreciate any contribution, from a single word fix to a new best practice. Below is a list of everyone who contributed to this project. A 🌻 marks a successful pull request and a ⭐ marks an approved new best practice. 207 | 208 | ### Flowers 209 | 210 | A successfull PR gives you a 🌻, be the first to collect it. 211 | 212 | 🌻 [Ferdinando Santacroce](https://github.com/jesuswasrasta) 213 | 🌻 [Luca Piazzoni](https://github.com/bioz87) 214 | 🌻 [Luca Previtali](https://www.linkedin.com/in/previtaliluca/) 215 | 216 | ### Stars 217 | 218 | An approved new best practice Be the first to collect a ⭐, contribute to this repository 😁 219 | 220 |


221 | 222 | This repository is inspired to the [nodebestpractices](https://github.com/i0natan/nodebestpractices) one, thank you [Yoni](https://github.com/i0natan) and the whole [steering team](https://github.com/i0natan/nodebestpractices#steering-committee) to keep it updated and to allow the creation of this repository. 223 | 224 |


225 | -------------------------------------------------------------------------------- /assets/images/banner-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/banner-2.jpg -------------------------------------------------------------------------------- /assets/images/banner-2.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/banner-2.psd -------------------------------------------------------------------------------- /assets/images/checkbox-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/checkbox-sm.png -------------------------------------------------------------------------------- /assets/images/checkbox-small-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/checkbox-small-blue.png -------------------------------------------------------------------------------- /assets/images/checkbox-small.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/checkbox-small.PNG -------------------------------------------------------------------------------- /assets/images/checkmark-green-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/checkmark-green-small.png -------------------------------------------------------------------------------- /assets/images/checkmark-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/checkmark-green.png -------------------------------------------------------------------------------- /assets/images/checkmark-green_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/checkmark-green_small.png -------------------------------------------------------------------------------- /assets/images/linkedin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/linkedin.png -------------------------------------------------------------------------------- /assets/images/members/member.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/members/member.psd -------------------------------------------------------------------------------- /assets/images/members/noriste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/members/noriste.png -------------------------------------------------------------------------------- /assets/images/stackoverflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/stackoverflow.png -------------------------------------------------------------------------------- /assets/images/twitter-s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/twitter-s.png -------------------------------------------------------------------------------- /assets/images/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/twitter.png -------------------------------------------------------------------------------- /assets/images/use-your-testing-tool-as-your-primary-development-tool/browser-selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/use-your-testing-tool-as-your-primary-development-tool/browser-selection.png -------------------------------------------------------------------------------- /assets/images/use-your-testing-tool-as-your-primary-development-tool/devtools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/use-your-testing-tool-as-your-primary-development-tool/devtools.png -------------------------------------------------------------------------------- /assets/images/use-your-testing-tool-as-your-primary-development-tool/skip-and-only-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/use-your-testing-tool-as-your-primary-development-tool/skip-and-only-ui.png -------------------------------------------------------------------------------- /assets/images/viconblue.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/viconblue.PNG -------------------------------------------------------------------------------- /assets/images/www.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldbergyoni/ui-testing-best-practices/f4e2d48ca69e09f2318c9b697a5da67bdbb2ed96/assets/images/www.png -------------------------------------------------------------------------------- /assets/images/www.svg: -------------------------------------------------------------------------------- 1 | Neelpari Artist -------------------------------------------------------------------------------- /references.md: -------------------------------------------------------------------------------- 1 | # Here is a list of awesome articles on UI testing 2 | 3 | 4 | [DZONE- UI Test automation best practices ](https://dzone.com/articles/top-15-ui-test-automation-best-practices-you-shoul) 5 | 6 | [TestProject-Test Automation Best Practices](https://blog.testproject.io/2017/04/16/test-automation-best-practices/) 7 | 8 | [Test Tips](https://dev.to/juperala/10-tips-for-test-automation-2pc3_) 9 | 10 | [Making UI Tests Resilient](https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change) 11 | 12 | [Testing Visual Design](https://www.nngroup.com/articles/testing-visual-design/) 13 | 14 | [Ways to speed your tests](https://www.thoughtworks.com/insights/blog/6-ways-speed-your-tests) 15 | 16 | [Regression Testing](https://www.infoq.com/articles/regression-testing-strategies/) 17 | 18 | [Best Practices for UI Testing](https://channel9.msdn.com/Shows/XamarinShow/Best-Practices-for-User-Interface-Automation) 19 | 20 | [Eggplant best practices blog](https://blog.eggplant.io/topic/testing-best-practices) 21 | 22 | [Guide Unit Testing](https://github.com/mawrkus/js-unit-testing-guide) 23 | 24 | 25 | -------------------------------------------------------------------------------- /sections/draft.md: -------------------------------------------------------------------------------- 1 | 2 | - beginners? go to the dedicated section 3 | 4 | - [ ] back-end related tests 5 | - [x] test request and response payloads 6 | - [ ] test the frontend with the integration tests, the backend with the E2E ones 7 | - [x] test the server schema (or everything that can impact the front-end app like PostMan exports, Elastic Search mappings etc.). That sould not be part of the front-end tests but consider that the app will be often broken by a server data change 8 | - [x] monitoring tests? 9 | - [ ] testing strategy 10 | - [x] component vs integration vs e2e testing 11 | - [x] when you find a bug, write the test (that fails, it's important) and then fix the bug 12 | - [x] choose a reference browser (and if you need mobile browsers use TestCafè) 13 | - [x] avoid perfectionism, lot of UI interaction details are useful but they don't need to be tested (unless you have been proven that they bring value to your company) 14 | - [ ] if you use typescript in your app, use it in your tests too, the initial temptation of avoiding it will not last long 15 | - [ ] ui testing best practices 16 | - [x] await, don't sleep 17 | - [x] wait for contents 18 | - [x] standard 19 | - [x] with custom selectors 20 | - [x] wait for network requests 21 | - [x] wait for front-end specific state 22 | - [ ] assert frequently. An assertion is auto-explicative, an error isn't. 23 | - [ ] choose a made on purpose library 24 | - [ ] use the same front-end constants/functions 25 | - [x] UI testing framework as a development tool. Write tests step by step to avoid manual testing even during the development phase and to have them already written when you finished (easier with Cypress). 26 | - [ ] don't use the UI to reach the desired UI state. But remember to avoid writing one more app into your testing framework to consume the same resources 27 | - [ ] we aren't unit-testing, every test has a flow and a lot of assertions 28 | - [ ] deterministic tests as wrote here https://docs.cypress.io/guides/core-concepts/conditional-testing.html#Error-Recovery 29 | - [ ] in your app / practical advices 30 | - [ ] expose costants/functions. It makes tests more portable too 31 | - [ ] don't delay this process, by definition UI tests are slow, avoid them failing for a silly string 32 | - [ ] expose some shortcuts. Everything useful for leting the UI run faster (without compromising reliability) is welcome 33 | - [ ] let the front-end work for you 34 | - [ ] base your tests on contents 35 | - [ ] ui testing is framework agnostic, base it on contents (the same consumed by the user) 36 | - [ ] pay attention on the pages that update frequently 37 | - [ ] a content-based failing test needs just a screenshot to be debugged, an attribute-based one needs the page to be inspected 38 | - [ ] if you can't rely on contents, use test-ids, never user classes of ids 39 | - [ ] avoid testing implementation details 40 | - [ ] generic testing best practices 41 | - [ ] use the right assertion 42 | - [ ] use "only" and "skip" 43 | - [x] name the test file wisely 44 | - [ ] check the Yoni's post https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347 45 | - [ ] don't share the state between tests 46 | - [ ] component testing 47 | - [ ] use storybook (or a styleguide framework of choice) for components reporting all cases. In fact, they are tests too 48 | - [ ] add snapshot testing to storybook (or a styleguide framework of choice) 49 | - [ ] add regression testing to storybook (or a styleguide framework of choice) 50 | - [ ] performance 51 | - [ ] always choose the "simplest"/fastest test. dom-ui-testing is faster then Puppeteer that's faster then Cypress etc. 52 | - [ ] UI test debugging (mark every single tip necessary/unnecessary with existing frameworks) 53 | - [ ] make screenshots 54 | - [ ] launch the browser in non-headless mode 55 | - [ ] launch the browser with the devtools already opened 56 | - [ ] slow down the browser actions 57 | - [ ] increase the test timeout 58 | - [ ] avoid closing the browser when the test ends 59 | - [ ] console.log the name of the test 60 | - [ ] frameworks 61 | - [ ] everything is async 62 | - [ ] dedicated ones vs generic ones 63 | - [ ] device emulation 64 | - [ ] cross browser support 65 | - [ ] custom extension installation 66 | - [ ] test management dedicated UI 67 | - [ ] running tests command log 68 | - [ ] hidden flags etc. 69 | - [ ] dedicated development browser 70 | - [ ] available plugins 71 | - [ ] generic browser automations 72 | - [ ] automatic dynamic waiting (like the cypress one) 73 | - [ ] snapshot management (like the cypress one) 74 | - [ ] dom-testing-library integration 75 | - [ ] automatic screenshot/video management 76 | - [ ] Puppeteer only: Node.js UI, make self-contained Node.js apps with a UI (thank to Carlo by Google) 77 | - [ ] automatic retry (cypress) 78 | - [ ] browser automation 79 | - [ ] common issues 80 | - [ ] promise everything 81 | - [ ] puppeteer evaluate 82 | - [ ] cypress then 83 | - [ ] ... ? 84 | - [ ] beginners 85 | - [ ] what is UI testing 86 | - [ ] why is it so important 87 | - [ ] headless browser 88 | - [ ] use it while studying 89 | - [ ] automate repetitive and annoying 90 | - [x] use testing frameworks as development tools 91 | - [ ] data scraping (take care that some sites will block you because of the high number of login requests etc.) 92 | - [ ] avoid regression 93 | - [ ] avoid manually testing 94 | - [ ] the other kind of tests 95 | - [ ] unit 96 | - [ ] integration 97 | - [ ] regression 98 | - [ ] snap shot testing 99 | - [ ] the testing pyramid (standard and the kent's one) 100 | - [ ] Always use the simplest kind of test 101 | - [ ] Why it's hard to do UI testing 102 | - [ ] you aren’t in isolation (like in Unit tests), nor in a super-mocked environment... 103 | - [ ] You have a real browser on a real network 104 | - [ ] Simulating the (exact) user behaviour sometimes could be very tricky 105 | - [ ] They can fail 106 | - [ ] They are slow 107 | - [ ] a11n? 108 | - [ ] take a look at every TODO in the various contents 109 | - [ ] link every section to each other 110 | - [ ] consider adding some links to a-z testing 111 | 112 | - take a look at https://slides.com/noriste/milano-frontend-ui-testing-best-practices to check if 113 | some contents are missing 114 | 115 | For contributors, write: 116 | - that a lot of missing content could be applied and you ask for contributors 117 | - that your English could need a check 118 | - that you'd like to hear from other experts, you have not years of experience with every tool 119 | - tool creators could help a lot, too 120 | -------------------------------------------------------------------------------- /sections/generic-best-practices/await-dont-sleep.md: -------------------------------------------------------------------------------- 1 | # Await, don't sleep 2 | 3 |

4 | 5 | ### One Paragraph Explainer 6 | 7 | When testing your UI, you define a sort of key points the app must pass through. Reaching these key 8 | points is an asynchronous process because, almost 100% of the times, your UI does not update 9 | synchronously. 10 | 11 | Those key points are called **deterministic events**, as known as something that you know that must happen. 12 | 13 | It depends on the events you define and how your UI reaches them but, usually, there are some 14 | "long" waitings, like XHR requests, and some faster ones, like re-render updates. 15 | 16 | The solution to the asynchronous updates seems handy: **sleeping/pausing the test** for a bunch of 17 | milliseconds, tenths of a second, or even seconds. It can make your test working because it gives 18 | the app the time to update itself and moving to the next deterministic event to be tested. 19 | 20 | Consider that, except for specific and known waitings (like when you use `setInterval` or 21 | `setTimeout`), **it's totally unpredictable** how much the sleeping time should be because it could depend on: 22 | - the network state (for XHR requests) 23 | - the total amount of available machine resources (CPU, RAM, etc.) 24 | - a CI pipeline can limit them for example 25 | - other apps can consume them on your local machine too 26 | - the concurrence of other resource-consuming updates (canvas, etc.) 27 | - a bunch of unpredictable game players like Service Workers, cache management etc. that can make 28 | the UI update process faster or slower 29 | 30 | Every fixed delay leads your test to be more brittle and **increasing its duration**. You are going to 31 | find a balance between false negatives—when the test fails because of a too low sleeping 32 | time—and exaggerate test duration. 33 | 34 | What about waiting just the right amount of time? The amount of time that makes the test as fast as 35 | possible! 36 | 37 | Waitings fall in four main categories 38 | - **[page load waitings](#page-load-waitings)**: the first waiting to manage while testing your app, waiting for an event that 39 | allows you to understand that the page is interactive 40 | - **[content waitings](#content-waitings)**: waiting for DOM element that matches a selector 41 | - **[XHR request waitings](#xhr-request-waitings)**: waiting for an XHR request start or the corresponding response received 42 | - **[custom waitings](#custom-waitings)**: waiting for everything strictly related to the app that does not fall into 43 | the above categories 44 | 45 | Every UI testing tool manages waitings in different ways, sometimes automatically and 46 | sometimes manually. Below you can find some examples 47 | of implementing the listed waitings. 48 | 49 | 50 |

51 | 52 | ## Page load waitings 53 | 54 | Every tool manages the page load waiting in a different way (in terms of what is waited before 55 | considering the page loaded). 56 | 57 | Cypress 58 | 59 | ```javascript 60 | cy.visit('http://localhost:3000') 61 | ``` 62 | 63 |
Puppeteer 64 | 65 | ```javascript 66 | await page.goto("http://localhost:3000"); 67 | ``` 68 |
69 | 70 |
Selenium 71 | 72 | ```javascript 73 | driver.get('http://localhost:3000'); 74 | driver.wait(function() { 75 | return driver.executeScript('return document.readyState').then(function(readyState) { 76 | return readyState === 'complete'; 77 | }); 78 | }); 79 | ``` 80 |
81 | 82 |
TestCafé 83 | 84 | ```javascript 85 | fixture `Page Load` 86 | .page `http://localhost:3000`; 87 | ``` 88 |
89 | 90 | 91 |

92 | 93 | ## Content waitings 94 | 95 | Take a look at the following examples to see how waiting for a DOM element could be implemented in 96 | the available tools. 97 | 98 | ### Code Examples 99 | Cypress 100 | 101 | - waiting for an element: 102 | ```javascript 103 | // it waits up to 4 seconds by default 104 | cy.get("#form-feedback") 105 | // the timeout can be customized 106 | cy.get("#form-feedback", {timeout: 5000}) 107 | ``` 108 | - waiting for an element with specific content 109 | ```javascript 110 | cy.get("#form-feedback").contains("Success") 111 | ``` 112 | 113 |
Puppeteer 114 | 115 | - waiting for an element: 116 | ```javascript 117 | // it waits up to 30 seconds by default 118 | await page.waitForSelector('#form-feedback'); 119 | // the timeout can be customized 120 | await page.waitForSelector('#form-feedback', {timeout: 5000}); 121 | ``` 122 | - waiting for an element with specific content 123 | ```javascript 124 | await page.waitForFunction(selector => { 125 | const el = document.querySelector(selector); 126 | return el && el.innerText === "Success"; 127 | }, {}, '#form-feedback'); 128 | ``` 129 | 130 |
131 | 132 |
Selenium 133 | 134 | - waiting for an element: 135 | ```javascript 136 | driver.wait(until.elementLocated(By.id('#form-feedback')), 4000); 137 | ``` 138 | - waiting for an element with specific content 139 | ```javascript 140 | const el = driver.wait(until.elementLocated(By.id('#form-feedback')), 4000); 141 | wait.until(ExpectedConditions.textToBePresentInElement(el, "Success")); 142 | ``` 143 |
144 | 145 |
TestCafé 146 | 147 | - waiting for an element: 148 | ```javascript 149 | // it waits up to 10 seconds by default 150 | await Selector('#form-feedback') 151 | // the timeout can be customized 152 | await Selector('#form-feedback').with({timeout: 4000}) 153 | ``` 154 | - waiting for an element with specific content 155 | ```javascript 156 | await Selector('#form-feedback').withText('Success') 157 | ``` 158 |
159 | 160 |
DOM Testing Library 1 161 | 162 | - waiting for an element: 163 | ```javascript 164 | await waitForElement(() => getByTestId('form-feedback')); 165 | ``` 166 | - waiting for an element with specific content 167 | ```javascript 168 | const container = await waitForElement(() => getByTestId('form-feedback')); 169 | await waitForElement(() => getByText('Success'), { container }); 170 | ``` 171 |
172 | 173 |

174 | 175 | ## XHR request waitings 176 | 177 | ### Code Examples 178 | 179 | Cypress 180 | 181 | - waiting for an XHR request/response 182 | ```javascript 183 | cy.server() 184 | cy.route("http://dummy.restapiexample.com/api/v1/employees").as('employees') 185 | cy.wait("@employees") 186 | .then(xhr => xhr.response.body) 187 | .then(body => {/* ... */}) 188 | ``` 189 | 190 | 191 |
Puppeteer 192 | 193 | - waiting for an XHR request 194 | ```javascript 195 | await page.waitForRequest('http://dummy.restapiexample.com/api/v1/employees'); 196 | ``` 197 | - waiting for an XHR response 198 | ```javascript 199 | const response = await page.waitForResponse('http://dummy.restapiexample.com/api/v1/employees'); 200 | const body = response.json(); 201 | ``` 202 |
203 | 204 |
205 | Even if it's a really important point, at the time of writing (May, 2019) it seems that waiting for XHR requests and responses is not so 206 | common. With exceptions for Cypress and Puppeteer, other tools/frameworks force you to look for 207 | something in the DOM that reflects the XHR result instead of looking for the XHR request itself. You can read more about th topic: 208 | 209 | - Selenium WebDriver: [5 Ways to Test AJAX Calls in Selenium WebDriver](https://www.blazemeter.com/blog/five-ways-to-test-ajax-calls-with-selenium-webdriver) 210 | - TestCafé: [Wait Mechanism for XHR and Fetch Requests](https://devexpress.github.io/testcafe/documentation/test-api/built-in-waiting-mechanisms.html#wait-mechanism-for-xhr-and-fetch-requests) 211 | - DOM Testing Library: [await API](https://testing-library.com/docs/dom-testing-library/api-async#wait) 212 | 213 |

214 | 215 | ## Custom waitings 216 | 217 | The various UI testing tools/frameworks have built-in solutions to perform a lot of checks, but let's 218 | concentrate on writing a custom waiting. Since UI testing is 100% asynchronous, a custom waiting 219 | should face recursive promises, a concept not so handy to manage at the beginning. 220 | 221 | Luckily, there are some handy solutions and plugins to help us with that. Consider if we want to 222 | wait until a global variable (`foo`) is assigned with a particular value (`bar`): below you are going to 223 | find some examples. 224 | 225 | ### Code Examples 226 | 227 | Cypress 228 | 229 | Thanks to the [cypress-wait-until plugin](https://github.com/NoriSte/cypress-wait-until) you can do: 230 | ```javascript 231 | cy.waitUntil(() => cy.window().then(win => win.foo === "bar")) 232 | ``` 233 | 234 | 235 |
Puppeteer 236 | 237 | ```javascript 238 | await page.waitForFunction('window.foo === "bar"'); 239 | ``` 240 |
241 | 242 |
Selenium 243 | 244 | ```javascript 245 | browser.executeAsyncScript(` 246 | window.setTimeout(function(){ 247 | if(window.foo === "bar") { 248 | arguments[arguments.length - 1](); 249 | } 250 | }, 300); 251 | `); 252 | ``` 253 |
254 | 255 |
TestCafé 256 | 257 | ```javascript 258 | const waiting = ClientFunction(() => window.foo === 'bar') 259 | await t.expect(waiting()).ok({ timeout: 5000 }) 260 | ``` 261 |
262 | 263 |
DOM Testing Library 1 264 | 265 | ```javascript 266 | await wait(() => global.foo === "bar"); 267 | ``` 268 |
269 | 270 | 271 |
272 | 1: unlike Cypress, Puppeteer, etc. DOM Testing Library is quite a different tool, that's why the examples are not available for every single part. 273 | 274 | [//]: <> (useful https://www.freecodecamp.org/news/how-to-write-reliable-browser-tests-using-selenium-and-node-js-c3fdafdca2a9/) 275 | [//]: <> (useful https://testcafe-discuss.devexpress.com/t/how-do-i-make-a-selector-wait-for-element-to-exist/569/2) 276 | -------------------------------------------------------------------------------- /sections/generic-best-practices/name-test-files-wisely.md: -------------------------------------------------------------------------------- 1 | # Name the test files wisely 2 | 3 |

4 | 5 | ### One Paragraph Explainer 6 | 7 | You can write a lot of different UI tests and it's a good habit to have a common way of naming the 8 | test files. 9 | 10 | It's useful because often you need to run just a type of tests, the situations could be: 11 | - during the development process, you need to run just some of them 12 | - you're changing some related components and you need to check that the generated markup does not change 13 | - you're changing a global CSS rule and you need to run only the visual tests 14 | - you're changing an app flow and you need to run the whole app integration tests 15 | - your DevOps colleague needs to be sure that everything is up and running and the easiest way to do 16 | that is launching just the E2E tests 17 | - your building pipeline needs to run just the integration and E2E tests 18 | - your monitoring pipeline needs a script to launch the E2E and monitoring tests 19 | 20 | If you name your tests wisely, it will be really easy to launch just some kind of them. 21 | 22 | Cypress: 23 | ```bash 24 | cypress run --spec \"cypress/integration/**/*.e2e.*\" 25 | ``` 26 | 27 | Jest: 28 | ```bash 29 | jest --testPathPattern=e2e\\.*$ 30 | ``` 31 | 32 |
33 | 34 | A global way to name the test files does not exist, a suggestion could be to name them with: 35 | - the subject you are testing 36 | - the kind of test (`integration`, `e2e`, `monitoring`, `component`, etc.) 37 | - the test suffix of choice (`test`, `spec`, etc.) 38 | - the file extension (`.js`, `.ts`, `.jsx`, `.tsx`, etc.) 39 | 40 | all of them separated by a period. 41 | 42 | Some examples could be 43 | - `authentication.e2e.test.ts` 44 | - `authentication.integration.test.ts` 45 | - `site.monitoring.test.js` 46 | - `login.component.test.tsx` 47 | etc. 48 | -------------------------------------------------------------------------------- /sections/generic-best-practices/use-your-testing-tool-as-your-primary-development-tool.md: -------------------------------------------------------------------------------- 1 | # Use your testing tool as your primary development tool 2 | 3 |

4 | 5 | ### One Paragraph Explainer 6 | 7 | An example speaks itself. Let's say you're developing an authentication form, probably, you: 8 | - code the username input field 9 | - **try it manually** in the browser 10 | - code the password input field 11 | - **try it manually** in the browser 12 | - code the submit button 13 | - code the XHR request management 14 | 15 | then, you can't go ahead because, without changing the source code, you need that a stubbed/mocked server responds to the app XHR requests. **Then you start writing an integration test** that: 16 | - fill the username input field 17 | - fill the password input field 18 | - click the submit button 19 | - check the XHR request 20 | - stub the XHR response 21 | - check the feedbacks 22 | - re-do it for every error flow 23 | - code the error flow management 24 | - re-check the tests 25 | 26 | Take a look at the first test steps, they are **the same we made manually** while coding the authentication form. Then, we stub the 27 | server responses and check the final behavior of the form (with success/failure responses). 28 | 29 | This working flow could be easily improved if we write the test alongside the form itself (TDD 30 | developers are already trained to do that): 31 | - **code the username input field** * 32 | - **write the test to fill** the username input field * 33 | - code the password input field 34 | - update the test to fill the password input field 35 | - code the submit button 36 | - update the test to click the submit button 37 | - stub the XHR response into the test 38 | - code the XHR request management 39 | - check the feedbacks 40 | - code the error flow management 41 | - update the test to check the error flow 42 | - re-do the above steps for every single error flow 43 | 44 | \* please note that the first and the second step could be inverted if you want to apply a strict TDD approach 45 | 46 | What are the most important advantages of doing that? 47 | - you **avoid (almost) completely manually testing** your app 48 | - you leverage the speed of your testing tool, it fills the form at a blazing speed and let you **save 49 | a lot of time** 50 | - you don't have to write the test after you coded the form (again, TDD developers already avoid it) 51 | that, only at the first approaches, could seem an annoying task 52 | - you completely **avoid putting some temporary states into your source code** (input field default 53 | values, fake XHR responses) 54 | - you test your app directly with a real network response (remember that your app does not know that 55 | the network request is stubbed by the testing tool) 56 | - the test is relaunched every time you save the test file 57 | 58 | One more question: how can I leverage the **existing Development Tools**?
59 | Well, you can do that in 60 | almost every testing tool but Cypress stands out for this kind of goal. Cypress has a dedicated 61 | Chrome user that's persisted across all your tests and all your projects. Doing so, Cypress allows 62 | you to have a real testing-dedicated browser with your favorite extensions, even if you use the 63 | same Chrome version you use to browse.
64 | Mix it with a great UI and you are ready to start developing all your app directly with Cypress. 65 | 66 | Below you can find some screenshot of the Cypress UI to show you how much easy is using it as a 67 | primary development tool. 68 | 69 |
70 | 71 | **Browser Selection** 72 | ![Cypress browser 73 | selection](../../assets/images/use-your-testing-tool-as-your-primary-development-tool/browser-selection.png 74 | "Cypress browser selection") 75 | 76 | **Browser DevTools** 77 | ![Cypress browser 78 | devtools](../../assets/images/use-your-testing-tool-as-your-primary-development-tool/devtools.png 79 | "Cypress browser devtools") 80 | 81 | **Cypress [Skip and Only UI plugin](https://github.com/bahmutov/cypress-skip-and-only-ui)** 82 | ![Cypress Skip and Only 83 | UI](../../assets/images/use-your-testing-tool-as-your-primary-development-tool/skip-and-only-ui.png 84 | "Cypress Skip and Only UI") 85 | 86 | **Cypress [Watch and Reload plugin](https://github.com/bahmutov/cypress-watch-and-reload)** 87 | 88 | 89 | If you want to see the React/Redux devtools in action with the Cypress controlled browser you can use the [cypress-react-devtools](https://github.com/NoriSte/cypress-react-devtools) repository. 90 | -------------------------------------------------------------------------------- /sections/server-communication-testing/monitoring-tests.md: -------------------------------------------------------------------------------- 1 | # Monitoring tests 2 | 3 |

4 | 5 | ### One Paragraph Explainer 6 | 7 | The more the front-end expectations grow, the more the server and services complexity grows. Front-end applications need to be faster every day: code splitting, lazy loading, brotli compression and a lot of other performance-oriented solutions became a standard during the last years. Not to cite some amazing solutions like code splitting and resources preloading based on machine learning and analytics data. More: JAMstack site generators are useful to avoid manually managing a lot of performance optimizations but their configuration and their build processes could break an **already tested feature**. 8 | 9 | There are a lot of features that we take for granted once tested that are not regression-free and that could lead to disasters. Some examples could be: 10 | - `sitemap.xml` and `robots.txt` crawling configurations (usually different for every environment) 11 | - Brotli/gzip served assets: a wrong content-encoding could break all the site functionalities 12 | - cache management with different configurations for static or dynamic assets 13 | 14 | They could seem obvious things but they are more subtle then what you think. If you care about the good user experience you should keep it monitored because it's usually too late when you discover that something did not work. You could not monitor everything, I know, but the more you test your applications, the more you leverage tests as your first quality checker. 15 | 16 | Monitoring tests could also be integrated with E2E ones (after all, they are super-simple E2E tests) but keeping them separated helps you running them-only if you need. Most of the above-cited things are DevOps-related and having super-fast monitoring tests allows you to have immediate and focused feedbacks. 17 | 18 |

19 | 20 | ## Cypress examples 21 | 22 | Cache monitoring tests 23 | 24 | ```javascript 25 | const urls = { 26 | staging: "https://staging.example.com", 27 | production: "https://example.com", 28 | } 29 | 30 | const shouldNotBeCached = (xhr) => cy.wrap(xhr).its("headers.cache-control").should("equal", "public,max-age=0,must-revalidate") 31 | const shouldBeCached = (xhr) => cy.wrap(xhr).its("headers.cache-control").should("equal", "public,max-age=31536000,immutable") 32 | // extract the main JS file from the source code of the page 33 | const getMainJsUrl = pageSource => "/app-56a3f6cb9e6156c82be6.js" 34 | 35 | context('Site monitoring', () => { 36 | context('The HTML should not be cached', () => { 37 | const test = url => 38 | cy.request(url) 39 | .then(shouldNotBeCached) 40 | 41 | it("staging", () => test(urls.staging)) 42 | it("production", () => test(urls.production)) 43 | }) 44 | 45 | context('The static assets should be cached', () => { 46 | const test = url => 47 | cy.request(url) 48 | .its("body") 49 | .then(getMainJsUrl) 50 | .then(appUrl => url+appUrl) 51 | .then(cy.request) 52 | .then(shouldBeCached) 53 | 54 | it('staging', () => test(urls.staging)) 55 | it('production', () => test(urls.production)) 56 | }) 57 | }) 58 | ``` 59 | 60 | Content encoding monitoring tests 61 | 62 | ```javascript 63 | context('The Brotli-compressed assets should be served with the correct content encoding', () => { 64 | const test = url => { 65 | cy.request(url) 66 | .its("body") 67 | .then(getMainJsUrl) 68 | .then(appUrl => cy.request({url: url + appUrl, headers: {"Accept-Encoding": "br"}}) 69 | .its("headers.content-encoding") 70 | .should("equal", "br")) 71 | } 72 | 73 | it('staging', () => test(urls.staging)) 74 | it('production', () => test(urls.production)) 75 | }) 76 | ``` 77 | 78 | Crawling monitoring tests 79 | ```javascript 80 | context('The robots.txt file should disallow the crawling of the staging site and allow the production one', () => { 81 | const test = (url, content) => 82 | cy.request(`${url}/robots.txt`) 83 | .its("body") 84 | .should("contain", content) 85 | 86 | it('staging', () => test(urls.staging, "Disallow: /")) 87 | it('production', () => test(urls.production, "Allow: /")) 88 | }) 89 | ``` 90 | -------------------------------------------------------------------------------- /sections/server-communication-testing/test-request-and-response-payload.md: -------------------------------------------------------------------------------- 1 | # Test the request and response payloads 2 | 3 |

4 | 5 | ### One Paragraph Explainer 6 | 7 | How many times the front-end application stops working because of a misaligned communication with the back-end? 8 | 9 | The front-end application and the back-end one have a contract, and you always need to test contract compliance. Every communication between the two apps is defined by: 10 | 11 | - its URL 12 | - the HTTP verb used (GET, POST, etc.) 13 | - the request payload and headers: the data that the front-end application sends to the back-end one 14 | - the response payload, headers, and status: the data that the bakc-end application sends back to the front-end one 15 | 16 | You need to test all of them and, more in general, you need to wait for every relevant AJAX request, why? 17 | 18 | - a relevant XHR request is part of the application flow that you're testing 19 | - if an XHR request is not part of the flow that you're testing, it could be relevant to reach the desired UI state 20 | - waiting for XHR requests make your test more robust, see the [Await, don't sleep](/sections/generic-best-practices/await-dont-sleep.md) chapter and its [XHR request waitings](/sections/generic-best-practices/await-dont-sleep.md#xhr-request-waitings) section 21 | 22 | Full XHR request waiting and inspection is not so common in the existing testing tools, Cypress provides the most complete inspection support at the moment. 23 | 24 |

25 | 26 | *Please note: all the following examples are for Cypress, it has the best XHR testing support at the moment.* 27 | 28 | ## Asserting about an XHR request, a complete example 29 | 30 | ```javascript 31 | // ask Cypress to intercept every XHR request made to a URL ending with `/authentication` 32 | cy.server(); 33 | cy.route("POST", "**/authentication").as("authentication-xhr"); 34 | 35 | // ... your test actions... 36 | 37 | cy.wait("@authentication-xhr").then(xhr => { 38 | // request headers assertion 39 | expect(xhr.request.headers).to.have.property("Content-Type", "application/json"); 40 | // request payload assertions 41 | expect(xhr.request.body).to.have.property("username", "admin"); 42 | expect(xhr.request.body).to.have.property("password", "asupersecretpassword"); 43 | // status assertion 44 | expect(xhr.status).to.equal(200); 45 | // response headers assertions 46 | expect(xhr.response.body).to.have.property("access-control-allow-origin", "*"); 47 | // response payload assertions 48 | expect(xhr.response.body).to.have.property("token"); 49 | }); 50 | ``` 51 | 52 | In the next sections, we are going to split the different characteristics of an XHR request. 53 | 54 | 55 | 56 | 57 | 58 |
Asserting about the XHR request URL 59 | 60 | With Cypress, the URL used for the request is defined with the `cy.route` call. You could need to inspect the query string of the URL. 61 | 62 | ```javascript 63 | // ask Cypress to intercept every XHR request made to a URL ending with `/authentication` 64 | cy.server(); 65 | // the GET method is implied 66 | cy.route("**/authentication**").as("authentication-xhr"); 67 | 68 | // ... your test actions... 69 | 70 | cy.wait("@authentication-xhr").then(xhr => { 71 | // query string assertion 72 | expect(xhr.url).to.contain("username=admin"); 73 | expect(xhr.url).to.contain("password=asupersecretpassword"); 74 | }); 75 | ``` 76 | 77 | Please note that the `then => expect` syntax of Cypress is helpful when you need to assert about multiple subjects (ex. both the URL and the status). If you need to assert about a single subject you could use more expressive `should` syntax 78 | 79 | ```javascript 80 | cy.wait("@authentication-xhr") 81 | .its("url") 82 | .should("contain", "username=admin") 83 | .and("contain", "password=asupersecretpassword"); 84 | ``` 85 |
86 | 87 | 88 | 89 | 90 | 91 |
The XHR request method 92 | 93 | With Cypress, the method used for the request is defined calling the `cy.route` function. You specify it to define what kind of request you want to intercept. 94 | 95 | ```javascript 96 | // the most compact `cy.route` call, the GET method is implied 97 | cy.route("**/authentication").as("authentication-xhr"); 98 | 99 | // method can be explicitly defined 100 | cy.route("POST", "**/authentication").as("authentication-xhr"); 101 | 102 | // the extended `cy.route` call is available too 103 | cy.route({ 104 | method: "POST", 105 | url: "**/authentication" 106 | }).as("authentication-xhr"); 107 | ``` 108 |
109 | 110 | 111 | 112 | 113 | 114 |
Asserting about the XHR request payload and headers 115 | 116 | Asserting about the request payload and headers allows you to have immediate and detailed feedback about the reason for a bad XHR request. They must be checked on every single XHR request to be sure that everything represents correctly the UI actions the test makes. 117 | 118 | ```javascript 119 | // ask Cypress to intercept every XHR request made to a URL ending with `/authentication` 120 | cy.server(); 121 | cy.route("POST", "**/authentication").as("authentication-xhr"); 122 | 123 | // ... your test actions... 124 | 125 | cy.wait("@authentication-xhr").then(xhr => { 126 | // request headers assertion 127 | expect(xhr.request.headers).to.have.property("Content-Type", "application/json"); 128 | // request payload assertions 129 | expect(xhr.request.body).to.have.property("username", "admin"); 130 | expect(xhr.request.body).to.have.property("password", "asupersecretpassword"); 131 | }); 132 | ``` 133 |
134 | 135 | 136 | 137 | 138 |
Asserting about the XHR response payload, headers, and status 139 | 140 | The response must adhere 100% to what the front-end application expects, otherwise, an unexpected state could be shown to the user. Response assertions are useful for full E2E tests, while they're useless in UI integration tests (TODO: link the integration test page). 141 | 142 | ```javascript 143 | // ask Cypress to intercept every XHR request made to a URL ending with `/authentication` 144 | cy.server(); 145 | cy.route("POST", "**/authentication").as("authentication-xhr"); 146 | 147 | // ... your test actions... 148 | 149 | cy.wait("@authentication-xhr").then(xhr => { 150 | // status assertions 151 | expect(xhr.status).to.equal(200); 152 | // response headers assertions 153 | expect(xhr.response.body).to.have.property("access-control-allow-origin", "*"); 154 | // response payload assertions 155 | expect(xhr.response.body).to.have.property("token"); 156 | }); 157 | ``` 158 |
159 | -------------------------------------------------------------------------------- /sections/template.md: -------------------------------------------------------------------------------- 1 | # Title here 2 | 3 |

4 | 5 | ### One Paragraph Explainer 6 | 7 | Text 8 | 9 |

10 | 11 | ### Code Example – explanation 12 | 13 | ```javascript 14 | code here 15 | ``` 16 | 17 |

18 | 19 | ### Code Example – another 20 | 21 | ```javascript 22 | code here 23 | ``` 24 | 25 |

26 | 27 | ### Blog Quote: "Title" 28 | 29 | From the blog, pouchdb.com ranked 11 for the keywords “Node Promises” 30 | 31 | > …text here 32 | 33 |

34 | 35 | ### Example: Complex methods analysis with CodeClimate (commercial) 36 | 37 | ![alt text](https://github.com/i0natan/nodebestpractices/blob/master/assets/images/codeanalysis-climate-complex-methods.PNG "Complex methods analysis") 38 | 39 | ### Example: Code analysis trends and history with CodeClimate (commercial) 40 | 41 | ![alt text](https://github.com/i0natan/nodebestpractices/blob/master/assets/images/codeanalysis-climate-history.PNG "Code analysis history") 42 | 43 | ### Example: Code analysis summary and trends with SonarQube (commercial) 44 | 45 | ![alt text](https://github.com/i0natan/nodebestpractices/blob/master/assets/images/codeanalysis-sonarqube-dashboard.PNG "Code analysis history") 46 | 47 | 48 |

49 | -------------------------------------------------------------------------------- /sections/testing-strategy/avoid-perfectionism.md: -------------------------------------------------------------------------------- 1 | # In the beginning, avoid perfectionism 2 | 3 |
4 | 5 | ### One Paragraph Explainer 6 | 7 | Testing really changes the way you work but, like everything, it requires a bit of experience to get the best of it. In the beginning, avoid perfectionism at all. Why? 8 | 9 | - tests are little programs after all. Perfectionism could drive you to write **extremely complex tests** before knowing how to manage the different testing contexts. 10 | 11 | Tests complexity is a big enemy because debugging a failing test is harder than debugging a failing application. And complex tests make you lose the advantage of testing practices themselves, make you lose a lot of time, and inevitably make you exclude them sooner or later. **If it happens to you don't give up**, it's the same for a lot of testing beginners (it was the same for me, that's why I started writing this repo 😊) and do not be afraid of asking your colleagues or publicly to other developers. 12 | 13 | - false negatives: perfectionism-driven tests lead to a lot of false negatives. A false negative is a situation where your application works as expected but the test fails. 14 | 15 | **False negatives are really de-motivating** at the beginning because you started writing tests to have an ally in checking the application status... But you ended up with another application to maintain with no help from the tests. If you realize you are fighting with false negatives, stop yourself, restart studying and ask for help! 16 | 17 | - tests utility: successful tests drive you directly to the problem when they fail. The right assertions and [deterministic events](/sections/generic-best-practices/await-dont-sleep.md) make your tests robust and, super important, useful if they fail. At the opposite, too much assertions/checks could make your tests brittle because of their uselessness 18 | 19 | What do you mean for perfectionism? I mean checking every front-end detail. Your working experience allows you to write complex user interactions but, in the beginning, your limited testing experience do not allow you to test all of the interactions profitably. Start testing the easiest things like 20 | - is my page loading correctly? 21 | - do the menu buttons works? 22 | - can the user fill the form and reach the thank you page? 23 | 24 | and forget, in the beginning, to test things like 25 | - conditional data loading 26 | - complex form rules 27 | - uncontrolled (third party) integrations 28 | - element selectors 29 | 30 |
31 | 32 | A beginning todo list to avoid falling into the perfectionism trap could be: 33 | 34 | - choose the simplest thing to test (something that's useful for the users) 35 | - think about it from the users perspective. Remember that the users care about contents and functionalities, not about selectors and internal application states 36 | - write your test 37 | - run it more than once to be sure that it's stable 38 | - when it succeeds, insert a bug into the front-end app that breaks it and checks that the test fails. Then, remove your made-on-purpose bug 39 | - run the test both in headless and non-headless mode 40 | - think about, based on your experience (ask your colleagues too), what are the reasons that could break the front-end application from the perspective of what you're testing 41 | - simulate the different front-end failures (kill the server, insert other bugs) and check if the test gives you enough feedback to understand what failed 42 | - do that for just two or three kinds of failures, remember that your limited experience could drive you to test the wrong things 43 | - then, move to another thing to test and repeat all the previous steps 44 | 45 | Software testing is an amazing journey and the goal of this repo is helping you avoid the most common pitfalls. 46 | 47 | The suggested flow is just one of the possible approaches. I know that everything is subjective and please, open a PR for every suggestion! 48 | -------------------------------------------------------------------------------- /sections/testing-strategy/choose-a-reference-browser.md: -------------------------------------------------------------------------------- 1 | # Choose a reference browser 2 | 3 |
4 | 5 | ### One Paragraph Explainer 6 | 7 | Everyone cares about cross-browser testing. We are used to manually testing everything on every browser because, we know, there are a lot of browser differences. Obviously, we'd like to have the same cross-browser support from the tool we use to test our front-end application... But the reality is that cross-browser support is very limited. 8 | 9 | The next table reports the cross-browser support for the major testing/automation tools. 10 | 11 | | Tool | Chrome | Firefox | IE11 | Edge | Safari | iOS Safari | Android Chrome | 12 | |------------|--------|---------|------|------|--------|------------|----------------| 13 | | [Cypress](https://www.cypress.io) | ✅ | ⌛[1](#footnote1) | ⌛️[1](#footnote1) | ⌛️[1](#footnote1) | ⌛ | ⌛️[1](#footnote1) | ⌛️[1](#footnote1) | 14 | | [TestCafé](https://testcafe.devexpress.com) | ✅ | ✅️ | ✅ | ✅ | ✅ | ✅️ | ✅️ | 15 | | [Puppeteer](https://pptr.dev) | ✅ | ⌛[2](#footnote2) | ⬜️ | ⬜️ | ⬜ | ⬜️ | ⬜️ | 16 | | [Selenium](https://www.seleniumhq.org) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅️[3](#footnote3) | ✅[3](#footnote3) | 17 | 18 |
19 | Anyway: don't take for granted that testing everything on every browser is always the best solution. Try to think about what you need to test before choosing a testing tool. Think that: 20 | 21 | - both **Selenium and Puppeteer are generic automation tools**. They can be used as testing tools (there are a lot of plugins and modules that help you do that) but they are not created with testing in mind so they miss some integrated utilities that could simplify your life as a test writer 22 | - consider only **Cypress and TestCafé** because they are both tools created to **simplify the UI testing process**. Half of the best practices you should care in your tests are automatically managed by Cypress/TestCafé out of the box. Choosing the right testing tool is all about finding the right trade-off. UI testing is hard by definition so, spend some time experimenting with both Cypress and TestCafé 23 | - think about what you need to test. Choose [TestCafé](https://testcafe.devexpress.com) if you need to test a particular mobile capability, but if you need to test that the forms and the buttons work you are less limited with your choice 24 | - take a look at the [Cypress Test Runner](https://docs.cypress.io/guides/core-concepts/test-runner.html#Command-Log), it's what makes Cypress outstanding and it's a precious ally during test development 25 | - cross-browser testing is usually related to visual testing (CSS browser differences) but this is not related to functional testing. Visual testing is made easy by a lot of dedicated plugins and tools. Take a look at [Applitools](https://applitools.com) and [Percy](https://percy.io), both can be integrated seamlessly in every testing tool and they work by uploading a snapshot of the page under test into their servers and render them 26 | 27 | You can take a sneak peek at some differences between the various testing tools into the [Await, don't sleep](/sections/generic-best-practices/await-dont-sleep.md) chapter. 28 | 29 |
30 | 31 | 1: crossbrowser support [is on the Cypress roadmap](https://github.com/cypress-io/cypress/issues/310) 32 |
33 | 2: Firefox support for Puppeteer [is not complete yet](https://aslushnikov.github.io/ispuppeteerfirefoxready/) 34 |
35 | 3: Selenium supports mobile browser through [Appium](http://appium.io/docs/en/writing-running-appium/web/mobile-web/) 36 | -------------------------------------------------------------------------------- /sections/testing-strategy/component-vs-integration-vs-e2e-testing.md: -------------------------------------------------------------------------------- 1 | # Component vs (UI) Integration vs E2E tests 2 | 3 |
4 | 5 | ### One Paragraph Explainer 6 | 7 | Speaking about UI Testing (remember that we are speaking about the UI only, not the underlying JavaScript code), there are three main test types: 8 | - **Component tests**: the unit tests of a UI, they test every single component in an isolated environment. 9 | 10 | Developing components in isolation is important because it allows you to isolate them from the corresponding container/use. A component exists to isolate a single behavior/content (the [Single responsibility principle](https://www.wikiwand.com/en/Single_responsibility_principle)) and therefore, coding it in isolation is profitable. 11 | 12 | There are many ways and tools to develop components in isolation but [Storybook](https://storybook.js.org) became the standard choice because of its effectiveness and its ecosystem. 13 | 14 | Components have three types of contracts: the generated output (**HTML**), their visual aspect (**CSS**), and the external APIs (**props and callbacks**). Testing every aspect could be cumbersome, that's where [Storyshots](https://www.npmjs.com/package/@storybook/addon-storyshots) comes in handy. It allows you to automate: 15 | - **the snapshot tests**: a snapshot is an output generated by your component, a string containing all the rendered HTML. If the generated HTML changes, accidentally or not, the snapshot tests fail and you can choose if the changes were intentional or not. 16 | - **the visual regression tests**: the visual aspect of the component compared **pixel by pixel** with the previous one, again, you are prompted to choose if you accept the changes or not. 17 | 18 | These tests are launched by [Storyshots](https://www.npmjs.com/package/@storybook/addon-storyshots) automatically on every Storybook page (AKA "stories"). 19 | - **the callback tests**: a small React container app renders the component passing it some callbacks. Then, the user interactions are simulated and passed the callback is expected to be called. [React Testing Library](https://testing-library.com/docs/react-testing-library/) is the standard library of choice for this kind of tests 20 | - **the interaction/state tests**: some interactions with a component expect correct state management. This kind of test must be written from the consumer point of view, not from the inner one (ex. the value of the input field when the user fills it, not the inner component state). An interaction/state test should assert the input field value after the keyboard events triggered. 21 | 22 | 23 | - **UI Integration tests**: they run the whole app in a real browser **without hitting a real server**. These tests are the ace in the hole of every front-end developer. They are blazing fast and less exposed to random failures or false negatives. 24 | 25 | The front-end application does not know that there is not a real server: every AJAX call is resolved in no time by the testing tool. Static JSON responses (called "fixtures") are used to simulate the server responses. Fixtures allow us to test the front-end state simulating every possible back-end state. 26 | 27 | Another interesting effect: Fixtures **allow you to work without a working back-end** application. You can think about UI Integration tests as "front-end-only tests". 28 | 29 | At the core of the most successful test suites, there is a lot of UI Integration tests, considering the best type of test for your front-end app. 30 | 31 | - **End-to-end (E2E) tests**: they run the whole app interacting with the real server. From the user interactions (one of the "end") to the business data (the other "end"): everything must work as designed. E2E tests are typically slow because 32 | - they need a **working back-end** application, typically launched alongside the front-end application. You can't launch them without a server, so you depend on the back-end developers to work 33 | - they need **reliable data**, seeding and cleaning it before every test 34 | 35 | That's why E2E tests are not feasible to be used as the only/main test type. They are pretty important because they are testing everything (front-end + back-end) but they must be used carefully to avoid brittle and hour-long test suites. 36 | 37 | In a complete suite with a lot of UI Integration tests, you can think about E2E tests as "back-end tests". What flows should you test through them? 38 | - the Happy Path flows: you need to be sure that, at least, the users are able to complete the basic operations 39 | - everything valuable for your business: happy path or not, test whatever your business cares about (prioritizing them, obviously) 40 | - everything that breaks often: weak areas of the system must be monitored too 41 | 42 | Identifying/defining the type of test is useful to group them, to [name the test files]((/sections/generic-best-practices/name-test-files-wisely.md)), to limit their scope, and to choose where to run them or not though the whole application and deployment pipelines. 43 | -------------------------------------------------------------------------------- /sections/testing-strategy/write-test-then-fix-bug.md: -------------------------------------------------------------------------------- 1 | # Found a bug? Write the test, then fix it 2 | 3 |
4 | 5 | ### One Paragraph Explainer 6 | 7 | So, you have found a bug in your front-end application and you have already debugged it. You can reproduce it systematically and you're ready to fix it. A testing-oriented mind must pass through these steps: 8 | - identify the expected behavior 9 | - write a test that aims to consume the front-end application the correct way 10 | - the test must fail, obviously, because the bug does not allow the user to perform his task 11 | - fix the bug 12 | - check that the test now passes 13 | 14 | What are the advantages of this approach? Why should you write a test? I know that fixing the bug without a test could seem faster but consider that: 15 | - as usual, your testing tool is faster than you to reach the state of the application that shows the bug (see the [Use your testing tool as your primary development tool](/sections/generic-best-practices/use-your-testing-tool-as-your-primary-development-tool.md) chapter) 16 | - sometimes you think that you're able to reproduce the bug systematically, but it's not always true. Writing a test that unearths the bug make you 100% sure that the bug is reproducible **excluding a lot of deviant variables** like existing sessions, caches, service workers, browser extensions, browser version, etc. that could influence your confidence. Sometimes you discover that you did not identify the bug correctly 17 | - at the same time, when the test passes thanks to your fix, you are really sure that your solution works as expected. The same variables that could influence your bug identification process could mine the false sense of the job's effectiveness 18 | - w**ith a test, the bug is fixed forever!** The test will be run thousands of times and let you sleep well about that forever 19 | - a successful test could be used as a proven track of the work you've done 20 | 21 | Last but not least: be sure that the test you write fails at the beginning! And that it fails because of the bug! The test is not useful only to reproduce the bug and check it visually, but it must put you in the position of having positive feedback after the bug fixing process. **A bug-related test that does not fail is really dangerous** because you can think that you've made a good job when the reality is that you have not reproduced the bug correctly since the beginning. As a general rule: a broken flow must have a broken test, a successful test must be related to a working app. 22 | --------------------------------------------------------------------------------