Skip to content

NoriSte/ui-testing-best-practices

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ‡¬πŸ‡§ English version | πŸ‡¨πŸ‡³ δΈ­ζ–‡ (Chinese version)

UI Testing Best Practices

UI testing Best Practices


26 items Last update: June, 2023

Follow us on Twitter!:


Built and maintained by our Steering Committee and Collaborators

Table of Contents

  1. Testing strategies (5)
  2. Generic Best Practices (6)
  3. Server Communication Testing (3)
  4. Beginners (1)
  5. Generic testing perks (1)
  6. Tools (2)
  7. Advanced (5)
  8. Real Life Examples (2)
  9. Obsolete chapters (3)



1. Testing strategies

βœ” 1.1 Component tests vs (UI) Integration tests vs E2E tests

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.

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.

πŸ”— Read More: Component vs (UI) Integration vs E2E tests


βœ” 1.2 In the beginning, avoid perfectionism

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.

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.

πŸ”— Read More: In the beginning, avoid perfectionism


βœ” 1.3 Choose a reference browser

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.

Otherwise: You could choose the wrong testing tool based on the cross-browser support.

πŸ”— Read More: Choose a reference browser


βœ” 1.4 Found a bug? Write the test, then fix it

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.

Otherwise: You could not identify correctly the bug and you can not be sure that the bug will not present again in the future.

πŸ”— Read More: Found a bug? Write the test, then fix it


βœ” 1.5 One long E2E test or small, independent ones?

TL;DR: When dealing with E2E tests and their difficulties, opting for a lot of small and independent tests or for a long one is not an obvious choice. Either the solutions have pros and cons, deriving from the inner complexity of the E2E tests where you deal with a real back-end and real data.

Otherwise: You could create hard-to-maintain E2E tests.

πŸ”— Read More: One long E2E test or small, independent ones?



2. Generic Best Practices

βœ” 2.1 Await, don't sleep

TL;DR: When testing your UI, you define a sort of key points the app must pass through. Reaching these key points is an asynchronous process because, almost 100% of the times, your UI does not update synchronously. Those key points are called deterministic events, as known as something that you know that must happen. You need to wait for these events to make your tests robust.

Otherwise: Sleeping the tests make your tests slow and brittle, it's one of the most common and biggest errors in UI testing.

πŸ”— Read More: Await, don't sleep


βœ” 2.2 Name your test files wisely

TL;DR: Lot of times you need to launch just a type of tests and it's super easy if you follow a common pattern while naming your testing files.

Otherwise: You need to launch a long test suite just to have some of them run.

πŸ”— Read More: Name the test files wisely


βœ” 2.3 UI Tests Debugging Best Practices

TL;DR: Debugging a UI test could be really hard, especially if you use generic browser automation tools. Here is a list of simple rules that are at the base of the debugging process.

Otherwise: You are going to waste a lot of time without taming the exponential complexity of a UI test.

πŸ”— Read More: UI Tests Debugging Best Practices


βœ” 2.4 Reaching UI state for tests without using the UI

TL;DR: As a developer who wants to ensure quality, it is important to think about cost of tests vs the value they provide. Where reasonable, strive to not duplicate effort, and still get high value by considering alternatives for setting up state for a test.

πŸ”— Read More: Reaching UI state


βœ” 2.5 Use your testing tool as your primary development tool

TL;DR: Leveraging your testing tool to avoid manual tests is one of the biggest improvements you could do to speed up your working flow. Testing tools are faster than you and the most modern ones include some UI utilities that make easy to use them as a development tool.

Otherwise: You code the app the old way, losing a lot of time interacting manually with the UI itself.

πŸ”— Read More: Use your testing tool as your primary development tool


βœ” 2.6 Keep abstraction low to ease debugging the tests

TL;DR: Tests should be written with readability and debuggability in mind. Abstraction may be good in some instances, but it always incurs a cost in debuggability and therefore sometimes may not be worth it. This is especially important for UI tests; consequent of the complex stack, it can get harder to understand the real source of failures. Reducing abstraction for the sake of easier debugging is key for future proofing the test code.

Otherwise: There is a balance between abstraction and debuggability; the higher the abstraction, the harder it is going to be to debug the tests in the future.

πŸ”— Read More: Keep abstraction low to ease debugging the tests



3. Server Communication Testing

βœ” 3.1 Test the request and response payloads

TL;DR: The UI communicates continuously with the back-end, and usually every communication is critical. A bad request or a bad 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.

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.

πŸ”— Read More: Test the request and response payloads


βœ” 3.2 Test the server schema

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 TypeScript types, the ElasticSearch mapping, the Pact contract, 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.

Otherwise: You could miss some back-end change and your front-end application could break inadvertently.


βœ” 3.3 Monitoring tests

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.

Otherwise: You mix tech-details tests with the user-oriented ones.

πŸ”— Read More: Monitoring tests



4. Beginners

βœ” 4.1 Approach the testing pyramid from the top!

TL;DR: Approaching the testing world could be inefficient and not satisfactory. You start writing some unit tests but you are left with a lot of doubts. UI Testing allows you to start with a high confidence since the very first day.

Otherwise: The wrong approach could condition the way you think about testing and could leave you with the false idea of testing the right way when the truth is you're testing nothing.

πŸ”— Read More: Approach the testing pyramid from the top!



5. Generic testing perks

βœ” 5.1 Software tests as a documentation tool

TL;DR: Tests are a good way to have a concise, code-coupled, and updated documentation. Good storytelling test descriptions could make the comprehension of a codebase or a new project very simple.

