Web Application Testing
anthropics/skills
Tests local web applications with Python Playwright scripts, checking frontend behavior, capturing screenshots and reading browser console logs.
Writes and reviews Geb browser automation specs with Spock, using Page Objects, at checkers, Modules and explicit waits, for Groovy and Gradle projects.
$ npx skills add apache/groovy-geb --skill geb-spock -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install apache/groovy-geb geb-spock --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/apache/groovy-geb.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/geb-spock .claude/skills/geb-spock && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "geb-spock" agent skill from https://github.com/apache/groovy-geb/tree/master/.agents/skills/geb-spock into .claude/skills/geb-spock/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "geb-spock", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/apache/groovy-geb/tree/master/.agents/skills/geb-spockType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add apache/groovy-geb --skill geb-spock -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install apache/groovy-geb geb-spock --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/apache/groovy-geb.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/geb-spock .agents/skills/geb-spock && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "geb-spock" agent skill from https://github.com/apache/groovy-geb/tree/master/.agents/skills/geb-spock into .agents/skills/geb-spock/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "geb-spock", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add apache/groovy-geb --skill geb-spock -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install apache/groovy-geb geb-spock --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/apache/groovy-geb.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/geb-spock .cursor/skills/geb-spock && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "geb-spock" agent skill from https://github.com/apache/groovy-geb/tree/master/.agents/skills/geb-spock into .cursor/skills/geb-spock/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "geb-spock", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/apache/groovy-geb.git --path .agents/skills/geb-spock--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add apache/groovy-geb --skill geb-spock -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install apache/groovy-geb geb-spock --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/apache/groovy-geb.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/geb-spock .gemini/skills/geb-spock && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "geb-spock" agent skill from https://github.com/apache/groovy-geb/tree/master/.agents/skills/geb-spock into .gemini/skills/geb-spock/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "geb-spock", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install apache/groovy-geb geb-spockInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add apache/groovy-geb --skill geb-spock -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/apache/groovy-geb.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/geb-spock .github/skills/geb-spock && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "geb-spock" agent skill from https://github.com/apache/groovy-geb/tree/master/.agents/skills/geb-spock into .github/skills/geb-spock/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "geb-spock", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add apache/groovy-geb --skill geb-spock -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install apache/groovy-geb geb-spock --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/apache/groovy-geb.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/geb-spock .opencode/skills/geb-spock && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "geb-spock" agent skill from https://github.com/apache/groovy-geb/tree/master/.agents/skills/geb-spock into .opencode/skills/geb-spock/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "geb-spock", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
geb-spockWrites and reviews Geb browser automation specs with Spock, using Page Objects, at checkers, Modules and explicit waits, for Groovy and Gradle projects.
Geb plus Spock specs are generated and reviewed against a fixed set of principles: always use Page Objects and never inline selectors, give every page a static at checker, prefer CSS selectors over XPath, and use waitFor explicitly instead of Thread.sleep, ideally inside methods on the page or module classes so the waiting knowledge is reusable.
Specs extend GebReportingSpec rather than GebSpec so screenshots are captured on failure, stay in given, when and then blocks with one behavior per feature method, and use Modules for repeated components such as navigation bars, modals and form rows. To avoid flaky tests, the skill suggests stress-testing a spec by adding network latency and re-running it many times locally. Templates show the spec, Page Object and Module structure, and the Geb manual is the reference for details.
8 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit e433962. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are groovy).
From the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
groovy.apache.orgspockframework.orgFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Geb and Spock Browser Tests loads about 2.4k tokens when it runs. Until then it costs about 124 tokens; SKILL.md has 712 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from apache/groovy-geb at commit e433962, republished under its Apache-2.0 licence (© apache). 712 words, ~2,363 tokens.
.claude/skills/geb-spock/SKILL.md (or your agent's skills folder).<!--
SPDX-License-Identifier: Apache-2.0
Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements; and to You under the Apache License, Version 2.0.
-->
Generates and reviews Geb + Spock browser automation specs following intermediate-level best practices.
Geb documentation is at https://groovy.apache.org/geb/manual/current/.
at checkers — every Page Object must declare static at.waitFor explicitly for dynamic content; never Thread.sleep.waitFor method calls into methods inside classes that extend geb.Page, geb.Module, or other shared test fixtures. If clicking or interacting with some object on a page requires waiting for some response, it's best to encapsulate that knowledge into a method on the pageObject (e.g. deleteTableRow or submitForm) that then waits for the signal that the operation is complete. That will make the knowledge of your page more reusable and avoid repeated waitFor.GebReportingSpec (not GebSpec) so screenshots are captured on failure.given/when/then blocks — one behaviour per feature method.when/then block pairs within one test method, so long as each intermediary step is integral to the journey under test.package com.example.specs
import geb.spock.GebReportingSpec
import com.example.pages.LoginPage
import com.example.pages.DashboardPage
import spock.lang.Stepwise // only when steps truly depend on each other
@Stepwise // omit if steps are independent
class LoginSpec extends GebReportingSpec {
def "successful login redirects to dashboard"() {
given: "user is on the login page"
to LoginPage
when: "valid credentials are submitted"
loginForm.username = "user@example.com"
loginForm.password = "secret"
loginForm.submit()
then: "the dashboard is displayed"
at DashboardPage
welcomeMessage.text() == "Welcome, user@example.com"
}
def "login fails with invalid credentials"() {
given:
to LoginPage
when:
loginForm.username = "bad@example.com"
loginForm.password = "wrong"
loginForm.submit()
then:
at LoginPage
errorMessage.displayed
errorMessage.text().contains("Invalid credentials")
}
}package com.example.pages
import geb.Page
import com.example.modules.LoginFormModule
class LoginPage extends Page {
// `at` checker — verified when `to` or `at` is called
static at = { title == "Login | MyApp" }
// URL for `to LoginPage`
static url = "/login"
static content = {
// Lazy by default; set required: false for optional elements
loginForm { module(LoginFormModule) }
errorMessage(required: false) { $(".alert-error") }
}
}class DashboardPage extends Page {
static at = { $("h1.dashboard-title").displayed }
static url = "/dashboard"
static content = {
welcomeMessage { $(".welcome-msg") }
navBar { module(NavBarModule) }
}
}Use modules for components that repeat across pages (nav, modal, form row, table row).
package com.example.modules
import geb.Module
class LoginFormModule extends Module {
static content = {
username { $("input[name='username']") }
password { $("input[name='password']") }
submitBtn { $("button[type='submit']") }
}
void submit() {
submitBtn.click()
}
}waitFor Patterns// Wait for element to appear (default timeout from GebConfig)
waitFor { $(".spinner").not(".active") }
// Wait with custom timeout (seconds)
waitFor(10) { successBanner.displayed }
// Wait and return the element
def result = waitFor { $(".result-row") }
// Use in content DSL for elements that load dynamically
static content = {
// Wait for this element every time it's accessed
asyncTable(wait: true) { $("table.results") }
}Never use
Thread.sleep. IfwaitForkeeps timing out, make sure your assertion is actually eventually true (you may be relying on an unreliable side effect), ensure that your page is completing its work as quickly as it can, or increase the timeout inGebConfig.groovyrather than sleeping.
| ✅ Prefer | ❌ Avoid |
|---|---|
$("input[name='email']") | $("div > div:nth-child(2) > input") |
$(".submit-btn") | $("button", text: "Submit") (fragile for i18n) |
$("table.results tbody tr") | XPath selectors |
data-testid attributes | Position-based selectors |
If the app doesn't have data-testid attrs, use stable semantic selectors: name, id, aria-label, role.
def rows =
rows.size() == 3
rows[0].find("td.name").text() == "Alice"$("input[name='firstName']").value("Jane")
$("select[name='country']").value("US")
$("input[type='checkbox'][name='agree']").value(true)// For custom JS dropdowns (not <select>)
$(".dropdown-trigger").click()
waitFor { $(".dropdown-menu").displayed }
$(".dropdown-menu li", text: "Option B").click()// Checks URL and `at` checker
at ConfirmationPage
currentUrl.contains("/confirmation")@Stepwise overuse — only use when steps share state (e.g., a multi-step wizard). Independent scenarios should be separate specs or use setup()/cleanup().when: blocks — lines after then: or expect: are automatically asserted - no need to even supply the assert keyword!sleep() anywhere in test code.GebConfig.groovy.$() calls belong in Page Objects or Modules.required: false on optional content - the only time you really want to mark a page element as required: false is when your spec needs to try to interact with it when it's absent (for example, to assert that it isn't present, !page.buttons.sometimesThereButton). If the button may or may not be there, but you never test the case where it isn't there, you should just leave it as required. Remember, throwing an exception when something exceptional happens is okay, especially in tests!Browser testing frameworks like Geb sometimes get a bad reputation for being flaky, but with some diligence you can keep your Geb tests more reliable!
Adding even a small amount of network latency to your test can expose places where you probably want to add a waitFor statement to your page object. Drop some code like this in your test's setup() method and run it a few times to make sure it consistently works:
def networkLatency = java.time.Duration.ofMillis(500)
browser.networkLatency = networkLatencyWhile developing your tests, try doing a pass of re-running the test locally to make sure it consistently passes. If each of your tests only fails 1 time out of a hundred, but you have ten tests, your build pipelines are going to be flakier than your team can tolerate.
If you're using geb-spock, use the RepeatUntilFailure annotation with a maxAttempts value to run the test locally. You probably won't want to commit that annotation in most cases, but it's a good tool to verify your test is consistent before making it a blocker for someone else's PR.
© apache, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/geb-spock of apache/groovy-geb.
Open the folder on GitHubat commit e433962
Geb and Spock Browser Tests next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Geb and Spock Browser Tests this skillapache/groovy-geb | 1.2k | — | ~2.4k | Automated safety check: Pass | Apache-2.0 | |
| Web Application Testinganthropics/skills | 180k | 51 repos | ~966 | Automated safety check: Pass | Apache-2.0 | |
| playwright-cli Browser Automationgithub/gh-aw | 5.4k | 24 repos | ~2.8k | Automated safety check: Pass | MIT | |
| Write and Verify Playwright Testsappsmithorg/appsmith | 41k | — | ~2.9k | Automated safety check: Notes | Apache-2.0 | |
| Cucumber and Playwright E2E Testslanggenius/dify | 158k | — | ~682 | Automated safety check: Pass | Custom licence | |
| E2E Testinglangflow-ai/langflow | 156k | — | ~3.3k | Automated safety check: Pass | MIT |
anthropics/skills
Tests local web applications with Python Playwright scripts, checking frontend behavior, capturing screenshots and reading browser console logs.
github/gh-aw
Drives a real browser from the command line with playwright-cli to open pages, interact, mock requests, save state and work with Playwright tests.
appsmithorg/appsmith
Writes a Playwright end-to-end test from a prompt, runs it against a live Appsmith deployment and retries with fixes up to three times until it passes.
langgenius/dify
Guides changes and reviews of the Cucumber and Playwright end-to-end suite under `e2e/`: feature files, step definitions, support code, tags, locators and assertions.
langflow-ai/langflow
Write and review Playwright E2E tests for Langflow. An agent skill from langflow-ai/langflow.
handsontable/handsontable
Guides writing and changing Playwright end-to-end tests for Handsontable using page objects, data-testid hooks and deterministic waits.
Works with
Categories
Writes and reviews Geb browser automation specs with Spock, using Page Objects, at checkers, Modules and explicit waits, for Groovy and Gradle projects. sleep, ideally inside methods on the page or module classes so the waiting knowledge is reusable.
Geb and Spock Browser Tests fits situations like: writing a new Geb spec for a web page; reviewing Geb tests for brittle selectors or sleeps; creating Page Objects and Modules in a Groovy project; fixing a flaky Geb test.
Run `npx skills add apache/groovy-geb --skill geb-spock -a claude-code`. Or copy the skill folder (.agents/skills/geb-spock in apache/groovy-geb) into .claude/skills/geb-spock in your project. Claude Code loads it when a task matches its description.
Run `npx skills add apache/groovy-geb --skill geb-spock -a codex`. Or copy the skill folder (.agents/skills/geb-spock in apache/groovy-geb) into .agents/skills/geb-spock in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add apache/groovy-geb --skill geb-spock -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/geb-spock, .gemini/skills/geb-spock, .github/skills/geb-spock and .opencode/skills/geb-spock in your project.
SKILL.md names no scripts, command-line tools or credentials: Geb and Spock Browser Tests is instructions for the agent only. Our summary lists: A Groovy project with Geb and Spock set up, such as through Gradle.
SKILL.md names 2 domains. As links in the text: groovy.apache.org and spockframework.org. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Geb and Spock Browser Tests is published under the Apache-2.0 licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 2.4k tokens (SKILL.md is roughly 9.5k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Geb and Spock Browser Tests: Web Application Testing (anthropics/skills, 180k stars), playwright-cli Browser Automation (github/gh-aw, 5.4k stars), Write and Verify Playwright Tests (appsmithorg/appsmith, 41k stars) and Cucumber and Playwright E2E Tests (langgenius/dify, 158k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
apache (a GitHub organization) maintains it in apache/groovy-geb, which has 1,174 GitHub stars. The repository was last updated on October 7, 2026.
Source: apache/groovy-geb on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.