Skip to content

Commit 637a16b

Browse files
committed
refactor: land Clerk example and other small refactorings
1 parent e2d7bfc commit 637a16b

File tree

5 files changed

+140
-67
lines changed

5 files changed

+140
-67
lines changed

.github/workflows/run-apollo-app-example.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,5 @@ jobs:
5757
echo 'module.exports={"presets":["next/babel"]};' > babel.config.js
5858
mkdir -p app/api/graphql
5959
curl -o app/api/graphql/route.js https://raw.githubusercontent.com/Xunnamius/next-test-api-route-handler/main/apollo_test_raw_app_route
60-
curl -o test/my.test.js https://raw.githubusercontent.com/Xunnamius/next-test-api-route-handler/main/apollo_test_raw_app_test
60+
curl -o test/integration.test.js https://raw.githubusercontent.com/Xunnamius/next-test-api-route-handler/main/apollo_test_raw_app_test
6161
npx jest

.github/workflows/run-apollo-pages-example.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,5 @@ jobs:
6161
# npm install --force [email protected] next-server
6262
echo 'module.exports={"presets":["next/babel"]};' > babel.config.js
6363
mkdir test
64-
curl -o test/my.test.js https://raw.githubusercontent.com/Xunnamius/next-test-api-route-handler/main/apollo_test_raw
64+
curl -o test/integration.test.js https://raw.githubusercontent.com/Xunnamius/next-test-api-route-handler/main/apollo_test_raw
6565
npx jest

README.md

+136-63
Original file line numberDiff line numberDiff line change
@@ -647,8 +647,8 @@ These examples use Next.js's [App Router][51] API.
647647
#### Testing Apollo's Official Next.js Integration @ `app/api/graphql`
648648

649649
This example is based on [the official Apollo Next.js App Router
650-
integration][52]. You can easily run it yourself by copying and pasting the
651-
following commands into your terminal.
650+
integration][52]. You can run it yourself by copying and pasting the following
651+
commands into your terminal.
652652

653653
> The following should be run in a nix-like environment. On Windows, that's
654654
> [WSL][53]. Requires `curl`, `node`, and `git`.
@@ -660,13 +660,15 @@ npm install --force next @apollo/server @as-integrations/next graphql-tag next-t
660660
echo 'module.exports={"presets":["next/babel"]};' > babel.config.js
661661
mkdir -p app/api/graphql
662662
curl -o app/api/graphql/route.js https://raw.githubusercontent.com/Xunnamius/next-test-api-route-handler/main/apollo_test_raw_app_route
663-
curl -o test/my.test.js https://raw.githubusercontent.com/Xunnamius/next-test-api-route-handler/main/apollo_test_raw_app_test
663+
curl -o test/integration.test.js https://raw.githubusercontent.com/Xunnamius/next-test-api-route-handler/main/apollo_test_raw_app_test
664664
npx jest
665665
```
666666

667-
The above script creates a new temporary directory, installs NTARH and
668-
configures dependencies, downloads the [app route][54] and [jest test][55] files
669-
shown below, and runs the test using [jest][56].
667+
This script creates a new temporary directory, installs NTARH and configures
668+
dependencies, downloads the [app route][54] and [jest test][55] files shown
669+
below, and runs the test using [jest][56].
670+
671+
The following is our new app route:
670672

671673
```typescript
672674
/* File: app/api/graphql/route.js */
@@ -697,8 +699,11 @@ const handler = startServerAndCreateNextHandler(server);
697699
export { handler as GET, handler as POST };
698700
```
699701

702+
And with the following jest test, we ensure our route integrates with Apollo
703+
correctly:
704+
700705
```typescript
701-
/* File: tests/my.test.js */
706+
/* File: tests/integration.test.js */
702707

