CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-testcontainers--mysql

MySQL module for Testcontainers that enables programmatic creation and management of ephemeral MySQL database containers for testing Node.js applications.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

Testcontainers MySQL

Testcontainers MySQL is a specialized module that provides a fluent API for programmatically creating and managing ephemeral MySQL database containers for testing Node.js applications. It extends the base Testcontainers library with MySQL-specific configuration and connection management capabilities.

Package Information

  • Package Name: @testcontainers/mysql
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @testcontainers/mysql

Core Imports

import { MySqlContainer, StartedMySqlContainer } from "@testcontainers/mysql";

For CommonJS:

const { MySqlContainer, StartedMySqlContainer } = require("@testcontainers/mysql");

Basic Usage

import { MySqlContainer } from "@testcontainers/mysql";
import { createConnection } from "mysql2/promise";

// Start a MySQL container with default settings
await using container = await new MySqlContainer("mysql:8.0").start();

// Connect using mysql2 client
const client = await createConnection({
  host: container.getHost(),
  port: container.getPort(),
  database: container.getDatabase(),
  user: container.getUsername(),
  password: container.getUserPassword(),
});

// Execute queries
const [rows] = await client.execute("SELECT 1 as result");
console.log(rows); // [{ result: 1 }]

await client.end();
// Container automatically disposed with 'await using'

Architecture

The module consists of two main classes:

  • MySqlContainer: Extends GenericContainer from testcontainers, providing MySQL-specific configuration methods in a fluent builder pattern
  • StartedMySqlContainer: Extends AbstractStartedContainer from testcontainers, representing a running container with access to MySQL-specific connection details and query execution

The module automatically configures MySQL environment variables, exposes port 3306, and provides convenient methods for obtaining connection details.

Capabilities

Container Configuration

Configure and start a MySQL container with custom settings.

class MySqlContainer extends GenericContainer {
  /**
   * Create a new MySQL container configuration
   * @param image - Docker image name (e.g., "mysql:8.0", "mysql:5.7")
   */
  constructor(image: string);

  /**
   * Set the MySQL database name to be created
   * @param database - Database name (default: "test")
   * @returns this for method chaining
   */
  withDatabase(database: string): this;

  /**
   * Set the MySQL username
   * @param username - Username for the MySQL user (default: "test")
   * @returns this for method chaining
   */
  withUsername(username: string): this;

  /**
   * Set the MySQL user password
   * @param userPassword - Password for the MySQL user (default: "test")
   * @returns this for method chaining
   */
  withUserPassword(userPassword: string): this;

  /**
   * Set the MySQL root password
   * @param rootPassword - Root user password (default: "test")
   * @returns this for method chaining
   */
  withRootPassword(rootPassword: string): this;

  /**
   * Start the MySQL container
   * @returns Promise resolving to a started container instance
   */
  start(): Promise<StartedMySqlContainer>;
}

Usage Examples:

// Custom database configuration
await using container = await new MySqlContainer("mysql:8.0")
  .withDatabase("myapp_test")
  .withUsername("app_user")
  .withUserPassword("secret123")
  .withRootPassword("rootsecret")
  .start();

// Use URI-based connection
const connectionUri = container.getConnectionUri();
// mysql://app_user:secret123@localhost:32768/myapp_test

Inherited Configuration Methods

MySqlContainer inherits extensive configuration capabilities from GenericContainer:

interface GenericContainer {
  /** Configure exposed ports */
  withExposedPorts(...ports: number[]): this;

  /** Set startup timeout in milliseconds (default for MySQL: 120000) */
  withStartupTimeout(startupTimeout: number): this;

  /** Set additional environment variables */
  withEnvironment(environment: Record<string, string>): this;

  /** Configure wait strategy before considering container ready */
  withWaitStrategy(waitStrategy: WaitStrategy): this;

  /** Set network mode */
  withNetworkMode(networkMode: string): this;

  /** Copy files to container before start */
  withCopyFilesToContainer(filesToCopy: FileToCopy[]): this;

  /** Set container command */
  withCommand(command: string[]): this;

  /** Set container entrypoint */
  withEntrypoint(entrypoint: string[]): this;

  /** Configure bind mounts */
  withBindMounts(bindMounts: BindMount[]): this;

  /** Configure tmpfs mounts */
  withTmpFs(tmpFs: TmpFs): this;

  /** Configure container health check */
  withHealthCheck(healthCheck: HealthCheck): this;

  /** Set log consumer for container output */
  withLogConsumer(consumer: (stream: Readable) => unknown): this;

  /** Set container user */
  withUser(user: string): this;

  /** Set working directory */
  withWorkingDir(workingDir: string): this;

  /** Enable privileged mode */
  withPrivilegedMode(): this;

  /** Set container labels */
  withLabels(labels: Labels): this;

  /** Set container name */
  withName(name: string): this;

  /** Enable container reuse across test runs */
  withReuse(): this;

  /** Enable automatic container removal after stop (default behavior) */
  withAutoRemove(): this;

  /** Set image pull policy */
  withPullPolicy(pullPolicy: ImagePullPolicy): this;
}

Connection Information Access

