seed-skills/gauge-testing/SKILL.md
Test automation with Gauge framework using Markdown specifications, step implementations in Java/Python/JavaScript/Ruby/C#, concepts, data-driven testing, and living documentation.
npx skillsauth add PramodDutta/qaskills Gauge TestingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are an expert QA engineer specializing in Gauge, ThoughtWorks' open-source test automation framework. When the user asks you to write, review, debug, or set up Gauge tests, follow these detailed instructions. You understand the Gauge ecosystem deeply including Markdown-based specifications, multi-language step implementations (Java, Python, JavaScript, Ruby, C#), concepts, data tables, tags, hooks, screenshots, and parallel execution.
project-root/
├── manifest.json # Gauge project configuration
├── env/
│ ├── default/
│ │ └── default.properties # Default environment variables
│ ├── staging/
│ │ └── staging.properties # Staging environment overrides
│ └── ci/
│ └── ci.properties # CI environment overrides
├── specs/
│ ├── auth/
│ │ ├── login.spec # Login specification
│ │ ├── signup.spec # Signup specification
│ │ └── concepts/
│ │ └── auth.cpt # Auth-related concepts
│ ├── shopping/
│ │ ├── cart.spec
│ │ ├── checkout.spec
│ │ └── concepts/
│ │ └── shopping.cpt
│ └── api/
│ ├── users_api.spec
│ └── orders_api.spec
├── src/test/java/ # Java step implementations
│ ├── steps/
│ │ ├── AuthSteps.java
│ │ ├── ShoppingSteps.java
│ │ └── ApiSteps.java
│ ├── pages/
│ │ ├── BasePage.java
│ │ ├── LoginPage.java
│ │ └── DashboardPage.java
│ └── hooks/
│ └── ExecutionHooks.java
├── reports/
│ └── html-report/
└── pom.xml # Maven configuration (Java)
# User Authentication
Tags: auth, smoke
## Successful Login
Tags: positive, critical
* Navigate to login page
* Enter email "[email protected]"
* Enter password "SecurePass123"
* Click the login button
* Verify user is on the dashboard
* Verify welcome message contains "Welcome"
## Login with Invalid Credentials
Tags: negative
* Navigate to login page
* Enter email "[email protected]"
* Enter password "wrongpassword"
* Click the login button
* Verify error message "Invalid credentials" is displayed
* Verify user is still on the login page
## Login Validation Errors
|email |password |error |
|-------------------|-------------|----------------------|
| |SecurePass123|Email is required |
|[email protected] | |Password is required |
|invalid-email |SecurePass123|Invalid email format |
* Navigate to login page
* Enter email <email>
* Enter password <password>
* Click the login button
* Verify error message <error> is displayed
# Login as user with email <email> and password <password>
* Navigate to login page
* Enter email <email>
* Enter password <password>
* Click the login button
* Verify user is on the dashboard
# Create a new user with name <name> and email <email>
* Send POST request to "/api/users" with name <name> and email <email>
* Verify response status code is "201"
* Save created user ID
# Add product to cart and verify
* Click "Add to Cart" button for the current product
* Verify cart count increases by "1"
* Verify success notification is displayed
// src/test/java/steps/AuthSteps.java
package steps;
import com.thoughtworks.gauge.Step;
import com.thoughtworks.gauge.Table;
import com.thoughtworks.gauge.TableRow;
import com.thoughtworks.gauge.datastore.ScenarioDataStore;
import org.openqa.selenium.WebDriver;
import pages.LoginPage;
import pages.DashboardPage;
import static org.assertj.core.api.Assertions.assertThat;
public class AuthSteps {
private final LoginPage loginPage;
private final DashboardPage dashboardPage;
public AuthSteps() {
WebDriver driver = DriverFactory.getDriver();
this.loginPage = new LoginPage(driver);
this.dashboardPage = new DashboardPage(driver);
}
@Step("Navigate to login page")
public void navigateToLoginPage() {
loginPage.open();
assertThat(loginPage.isLoaded()).isTrue();
}
@Step("Enter email <email>")
public void enterEmail(String email) {
loginPage.enterEmail(email);
}
@Step("Enter password <password>")
public void enterPassword(String password) {
loginPage.enterPassword(password);
}
@Step("Click the login button")
public void clickLoginButton() {
loginPage.clickLogin();
}
@Step("Verify user is on the dashboard")
public void verifyOnDashboard() {
assertThat(dashboardPage.isLoaded())
.as("User should be on the dashboard")
.isTrue();
}
@Step("Verify welcome message contains <text>")
public void verifyWelcomeMessage(String text) {
String message = dashboardPage.getWelcomeMessage();
assertThat(message)
.as("Welcome message should contain '%s'", text)
.contains(text);
}
@Step("Verify error message <message> is displayed")
public void verifyErrorMessage(String message) {
String actual = loginPage.getErrorMessage();
assertThat(actual)
.as("Error message should be '%s'", message)
.isEqualTo(message);
}
@Step("Verify user is still on the login page")
public void verifyStillOnLoginPage() {
assertThat(loginPage.isLoaded())
.as("User should still be on the login page")
.isTrue();
}
}
# step_impl/auth_steps.py
from getgauge.python import step, before_scenario, after_scenario, data_store
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from pages.login_page import LoginPage
from pages.dashboard_page import DashboardPage
@before_scenario
def setup_browser(context):
chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--window-size=1920,1080")
driver = webdriver.Chrome(options=chrome_options)
data_store.scenario["driver"] = driver
data_store.scenario["login_page"] = LoginPage(driver)
data_store.scenario["dashboard_page"] = DashboardPage(driver)
@after_scenario
def teardown_browser(context):
driver = data_store.scenario.get("driver")
if driver:
driver.quit()
@step("Navigate to login page")
def navigate_to_login():
page = data_store.scenario["login_page"]
page.open()
assert page.is_loaded(), "Login page did not load"
@step("Enter email <email>")
def enter_email(email):
data_store.scenario["login_page"].enter_email(email)
@step("Enter password <password>")
def enter_password(password):
data_store.scenario["login_page"].enter_password(password)
@step("Click the login button")
def click_login():
data_store.scenario["login_page"].click_login()
@step("Verify user is on the dashboard")
def verify_on_dashboard():
page = data_store.scenario["dashboard_page"]
assert page.is_loaded(), "Dashboard did not load"
@step("Verify welcome message contains <text>")
def verify_welcome(text):
page = data_store.scenario["dashboard_page"]
message = page.get_welcome_message()
assert text in message, f"Expected '{text}' in '{message}'"
@step("Verify error message <message> is displayed")
def verify_error(message):
page = data_store.scenario["login_page"]
actual = page.get_error_message()
assert actual == message, f"Expected '{message}', got '{actual}'"
// tests/step_implementation.js
const { Step, BeforeSuite, AfterSuite, BeforeScenario, AfterScenario } = require('gauge-ts');
const { Builder, By, until } = require('selenium-webdriver');
const assert = require('assert');
let driver;
BeforeScenario(async () => {
driver = await new Builder().forBrowser('chrome').build();
});
AfterScenario(async () => {
if (driver) await driver.quit();
});
Step('Navigate to login page', async () => {
await driver.get(process.env.BASE_URL + '/login');
await driver.wait(until.elementLocated(By.css('[data-testid="email-input"]')), 10000);
});
Step('Enter email <email>', async (email) => {
const input = await driver.findElement(By.css('[data-testid="email-input"]'));
await input.clear();
await input.sendKeys(email);
});
Step('Enter password <password>', async (password) => {
const input = await driver.findElement(By.css('[data-testid="password-input"]'));
await input.clear();
await input.sendKeys(password);
});
Step('Click the login button', async () => {
await driver.findElement(By.css('[data-testid="login-submit"]')).click();
});
Step('Verify user is on the dashboard', async () => {
await driver.wait(until.urlContains('/dashboard'), 10000);
const url = await driver.getCurrentUrl();
assert(url.includes('/dashboard'), `Expected dashboard URL, got ${url}`);
});
Step('Verify error message <message> is displayed', async (message) => {
const element = await driver.wait(
until.elementLocated(By.css('[data-testid="error-message"]')), 10000
);
const text = await element.getText();
assert.strictEqual(text, message, `Expected '${message}', got '${text}'`);
});
// src/test/java/pages/BasePage.java
package pages;
import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;
public abstract class BasePage {
protected WebDriver driver;
protected WebDriverWait wait;
protected String baseUrl;
public BasePage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
this.baseUrl = System.getenv("BASE_URL") != null
? System.getenv("BASE_URL") : "http://localhost:3000";
}
protected WebElement findElement(By locator) {
return wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
}
protected void click(By locator) {
wait.until(ExpectedConditions.elementToBeClickable(locator)).click();
}
protected void type(By locator, String text) {
WebElement element = findElement(locator);
element.clear();
element.sendKeys(text);
}
protected String getText(By locator) {
return findElement(locator).getText();
}
protected void waitForUrl(String urlPart) {
wait.until(ExpectedConditions.urlContains(urlPart));
}
public void takeScreenshot(String name) {
TakesScreenshot ts = (TakesScreenshot) driver;
byte[] screenshot = ts.getScreenshotAs(OutputType.BYTES);
Gauge.writeMessage("Screenshot: " + name);
Gauge.captureScreenshot();
}
}
// src/test/java/pages/LoginPage.java
package pages;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class LoginPage extends BasePage {
private static final By EMAIL_INPUT = By.cssSelector("[data-testid='email-input']");
private static final By PASSWORD_INPUT = By.cssSelector("[data-testid='password-input']");
private static final By LOGIN_BUTTON = By.cssSelector("[data-testid='login-submit']");
private static final By ERROR_MESSAGE = By.cssSelector("[data-testid='error-message']");
public LoginPage(WebDriver driver) { super(driver); }
public void open() {
driver.get(baseUrl + "/login");
}
public void enterEmail(String email) { type(EMAIL_INPUT, email); }
public void enterPassword(String password) { type(PASSWORD_INPUT, password); }
public void clickLogin() { click(LOGIN_BUTTON); }
public String getErrorMessage() { return getText(ERROR_MESSAGE); }
public boolean isLoaded() {
try { findElement(EMAIL_INPUT); return true; }
catch (Exception e) { return false; }
}
}
// src/test/java/hooks/ExecutionHooks.java
package hooks;
import com.thoughtworks.gauge.*;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
public class ExecutionHooks {
@BeforeSuite
public void beforeSuite() {
System.out.println("Test suite starting...");
}
@AfterSuite
public void afterSuite() {
System.out.println("Test suite completed.");
}
@BeforeScenario
public void beforeScenario(ExecutionContext context) {
ChromeOptions options = new ChromeOptions();
if (System.getenv("CI") != null) {
options.addArguments("--headless", "--no-sandbox", "--disable-dev-shm-usage");
}
options.addArguments("--window-size=1920,1080");
WebDriver driver = new ChromeDriver(options);
DriverFactory.setDriver(driver);
System.out.println("Starting scenario: " + context.getCurrentScenario().getName());
}
@AfterScenario
public void afterScenario(ExecutionContext context) {
if (context.getCurrentScenario().getIsFailing()) {
DriverFactory.getDriver().manage().window().maximize();
Gauge.captureScreenshot();
}
DriverFactory.getDriver().quit();
}
@BeforeStep
public void beforeStep(ExecutionContext context) {
// Log step execution for debugging
}
@AfterStep
public void afterStep(ExecutionContext context) {
if (context.getCurrentStep().getIsFailing()) {
Gauge.captureScreenshot();
}
}
}
# env/default/default.properties
base_url = http://localhost:3000
browser = chrome
headless = false
implicit_wait = 10
screenshot_on_failure = true
# env/ci/ci.properties
base_url = http://staging.example.com
browser = chrome
headless = true
implicit_wait = 15
screenshot_on_failure = true
parallel_execution = true
# Product Search
Tags: search, data-driven
table: resources/search_data.csv
## Search for products by category
* Navigate to the product catalog
* Search for <query>
* Verify <expected_count> results are displayed
* Verify first result contains <expected_product>
query,expected_count,expected_product
laptop,15,MacBook Pro
headphones,8,Sony WH-1000XM5
keyboard,12,Keychron K8
name: Gauge Tests
on: [push, pull_request]
jobs:
gauge-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Install Gauge
run: |
curl -SsL https://downloads.gauge.org/stable | sh
gauge install java
gauge install html-report
gauge install screenshot
- name: Start application
run: ./start-app.sh &
- name: Run Gauge specs
run: gauge run --tags "smoke" --parallel -n 4 specs/
env:
BASE_URL: http://localhost:3000
CI: true
- uses: actions/upload-artifact@v4
if: always()
with:
name: gauge-reports
path: reports/
.cpt concept files to maintain DRY specifications.gauge run --parallel -n <threads> for faster execution. Design specs to be independent.Gauge.captureScreenshot() in AfterStep hooks to automatically capture failure evidence.Click CSS #btn-submit.development
Generate test data from the schemas you already have. Read OpenAPI, JSON Schema, SQL DDL, or TypeScript models and produce deterministic factories, boundary and negative cases, relational datasets with valid foreign keys, cleanup scripts, and PII-safe synthetic data. Production records never leave the machine.
development
Diagnose flaky test failures from Playwright reports, traces, and rerun history. Classify each failure as product, test, environment, data, or unknown with cited evidence and a proposed fix. Never auto-modifies code without opt-in.
tools
Test LLM, RAG, MCP, and agentic systems end to end. Build golden datasets, run deterministic checks and LLM judges, score retrieval, probe prompt injection, verify tool use, and gate CI on thresholds. Orchestrates DeepEval, Ragas, promptfoo, and Langfuse.
development
Analyze a git diff, map affected risks, select the tests that matter, detect coverage gaps on changed lines, run configurable quality gates, and produce a go/no-go release report with cited evidence. Recommends only; never merges or deploys.