Python library for throwaway instances of anything that can run in a Docker container
Containers for web services, browser automation, and testing infrastructure including Nginx, Selenium WebDriver, and specialized testing utilities for comprehensive web application testing.
Selenium browser container for Chrome and Firefox automation with VNC support and video recording capabilities.
class BrowserWebDriverContainer:
def __init__(
self,
capabilities: dict,
options: Optional[Any] = None,
image: Optional[str] = None,
port: int = 4444,
vnc_port: int = 5900,
**kwargs: Any
):
"""
Initialize browser WebDriver container.
Args:
capabilities: Selenium capabilities dictionary
options: Browser-specific options
image: Docker image (auto-selected if None)
port: Selenium Grid port (default 4444)
vnc_port: VNC port for remote viewing (default 5900)
**kwargs: Additional container options
"""
def get_driver(self):
"""
Get configured WebDriver instance.
Returns:
Selenium WebDriver instance
"""
def get_connection_url(self) -> str:
"""
Get Selenium Grid connection URL.
Returns:
Selenium Grid URL string
"""
def with_options(self, options: Any) -> "BrowserWebDriverContainer":
"""
Set browser-specific options.
Args:
options: Chrome/Firefox options object
Returns:
Self for method chaining
"""
def with_video(self, image: Optional[str] = None, video_path: Optional[str] = None) -> "BrowserWebDriverContainer":
"""
Enable video recording of browser session.
Args:
image: Video recorder image
video_path: Host path to save videos
Returns:
Self for method chaining
"""Nginx web server container for serving static content, reverse proxy testing, and web server functionality.
class NginxContainer:
def __init__(
self,
image: str = "nginx:alpine",
port: int = 80,
**kwargs: Any
):
"""
Initialize Nginx container.
Args:
image: Nginx Docker image
port: HTTP port (default 80)
**kwargs: Additional container options
"""
def get_url(self) -> str:
"""
Get Nginx server URL.
Returns:
Nginx server URL string
"""Specialized containers for testing scenarios and development utilities.
class MailpitContainer:
def __init__(
self,
image: str = "axllent/mailpit:latest",
smtp_port: int = 1025,
web_port: int = 8025,
**kwargs: Any
):
"""
Initialize Mailpit email testing container.
Args:
image: Mailpit Docker image
smtp_port: SMTP server port (default 1025)
web_port: Web interface port (default 8025)
**kwargs: Additional container options
"""
def get_smtp_connection_url(self) -> str:
"""
Get SMTP connection URL.
Returns:
SMTP connection URL string
"""
def get_web_url(self) -> str:
"""
Get web interface URL.
Returns:
Web interface URL string
"""
class SftpContainer:
def __init__(
self,
image: str = "atmoz/sftp:latest",
port: int = 22,
username: str = "testuser",
password: str = "testpass",
**kwargs: Any
):
"""
Initialize SFTP server container.
Args:
image: SFTP Docker image
port: SFTP port (default 22)
username: SFTP username
password: SFTP password
**kwargs: Additional container options
"""
def get_connection_url(self) -> str:
"""
Get SFTP connection URL.
Returns:
SFTP connection URL string
"""from testcontainers.selenium import BrowserWebDriverContainer
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Chrome browser automation
chrome_capabilities = {
"browserName": "chrome",
"browserVersion": "latest"
}
with BrowserWebDriverContainer(chrome_capabilities) as chrome:
# Get WebDriver instance
driver = chrome.get_driver()
try:
# Navigate to a website
driver.get("https://example.com")
# Wait for page to load
wait = WebDriverWait(driver, 10)
title_element = wait.until(
EC.presence_of_element_located((By.TAG_NAME, "h1"))
)
# Interact with page
print(f"Page title: {driver.title}")
print(f"H1 text: {title_element.text}")
# Take screenshot
driver.save_screenshot("example_page.png")
# Find and click elements
links = driver.find_elements(By.TAG_NAME, "a")
print(f"Found {len(links)} links on the page")
finally:
driver.quit()from testcontainers.selenium import BrowserWebDriverContainer
from selenium.webdriver.firefox.options import Options
# Configure Firefox options
firefox_options = Options()
firefox_options.add_argument("--headless") # Run in background
firefox_options.set_preference("network.http.pipelining", True)
firefox_capabilities = {
"browserName": "firefox",
"browserVersion": "latest"
}
with BrowserWebDriverContainer(firefox_capabilities) as firefox:
firefox.with_options(firefox_options)
driver = firefox.get_driver()
try:
# Test JavaScript execution
driver.get("data:text/html,<html><body><h1 id='test'>Hello World</h1></body></html>")
# Execute JavaScript
result = driver.execute_script("return document.getElementById('test').textContent;")
print(f"JavaScript result: {result}")
# Test page performance
navigation_start = driver.execute_script("return window.performance.timing.navigationStart")
load_complete = driver.execute_script("return window.performance.timing.loadEventEnd")
page_load_time = load_complete - navigation_start
print(f"Page load time: {page_load_time}ms")
finally:
driver.quit()from testcontainers.nginx import NginxContainer
import requests
import tempfile
import os
# Create test HTML content
test_html = """
<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
</head>
<body>
<h1>Welcome to Test Site</h1>
<div id="content">
<p>This is a test page served by Nginx.</p>
<form action="/submit" method="post">
<input type="text" name="data" placeholder="Enter data">
<button type="submit">Submit</button>
</form>
</div>
</body>
</html>
"""
# Create temporary directory with test content
with tempfile.TemporaryDirectory() as temp_dir:
# Write test HTML file
html_file = os.path.join(temp_dir, "index.html")
with open(html_file, "w") as f:
f.write(test_html)
# Start Nginx container with custom content
nginx = NginxContainer("nginx:alpine") \
.with_volume_mapping(temp_dir, "/usr/share/nginx/html", "ro") \
.with_exposed_ports(80)
with nginx:
# Get server URL
server_url = nginx.get_url()
# Test static content serving
response = requests.get(server_url)
assert response.status_code == 200
assert "Welcome to Test Site" in response.text
# Test different HTTP methods
head_response = requests.head(server_url)
assert head_response.status_code == 200
# Test non-existent page
not_found = requests.get(f"{server_url}/nonexistent")
assert not_found.status_code == 404
print(f"Nginx serving content at: {server_url}")
print(f"Content length: {len(response.text)} bytes")from testcontainers.mailpit import MailpitContainer
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import requests
with MailpitContainer() as mailpit:
# Get connection details
smtp_url = mailpit.get_smtp_connection_url()
web_url = mailpit.get_web_url()
# Parse SMTP connection
smtp_host = smtp_url.split("://")[1].split(":")[0]
smtp_port = int(smtp_url.split(":")[2])
# Send test emails
with smtplib.SMTP(smtp_host, smtp_port) as server:
# Send plain text email
plain_msg = MIMEText("This is a plain text test email.")
plain_msg["Subject"] = "Plain Text Test"
plain_msg["From"] = "sender@example.com"
plain_msg["To"] = "recipient@example.com"
server.send_message(plain_msg)
# Send HTML email
html_msg = MIMEMultipart("alternative")
html_msg["Subject"] = "HTML Test Email"
html_msg["From"] = "sender@example.com"
html_msg["To"] = "recipient@example.com"
html_content = """
<html>
<body>
<h1>Test Email</h1>
<p>This is an <b>HTML</b> test email.</p>
<a href="https://example.com">Click here</a>
</body>
</html>
"""
html_part = MIMEText(html_content, "html")
html_msg.attach(html_part)
server.send_message(html_msg)
# Check emails via web API
import time
time.sleep(1) # Wait for emails to be processed
# Get emails via Mailpit API
api_response = requests.get(f"{web_url}/api/v1/messages")
emails = api_response.json()
print(f"Received {len(emails['messages'])} emails")
for email in emails["messages"]:
print(f"- Subject: {email['Subject']}")
print(f" From: {email['From']['Address']}")
print(f" To: {email['To'][0]['Address']}")from testcontainers.sftp import SftpContainer
import paramiko
import io
with SftpContainer() as sftp:
connection_url = sftp.get_connection_url()
# Parse connection details
host = connection_url.split("://")[1].split("@")[1].split(":")[0]
port = int(connection_url.split(":")[3])
username = "testuser"
password = "testpass"
# Create SSH client
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
# Connect to SFTP server
ssh.connect(hostname=host, port=port, username=username, password=password)
sftp_client = ssh.open_sftp()
# Upload file
test_content = "Hello, SFTP!\nThis is a test file."
file_buffer = io.StringIO(test_content)
with sftp_client.open("test_upload.txt", "w") as remote_file:
remote_file.write(test_content)
# List files
files = sftp_client.listdir(".")
print(f"Files on SFTP server: {files}")
# Download file
with sftp_client.open("test_upload.txt", "r") as remote_file:
downloaded_content = remote_file.read()
print(f"Downloaded content: {downloaded_content}")
# Create directory and upload multiple files
sftp_client.mkdir("test_directory")
for i in range(3):
filename = f"test_directory/file_{i}.txt"
content = f"Content of file {i}"
with sftp_client.open(filename, "w") as remote_file:
remote_file.write(content)
# List directory contents
dir_files = sftp_client.listdir("test_directory")
print(f"Files in test_directory: {dir_files}")
finally:
sftp_client.close()
ssh.close()from testcontainers.selenium import BrowserWebDriverContainer
from testcontainers.nginx import NginxContainer
from testcontainers.mailpit import MailpitContainer
from testcontainers.postgres import PostgresContainer
from testcontainers.core.network import Network
import tempfile
import os
# Create test web application
app_html = """
<!DOCTYPE html>
<html>
<head>
<title>Test App</title>
<script>
function submitForm() {
// Simulate form submission
document.getElementById('result').innerText = 'Form submitted successfully!';
}
</script>
</head>
<body>
<h1>Test Application</h1>
<form onsubmit="submitForm(); return false;">
<input type="email" id="email" placeholder="Enter email" required>
<button type="submit">Submit</button>
</form>
<div id="result"></div>
</body>
</html>
"""
with tempfile.TemporaryDirectory() as temp_dir:
# Create test HTML
html_file = os.path.join(temp_dir, "index.html")
with open(html_file, "w") as f:
f.write(app_html)
# Create network for services
with Network() as network:
# Start all services
with NginxContainer() as web_server, \
MailpitContainer() as email_server, \
PostgresContainer("postgres:13") as database, \
BrowserWebDriverContainer({"browserName": "chrome"}) as browser:
# Configure web server
web_server.with_volume_mapping(temp_dir, "/usr/share/nginx/html", "ro")
web_server.with_network(network).with_network_aliases("web")
# Configure other services
email_server.with_network(network).with_network_aliases("mail")
database.with_network(network).with_network_aliases("db")
browser.with_network(network)
# Get service URLs
web_url = web_server.get_url()
mail_web_url = email_server.get_web_url()
db_url = database.get_connection_url()
print(f"Web server: {web_url}")
print(f"Mail server: {mail_web_url}")
print(f"Database: {db_url}")
# Automated testing
driver = browser.get_driver()
try:
# Test web application
driver.get(web_url)
# Fill form
email_input = driver.find_element("id", "email")
email_input.send_keys("test@example.com")
# Submit form
submit_button = driver.find_element("css selector", "button[type='submit']")
submit_button.click()
# Verify result
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
wait = WebDriverWait(driver, 10)
result_element = wait.until(
EC.text_to_be_present_in_element((By.ID, "result"), "Form submitted successfully!")
)
print("✓ Web application test passed")
# Take screenshot of success
driver.save_screenshot("test_success.png")
finally:
driver.quit()
print("✓ Complete web application testing stack verified")from testcontainers.nginx import NginxContainer
import requests
import time
import concurrent.futures
import statistics
def performance_test(url, num_requests=100, concurrent_users=10):
"""Run performance test against web server."""
def make_request():
start_time = time.time()
try:
response = requests.get(url, timeout=10)
end_time = time.time()
return {
"status_code": response.status_code,
"response_time": end_time - start_time,
"success": response.status_code == 200
}
except Exception as e:
return {
"status_code": 0,
"response_time": 0,
"success": False,
"error": str(e)
}
# Run concurrent requests
results = []
with concurrent.futures.ThreadPoolExecutor(max_workers=concurrent_users) as executor:
futures = [executor.submit(make_request) for _ in range(num_requests)]
results = [future.result() for future in concurrent.futures.as_completed(futures)]
# Calculate statistics
successful_requests = [r for r in results if r["success"]]
response_times = [r["response_time"] for r in successful_requests]
if response_times:
stats = {
"total_requests": num_requests,
"successful_requests": len(successful_requests),
"success_rate": len(successful_requests) / num_requests * 100,
"avg_response_time": statistics.mean(response_times),
"min_response_time": min(response_times),
"max_response_time": max(response_times),
"median_response_time": statistics.median(response_times)
}
else:
stats = {"error": "No successful requests"}
return stats
# Run performance test
with NginxContainer() as nginx:
server_url = nginx.get_url()
print(f"Running performance test against: {server_url}")
results = performance_test(server_url, num_requests=50, concurrent_users=5)
print("\nPerformance Test Results:")
for key, value in results.items():
if isinstance(value, float):
print(f"{key}: {value:.4f}")
else:
print(f"{key}: {value}")Install with Tessl CLI
npx tessl i tessl/pypi-testcontainers