Testing
A test suite needs a database that matches the app's: the same extensions, the same schema, the same seed. nuxt-pglite/testing builds one from your server config, init included, so migrations applied from init with applyMigrations are applied here too. It lives in memory, so nothing of the app's data directory is touched, and it works with vitest, @nuxt/test-utils or any other runner.
import { afterAll, beforeAll, expect, it } from 'vitest'
import { createTestDatabase } from 'nuxt-pglite/testing'
import type { TestDatabase } from 'nuxt-pglite/testing'
let db: TestDatabase
beforeAll(async () => {
db = await createTestDatabase({ config: 'server/pglite.config' })
})
afterAll(() => db.close())
it('stores a todo', async () => {
await db.pg.query('INSERT INTO todos (title) VALUES ($1)', ['first'])
const { rows } = await db.pg.query('SELECT title FROM todos')
expect(rows).toEqual([{ title: 'first' }])
})
db.pg is the PGlite instance, after init has run. close() runs the config's dispose, then closes everything the database opened: its forks, its socket and the instance.
One database can serve a whole suite, or be forked per test so that each test starts from the same data. For a whole vitest run behind one URL, see vitest.
Options
const db = await createTestDatabase({
config: 'server/pglite.config', // or the config object itself
alias: {}, // import aliases the config file uses, see below
dataDir: 'memory://', // whatever the config says
socket: false, // `true`, or the socket's options, to serve it over a URL
exportEnv: true, // when `socket` is on: set its variables on `process.env`
})
| Option | Type | Default | |
|---|---|---|---|
config | PGliteConfig | string | {} | The app's server config, or the path of its file. $test overrides apply. |
alias | Record<string, string> | Import aliases a config path may use, name to absolute path, as nuxt.options.alias holds them. See Config files. | |
dataDir | string | 'memory://' | Replaces the config's dataDir. The config's fs is dropped too, since it would hold the app's own data directory. |
socket | boolean | TestSocketOptions | false | Serves the database over the Postgres wire protocol: true for a free loopback port. See Through the socket. |
exportEnv | boolean | true when socket is on | Sets the socket's variables on process.env while the database is open, those still unset only. |
Passed as an object, config types db.pg with its extensions; loaded from a path, it cannot.
Config files
A config path is loaded with loadPGliteConfig(path, { alias }), also exported, the way the module loads it:
- relative to
process.cwd(), extension optional; - imported through jiti, so TypeScript works on any runtime, and fresh on every call;
- with
definePGliteServerConfigprovided as a global while the file is imported, so a file written for the auto-import works unchanged; - with the
$testoverrides applied, and$development/$productionignored.
export default definePGliteServerConfig({
init: async (pg) => {
await pg.exec('CREATE TABLE IF NOT EXISTS todos (id serial PRIMARY KEY, title text NOT NULL)')
},
$test: {
debug: 1, // a shallow override, applied in tests only
},
})
Outside Nuxt the app's aliases (~~, #pglite/migrations, …) are not defined, so a file importing through one fails to load. Either import from nuxt-pglite/migrations in the file, which resolves anywhere, or pass the aliases as alias, name to absolute path:
import { fileURLToPath } from 'node:url'
const db = await createTestDatabase({
config: 'server/pglite.config',
alias: {
'#pglite/migrations': fileURLToPath(import.meta.resolve('nuxt-pglite/migrations')),
},
})
The paths of .nuxt/tsconfig.json list the others.
Through the socket
Code that connects through a URL, rather than receiving pg, reaches the database over the Postgres wire protocol with socket: true for a free loopback port, or the module's socket options but devtoolsActions (port, env, provider, …), plus the server's own user, database and logger.
const db = await createTestDatabase({ config: 'server/pglite.config', socket: true })
db.url // postgres://postgres@127.0.0.1:<port>/postgres
db.env // { DATABASE_URL: db.url }
db.env holds the variables the socket resolves, as in nuxt dev: DATABASE_URL by default, NETLIFY_DB_URL and NETLIFY_DB_DRIVER with provider: 'netlify', env merged over them. They are set on process.env while the database is open, unless exportEnv: false, and unset on close().
DATABASE_URL already in the environment, from your shell or a CI job, code reading it reaches that database rather than the test one. db.env always holds the test database's values, exported or not: pass it on explicitly when that matters.