I work on a NextJS project with Pages Router. We are using Jest for unit tests and Playwright for E2E.

The application we are making is a funnel with several steps. Each step is a form with several fields. The final form is the one where the submit button makes a call to the backend.

API calls are located in /src/api/some-file.ts, e.g:

export const callBackend = (
  inquiryKey: string,
): Promise<AxiosResponse<void>> =>
  backendService.put<void>(`/my/url/${inquiryKey}`);

Those API functions are called from Redux Saga generator functions (in /src/sagas/some-folder/someSaga.ts), like this:

export function* watchCheckoutStep(): Generator<ForkEffect> {
    yield takeEvery(completionAT.SAVE_FORM_INPUTS, workCheckoutSaveStep);
    ...
}

...

function* workCheckoutSaveStep(
  action: ReturnType<typeof completionAC.doSaveCheckoutFormInputs>,
) {
    yield callCompleteCheckout();
}

export const callCompleteCheckout = (
  inquiryKey: string,
): Promise<AxiosResponse<void>> =>
  myBackendService.put<void>(`/checkout/complete/${inquiryKey}`);

The service is created using Axios, e.g. in /src/api/myBackendService.ts:

export const myBackendService = axios.create({
  baseURL: creditAPIBaseURL,
  withCredentials: true,
});

Action creators are in /src/state/my-funnel/myFunnel.actionCreators.ts:

export const doSaveInquiryFormInputs = (data: Partial<MyData>) =>
  ({
    type: SAVE_FORM_INPUTS,
    data
  }) as const;

The action creators are called from the components where the forms are located, e.g. /src/components/FirstPage/steps/AmountStep.tsx:

const form = useReactiveForm({
    initialState: myFormInputs,
    validation: myValidators,
    callback: (values: mFormInputs) => {
        ...
        dispatch(doSaveInquiryFormInputs(values));
        goToStep(AnotherStep); // using next/router
        ...
    },
  });

And finally, this component is used in a page at /src/pages/myfunnel/mypage.page.tsx:

function SomePage(): JSX.Element {
    ...
  return (
    <PageLayout>
        <AmountStep />
    </PageLayout>
  );
}

The task is to create test(s) which will go through the whole funnel, fill all fields, and then verify that the final backend call is made with the correct payload.

I tried using Playwright, but it turns out that I can't access the requests made from the server side. I was thinking about using Jest tests, but I'm not sure how to simulate filling the whole funnel and navigating between the forms. Any ideas/hints/suggestions?

2 Replies 2

Redux sagas run in the browser, so Playwright can intercept the HTTP requests they make. I don't think you need Jest. I suggest you use page.route() to intercept your final backend endpoint, then go through the funnel, fill all the forms, and submit. Also, verify the captured request has the correct URL and payload.

As you can said you cannot test Redux saga calls using Axios from serve-side not visible to playwright because they happen outside browser context.
You need two layers of tests:

  1. E2E (Playwright)

    • Simulate the user journey: fill forms, navigate steps.

    • Assert UI behavior (e.g., success message, redirect).

    • Mock the backend so you don't hit real API.

  2. Integration/Unit (Jest + React Testing Library)

    • Test Redux Saga + API calls in isolation.

    • Mock Axios and assert that the correct endpoint and payload are called.

Your Reply

By clicking “Post Your Reply”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.