Skip to main content
doc0blade47/drizzle-ormdocumentation home
Sign in

Integration Test Harness

Last updated Oct 12, 2026100% grounded
Relevant source files

The following files were used as context for generating this wiki page:

Overview

The integration test harness coordinates multi-dialect validation suites across local environments and continuous integration pipelines, verifying database driver behavior, schema migrations, and query execution semantics. By combining Vitest runner configurations, AWS SST infrastructure fixtures, and multi-dialect snapshot journals, the suite validates database interactions across SQLite, PostgreSQL, MySQL, SingleStore, and Gel.

Sources: integration-tests/vitest.config.ts:6-24, integration-tests/package.json:74-74, integration-tests/drizzle2/sqlite/meta/_journal.json:1-13

Vitest runner configuration across environments

Local and CI configuration structures

The integration test suite utilizes distinct Vitest runner configurations for local execution and continuous integration environments. Local runs are governed by integration-tests/vitest.config.ts, which loads environment variables via dotenv/config and resolves TypeScript path mappings through vite-tsconfig-paths. The local configuration explicitly defines inclusion globs covering relational tests, dialect-specific test suites, driver initializations, and vector or spatial extensions.

test: {
	include: [
		'tests/seeder/**/*.test.ts',
		'tests/extensions/postgis/**/*',
		'tests/relational/**/*.test.ts',
		'tests/pg/**/*.test.ts',
		'tests/mysql/**/*.test.ts',
		'tests/singlestore/**/*.test.ts',
		'tests/sqlite/**/*.test.ts',
		'tests/replicas/**/*',
		'tests/imports/**/*',
		'tests/extensions/vectors/**/*',
		'tests/version.test.ts',
		'tests/pg/node-postgres.test.ts',
		'tests/utils/is-config.test.ts',
		'js-tests/driver-init/commonjs/*.test.cjs',
		'js-tests/driver-init/module/*.test.mjs',
		'tests/gel/**/*.test.ts',
	],

Sources: integration-tests/vitest.config.ts:6-24

Note

When SKIP_EXTERNAL_DB_TESTS is active in the environment, local execution automatically filters out tests requiring remote or external database services such as PlanetScale, Neon, TiDB, LibSQL, and Vercel.

Continuous integration runs are directed by integration-tests/vitest-ci.config.ts, which omits the verbose include and exclude pattern arrays to streamline execution while retaining core test timeouts, single-thread pool options, and type checking constraints.

export default defineConfig({
	test: {
		typecheck: {
			tsconfig: 'tsconfig.json',
		},
		testTimeout: 100000,
		hookTimeout: 200000,
		isolate: true,
		poolOptions: {
			threads: {
				singleThread: true,
			},
		},
		maxWorkers: 1,
		fileParallelism: false,
	},

Sources: integration-tests/vitest-ci.config.ts:5-20

Execution parameter matrix

Both local and CI runner configurations enforce strict concurrency controls and execution boundaries to prevent race conditions against shared or local database instances. The parameter configuration defines explicit timeouts, worker limits, and isolation rules.

ParameterConfiguration KeyValuePurpose
Test TimeouttestTimeout100000Maximum execution time in milliseconds allotted to an individual test case.
Hook TimeouthookTimeout200000Maximum execution time in milliseconds allotted to setup and teardown hooks.
Test IsolationisolatetrueEnsures test files run in isolated environments to avoid state leakage.
Single ThreadpoolOptions.threads.singleThreadtrueForces test execution onto a single thread within the pool.
Max WorkersmaxWorkers1Restricts parallel worker processes to prevent database connection contention.
File ParallelismfileParallelismfalseDisables concurrent test file execution across workers.

Sources: integration-tests/vitest.config.ts:70-83, integration-tests/vitest-ci.config.ts:7-19

Infrastructure provisioning with SST fixtures

Cloud stack orchestration and AWS Postgres configuration

The integration test suite utilizes SST (Serverless Stack) to orchestrate cloud infrastructure stacks for serverless database validation. The configuration file integration-tests/sst.config.ts includes a triple-slash reference to ./.sst/platform/config.d.ts for type safety and is exported via the $config function block.

// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference path="./.sst/platform/config.d.ts" />
 
export default $config({
	app(_input) {
		return {
			name: 'awsdataapi',
			removal: 'remove',
			home: 'aws',
		};
	},
	async run() {
		new sst.aws.Postgres('Postgres', {
			scaling: {
				min: '0.5 ACU',
				max: '1 ACU',
			},
		});
	},

Sources: integration-tests/sst.config.ts:1-19

Configuration PropertyTarget Value / SettingContext
App NameawsdataapiDefined within the app hook callback.
Removal PolicyremoveSpecifies stack teardown behavior upon destruction.
Home ProviderawsDesignates AWS as the infrastructure provider.
Postgres Resource IDPostgresInstantiated via new sst.aws.Postgres('Postgres', ...).
Minimum ACU0.5 ACUServerless scaling lower bound for the Postgres instance.
Maximum ACU1 ACUServerless scaling upper bound for the Postgres instance.

Sources: integration-tests/sst.config.ts:4-19

Note

The serverless PostgreSQL resource scales dynamically between 0.5 and 1 Aurora Capacity Units (ACU) to accommodate AWS Data API integration tests without maintaining idle compute overhead.

Generated environment bindings

Environment binding synchronization for the SST stack is managed through generated type definition files. The file integration-tests/sst-env.d.ts establishes type references for runtime resource bindings generated during stack deployment.

// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference path="./.sst/types.generated.ts" />

Sources: integration-tests/sst-env.d.ts:1-2

Warning

Manual modifications to sst-env.d.ts will be overwritten when SST generates new environment type definitions from the active stack state.

Cross dialect migration journal fixtures

Migration journal schema and dialect variants

Integration tests validate schema change tracking and snapshot generation by utilizing multi-dialect migration journal fixtures. Each migration journal is defined inside a meta/_journal.json configuration file, specifying the schema metadata version, target SQL dialect, and sequential entries detailing individual migration steps. The journal format records metadata such as transaction timestamps, unique tags, and breakpoint configurations.

{
  "version": "5",
  "dialect": "sqlite",
  "entries": [
    {
      "idx": 0,
      "version": "5",
      "when": 1680202256473,
      "tag": "0000_fancy_bug",
      "breakpoints": true
    }
  ]

Sources: integration-tests/drizzle2/sqlite/meta/_journal.json:1-12

The migration journals capture differences across database engines. For example, PostgreSQL journal configurations accommodate single and multi-step migration histories, whereas SQLite and SingleStore maintain target-specific format versions.

{
  "version": "5",
  "dialect": "pg",
  "entries": [
    {
      "idx": 0,
      "version": "5",
      "when": 1680271923328,
      "tag": "0000_puzzling_flatman",
      "breakpoints": true
    },
    {
      "idx": 1,
      "version": "5",
      "when": 1680271923329,
      "tag": "0001_test",
      "breakpoints": true
    }
  ]

Sources: integration-tests/drizzle2/pg/meta/_journal.json:1-19

DialectJournal File PathVersionEntry CountDialect Identifier
SQLiteintegration-tests/drizzle2/sqlite/meta/_journal.json51sqlite
PostgreSQLintegration-tests/drizzle2/pg/meta/_journal.json52pg
SingleStoreintegration-tests/drizzle2/singlestore/meta/_journal.json11singlestore
PostgreSQL Proxyintegration-tests/drizzle2/pg-proxy/first/meta/_journal.json51pg

Sources: integration-tests/drizzle2/sqlite/meta/_journal.json:1-12, integration-tests/drizzle2/pg/meta/_journal.json:1-19, integration-tests/drizzle2/singlestore/meta/_journal.json:1-13, integration-tests/drizzle2/pg-proxy/first/meta/_journal.json:1-13

Proxy configurations and isolated entrysets

Proxy integration tests use specialized journal directories such as pg-proxy/first/meta/_journal.json to validate driver-agnostic query and migration proxy layers. These proxy setups mirror standard PostgreSQL version schemas while restricting entrysets to initial baseline migrations.

{
  "version": "5",
  "dialect": "pg",
  "entries": [
    {
      "idx": 0,
      "version": "5",
      "when": 1680271923328,
      "tag": "0000_puzzling_flatman",
      "breakpoints": true
    }
  ]
}

Sources: integration-tests/drizzle2/pg-proxy/first/meta/_journal.json:1-13

Note

SingleStore migration journals specify format version 1 and dialect identifier singlestore, differing from the version 5 format utilized across PostgreSQL and SQLite fixtures.

Caution

Altering migration entry indices (idx) or timestamp values (when) within active journal fixtures causes migration parser validation checks to fail during test harness startup.

In memory SQLite and embedded PostgreSQL execution

SQLite driver instantiation across runtimes

SQLite test harnesses instantiate local in-memory databases by invoking engine-specific constructors, such as Database from better-sqlite3 or Database from bun:sqlite, paired with the ':memory:' connection string. These client instances are passed directly to dialect-specific initialization helpers like drizzleBetterSqlite3, drizzleBun, drizzleD1, and durableSqlite to construct fully typed database instances for test execution and seeding utilities.

import Database from 'better-sqlite3';
import { Database as BunDatabase } from 'bun:sqlite';
import { drizzle as drizzleBetterSqlite3 } from '~/better-sqlite3/index.ts';
import { drizzle as drizzleBun } from '~/bun-sqlite/index.ts';
import { drizzle as drizzleD1 } from '~/d1/index.ts';
import { drizzle as durableSqlite } from '~/durable-sqlite/index.ts';
 
const client = new Database(':memory:');
const bunClient = new BunDatabase(':memory:');
declare const d1: D1Database;
declare const durableSql: DurableObjectStorage;
 
export const db = drizzleBetterSqlite3(client);
export const bunDb = drizzleBun(bunClient);
export const d1Db = drizzleD1(d1);
export const durableSqliteDb = durableSqlite(durableSql);

Sources: drizzle-orm/type-tests/sqlite/db.ts:1-16

Tip

SQLite seeding utilities support both standard table definitions and foreign key relational references using in-memory connections, allowing rapid fixture resets via reset and seed function calls.

Sources: drizzle-seed/type-tests/sqlite.ts:1-17

Embedded PGlite driver and session configuration

Embedded PostgreSQL execution relies on the PgliteDriver class and the @electric-sql/pglite package to spin up zero-dependency PostgreSQL instances within test environments. The drizzle entry point handles multiple parameter overload signatures, accepting either an existing PGlite client instance, a connection string, a data directory path with options, or a configuration object containing logger and cache parameters.

export function drizzle<
	TSchema extends Record<string, unknown> = Record<string, never>,
	TClient extends PGlite = PGlite,
>(
	...params:
		| []
		| [
			TClient | string,
		]
		| [
			TClient | string,
			DrizzleConfig<TSchema>,
		]
		| [
			(
				& DrizzleConfig<TSchema>
				& ({
					connection?: (PGliteOptions & { dataDir?: string }) | string;
				} | {
					client: TClient;
				})
			),
		]
): PgliteDatabase<TSchema> & {
	$client: TClient;
} {
	if (params[0] === undefined || typeof params[0] === 'string') {
		const instance = new PGlite(params[0]);
		return construct(instance, params[1]) as any;
	}
 
	if (isConfig(params[0])) {
		const { connection, client, ...drizzleConfig } = params[0] as {
			connection?: PGliteOptions & { dataDir: string };
			client?: TClient;
		} & DrizzleConfig<TSchema>;
 
		if (client) return construct(client, drizzleConfig) as any;
 
		if (typeof connection === 'object') {
			const { dataDir, ...options } = connection;
 
			const instance = new PGlite(dataDir, options);
 
			return construct(instance, drizzleConfig) as any;
		}
 
		const instance = new PGlite(connection);
 
		return construct(instance, drizzleConfig) as any;
	}
 
	return construct(params[0] as TClient, params[1] as DrizzleConfig<TSchema> | undefined) as any;
}

Sources: drizzle-orm/src/pglite/driver.ts:98-151

The internal construct function initializes the PostgreSQL dialect with optional casing configurations, parses user-provided loggers and schema definitions using extractTablesRelationalConfig, and attaches client reference properties $client and $cache to the resulting PgliteDatabase instance.

function construct<TSchema extends Record<string, unknown> = Record<string, never>>(
	client: PgliteClient,
	config: DrizzleConfig<TSchema> = {},
): PgliteDatabase<TSchema> & {
	$client: PgliteClient;
} {
	const dialect = new PgDialect({ casing: config.casing });
	let logger;
	if (config.logger === true) {
		logger = new DefaultLogger();
	} else if (config.logger !== false) {
		logger = config.logger;
	}
 
	let schema: RelationalSchemaConfig<TablesRelationalConfig> | undefined;
	if (config.schema) {
		const tablesConfig = extractTablesRelationalConfig(
			config.schema,
			createTableRelationsHelpers,
		);
		schema = {
			fullSchema: config.schema,
			schema: tablesConfig.tables,
			tableNamesMap: tablesConfig.tableNamesMap,
		};
	}
 
	const driver = new PgliteDriver(client, dialect, { logger, cache: config.cache });
	const session = driver.createSession(schema);
	const db = new PgliteDatabase(dialect, session, schema as any) as PgliteDatabase<TSchema>;
	(<any> db).$client = client;
	(<any> db).$cache = config.cache;
	if ((<any> db).$cache) {
		(<any> db).$cache['invalidate'] = config.cache?.onMutate;
	}
	// (<any> db).$cache = { invalidate: (<any> config).cache?.onMutate };
	// if (config.cache) {
	// 	for (
	// 		const key of Object.getOwnPropertyNames(Object.getPrototypeOf(config.cache)).filter((key) =>
	// 			key !== 'constructor'
	// 		)
	// 	) {
	// 		(<any> db).$cache[key as keyof typeof config.cache] = (<any> config).cache[key];
	// 	}
	// }
 
	return db as any;
}

Sources: drizzle-orm/src/pglite/driver.ts:49-96

Overload SignaturePrimary Parameter TypeDescription
Client or StringTClient | string | undefinedInstantiates a new PGlite with an optional connection string or data path.
Configuration ObjectDrizzleConfig & (connection | client)Configures PGlite using explicit connection options or a passed client instance.
Mock InstanceDrizzleConfig via drizzle.mock()Returns a mock database instance where $client is marked as unavailable.

Sources: drizzle-orm/src/pglite/driver.ts:98-160

Warning

Calling drizzle.mock() provides a database instance without an active client connection, returning the string literal '\\$client is not available on drizzle.mock()' for any access to the $client property.

SingleStore connection pooling and query execution

Connection pool instantiation and session setup

SingleStore integration tests establish database connections and connection pools by utilizing the mysql2/promise package. The test harness creates a connection pool through the createPool function and passes the resulting pool object into the drizzle factory function to construct a typed SingleStore database instance for query execution.

import { createPool } from 'mysql2/promise';
import { drizzle } from '~/singlestore/index.ts';
 
const pool = createPool({});
 
export const db = drizzle(pool);
 

Sources: drizzle-orm/type-tests/singlestore/db.ts:1-7

The drizzle function accepts various configuration combinations, including passing the pool directly, providing a schema object alongside the pool, or supplying empty options configurations during initialization.

{
	drizzle(pool);
	drizzle(pool, { schema: {} });
	drizzle(pool, { schema: {} });
	drizzle(pool, {});
}

Sources: drizzle-orm/type-tests/singlestore/db.ts:8-13

Note

SingleStore database instances support optional schema definitions passed via the initialization configuration object to bind tables directly to targeted named schemas.

Dialect query lifecycle and locking modifiers

Query execution test suites validate complex join operations, subqueries, and table aliasing across the SingleStore dialect. Queries support explicit locking clauses such as .for('update') and .for('share'), with configuration options including noWait and skipLocked flags.

await db.select().from(users).for('update');
await db.select().from(users).for('share', { skipLocked: true });
await db.select().from(users).for('update', { noWait: true });

Sources: drizzle-orm/type-tests/singlestore/select.ts:615-617

Locking ClauseModifier OptionDescription
for('update')NoneLocks selected rows for update operations.
for('share'){ skipLocked: true }Shares selected rows while skipping locked records.
for('update'){ noWait: true }Attempts to lock rows for update without waiting for locks to release.

Sources: drizzle-orm/type-tests/singlestore/select.ts:615-617

Caution

Combining both noWait and skipLocked within the same locking modifier options object triggers a type-level compilation error to prevent conflicting locking behaviors.

/* await db
	.select()
	.from(users)
	// @ts-expect-error - can't use both skipLocked and noWait
	.for('share', { noWait: true, skipLocked: true });

Sources: drizzle-orm/type-tests/singlestore/select.ts:619-623

Ecosystem package test harnesses

Schema validation and seeding test parameters

Test configuration parity across ecosystem packages is maintained through dedicated Vitest runner settings in drizzle-zod, drizzle-typebox, drizzle-valibot, drizzle-arktype, and drizzle-seed. Schema validator packages exclude runtime bun-specific test folders (tests/bun/**/*) while configuring test timeouts to 100000 milliseconds, hook timeouts to 100000 milliseconds, and running tests with isolate: false and singleThread: true via thread pool options.

test: {
	include: [
		'tests/**/*.test.ts',
	],
	exclude: [
		'tests/bun/**/*',
	],
	typecheck: {
		tsconfig: 'tsconfig.json',
	},
	testTimeout: 100000,
	hookTimeout: 100000,
	isolate: false,
	poolOptions: {
		threads: {
			singleThread: true,
		},
	},
},

Sources: drizzle-zod/vitest.config.ts:5-23

Package ConfigurationTest Isolation (isolate)Thread Mode (singleThread)Test Timeout (ms)Excluded Patterns
drizzle-zodfalsetrue100000tests/bun/**/*
drizzle-typeboxfalsetrue100000tests/bun/**/*
drizzle-valibotfalsetrue100000tests/bun/**/*
drizzle-arktypefalsetrue100000tests/bun/**/*
drizzle-seedtruetrue100000None

Sources: drizzle-seed/vitest.config.ts:4-24, drizzle-arktype/vitest.config.ts:5-23, drizzle-valibot/vitest.config.ts:5-23, drizzle-typebox/vitest.config.ts:5-23, drizzle-zod/vitest.config.ts:5-23

Note

drizzle-seed enforces strict test isolation (isolate: true) across postgres, mysql, and sqlite test directories while explicitly setting maxWorkers: 1 and fileParallelism: false.

Linting tool verification and path resolution

The eslint-plugin-drizzle test suite relies on a simplified Vitest setup enabling global test APIs and excluding **/dist/** build output paths. Meanwhile, parser configurations across drizzle-kit, drizzle-arktype, drizzle-valibot, drizzle-typebox, and drizzle-zod utilize vite-tsconfig-paths plugins to map internal path aliases directly against local tsconfig.json definitions.

import { defineConfig } from 'vitest/config';
 
export default defineConfig({
	test: {
		globals: true,
		exclude: ['**/dist/**'],
	},

Sources: eslint-plugin-drizzle/vitest.config.ts:1-7

Warning

Omitting vite-tsconfig-paths plugin registration in ecosystem package test files causes module resolution failures when test suites import internal workspace dependencies using path aliases.

Was this page helpful?