npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mattermost/testcontainers

v0.2.1

Published

CLI and library for managing Mattermost test environments using Docker containers with automatic port allocation, subpath routing, HA clustering, and isolated dependencies

Downloads

592

Readme

@mattermost/testcontainers

CLI and library for spinning up Mattermost test environments using Docker containers. Handles automatic port allocation, networking, health checks, and dependency orchestration so you can focus on testing.

Requirements

  • Docker running locally
  • Node.js 24+

Install

npm install @mattermost/testcontainers

Or run directly with npx:

npx @mattermost/testcontainers start

Quick Start

Start a Mattermost server with PostgreSQL and Inbucket (email):

npx @mattermost/testcontainers start

This starts three containers on a shared Docker network, waits for health checks, configures default test settings via mmctl, and prints connection info:

Connection Information:
=======================
Mattermost:      http://localhost:34025
PostgreSQL:      postgres://mmuser:mostest@localhost:34015/mattermost_test?sslmode=disable
Inbucket:        http://localhost:34016

Stop everything:

npx @mattermost/testcontainers stop

CLI Commands

start

Start the test environment.

npx @mattermost/testcontainers start [options]

| Option | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | -e, --edition <edition> | Server edition: enterprise (default), fips, team | | -t, --tag <tag> | Image tag (e.g., master, release-11.4) | | -D, --deps <deps> | Additional dependencies, comma-separated: openldap, keycloak, minio, elasticsearch, opensearch, redis, dejavu, prometheus, grafana, loki, promtail, libretranslate | | --deps-only | Start dependencies only (no Mattermost server) | | --ha | High-availability mode (3-node cluster with nginx) | | --subpath | Subpath mode (two servers at /mattermost1 and /mattermost2) | | --entry | Mattermost Entry tier | | --esr | Use the current 10.11 ESR (Extended Support Release) version | | --admin [username] | Create admin user (default: sysadmin) | | --admin-password <pw> | Admin password (default: Sys@dmin-sample1) | | -E, --env <KEY=value> | Environment variable for Mattermost (repeatable) | | --env-file <path> | Env file for Mattermost server variables | | -S, --service-env <env> | Service environment: test (default), production, dev | | -c, --config <path> | Path to config file | | -o, --output-dir <dir> | Output directory (default: .tc.out) |

stop

Stop all containers from the current session.

npx @mattermost/testcontainers stop

restart

Restart all containers. Stops Mattermost first, restarts dependencies, waits for readiness, then starts Mattermost.

npx @mattermost/testcontainers restart

rm

Stop and remove containers from the current session.

npx @mattermost/testcontainers rm [-y]

rm-all

Remove all testcontainers resources (finds containers and networks with the org.testcontainers=true Docker label).

npx @mattermost/testcontainers rm-all [-y]

upgrade

Upgrade Mattermost to a new image tag in-place (preserves network, ports, environment).

npx @mattermost/testcontainers upgrade -t release-11.5

info

Display available dependencies, configuration options, and examples.

npx @mattermost/testcontainers info

CLI Examples

Basic Server

# Default enterprise edition, master tag
npx @mattermost/testcontainers start

# Specific version
npx @mattermost/testcontainers start -t release-11.4

# Team edition
npx @mattermost/testcontainers start -e team -t release-11.4

# ESR version (currently 10.11)
npx @mattermost/testcontainers start --esr

# With admin user
npx @mattermost/testcontainers start --admin sysadmin --admin-password 'Sys@dmin-sample1'

With Additional Dependencies

# Add LDAP
npx @mattermost/testcontainers start -D openldap

# Add S3 storage and search
npx @mattermost/testcontainers start -D minio,elasticsearch

# Full stack (requires MM_LICENSE)
npx @mattermost/testcontainers start -D openldap,minio,elasticsearch,redis,keycloak

# Monitoring stack
npx @mattermost/testcontainers start -D prometheus,grafana,loki,promtail

HA Mode (3-Node Cluster)

Requires MM_LICENSE environment variable.

export MM_LICENSE="your-license-string"

# HA cluster with nginx load balancer
npx @mattermost/testcontainers start --ha

# HA with dependencies
npx @mattermost/testcontainers start --ha -D minio,elasticsearch,redis

Output:

