Skip to content

Commit 0b27d6f

Browse files
authored
feat: bundler (esbuild, nextjs) integration tests (#699)
1 parent a561c1b commit 0b27d6f

File tree

11 files changed

+723
-508
lines changed

11 files changed

+723
-508
lines changed

integrations/esbuild/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
index.js

integrations/esbuild/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { Resend } from 'resend';
2+
3+
new Resend('');

integrations/esbuild/package.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"dependencies": {
3+
"esbuild": "0.25.11",
4+
"resend": "../.."
5+
},
6+
"scripts": {
7+
"build": "esbuild ./index.ts --bundle --platform=node --target=node18 --outfile=./index.js"
8+
}
9+
}

integrations/integrations.spec.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { spawnSync } from 'node:child_process';
2+
import fs from 'node:fs';
3+
import os from 'node:os';
4+
import path from 'node:path';
5+
6+
describe('integrations', () => {
7+
const sdkPath = path.resolve(__dirname, '..');
8+
9+
beforeAll(() => {
10+
const build = spawnSync('pnpm build', {
11+
stdio: 'inherit',
12+
cwd: path.resolve(__dirname, '..'),
13+
shell: true,
14+
});
15+
if (build.status !== 0) {
16+
throw new Error('SDK build failed');
17+
}
18+
});
19+
20+
/**
21+
* Create an extra temporary copy of the given integration so that there's no `@react-email/render` module resolution from the resend-node's devDependencies
22+
*
23+
* Also modifies the package.json to point to the SDK with an absolute path.
24+
*/
25+
async function prepareTemporaryIntegrationCopy(integrationPath: string) {
26+
const temporaryIntegrationPath = await fs.promises.mkdtemp(
27+
path.join(
28+
os.tmpdir(),
29+
`resend-node-integration-${path.basename(integrationPath)}`,
30+
),
31+
);
32+
await fs.promises.cp(
33+
path.resolve(__dirname, integrationPath),
34+
temporaryIntegrationPath,
35+
{
36+
recursive: true,
37+
},
38+
);
39+
40+
const testingLockPackageJson: { dependencies: Record<string, string> } =
41+
JSON.parse(
42+
await fs.promises.readFile(
43+
path.resolve(temporaryIntegrationPath, 'package.json'),
44+
'utf8',
45+
),
46+
);
47+
testingLockPackageJson.dependencies.resend = sdkPath;
48+
await fs.promises.writeFile(
49+
path.resolve(temporaryIntegrationPath, 'package.json'),
50+
JSON.stringify(testingLockPackageJson, null, 2),
51+
);
52+
53+
return temporaryIntegrationPath;
54+
}
55+
56+
test('nextjs', { timeout: 30_000 }, async () => {
57+
const temporaryNextAppPath =
58+
await prepareTemporaryIntegrationCopy('./nextjs');
59+
60+
const buildInstall = spawnSync(
61+
'npm install --install-links && npm run build',
62+
{
63+
stdio: 'inherit',
64+
cwd: temporaryNextAppPath,
65+
shell: true,
66+
},
67+
);
68+
if (buildInstall.status !== 0) {
69+
throw new Error('next.js build failed');
70+
}
71+
});
72+
73+
test('esbuild', { timeout: 30_000 }, async () => {
74+
const temporaryEsbuildAppPath =
75+
await prepareTemporaryIntegrationCopy('./esbuild');
76+
77+
const buildInstall = spawnSync(
78+
'npm install --install-links && npm run build',
79+
{
80+
stdio: 'inherit',
81+
cwd: temporaryEsbuildAppPath,
82+
shell: true,
83+
},
84+
);
85+
if (buildInstall.status !== 0) {
86+
throw new Error('esbuild build failed');
87+
}
88+
});
89+
});

integrations/nextjs/.gitignore

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
package-lock.json
5+
/node_modules
6+
/.pnp
7+
.pnp.*
8+
.yarn/*
9+
!.yarn/patches
10+
!.yarn/plugins
11+
!.yarn/releases
12+
!.yarn/versions
13+
14+
# testing
15+
/coverage
16+
17+
# next.js
18+
/.next/
19+
/out/
20+
21+
# production
22+
/build
23+
24+
# misc
25+
.DS_Store
26+
*.pem
27+
28+
# debug
29+
npm-debug.log*
30+
yarn-debug.log*
31+
yarn-error.log*
32+
.pnpm-debug.log*
33+
34+
# env files (can opt-in for committing if needed)
35+
.env*
36+
37+
# vercel
38+
.vercel
39+
40+
# typescript
41+
*.tsbuildinfo
42+
next-env.d.ts

integrations/nextjs/app/route.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { Resend } from 'resend';
2+
3+
export function GET() {
4+
new Resend('');
5+
6+
return new Response('Hello from this API route!', { status: 200 });
7+
}

integrations/nextjs/next.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = {};

integrations/nextjs/package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"dependencies": {
3+
"next": "15.5.6",
4+
"react": "19.2.0",
5+
"react-dom": "19.2.0",
6+
"resend": "../.."
7+
},
8+
"scripts": {
9+
"build": "next build"
10+
}
11+
}

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@
3131
},
3232
"scripts": {
3333
"build": "tsdown src/index.ts --format esm,cjs --dts",
34+
"integration:nextjs": "cd ./integrations/nextjs && next build --turbopack",
3435
"lint": "biome check .",
3536
"lint:fix": "biome check . --write",
3637
"prepublishOnly": "pnpm run build",
3738
"test": "vitest run",
3839
"test:dev": "cross-env TEST_MODE=dev vitest run",
40+
"test:integrations": "vitest run integrations",
3941
"test:record": "rimraf --glob \"**/__recordings__\" && cross-env TEST_MODE=record vitest run",
4042
"test:watch": "vitest",
4143
"typecheck": "tsc --noEmit"

0 commit comments

Comments
 (0)