Component Testing with WebdriverIO [Testμ 2023]

LambdaTest Team - Nov 20 '23 - - Dev Community

As the use of frontend frameworks in web development continues to grow, the importance of testing individual web page components becomes evident. This approach facilitates quicker problem identification and resolution. However, a significant challenge persists in many testing tools: the inability to conduct tests in a real web browser. Instead, they rely on a virtual DOM. But wouldn’t it be more effective to test in an actual web browser, similar to the one users use daily?

This is where WebdriverIO version 8 came into play. It allowed developers to run these tests directly in real web browsers, simplifying and enhancing the testing process by mirroring user interactions. This new feature marked a substantial advancement in web component testing.

Christian Bromann, a Founding Engineer at Stateful, provides complete insights into the new browser runner capabilities and live demonstration on component testing in Vue, Svelte, React, or Preact. Prepare to be impressed as Christian simplifies and enhances component testing like never before!

If you couldn’t catch all the sessions live, don’t worry! You can access the recordings at your convenience by visiting the LambdaTest YouTube Channel.

Let’s dive into the session without wasting any more time. Christian outlined the session walkthrough along with the session’s agenda.

Agenda

Christian outlined the session’s agenda and further briefed on each topic, along with live coding for better understanding.

  • What are Web Components?

  • Testing Principles

  • Status Quo

  • WebdriverIO Setup

  • Live Coding

  • What’s Next?

What are Web Components?

Christian provided insights into web components, which had been in use for some time and had garnered widespread adoption. They served as a means to encapsulate reusable UI elements for application-wide use. Web Components encompassed two interconnected concepts: reusable UI components and web technology known as web components.

As implemented in frameworks like React, reusable UI components could encapsulate styles and functionality. On the other hand, web components consisted of specifications and APIs enabling the creation of custom elements and components using HTML, JavaScript, and CSS.

Christian continued stating that developing web components didn’t necessarily require using frameworks or build tools; basic JavaScript and web APIs sufficed. However, frameworks like Lit HTML, Stencil.js, React, Vue, and Svelte provided more straightforward approaches to crafting web components.

Why Test Web Components?

When testing Web Components, it was crucial to consider what was being tested. This involved determining whether the tested feature modified the entire application or required a specific third-party service. As technology evolved, there was a need to contemplate efficient testing practices and revisit best practices.

Component testing with WebdriverIO has proven effective in enhancing stability and expanding test coverage.

The Testing Pyramid

Christian elaborated on the testing pyramid, emphasizing the importance of testing. This concept categorized software tests into different levels based on their granularity.

While he believed in the direction of the testing pyramid, he acknowledged the plethora of available tools, which could be overwhelming. He often found himself comfortable writing high-level tests that offered substantial confidence. However, he mentioned that this practice would lead to an imbalance in the testing pyramid, with the top part becoming overly extensive. As testers and developers, their priority is to focus mainly on writing unit tests due to their speed of execution. In addition, they invested in many integration tests and a few end-to-end tests to ensure the smooth interaction of all components.

The Testing Trophy

Christian emphasized that this testing trophy was introduced by Kenzie Dodds and highlighted the return on investment in testing. It suggested that the focus should be on the integration level to strike a balance between complexity, confidence, and execution time and further illustrated the trophy concept with an example.

Christian progressed by considering an example. He continued, Imagine we had a login application with a login form. Typically, we would have written an end-to-end test to check if the login process worked correctly. However, we could have increased our coverage by writing component tests for the UI component (login form) and API tests for the backend. This approach would have allowed us to test various input types without running the whole application.

What tools to use?

Christian recommended looking at your existing stack and what additional tooling is recommended when selecting tools for testing. For component testing, different frameworks had different recommendations.

React

React suggested using a JavaScript test runner with JSDOM for testing React components. However, Christian found this approach less ideal and preferred using a real browser for component testing. JSDOM has limitations and does not fully emulate a browser, making it challenging to test specific scenarios and debug issues. Additionally, he mentioned that it lacked support for modern web APIs like the Fetch API and CORS, making it less suitable for cross-browser testing.

Vue

Christian mentioned that Vue has better documentation when compared to React for unit tests.

JSDOM caveats

Christian explained that JSDOM is a JavaScript implementation of the DOM (Document Object Model), enabling developers to emulate a browser-like environment within Node.js. It was commonly used for testing and other server-side tasks.

While JSDOM was a valuable tool for specific tasks, it had some limitations when fully replicating a natural browser environment. Here are some critical points regarding JSDOM:

  • Interactions with Components via JavaScript: Christian noted that JSDOM could simulate interactions with components through JavaScript. In short, developers could start events, manipulate the DOM, and affect user interactions, which was crucial for testing.

  • Missing Web APIs: JSDOM only partially implemented all web APIs in a modern web browser. This could be a limitation when testing features or functionality that rely on specific web APIs. Some notable missing APIs included the Fetch API, which was used for making HTTP requests, and the ability to handle CORS (Cross-Origin Resource Sharing) requests.

  • Module Scripts (ESM): JSDOM had limitations in running module scripts using the ECMAScript Module (ESM) syntax, commonly used in modern JavaScript applications, and limiting the ability to test styles and interactions relying on these states.