Mattermost HA:   http://localhost:34025 (nginx load balancer)
  Cluster: mm_test_cluster
  leader: http://localhost:34026
  follower: http://localhost:34027
  follower2: http://localhost:34028

Subpath Mode (Two Servers Behind Nginx)

Two independent servers behind a single nginx reverse proxy. Server 1 (/mattermost1) is fully configurable. Server 2 (/mattermost2) is a bare, unconfigured instance with its own database.

# Basic subpath
npx @mattermost/testcontainers start --subpath

# Subpath with admin on server1 only
npx @mattermost/testcontainers start --subpath --admin

# Subpath with HA server1 (requires MM_LICENSE)
npx @mattermost/testcontainers start --subpath --ha

# Subpath with dependencies on server1
npx @mattermost/testcontainers start --subpath -D minio,openldap

Output:

Mattermost:      http://localhost:34063 (nginx with subpaths)
  Server 1:      http://localhost:34063/mattermost1
    Direct: http://localhost:34064
  Server 2:      http://localhost:34063/mattermost2 (bare)
    Direct: http://localhost:34067

Dependencies Only (Local Development)

Start only the dependencies and run Mattermost locally:

npx @mattermost/testcontainers start --deps-only

# Source the generated env file, then run your local server
source .tc.out/.env.tc
make run-server

Environment Variables and Feature Flags

# Set feature flags
npx @mattermost/testcontainers start -E MM_FEATUREFLAGS_MOVETHREADSENABLED=true

# Multiple env vars
npx @mattermost/testcontainers start \
  -E MM_SERVICESETTINGS_ENABLEOPENSERVER=false \
  -E MM_TEAMSETTINGS_MAXUSERSPERTEAM=50

# From env file
npx @mattermost/testcontainers start --env-file ./test.env

Configuration File

Create mattermost-testcontainers.config.mjs in your project root:

import {defineConfig} from '@mattermost/testcontainers';

export default defineConfig({
    server: {
        edition: 'enterprise',
        tag: 'release-11.4',
        ha: false,
        subpath: false,
        env: {
            MM_FEATUREFLAGS_MOVETHREADSENABLED: 'true',
        },
        config: {
            ServiceSettings: {
                EnableOpenServer: false,
            },
            TeamSettings: {
                MaxUsersPerTeam: 50,
            },
        },
    },
    dependencies: ['postgres', 'inbucket', 'openldap', 'minio'],
    admin: {
        username: 'sysadmin',
        password: 'Sys@dmin-sample1',
    },
});

JSONC format is also supported as mattermost-testcontainers.config.jsonc.

Configuration Priority

Settings are resolved from multiple sources. When the same setting is defined in more than one source, the highest-priority source wins.

| Priority | Source | Example | | ----------- | --------------------- | -------------------------------------------------------- | | 1 (highest) | CLI flags | --edition team, -t release-11.4, -D openldap,minio | | 2 | Environment variables | TC_EDITION=team, TC_SERVER_TAG=release-11.4 | | 3 | Config file | mattermost-testcontainers.config.mjs or .jsonc | | 4 (lowest) | Built-in defaults | enterprise edition, master tag, postgres + inbucket |

For example, if your config file sets server.tag: 'release-11.4' but you run with -t master, the CLI flag wins and the master tag is used.

Special cases:

  • MM_LICENSE must come from an environment variable — it cannot be set in the config file (rejected to prevent accidental commits).
  • TC_SERVER_IMAGE overrides the computed edition + tag image entirely (e.g., TC_SERVER_IMAGE=myregistry/custom:latest).
  • -D / TC_DEPENDENCIES adds to dependencies from the config file rather than replacing them.

Configuration Reference

| Key | Type | Default | Description | | --------------------------- | ---------- | -------------------------- | ----------------------------------------- | | server.edition | string | 'enterprise' | enterprise, fips, or team | | server.tag | string | 'master' | Docker image tag | | server.ha | boolean | false | Enable HA mode | | server.subpath | boolean | false | Enable subpath mode | | server.entry | boolean | false | Enable Entry tier | | server.serviceEnvironment | string | 'test' | test, production, or dev | | server.imageMaxAgeHours | number | 24 | Max hours before re-pulling :master tag | | server.env | object | {} | Mattermost MM_* environment variables | | server.config | object | {} | Server config patches (applied via mmctl) | | dependencies | string[] | ['postgres', 'inbucket'] | Enabled dependencies | | images | object | {} | Override default container images | | outputDir | string | '.tc.out' | Output directory | | admin.username | string | — | Admin username to create | | admin.password | string | 'Sys@dmin-sample1' | Admin password |

