



















We understand that writing tests isn't the most exciting part of development. That's why they are often shelved as "tech debt" or pushed to the bottom of the priority list. But it's not just about motivation - writing good tests is hard.
You might wonder:
This post addresses these challenges directly to help you develop a meaningful testing strategy for your Next.js application using Clerk.
By the end, you'll be equipped to test critical authentication flows by mocking Clerk's API in integration tests.
You'll also learn how to incorporate end-to-end tests and simulate real-world user interactions with your application to make sure that your application works (and continues to work) as it should in production.
This post demonstrates how to add comprehensive tests to a sample application called Pup Party.
Pup Party allows dog owners to rate and discover dog-friendly cafes and restaurants. Users can evaluate venues as "Pup-approved" or "Pup-fail" based on criteria such as dog-friendliness, ambiance, and the quality of dog treats.
To follow along and implement tests step-by-step, download the starter code and follow the set up instructions here.
Alternatively, you can study the complete source code, including tests, here.
Before we dive in, it's important to take a moment to think about what exactly you should be testing and the types of tests that will be most effective. This planning step is crucial, as it guides you in creating tests that are not only meaningful but also efficient to run and maintain.
I've seen teams fall into three common traps:
So, what's the right approach?
In this post, we turn to Kent C. Dodds and his testing trophy:
Following Kent's testing philosophy, this post primarily focuses on integration tests and later addresses E2E tests for critical user paths.
To write integration tests, you will be using two essential tools:
Start by installing these dev dependencies:
Add a test:jest script to package.json:
Add a jest.config.ts file to the root of your project:
Create a jest.setup.ts file in the root of your project to globally import @testing-library/jest-dom, which enhances Jest with custom matchers for more intuitive and readable DOM assertions:
In the ./tsconfig.json file, add "jest" to the types array:
Finally, create a ./__tests__ directory in your root folder. Within this directory, add an empty index.test.tsx file - this is where you'll set up your mocks, configure helpers, and write your integration tests in the next section.
In your integration tests, you should avoid making actual network calls, including to Clerk. Network calls can introduce variability and slow down your test suite, making it harder to achieve consistent and fast test results. Instead, you should mock these libraries to control their behavior in your tests and keep your integration test suite lean.
Below is the code to mock @clerk/nextjs, which allows you to simulate its behavior and focus on testing your application's logic without relying on external dependencies. Additionally, a helper function called renderWithProviders is defined. This function takes an isSignedIn argument, allowing you to simulate authenticated and unauthenticated user states in your tests.
Now that you have Jest and RTL configured, along with your mocks and test context provider, it's time to write some meaningful integration tests!
You will implement three integration tests for Pup Party. For each test scenario, you'll read a definition of the requirements in plain text before implementing code to programmatically test the expected behavior and protect against regressions.
If an unauthenticated user tries to access the submission page, they should be redirected to the sign-in page.
Here's the test implementation, along with comments explaining each notable line.
Add it to the bottom of index.test.tsx:
In this test, an unauthenticated user's experience on the <SubmitReviewPage /> is simulated by setting isSignedIn to false and passing it as the second argument to our renderWithProviders function.
The waitFor utility from React Testing Library is used to verify that the UI updates correctly after state changes, specifically ensuring the user is redirected to the sign-in page and cannot access the review submission content.
When a signed-in user submits valid details in the review form, the form should process successfully and then display a confirmation message.
Here's the test implementation:
In the code above, isSignedIn is set to true to simulate the experience of an authenticated user accessing Pup Party.
The userEvent utilities are used to mimic user actions, such as clicking into a form input, typing, hitting "Submit", and viewing a success notification.
Requirements for the submission form:
Here's the test code that checks these requirements:
This code simulates a user interaction where an invalid review is submitted. It sets up a user event, renders the <SubmitReviewPage /> for an authenticated user, and then mimics user actions of submitting a valid review but an invalid rating.
The async and await syntax is used to ensure that each action and corresponding assertion happens in the correct order, as some operations are asynchronous and need to complete before the next action or assertion takes place.
Execute your integration tests by running test:jest:
This script, defined earlier, will run the tests and display the results in your terminal:

Having implemented integration tests, let's turn our attention to end-to-end (E2E) tests.
Unlike integration tests that mock Clerk, E2E tests interact with Clerk directly to simulate production conditions.
To write E2E tests, you will be using two essential tools:
Start by create a new directory called ./e2e - this is where you'll write your E2E in the upcoming section.
Install @clerk/testing as a dev dependency:
Initialize and install Playwright:
Choose the following options when prompted:
Replace the contents of ./playwright.config.ts to configure Playwright for end-to-end testing:
Define an additional script to run E2E tests:
To ensure your E2E tests don't inadvertently run when invoking the test:jest script - which could cause errors due to Playwright tests being incompatible with Jest - update jest.config.ts as follows:
Clerk testing tokens allow you to bypass Clerk's bot detection mechanisms, which can otherwise block automated test requests with "bot traffic detected" errors.
The @clerk/testing library makes accessing Clerk testing tokens easy by automatically obtaining one when your test suite starts. It then offers the setupClerkTestingToken function, which injects the token, enabling your tests to bypass Clerk's bot detection mechanisms without any hassle. The clerk.signIn method internally uses the setupClerkTestingToken helper, so there's no need to call it separately when using this method.
To configure Playwright with Clerk, create ./e2e/global.setup.ts and call the clerkSetup() function:
Next, make sure global.setup.ts is called from ./playwright.config.ts:
Since E2E tests interact with the Clerk API and require user authentication, you must create a real Clerk user and supply your test runner with the user's credentials. These credentials allow your tests to sign in, simulate an authenticated user state, and ensure everything functions as expected in a real-world scenario.
Create a test user through the Clerk dashboard:

Add the username and password to .env.local. Also add your Clerk application's SECRET_KEY and PUBLISHABLE_KEY if you haven't already:
Next, update your playwright.config.ts file to load environment variables such that they can be accessed from your tests:
You now have everything in place to write an end-to-end test.
This test verifies a critical user flow in a Clerk-authenticated application: signing in, submitting a review, and signing out.
Since this is an end-to-end test, it will cover multiple points in the system, ensuring that real user interactions work as expected.
Create ./e2e/user-submits-review.spec.ts and paste the following:
The test starts by navigating to the sign-in page and using Clerk's signIn utility to authenticate a test user.
Once signed in, the test redirects to the review submission page, where it completes and submits a form, then verifies a success message. Finally, it signs out and confirms redirection to the home page.
Running this test in the future will help catch any errors introduced by code changes. If a change breaks the functionality, the test will fail, alerting you to the issue. If the test passes, you can be confident that this flow in your application is working as it should.
Run test:playwright to execute your end-to-end tests:
The result:

In the introduction, key questions were posed about testing in Clerk applications:
This post has provided comprehensive answers to these questions, guiding you through the process of developing a robust testing strategy against a practical application.
Equipped with this knowledge, you now have the tools to confidently implement a balanced testing strategy for any appliation using Clerk for Next.js authentication.
For more detailed guidance on testing Clerk applications, be sure to check out the Clerk documentation on testing.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。