703708
import { testApiHandler } from 'next-test-api-route-handler';
704709
// Import the handler under test from the app/api directory
@@ -740,27 +745,84 @@ describe('my-test (app router)', () => {
740745

741746
#### Testing Clerk's Official Next.js Integration @ `app/api/authed`
742747

743-
Suppose we have an _authenticated_ API endpoint built using [Clerk's quick-start
744-
guide for Next.js][57], or perhaps [from their official demo repo][58].
748+
Suppose we created a new _authenticated_ API endpoint at `app/api/authed` using
749+
[Clerk's quick-start guide for Next.js][57]:
750+
751+
```typescript
752+
/* File: app/api/authed/route.ts */
753+
754+
import { auth } from '@clerk/nextjs';
755+
756+
export async function GET() {
757+
const { userId } = auth();
758+
return Response.json({ isAuthed: !!userId, userId });
759+
}
760+
```
745761

746-
How might we test that this endpoint behaves as we expect?
762+
How might we test that this endpoint functions as we expect?
747763

748764
```typescript
749765
/* File: test/unit.test.ts */
750766

767+
import * as Clerk from '@clerk/nextjs';
751768
import { testApiHandler } from 'next-test-api-route-handler';
752-
import * as appHandler from '../app/api/authed/route';
753769

754-
it('', async () => {
770+
import * as appHandler from './app/api/authed/route';
771+
772+
let mockedClerkAuthReturnValue:
773+
| Partial<ReturnType<(typeof Clerk)['auth']>>
774+
| undefined = undefined;
775+
776+
jest.mock('@clerk/nextjs', () => {
777+
return {
778+
auth() {
779+
return mockedClerkAuthReturnValue;
780+
}
781+
};
782+
});
783+
784+
afterEach(() => {
785+
mockedClerkAuthReturnValue = undefined;
786+
});
787+
788+
it('returns isAuthed: true and a userId when authenticated', async () => {
755789
expect.hasAssertions();
756790

791+
mockedClerkAuthReturnValue = { userId: 'winning' };
792+
757793
await testApiHandler({
758794
appHandler,
759-
test: async ({ fetch }) => // TODO
795+
test: async ({ fetch }) => {
796+
await expect((await fetch()).json()).resolves.toStrictEqual({
797+
isAuthed: true,
798+
userId: 'winning'
799+
});
800+
}
801+
});
802+
});
803+
804+
it('returns isAuthed: false and nothing else when unauthenticated', async () => {
805+
expect.hasAssertions();
806+
807+
mockedClerkAuthReturnValue = { userId: null };
808+
809+
await testApiHandler({
810+
appHandler,
811+
test: async ({ fetch }) => {
812+
await expect((await fetch()).json()).resolves.toStrictEqual({
813+
isAuthed: false,
814+
userId: null
815+
});
816+
}
760817
});
761818
});
762819
```
763820

821+
If you're feeling more adventurous, you can turn this unit test into an
822+
_integration_ test by calling [`authMiddleware`][58] in `requestPatcher` instead
823+
of mocking `@clerk/nextjs`. For insight into what you'd need to mock to make
824+
this work, check out [Clerk's own tests][59].
825+
764826
#### Testing an Unreliable Handler on the Edge @ `app/api/unreliable`
765827

766828
Suppose we have an API endpoint we use to test our application's error handling.
@@ -846,11 +908,11 @@ it('injects contrived errors at the required rate', async () => {
846908

847909
### Using the Pages Router
848910

849-
These examples use Next.js's [Pages Router][59] API.
911+
These examples use Next.js's [Pages Router][60] API.
850912

851913
#### Testing Next.js's Official Apollo Example @ `pages/api/graphql`
852914

853-
This example uses the [official Next.js Apollo demo][60]. You can easily run it
915+
This example uses the [official Next.js Apollo demo][61]. You can easily run it
854916
yourself by copying and pasting the following commands into your terminal.
855917

856918
> The following should be run in a nix-like environment. On Windows, that's
@@ -867,21 +929,21 @@ npm install --force next-test-api-route-handler jest babel-jest @babel/core @bab
867929
# npm install --force [email protected] next-server
868930
echo 'module.exports={"presets":["next/babel"]};' > babel.config.js
869931
mkdir test
870-
curl -o test/my.test.js https://raw.githubusercontent.com/Xunnamius/next-test-api-route-handler/main/apollo_test_raw
932+
curl -o test/integration.test.js https://raw.githubusercontent.com/Xunnamius/next-test-api-route-handler/main/apollo_test_raw
871933
npx jest
872934
```
873935

874-
The above script clones [the Next.js repository][61], installs NTARH and
875-
configures dependencies, downloads the [jest test][62] file shown below, and
876-
runs it using [jest][56].
936+
This script clones [the Next.js repository][62], installs NTARH and configures
937+
dependencies, downloads the [jest test][63] file shown below, and runs it using
938+
[jest][56] to ensure our route integrates with Apollo correctly.
877939

878940
> \[!IMPORTANT]\
879-
> Note that passing the [route configuration object][63] (imported below as `config`)
880-
> through to NTARH and setting `request.url` to the proper value is **[crucial][64]**
881-
> when testing Apollo endpoints using the Pages Router!
941+
> Note that passing the [route configuration object][64] (imported below as `config`)
942+
> through to NTARH and setting `request.url` to the proper value [may be necessary][65]
943+
> when testing Apollo endpoints using the Pages Router.
882944
883945
```typescript
884-
/* File: examples/api-routes-apollo-server-and-client/tests/my.test.js */
946+
/* File: examples/api-routes-apollo-server-and-client/tests/integration.test.js */
885947

886948
import { testApiHandler } from 'next-test-api-route-handler';
887949
// Import the handler under test from the pages/api directory
@@ -1128,52 +1190,60 @@ Further documentation can be found under [`docs/`][x-repo-docs].
11281190
Since NTARH is meant for unit testing API routes rather than faithfully
11291191
recreating Next.js functionality, NTARH's feature set comes with some caveats.
11301192
Namely: no Next.js features will be available that are external to processing
1131-
API routes and executing their handlers. This includes [middleware][65] (see
1132-
[`requestPatcher`][66] if you need to mutate the `Request` before it gets to the
1133-
handler under test), [metadata][67], [static assets][68], [OpenTelemetry][69]
1134-
and [instrumentation][70], [caching][71], [styling][72], [server actions and
1135-
mutations][73], [helper functions][5] (except: `cookies`, `fetch` (global),
1193+
API routes and executing their handlers. This includes [middleware][66] (see
1194+
[`requestPatcher`][67] if you need to mutate the `Request` before it gets to the
1195+
handler under test), [metadata][68], [static assets][69], [OpenTelemetry][70]
1196+
and [instrumentation][71], [caching][72], [styling][73], [server actions and
1197+
mutations][74], [helper functions][5] (except: `cookies`, `fetch` (global),
11361198
`headers`, `NextRequest`/`NextResponse`, `notFound`, `permanentRedirect`,
1137-
`redirect`, and `userAgent`), and anything related to React or [components][74].
1199+
`redirect`, and `userAgent`), and anything related to React or [components][75].
11381200

11391201
NTARH is for testing your API route handlers only.
11401202

1141-
Further, any support NTARH appears to have for any "[edge runtime][75]" (or any
1142-
other runtime) beyond what is provided by [`AppRouteRouteModule`][76] is merely
1203+
Further, any support NTARH appears to have for any "[edge runtime][76]" (or any
1204+
other runtime) beyond what is provided by [`AppRouteRouteModule`][77] is merely
11431205
cosmetic. **Your tests will always run in Node.js** (or your runner of choice)
11441206
and never in a different runtime, realm, or VM. This means unit testing like
11451207
with NTARH must be done in addition to, and not in lieu of, more holistic
1146-
testing practices (e.g. [end-to-end][77]).
1208+
testing practices (e.g. [end-to-end][78]).
11471209

11481210
If you're having trouble with your App Router and/or Edge Runtime routes,
11491211
consider [opening a new issue][x-repo-choose-new-issue]!
11501212

1213+
> Also note that Next.js's middleware **only supports the Edge runtime**, even
1214+
> if the Next.js application is being run entirely by Node.js. This is an
1215+
> artificial constraint imposed by Next.js; when running the middleware locally
1216+
> (via `npm run dev` or something similar), the middleware will still run on
1217+
> Node.js.
1218+
>
1219+
> Next.js's middleware limitation is discussed at length [here][79].
1220+
11511221
### Legacy Runtime Support
11521222

11531223
As of version `4.0.0`, NTARH supports both the App Router (for `next@>=14.0.4`)
11541224
and the "legacy" Pages Router Next.js APIs.
11551225

11561226
Additionally, as of version `2.1.0`, NTARH is fully backwards compatible with
11571227
Next.js going _allll_ the way back to `[email protected]` [when API routes were first
1158-
introduced][78]!
1228+
introduced][80]!
11591229

11601230
If you're working with `next@<9.0.6` (so: [before `next-server` was merged into
1161-
`next`][79]), you might need to install `next-server` manually:
1231+
`next`][81]), you might need to install `next-server` manually:
11621232

11631233
```shell
11641234
npm install --save-dev next-server
11651235
```
11661236

11671237
Similarly, if you are using `npm@<7` or `node@<15`, you must install Next.js
11681238
_and its peer dependencies_ manually. This is because [`npm@<7` does not install
1169-
peer dependencies by default][80].
1239+
peer dependencies by default][82].
11701240

