What Is Keyword-Driven Testing?

Keyword-driven testing (also called table-driven or action-word testing) separates test design from test implementation by defining tests as sequences of keywords — human-readable action words that map to automation code.

A keyword table might look like this:

StepKeywordArgument 1Argument 2
1Open Browserhttps://app.example.comChrome
2Enter Text#emailadmin@test.com
3Enter Text#passwordsecret123
4Click Button#login-btn
5Verify Text.welcomeWelcome, Admin
6Close Browser

Non-technical team members can read, write, and maintain these tables without understanding the underlying automation code.

Architecture

Keyword-driven testing has three layers:

┌─────────────────────┐
│   Test Cases         │  Keyword tables (what to test)
│   (Keywords + Data)  │
├─────────────────────┤
│   Keyword Library    │  Mapping keywords to code
│   (Definitions)      │
├─────────────────────┤
│   Automation Engine  │  Selenium, Playwright, API clients
│   (Implementation)   │
└─────────────────────┘

Layer 1: Test Cases (Keyword Tables)

Written in spreadsheets, CSV files, or specialized tools:

Test Case: Valid Login
  Open Browser    ${BASE_URL}
  Login           admin@test.com    secret123
  Verify Page     Dashboard
  Logout
  Close Browser

Layer 2: Keyword Library

Definitions that map keywords to automation code:

const keywords = {
  'Open Browser': async (url) => {
    browser = await chromium.launch();
    page = await browser.newPage();
    await page.goto(url);
  },

  'Login': async (email, password) => {
    await page.fill('#email', email);
    await page.fill('#password', password);
    await page.click('#login-btn');
  },

  'Verify Page': async (pageName) => {
    const titles = { Dashboard: 'Dashboard - MyApp', Profile: 'Profile - MyApp' };
    await expect(page).toHaveTitle(titles[pageName]);
  },

  'Logout': async () => {
    await page.click('#logout');
  },

  'Close Browser': async () => {
    await browser.close();
  }
};

Layer 3: Automation Engine

The actual browser automation, API calls, and assertions handled by tools like Playwright or Selenium.

Robot Framework: The Standard

Robot Framework is the most popular keyword-driven testing tool. It uses a tabular syntax with .robot files.

Basic Robot Framework Test

*** Settings ***
Library    Browser

*** Test Cases ***
Valid Login
    New Browser    chromium    headless=false
    New Page       https://app.example.com/login
    Fill Text      #email       admin@test.com
    Fill Text      #password    secret123
    Click          #login-btn
    Get Title      ==    Dashboard - MyApp

Invalid Login Shows Error
    New Browser    chromium    headless=false
    New Page       https://app.example.com/login
    Fill Text      #email       wrong@test.com
    Fill Text      #password    wrongpass
    Click          #login-btn
    Get Text       .error    ==    Invalid credentials

Custom Keywords in Robot Framework

*** Keywords ***
Login With Credentials
    [Arguments]    ${email}    ${password}
    Fill Text      #email       ${email}
    Fill Text      #password    ${password}
    Click          #login-btn

Verify Dashboard Loaded
    Get Title      ==    Dashboard - MyApp
    Get Text       .welcome    contains    Welcome

*** Test Cases ***
Admin Can Access Dashboard
    New Browser    chromium    headless=false
    New Page       https://app.example.com/login
    Login With Credentials    admin@test.com    secret123
    Verify Dashboard Loaded

Building a Custom Keyword Engine

If Robot Framework does not fit your stack, you can build a lightweight keyword engine:

class KeywordEngine {
  constructor() {
    this.keywords = new Map();
    this.variables = new Map();
  }

  register(name, implementation) {
    this.keywords.set(name.toLowerCase(), implementation);
  }

  setVariable(name, value) {
    this.variables.set(name, value);
  }

  resolveArgs(args) {
    return args.map(arg => {
      if (arg.startsWith('${') && arg.endsWith('}')) {
        const varName = arg.slice(2, -1);
        return this.variables.get(varName) || arg;
      }
      return arg;
    });
  }

  async execute(keyword, ...args) {
    const impl = this.keywords.get(keyword.toLowerCase());
    if (!impl) throw new Error(`Unknown keyword: ${keyword}`);
    const resolvedArgs = this.resolveArgs(args);
    await impl(...resolvedArgs);
  }

  async runTestCase(steps) {
    for (const step of steps) {
      const [keyword, ...args] = step;
      console.log(`  Executing: ${keyword} ${args.join(' ')}`);
      await this.execute(keyword, ...args);
    }
  }
}

Advanced Keyword Patterns

Composite Keywords

Build complex keywords from simpler ones:

engine.register('complete checkout', async (product, card) => {
  await engine.execute('add to cart', product);
  await engine.execute('go to checkout');
  await engine.execute('enter payment', card);
  await engine.execute('confirm order');
});

// Test case uses the composite keyword
const testCase = [
  ['login', 'customer@test.com', 'password'],
  ['complete checkout', 'Wireless Mouse', '4242424242424242'],
  ['verify order confirmation'],
];

Data-Driven Keywords

Combine keyword-driven with data-driven approaches:

Test Template: Login Test
  [Arguments]    ${email}    ${password}    ${expected}
  Open Browser   ${BASE_URL}
  Login          ${email}    ${password}
  Verify Result  ${expected}

Test Data:
  | admin@test.com | AdminPass1 | success |
  | wrong@test.com | wrong      | error   |
  | ""             | ""         | error   |

Error Handling Keywords

engine.register('try keyword', async (keyword, ...args) => {
  try {
    await engine.execute(keyword, ...args);
    return true;
  } catch (error) {
    console.log(`Keyword failed: ${keyword} - ${error.message}`);
    return false;
  }
});

engine.register('retry keyword', async (keyword, retries, ...args) => {
  for (let i = 0; i < parseInt(retries); i++) {
    try {
      await engine.execute(keyword, ...args);
      return;
    } catch (e) {
      if (i === parseInt(retries) - 1) throw e;
    }
  }
});

When to Use Keyword-Driven Testing

ScenarioKeyword-Driven?
Non-technical team members write testsYes
Highly regulated industry (requires traceable test cases)Yes
Small team, all programmersProbably not
Complex logic requiring code flexibilityNo
Integration with existing code-based frameworkHybrid approach
Rapid prototypingNo

Advantages

  • Accessible to non-programmers
  • Tests serve as documentation
  • Separation of test design from implementation
  • Easy to create new test cases from existing keywords

Disadvantages

  • Additional abstraction layer adds complexity
  • Debugging can be harder (which keyword failed and why?)
  • Limited flexibility compared to code-based tests
  • Maintaining the keyword library requires developer support

Exercise: Design a Keyword-Driven Test Suite

Create a keyword library and test cases for an e-commerce application:

  1. Define 10 keywords: OpenBrowser, Login, SearchProduct, AddToCart, ViewCart, UpdateQuantity, RemoveItem, Checkout, VerifyOrderTotal, CloseBrowser
  2. Write 3 test cases using these keywords (happy path, empty cart, invalid payment)
  3. Create 2 composite keywords that combine multiple basic keywords
  4. Add a data-driven test case that tests 5 different product searches
  5. Implement the keyword definitions using Playwright

Key Takeaways

  • Keyword-driven testing uses human-readable keywords to abstract automation complexity
  • Three layers: test cases (keywords), keyword library (definitions), automation engine
  • Robot Framework is the industry standard for keyword-driven testing
  • Best suited for teams with non-technical test designers
  • Composite keywords build complex tests from simple building blocks
  • Can be combined with data-driven testing for maximum flexibility