Image Overrides

Override default images in the config file:

export default defineConfig({
    images: {
        postgres: 'postgres:16',
        mattermost: 'mattermostdevelopment/mattermost-enterprise-edition:release-11.5',
    },
});

Or via environment variables: TC_POSTGRES_IMAGE, TC_MINIO_IMAGE, TC_SERVER_IMAGE, etc.

Using in Tests

Approach 1: Embedded (Playwright)

Import MattermostTestEnvironment in your global setup. The environment starts before tests and stops after. Gated by an environment variable so it's opt-in.

global-setup.ts (actual pattern used by e2e-tests/playwright):

import {discoverAndLoadConfig, MattermostTestEnvironment} from '@mattermost/testcontainers';

let environment: MattermostTestEnvironment | null = null;

export default async function globalSetup() {
    // Only start containers when PW_TC=true
    if (process.env.PW_TC === 'true') {
        const config = await discoverAndLoadConfig();
        environment = new MattermostTestEnvironment(config);
        await environment.start();

        // Set base URL for Playwright
        process.env.PW_BASE_URL = environment.getServerUrl();
    }

    // ... other setup (admin user creation, etc.)

    // Return teardown function — Playwright calls this after all tests
    return async function globalTeardown() {
        if (environment) {
            await environment.stop();
            environment = null;
        }
    };
}

playwright.config.ts:

import {defineConfig} from '@playwright/test';

export default defineConfig({
    globalSetup: './global-setup.ts',
    use: {
        baseURL: process.env.PW_BASE_URL || 'http://localhost:8065',
    },
});

Run with testcontainers:

PW_TC=true npx playwright test

Approach 2: Separate Script (Cypress, etc.)

Start the environment as a separate process before running tests. The CLI writes connection info to .tc.out/ which your tests can read.

package.json:

{
    "scripts": {
        "test:setup": "npx @mattermost/testcontainers start --admin",
        "test:teardown": "npx @mattermost/testcontainers stop",
        "test:run": "cypress run",
        "test": "npm run test:setup && npm run test:run; npm run test:teardown"
    }
}

Read connection info in Cypress (cypress.config.ts):

import {defineConfig} from 'cypress';
import * as fs from 'fs';

// Read container info written by the CLI
const dockerInfo = JSON.parse(fs.readFileSync('.tc.out/.tc.docker.json', 'utf-8'));
const mmContainer = dockerInfo.containers.mattermost || dockerInfo.containers['mattermost-server1'];
const serverUrl = mmContainer?.url || 'http://localhost:8065';

export default defineConfig({
    e2e: {
        baseUrl: serverUrl,
    },
    env: {
        // Pass connection info to tests
        INBUCKET_URL: dockerInfo.containers.inbucket
            ? `http://${dockerInfo.containers.inbucket.host}:${dockerInfo.containers.inbucket.webPort}`
            : undefined,
    },
});

Or source the env file:

# Start environment
npx @mattermost/testcontainers start --admin

# Source environment variables
source .tc.out/.env.tc

# Run tests with env vars available
cypress run

Approach 3: Programmatic (Node.js Test Scripts)

Use the library API for full control in custom test scripts:

import {MattermostTestEnvironment, discoverAndLoadConfig} from '@mattermost/testcontainers';

async function main() {
    const config = await discoverAndLoadConfig();

    const env = new MattermostTestEnvironment(config);
    await env.start();

    const serverUrl = env.getServerUrl();
    console.log(`Server running at ${serverUrl}`);

    // Access specific service info
    const info = env.getConnectionInfo();
    console.log(`PostgreSQL: ${info.postgres.connectionString}`);

    // Run mmctl commands
    const mmctl = env.getMmctl();
    await mmctl.exec('user create --email [email protected] --username testuser --password Test123! --system-admin');

    // ... run your tests ...

    await env.stop();
}

main().catch(console.error);

Environment Variables

