Playwright Security Testing
Add 250+ security checks to your Playwright E2E tests. Detect XSS vectors, CSP issues, insecure cookies, and more - automatically during your existing test runs.
Quick Start with Playwright
1. Install QAstell
npm install qastell
2. Add Security Auditing to Your Test
import { test, expect } from '@playwright/test';
import { SecurityAuditor } from 'qastell';
test('homepage should pass security audit', async ({ page }) => {
await page.goto('https://your-app.com');
// Run 250+ security checks
const auditor = new SecurityAuditor(page);
await auditor.assertNoViolations();
});
3. Run Your Tests
npx playwright test
Zero Configuration: QAstell automatically detects Playwright pages. Just pass your page object to SecurityAuditor and you're done.
Complete Playwright Example
Here's a comprehensive example showing security auditing integrated into a typical Playwright test:
import { test, expect } from '@playwright/test';
import { SecurityAuditor } from 'qastell';
import * as fs from 'fs';
test.describe('Security Audits', () => {
test('login page security', async ({ page }) => {
await page.goto('/login');
const auditor = new SecurityAuditor(page);
// Strict audit - fail on any violation
await auditor.assertNoViolations();
});
test('dashboard with thresholds', async ({ page }) => {
await page.goto('/dashboard');
const auditor = new SecurityAuditor(page);
// Gradual adoption - allow some low-severity issues
await auditor.assertNoViolations({
thresholds: {
info: 10,
low: 5,
medium: 0,
high: 0,
critical: 0,
},
});
});
test('generate security report', async ({ page }) => {
await page.goto('/');
const auditor = new SecurityAuditor(page);
const results = await auditor.audit();
// Save HTML report
fs.writeFileSync('security-report.html', results.toHTML());
// Log summary
console.log(`Found ${results.summary.total} issues`);
});
});
Playwright-Specific Features
Works with All Playwright APIs
QAstell works with Playwright's Page object from any source:
// From test fixtures
test('fixture page', async ({ page }) => {
const auditor = new SecurityAuditor(page);
});
// From browser context
const context = await browser.newContext();
const page = await context.newPage();
const auditor = new SecurityAuditor(page);
// From browser directly
const page = await browser.newPage();
const auditor = new SecurityAuditor(page);
Multi-Page Testing
Audit multiple pages in a single test:
test('audit user journey', async ({ page }) => {
const pagesToAudit = ['/', '/login', '/dashboard', '/settings'];
for (const url of pagesToAudit) {
await page.goto(url);
const auditor = new SecurityAuditor(page);
await auditor.assertNoViolations();
}
});
Integration with Playwright Config
Set up license globally in your Playwright configuration:
// playwright.config.ts
import { defineConfig } from '@playwright/test';
import { initLicense } from 'qastell';
// Initialize license once at config load
initLicense(process.env.QASTELL_LICENSE);
export default defineConfig({
// ... your config
});
Parallel Workers
Playwright runs tests in parallel worker processes by default. For the simplest setup with parallel workers, use the environment variable approach:
# Environment variable is inherited by all workers
QASTELL_LICENSE="your-key" npx playwright test --workers=4
The license is automatically read from QASTELL_LICENSE by each worker process. See parallel execution for more details on scan counting behavior.
Force Framework Detection
If you're using custom page wrappers and auto-detection fails, you can force Playwright mode:
const auditor = new SecurityAuditor(page, { framework: 'playwright' });
// Verify the detected framework
console.log(auditor.getFramework()); // 'playwright'
What Gets Checked
QAstell runs 250+ security checks across these categories when using Playwright:
- Security Headers - CSP, X-Frame-Options, HSTS, Referrer-Policy, Permissions-Policy
- Cookies - HttpOnly, Secure, SameSite flags on sensitive cookies
- Forms - CSRF tokens, autocomplete on sensitive fields, action URLs
- Links - Missing rel="noopener", javascript: URLs
- DOM Security - Inline handlers, DOM clobbering, prototype pollution
- Secrets - API keys, tokens in HTML, comments, localStorage
- Mixed Content - HTTP resources on HTTPS pages
- And 40+ more categories...
Using a Different Framework?
Reporter Integration
QAstell integrates with popular test reporters to display security results alongside your test results.
Allure Reporter
Attach security results to Allure reports (works with both Allure 2 and Allure 3):
import { test, expect } from '@playwright/test';
import { SecurityAuditor, ReportConnector, adapters } from 'qastell';
import { allure } from 'allure-playwright';
test('security audit', async ({ page }) => {
await page.goto('https://example.com');
const auditor = new SecurityAuditor(page);
const results = await auditor.audit();
// Create adapter for Allure
const adapter = adapters.allure(allure);
const connector = new ReportConnector(adapter);
// Attach markdown summary inline, HTML report as attachment
await connector.attach(results, {
inline: 'markdown',
attachments: ['html'],
});
expect(results.passed()).toBe(true);
});
Playwright HTML Reporter
Attach results to Playwright's built-in HTML reporter:
import { test, expect } from '@playwright/test';
import { SecurityAuditor, ReportConnector, adapters } from 'qastell';
test('security audit', async ({ page }, testInfo) => {
await page.goto('https://example.com');
const auditor = new SecurityAuditor(page);
const results = await auditor.audit();
// Create adapter for Playwright testInfo
const adapter = adapters.playwright(testInfo);
const connector = new ReportConnector(adapter);
// Attach compact HTML summary inline, full report as attachment
await connector.attach(results, {
inline: 'htmlSummary',
attachments: ['html'],
});
expect(results.passed()).toBe(true);
});
Cucumber BDD
Playwright works seamlessly with Cucumber for BDD-style security tests:
// steps/security.steps.ts
import { When, Then } from '@cucumber/cucumber';
import { SecurityAuditor, ReportConnector, adapters } from 'qastell';
When('I perform a security audit', async function() {
const auditor = new SecurityAuditor(this.page);
this.auditResults = await auditor.audit();
});
Then('the audit results should be attached to the report', async function() {
// Create adapter for Cucumber (uses World context)
const adapter = adapters.cucumber(this);
const connector = new ReportConnector(adapter);
// Attach markdown summary to Cucumber report
await connector.attach(this.auditResults, {
inline: 'markdown',
});
});
See the playwright-cucumber and playwright-cucumber-multi examples for complete working implementations.
See the Reporter Integration section for all available adapters and formatters.