or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cache-messaging.mdcloud-services.mdcompose.mdcore-containers.mddatabase-containers.mdindex.mdsearch-analytics.mdwaiting-strategies.mdweb-testing.md

web-testing.mddocs/

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

```