Taiko Getting Started: Browser Automation with Node.js

Taiko Getting Started: Browser Automation with Node.js

Taiko is an open-source browser automation library built by ThoughtWorks. It uses a Node.js API and Chrome DevTools Protocol (CDP) directly — no WebDriver intermediary. The result is a faster, more reliable automation tool with a selector model designed to match how users actually interact with pages.

What Makes Taiko Different

Taiko's key design choices:

  • Smart selectors: Finds elements by proximity to labels, not just CSS paths
  • Implicit wait: Waits for page load and network activity automatically — no manual waits for most actions
  • REPL mode: Interactive session for exploring and debugging selectors
  • CDP-native: Direct Chrome DevTools Protocol, not WebDriver — faster and more reliable

Taiko is frequently used with Gauge, ThoughtWorks' test framework, but it works standalone with any test runner.

Installation

npm install --save-dev taiko

This installs Taiko and downloads Chromium automatically. No separate browser driver installation needed.

Verify the installation:

npx taiko --version

First Script

Create tests/first-test.js:

const { openBrowser, goto, click, type, closeBrowser, $, text } = require('taiko');

(async () => {
    try {
        await openBrowser({ headless: true });
        await goto('https://example.com');
        console.log('Page loaded');
        await closeBrowser();
    } catch (e) {
        console.error('Test failed:', e);
        await closeBrowser();
        process.exit(1);
    }
})();

Run it:

node tests/first-test.js

Core Actions

Taiko provides a flat API of action functions:

const { openBrowser, goto, click, type, write, press, closeBrowser,
        $, text, button, link, inputField, checkBox, dropDown,
        waitFor, screenshot, focus } = require('taiko');

// Navigation
await goto('https://example.com/login');
await reload();

// Typing
await write('user@example.com', into(inputField('Email')));
await type('password123', { into: $('input[name=password]') });

// Clicking
await click('Sign In');                    // find by text
await click(button('Submit'));             // find button by text
await click(link('Forgot password?'));     // find link by text
await click($('#submit-btn'));             // find by CSS selector

// Form interactions
await checkBox('Remember me').check();
await dropDown('Country').select('United States');

// Keyboard
await press('Enter');
await press('Tab');

// Waiting
await waitFor(2000);                       // fixed wait (avoid when possible)
await waitFor(() => text('Success').exists());  // conditional wait

// Utilities
await screenshot({ path: 'output.png' });
await scrollDown();
await scrollUp();

Smart Selectors

This is Taiko's most distinctive feature. Rather than requiring CSS paths, Taiko finds elements based on how they relate to visible text on the page.

Text-Based Selectors

// Find elements by their visible text
await click('Sign In');
await click(button('Add to Cart'));
await click(link('Privacy Policy'));

Proximity Selectors

Find inputs by their associated label text, even without for/id attributes:

// Find input near the label "Email Address"
await write('user@example.com', into(inputField('Email Address')));

// Find input to the right of the label "Username"
await write('alice', into(inputField(toRightOf('Username'))));

// Find checkbox below a heading
await checkBox(below('Notifications')).check();

Proximity selectors are powerful for forms where CSS selectors are fragile or where id/name attributes aren't set.

CSS Selectors

Standard CSS selectors with $():

await click($('button.primary'));
await type('search term', { into: $('input[type=search]') });

Combining Selectors

// Button with specific text inside a specific container
await click(button('Delete', within($('#actions-panel'))));

// Link near specific text
await click(link(near('Alice Johnson')));

Writing Tests with a Test Runner

Taiko works with any Node.js test runner. Here's a Mocha example:

const { openBrowser, closeBrowser, goto, write, click, 
        button, text, inputField, $, waitFor } = require('taiko');
const assert = require('assert');

describe('Login flow', () => {
    before(async () => {
        await openBrowser({ headless: true });
    });

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

    it('allows valid login', async () => {
        await goto('https://example.com/login');
        await write('alice@example.com', into(inputField('Email')));
        await write('password123', into(inputField('Password')));
        await click(button('Sign In'));

        assert.ok(await text('Welcome, Alice').exists());
    });

    it('shows error for wrong password', async () => {
        await goto('https://example.com/login');
        await write('alice@example.com', into(inputField('Email')));
        await write('wrongpassword', into(inputField('Password')));
        await click(button('Sign In'));

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

Interactive REPL

Taiko's REPL is useful for exploring a page and building selectors interactively:

npx taiko

In the REPL:

> openBrowser()
> goto('https://example.com')
> $('h1').text()
'Example Domain'
> click('More information...')
> screenshot()

Once you've found the right selectors, copy the commands into your test file. The REPL dramatically speeds up test development.

Headless Configuration

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

// With visible browser (for debugging)
await openBrowser({ headless: false });

// Slow motion (for debugging timing issues)
await openBrowser({
    headless: false,
    slowMo: 100  // 100ms between actions
});

Running in CI

TAIKO_BROWSER_ARGS="--no-sandbox,--disable-dev-shm-usage" npx mocha tests/

Or set in code:

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

Implicit Waiting

Taiko automatically waits for:

  • Page load to complete after navigation
  • Network requests to settle after actions
  • Elements to be interactive before acting on them

This means you don't need waitFor after most clicks and form submissions. Add explicit waitFor only when you need to wait for a specific condition:

// Usually not needed — Taiko waits for page load automatically:
await goto('https://example.com/dashboard');
// Dashboard is already loaded here

// Needed for AJAX content that loads after the page:
await waitFor(() => text('Results').exists());

Summary

Taiko's value proposition is a cleaner automation experience: smart selectors that survive UI refactors, implicit waiting that removes timing boilerplate, and a REPL for interactive exploration. It runs on Node.js, uses Chrome directly via CDP, and integrates with any test framework.

The smart selectors are the standout feature — inputField('Email Address') is more resilient than $('form > div:nth-child(2) > input') and communicates intent clearly. That alone makes Taiko worth evaluating for Node.js teams.

Read more

Start now free