WebdriverIO

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:

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:

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.

Next Steps