Traditional element selectors are fragile. A single DOM change can break dozens of tests. wdio-ai-locator-service takes a radically different approach — describe what you want in plain English, and let AI find it for you.
The Problem with Traditional Selectors
| Feature | Traditional Selectors | AI Locator Service |
|---|---|---|
| Maintainability | Manual updates needed | Self-healing locators |
| Readability | Complex XPath/CSS | Plain English |
| Speed | Write & debug selectors | Describe what you want |
| Resilience | Breaks on DOM changes | Adapts automatically |
| Collaboration | Technical knowledge required | Anyone can write tests |
Features
- Natural Language — Find elements using plain English descriptions
- Self-Healing — Auto-regenerates locators when UI changes
- Smart Caching — Reduces AI calls by 99% with intelligent caching
- Template Variables — Reusable dynamic locators with
{variable}syntax - Multi-Provider Support — Works with OpenAI, OpenAI Router, and Ollama
- Usage Tracking — Monitor AI API consumption and costs
- Auto-Retry — Multiple fallback strategies for maximum reliability
Installation
npm install wdio-ai-locator-service --save-dev
Quick Start
Step 1: Configure the Service
// wdio.conf.ts
export const config = {
services: [
['ai-locator', {
provider: 'openai',
apiKey: process.env.OPENAI_API_KEY,
model: 'gpt-4o-mini',
enableUsageTracking: true,
cachePath: './.ai-locator-cache.json'
}]
]
}
Step 2: Write Tests with Natural Language
describe('Login Flow', () => {
it('should login successfully', async () => {
await browser.url('https://example.com/login')
const emailInput = await browser.aiLocator('email input field')
await $(emailInput).setValue('user@example.com')
const passwordInput = await browser.aiLocator('password field')
await $(passwordInput).setValue('secret123')
const loginButton = await browser.aiLocator('login button')
await $(loginButton).click()
})
})
Template Variables for Data-Driven Testing
The killer feature — use template caching to make 1 AI call instead of N calls in loops:
const users = ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve']
for (const userName of users) {
const locator = await browser.aiLocator('Edit button for {userName}', {
variables: { userName },
cacheBy: 'template' // Only 1 AI call for all 5 users!
})
await $(locator).click()
}
// Without template caching: 5 AI calls
// With template caching: 1 AI call — 80% cost reduction!
Global Context
Set variables once, use everywhere:
describe('User Management', () => {
beforeEach(async () => {
await browser.setAiContext({
userName: 'John Doe',
role: 'admin'
})
})
afterEach(async () => {
await browser.clearAiContext()
})
it('should manage profile', async () => {
const profileLoc = await browser.aiLocator('Profile for {userName}')
await $(profileLoc).click()
})
})
Multi-Provider Support
| Provider | Cost | Speed | Accuracy | Privacy |
|---|---|---|---|---|
| OpenAI | $$ | Fast | Excellent | Cloud |
| OpenAI Router | $ | Good | Good | Cloud |
| Ollama | Free | Good | Good | Local |
Ollama (Local / Free)
services: [
['ai-locator', {
provider: 'ollama',
model: 'llama3',
baseUrl: 'http://localhost:11434'
}]
]
Auto-Heal Feature
When a cached locator fails to find an element, the service automatically:
- Detects that the cached selector no longer works
- Sends a fresh request to the AI with the current page DOM
- Generates new selectors and updates the cache
- Continues the test without manual intervention
For the full documentation, visit the GitHub repo.
Want to try AI-powered testing? Feel free to reach out or open an issue on GitHub.