0
# Web and Testing Containers
1
2
Containers for web services, browser automation, and testing infrastructure including Nginx, Selenium WebDriver, and specialized testing utilities for comprehensive web application testing.
3
4
## Capabilities
5
6
### Browser WebDriver Container
7
8
Selenium browser container for Chrome and Firefox automation with VNC support and video recording capabilities.
9
10
```python { .api }
11
class BrowserWebDriverContainer:
12
def __init__(
13
self,
14
capabilities: dict,
15
options: Optional[Any] = None,
16
image: Optional[str] = None,
17
port: int = 4444,
18
vnc_port: int = 5900,
19
**kwargs: Any
20
):
21
"""
22
Initialize browser WebDriver container.
23
24
Args:
25
capabilities: Selenium capabilities dictionary
26
options: Browser-specific options
27
image: Docker image (auto-selected if None)
28
port: Selenium Grid port (default 4444)
29
vnc_port: VNC port for remote viewing (default 5900)
30
**kwargs: Additional container options
31
"""
32
33
def get_driver(self):
34
"""
35
Get configured WebDriver instance.
36
37
Returns:
38
Selenium WebDriver instance
39
"""
40
41
def get_connection_url(self) -> str:
42
"""
43
Get Selenium Grid connection URL.
44
45
Returns:
46
Selenium Grid URL string
47
"""
48
49
def with_options(self, options: Any) -> "BrowserWebDriverContainer":
50
"""
51
Set browser-specific options.
52
53
Args:
54
options: Chrome/Firefox options object
55
56
Returns:
57
Self for method chaining
58
"""
59
60
def with_video(self, image: Optional[str] = None, video_path: Optional[str] = None) -> "BrowserWebDriverContainer":
61
"""
62
Enable video recording of browser session.
63
64
Args:
65
image: Video recorder image
66
video_path: Host path to save videos
67
68
Returns:
69
Self for method chaining
70
"""
71
```
72
73
### Nginx Container
74
75
Nginx web server container for serving static content, reverse proxy testing, and web server functionality.
76
77
```python { .api }
78
class NginxContainer:
79
def __init__(
80
self,
81
image: str = "nginx:alpine",
82
port: int = 80,
83
**kwargs: Any
84
):
85
"""
86
Initialize Nginx container.
87
88
Args:
89
image: Nginx Docker image
90
port: HTTP port (default 80)
91
**kwargs: Additional container options
92
"""
93
94
def get_url(self) -> str:
95
"""
96
Get Nginx server URL.
97
98
Returns:
99
Nginx server URL string
100
"""
101
```
102
103
### Testing Utility Containers
104
105
Specialized containers for testing scenarios and development utilities.
106
107
```python { .api }
108
class MailpitContainer:
109
def __init__(
110
self,
111
image: str = "axllent/mailpit:latest",
112
smtp_port: int = 1025,
113
web_port: int = 8025,
114
**kwargs: Any
115
):
116
"""
117
Initialize Mailpit email testing container.
118
119
Args:
120
image: Mailpit Docker image
121
smtp_port: SMTP server port (default 1025)
122
web_port: Web interface port (default 8025)
123
**kwargs: Additional container options
124
"""
125
126
def get_smtp_connection_url(self) -> str:
127
"""
128
Get SMTP connection URL.
129
130
Returns:
131
SMTP connection URL string
132
"""
133
134
def get_web_url(self) -> str:
135
"""
136
Get web interface URL.
137
138
Returns:
139
Web interface URL string
140
"""
141
142
class SftpContainer:
143
def __init__(
144
self,
145
image: str = "atmoz/sftp:latest",
146
port: int = 22,
147
username: str = "testuser",
148
password: str = "testpass",
149
**kwargs: Any
150
):
151
"""
152
Initialize SFTP server container.
153
154
Args:
155
image: SFTP Docker image
156
port: SFTP port (default 22)
157
username: SFTP username
158
password: SFTP password
159
**kwargs: Additional container options
160
"""
161
162
def get_connection_url(self) -> str:
163
"""
164
Get SFTP connection URL.
165
166
Returns:
167
SFTP connection URL string
168
"""
169
```
170
171
## Usage Examples
172
173
### Selenium Browser Automation
174
175
```python
176
from testcontainers.selenium import BrowserWebDriverContainer
177
from selenium.webdriver.common.by import By
178
from selenium.webdriver.support.ui import WebDriverWait
179
from selenium.webdriver.support import expected_conditions as EC
180
181
# Chrome browser automation
182
chrome_capabilities = {
183
"browserName": "chrome",
184
"browserVersion": "latest"
185
}
186
187
with BrowserWebDriverContainer(chrome_capabilities) as chrome:
188
# Get WebDriver instance
189
driver = chrome.get_driver()
190
191
try:
192
# Navigate to a website
193
driver.get("https://example.com")
194
195
# Wait for page to load
196
wait = WebDriverWait(driver, 10)
197
title_element = wait.until(
198
EC.presence_of_element_located((By.TAG_NAME, "h1"))
199
)
200
201
# Interact with page
202
print(f"Page title: {driver.title}")
203
print(f"H1 text: {title_element.text}")
204
205
# Take screenshot
206
driver.save_screenshot("example_page.png")
207
208
# Find and click elements
209
links = driver.find_elements(By.TAG_NAME, "a")
210
print(f"Found {len(links)} links on the page")
211
212
finally:
213
driver.quit()
214
```
215
216
### Firefox with Custom Options
217
218
```python
219
from testcontainers.selenium import BrowserWebDriverContainer
220
from selenium.webdriver.firefox.options import Options
221
222
# Configure Firefox options
223
firefox_options = Options()
224
firefox_options.add_argument("--headless") # Run in background
225
firefox_options.set_preference("network.http.pipelining", True)
226
227
firefox_capabilities = {
228
"browserName": "firefox",
229
"browserVersion": "latest"
230
}
231
232
with BrowserWebDriverContainer(firefox_capabilities) as firefox:
233
firefox.with_options(firefox_options)
234
235
driver = firefox.get_driver()
236
237
try:
238
# Test JavaScript execution
239
driver.get("data:text/html,<html><body><h1 id='test'>Hello World</h1></body></html>")
240
241
# Execute JavaScript
242
result = driver.execute_script("return document.getElementById('test').textContent;")
243
print(f"JavaScript result: {result}")
244
245
# Test page performance
246
navigation_start = driver.execute_script("return window.performance.timing.navigationStart")
247
load_complete = driver.execute_script("return window.performance.timing.loadEventEnd")
248
page_load_time = load_complete - navigation_start
249
250
print(f"Page load time: {page_load_time}ms")
251
252
finally:
253
driver.quit()
254
```
255
256
### Web Application Testing with Nginx
257
258
```python
259
from testcontainers.nginx import NginxContainer
260
import requests
261
import tempfile
262
import os
263
264
# Create test HTML content
265
test_html = """
266
<!DOCTYPE html>
267
<html>
268
<head>
269
<title>Test Page</title>
270
</head>
271
<body>
272
<h1>Welcome to Test Site</h1>
273
<div id="content">
274
<p>This is a test page served by Nginx.</p>
275
<form action="/submit" method="post">
276
<input type="text" name="data" placeholder="Enter data">
277
<button type="submit">Submit</button>
278
</form>
279
</div>
280
</body>
281
</html>
282
"""
283
284
# Create temporary directory with test content
285
with tempfile.TemporaryDirectory() as temp_dir:
286
# Write test HTML file
287
html_file = os.path.join(temp_dir, "index.html")
288
with open(html_file, "w") as f:
289
f.write(test_html)
290
291
# Start Nginx container with custom content
292
nginx = NginxContainer("nginx:alpine") \
293
.with_volume_mapping(temp_dir, "/usr/share/nginx/html", "ro") \
294
.with_exposed_ports(80)
295
296
with nginx:
297
# Get server URL
298
server_url = nginx.get_url()
299
300
# Test static content serving
301
response = requests.get(server_url)
302
assert response.status_code == 200
303
assert "Welcome to Test Site" in response.text
304
305
# Test different HTTP methods
306
head_response = requests.head(server_url)
307
assert head_response.status_code == 200
308
309
# Test non-existent page
310
not_found = requests.get(f"{server_url}/nonexistent")
311
assert not_found.status_code == 404
312
313
print(f"Nginx serving content at: {server_url}")
314
print(f"Content length: {len(response.text)} bytes")
315
```
316
317
### Email Testing with Mailpit
318
319
```python
320
from testcontainers.mailpit import MailpitContainer
321
import smtplib
322
from email.mime.text import MIMEText
323
from email.mime.multipart import MIMEMultipart
324
import requests
325
326
with MailpitContainer() as mailpit:
327
# Get connection details
328
smtp_url = mailpit.get_smtp_connection_url()
329
web_url = mailpit.get_web_url()
330
331
# Parse SMTP connection
332
smtp_host = smtp_url.split("://")[1].split(":")[0]
333
smtp_port = int(smtp_url.split(":")[2])
334
335
# Send test emails
336
with smtplib.SMTP(smtp_host, smtp_port) as server:
337
# Send plain text email
338
plain_msg = MIMEText("This is a plain text test email.")
339
plain_msg["Subject"] = "Plain Text Test"
340
plain_msg["From"] = "sender@example.com"
341
plain_msg["To"] = "recipient@example.com"
342
343
server.send_message(plain_msg)
344
345
# Send HTML email
346
html_msg = MIMEMultipart("alternative")
347
html_msg["Subject"] = "HTML Test Email"
348
html_msg["From"] = "sender@example.com"
349
html_msg["To"] = "recipient@example.com"
350
351
html_content = """
352
<html>
353
<body>
354
<h1>Test Email</h1>
355
<p>This is an <b>HTML</b> test email.</p>
356
<a href="https://example.com">Click here</a>
357
</body>
358
</html>
359
"""
360
361
html_part = MIMEText(html_content, "html")
362
html_msg.attach(html_part)
363
364
server.send_message(html_msg)
365
366
# Check emails via web API
367
import time
368
time.sleep(1) # Wait for emails to be processed
369
370
# Get emails via Mailpit API
371
api_response = requests.get(f"{web_url}/api/v1/messages")
372
emails = api_response.json()
373
374
print(f"Received {len(emails['messages'])} emails")
375
for email in emails["messages"]:
376
print(f"- Subject: {email['Subject']}")
377
print(f" From: {email['From']['Address']}")
378
print(f" To: {email['To'][0]['Address']}")
379
```
380
381
### SFTP File Transfer Testing
382
383
```python
384
from testcontainers.sftp import SftpContainer
385
import paramiko
386
import io
387
388
with SftpContainer() as sftp:
389
connection_url = sftp.get_connection_url()
390
391
# Parse connection details
392
host = connection_url.split("://")[1].split("@")[1].split(":")[0]
393
port = int(connection_url.split(":")[3])
394
username = "testuser"
395
password = "testpass"
396
397
# Create SSH client
398
ssh = paramiko.SSHClient()
399
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
400
401
try:
402
# Connect to SFTP server
403
ssh.connect(hostname=host, port=port, username=username, password=password)
404
sftp_client = ssh.open_sftp()
405
406
# Upload file
407
test_content = "Hello, SFTP!\nThis is a test file."
408
file_buffer = io.StringIO(test_content)
409
410
with sftp_client.open("test_upload.txt", "w") as remote_file:
411
remote_file.write(test_content)
412
413
# List files
414
files = sftp_client.listdir(".")
415
print(f"Files on SFTP server: {files}")
416
417
# Download file
418
with sftp_client.open("test_upload.txt", "r") as remote_file:
419
downloaded_content = remote_file.read()
420
print(f"Downloaded content: {downloaded_content}")
421
422
# Create directory and upload multiple files
423
sftp_client.mkdir("test_directory")
424
425
for i in range(3):
426
filename = f"test_directory/file_{i}.txt"
427
content = f"Content of file {i}"
428
with sftp_client.open(filename, "w") as remote_file:
429
remote_file.write(content)
430
431
# List directory contents
432
dir_files = sftp_client.listdir("test_directory")
433
print(f"Files in test_directory: {dir_files}")
434
435
finally:
436
sftp_client.close()
437
ssh.close()
438
```
439
440
### Complete Web Application Testing Stack
441
442
```python
443
from testcontainers.selenium import BrowserWebDriverContainer
444
from testcontainers.nginx import NginxContainer
445
from testcontainers.mailpit import MailpitContainer
446
from testcontainers.postgres import PostgresContainer
447
from testcontainers.core.network import Network
448
import tempfile
449
import os
450
451
# Create test web application
452
app_html = """
453
<!DOCTYPE html>
454
<html>
455
<head>
456
<title>Test App</title>
457
<script>
458
function submitForm() {
459
// Simulate form submission
460
document.getElementById('result').innerText = 'Form submitted successfully!';
461
}
462
</script>
463
</head>
464
<body>
465
<h1>Test Application</h1>
466
<form onsubmit="submitForm(); return false;">
467
<input type="email" id="email" placeholder="Enter email" required>
468
<button type="submit">Submit</button>
469
</form>
470
<div id="result"></div>
471
</body>
472
</html>
473
"""
474
475
with tempfile.TemporaryDirectory() as temp_dir:
476
# Create test HTML
477
html_file = os.path.join(temp_dir, "index.html")
478
with open(html_file, "w") as f:
479
f.write(app_html)
480
481
# Create network for services
482
with Network() as network:
483
# Start all services
484
with NginxContainer() as web_server, \
485
MailpitContainer() as email_server, \
486
PostgresContainer("postgres:13") as database, \
487
BrowserWebDriverContainer({"browserName": "chrome"}) as browser:
488
489
# Configure web server
490
web_server.with_volume_mapping(temp_dir, "/usr/share/nginx/html", "ro")
491
web_server.with_network(network).with_network_aliases("web")
492
493
# Configure other services
494
email_server.with_network(network).with_network_aliases("mail")
495
database.with_network(network).with_network_aliases("db")
496
browser.with_network(network)
497
498
# Get service URLs
499
web_url = web_server.get_url()
500
mail_web_url = email_server.get_web_url()
501
db_url = database.get_connection_url()
502
503
print(f"Web server: {web_url}")
504
print(f"Mail server: {mail_web_url}")
505
print(f"Database: {db_url}")
506
507
# Automated testing
508
driver = browser.get_driver()
509
510
try:
511
# Test web application
512
driver.get(web_url)
513
514
# Fill form
515
email_input = driver.find_element("id", "email")
516
email_input.send_keys("test@example.com")
517
518
# Submit form
519
submit_button = driver.find_element("css selector", "button[type='submit']")
520
submit_button.click()
521
522
# Verify result
523
from selenium.webdriver.support.ui import WebDriverWait
524
from selenium.webdriver.support import expected_conditions as EC
525
from selenium.webdriver.common.by import By
526
527
wait = WebDriverWait(driver, 10)
528
result_element = wait.until(
529
EC.text_to_be_present_in_element((By.ID, "result"), "Form submitted successfully!")
530
)
531
532
print("✓ Web application test passed")
533
534
# Take screenshot of success
535
driver.save_screenshot("test_success.png")
536
537
finally:
538
driver.quit()
539
540
print("✓ Complete web application testing stack verified")
541
```
542
543
### Performance Testing Setup
544
545
```python
546
from testcontainers.nginx import NginxContainer
547
import requests
548
import time
549
import concurrent.futures
550
import statistics
551
552
def performance_test(url, num_requests=100, concurrent_users=10):
553
"""Run performance test against web server."""
554
555
def make_request():
556
start_time = time.time()
557
try:
558
response = requests.get(url, timeout=10)
559
end_time = time.time()
560
return {
561
"status_code": response.status_code,
562
"response_time": end_time - start_time,
563
"success": response.status_code == 200
564
}
565
except Exception as e:
566
return {
567
"status_code": 0,
568
"response_time": 0,
569
"success": False,
570
"error": str(e)
571
}
572
573
# Run concurrent requests
574
results = []
575
with concurrent.futures.ThreadPoolExecutor(max_workers=concurrent_users) as executor:
576
futures = [executor.submit(make_request) for _ in range(num_requests)]
577
results = [future.result() for future in concurrent.futures.as_completed(futures)]
578
579
# Calculate statistics
580
successful_requests = [r for r in results if r["success"]]
581
response_times = [r["response_time"] for r in successful_requests]
582
583
if response_times:
584
stats = {
585
"total_requests": num_requests,
586
"successful_requests": len(successful_requests),
587
"success_rate": len(successful_requests) / num_requests * 100,
588
"avg_response_time": statistics.mean(response_times),
589
"min_response_time": min(response_times),
590
"max_response_time": max(response_times),
591
"median_response_time": statistics.median(response_times)
592
}
593
else:
594
stats = {"error": "No successful requests"}
595
596
return stats
597
598
# Run performance test
599
with NginxContainer() as nginx:
600
server_url = nginx.get_url()
601
602
print(f"Running performance test against: {server_url}")
603
results = performance_test(server_url, num_requests=50, concurrent_users=5)
604
605
print("\nPerformance Test Results:")
606
for key, value in results.items():
607
if isinstance(value, float):
608
print(f"{key}: {value:.4f}")
609
else:
610
print(f"{key}: {value}")
611
```