Yes, we do need to test our UI components but... If this rings a bell, and especially if your application has advanced UI functionality, this talk is for you.In this talk, we will cover what are the factors that need to be tested in UI components. We will challenge the testing pyramid when it comes to UI Components testing, and review the different tools that we have nowadays for making UI component testing complete Zen.
Zen and the Art of UI Components Testing
AI Generated Video Summary
The Talk discusses the evolution of test automation from the original test automation pyramid to the testing pyramid. It explores modern approaches to UI component testing, including isolations and testing with a fake DOM. The importance of testing in a real browser and the emergence of tools like Selenium, WebDriver.io, Puppeteer, Cypress, and PlayWrite for browser automation are highlighted. The advantages of out-of-process browser automation are explained, along with the use of Storybook and Playwright for testing components. The distinction between end-to-end testing and component testing is also mentioned.
1. Introduction to Test Automation Pyramid
In 1990, testing was not taught in programming boot camps. A book published by Mycom introduced the original test automation pyramid with three levels: unit, service, and UI. Over time, it evolved into the testing pyramid, with unit tests, integration tests, and end-to-end tests.
A short walk down memory lane. This is me. Here I just graduated my programming boot which was in the Israeli Army, the Mammran boot camp. We learned a lot of things. The one thing we did not learn is testing. And this is because the year is 1990. And this is the very same year that this book was published by Mycom. And it's talking about succeeding with Agile. And if you dive into this book, you would find this diagram. This is the original test automation pyramid. It talks about three levels. Unit, service, and UI. And you notice that the UI is at the top. Later on, this is evolved into the testing pyramid, which we all know. And the name changed. We still talk about unit test. But we also talk about integration. And the UI test has become end to end test. And this is actually true, because this is what happened for many years. We would see end to end test as a synonym for UI tests.
2. Modern Approaches to UI Component Testing
I want to talk about modern approaches to UI component testing. The first principle is isolations. Components let you split the UI into independent and reusable pieces. You can think about each piece in isolation, build it in isolation, and test it in isolation.
My name is Tali Barak. I work for a company called Ubiq. And I want to talk about modern approaches to UI component testing, and I call this talk Zen and the Art of UI Component Testing. And soon, we will see what is the Zen and how we can achieve it.
And the first thing, the first principle, is I want to talk about isolations. This is a page, what a web page, a web application looked like back in the 1990s. As you can see, it is quite simple and it is just one page. But then, later on, and we're talking here about 2015, sort of like, we started working in a complete different way when building our web application. We started talking about components.
This is AngularJS, as I said, in December 2015. They are talking about understanding components when you develop an Angular application. And this is from June 2016. This is the actual commit that was made into the React readme. And it started talking also about what it means to be component based. It talks about building encapsulated components that manage their own state and then compose them into more complex UIs. And we still look at components as sort of lego bricks. You have a separate component exhibit. Each one with its own functionality and then you go and you build them into larger UI such as ships, houses, or even a search engine rack server that was built from lego.
Today when we talk about the modern framework for building UI such as Angular React, Vue, Solid, Svelte, etc., they are all built on the principle of component-based. And this is what components let you do. They let you to split the UI into independent and reusable pieces and you can think about each piece in isolation. And when you say think, it's not just about thinking, it's also about building it in isolation and testing it in isolation. In this example here, we can see this is a CodeWe app, a demo app that is built in multiple languages and frameworks. You can just find almost any framework you would like. And you can see here that it is actually using the same component of an article preview both on the global feed and on the MyPost. And this actually implies that if I want to test the functionality of this component, I don't need to go to the specific page of the global feed as I would do in end-to-end test or to login and go into MyPost as I would do in the MyPost page. I can actually isolate this component, put it on separately. And such as we see here, this is the same component, but the page only shows this component. This is using Storybook. Storybook is a great tool for demoing and showing and showcasing components in isolation.
3. Testing UI Components with a Fake DOM
I can test my component in isolation. When testing UI components, we use tools like Jest or V-test, which work with a fake DOM. This fake DOM is created using engines like Node.js, but it doesn't fully replicate the browser's behavior. Therefore, when testing components, it feels like playing a guessing game, as we can't see the actual visual side. We rely on tools like enzyme or testing library to assist us.
I can see here this is from the same application. I took the editor component. This is when I want to compose an article. And you can see on the same Storybook, I have this component in isolation. And once I have this component, this is zooming in into the component, I can actually test that it works correctly, regardless of which page it is put on. So I can check here that I have my likes, that I can click on them. I can check that the read is actually the reference to the correct URL. I can test here that I'm showing the correct tags, that they are in the right order if there is a specific rule for the order and so on. So point number one is I can test my component in isolation.
4. UI Component Testing and Browser Automation
When working with advanced UI components, it can be challenging to mock APIs and create a fake DOM that accurately simulates a browser. Testing in a real browser is essential to ensure proper rendering, CSS functionality, and interaction testing. Over the years, various tools have emerged to support browser automation, including Selenium, WebDriver.io, Puppeteer, Cypress, and PlayWrite. Testing in a real browser and achieving efficiency are two key goals in component testing.
And especially when we are working with advanced UI components, UI components that have things like advanced media that have canvases and graphs that is being animated. And we have a lot of micro-interactions and we also have a lot of gestures that we need to support, such as drag and drop or zooming and so on. This is where the mocking of the APIs are played really short. And it's sometimes very hard and you're just trying to make your fake DOM, fake browser work like a browser and you invest a lot of time and it's really frustrating in the test.
Because at the end of the day, it's very simple. When we have UI components, we want to test them in real browser. And this means that it will really render our component. We are not just going to test that we have the right CSS class, but we also want to test that the CSS is building our component correctly and it's actually correctly visualized. We want to talk about network call that is sometimes different when we are working with browser. We want to test the interaction, all the gestures that I mentioned, and also proper timing. When we are working with a mock, it usually does not conform to the timing that the browser really has, or pseudo event and so on. If there are side effects, again, pseudo event is one example, like input change and so on, we want to make sure that it's really triggered correctly, and not us manually triggering, and at the end of the day we might want to actually look at the component and screenshot it and do a visual regression test and make sure that it looks just like we expected it to look.
And over the years, there are a lot of tools that are supporting this kind of browser automation. They usually are a synonym of end-to-end tests, again from this approach, it's saying UI is only being tested in end-to-end. We have Selenium for 20 years now, we have WebDriver.io which is very popular. These are not the only ones. And recently, in the last few years, we have more modern tools like Puppeteer and Cypress, and just probably the latest and greatest addition is PlayWrite together with the newer version of Selenium. And we will discuss how they are different.
5. Out-of-Process Browser Automation
The second generation is those fake browsers that I talked about, which are still popular, which basically say we don't have any of this, we are just writing in Node some of the test that we want. And the more modern approach is to have, what we call, an out-of-process automation. All of this part of the browser is actually accessible via APIs. It started as a Chrome developer protocol. And we write an external program that is actually controlling all of these part. This was initiated with Puppeteer in Google. This is what they did as a generic tool that is written in Node.js and it's controlling our browser through this protocol. And later on, the same team that was building Puppeteer in Google has moved to Microsoft and built Playwright. And they extended this protocol, not just for generic browser automation, but actually focusing on what is available, what is required for testing, such as if we have animation, we want to wait until it stabilizes and only then I want to click the button. A lot of the problems existed with all tools like Selenium.
So, saying all of that, what does that mean for our ZenUI component testing? This is what we are doing at ubiq. We are using a combination of playwright and storybook, as I gave some hints along the way, in order to test our component.
6. Testing Components with Storybook and Playwright
We use Storybook to build and render our components in isolation. Playwright is the tool we use for browser automation and testing. With Playwright, we can achieve real component rendering without the need for mocking. It provides stability, efficient execution, and the ability to run tests in parallel and headless. We can also perform visual regression tests and take screenshots. Storybook and Playwright are continuously improving their testing capabilities, including component testing. End-to-end testing involves working with a real backend server and testing complete user flows, while component testing focuses on variations and edge cases without relying on the backend.
We are using storybook to build our component and to render our component in isolation. We build stories for each component and on top of these stories we are running our tests because playwright does not really care, as long as you give it a web page, it does not really care what's inside the web page. You just need to provide the URL and playwright will open it. So we are spawning our storybook and then on top of it we run the test and we use playwright also for the browser automation.
Playwright started as a browser automation only but it also has now a great test runner that has a lot of really advanced functionality and a great setup, and this is how we actually test our components. This is what it looks like. I'm not sure how useful that is, but you can see here I have it in VS Code and I'm just running the test, it opens the page, it shows me the specific component and I can simply go and see it. Let's see that quickly again. You're running the test inside VS Code. You can see quickly that it passes and the test passes.
So what do we gain from this approach? First of all, this is real component rendering, we don't need to mock anything, the browser is responsible for that. We already write stories for storybooks to show our component so we reuse them and we run the test on top of them. This is a very stable test, we don't need to mock, Playwright is providing a very good feedback Playwright is providing a lot of stability in our tests, we get efficient execution, it can run in parallel, it can run in headless, which means it can run on the CI, it can also shards or you can run it across multiple machines in the CI, you basically have a lot of access to everything, just like any node or program that you want to run. Playwright, and I mean this could be a whole talk about how advanced debugging and tracing can do that. And we get the ability because this is running in the real browser, we can do screenshots and we can do visual regression tests. We can do that in Storybook, we can do that in Playwright and so on. I just want to mention a few other things that they are also doing, Storybook is also advancing their testing capabilities, Playwright has component testing so you can use it not just only for end-to-end and same goes for Cypress, they provide component testing. To make this quick, we can see here that when we talk about end-to-end tests and component testing, we have a real browser and visual migration can achieve this both, but the main difference is this, that in end-to-end we will probably work with a real backend server and make requests to real server and database and we will test complete user flows from ordering to payment, but because they are so long we will probably focus on the happy path while in component testing we will lock our backend, we don't want to go to our backend to run it and there are a lot of tools for doing that and we will focus more on variation and end case.