| Variable | Description | | ------------------------ | -------------------------------------------------------- | | MM_LICENSE | Enterprise license (required for --ha and redis) | | TC_EDITION | Server edition | | TC_SERVER_TAG | Server image tag | | TC_SERVER_IMAGE | Full server image (overrides edition + tag) | | TC_DEPENDENCIES | Dependencies (comma-separated) | | TC_HA | Enable HA mode (true/false) | | TC_SUBPATH | Enable subpath mode (true/false) | | TC_ENTRY | Enable Entry tier (true/false) | | TC_ADMIN_USERNAME | Admin username | | TC_ADMIN_PASSWORD | Admin password | | TC_OUTPUT_DIR | Output directory | | TC_IMAGE_MAX_AGE_HOURS | Max hours before re-pulling :master images | | TC_<SERVICE>_IMAGE | Override image for a service (e.g., TC_POSTGRES_IMAGE) |

Supported Dependencies

| Dependency | Description | Default Image | | ---------------- | --------------------------------------------------------------- | ------------------------------------------------------ | | postgres | PostgreSQL database (always included) | postgres:14 | | inbucket | Email testing (SMTP + web UI, always included) | inbucket/inbucket:stable | | openldap | LDAP authentication | osixia/openldap:1.4.0 | | keycloak | SAML/OIDC identity provider | quay.io/keycloak/keycloak:23.0.7 | | minio | S3-compatible object storage | minio/minio:RELEASE.2024-06-22T05-26-45Z | | elasticsearch | Search engine | mattermostdevelopment/mattermost-elasticsearch:8.9.0 | | opensearch | Search engine (alternative) | mattermostdevelopment/mattermost-opensearch:2.7.0 | | redis | Cache (requires MM_LICENSE) | redis:7.4.0 | | dejavu | Elasticsearch web UI (requires elasticsearch or opensearch) | appbaseio/dejavu:3.4.2 | | prometheus | Metrics collection | prom/prometheus:v2.46.0 | | grafana | Dashboards (requires prometheus or loki) | grafana/grafana:10.4.2 | | loki | Log aggregation (requires promtail) | grafana/loki:3.0.0 | | promtail | Log shipping (requires loki) | grafana/promtail:3.0.0 | | libretranslate | Translation service | libretranslate/libretranslate:v1.8.4 |

Output Directory

After start, the output directory (default .tc.out/) contains:

.tc.out/
  .env.tc                    # Sourceable environment variables
  .tc.docker.json            # Container metadata (IDs, ports, images)
  .tc.server.config.json     # Server configuration dump
  logs/
    postgres.log
    inbucket.log
    mattermost.log
    ...

Default Credentials

| Service | Username | Password | | ---------------------- | ------------------------------- | ------------------ | | PostgreSQL | mmuser | mostest | | Admin (when --admin) | sysadmin | Sys@dmin-sample1 | | Keycloak admin | admin | admin | | Keycloak test users | user-1, user-2 | Password1! | | OpenLDAP admin | cn=admin,dc=mm,dc=test,dc=com | mostest | | OpenLDAP test users | test.one, test.two | Password1 | | MinIO | minioaccesskey | miniosecretkey |

Security Considerations

This CLI is designed for controlled environments — developer machines and CI pipelines. It is not intended for production use.

Hardcoded Test Credentials

All service credentials listed above are hardcoded defaults intended for local testing only. They match the upstream Mattermost docker-compose test configuration. These credentials are:

  • Written to .tc.out/.env.tc and .tc.out/.tc.docker.json in plaintext
  • Printed to console output (admin credentials when --admin is used)
  • Visible in CI logs if captured

Do not use these credentials in any production or staging environment. Add .tc.out/ to your .gitignore to prevent accidental commits of output files.

Enterprise License

MM_LICENSE must be provided via environment variable (not config files) to prevent accidental leakage in committed configuration. The CLI explicitly rejects MM_LICENSE in config file server.env sections.

Docker Commands

All Docker CLI invocations use execFileSync (array-form arguments) to prevent shell injection. Container IDs read from .tc.docker.json are validated against ^[a-f0-9]{12,64}$ before use. Output directory paths are validated to prevent path traversal before any recursive deletion.

Network Exposure

Containers bind to 0.0.0.0 (default testcontainers behavior) with dynamically allocated ports. On shared networks, services may be accessible to other machines. This is standard for local Docker development but should be considered in shared CI environments.

License

See LICENSE.txt in the project root for details.