Retrieve connection details from a started MySQL container.

class StartedMySqlContainer extends AbstractStartedContainer {
  /**
   * Get the host port mapped to MySQL's internal port 3306
   * @returns The mapped port number
   */
  getPort(): number;

  /**
   * Get the database name
   * @returns Database name
   */
  getDatabase(): string;

  /**
   * Get the MySQL username
   * @returns Username
   */
  getUsername(): string;

  /**
   * Get the MySQL user password
   * @returns User password
   */
  getUserPassword(): string;

  /**
   * Get the MySQL root password
   * @returns Root password
   */
  getRootPassword(): string;

  /**
   * Generate a MySQL connection URI
   * @param isRoot - If true, use root credentials; if false, use user credentials (default: false)
   * @returns Connection URI in format mysql://user:password@host:port/database
   */
  getConnectionUri(isRoot?: boolean): string;
}

Usage Examples:

await using container = await new MySqlContainer("mysql:8.0")
  .withDatabase("testdb")
  .withUsername("testuser")
  .withUserPassword("testpass")
  .start();

// Individual connection details
const host = container.getHost();
const port = container.getPort();
const database = container.getDatabase();
const username = container.getUsername();
const password = container.getUserPassword();

// Full connection URI
const userUri = container.getConnectionUri(); // Uses user credentials
const rootUri = container.getConnectionUri(true); // Uses root credentials

Query Execution

Execute SQL queries directly within the container using the MySQL CLI.

class StartedMySqlContainer {
  /**
   * Execute a SQL query inside the container using MySQL CLI
   * @param query - SQL query to execute
   * @param additionalFlags - Optional additional CLI flags (default: [])
   * @param isRoot - If true, execute as root user; if false, use configured user (default: false)
   * @returns Promise resolving to query output as string
   * @throws Error if query execution fails (non-zero exit code)
   */
  executeQuery(
    query: string,
    additionalFlags?: string[],
    isRoot?: boolean
  ): Promise<string>;
}

Usage Examples:

await using container = await new MySqlContainer("mysql:8.0").start();

// Basic query execution
const result = await container.executeQuery("SELECT 1 as result");
// Output: "result\n1\n"

// Execute with additional CLI flags
const jsonResult = await container.executeQuery(
  "SELECT * FROM users",
  ["--json"]
);

// Execute as root user for admin operations
const adminResult = await container.executeQuery(
  "SHOW DATABASES",
  [],
  true
);

// Error handling
try {
  await container.executeQuery("INVALID SQL");
} catch (error) {
  console.error("Query failed:", error.message);
}

Container Lifecycle Management

Manage the container lifecycle with inherited methods from AbstractStartedContainer.

class StartedMySqlContainer {
  /**
   * Stop the container
   * @param options - Optional stop options
   * @returns Promise resolving to stopped container
   */
  stop(options?: Partial<StopOptions>): Promise<StoppedTestContainer>;

  /**
   * Restart the container
   * @param options - Optional restart options
   * @returns Promise that resolves when restart completes
   */
  restart(options?: Partial<RestartOptions>): Promise<void>;

  /**
   * Get the container host address
   * @returns Host address (typically "localhost")
   */
  getHost(): string;

  /**
   * Get the container hostname
   * @returns Container hostname
   */
  getHostname(): string;

  /**
   * Get the container ID
   * @returns Docker container ID
   */
  getId(): string;

  /**
   * Get the container name
   * @returns Container name
   */
  getName(): string;

  /**
   * Get container labels
   * @returns Container labels object
   */
  getLabels(): Labels;

  /**
   * Async disposal for use with 'await using' syntax
   */
  [Symbol.asyncDispose](): Promise<void>;
}

Usage Examples:

// Manual lifecycle management
const container = await new MySqlContainer("mysql:8.0").start();

// Use the container
const client = await createConnection({
  host: container.getHost(),
  port: container.getPort(),
  database: container.getDatabase(),
  user: container.getUsername(),
  password: container.getUserPassword(),
});

// Restart the container
await container.restart();

// Manual cleanup
await container.stop();

// Automatic disposal (recommended)
await using container2 = await new MySqlContainer("mysql:8.0").start();
// Container automatically stopped when leaving scope

Network and Port Management

Access network-related information from a started container.

class StartedMySqlContainer {
  /**
   * Get the first mapped port
   * @returns First mapped port number
   */
  getFirstMappedPort(): number;

  /**
   * Get mapped port for a specific internal port
   * @param port - Internal container port or port with protocol (e.g., "3306/tcp")
   * @param protocol - Protocol ("tcp" or "udp"), defaults to "tcp"
   * @returns Mapped host port
   */
  getMappedPort(port: number, protocol?: string): number;
  getMappedPort(portWithProtocol: `${number}/${"tcp" | "udp"}`): number;

  /**
   * Get network names the container is connected to
   * @returns Array of network names
   */
  getNetworkNames(): string[];

  /**
   * Get network ID for a specific network name
   * @param networkName - Network name
   * @returns Network ID
   */
  getNetworkId(networkName: string): string;

