E2e framework setup
Skill vasyafomiuk/skills/java-playwright-e2e/skills/e2e-framework-setup
Claude Code skill plugin marketplace — java-playwright-e2e: Java + Playwright + Cucumber (BDD) end-to-end test automation
npx -y skills add vasyafomiuk/skills --skill e2e-framework-setupAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Scaffolds a new Java + Playwright + Cucumber end-to-end automation project and wires up its execution machinery from scratch. Use this skill when the user wants to: bootstrap or initialize a new test automation framework, create the Maven project structure or pom.xml, set up a multi-module skeleton (parent + framework + suites), add and pin Playwright/Cucumber/REST Assured dependencies, install Playwright browsers, configure a Cucumber runner (JUnit 5 platform suite or TestNG), enable parallel execution, configure cross-browser / -Dbrowser execution, manage per-environment config and secrets, or stand up a CI pipeline (GitHub Actions/GitLab) that runs the suite headless on Linux with traces and reports. This is the prerequisite scaffold every other test-authoring skill assumes already exists; hook bodies and the per-scenario context lifecycle belong to cucumber-step-definitions. Project-agnostic — no application-specific assumptions.
SKILL.md
17.5 KB, as published. Nobody here has run it
E2E Framework Setup
This skill stands up the empty, runnable skeleton that the rest of the
acceptance-criteria → passing-test workflow builds on: a multi-module Maven
project, pinned dependencies, a working Cucumber runner, parallel execution,
config/secrets, and CI. When you finish, mvn test runs zero scenarios green —
the framework module compiles, a suite module exists, and Playwright browsers are
installed. Cross-cutting conventions (locator priority, web-first assertions, DI,
isolation, naming/OOP) live in the orchestrator (java-playwright-e2e:orchestrator) —
this skill owns only the scaffold and the machinery that executes it.
WHEN TO USE
Use this skill when the user asks to:
- "Bootstrap / set up / initialize a new automation project (or module)."
- "Create the Maven structure / parent pom / multi-module skeleton for E2E tests."
- "Add Playwright + Cucumber + REST Assured dependencies" / "what versions do I pin?"
- "Install Playwright browsers."
- "Set up the Cucumber runner" / "JUnit 5 vs TestNG runner" / "make tests run in parallel."
- "Add per-environment config /
-Denvselection / keep secrets out of the repo." - "Wire up CI so the suite runs headless on Linux with traces and an HTML report."
Do NOT use this for authoring tests — once the scaffold runs, hand off (see HANDOFF).
STACK & VERSIONS (single source surfaced here; the orchestrator references this matrix)
Known-good example versions — verify the current release on Maven Central and bump.
| Component | Version | Notes |
|---|---|---|
| JDK | 17+ | Playwright Java requires 17 minimum; build fails on 11. |
| Playwright Java | 1.55.0 | com.microsoft.playwright:playwright; pin and keep current. |
| Cucumber JVM | 7.20.1 | cucumber-java + one engine (JUnit platform or TestNG). |
| Cucumber DI | cucumber-picocontainer (7.20.1) | Lightest container; per-scenario instances make parallel safe. Spring is the heavier alternative. |
| Test engine | cucumber-junit-platform-engine + junit-platform-suite (1.11.4) or cucumber-testng | Pick exactly one. |
| API | REST Assured 5.5.0 | io.rest-assured:rest-assured; API + hybrid scenarios. |
| DB pool | HikariCP 6.2.1 (com.zaxxer:HikariCP) | Connection pool for database-validation. |
| JDBC driver | postgresql 42.7.4 (org.postgresql:postgresql) | Swap for your DB (MySQL, etc.). |
| Accessibility (optional) | axe-core Playwright (com.deque.html.axe-core:playwright) | Drop in only if a11y checks are wanted. |
| Build | Maven 3.9+, maven-surefire-plugin 3.5.2 | Node.js is pulled in transitively (Playwright drives it internally). |
Keep Playwright current — new versions track the latest browser builds and catch
regressions early. Pin every version in <properties> so all modules agree.
STEP 1 — Multi-module skeleton (framework vs suite)
A multi-module Maven layout keeps the reusable framework (driver, annotations, config, common steps — no tests) separate from per-suite modules (Gherkin + suite pages/glue). Build the framework once; every suite consumes it as a Maven dependency. Add suites as siblings, one per app/area.
automation/
├── pom.xml # parent: aggregator + <dependencyManagement>
├── framework/ # reusable library — NO tests here
│ ├── pom.xml
│ └── src/main/java/com/example/automation/
│ ├── annotation/ # @FindBy, @VerifyAt, @VerifyBy → playwright-page-objects
│ ├── driver/ # BrowserFactory, BrowserManager, PageHolder
│ ├── pageobject/ context/ # CommonPage base; ScenarioContext (state sharing)
│ ├── config/ # Config, Environment, secret access
│ ├── steps/ api/ db/ # common steps+services; REST Assured wrappers; repositories
│ └── util/ # helpers (dates, strings, files)
└── ui-suite/ # one test suite (repeat per app/area; depends on framework)
└── src/test/
├── java/com/example/automation/
│ ├── pages/ steps/ hooks/ runners/ # suite pages, glue, @Before/@After, runner
└── resources/
├── features/ # *.feature (ui/, api/, e2e/)
├── junit-platform.properties # glue/plugin/parallel config (JUnit 5)
└── application-*.properties # per-environment config
Rule: never put feature files or page objects in the framework module, and
never put driver/config/annotation infrastructure in a suite. If a second suite
would copy a class, it belongs in framework.
STEP 2 — Parent POM and pinned dependencies
Parent declares modules, the Java version, and pins all versions in
<properties>; <dependencyManagement> lets child modules omit versions.
<project>
<packaging>pom</packaging>
<modules>
<module>framework</module>
<module>ui-suite</module>
</modules>
<!-- Known-good example versions — verify the current release on Maven Central and bump. -->
<properties>
<maven.compiler.release>17</maven.compiler.release>
<playwright.version>1.55.0</playwright.version>
<cucumber.version>7.20.1</cucumber.version>
<junit.platform.version>1.11.4</junit.platform.version>
<restassured.version>5.5.0</restassured.version>
<surefire.version>3.5.2</surefire.version>
<hikaricp.version>6.2.1</hikaricp.version>
<postgresql.version>42.7.4</postgresql.version>
</properties>
</project>
Dependencies (framework for shared libs; the suite adds the engine/runner deps):
<dependency><groupId>com.microsoft.playwright</groupId><artifactId>playwright</artifactId><version>${playwright.version}</version></dependency>
<dependency><groupId>io.cucumber</groupId><artifactId>cucumber-java</artifactId><version>${cucumber.version}</version></dependency>
<!-- DI for step/page collaborators (per-scenario instances → parallel-safe) -->
<dependency><groupId>io.cucumber</groupId><artifactId>cucumber-picocontainer</artifactId><version>${cucumber.version}</version></dependency>
<dependency><groupId>io.rest-assured</groupId><artifactId>rest-assured</artifactId><version>${restassured.version}</version></dependency>
<!-- DB validation: connection pool + JDBC driver (swap postgresql for your DB) -->
<dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>${hikaricp.version}</version></dependency>
<dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><version>${postgresql.version}</version></dependency>
<!-- Engine: choose JUnit 5 platform suite ... -->
<dependency><groupId>io.cucumber</groupId><artifactId>cucumber-junit-platform-engine</artifactId><version>${cucumber.version}</version><scope>test</scope></dependency>
<dependency><groupId>org.junit.platform</groupId><artifactId>junit-platform-suite</artifactId><version>${junit.platform.version}</version><scope>test</scope></dependency>
<!-- ... OR TestNG: io.cucumber:cucumber-testng (use one engine, never both) -->
maven-surefire-plugin runs JUnit-platform / TestNG tests on mvn test; pin it
to 3.5+ so it discovers the JUnit Platform suite without extra wiring.
STEP 3 — Install Playwright browsers
Run once after the framework module compiles (it provides the Playwright CLI):
mvn -q -pl framework exec:java -e \
-D exec.mainClass=com.microsoft.playwright.CLI \
-D exec.args="install"
On Linux / CI add --with-deps to pull system libraries:
-D exec.args="install --with-deps chromium". Install only the browsers you run
(usually chromium) to keep CI fast.
STEP 4 — Runner & parallel execution
JUnit 5 platform suite (modern default). The @Suite class is just an entry
point; configuration lives in junit-platform.properties.
@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("features")
public class TestRunner { }
Glue lives in junit-platform.properties only (cucumber.glue=...) — don't also
set it via @ConfigurationParameter(GLUE_PROPERTY_NAME, ...) on the suite, or the
two sources drift.
src/test/resources/junit-platform.properties:
cucumber.glue=com.example.automation.steps,com.example.automation.hooks
cucumber.plugin=pretty, html:target/cucumber.html, json:target/cucumber.json
cucumber.execution.parallel.enabled=true
cucumber.execution.parallel.config.strategy=dynamic
TestNG alternative — extend AbstractTestNGCucumberTests and override
scenarios() with @DataProvider(parallel = true); configure glue/plugin via
@CucumberOptions. Use one engine, never both.
@CucumberOptions(features = "src/test/resources/features",
glue = {"com.example.automation.steps", "com.example.automation.hooks"},
plugin = {"pretty", "html:target/cucumber.html"})
public class TestRunner extends AbstractTestNGCucumberTests {
@Override @DataProvider(parallel = true)
public Object[][] scenarios() { return super.scenarios(); }
}
Parallel rule (the one that prevents 90% of flakiness): parallel runs one
scenario per thread, and each thread must own its own BrowserContext +
Page — never share them across threads. PicoContainer hands each scenario
fresh collaborator instances, so a per-scenario PageHolder created in @Before
and closed in @After is automatically thread-safe. The framework only has to
guarantee instances are per-scenario; the hook/lifecycle details belong to
cucumber-step-definitions. For more capacity, shard the suite across CI
runners rather than over-threading one machine.
Common invocations:
mvn test -Denv=dev # select environment
mvn test -Dcucumber.filter.tags="@ui and @AC1" # filter by tags
mvn test -Dbrowser=firefox # cross-browser
STEP 5 — Config, environments & secrets
- One
application-<env>.propertiesper environment (application-dev.properties,application-staging.properties); select with-Denv=<env>. - A single typed
Configclass loads the active file and exposes typed accessors (base URLs, browser, headless, timeouts) — callers reference keys, never inline literals. - Never commit secret values. Read credentials/tokens from environment
variables or a secret manager at runtime; the properties file holds only the
key name or a
${ENV_VAR}reference.
/** Loads application-<env>.properties; secrets come from env/secret-manager at runtime. */
public final class Config {
private static final Properties P = load(System.getProperty("env", "dev"));
private Config() {}
public static String get(String key) { return P.getProperty(key); }
public static String secret(String key) { return System.getenv(key); } // never from the file
public static String baseUrl() { return get("base.url"); } // UI base URL
public static String apiBaseUrl() { return get("api.base.url"); } // API base URL
public static String token() { return secret("API_TOKEN"); }
public static boolean headless() { return Boolean.parseBoolean(get("headless")); }
}
Keep base URLs and credentials out of feature files and page objects entirely —
they flow in through Config.
STEP 6 — CI pipeline
Run the suite on every commit/PR. Linux runners are cheaper and consistent; headless is the CI default (headed only locally).
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with: { distribution: temurin, java-version: '17', cache: maven }
- name: Install browsers + system deps
run: mvn -q -pl framework exec:java
-D exec.mainClass=com.microsoft.playwright.CLI
-D exec.args="install --with-deps chromium"
- name: Run E2E suite
run: mvn test -Denv=ci -Dheadless=true
- name: Upload report + traces
if: always() # so artifacts exist on failure
uses: actions/upload-artifact@v4
with:
name: e2e-report
path: |
**/target/cucumber.html
**/target/**/trace.zip
CI essentials:
cache: maven(or cache~/.m2) to skip re-downloading dependencies.install --with-deps— the system libraries are required on bare Linux runners.- Capture traces on first retry, not always-on (traces are heavy); the record/open how-to lives in cucumber-step-definitions.
- Upload the Cucumber HTML report and traces with
if: always()so they survive as CI artifacts for download. - Shard large suites across runners (matrix on a tag/feature subset) instead of pushing thread count on one box.
RETRIES & FLAKY-TEST TRIAGE
Reruns are what make the "traces on first retry" CI line above actually fire.
Enable them with the Cucumber rerun plugin, which writes the failed scenarios to
a file; a second suite re-runs only those.
junit-platform.properties (append the rerun plugin):
cucumber.plugin=pretty, html:target/cucumber.html, json:target/cucumber.json, rerun:target/rerun.txt
A second @Suite re-runs only the failures from that file:
@Suite
@IncludeEngines("cucumber")
@SelectFile(value = "@target/rerun.txt") // re-run only the scenarios that failed
public class RerunRunner { }
(TestNG equivalent: implement IRetryAnalyzer and attach it via an
IAnnotationTransformer listener.)
Triage rule — a passing retry is a FLAKE SIGNAL, not a fix. If a scenario
fails then passes on rerun, do not treat green as resolved: tag it @flaky,
exclude @flaky from the merge gate (-Dcucumber.filter.tags="not @flaky"), and
capture the trace on the retry so the flake is debuggable. Quarantine, then fix
the root cause — never leave silent auto-retries masking real defects.
AUTH REUSE (storageState)
Logging in through the UI in every scenario is slow and flaky. Authenticate once in a one-time global setup, persist the session per role, and have contexts load it — no login steps in the bodies.
// global setup: run once per role before the suite
BrowserContext ctx = browser.newContext();
Page page = ctx.newPage();
// ... perform the login flow for this role ...
ctx.storageState(new BrowserContext.StorageStateOptions()
.setPath(Paths.get("auth/admin.json"))); // repeat → auth/viewer.json, etc.
ctx.close();
- Write one file per role:
auth/admin.json,auth/viewer.json. - A context then starts authenticated:
browser.newContext(new Browser.NewContextOptions().setStorageStatePath(Paths.get("auth/admin.json"))). - gitignore
auth/— these files hold live session tokens; never commit them. - Refresh the files when tokens expire (re-run global setup).
Per-scenario seeding (tag-driven @admin / @viewer selection of which state to
load) is shown in cucumber-step-definitions.
INPUT-ACQUISITION FALLBACK
This skill has no external-input chain — it produces inputs for others. If a prerequisite for running something is missing (an endpoint base URL, a DB connection string, an existing feature or page), it is not this skill's job to invent it: ask the user, or point them to the sibling that produces it (endpoints → rest-assured-api-tests, schema/connection → database-validation, features → create-test-scenarios, pages → playwright-page-objects).
HANDOFF
Once mvn test runs green with zero scenarios and browsers are installed, the
scaffold is done. Hand off:
- the orchestrator (
java-playwright-e2e:orchestrator) — single source of truth for all cross-cutting conventions (locator priority, web-first assertions, DI, isolation, test-integrity, naming/OOP). It references the STACK & VERSIONS matrix above. Return here when a new suite module is needed. - create-test-scenarios — turn Jira/AC into Gherkin feature files that drop
into a suite's
resources/features/. - playwright-page-objects — build the
@FindBy/@VerifyAt/@VerifyByannotations and Page Objects this skeleton reserves packages for. - cucumber-step-definitions — the step glue → service layer, plus the
per-scenario
@Before/@Afterhooks that create and close theBrowserContextthis skill made parallel-safe. - rest-assured-api-tests — REST Assured scenarios and
page.routemocking, using the pinned REST Assured dependency added here. - database-validation — persistence verification via the
db/repository packages reserved in the framework module.