neon-testing 2.6.2 → 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,9 @@
5
5
  [![GitHub release](https://img.shields.io/github/v/release/starmode-base/neon-testing)](https://github.com/starmode-base/neon-testing/releases)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue)](LICENSE)
7
7
 
8
- A [Vitest](https://vitest.dev/) utility for seamless integration tests with [Neon Postgres](https://neon.com/). <!-- A [STΛR MODΞ](https://starmode.dev) open-source project. -->
8
+ A testing utility for seamless integration tests with [Neon Postgres](https://neon.com/), for [Vitest](https://vitest.dev/) and [Bun Test](https://bun.com/docs/cli/test).
9
+
10
+ <!-- A [STΛR MODΞ](https://starmode.dev) open-source project. -->
9
11
 
10
12
  Each test file runs against its own isolated PostgreSQL database (Neon branch), ensuring clean, parallel, and reproducible testing of code that interacts with a database. Because it uses a real, isolated clone of your production database, you can test code logic that depends on database features, such as transaction rollbacks, unique constraints, and more.
11
13
 
@@ -29,7 +31,7 @@ Each test file runs against its own isolated PostgreSQL database (Neon branch),
29
31
  - 🔄 **Isolated test environments** - Each test file runs against its own Postgres database with your actual schema and constraints
30
32
  - 🧹 **Automatic cleanup** - Neon test branches are created and destroyed automatically
31
33
  - 🐛 **Debug friendly** - Option to preserve test branches for debugging failed tests
32
- - 🛡️ **TypeScript native** - With JavaScript support
34
+ - 🛡️ **TypeScript only** - Ships TypeScript source files
33
35
  - 🎯 **ESM only** - No CommonJS support
34
36
 
35
37
  ## How it works
@@ -41,7 +43,9 @@ Each test file runs against its own isolated PostgreSQL database (Neon branch),
41
43
 
42
44
  ### Test isolation
43
45
 
44
- Tests in the same file share a single database instance (Neon branch). This means test files are fully isolated from each other, but individual tests within a file are intentionally not isolated. This works because Vitest runs test files in [parallel](https://vitest.dev/guide/parallelism.html), while tests within each file run sequentially.
46
+ Each test file runs against its own database instance (Neon branch), so test files are fully isolated from each other. Tests within a single file share that branch and run sequentially individual tests within a file are intentionally not isolated.
47
+
48
+ Vitest and Bun differ in how they execute files. Vitest runs each file in its own process, [in parallel](https://vitest.dev/guide/parallelism.html), while Bun runs every file in [a single shared process](https://bun.com/docs/test), one after another by default. File-level isolation is the same on both — each file gets its own branch — but Vitest creates those branches concurrently whereas Bun creates them one at a time.
45
49
 
46
50
  If you prefer individual tests to be isolated, you can [reset the database](examples/isolated.test.ts) in a `beforeEach` lifecycle hook.
47
51
 
@@ -59,7 +63,11 @@ Test branches are automatically deleted after your tests complete. As a safety n
59
63
  ### Install
60
64
 
61
65
  ```sh
66
+ # Vitest
62
67
  bun add -d neon-testing vitest
68
+
69
+ # Bun Test
70
+ bun add -d neon-testing
63
71
  ```
64
72
 
65
73
  ### Minimal example
@@ -67,7 +75,7 @@ bun add -d neon-testing vitest
67
75
  ```ts
68
76
  // minimal.test.ts
69
77
  import { expect, test } from "vitest";
70
- import { makeNeonTesting } from "neon-testing";
78
+ import { makeNeonTesting } from "neon-testing/vitest";
71
79
  import { Pool } from "@neondatabase/serverless";
72
80
 
73
81
  // Enable Neon test branch for this test file
@@ -75,6 +83,7 @@ makeNeonTesting({
75
83
  apiKey: process.env.NEON_API_KEY!,
76
84
  projectId: process.env.NEON_PROJECT_ID!,
77
85
  // Recommended for Neon WebSocket drivers to automatically close connections
86
+ // (Vitest only)
78
87
  autoCloseWebSockets: true,
79
88
  })();
80
89
 
@@ -93,21 +102,29 @@ Source: [`examples/minimal.test.ts`](examples/minimal.test.ts)
93
102
 
94
103
  ### Recommended usage
95
104
 
96
- #### 1. Plugin setup
105
+ #### 1. Setup
97
106
 
98
- First, add the Vite plugin to clear any existing `DATABASE_URL` environment variable before tests run, ensuring tests use isolated test databases.
107
+ Register `neon-testing/setup` so any existing `DATABASE_URL` is cleared before tests run. A test file that forgets to enable branching then fails loudly instead of silently writing to a real database.
99
108
 
100
109
  ```ts
101
110
  // vitest.config.ts
102
111
  import { defineConfig } from "vitest/config";
103
- import { neonTesting } from "neon-testing/vite";
104
112
 
105
113
  export default defineConfig({
106
- plugins: [neonTesting()],
114
+ test: {
115
+ setupFiles: ["neon-testing/setup"],
116
+ },
107
117
  });
108
118
  ```
109
119
 
110
- This plugin is recommended but not required. Without it, tests might accidentally use your existing `DATABASE_URL` (from `.env` files or environment variables) instead of the isolated test databases that Neon Testing creates. This can happen if you forget to call `neonTesting()` in a test file where database writes happen.
120
+ For Bun, add it to `bunfig.toml` instead:
121
+
122
+ ```toml
123
+ [test]
124
+ preload = ["neon-testing/setup"]
125
+ ```
126
+
127
+ Recommended but not required. Without it, a test file that forgets to call `neonTesting()` could fall back to your real `DATABASE_URL` (from `.env` or the environment) instead of an isolated test branch.
111
128
 
112
129
  #### 2. Configuration
113
130
 
@@ -115,7 +132,7 @@ Use the `makeNeonTesting` factory to generate a lifecycle function for your test
115
132
 
116
133
  ```ts
117
134
  // neon-testing.ts
118
- import { makeNeonTesting } from "neon-testing";
135
+ import { makeNeonTesting } from "neon-testing/vitest"; // or "neon-testing/bun"
119
136
 
120
137
  // Export a configured lifecycle function to use in test files
121
138
  export const neonTesting = makeNeonTesting({
@@ -139,6 +156,7 @@ import { Pool } from "@neondatabase/serverless";
139
156
  // Enable Neon test branch for this test file
140
157
  neonTesting({
141
158
  // Recommended for Neon WebSocket drivers to automatically close connections
159
+ // (Vitest only)
142
160
  autoCloseWebSockets: true,
143
161
  });
144
162
 
@@ -157,20 +175,28 @@ Source: [`examples/recommended.test.ts`](examples/recommended.test.ts)
157
175
 
158
176
  ## Drivers
159
177
 
160
- This library works with any database driver that supports Neon Postgres and Vitest. The examples below demonstrate connection management, transaction support, and test isolation patterns for some popular drivers.
178
+ This library works with any database driver that supports Neon Postgres.
179
+
180
+ ### Closing connections
181
+
182
+ Some drivers keep a connection open after a test finishes — [Neon's WebSocket driver](https://neon.com/docs/serverless/serverless-driver#use-the-driver-over-websockets) and [node-postgres](https://www.npmjs.com/package/pg). If the test branch is deleted while a connection is still open, the driver errors. Avoid it in one of three ways:
161
183
 
162
- **IMPORTANT:** For [Neon WebSocket drivers](https://neon.com/docs/serverless/serverless-driver), enable `autoCloseWebSockets` in your `makeNeonTesting()` or `neonTesting()` configuration. This automatically closes WebSocket connections when deleting test branches, preventing connection termination errors.
184
+ - close the connection yourself (e.g. `await pool.end()`)
185
+ - enable `autoCloseWebSockets` (WebSocket driver only, Vitest only)
186
+ - keep the branch with `deleteBranch: false`
187
+
188
+ [Neon's HTTP driver](https://neon.com/docs/serverless/serverless-driver#use-the-driver-over-http) and [Postgres.js](https://www.npmjs.com/package/postgres) close their own connections, so they need none of this.
163
189
 
164
190
  ### Examples
165
191
 
166
- - [Neon serverless WebSocket](examples/drivers/ws-neon.test.ts)
167
- - [Neon serverless WebSocket + Drizzle](examples/drivers/ws-neon-drizzle.test.ts)
168
- - [Neon serverless HTTP](examples/drivers/http-neon.test.ts)
169
- - [Neon serverless HTTP + Drizzle](examples/drivers/http-neon-drizzle.test.ts)
170
- - [node-postgres](examples/drivers/tcp-pg.test.ts)
171
- - [node-postgres + Drizzle](examples/drivers/tcp-pg-drizzle.test.ts)
172
- - [Postgres.js](examples/drivers/tcp-postgres.test.ts)
173
- - [Postgres.js + Drizzle](examples/drivers/tcp-postgres-drizzle.test.ts)
192
+ - [Neon serverless WebSocket](tests-vitest/drivers/ws-neon.test.ts)
193
+ - [Neon serverless WebSocket + Drizzle](tests-vitest/drivers/ws-neon-drizzle.test.ts)
194
+ - [Neon serverless HTTP](tests-vitest/drivers/http-neon.test.ts)
195
+ - [Neon serverless HTTP + Drizzle](tests-vitest/drivers/http-neon-drizzle.test.ts)
196
+ - [node-postgres](tests-vitest/drivers/tcp-pg.test.ts)
197
+ - [node-postgres + Drizzle](tests-vitest/drivers/tcp-pg-drizzle.test.ts)
198
+ - [Postgres.js](tests-vitest/drivers/tcp-postgres.test.ts)
199
+ - [Postgres.js + Drizzle](tests-vitest/drivers/tcp-postgres-drizzle.test.ts)
174
200
 
175
201
  ## Configuration
176
202
 
@@ -179,10 +205,10 @@ You configure Neon Testing in two places:
179
205
  - **Base settings** in `makeNeonTesting()`
180
206
  - **Optional overrides** when calling the returned function (e.g., `neonTesting()`)
181
207
 
182
- Configure these in `makeNeonTesting()` and optionally override per test file when calling the returned function.
208
+ Configure these in `makeNeonTesting()`; every option except `apiKey` can also be overridden per test file when calling the returned function.
183
209
 
184
210
  ```ts
185
- export interface NeonTestingOptions {
211
+ export interface MakeNeonTestingOptions {
186
212
  /**
187
213
  * The Neon API key, this is used to create and teardown test branches (required)
188
214
  *
@@ -224,6 +250,8 @@ export interface NeonTestingOptions {
224
250
  * Suppresses the specific Neon WebSocket "Connection terminated unexpectedly"
225
251
  * error that may surface when deleting a branch with open WebSocket
226
252
  * connections
253
+ *
254
+ * Vitest only.
227
255
  */
228
256
  autoCloseWebSockets?: boolean;
229
257
  /**
@@ -249,6 +277,21 @@ export interface NeonTestingOptions {
249
277
  * The database to connect to (default: project default database)
250
278
  */
251
279
  databaseName?: string;
280
+ /**
281
+ * Override the `sslmode` query param on the connection URI (default:
282
+ * undefined — URI is passed through unchanged)
283
+ *
284
+ * Neon's API returns URIs with `sslmode=require`. In pg v9 the meaning of
285
+ * `require` changes to libpq semantics (encrypt, but don't verify the CA).
286
+ *
287
+ * - `"verify-full"` — strict CA verification (silences the pg v9 warning)
288
+ * - `"require"` — preserves today's effective behavior under pg v9 by also
289
+ * setting `uselibpqcompat=true`
290
+ *
291
+ * Only affects drivers that parse `sslmode` (e.g. `pg`). The Neon
292
+ * serverless driver ignores it.
293
+ */
294
+ sslMode?: "verify-full" | "require";
252
295
  }
253
296
  ```
254
297
 
@@ -258,7 +301,7 @@ Configure the base settings in `makeNeonTesting()`:
258
301
 
259
302
  ```ts
260
303
  // neon-testing.ts
261
- import { makeNeonTesting } from "neon-testing";
304
+ import { makeNeonTesting } from "neon-testing/vitest";
262
305
 
263
306
  export const neonTesting = makeNeonTesting({
264
307
  apiKey: process.env.NEON_API_KEY!,
@@ -313,6 +356,20 @@ neonTesting({
313
356
  });
314
357
  ```
315
358
 
359
+ ### SSL mode
360
+
361
+ Neon returns URIs with `sslmode=require`. In pg v9 the meaning of `require` changes to libpq semantics (encrypt, but don't verify the CA). Use `sslMode` to pick the semantics you want:
362
+
363
+ ```ts
364
+ // Strict CA verification (silences the pg v9 deprecation warning) - recommended
365
+ neonTesting({ sslMode: "verify-full" });
366
+
367
+ // Preserve today's effective behavior under pg v9
368
+ neonTesting({ sslMode: "require" });
369
+ ```
370
+
371
+ Only affects drivers that parse `sslmode` (e.g. [`pg`](https://www.npmjs.com/package/pg)). The [Neon serverless driver](https://www.npmjs.com/package/@neondatabase/serverless) ignores it.
372
+
316
373
  ## Error handling
317
374
 
318
375
  ### Rate limiting
@@ -344,7 +401,9 @@ It's easy to run Neon integration tests in CI/CD pipelines:
344
401
 
345
402
  ## API Reference
346
403
 
347
- ### Main exports (`neon-testing`)
404
+ ### Runner entry (`neon-testing/vitest` or `neon-testing/bun`)
405
+
406
+ Both entries export the same `makeNeonTesting`; they differ only in which runner's `beforeAll`/`afterAll` hooks they wire up. (For other runners, `neon-testing/core` takes the hooks directly.)
348
407
 
349
408
  #### makeNeonTesting(options)
350
409
 
@@ -352,7 +411,7 @@ The factory function that creates a configured lifecycle function for your tests
352
411
 
353
412
  ```ts
354
413
  // neon-testing.ts
355
- import { makeNeonTesting } from "neon-testing";
414
+ import { makeNeonTesting } from "neon-testing/vitest";
356
415
 
357
416
  export const neonTesting = makeNeonTesting({
358
417
  apiKey: process.env.NEON_API_KEY!,
@@ -405,24 +464,11 @@ test("access branch information", () => {
405
464
 
406
465
  See the [Neon Branch API documentation](https://api-docs.neon.tech/reference/getprojectbranch) for all available properties.
407
466
 
408
- ### Vite plugin (`neon-testing/vite`)
409
-
410
- The Vite plugin clears any existing `DATABASE_URL` environment variable before tests run, ensuring tests use isolated test databases.
411
-
412
- ```ts
413
- import { defineConfig } from "vitest/config";
414
- import { neonTesting } from "neon-testing/vite";
415
-
416
- export default defineConfig({
417
- plugins: [neonTesting()],
418
- });
419
- ```
420
-
421
- **Options:**
467
+ ### Setup (`neon-testing/setup`)
422
468
 
423
- - `debug` (boolean, default: `false`) - Enable debug logging
469
+ A zero-config preload that clears `DATABASE_URL` before tests run, so a file that forgets to call `neonTesting()` can't reach a real database. Register it with your runner — Vitest `setupFiles` or Bun `bunfig` `preload` (see [Recommended usage](#recommended-usage)).
424
470
 
425
- This plugin is recommended but not required. Without it, tests might accidentally use your existing `DATABASE_URL` instead of isolated test databases.
471
+ Set `NEON_TESTING_DEBUG=true` to log when it clears a value.
426
472
 
427
473
  ### Utilities (`neon-testing/utils`)
428
474
 
package/package.json CHANGED
@@ -1,12 +1,14 @@
1
1
  {
2
2
  "name": "neon-testing",
3
- "version": "2.6.2",
4
- "description": "A Vitest utility for seamless integration tests with Neon Postgres",
3
+ "version": "3.0.0-beta.0",
4
+ "description": "A testing utility for seamless integration tests with Neon Postgres, for Vitest and Bun Test.",
5
5
  "keywords": [
6
6
  "neon",
7
7
  "postgres",
8
8
  "postgresql",
9
- "vitest"
9
+ "vitest",
10
+ "bun",
11
+ "testing"
10
12
  ],
11
13
  "author": "Mikael Lirbank",
12
14
  "license": "MIT",
@@ -15,60 +17,68 @@
15
17
  "bugs": "https://github.com/starmode-base/neon-testing/issues",
16
18
  "type": "module",
17
19
  "exports": {
18
- ".": {
19
- "types": "./dist/index.d.ts",
20
- "import": "./dist/index.js"
21
- },
22
- "./utils": {
23
- "types": "./dist/utils.d.ts",
24
- "import": "./dist/utils.js"
25
- },
26
- "./vite": {
27
- "types": "./dist/vite-plugin.d.ts",
28
- "import": "./dist/vite-plugin.js"
29
- }
20
+ "./core": "./src/core.ts",
21
+ "./vitest": "./src/vitest.ts",
22
+ "./bun": "./src/bun.ts",
23
+ "./utils": "./src/utils.ts",
24
+ "./setup": "./src/setup.ts"
30
25
  },
31
26
  "files": [
32
- "dist"
27
+ "src",
28
+ "!src/**/*.test.ts"
33
29
  ],
30
+ "engines": {
31
+ "node": ">=22"
32
+ },
34
33
  "scripts": {
35
- "dev": "tsc -p tsconfig.build.json --watch",
36
- "build": "rm -rf dist && tsc -p tsconfig.build.json && tsc && prettier --check . && vitest run",
34
+ "dev": "tsc --watch",
35
+ "check": "prettier --check . && tsc && bun run check:drift && bun run test",
36
+ "check:drift": "diff -r -x neon-testing.ts tests-bun tests-vitest",
37
37
  "format": "prettier --write .",
38
- "test": "vitest",
38
+ "test": "vitest run && bun test",
39
+ "test:unit": "vitest run src",
40
+ "test:unit:watch": "vitest src",
41
+ "test:examples": "vitest run examples",
42
+ "test:examples:watch": "vitest examples",
43
+ "test:vitest": "vitest run tests-vitest",
44
+ "test:vitest:watch": "vitest tests-vitest",
45
+ "test:bun": "bun test",
46
+ "test:bun:watch": "bun test --watch",
39
47
  "skills:update": "bunx skills add neondatabase/agent-skills",
40
- "clean:soft": "rm -rf node_modules dist && bun install",
41
- "clean:hard": "rm -rf node_modules dist bun.lock && bun install",
42
- "release:patch": "bun pm version patch",
43
- "release:minor": "bun pm version minor",
44
- "release:major": "bun pm version major",
45
- "release:beta": "bun pm version prerelease --preid=beta",
46
- "release:beta:patch": "bun pm version prepatch --preid=beta",
47
- "release:beta:minor": "bun pm version preminor --preid=beta",
48
- "release:beta:major": "bun pm version premajor --preid=beta",
48
+ "clean:soft": "rm -rf node_modules && bun install",
49
+ "clean:hard": "rm -rf node_modules bun.lock && bun install",
50
+ "release:patch": "bun pm version patch --message 'release: v%s'",
51
+ "release:minor": "bun pm version minor --message 'release: v%s'",
52
+ "release:major": "bun pm version major --message 'release: v%s'",
53
+ "release:beta": "bun pm version prerelease --preid=beta --message 'release: v%s'",
54
+ "release:beta:patch": "bun pm version prepatch --preid=beta --message 'release: v%s'",
55
+ "release:beta:minor": "bun pm version preminor --preid=beta --message 'release: v%s'",
56
+ "release:beta:major": "bun pm version premajor --preid=beta --message 'release: v%s'",
57
+ "preversion": "test \"$(git branch --show-current)\" = main && git pull --ff-only",
49
58
  "postversion": "git push --follow-tags"
50
59
  },
51
60
  "dependencies": {
52
- "@neondatabase/api-client": "^2.7.1"
61
+ "@neondatabase/api-client": "2.7.1"
53
62
  },
54
63
  "peerDependencies": {
55
- "vite": "^7",
56
64
  "vitest": "^3 || ^4"
57
65
  },
66
+ "peerDependenciesMeta": {
67
+ "vitest": {
68
+ "optional": true
69
+ }
70
+ },
58
71
  "devDependencies": {
59
- "@neondatabase/serverless": "^1.0.2",
72
+ "@neondatabase/serverless": "^1.1.0",
73
+ "@types/bun": "^1.3.14",
60
74
  "@types/pg": "^8.20.0",
61
75
  "dotenv": "^17.4.2",
62
76
  "drizzle-orm": "^0.45.2",
63
- "pg": "^8.20.0",
77
+ "pg": "^8.21.0",
64
78
  "postgres": "^3.4.9",
65
- "prettier": "^3.8.2",
79
+ "prettier": "^3.8.4",
66
80
  "tiny-invariant": "^1.3.3",
67
- "typescript": "^5.9.3",
68
- "vite": "^7.3.2",
69
- "vitest": "^4.1.4"
70
- },
71
- "browser": {
72
- "./dist/vite-plugin.js": "./dist/browser-empty.js"
81
+ "typescript": "^6.0.3",
82
+ "vitest": "^4.1.9"
73
83
  }
74
84
  }
package/src/bun.ts ADDED
@@ -0,0 +1,13 @@
1
+ /// <reference types="bun" />
2
+ import { beforeAll, afterAll } from "bun:test";
3
+ import { makeNeonTestingCore } from "./core";
4
+ import type { MakeNeonTestingOptions } from "./core";
5
+
6
+ export type { MakeNeonTestingOptions, NeonTestingOptions } from "./core";
7
+
8
+ /**
9
+ * Create a Neon test-branch factory wired to Bun's lifecycle hooks.
10
+ */
11
+ export function makeNeonTesting(options: MakeNeonTestingOptions) {
12
+ return makeNeonTestingCore({ ...options, hooks: { beforeAll, afterAll } });
13
+ }