Search code examples
reactjse2e-testingplaywright

Playwright - expect error - how to do it?


I am writing my first e2e tests in Playwright. Before I was using Cypress. This is a Next.js app.

I have an app that:

  1. on the homepage: http://localhost:3000/ it checks if the user is validated (has the token in the cookies)
  2. If yes, then it shows the normal pages
  3. If not, it redirects the user to the /login

This is controlled in the _app.tsx file with Authguard:

const AuthGuard = ({ children }: { children: React.ReactNode }) => {
  const { isLoading, isValidating, error } = useMe();

  if (isLoading || isValidating) return <Spinner belowText="Loading..." />;

  if (error) {
    if (error.response && error.response.status === 401)
      return <Spinner belowText="Unauthorized" />;

    if (!error.response && error.code === "ERR_NETWORK")
      return (
        <Spinner belowText="Network error. Check if you are connected to the VPN" />
      );

    return <p>Unknown error, redirecting to login...</p>;
  }

  return <>{children}</>;
};

...

const isAuthRequired = Component.auth ?? true;
    ...
            <EmotionThemeProvider theme={theme}>
              <CssBaseline />
              {isAuthRequired ? (
                <AuthGuard>
                  <Component {...pageProps} />
                </AuthGuard>
              ) : (
                <Component {...pageProps} />
              )}
            </EmotionThemeProvider>
    ...

And this is my test:

import { test } from "@playwright/test";

test("unauthorized users should be redirected to /login", async ({ page }) => {
  // Go to the homepage
  await page.goto("/");

  // Wait for the Unauthorized spinner
  const spinner = await page.waitForSelector('text="Unauthorized"', { timeout: 10000 });
  
  // Verify that the spinner was found
  if (spinner) {
    // Check that the page has been redirected to /login
    const url = page.url();
    expect(url).toContain("/login");
  } else {
    throw new Error('Unauthorized spinner not found');
  }
});

The problem I am facing is: When I run npx playwright test --ui I see that:

  • page.goto / works fine
  • page.waitForSelector locator('text="Unauthorized"') also works fine (the log says locator resolved to visible <p>Unauthorized</p>)
  • however in the previous page.waitForSelector locator('text="Unauthorized"') if I go to the Console tab, I see Failed to load resource: the server responded with a status of 401 (Unauthorized) which is normal, because the user is not logged in yet.

The test should not fail. Should redirect to /login and PASS. But the test fails because of that network error.

The hook useMe is the one that makes the redirect to /login:

const useMe = () => {
  const router = useRouter();
  return useSWR(
    "/users/me",
    (url: string) => axios.get<MeResponse>(url).then((res) => res.data),
    {
      revalidateOnFocus: false,
      onError: () => {
        router.push("/login");
      },
    }
  );
};
export { useMe };

How can I solve this?


Solution

  • How to wait for url to redirect and then verify?

    Use toHaveURL assertion.

    await expect(page).toHaveURL(/.*login/);

    So that it will wait for url to redirect and does not verify the url immediately before the change.