TL;DR

  • Taiko uses natural language selectors: click('Login') instead of page.locator('#btn-login').click()
  • Built-in REPL mode for interactive test development — type .code to generate script from your session
  • Best for: teams prioritizing simplicity over advanced features; rapid prototyping

Best for: Teams new to browser automation or frustrated with flaky XPath/CSS selectors Skip if: You need parallel execution, complex multi-browser scenarios, or mobile testing Read time: 10 minutes

Your Selenium tests fail because a developer renamed a CSS class. Your Playwright selectors break when the DOM structure changes. What if your tests could find elements the way humans do — by the text they see?

Taiko takes a different approach to browser automation. Instead of brittle locators, you write click('Submit') and Taiko figures out which button you mean.

What Makes Taiko Different

Taiko is a free and open-source browser automation tool from ThoughtWorks, designed with smart selectors and a human-readable API. The key difference from Selenium or Playwright: you describe what you see, not where it is in the DOM.

Smart Selectors: Natural Language Automation

// Traditional Selenium/Playwright
await page.locator('#username').fill('user@example.com');
await page.locator('xpath=//button[contains(text(), "Login")]').click();

// Taiko - Smart Selectors
await write('user@example.com', into(textBox('Username')));
await click('Login');

// More examples
await write('John Doe', into('Full Name'));
await click(button('Submit'));
await click(link('Contact Us'));
await select('California', from('State'));
await attach('resume.pdf', to('Upload Resume'));

REPL Mode: Interactive Testing

# Start Taiko REPL
$ taiko

> openBrowser()
✔ Browser opened
> goto('https://example.com')
✔ Navigated to URL https://example.com
> write('search query', into('Search'))
✔ Wrote search query into the Search
> click('Search')
✔ Clicked element matching text "Search"
> screenshot()
✔ Screenshot is created at /screenshots/1234567890.png
> .code
// Code generated for this session:
const { openBrowser, goto, write, click, screenshot } = require('taiko');
(async () => {
    try {
        await openBrowser();
        await goto('https://example.com');
        await write('search query', into('Search'));
        await click('Search');
        await screenshot();
    } catch (error) {
        console.error(error);
    } finally {
        await closeBrowser();
    }
})();
> closeBrowser()
✔ Browser closed

Complete Test Example

// test/login.test.js
const { openBrowser, goto, write, click, text, closeBrowser, into, button } = require('taiko');

describe('User Authentication', () => {
  beforeAll(async () => {
    await openBrowser({ headless: true });
  });

  afterAll(async () => {
    await closeBrowser();
  });

  test('should login with valid credentials', async () => {
    await goto('https://example.com/login');

    await write('user@example.com', into('Email'));
    await write('password123', into('Password'));
    await click(button('Login'));

    await text('Welcome back').exists();
  });

  test('should show error for invalid credentials', async () => {
    await goto('https://example.com/login');

    await write('invalid@example.com', into('Email'));
    await write('wrongpass', into('Password'));
    await click(button('Login'));

    await text('Invalid credentials').exists();
  });
});

Advanced Features

Proximity Selectors

// Find elements relative to others
await write('John', into(textBox(near('First Name'))));
await write('Doe', into(textBox(near('Last Name'))));

await click(button('Save', below('Profile Picture')));
await click(link('Edit', toRightOf('John Doe')));

// Chaining proximity
await write('94105', into(
  textBox(near('Zip Code'), below('Address'))
));

Custom Waits and Assertions

const { openBrowser, goto, click, waitFor, text, evaluate } = require('taiko');

// Wait for element
await waitFor('Loading complete');
await waitFor(2000);  // Wait 2 seconds
await waitFor(async () => (await $('div.loader').exists()) === false);

// Custom assertions
await text('Order Confirmed').exists();
await text('Error').exists(undefined, { timeout: 1000 }).catch(() => {
  console.log('No error message shown');
});

// Evaluate JavaScript
const count = await evaluate(() => {
  return document.querySelectorAll('.product-item').length;
});
console.log(`Found ${count} products`);

Intercept Network Requests

const { openBrowser, goto, intercept, click } = require('taiko');

// Intercept and modify requests
await intercept('https://api.example.com/products', {
  body: JSON.stringify({
    products: [
      { id: 1, name: 'Test Product', price: 99.99 }
    ]
  })
});

await goto('https://example.com/products');
// Page will receive mocked response

// Intercept and validate
await intercept('https://api.example.com/orders', (request) => {
  console.log('Order request:', request.postData);
  return { status: 201, body: { orderId: '12345' } };
});

await click('Place Order');

Taiko vs Selenium vs Playwright

FeatureTaikoSeleniumPlaywright
Selector StrategySmart, natural languageManual (ID, CSS, XPath)Advanced (text, role, label)
REPL ModeBuilt-inNoNo
Learning CurveVery LowMedium-HighMedium
Auto-waitIntelligentManualBuilt-in
Browser SupportChrome, Firefox, SafariAll major browsersChromium, Firefox, WebKit
Multi-tabYesYesExcellent
Network InterceptYesLimitedExcellent
ScreenshotsEasyManualBuilt-in
Video RecordingPluginNoBuilt-in
Code GenerationREPL .codeNoCodegen tool
Mobile TestingLimitedYes (Appium)Limited
Parallel ExecutionManualYesBuilt-in
CommunityGrowingVery LargeLarge