Christian highlighted that JSDOM was a valuable tool for many testing and development scenarios. Still, it was essential to know its limitations, especially when working with modern web applications relying on specific web APIs or complex browser behaviors. Complementing JSDOM-based testing with accurate browser testing was often a good practice to ensure comprehensive coverage.

Christian mentioned that some features, like scrolling and pinch-zoom, couldn’t be tested in JSDOM environments because they didn’t render anything on the screen.

Mocking

Furthermore, he added that mocking played a crucial role in component testing, enabling testing specific interfaces without network requests.

While JSDOM and Jest offered excellent interfaces for mocking modules, WebdriverIO had been one of the pioneering frameworks to introduce mocking within the browser environment.

WebdriverIO Setup

Christian guided his audience on how to set up WebdriverIO using the command. He further elaborated that to set up WebdriverIO, developers could use the npm init command with the latest version of WebdriverIO and specify the directory to their project folder.

He further continued that during the setup process, they had the option to configure various types of tests, including end-to-end tests, component tests, desktop tests, or Electron tests. If they chose component tests, they could select from a list of supported frameworks like React or Vue. Additionally, they had the option to use the Testing Library for staging and selecting elements within the website.

The setup generated a project with a boilerplate component, and ideally, developers had a passing test immediately. Only the specific component to be tested was rendered on the page when running the component tests. The browser interface was divided into three parts: the left displayed the rendered component, the middle showed the test reporter, and the right loaded the Chrome DevTools.

DevTools came in handy for executing WebdriverIO commands, preparing tests, and locating elements using the accessibility label selector. This feature simplified the test-writing process as developers could interact with the component in the browser and then directly copy the commands used into their test scripts.

Live Coding

To follow along with Christian, one could choose any framework. Christian preferred using React as his Framework for the demo. The complete code was available in the GitHub Repository shared by Christian, and additional insights could be gained by following the YouTube video.

Testing React Component in the Browser

In the live coding demo, the audience learned how to write component tests for a basic login component using React. Christian used a web API to verify that the tests ran in the browser and explored how to test the component in different browsers, such as Safari.

To run the test in the browser, the first step was to configure WebDriver. In the wdr-config file, the runner was set to the browser, and the preset was set to React. This ensured that the component was rendered correctly in the browser. Then, the test was executed by targeting the login test and running it. This opened up a browser window and rendered the component, and the browser version could be seen in the console logs.
To test the component in different browsers, it was easily switched by changing the capabilities in the wdr-config file. For example, the capability was set to use Safari instead of Chrome.

To render and stage the component, the testing library was used. It was imported into the library, and the render method was used to render the login component, allowing the browser to inspect the rendered components. In writing end-to-end tests, the watch flag is utilized to iterate continuously on the component. This enabled deis bugging directly in the browser using Chrome DevTools, where elements could be inspected and component behavior verified.

Christian guided his audience to exclude the backend from the component tests, and the API was mocked. The mock function from the WebDriver library was employed to simulate the login function, allowing the testing of the component independently from the backend.

Output

The component was loaded, and Christian successfully generated the test result.

Christian wrapped up his session by answering a few questions posted by his audience.

Q & A Session

Q. What are the benefits of running tests in an actual browser?

Christian: Running tests in an actual browser offers several key advantages. Christian highlighted that it ensures components function as intended in real-world scenarios. This approach also aids in the identification of issues that might remain hidden when using a headless browser for testing.

Q. How does WebdriverIO differ from other component testing tools?

Christian: WebdriverIO introduces a unique browser runner capability that differentiates it from other component testing tools. This capability allows direct execution of component tests within your browser, simplifying the process of testing individual components and validating their performance in real-world conditions. Christian emphasized defining the test scope based on the specific component and its dependencies.

Q. Can code coverage be extended to other tests besides component testing?

Christian: Currently, Christian clarified that code coverage is exclusively available for component testing. He suggested that as WebdriverIO continues to evolve and incorporate additional functionalities, there is potential for code coverage to expand its reach to encompass other test types in the future.

Q. What other features does WebdriverIO provide for component testing?

Christian: WebdriverIO offers support for snapshot testing, a valuable feature that enables capturing snapshots of DOM nodes. These snapshots can then be compared to previous versions to ensure that unexpected changes have not occurred. Moreover, WebdriverIO is compatible with various testing frameworks, such as Jasmine and Cucumber, providing flexibility in choosing the framework that aligns with your testing needs.

Q. What are component testing challenges, and how can they be overcome?

Christian acknowledged that component testing can pose challenges, especially if executed incorrectly. He identified two main challenges: expense and fragility. To mitigate these issues, he emphasized the importance of focusing on testing at the component level, which leads to faster and more efficient testing processes. Additionally, Christian recommended leveraging tools you are comfortable with from your technology stack for effective component testing.

Have you got more questions? Please put it on the LambdaTest Community.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .