webdriverio
Skill2 starsChanged 3 months agoMITView on GitHub
WebdriverIO for E2E testing: Page Object Model, selectors, cross-browser execution, mobile emulation, visual regression, and CI/CD integration.
- Installs packages
Files
WebdriverIO
Invoke when user asks about WebdriverIO, WDIO, or Selenium-based E2E automation with modern JavaScript.
Core Principles
- WebDriver protocol: Standard, cross-browser, cross-platform.
- Modern syntax:
async/await, TypeScript, built-in assertions. - Ecosystem: Services, reporters, visual regression, mobile emulation.
Installation & Setup
# Init project
npm create wdio@latest ./
# Select:
# - E2E Testing
# - On my local machine
# - Mocha
# - TypeScript
# - Chrome + Firefox
# - Spec reporter
# - Page Object Modelwdio.conf.ts
export const config: WebdriverIO.Config = {
runner: 'local',
specs: ['./features/**/*.feature'],
exclude: [],
maxInstances: 5,
capabilities: [
{
browserName: 'chrome',
'goog:chromeOptions': { args: ['--headless', '--disable-gpu'] },
},
{
browserName: 'firefox',
'moz:firefoxOptions': { args: ['-headless'] },
},
],
logLevel: 'warn',
baseUrl: 'https://example.com',
waitforTimeout: 10000,
connectionRetryTimeout: 90000,
connectionRetryCount: 3,
services: ['selenium-standalone'],
framework: 'mocha',
reporters: ['spec', ['allure', { outputDir: 'allure-results' }]],
// Page Object auto-import
autoCompileOpts: {
autoCompile: true,
tsNodeOpts: { project: './tsconfig.json' },
},
};Page Object Model
// pages/Login.page.ts
export default class LoginPage {
get inputUsername() { return $('#username'); }
get inputPassword() { return $('#password'); }
get btnSubmit() { return $('button[type="submit"]'); }
get flashMessage() { return $('.flash'); }
async open() {
await browser.url('/login');
}
async login(username: string, password: string) {
await this.inputUsername.setValue(username);
await this.inputPassword.setValue(password);
await this.btnSubmit.click();
}
async getFlashMessage(): Promise<string> {
return this.flashMessage.getText();
}
}Test Example
// specs/login.spec.ts
import LoginPage from '../pages/Login.page';
describe('Login', () => {
const loginPage = new LoginPage();
it('should login with valid credentials', async () => {
await loginPage.open();
await loginPage.login('tomsmith', 'SuperSecretPassword!');
await expect(loginPage.flashMessage).toHaveTextContaining(
'You logged into a secure area!'
);
});
it('should fail with invalid credentials', async () => {
await loginPage.open();
await loginPage.login('foo', 'bar');
await expect(loginPage.flashMessage).toHaveTextContaining(
'Your username is invalid!'
);
});
});Selectors
// CSS
await $('#username'); // ID
await $('.login-form'); // Class
await $('input[type="email"]'); // Attribute
// XPath
await $("//button[contains(text(), 'Submit')]");
// Accessibility
await $('[aria-label="Search"]');
await $('aria/Search'); // WDIO aria selector
// Chain
await $('.cart').$('button.checkout');
// React (with resq)
await $('=LoginForm');Mobile Emulation
// wdio.conf.ts
capabilities: [{
browserName: 'chrome',
'goog:chromeOptions': {
mobileEmulation: { deviceName: 'iPhone 14 Pro Max' },
},
}];Visual Regression
npm install -D wdio-image-comparison-service// wdio.conf.ts
services: [
['image-comparison', {
baselineFolder: './baseline',
formatImageName: '{tag}-{width}x{height}',
screenshotPath: './screenshots',
savePerInstance: true,
autoSaveBaseline: true,
}],
];// test
it('should match homepage', async () => {
await browser.url('/');
expect(await browser.checkScreen('homepage', {})).toEqual(0);
});CI/CD Integration
# .github/workflows/e2e.yml
name: E2E Tests
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npx wdio run wdio.conf.ts
- uses: actions/upload-artifact@v4
if: failure()
with:
name: wdio-screenshots
path: screenshots/Cucumber Integration
npm install -D @wdio/cucumber-framework// features/login.feature
Feature: Login
Scenario: Valid login
Given I open the login page
When I enter valid credentials
Then I should see the secure area// step-definitions/login.steps.ts
import { Given, When, Then } from '@wdio/cucumber-framework';
import LoginPage from '../pages/Login.page';
const loginPage = new LoginPage();
Given('I open the login page', async () => {
await loginPage.open();
});
When('I enter valid credentials', async () => {
await loginPage.login('tomsmith', 'SuperSecretPassword!');
});
Then('I should see the secure area', async () => {
await expect(loginPage.flashMessage).toHaveTextContaining('secure');
});Anti-Patterns
| Anti-Pattern | Fix |
browser.pause(3000) | Use explicit waits: waitForDisplayed, waitForClickable |
| XPath with indices | Use CSS or stable data-testid |
| One massive spec file | Split by domain/page |
| No baseline for visual tests | Auto-save baseline in CI on main branch |
| Testing in only Chrome | Add Firefox, Safari in pipeline |
Quick Reference
| Command | Purpose |
browser.url('/path') | Navigate |
$('#id').click() | Click element |
$('#id').setValue('text') | Type text |
$('#id').getText() | Get text |
$('#id').isDisplayed() | Check visibility |
browser.saveScreenshot('name.png') | Screenshot |
browser.execute(() => window.scrollTo(0,0)) | Execute JS |
In this repository45 other files it gives its agents.
- AGENTS.mdAGENTS.md
- allure-reportsSkill
- android-nativeSkill
- appian-lowcodeSkill
- appium-mobileSkill
- behave-bddSkill
- BiDiWave Cross-BrowserSkill
- BiDiWave Network InterceptionSkill
- CDPWave DebuggingSkill
- CDPWave TestingSkill
- db2-oracleSkill
- ebook-writerSkill
- flask-apiSkill
- flet-desktopSkill
- google-crawling-indexingSkill
- google-ranking-appearanceSkill
- google-seo-fundamentalsSkill
- google-seo-monitoringSkill
- jinja2-templatesSkill
- jmeter-load-testingSkill
- k6-load-testingSkill
- karate-api-testingSkill
- octane-almSkill
- paramiko-sshSkill
- postman-api-automationSkill
- prestashop-moduleSkill
- prompt-engineering-best-practicesSkill
- pytest-advancedSkill
- robot-frameworkSkill
- salesforce-devSkill
- sonarqube-quality-gatesSkill
- sql-serverSkill
- Skill NameSkill
- testcontainersSkill
- wave-ecosystem-guideSkill
- WaveXis AccessibilitySkill
- WaveXis CI/CD IntegrationSkill
- wavexis-cli-automationSkill
- wavexis-mcp-agent-integrationSkill
- WaveXis Network TestingSkill
- WaveXis Performance AuditSkill
- WaveXis Session RecordingSkill
- WaveXis Web ScrapingSkill
- wordpress-themesSkill
- xctest-iosSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