Headless Testing

const { openBrowser, goto, screenshot, closeBrowser } = require('taiko');

(async () => {
  try {
    // Headless mode
    await openBrowser({ headless: true });
    await goto('https://example.com');

    // Headless with custom args
    await openBrowser({
      headless: true,
      args: [
        '--no-sandbox',
        '--disable-setuid-sandbox',
        '--disable-dev-shm-usage'
      ]
    });

    await screenshot({ fullPage: true });
  } finally {
    await closeBrowser();
  }
})();

CI/CD Integration

# .github/workflows/taiko-tests.yml
name: Taiko E2E Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:

      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Run Taiko tests
        run: npm test

      - name: Upload screenshots
        if: failure()
        uses: actions/upload-artifact@v3
        with:
          name: taiko-screenshots
          path: screenshots/

Best Practices

1. Page Object Pattern with Taiko

// pages/LoginPage.js
const { goto, write, click, into, button } = require('taiko');

class LoginPage {
  async navigate() {
    await goto('https://example.com/login');
  }

  async login(email, password) {
    await write(email, into('Email'));
    await write(password, into('Password'));
    await click(button('Login'));
  }

  async loginAsAdmin() {
    await this.login('admin@example.com', 'admin123');
  }
}

module.exports = new LoginPage();

2. Reusable Helpers

// helpers/auth.js
const { write, click, into, button } = require('taiko');

async function loginAs(userType) {
  const users = {
    admin: { email: 'admin@example.com', password: 'admin123' },
    user: { email: 'user@example.com', password: 'user123' }
  };

  const credentials = users[userType];
  await write(credentials.email, into('Email'));
  await write(credentials.password, into('Password'));
  await click(button('Login'));
}

module.exports = { loginAs };

3. Custom Assertions

// helpers/assertions.js
const { text } = require('taiko');

async function assertTextExists(expectedText, message) {
  const exists = await text(expectedText).exists();
  if (!exists) {
    throw new Error(message || `Text "${expectedText}" not found`);
  }
}

async function assertTextNotExists(unexpectedText) {
  const exists = await text(unexpectedText).exists();
  if (exists) {
    throw new Error(`Text "${unexpectedText}" should not exist`);
  }
}

module.exports = { assertTextExists, assertTextNotExists };

AI-Assisted Test Development with Taiko

AI tools work well with Taiko’s natural language approach.

What AI does well:

  • Converting manual test descriptions to Taiko scripts (natural language in, natural language out)
  • Generating proximity selector chains for complex forms
  • Creating test data sets for data-driven testing
  • Explaining Taiko’s API functions and their Selenium/Playwright equivalents

What still needs humans:

  • Deciding which user flows need automation
  • Determining appropriate assertions for business logic
  • Debugging timing issues in dynamic applications
  • Choosing between Taiko’s multiple selector strategies for ambiguous elements

Useful prompt:

Convert this manual test case to a Taiko script:
1. Open the login page
2. Enter username in the Username field
3. Enter password in the Password field
4. Click the Login button
5. Verify "Welcome back" text appears

Use Taiko's smart selectors and proper error handling.

FAQ

What is Taiko used for?

Taiko is a Node.js browser automation tool from ThoughtWorks designed for web testing. Its key feature is smart selectors — you write click('Login') instead of finding CSS selectors or XPath. This makes tests more readable and less brittle when UI changes. Taiko is used for E2E testing, regression testing, and rapid prototyping of browser automation scripts.

Is Taiko better than Playwright?

They serve different needs. Taiko excels at simplicity: the REPL mode lets you build tests interactively, and smart selectors reduce maintenance burden. Playwright offers more features: parallel execution, multiple browser contexts, video recording, and trace viewer for debugging. Choose Taiko for small to medium projects prioritizing developer experience. Choose Playwright for large test suites needing advanced features.

Does Taiko support headless testing?

Yes. Use openBrowser({ headless: true }) for headless mode. This is essential for CI/CD pipelines where no display is available. Taiko also supports custom browser arguments for Docker environments:

await openBrowser({
  headless: true,
  args: ['--no-sandbox', '--disable-dev-shm-usage']
});

Can Taiko intercept network requests?

Yes. Taiko’s intercept() function mocks API responses without hitting the backend:

await intercept('https://api.example.com/users', {
  body: JSON.stringify([{ id: 1, name: 'Test User' }])
});

This is similar to Playwright’s page.route() or Cypress cy.intercept(). Useful for testing error states, slow network conditions, or isolating frontend tests from backend dependencies.

When to Choose Taiko

Choose Taiko when:

  • Team values simplicity and ease of use
  • Natural language selectors preferred
  • REPL-driven development is attractive
  • Chromium/Firefox/Safari coverage sufficient
  • Rapid prototyping needed

Choose alternatives when:

  • Need advanced features like trace viewer (Playwright)
  • Large existing test infrastructure in another framework
  • Mobile testing essential (Appium)
  • Built-in parallel execution needed (Playwright)
  • Extensive browser version matrix required (Selenium Grid)

For projects where developer experience and test maintainability are priorities, Taiko’s smart selectors and intuitive API provide a compelling alternative to traditional automation frameworks.

Official Resources

See Also