Developer Insights
Join millions of viewers! Our engineers craft human-written articles solving real-world problems weekly. Enjoy fresh technical content and numerous interviews featuring modern web advancements with industry leaders and open-source authors.
Unit Testing, TypeScript, and AI: Enhancing Code Quality and Productivity in 2024
In this episode of the Modern Web Podcast, host Rob Ocel and co-hosts Adam Rackis, Tracy Lee, and Danny Thompson discuss the importance of unit testing for maintaining code quality and reliability, emphasizing its role in scaling projects and ensuring long-term stability. The conversation also highlights the benefits of TypeScript in improving code safety and developer productivity, sharing experiences on how it catches errors early in the process. They also examine the growing role of AI in automating development tasks, weighing the efficiency gains against the risks of over-reliance on automation while stressing the importance of understanding the underlying processes. Chapters 00:00 - Introduction and Episode Overview 02:59 - The Importance of Unit Testing 10:03 - Best Practices for Implementing Unit Tests 17:15 - TypeScript’s Role in Code Safety and Productivity 2:30 - AI in Software Development: Automating Tasks 29:16 - Balancing AI Automation with Developer Expertise 32:07 - Final Thoughts and Closing Remarks Sponsored by This Dot: thisdot.co...
Oct 23, 2024
1 min
Enhancing Your Playwright Workflow: A Guide to the VSCode Extension
An introduction to the Playwright VSCode extension - a powerful tool that can streamline your end-to-end testing workflow. From installation and setup to running tests and debugging, learn how this extension can enhance your Playwright experience....
Sep 6, 2024
5 mins
Quick Guide to Playwright Fixtures: Enhancing Your Tests
Explore the essentials of using Playwright fixtures in our latest guide. Learn how to create, implement, and manage fixtures to streamline your end-to-end testing process. This quick guide provides practical examples....
Jul 26, 2024
2 mins
Our Journey from Cypress to Playwright for E2E Testing
In this blog post, we share our experience of transitioning our end-to-end (E2E) testing framework from Cypress to Playwright. Faced with a technical incompatibility in our existing setup, we embarked on a journey to find a more robust and flexible solutio...
May 31, 2024
3 mins
What is Cypress Studio?
Cypress Studio has been around for some time. It was introduced in Cypress v6.3.0, removed in v10, and reintroduced in v10.7.0. This blog post will dive into its current state and how to use it today....
May 3, 2024
5 mins
A Look at Playwright Parallelism
In this blog post, we are exploring Playwright’s parallelism capabilities to speed up test execution....
Mar 20, 2024
5 mins
How to test React custom hooks and components with Vitest
In this guide, we'll navigate through the process of testing React hooks and components using Vitest—a powerful JavaScript unit testing framework. Discover how Vitest simplifies testing setups...
Mar 15, 2024
5 mins
Testing Accessibility Features With Playwright
Discover how Playwright can help ensure accessibility in your applications. This article demonstrates how to use Playwright for testing keyboard navigation and identifying accessibility regressions before production....
Jan 31, 2024
5 mins
Does Replay Fix All Debugging Issues?
Rob Ocel and Adam Barrett talk with Jason Laster, CEO and co-founder of Replay. For those of you who are unfamiliar, Replay is an innovative browser development tool that is revolutionizing the way developers approach time travel debugging and bug fixing. This episode highlights all the reasons why Replay is such an amazing tool and all the problems it solves for developers. Jason shares the background on where the concept of time travel debugging came from, and how it actually works in Replay. The idea that you can capture a bug once and replay it as many times as needed enables developers to zoom in and identify the root cause of the issue. This approach saves infinite time, as you no longer have to rely on guesswork or spend hours reproducing bugs. Download this podcast episode here!...
Jan 5, 2024
1 min
Testing a Fastify app with the NodeJS test runner
ant to simplify your testing process? Our new blog post on Node.js' built-in test runner is a great place to start. Learn how to test Fastify apps, including practical examples for testing an API server and SQL plugins....
Nov 29, 2023
5 mins
E2E Testing Basics with Playwright
End-to-end (E2E) testing is a crucial piece of the application testing puzzle. E2E testing generally refers to testing your application as an entire system as opposed to testing it in small isolated pieces like unit tests. This post introduces Playwright, a powerful E2E testing framework that offers APIs in several different programming languages. Before we dive in, let's take a high-level look at some of its most noteworthy features. - Component testing - This post is specifically about E2E tests but being able to test your components in isolation with the same framework is a really nice feature. - Incredible flexibility - Headless and headed test modes - Multiple browsers (Chromium, Firefox, WebKit), and mobile device testing environments - API is available in several different languages - Single-page and multi-page app testing - Project config supports running particular sets of tests against specific browsers and environments - Multiple browser contexts - Useful for testing multiple sessions or user accounts simultaneously - Parallel test execution - Runs tests in parallel by default - Test Generation - You can interact with your web app UI in the headed Playwright browser and have it generate selectors and test code for you. We won’t touch on it in this article, but you can learn more about it here - Debugging - Has built-in support for debugging Playwright in Practice In this post, we will reference a fictional web application with authentication that includes user login and profile setup flows to illustrate how you can use Playwright to test an application. Here is the directory structure for our tests: ` Playwright configuration playwright.config.ts is where you can specify various options and features for your testing setup. The projects option is where things get really interesting. You can use projects to configure different sets of tests to run on different browsers and devices. We can add tags to our test description to target particular tests for specific projects. For example, we can tag particular tests with @firefox and configure a project that only runs it against the Firefox browser. This might be useful for testing against regressions for a browser specific bug. We are also able to match against file names. In the project config below, we are ignoring tests with .mobile in the filename in all of our projects except the one that is mobile-specific. Here are some reference pages for some of the features, and config options covered here: - https://playwright.dev/docs/test-configuration - https://playwright.dev/docs/test-projects - https://playwright.dev/docs/running-tests ` The webServer option allows specifying a web server for server-rendered and API servers. You can provide a command to start the server, and Playwright will wait for it to be ready before running your tests. Artifacts and Fixtures In addition to the models and specs directories, we also have an artifacts directory and a fixtures directory. The artifacts directory is used to store any artifacts generated during tests, such as screenshots or videos. Playwright can automatically take screenshots or videos of test runs, and these will be saved in the artifacts directory. The fixtures directory, on the other hand, contains any static data that might be needed during tests, such as images or data files. For example, in our auth-flow tests, we use an avatar image stored in the fixtures directory to simulate a user uploading an avatar image during the profile setup process. Selectors and Basic Test Writing In Playwright, we use selectors to target and interact with specific elements on a page. Playwright supports a wide range of selector engines, including CSS, XPath, and text-based selectors. You can also create custom selectors to suit your specific testing needs. When writing tests, we typically use the page.locator() method to target a specific element using a selector. For instance, you can use CSS selectors to target elements by their class, ID, or attributes. Here's an example that demonstrates how to use selectors to interact with a simple login form: ` In this example, we used CSS selectors to target the email and password input fields and a text-based selector to locate the login button. We can call methods, such as fill() and click(), that simulate user interactions and verify that the application behaves as expected. If you want to learn more on this topic, check out the writing tests page of the documentation. Page Object Models One pattern that Playwright recommends in its documentation is called Page Object Models. A page object model is a design pattern for organizing tests in a way that makes them more maintainable and encapsulates reusable logic. The basic idea is to define a set of classes that represent the pages and components of your web application, and then use these classes in your tests to interact with the application. For testing our applications, auth flows we might add a auth-flow.ts file. We can define an AuthFlow class that represents the authentication flow of our web application. This class encapsulates all the logic for requesting magic links, creating user accounts, and clicking links in the email sent to the user. By defining this class, we can write more readable and maintainable tests that use the AuthFlow class to perform the necessary actions. We accept a page argument in our constructor. This is a special argument that is always available in the browser context of our tests. It allows us to interact with the page via selectors and other easy to use APIs. There is a dedicated page in the documentation for this special object. ` Specs Finally, let's take a look at the specs directory. This directory contains the actual test files that use the AuthFlow class to perform the authentication and profile setup flows. new-user.spec.ts For example, the new-user.spec.ts file contains a test that verifies that a new user can complete the authentication flow, and be successfully redirected. In this example, we use the test.describe.serial test annotation to run the tests one after the other, since the second (sign-out) test depends on the user being logged in. (By default, Playwright runs as many tests as it can in parallel). We use test.beforeAll to run setup code (creating a magic link and user account) and test.afterAll to run any cleanup at the end of the tests. One of the first things you’ll notice is the callback functions that we pass to the Playwright test methods like beforeAll get called with an object argument that includes things like browser and baseURL. The browser object provides an API to the actual browser that our tests are running in, and we can use it to create and open new pages like we do in the first couple of lines of the beforeAll below. ` profile-setup.spec.ts Next, we have a profile-setup.spec.ts file that contains a test that verifies that the profile setup form can be filled out and changes can be successfully saved. Tests similar to this will be pretty common in most web applications. Luckily Playwright’s API and selectors make it pretty easy. We are able to test form accessibility here by trying both clicking and tabbing to the next fields. ` sign-in.spec.ts And finally, we have a sign-in.spec.ts file that contains a test that verifies that the sign-in modal can be opened and a magic link can be sent. ` Once you get familiar with the API, and the tools that Playwright makes available to you, writing tests for your application becomes pretty easy… and dare I say… fun? Summary There is so much more that we can cover when it comes to Playwright because it’s such a fantastic and powerful tool. Hopefully, this served as a good introduction to help you get started writing some basic E2E tests for your application. We covered some good ground after the intro by looking at some of the configuration options Playwright provides, and then writing some example tests for a fictional authentication flow. Our page object model implementation provided a nice abstraction for working with our app’s authentication mechanisms. Please keep in mind that this is not a prescription for how you need to write or structure your tests. The specific setup in this post is more to serve as a guide and a way to introduce some of the features and ways to start writing some tests. The most important part is that you can meet your application testing goals, and enjoy your time building out your tests!...
May 5, 2023
6 mins
How to Create Better Test Coverage Using Cypress 10
Testing is an integral part of software development, and it is important that all developers learn best testing practices. Jordan Powell, DX engineer at Cypress and Angular Google Developer Expert, has some tips to share with developers on how to write better tests using Cypress 10. In this article, we will take a look at Powell’s tips for writing end-to-end tests, component tests, and advanced testing patterns in Cypress. If you want to learn more from Jordan Powell, please check out his Advanced Cypress JS Drop training. Table of Contents - Why is Testing important? - Types of Testing - A new take on the testing pyramid - Differences between end-to-end testing and component testing - Jordan Powell’s best practices for E2E testing - Don’t use HTML Native selectors - Use Closures - Independent Test - Use Route Aliases - Setting a Global baseUrl - Jordan Powell’s Best Practices for Component Testing - Default Config Mount - Cypress Intercept - Use createOutputSpy - Jordan Powell’s Advanced Cypress Patterns - Session - Origin - Conclusion Why is Testing important? Software testing identifies issues within the application, and helps ensure that only high quality products are shipped to the user. Here are Jordan Powell’s reasons on why testing is important, and how it helps developers: Documentation: Good testing coverage will result in developers creating stronger test plans and better QA testing for new releases. Confidence: Writing good tests allows developers to build new features in confidence because the applications are working as intended. Safe Refactoring: Good test coverage leads to less refactoring down the road, and provides developers more time to work on new features. Improved UX: Good test coverage provides better UX (User Experience) for the end user because the application is working as intended. Types of Testing E2E, Integration, and Unit testing are three common methods for testing software applications. Unit Test: Unit testing serves as the foundation of the test pyramid. If you're working in a functional language, a unit will most likely be a single function. Your unit tests will call a function with different parameters and ensure that it returns the expected values. In an object-oriented language, a unit can range from a single method to an entire class. Integration test: Integration testing is where individual components of your application are tested as a group. End-to-end testing: E2E Testing is a technique that tests your app from the web browser through to the back end of your application, as well as testing integrations with third-party APIs and services. These types of tests are great at making sure your entire app is functioning as a cohesive whole. A new take on the testing pyramid In Jordan Powell’s Advanced Cypress JS Drop training, he challenges developers to rethink the traditional testing pyramid, and believes that component testing should also be included. Component Testing with Cypress 10 allows developers to test individual components quickly, regardless of its complexity. Component tests differ from end-to-end tests in that instead of visiting a URL to pull up an entire app, a component can be "mounted" and tested on its own. Differences between end-to-end testing and component testing Here are a few key differences between End-to-end and component testing: | End-to-end testing | Component testing | | ------------------------------------------------------- | ------------------------------------------------------------------------ | | The entire application and all of its layers are tested | Only the independent components are tested | | Testing can be done by developers and QA Teams | Testing is done by the developers | | Often requires a complex setup | No extra configuration for CI(Continuous Integration) environments needed | | Initialization command: cy.visit(url) | Initialization command: cy.mount() | Jordan Powell’s best practices for E2E testing Don’t use HTML Native selectors It is not good practice to use element selectors, id attributes, or class attributes when writing End-to-end tests. Using HTML Native selectors can lead to team members refactoring tests later on, or changing attributes which could affect the tests. Jordan Powell recommends using data attributes that can inform the team that this is a test attribute. When other team members need to change anything, they will be aware of the function of the attribute and what it may affect. Use Closures Jordan warns against assigned return values for Cypress assertions, and recommends using closures to access the Commands yield like this: ` Independent Test It is not good practice to combine related tests. Jordan Powell suggests that tests should be run independently from one another without sharing or relying on other test states. If test suites are related in any way, run the related properties or methods before each of the test runs, like in the code below: ` Use Route Aliases Another recommended practice is to use route aliases to guard Cypress against proceeding until an explicit condition is met. ` Setting a Global baseUrl It is bad practice to use hardcoded URL strings for the baseUrl because it will eventually fail when the environment changes. Instead, Powell recommends using a config file that holds the environment baseUrl. Jordan Powell’s Best Practices for Component Testing All of the code examples in this next section will be for Angular, but Cypress component testing works for all major Frontend JavaScript frameworks. Default Config Mount Component testing takes two parameters: the component to mount, and the object for configuration. A Custom Mount Config can boost flexibility. It ships a default mount config which you can use, but to manage multiple modules and import without adding too many boilerplate codes, it is recommended to have a custom mount config for specific instances. ` Cypress Intercept Component testing handles the individual components you are testing at a particular time, to access external API it is recommended to use cy.intercept. According to the Doc Cy.intercept can be used to passively listen for matching routes without manipulating the request or its response in any way. ` Use createOutputSpy When working with eventEmitter for components that may contain forms or other elements with events, createOutputSpy will automatically create an EventEmitter and set up the spy on it's .emit() method. ` Jordan Powell’s Advanced Cypress Patterns Session When testing for routes or components that require authentication Cypress provides cy.session which eliminates creating functions in your test to check for sessions on every call to the route or component. cy.session caches the sessions, and it will skip the login process for testing components that need the sessions on a second call. ` Origin Running tests for projects that require a visit to multiple different domains could get CORS, or a limitation of visits, due to browser environment. Cypress provides Origin to help bypass some of the browser limitations. ` Conclusion In this article, we looked at Jordan Powell’s tips for writing End-to-end tests, component tests, and advanced testing patterns in Cypress. I recommend watching the full video for Jordan Powell’s Advanced Cypress JS Drop training. Are you excited about the Cypress Component Testing? Let us know on Twitter....
Dec 19, 2022
6 mins
Let's innovate together!
We're ready to be your trusted technical partners in your digital innovation journey.
Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.