Giter Site home page Giter Site logo

xunnamius / next-test-api-route-handler Goto Github PK

View Code? Open in Web Editor NEW
262.0 2.0 14.0 21.95 MB

⚡ Confidently unit and integration test your Next.js API routes/handlers in an isolated Next.js-like environment

Home Page: https://npm.im/next-test-api-route-handler

License: MIT License

JavaScript 9.78% TypeScript 89.92% Shell 0.30%
route-handler resolver nextapiresponse nextapirequest async next next-js api route handler

next-test-api-route-handler's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

next-test-api-route-handler's Issues

Relative URL doesn't work with appHandler: "Invalid URL" error

The problem

It seems this commit about normalization of URLs may have broken the ability to use a relative-style url param with the app handler because calling new URL(url) on a path like "/my-url" throws Invalid URL error (as one would expect it to, since new URL() doesn't accept relative URLs).

    TypeError: Invalid URL

      at normalizeUrlForceTrailingSlashIfPathnameEmpty (node_modules/.pnpm/next-test-api-route-handler@4.
[email protected]/node_modules/next-test-api-route-handler/dist/src/index.js:337:16)

I was able to get around this easily by providing a dummy beginning of the url as the tests do (e.g. "ntarh://api/books" instead of just "/api/books"), but it doesn't match what the docs say, so it required some digging to figure this out.

I noticed the tests include a case with url: '/my-url' and pagesHandler, but not a case for the same url with appHandler. I believe that's the case that's broken.

Reproduction steps
  1. Run a basic example like:
it("works", async () => {
  await testApiHandler({
    appHandler,
    url: "/my-url",
    async test({ fetch }) {
      const res = await fetch({
        method: "GET",
      })

      const json = await res.json()

      expect(json).toStrictEqual([])
    },
  })
})

ReferenceError: Request is not defined

The problem

I'm encountering a ReferenceError: Request is not defined when attempting to test an API route using next-test-api-route-handler. The test is designed to verify that a GET request to /api/test should return {hello: 'world'}. However, the test fails with the mentioned error.

Here's the code snippet where the error occurs:

import { testApiHandler } from "next-test-api-route-handler";

describe("GET /api/test", () => {
  it("Returns {hello: 'world'}", async () => {
    await testApiHandler({
      appHandler: {
        GET: async () => {
          return Response.json({ hello: "world" }, { status: 200 });
        },
      },

      async test({ fetch }) {
        const res = await fetch();
        expect(res.status).toBe(200);
        const json = await res.json();
        expect(json).toStrictEqual({ hello: "world" });
      },
    });
  });
});
Reproduction steps
Additional context
  • OS: Mac 14.2.1
  • Node version: 20.10.0
  • Babel: yes, version 7.18
  • TypeScript: yes, version 5.2.2
  • Next.js: 13.5.4
  • Jest: 29.6.1

Error message in terminal:

ReferenceError: Request is not defined

  37 | describe("GET /api/test", () => {
  38 |   it("Returns {hello: 'world'}", async () => {
> 39 |     await testApiHandler({
     |                         ^
  40 |       appHandler: {
  41 |         GET: async () => {
  42 |           return Response.json({ hello: "world" }, { status: 200 });

  at Object.Request (node_modules/next/src/server/web/spec-extension/request.ts:10:34)
  at Object.<anonymous> (node_modules/next/server.js:2:16)
  at createAppRouterServer (node_modules/next-test-api-route-handler/dist/src/index.js:161:25)
  at testApiHandler (node_modules/next-test-api-route-handler/dist/src/index.js:110:57)
  at Object.<anonymous> (tests/route.test.ts:39:25)

Able to fetch data through axios

The Issue

When I test nextjs api, the body that I send is always undefined if I don't Stringify at test level and parse at api level.
It's working, but when I don't make test, the JSON.parse() stay there and I also have to check wether the request body is stringified or not.

From the test I have to stringify my body, otherwise it is undefined on the api
client level

I want to send the request through a client such as postman or web browser I am getting this exception becuase it tries to parse a plain object instead of string.

postman level

If I want to use both at test level and client level I have to check if I can parse or not the body
api level

The solution

Access to "axios" parameter in the test callback to send body as plain object and avoid to stringify data

Module not found: Can't resolve 'next/dist/next-server/server/api-utils.js' in '.../node_modules/next-test-api-route-handler/dist/esm'

The problem

Just updated next.js to version 12 and now the project build is failing.

Curiously the tests are still passing, but "next build" fails with the following error:

$ next build --debug
 ******* next.config.js building:
            NODE_ENV: production
                 ENV: localhost
info  - Checking validity of types...
warn  - The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config
info  - Creating an optimized production build...
warn  - Disabled SWC as replacement for Babel because of custom Babel configuration ".babelrc" https://nextjs.org/docs/messages/swc-disabled
info  - Using external babel configuration from /home/runner/my-project/.babelrc
Failed to compile.

./node_modules/next-test-api-route-handler/dist/esm/index.mjs
Module not found: Can't resolve 'next/dist/next-server/server/api-utils.js' in '/home/runner/my-project/node_modules/next-test-api-route-handler/dist/esm'

Import trace for requested module:
./src/pages/api/my-endpoint.test.ts

./node_modules/next-test-api-route-handler/dist/esm/index.mjs
Module not found: Can't resolve 'next-server/dist/server/api-utils.js' in '/home/runner/my-project/node_modules/next-test-api-route-handler/dist/esm'

Import trace for requested module:
./src/pages/api/my-endpoint.test.ts
Reproduction steps

I guess you just need to create a test and import next-test-api-route-handler, like this:

import { testApiHandler } from 'next-test-api-route-handler'

and then run next build.

Additional context
  • OS: OSX
  • Node version: 12.22.7

Revert accidental BC

Problematic behavior

90caad6, which manually updated dependencies, accidentally bumped the Next.js peer dependency from next@10 to next@11. The culprit was npm-check-updates without the --dep option. This has since been fixed.

The coming update will address this issue along with #295 by extending NTARH compat all the way back to next@9.

Reproduction steps
Expected behavior
Additional context

next-test-api-route-handler (NTARH) failed to import api-utils.js

When running npm test I see:

 next-test-api-route-handler (NTARH) failed to import api-utils.js

      This is usually caused by:

        1. Using npm@<7 and/or node@<15, which doesn't install peer deps automatically (review install instructions)
        2. NTARH and the version of Next.js you installed are actually incompatible (please submit a bug report)

      Failed import attempts:

node -v shows v16.20.0
npm -v shows 9.8.1

I'm on Mac OSX using jest. I've tried rm -rf the node_modules and reinstalling but still getting this error.

Compat issue with [email protected]

Problematic behavior

WIth 11.1.0, the Next.js devs moved api-utils.js to a slightly different path. Canary build already has a working fix, will push release momentarily. This version of NTARH will be backwards compatible with all versions of Next.js >= 10.0.0.

Enhancement: subsequent versions of NTARH will use the same technique to enable backwards compatibility with next going back to 9.0.0 (a little trickier)!

Reproduction steps
Expected behavior
Additional context

Recursive redirection occurs when redirecting within the handler

Note:
This is not a problem caused by this library itself, but rather an issue that can arise when using the library. It is being documented as an issue with the intention of highlighting potential problems that may occur when using the library, and to request its inclusion in the documentation.

Overview of the Issue

When redirecting within an API handler, if you simply call fetch() in the test, it recursively triggers redirection. As a result, an error stating redirect count exceeded occurs.

Reproduction Test Code

  test('redirect', async () => {
    await testApiHandler({
      pagesHandler: (_, res) => res.redirect(302, '/'),
      test: async ({ fetch }) => {
        const res = await fetch({ method: 'GET' })
        expect(res.redirected).toBeTruthy()
      }
    })
  })

Executing this code results in the following error:

    TypeError: fetch failed

       8 |       pagesHandler: (_, res) => res.redirect(302, '/'),
       9 |       test: async ({ fetch }) => {
    > 10 |         const res = await fetch({ method: 'GET' })
         |                     ^
      11 |         expect(res.redirected).toBeTruthy()
      12 |       }
      13 |     })

(snip)

    Cause:
    redirect count exceeded

      at async node:internal/deps/undici/undici:10342:20
      at async node:internal/deps/undici/undici:10342:20
      at async node:internal/deps/undici/undici:10342:20
      (The above line repeats)

Solution Approach

By adding redirect: 'manual' when calling fetch(), it prevents automatic redirection to the redirect destination, allowing validation of the response.

Updated test code:

  test.skip('redirect', async () => {
    await testApiHandler({
      pagesHandler: (_, res) => res.redirect(302, '/'),
      test: async ({ fetch }) => {
        const res = await fetch({ method: 'GET', redirect: 'manual' })
        expect(res.status).toEqual(302)
        expect(res.headers.get('location')).toEqual('/')
      }
    })
  })

See also: https://developer.mozilla.org/en-US/docs/Web/API/fetch#redirect

Expected Fix

To prevent similar issues in the future, it would be beneficial to explicitly mention this in the documentation.

App Router Examples

According to the docs NTARH got app router and edge route support in version 4..

However, I have been unable to find any examples of tests using the app router. Additionally, it seems like the types require a NextApiRequest/NextApiReponse,

Finally, if I simply ignore the types, I see API route returned a Response object in the Node.js runtime, this is not supported. Please use runtime: "edge" as an error in the response.

I am guessing this is all supported based on the docs, but don't see how. Any ideas?

Bypassing MSW does not work with MSW 2.X

This is more of a FYI.

In version 3.1.0, the x-msw-bypass header was introduced in order to have better out of the box support for MSW.

MSW released a new version two weeks ago. Version 2.0 no longer respects the x-msw-bypass header. It seems that this header was considered to be an implementation detail as it's not documented as a breaking change.

MSW 2.0 has a new utility called bypass. Based on the implementation, it seems that the new header that gets bypassed is:

'x-msw-intention': 'bypass'

I'm not suggesting similar support should be implemented for MSW 2.x as existed fro MSW 1.x. I just want to bring this change into your attention.

Alternatives and workarounds

As a workaround, the old header can be respected in userland:

  server.listen({
    onUnhandledRequest(request, print) {
      if (request.headers.get('x-msw-bypass') === 'true') {
        return;
      }

      print.warning();
    },
  })
);

Not sure if the new bypass utility can be used in some way that allows the implementation to not depend on implementation details.

npm package size is very large

I'm seeing 121mb in my node_modules which is larger than my next package:

121M	/app/node_modules/next-test-api-route-handler
103M	/app/node_modules/next

Any way that you could ignore content using the .npmignore file?

ValidationPipe not triggering in unit tests

The problem

When running a unit test using Jest the validation pipeline is not triggered. The expected behaviour would be by providing incorrect values to a route which accepts a body that the validation pipe would be triggered and an error returned to the client.

// The input model
import { IsNumber, IsNotEmpty, IsString, IsOptional } from 'class-validator';

export class UpdateAlbumInputModel {
  @IsNotEmpty()
  @IsNumber()
  albumId: number;
  @IsOptional()
  @IsString()
  description?: string;
  @IsNotEmpty()
  @IsString()
  name: string
}

// The route
@Put('/albums')
@HttpCode(204)
public async updateAlbums(
  @Body(ValidationPipe) body: UpdateAlbumInputModel
) {
  return await this.albumService.updateAlbums(body);
}

The unit test can be found here:

it('should fail to update albums, if the body is invalid', async () => {
  await testApiHandler({
    handler: albumHandler,
    url: '/api/albums',
    test: async ({ fetch }) => {
      const res = await fetch({
        method: 'PUT',
        body: JSON.stringify({
          description: 'description',
        }),
        headers: {
          'Content-Type': 'application/json',
        },
      });
      // This returns a 204 status code, but expected to return an invalid status code of 400 (Bad Request)
      console.log(res);
    },
  });
});
Additional context
Response {
        size: 0,
        timeout: 0,
        cookies: [Getter],
        [Symbol(Body internals)]: {
          body: PassThrough {
            _readableState: [ReadableState],
            _events: [Object: null prototype],
            _eventsCount: 2,
            _maxListeners: undefined,
            _writableState: [WritableState],
            allowHalfOpen: true,
            [Symbol(kCapture)]: false,
            [Symbol(kCallback)]: null
          },
          disturbed: false,
          error: null
        },
        [Symbol(Response internals)]: {
          url: 'http://localhost:53325/',
          status: 204,
          statusText: 'No Content',
          headers: Headers { [Symbol(map)]: [Object: null prototype] },
          counter: 0
        }
      }

Package versions:
"class-transformer": "0.5.1",
"class-validator": "0.14.0",
"next-api-decorators": "2.0.2",

Doesn't work in node 20.8.0 to 20.x

The problem

In a project using node 20.8+ (20.8.0, 20.8.1, 20.9.0...), using node 20 as major, minor 8 and up. Gives the following error:

Error: next-test-api-route-handler (NTARH) failed to import api-utils.js

  This is usually caused by:

    1. Using npm@<7 and/or node@<15, which doesn't install peer deps automatically (review install instructions)
    2. NTARH and the version of Next.js you installed are actually incompatible (please submit a bug report)

  Failed import attempts:

    - EBADF: bad file descriptor, fstat
    - Cannot find module 'next/dist/server/api-utils.js'
    - Cannot find module 'next/dist/next-server/server/api-utils.js'
    - Cannot find module 'next-server/dist/server/api-utils.js'

    at y (/<repo_path>/node_modules/next-test-api-route-handler/dist/index.js:71:38)
    at async Object.<anonymous> (<repo_path>/src/modules/portal/api/downloadExamPdf.test.ts:44:5)

I didn't try in other OS, just Macosx Ventura.

Seems working with no problem in 20.7.0

Reproduction steps In a basic next project, using jest and next-test-api-route-handler:
  • With node 20.8.0 execute an api handler test
Additional context
  • OS: Macosx Ventura
  • Node version: 20.8.0
  • TypeScript: yes, version 5.2.0

Relevant log lines:

(super long error log lines pasted here)

TypeError: Only absolute URLs are supported

Problematic behavior I've tried setting this up as explained in the docs. When I try running the test suite, my test fails with the message `TypeError: Only absolute URLs are supported`
Reproduction steps Here's what my code looks like: Screenshot 2021-08-22 at 09 01 19

I tried setting an absolute URL (e.g. http://localhost:3000/pages/api/me), but that didn't work. I also tried removing 'pages' (e.g. /api/me), and no luck there either.

I'm using the Next.js runtime, so my /api directory is inside /pages. So I tried switching to a Node.js runtime by moving the /api directory to the root folder, but no luck there either.

I may have missed something in the docs, but can't see it – this looks like a great, and much needed package, so would love to get this working!

Expected behavior I would expect to be able to run the test suite.

originalGlobalFetch is not a function

The problem

I tried NTARH v4.0.5 with Next.js v14.1.4 or v14.2.1 and my unit tests fail with this reason:
originalGlobalFetch is not a function

Sample unit test that fails

import { testApiHandler } from 'next-test-api-route-handler'

test('Sample test that fails on line 8', async () => {
  await testApiHandler({
    params: { id: 5 },
    pagesHandler: (req, res) => res.status(200).send({ id: req.query.id }),
    test: async ({ fetch }) =>
      expect((await fetch({ method: 'POST' })).json()).resolves.toStrictEqual({
        id: 5
      })
  });
})
Reproduction steps
  1. Clone the history repo I made: https://github.com/danactive/history/tree/update-deps
  2. nvm use Match node.js version
  3. npm ci Install deps
  4. npm test Run test suite
  5. See error "originalGlobalFetch is not a function" at test "Gallery endpoint › Expect result › * GET has gallery", which shouldn't be happening
Expected behavior
  1. Clone the history repo I made: https://github.com/danactive/history/tree/update-deps
  2. nvm use Match node.js version
  3. npm ci Install deps
  4. npm test Run test suite
  5. All tests should pass
Additional context
  • OS: macos Sonoma 14.3
  • Node version: 20
  • Babel: No
  • TypeScript: yes, version 5.2.2
  • Browser: N/A using Node.js CLI
  • List of installed packages

How to set cookie header?

I'm trying to set a cookie header so that my handler can access request.cookies, but can't figure out how to do it.

I want the equivalent of this:

const response = await supertest(app)
  .get(PATH)
  .set('Cookie', `magic-auth-token=${token}`)
  .expect(200);

I tried:

requestPatcher: request =>
  (request.headers = { 'set-cookie': [`magic-auth-token=${token}`] }),

and

requestPatcher: request =>
  (request.headers = { cookie: `magic-auth-token=${token}` }),

both of which do not work. How can I set a cookie?

Test file-uploading API Endpoint

I just discovered this library, and it seems to be exactly what I need, except ... I need to test a file-upload API, and I couldn't find any examples in the documentation of testing such endpoints.

Is it possible, and if so are there any examples or docs I can reference?

Error: Invariant: Method expects to have requestAsyncStorage, none available

Error: Invariant: Method expects to have requestAsyncStorage, none available

Hey! I am trying to test my app route handlers which are protected using Clerk.dev authentication.
When testing an endpoint which is not protected with clerk the test runs fine but as soon as an endpoint protected with clerk is tested it throws the following error:

 Error: Clerk: auth() and currentUser() are only supported in App Router (/app directory).
@acme/admin:test:       If you're using /pages, try getAuth() instead.
@acme/admin:test:       Original error: Error: Invariant: Method expects to have requestAsyncStorage, none available
Reproduction steps
  1. Create a basic next app and install clerk following the guide at https://clerk.com/docs
  2. Now try to create a test that tests a protected route, e.g:
import type { PageConfig } from "next";
import { testApiHandler } from "next-test-api-route-handler";

import {
  GET as getReqAdmin,
  PUT as putReqAdmin,
} from "../../app/api/admin/route";
import { prisma } from "../../lib/prismaClient";
import { orderSeedData, userSeedData } from "../testUtils/seedData";

beforeEach(async () => {
  await prisma.users.create({
    data: userSeedData,
  });
  await prisma.orders.create({
    data: orderSeedData,
  });
});

afterEach(async () => {
  await prisma.users.deleteMany();
  await prisma.users.deleteMany();
});

// Respect the Next.js config object if it's exported
const getReqHandler: typeof getReqAdmin & { config?: PageConfig } = getReqAdmin;
const putReqHandler: typeof putReqAdmin & { config?: PageConfig } = putReqAdmin;

describe("admin api", () => {
  it("should return 401 unauthorized", async () => {
    await testApiHandler({
      handler: getReqHandler,
      test: async ({ fetch }) => {
        const res = await fetch({ method: "GET" });
        await expect(res.status).resolves.toStrictEqual(401);
      },
    });
  });
});

Expected behavior

The test should pass since the library states that it is compatible with the app router.

Additional context

System:
OS: macOS 13.2.1
CPU: (8) arm64 Apple M1
Memory: 159.31 MB / 16.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 16.20.2 - /opt/homebrew/opt/node@16/bin/node
Yarn: 1.22.17 - ~/.yarn/bin/yarn
npm: 9.8.1 - ~/temp_turbo_order//node_modules/.bin/npm
pnpm: 8.5.1 - ~/Library/pnpm/pnpm

Status always 200 on redirect.

Problem

I think the title is self-explanatory. Status appears to be 200 in any case.

Reproduction steps Jest example:
import { testApiHandler } from 'next-test-api-route-handler';

test('redirect', async () => 
{
  await testApiHandler(
    {
      handler: (req, res) => res.redirect(307, 'https://example.com'),
      test: async ({ fetch }) => 
      {
        const res = await fetch();
        // this fails, status is 200
        expect(res.status).toBe(307);
      },
    },
  );
});

Support for edge function API

It'd be great if we could get an update to the handler parameter to also support the edge function format

i.e. handler(req: NextRequest): Promise<Response> (rather than the NextApiRequest/NextApiResponse)

Thanks

Add response.cookies field for easier access to multiple cookies

The problem

When testing a Next.js API route that sets multiple cookies, only the most recent Set-Cookie header is detected.

Reproduction steps

Clone this repo and run the test (instructions in README.md).

The test is expected to fail due to this bug. (However, I don't know what a pass looks like, as multiple cookies are encoded in a different way than other headers.)

Suggested solution

As this is partially caused by a deficiency in the fetch API, consider adding a cookies field to the response, so we can do something like this:

import {serialize} from 'cookie'
import {testApiHandler} from 'next-test-api-route-handler'

describe('next-test-api-route-handler bug', () => {
    it('is a bug', async () => {
        await testApiHandler({
            handler: async (_req, res) => {
                res.setHeader('Set-Cookie', serialize('access_token', '1234'))
                res.setHeader('Set-Cookie', serialize('refresh_token', '5678'))
                res.status(204).end()
            },
            test: async ({fetch}) => {
                const response = await fetch({
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({})
                })

                // Test hypothetical cookies property
                expect(response.cookies.sort()).toEqual([
                    'access_token=1234',
                    'refresh_token=5678',
                ])
            },
        })
    })
})

Could not find a declaration file for module 'next-test-api-route-handler'.

The problem

Hi! The import import { testApiHandler } from "next-test-api-route-handler"; gives me the following typescript error:

Could not find a declaration file for module 'next-test-api-route-handler'. '/Users/jakejones/Documents/repos/git/next-test-api-route-handler-import/node_modules/next-test-api-route-handler/dist/esm/index.mjs' implicitly has an 'any' type.
  There are types at '/Users/jakejones/Documents/repos/git/next-test-api-route-handler-import/node_modules/next-test-api-route-handler/dist/types/src/index.d.ts', but this result could not be resolved when respecting package.json "exports". The 'next-test-api-route-handler' library may need to update its package.json or typings.ts(7016)

I think the issue is related to prs such as:

Reproduction steps

For basic reproduction: https://github.com/jakejones2/next-test-api-route-handler-import

Suggested solution

A quick fix seems to be changing package.json as follows:

"exports": {
    ".": {
      "types": "./dist/types/src/index.d.ts",
      "import": "./dist/esm/index.mjs",
      "require": "./dist/index.js",
      "default": "./dist/index.js"
    },
    "./package": "./package.json",
    "./package.json": "./package.json"
  },

However, looking at similar pull requests, the problem might require an index.d.mts file. Something like this:

"exports": {
  ".": {
    "import": {
      "types": "./dist/types/src/index.d.mts",
      "default": "./dist/esm/index.mjs",
    },
    "require": {
      "types": "./dist/types/src/index.d.ts",
      "default": "./dist/index.js",
    }
  },
  "./package": "./package.json",
  "./package.json": "./package.json"
},
Additional context

node v.20.4.0
npm v.9.7.2

Verify support for app-based route handlers

It seems like NTARH works perfectly fine with the app-based route handlers as it does with the page-based ones (no one has reported any issues), but I haven't tested it yet since Vercel is still actively working on the feature. However, it seems like things are stable enough now that I can add some tests and update the documentation to verify NTARH's compatibility.

This issue exists to remind me, along with adding a signature for edge routes.

Compat issue with Next 10.2.0

Problematic behavior

The automated compat test reports incompatibility with Next 10.2.0. Seems a parameter has been removed from the api resolving function's interface. Fix is incoming.

Reproduction steps
Expected behavior
Additional context

Jest did not exit one second after the test run has completed.

i am looking for a nice way to unit test my route handlers.
many thanks for this package.

when using the appHandler, there seems to be an open promise after my tests complete: Jest did not exit one second after the test run has completed.

is this expected behavior, or am i perhaps missing some sort of tear down call ?

Jest --detectOpenHandles

  ●  TCPWRAP

      4 | describe('POST() route', () => {
      5 |   it('FOO', async () => {
    > 6 |     await testApiHandler({
        |                         ^
      7 |       appHandler,
      8 |       async test({ fetch }) {
      9 |         const result = await fetch({ method: 'POST', body: 'dummy-data' });

      at port (../../node_modules/.pnpm/[email protected][email protected]/node_modules/next-test-api-route-handler/dist/src/index.js:121:15)
      at testApiHandler (../../node_modules/.pnpm/[email protected][email protected]/node_modules/next-test-api-route-handler/dist/src/index.js:120:24)
      at Object.<anonymous> (app/match/organizations/_tests/POST.route.test.ts:6:25)

My route and test

import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
  return NextResponse.json({
    received: true,
  });
import { testApiHandler } from 'next-test-api-route-handler';
import * as appHandler from '../route';

describe('POST() route', () => {
  it('test()', async () => {
    await testApiHandler({
      appHandler,
      async test({ fetch }) {
        const result = await fetch({ method: 'POST', body: 'foo' });
        await expect(result.json()).resolves.toStrictEqual({ received: true });
      },
    });
  });
});

Steps To Reproduce using next-test-api-route-handler repo

  • it seems like the repo unit tests also demonstrate it
next-test-api-route-handler on  main is 📦 4.0.2 via ⬢ v18.17.1 took 24.8s 
➜ npm test

> [email protected] test
> npm run test:unit --


> [email protected] test:unit
> NODE_OPTIONS='--no-warnings' NODE_ENV=test jest '/unit-.*\.test\.tsx?' --testPathIgnorePatterns '/dist/'

 PASS  test/unit-index-imports.test.ts
 PASS  test/unit-msw.test.ts
 PASS  test/unit-external.test.ts
 PASS  test/unit-index.test.ts
A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --detectOpenHandles to find leaks. Active timers can also cause this, ensure that .unref() was called on them.

Test Suites: 4 passed, 4 total
Tests:       93 passed, 93 total
Snapshots:   0 total
Time:        1.821 s
Ran all test suites matching /\/unit-.*\.test\.tsx?/i.

Expose function callbacks to TestApiClient instance in next major version

The solution

I think these test, requestPatcher and responsePatcher functions are unnecessary to be defined when creating tester instance. It's so limited when we need to create tester with some options dynamically and asynchronous work with Promises is better than callbacks. So, to avoid dirty codes caused by callbacks, it can be solved by exposing these functions like setting headers to be setted after the testApiHandler instance is created.

Example:

const api = require("../../pages/api/someApiEndpoint")
const { TestApiClient } = require("next-test-api-route-handler")

// as class instance:
const tester = new TestApiClient({ handler: api })
// as function:
const tester = TestApiClient({ handler: api })

// Proposal 1: defining directly
tester.request.headers = { key: process.env.SPECIAL_TOKEN }
// Proposal 2: exposing 'setXXX' functions 
tester.request.setHeader('key', process.env.SPECIAL_TOKEN)

const example = await tester.fetch({ method: 'GET' }).then(r => r.json())

// test with test environments like jest
expect(example).toBe('test')

// Block tentative after test was already executed
tester.request.setHeader('test', 'error')
// Error: cannot set header after test was already executed

Alternatives considered

I'm open to other suggestions, but if you dont want to expose everything because there are too many codes to be edited, you can only expose the test function and this will help me a lot.

Additional context

stack trace from error on `test` function?

I been testing a route that was failing due to a problem with axios and i was getting a SyntaxError from inside of axios but i couldn't figure out where the error was coming from because it seems next-test-api-router-handler was throwing only a string and not the entire error / stack trace?

image

The solution

throw the entire error with stack trace when an error happen? Would that possible or is that a limitation from apiResolver?

That would help a lot when debugging errors on tests!

Thanks for your help / library

Issue with Apollo Server API (404 Error and no JSON Fetching work)

Problematic behavior

I created an API that serves an Apollo-Server with an Query. When I test it with your library it returns 404 Not Found and I can't access the Response Data json without invalid json error.

await testApiHandler({
    requestPatcher: (req) => {
      req.headers = {
        ...req.headers,
        Origin: "localhost:3000",
        Host: "localhost:3000",
      };
    },
    handler: graphQlHandler,
    test: async ({ fetch }) => {
      const query = `query getYoutubeVideoMetadata($youtubeVideoId: String!) {
  videoData: youtubeVideoMeadata(youtubeVideoId: $youtubeVideoId) {
    id
    title
    thumbnails {
      default {
        url
      }
    }
  }
}
`;
      const res = await fetch({
        method: "POST",
        headers: {
          Accept: "	*/*",
          "Accept-Encoding":
            "gzip deflate",
          "Accept-Language":
            "de,en-US;q=0.7,en;q=0.3",
          "Content-Type":
            "application/json",
          "User-Agent":
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:85.0) Gecko/20100101 Firefox/85.0",
        },
        body: JSON.stringify({
          operationName:
            "getYoutubeVideoMetadata",
          query,
          variables: {
            youtubeVideoId: exampleYoutubeVideoId,
          },
        }),
      });
      console.log(await res.json());
    },
  });
Expected behavior
Reproduction steps
  1. Start Jest Test against API.
  2. Return JSOnN Data from Query.
  3. Successful Resolve them and get 200 or so.
Runtime environment
  • OS: windows/mac os
  • Browser: firefox 71, chrome 90
  • Version: v1.2.3
  • Node version: 14
  • Babel: yes, version 7
  • TypeScript project: yes
Additional context

Potential NTARH incompatibility with `next/jest.js`

As discussed in #983.

Seems next/jest.js calls some sort of internal environmental setup function for http/https "agents" that ends up changing the nature of the Request object; specifically: spreading the Request object functions differently. This occurs when calling nextJest in const createJestConfig = nextJest({ dir: './' }) where nextJest is defined as import nextJest from 'next/jest.js'. When the dir option is omitted, the discussed error does not occur.

Drilling into what the function returned by calling createJestConfig in const jestConfig = await createJestConfig(config)() is actually doing, we get the following stack:

const jestConfig = await createJestConfig(config)()
const createJestConfig = nextJest({
  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
  dir: './'
});
function nextJest(options = {}) {
    // createJestConfig
    return (customJestConfig)=>{
        // Function that is provided as the module.exports of jest.config.js
        // Will be called and awaited by Jest
        return async ()=>{
...
            if (options.dir) {
                const resolvedDir = (0, _path.resolve)(options.dir);
                const packageConfig = loadClosestPackageJson(resolvedDir);
                isEsmProject = packageConfig.type === "module";
                nextConfig = await getConfig(resolvedDir);
...
async function getConfig(dir) {
    const conf = await (0, _config.default)(_constants.PHASE_TEST, dir);
    return conf;
}
// Is the "default" export of "config"
async function loadConfig(phase, dir, { customConfig, rawConfig, silent = true, onLoadUserConfig } = {}) {
...
assignDefaults(dir, ...)
..
function assignDefaults(dir, userConfig, silent) {
...
(0, _setuphttpagentenv.setHttpClientAndAgentOptions)(result || _configshared.defaultConfig);
...

This is the function that, once executed, somehow subtly changes what @whatwg-node/server's createServerAdapter() returns:

function setHttpClientAndAgentOptions(config) {
    if (globalThis.__NEXT_HTTP_AGENT) {
        // We only need to assign once because we want
        // to reuse the same agent for all requests.
        return;
    }
    if (!config) {
        throw new Error("Expected config.httpAgentOptions to be an object");
    }
    globalThis.__NEXT_HTTP_AGENT_OPTIONS = config.httpAgentOptions;
    globalThis.__NEXT_HTTP_AGENT = new _http.Agent(config.httpAgentOptions);
    globalThis.__NEXT_HTTPS_AGENT = new _https.Agent(config.httpAgentOptions);
}

Rather than investigate this further, it seems whatever is going on is not really an NTARH issue. The solution here is to just explicitly declare/reference each valid property in the Request constructor's options parameter instead of trying to spread the Request instance to grab its properties.

Vercel lambda governing compatibility badge isn't tracking latest compat version anymore

The problem

Maybe it's just that the caches near my usual internet access points are stale, but it appears the endpoint responsible for updating the compat info badge is no longer doing its job (still at 14.0.1 when next is at 14.0.4). The Actions tests all pass, so NTARH still works.

First guess: API change at shields.io. Second guess: GitHub's own image caching solution broke. Will investigate when I come back around to finish app router compat feature in a little bit. Nope. As usual, it was just my fault (shot myself in the foot with tee again).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.