Otherwise: You rely on the code documentation or, worse, on the readability of the code to comprehend that the code does.

πŸ”— Read More: Software tests as a documentation tool



6. Tools

βœ” 6.1 Some UI testing problems and the Cypress way

TL;DR: Why is testing a web application so hard? Why generic browser automation tools do not fit well the UI/E2E testing needs? Why does Cypress outstand?

Otherwise: A generic features comparison is not enough to understand what are the main UI Testing pains and how Cypress removes them.

πŸ”— Read More: Some UI testing problems and the Cypress way



βœ” 6.2 Visual Regression Testing

TL;DR: Visual regression tests hard and why we should rely on premium services.

Otherwise: Another continuous chore for regressions we do not care about. Possibility of missing out visual differences.

πŸ”— Read More: Visual Regression Testing



7. Advanced

βœ” 7.1 Test States

TL;DR: Tests should be repeatable, modular and should handle their own state setup. UI Tests should not be repeated in order to achieve state for another test.

πŸ”— Read More: Test States


βœ” 7.2 Test Flake

TL;DR: Tests must produce consistent results every time. Repeatable pipeline execution results are the quorum. If a test cannot produce reliable results, it reduces confidence in the tests and requires maintenance which reduces all value. In these cases it is best to manually test the functionality.

πŸ”— Read More: Test Flake


βœ” 7.3 Combinatorial Testing

TL;DR: Most software bugs and failures are caused by one or two parameters. Testing parameter combinations can provide more efficient fault detection than conventional methods. Combinatorial Testing is a proven method for more effective software testing at a lower cost.

πŸ”— Read More: Combinatorial Testing


βœ” 7.4 Performance Testing

TL;DR: Although this is a vast topic, Performance testing from a web development perspective can be simplified with modern tools and understanding. It is highly effective in ensuring user experience, satisfying non-functional requirements (NFRS), and detecting possible system-flake early on.

πŸ”— Read More: Performance Testing


βœ” 7.5 Email Testing

TL;DR: Email testing is critical for business success. Modern services not only allow automated email testing but also provide a stateless, scalable solution while testing SaaS applications.

πŸ”— Read More: Email Testing



8. Real Life Examples

βœ” 8.1 Siemens - Test the front-end with the integration tests, the back-end with the E2E ones - in reference to Component vs Integration vs E2e Testing

TL;DR: UI tests with a stubbed server are reliable and faster compared to full E2E tests. Full E2E tests are not always necessary to ensure front-end quality. We can instead have high confidence in front-end quality by using lower-cost UI integration tests and saving higher cost E2E tests for the back-end.

Otherwise: You waste time and resources with slow and brittle E2E tests while you can get a lot of confidence with a lot of UI integrations tests.

πŸ”— Read More: Test the front-end with the integration tests, the back-end with the E2E ones


βœ” 8.2 WorkWave - From unreadable React Component Tests to simple, stupid ones

TL;DR: The test's code must be as straightforward as possible. The benefit is to save a lot of time to understand, update, refactor, fix it when needed. At the opposite, a terrible scenario happens when you are not able to read some tests, even if you are the author! Here are reported some examples explaining why the test's code is hard, and how they have been refactored.

Otherwise: You waste a lot of time reading and understanding the tests when you have to update or fix them.

πŸ”— Read More: From unreadable React Component Tests to simple, stupid ones



9. Obsolete chapters

Unit Testing React components with Cypress

This section is now marked as obsolete because it refers to a very old version of Cypress (that now fully supports component tests).

TL;DR: Cypress v4.5.0 release allowed Unit Testing React components, an external tool like Storybook is not necessary anymore to test isolated components.

πŸ”— Read More: Unit Testing React components with Cypress.


@daedalius's approach: Exposing components from Storybook separating stories from tests

This section is now marked as obsolete because it refers to a very old version of Cypress and Storybook (either of them now fully support component tests).

TL;DR: You may expose the component reference from Storybook Story to test it whatever you wish in Cypress without breaking testing logic into pieces.

Otherwise: Splitted test logic and test data will make it difficult to read and support.

πŸ”— Read More: Cypress + Storybook. Keeping test scenario, data and component rendering in one place.

@NoriSte's approach: Testing a component with Cypress and Storybook

This section is now marked as obsolete because it refers to a very old version of Cypress and Storybook (either of them now fully support component tests).

TL;DR: Components ar the building blocks of your app, testing them in isolation is important to discover, as soon as possible, iof there is something wrong with them.

Otherwise: UI Tests without lower-level tests do not allow you to understand the source of the problem.

πŸ”— Read More: Testing a component with Cypress and Storybook



Steering Committee

Meet the steering committee members - the people who work together to provide guidance and future direction to the project.

Stefano Magni GitHub

Passionate, positive-minded / Front-end Tech Leader (platform) Hasura / Speaker / Instructor / Remote worker.



Murat Ozcan GitHub

Tech enthusiast in love with testing, development, devops, web and cloud. Staff eng / Test architect at Extend.



Thank You Notes

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.

Stars

An approved new best practice Be the first to collect a ⭐, contribute to this repository 😁

⭐ Murat Ozcan ⭐ Dmitriy Tishin ⭐ Nao

Flowers

A successfull PR gives you a 🌻, be the first to collect it.

🌻 Anoop Kumar Gupta 🌻 Ferdinando Santacroce 🌻 Luca Piazzoni 🌻 Luca Previtali 🌻 Luca Previtali 🌻 Filip Hric




This repository is inspired by the nodebestpractices one, thank you Yoni and the whole steering team to keep it updated and to allow the creation of this repository.