  /**
   * Get container IP address in a specific network
   * @param networkName - Network name
   * @returns IP address in the specified network
   */
  getIpAddress(networkName: string): string;
}

File Operations

Copy files and directories to/from the running container.

class StartedMySqlContainer {
  /**
   * Copy files to the running container
   * @param filesToCopy - Array of file copy definitions
   * @returns Promise that resolves when copy completes
   */
  copyFilesToContainer(filesToCopy: FileToCopy[]): Promise<void>;

  /**
   * Copy directories to the running container
   * @param directoriesToCopy - Array of directory copy definitions
   * @returns Promise that resolves when copy completes
   */
  copyDirectoriesToContainer(directoriesToCopy: DirectoryToCopy[]): Promise<void>;

  /**
   * Copy content to the running container
   * @param contentsToCopy - Array of content copy definitions
   * @returns Promise that resolves when copy completes
   */
  copyContentToContainer(contentsToCopy: ContentToCopy[]): Promise<void>;

  /**
   * Copy tar archive to the container
   * @param tar - Readable stream containing tar archive
   * @param target - Target path in container (default: "/")
   * @returns Promise that resolves when copy completes
   */
  copyArchiveToContainer(tar: Readable, target?: string): Promise<void>;

  /**
   * Copy archive from the container
   * @param path - Path in container to copy from
   * @returns Promise resolving to readable stream of tar archive
   */
  copyArchiveFromContainer(path: string): Promise<NodeJS.ReadableStream>;
}

Command Execution and Logging

Execute commands and retrieve logs from the running container.

class StartedMySqlContainer {
  /**
   * Execute a command in the running container
   * @param command - Command as string or array of strings
   * @param opts - Optional execution options
   * @returns Promise resolving to execution result
   */
  exec(
    command: string | string[],
    opts?: Partial<ExecOptions>
  ): Promise<ExecResult>;

  /**
   * Get container logs
   * @param opts - Optional log options (since, tail)
   * @returns Promise resolving to readable stream of logs
   */
  logs(opts?: { since?: number; tail?: number }): Promise<Readable>;

  /**
   * Commit the container to a new image
   * @param options - Commit options
   * @returns Promise resolving to new image ID
   */
  commit(options: CommitOptions): Promise<string>;
}

Usage Examples:

await using container = await new MySqlContainer("mysql:8.0").start();

// Execute arbitrary commands
const result = await container.exec(["ls", "-la", "/var/lib/mysql"]);
console.log(result.output);

// Get container logs
const logStream = await container.logs({ tail: 100 });
logStream.on("data", (chunk) => console.log(chunk.toString()));

// Copy SQL initialization file
await container.copyFilesToContainer([
  {
    source: "/path/to/init.sql",
    target: "/docker-entrypoint-initdb.d/init.sql"
  }
]);

Types

From testcontainers Package

The following types are imported from the base testcontainers package and used in the API:

/** Options for stopping a container */
interface StopOptions {
  timeout?: number;
  remove?: boolean;
}

/** Options for restarting a container */
interface RestartOptions {
  timeout?: number;
}

/** Result of command execution */
interface ExecResult {
  output: string;
  exitCode: number;
}

/** Options for command execution */
interface ExecOptions {
  workingDir?: string;
  env?: Record<string, string>;
  user?: string;
  privileged?: boolean;
  cmd?: string[];
}

/** Options for committing a container to an image */
interface CommitOptions {
  reference?: string;
  comment?: string;
  author?: string;
  pause?: boolean;
  changes?: string[];
}

/** File to copy to container */
interface FileToCopy {
  source: string;
  target: string;
  mode?: number;
}

/** Directory to copy to container */
interface DirectoryToCopy {
  source: string;
  target: string;
  mode?: number;
}

/** Content to copy to container */
interface ContentToCopy {
  content: string | Buffer;
  target: string;
  mode?: number;
}

/** Container labels as key-value pairs */
type Labels = Record<string, string>;

/** Bind mount configuration */
interface BindMount {
  source: string;
  target: string;
  mode?: "rw" | "ro";
}

/** TmpFs mount configuration */
type TmpFs = Record<string, string>;

/** Health check configuration */
interface HealthCheck {
  test: string[];
  interval?: number;
  timeout?: number;
  retries?: number;
  startPeriod?: number;
}

/** Wait strategy interface */
interface WaitStrategy {
  waitUntilReady(container: StartedTestContainer): Promise<void>;
}

/** Image pull policy */
interface ImagePullPolicy {
  shouldPull(): boolean;
}

/** Stopped test container interface */
interface StoppedTestContainer {
  getId(): string;
  getName(): string;
}

Error Handling

The executeQuery method throws an error if the SQL query fails:

try {
  await container.executeQuery("SELECT * FROM nonexistent_table");
} catch (error) {
  // Error message includes exit code and query
  console.error(error.message);
  // "executeQuery failed with exit code 1 for query: SELECT * FROM nonexistent_table"
}

For connection errors with MySQL clients, use standard error handling for the respective client library (e.g., mysql2, mysql, etc.).

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@testcontainers/mysql@11.9.x
Publish Source
CLI
Badge
tessl/npm-testcontainers--mysql badge