11711241
```shell
11721242
npm install --save-dev next@latest react
11731243
```
11741244

11751245
> If you're also using an older version of Next.js, ensure you install the [peer
1176-
> dependencies (like `react`) that your specific Next.js version requires][81]!
1246+
> dependencies (like `react`) that your specific Next.js version requires][83]!
11771247
11781248
### Inspiration
11791249

@@ -1193,8 +1263,8 @@ ballooning the execution time of the tests. That is: no spinning up the entire
11931263
Next.js runtime just to run a single test in isolation.
11941264

11951265
It doesn't seem like it'd be such a lift to surface a wrapped version of the
1196-
Pages Router's [`apiResolver`][82] function and a pared-down subclass of the App
1197-
Router's [`AppRouteRouteModule`][76], both accessible with something like
1266+
Pages Router's [`apiResolver`][84] function and a pared-down subclass of the App
1267+
Router's [`AppRouteRouteModule`][77], both accessible with something like
11981268
`import { ... } from 'next/test'`. This is essentially what NTARH does.
11991269

12001270
### Published Package Details
@@ -1458,39 +1528,42 @@ specification. Contributions of any kind welcome!
14581528
[55]: ./apollo_test_raw_app_test
14591529
[56]: https://www.npmjs.com/package/jest
14601530
[57]: https://clerk.com/docs/quickstarts/nextjs
1461-
[58]: https://github.com/clerk/clerk-nextjs-demo-app-router
1462-
[59]: https://nextjs.org/docs/pages
1463-
[60]:
1531+
[58]: https://clerk.com/docs/references/nextjs/auth-middleware
1532+
[59]:
1533+
https://github.com/clerk/javascript/blob/434a96ebefc550b726b417788b7bae9e41791408/packages/nextjs/src/server/authMiddleware.test.ts#L4
1534+
[60]: https://nextjs.org/docs/pages
1535+
[61]:
14641536
https://github.com/vercel/next.js/tree/deprecated-main/examples/api-routes-apollo-server-and-client
1465-
[61]: https://github.com/vercel/next.js
1466-
[62]: ./apollo_test_raw
1467-
[63]: https://nextjs.org/docs/api-routes/api-middlewares#custom-config
1468-
[64]: https://github.com/Xunnamius/next-test-api-route-handler/issues/56
1469-
[65]: https://nextjs.org/docs/app/building-your-application/routing/middleware
1470-
[66]: #requestpatcher-url
1471-
[67]: https://nextjs.org/docs/app/building-your-application/optimizing#metadata
1472-
[68]:
1473-
https://nextjs.org/docs/app/building-your-application/optimizing#static-assets
1537+
[62]: https://github.com/vercel/next.js
1538+
[63]: ./apollo_test_raw
1539+
[64]: https://nextjs.org/docs/api-routes/api-middlewares#custom-config
1540+
[65]: https://github.com/Xunnamius/next-test-api-route-handler/issues/56
1541+
[66]: https://nextjs.org/docs/app/building-your-application/routing/middleware
1542+
[67]: #requestpatcher-url
1543+
[68]: https://nextjs.org/docs/app/building-your-application/optimizing#metadata
14741544
[69]:
1475-
https://nextjs.org/docs/pages/building-your-application/optimizing/open-telemetry
1545+
https://nextjs.org/docs/app/building-your-application/optimizing#static-assets
14761546
[70]:
1547+
https://nextjs.org/docs/pages/building-your-application/optimizing/open-telemetry
1548+
[71]:
14771549
https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation
1478-
[71]: https://nextjs.org/docs/app/building-your-application/caching
1479-
[72]: https://nextjs.org/docs/app/building-your-application/styling
1480-
[73]:
1550+
[72]: https://nextjs.org/docs/app/building-your-application/caching
1551+
[73]: https://nextjs.org/docs/app/building-your-application/styling
1552+
[74]:
14811553
https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations
1482-
[74]: https://nextjs.org/docs/app/api-reference/components
1483-
[75]:
1484-
https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#runtime
1554+
[75]: https://nextjs.org/docs/app/api-reference/components
14851555
[76]:
1486-
https://github.com/vercel/next.js/blob/0aa0179246d4e59f74cd1d62e3beb8e9b670fc4e/packages/next/src/server/future/route-modules/app-route/module.ts#L118C24-L118C24
1556+
https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#runtime
14871557
[77]:
1558+
https://github.com/vercel/next.js/blob/0aa0179246d4e59f74cd1d62e3beb8e9b670fc4e/packages/next/src/server/future/route-modules/app-route/module.ts#L118C24-L118C24
1559+
[78]:
14881560
https://nextjs.org/docs/app/building-your-application/testing#types-of-tests
1489-
[78]: https://nextjs.org/blog/next-9
1490-
[79]: https://github.com/vercel/next.js/pull/8613
1491-
[80]:
1561+
[79]: https://github.com/vercel/next.js/discussions/46722
1562+
[80]: https://nextjs.org/blog/next-9
1563+
[81]: https://github.com/vercel/next.js/pull/8613
1564+
[82]:
14921565
https://github.blog/2021-02-02-npm-7-is-now-generally-available#peer-dependencies
1493-
[81]:
1566+
[83]:
14941567
https://github.com/vercel/next.js/blob/v9.0.0/packages/next/package.json#L106-L109
1495-
[82]:
1568+
[84]:
14961569
https://github.com/vercel/next.js/blob/90f95399ddfd036624c69b09910f40fa36c00ac2/packages/next/src/server/api-utils/node/api-resolver.ts#L321

apollo_test_raw

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* File: examples/api-routes-apollo-server-and-client/tests/my.test.js */
1+
/* File: examples/api-routes-apollo-server-and-client/tests/integration.test.js */
22

33
import { testApiHandler } from 'next-test-api-route-handler';
44
// Import the handler under test from the pages/api directory

apollo_test_raw_app_test

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* File: tests/my.test.js */
1+
/* File: tests/integration.test.js */
22

33
import { testApiHandler } from 'next-test-api-route-handler';
44
// Import the handler under test from the app/api directory

0 commit comments

Comments
 (0)