WebdriverIO Security Testing
Add 250+ security checks to your WebdriverIO automation. Detect XSS vectors, insecure cookies, and more - with rich Allure reporting integration.
Note: WebdriverIO cannot access HTTP response headers, so approximately 5 header-related rules are automatically skipped. All other security checks work identically to Playwright and Puppeteer.
Quick Start with WebdriverIO
1. Install QAstell
npm install qastell
2. Create a WebDriver Adapter
WebdriverIO uses a custom browser object that needs to be wrapped for QAstell:
// webdriverio-adapter.ts
import { createWebDriverAdapter } from 'qastell';
import { SecurityAuditor } from 'qastell';
export async function createAuditor(): Promise<SecurityAuditor> {
const adapter = createWebDriverAdapter(browser);
await adapter.init();
return new SecurityAuditor(adapter as any);
}
3. Add Security Auditing to Your Tests
import { createAuditor } from '../webdriverio-adapter';
describe('Security Audit', () => {
it('should pass security audit on homepage', async () => {
await browser.url('https://your-app.com');
const auditor = await createAuditor();
const results = await auditor.audit();
// Assert no security issues
expect(results.passed()).toBe(true);
});
});
4. Run Your Tests
npm test
Allure Integration: WebdriverIO pairs beautifully with Allure reporting. See the complete example below for rich security reports with labels, steps, and HTML attachments.
Complete WebdriverIO + Allure Example
Here's a comprehensive example showing security auditing with WebdriverIO and Allure reporting:
wdio.conf.ts
import type { Options } from '@wdio/types';
import { initLicense } from 'qastell';
export const config: Options.Testrunner = {
runner: 'local',
specs: ['./tests/**/*.ts'],
capabilities: [{
browserName: 'chrome',
'goog:chromeOptions': {
args: ['--headless', '--disable-gpu']
}
}],
framework: 'mocha',
reporters: [
'spec',
['allure', {
outputDir: 'allure-results',
disableWebdriverStepsReporting: true, // Hide low-level commands
}]
],
mochaOpts: {
ui: 'bdd',
timeout: 60000
},
before: function() {
// Initialize license once before all tests
initLicense(process.env.QASTELL_LICENSE);
}
};
Test with Allure Reporting
import AllureReporter from '@wdio/allure-reporter';
import * as fs from 'fs';
import { createAuditor } from '../webdriverio-adapter';
describe('Security Audit Demo', () => {
it('should audit the login page', async () => {
// Add Allure labels for filtering
AllureReporter.addLabel('epic', 'Security');
AllureReporter.addFeature('Login Page Security');
await browser.url('https://your-app.com/login');
const auditor = await createAuditor();
const results = await auditor.audit({
include: ['forms', 'cookies', 'sensitive-data']
});
// Add meaningful Allure steps
const { summary, violations } = results;
AllureReporter.addStep(`Security Audit: ${summary.total} issues found`);
// Set severity based on findings
if (summary.bySeverity.critical > 0) {
AllureReporter.addSeverity('critical');
} else if (summary.bySeverity.high > 0) {
AllureReporter.addSeverity('normal');
} else {
AllureReporter.addSeverity('minor');
}
// Generate and attach HTML report
const html = results.toHTML();
const reportPath = 'qastell-report/login-audit.html';
fs.mkdirSync('qastell-report', { recursive: true });
fs.writeFileSync(reportPath, html);
AllureReporter.addAttachment(
'QAstell Security Report',
fs.readFileSync(reportPath),
'text/html'
);
// Fail test if security issues found
expect(results.passed()).toBe(true);
});
});
WebdriverIO-Specific Features
Category Filtering
Focus audits on specific security areas:
// Audit only form-related security
const results = await auditor.audit({
include: ['forms', 'sensitive-data']
});
// Exclude certain categories
const results = await auditor.audit({
exclude: ['links', 'tabnabbing']
});
// Skip specific rules
const results = await auditor.audit({
skipRules: ['missing-csp']
});
Report Formats
Generate reports in multiple formats:
// Full HTML report (~50KB)
const fullHtml = results.toHTML();
// Summary HTML report (~5KB)
const summaryHtml = results.toHTML({ summary: true });
// JSON for programmatic access
const json = results.toJSON();
// SARIF for GitHub/GitLab integration
const sarif = results.toSARIF();
// JUnit XML for CI/CD
const junit = results.toJUnitXML();
Severity Thresholds
Configure what constitutes a failing audit:
const results = await auditor.audit({
thresholds: {
critical: 0, // Fail on any critical
high: 2, // Allow up to 2 high
medium: 10, // Allow up to 10 medium
}
});
// Check if passed with thresholds
if (results.passed()) {
console.log('Security audit passed!');
} else {
console.log('Security issues exceed thresholds');
}
Multi-Page Auditing
Audit multiple pages in your test suite:
const pages = [
{ name: 'Home', url: '/' },
{ name: 'Login', url: '/login' },
{ name: 'Dashboard', url: '/dashboard' }
];
for (const page of pages) {
it(`should audit ${page.name} page`, async () => {
await browser.url(page.url);
const auditor = await createAuditor();
const results = await auditor.audit();
expect(results.passed()).toBe(true);
});
}
Limitations
Due to WebdriverIO's architecture (built on WebDriver protocol), there are some limitations compared to Playwright and Puppeteer:
- No HTTP Response Headers - WebdriverIO cannot access HTTP response headers, so header-related rules (approximately 5 rules in the
headerscategory) are automatically skipped. - No Network Interception - WebdriverIO doesn't provide network-level access, so some advanced checks are not available.
- Adapter Required - Unlike Playwright/Puppeteer, WebdriverIO's browser object needs to be wrapped using
createWebDriverAdapter().
All other security checks - DOM analysis, cookie inspection, JavaScript evaluation, storage analysis, and Shadow DOM inspection - work identically across all frameworks.
What Gets Checked
QAstell runs 245+ security checks across these categories when using WebdriverIO:
- 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
- CSP Meta Tags - Content Security Policy in meta tags
- And 40+ more categories...
Using a Different Framework?
Reporter Integration (New)
QAstell v0.7+ introduces a cleaner formatters + adapters architecture for Allure integration:
import { SecurityAuditor, createWebDriverIOAdapter, ReportConnector, adapters } from 'qastell';
import AllureReporter from '@wdio/allure-reporter';
it('should audit the page for security issues', async () => {
const browserAdapter = createWebDriverIOAdapter(browser);
await browserAdapter.init();
const auditor = new SecurityAuditor(browserAdapter as any);
const results = await auditor.audit();
// Create adapter for Allure (auto-detects API style)
const adapter = adapters.allure(AllureReporter);
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);
});
The adapters.allure() function works with both WebDriverIO's @wdio/allure-reporter and Playwright's allure-playwright. See the Reporter Integration section for all available adapters and formatters.