Skip to content

Commit 7845cd1

Browse files
committed
Added gemini-cli capabilities, refactored fixture to testdata and minor refactor
1 parent a78017a commit 7845cd1

22 files changed

Lines changed: 289 additions & 84 deletions
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
name: code-reviewer
3+
description: Acts as a Senior QA Lead to review Playwright-Java code, ensuring architectural integrity and test stability.
4+
---
5+
# Code Reviewer Instructions
6+
When this skill is active:
7+
1. **Analyze the Role:** Determine if the file is a Page (ui/page), a Component (ui/component), a TestData class (testData), or a Test (e2e).
8+
2. **Apply Architectural Rules:** Use `review-rules.md` to ensure the logic is placed in the correct layer.
9+
3. **Feedback Format:**
10+
-**Violation:** Serious architectural or stability issues.
11+
- ⚠️ **Improvement:** Code smells or optimization opportunities.
12+
-**Correct:** Praise for good implementation.
13+
4. **Correction:** Always provide the refactored code snippet following the `io.github.tahanima` package standards.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Architecture Review Rules
2+
3+
## 1. UI Layer (Pages & Components)
4+
- **Inheritance:** `BasePage` must be extended by all pages; `BaseComponent` by all components.
5+
- **Locators:** Must be `private`. Use `page.getByRole`, `page.getByLabel`, or `page.getByTestId`.
6+
- **Method Scope:** Page methods should return `void` or a new Page instance (Fluent interface).
7+
- **Separation:** Ensure `Header` or `SideNavMenu` elements are not duplicated in `LoginPage`. They must stay in the `component` package.
8+
9+
## 2. Test Data Layer (The Bridge)
10+
- **Role:** Review `LoginTestData` or `ProductsTestData`. These should act as POJOs or Logic wrappers that interpret CSV data for the UI.
11+
- **Factory usage:** Ensure these classes don't instantiate pages using `new`. They should rely on the `BasePageFactory`.
12+
13+
## 3. E2E Test Layer
14+
- **Inheritance:** All tests must extend `BaseTest`.
15+
- **Annotations:**
16+
- Mandatory: `@Epic`, `@Feature`, and `@Story` (Allure).
17+
- Mandatory: Category annotations like `@Smoke` or `@Regression`.
18+
- **Data Driven:** - Verify `@ParameterizedTest` is used with `@TestDataSource(fileName = "xxx.csv")`.
19+
- Flag any hardcoded test data strings.
20+
- **Assertions:** Use Playwright's `assertThat()` for auto-retrying. Avoid generic JUnit `Assertions.assertEquals()` for UI elements.
21+
22+
## 4. Framework Consistency
23+
- **Configuration:** Use `ConfigurationManager.configuration()` to access properties; never use `System.getProperty` directly.
24+
- **Logging:** Use `AllureManager` for any custom logging or attachments within the test flow.
25+
- **Clean Code:** - No `Thread.sleep()`.
26+
- No `System.out.println()` (Use Allure steps).
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
name: healing-agent
3+
description: Expert in diagnosing Playwright failures and refactoring brittle locators into robust, accessibility-first selectors.
4+
---
5+
# Healing Agent Instructions
6+
When a test fails (especially a TimeoutError or 'element not found'):
7+
1. Load the corresponding Page Object or Component class from `src/main/java/io/github/tahanima/ui/`.
8+
2. Apply the "Healing Logic" defined in `locator-healer.md`.
9+
3. Propose the corrected Java code and explain why the new locator is more stable.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Playwright Locator Healing Logic
2+
3+
## 1. Diagnose the Brittle Locator
4+
Identify if the current locator uses any of these "Anti-Patterns":
5+
- Long XPath strings (e.g., `/html/body/div[1]/...`)
6+
- CSS classes that look autogenerated (e.g., `.css-19v7kv`)
7+
- Locators relying on specific DOM nesting that is likely to change.
8+
9+
## 2. Healing Strategy (Priority Order)
10+
Refactor the broken locator using the following Playwright priority list:
11+
1. **Role (Preferred):** `page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Login"))`
12+
2. **Label:** `page.getByLabel("Username")`
13+
3. **Placeholder:** `page.getByPlaceholder("Enter password")`
14+
4. **Text:** `page.getByText("Welcome back")`
15+
5. **Alt Text:** `page.getByAltText("Company Logo")`
16+
6. **TestID:** `page.getByTestId("submit-button")` (If `data-testid` is present in your HTML).
17+
18+
## 3. Example Transformation
19+
**Broken:**
20+
`private Locator loginBtn = page.locator("//div[@id='login-form']//button[2]");`
21+
22+
**Healed:**
23+
`private Locator loginBtn = page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Login"));`

GEMINI.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Project: Playwright Java Test Automation Architecture
2+
3+
## Context & Tech Stack
4+
- **Build Tool:** Gradle (using `build.gradle`)
5+
- **Language:** Java 17+
6+
- **Browser Automation Library:** Playwright
7+
- **Architecture:** Data-driven test automation using POM to model and reuse web page functionality.
8+
- **Base Package:** `io.github.tahanima`
9+
- **Test Runner:** JUnit 5 with custom annotations (`@TestDataSource`, `@Validation`, `@Smoke`, `@Regression`).
10+
11+
---
12+
13+
## Project Mapping
14+
- **Pages:** `src/main/java/io/github/tahanima/ui/page/` – Encapsulate low-level page actions and locators.
15+
- **Components:** `src/main/java/io/github/tahanima/ui/component/` – Reusable UI elements (Header, SideNav, etc.).
16+
- **TestData POJOs:** `src/main/java/io/github/tahanima/testdata/` – Business logic layer that interprets CSV data and interacts with Pages.
17+
- **Tests:** `src/test/java/io/github/tahanima/e2e/` – High-level orchestration; must extend `BaseTest`.
18+
- **Test Data Files:** `src/test/resources/testdata/` – CSV files for data-driven inputs.
19+
- **Utilities:**
20+
- `BrowserManager.java` – Browser lifecycle management.
21+
- `CsvLoader.java` – CSV loading for test data.
22+
- **Factories:**
23+
- `BasePageFactory.java` – Centralized page initialization.
24+
- `BrowserFactory.java` – Abstracts browser setup and creation.
25+
- **Reporting:** `AllureManager.java` – Custom logging, screenshots, and test reporting.
26+
27+
---
28+
29+
## Development Rules
30+
1. **Instantiation:** Do not use `new LoginPage()`. Always use the `BasePageFactory` to initialize pages.
31+
2. **Logic Placement:**
32+
- **Pages/Components:** Handle locators and atomic actions (e.g., `typeUsername`).
33+
- **TestData POJOs:** Handle business workflows (e.g., `loginWith(LoginTestData data)`).
34+
- **Tests:** Handle assertions and test flow. Minimal direct Playwright API calls here.
35+
3. **Stability & Waits:**
36+
- **No Hard Sleeps:** Never use `Thread.sleep()`. Rely on Playwright’s auto-waiting or `page.waitForCondition()`.
37+
- **Web-First Assertions:** Use `PlaywrightAssertions.assertThat()` for UI states to enable automatic retries.
38+
4. **Configuration:** Use `ConfigurationManager` to access `config.properties`. Do not hardcode URLs or credentials.
39+
5. **Data Loading:** Use the custom `@TestDataSource` annotation for CSV data-driven tests.
40+
6. **Naming Conventions:**
41+
- Pages → `*Page.java`
42+
- Components → `*Component.java`
43+
- Test Data POJOs → `*TestData.java` (must extend `BaseTestData`).
44+
45+
---
46+
47+
## Locator Strategy (Priority Order)
48+
1. `page.getByRole()` (Prioritize accessibility-first selectors).
49+
2. `page.getByLabel()` / `page.getByPlaceholder()`.
50+
3. `page.getByTestId()` (Use when `data-testid` attributes are available).
51+
4. CSS/XPath (Use only as a last resort for complex structural selectors).
52+
53+
---
54+
55+
## Test Data Flow
56+
- CSV files → `TestDataArgumentsProvider` → Test method parameters → Test execution.
57+
- POJOs (`testdata` package) represent structured test data for readability and business logic reuse.
58+
59+
---
60+
61+
## Running Tests
62+
- Run all tests: `./gradlew clean test`
63+
- Run a specific test class: `./gradlew test --tests *LoginTest`
64+
- Generate Allure report: `./gradlew allureServe`
65+
66+
---
67+
68+
## Available Skills (AI Toolbelt)
69+
1. **code-reviewer**:
70+
- **Trigger:** When providing new code or asking for architectural feedback.
71+
- **Focus:** Enforcing layer separation (Page vs. TestData vs. E2E) and checking Factory usage.
72+
2. **healing-agent**:
73+
- **Trigger:** When reporting a `TimeoutError`, broken locator, or execution failure.
74+
- **Focus:** Converting brittle selectors to the "Locator Strategy" priority list above.
75+
76+
### Usage Guidelines
77+
- **Skill Activation:** If a task matches the triggers above, ask for permission to load the skill using `/skills load <name>`.
78+
- **Contextual Awareness:** Before proposing code changes, refer to `src/main/resources/config.properties` for environment-specific settings.

README.md

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Ready-to-use UI Test Automation Architecture using Java and Playwright.
1111
- Records video of test execution
1212
- Provides detailed test report
1313
- Supports parallel test execution
14+
- Supports gemini-cli for AI-assisted coding
15+
---
1416

1517
## Installation Steps
1618

@@ -28,6 +30,7 @@ git clone https://github.com/[your_username]/playwright-java-test-automation-arc
2830
```
2931
./gradlew allureServe
3032
```
33+
---
3134

3235
## Languages and Frameworks
3336

@@ -41,13 +44,23 @@ The project uses the following:
4144
- *[Allure Report](https://qameta.io/allure-report/)* as the test reporting strategy.
4245
- *[Gradle](https://gradle.org/)* as the Java build tool.
4346
- *[IntelliJ IDEA](https://www.jetbrains.com/idea/)* as the IDE.
47+
- *[Gemini CLI](https://github.com/google-gemini/gemini-cli)* as an AI collaborator for code reviews, locator healing, and test generation.
48+
---
4449

4550
## Project Structure
4651

4752
The project is structured as follows:
4853

4954
```bash
5055
📦 playwright-java-test-automation-architecture
56+
├─ .gemini
57+
│  └─ skills
58+
│     └─ code-reviewer
59+
|        └─ review-rules.md
60+
|        └─ SKILL.md
61+
|     └─ healing-agent
62+
|        └─ locator-healer.md
63+
|        └─ SKILL.md
5164
├─ .github
5265
│  ├─ FUNDING.yml
5366
│  ├─ dependabot.yml
@@ -56,6 +69,7 @@ The project is structured as follows:
5669
├─ .gitignore
5770
├─ LICENSE
5871
├─ README.md
72+
├─ GEMINI.md
5973
├─ build.gradle
6074
├─ gradle
6175
│  └─ wrapper
@@ -76,10 +90,10 @@ The project is structured as follows:
7690
   │  │           ├─ factory
7791
   │  │           │  ├─ BasePageFactory.java
7892
   │  │           │  └─ BrowserFactory.java
79-
   │  │           ├─ fixture
80-
   │  │           │  ├─ BaseFixture.java
81-
   │  │           │  ├─ LoginFixture.java
82-
   │  │           │  └─ ProductsFixture.java
93+
   │  │           ├─ testData
94+
   │  │           │  ├─ BaseTestData.java
95+
   │  │           │  ├─ LoginTestData.java
96+
   │  │           │  └─ ProductsTestData.java
8397
   │  │           ├─ report
8498
   │  │           │  └─ AllureManager.java
8599
   │  │           ├─ ui
@@ -112,13 +126,14 @@ The project is structured as follows:
112126
      │           │  └─ ProductsTest.java
113127
      │           └─ util
114128
      │              ├─ TestDataArgumentsProvider.java
115-
      │              └─ TestFixtureCsvLoader.java
129+
      │              └─ CsvLoader.java
116130
      └─ resources
117131
         ├─ junit-platform.properties
118132
         └─ testdata
119133
            ├─ login.csv
120134
            └─ products.csv
121135
```
136+
---
122137

123138
## Basic Usage
124139

@@ -162,10 +177,10 @@ The project is structured as follows:
162177
- ### Test Data
163178
The project uses *csv* file to store test data and [*univocity-parsers*](https://github.com/uniVocity/univocity-parsers) to retrieve the data and map it to a Java bean.
164179
165-
To add configurations for new test data, add a new Java bean in the [*fixture*](./src/main/java/io/github/tahanima/fixture) package. For example, let's say I want to add test data for a `User` with the attributes `First Name` and `Last Name`. The code for this is as follows:
180+
To add configurations for new test data, add a new Java bean in the [*testData*](./src/main/java/io/github/tahanima/testdata) package. For example, let's say I want to add test data for a `User` with the attributes `First Name` and `Last Name`. The code for this is as follows:
166181
167182
```java
168-
package io.github.tahanima.fixture;
183+
package io.github.tahanima.testdata;
169184
170185
import com.univocity.parsers.annotations.Parsed;
171186
@@ -174,7 +189,7 @@ The project is structured as follows:
174189
175190
@Getter
176191
@ToString(callSuper = true)
177-
public class UserFixture extends BaseFixture {
192+
public class UsertestData extends BasetestData {
178193
179194
@Parsed(field = "First Name", defaultNullRead = "")
180195
private String firstName;
@@ -183,17 +198,47 @@ The project is structured as follows:
183198
private String lastName;
184199
}
185200
```
186-
Note that the class extends from BaseFixture and thus, inherits the attribute `Test Case ID`.
201+
Note that the class extends from BasetestData and thus, inherits the attribute `Test Case ID`.
187202

188203
Now, in the [*testdata*](./src/test/resources/testdata) folder you can add a csv file `user.csv` for `User` with the below contents and use it in your tests.
189204
```
190205
Test Case ID,First Name,Last Name
191206
TC-1,Tahanima,Chowdhury
192207
```
193-
For reference, check [this](./src/main/java/io/github/tahanima/fixture/LoginFixture.java), [this](./src/test/resources/testdata/login.csv) and [this](./src/test/java/io/github/tahanima/e2e/LoginTest.java).
208+
For reference, check [this](./src/main/java/io/github/tahanima/testdata/LogintestData.java), [this](./src/test/resources/testdata/login.csv) and [this](./src/test/java/io/github/tahanima/e2e/LoginTest.java).
194209

195210
- ### Page Objects and Page Component Objects
196211
The project uses [*Page Objects* and *Page Component Objects*](https://www.selenium.dev/documentation/test_practices/encouraged/page_object_models/) to capture the relevant behaviors of a web page. Check the [*ui*](./src/main/java/io/github/tahanima/ui) package for reference.
197212

198213
- ### Tests
199214
The project uses *JUnit 5* as the test runner. Check [this implementation](./src/test/java/io/github/tahanima/e2e/LoginTest.java) for reference.
215+
---
216+
217+
## AI-Augmented Workflow
218+
219+
This project is optimized for use with **Gemini CLI**, providing a specialized AI agent that understands the architecture.
220+
221+
### Prerequisites
222+
- Gemini CLI: -[Installed and authenticated](https://github.com/google-gemini/gemini-cli) via your Google Account.
223+
- Project Root: Ensure you run the CLI from the project root to allow it to parse the .gemini/ configuration.
224+
225+
### Project Context (GEMINI.md)
226+
The project includes a `GEMINI.md` file which serves as the AI's "Source of Truth." This ensures that any code generated or reviewed by the AI adheres to:
227+
- **BasePageFactory** initialization patterns.
228+
- **Layer Separation** (Pages vs. TestData POJOs vs. E2E Tests).
229+
- **Playwright Best Practices** (Accessibility-first locators over brittle XPaths).
230+
231+
### Specialized AI Skills
232+
We have implemented custom **Skills** in the `.gemini/skills/` directory to automate common QA tasks:
233+
234+
- **`code-reviewer`**: Automatically audits new Page Objects, POJOs, and Tests to ensure they follow the project's layer separation and naming conventions.
235+
- **`healing-agent`**: Diagnoses test failures (like `TimeoutError`) and suggests robust, accessibility-first Playwright locators (e.g., `getByRole`) to replace brittle XPaths.
236+
237+
### How to Use
238+
Simply run `gemini` in the project root. You can trigger skills manually or let the AI suggest them:
239+
```bash
240+
# To perform a code review
241+
gemini "Review this new test class: @src/test/java/io/github/tahanima/e2e/NewFeatureTest.java"
242+
243+
# To fix a failing locator
244+
gemini "The login button locator is failing. Use the healing-agent to suggest a fix for @src/main/java/io/github/tahanima/ui/page/LoginPage.java"

src/main/java/io/github/tahanima/factory/BasePageFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package io.github.tahanima.factory;
22

33
import com.microsoft.playwright.Page;
4+
45
import io.github.tahanima.ui.page.BasePage;
6+
57
import lombok.extern.slf4j.Slf4j;
68

79
/**
@@ -12,7 +14,7 @@ public final class BasePageFactory {
1214

1315
private BasePageFactory() {}
1416

15-
public static <T extends BasePage> T createInstance(final Page page, final Class<T> clazz) {
17+
public static <T extends BasePage> T createInstance(Page page, Class<T> clazz) {
1618
try {
1719
BasePage instance = clazz.getDeclaredConstructor().newInstance();
1820

src/main/java/io/github/tahanima/factory/BrowserFactory.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,19 @@ public enum BrowserFactory {
1414

1515
CHROMIUM {
1616
@Override
17-
public Browser createInstance(final Playwright playwright) {
17+
public Browser createInstance(Playwright playwright) {
1818
return playwright.chromium().launch(options());
1919
}
2020
},
2121
FIREFOX {
2222
@Override
23-
public Browser createInstance(final Playwright playwright) {
23+
public Browser createInstance(Playwright playwright) {
2424
return playwright.firefox().launch(options());
2525
}
2626
},
2727
WEBKIT {
2828
@Override
29-
public Browser createInstance(final Playwright playwright) {
29+
public Browser createInstance(Playwright playwright) {
3030
return playwright.webkit().launch(options());
3131
}
3232
};
@@ -37,5 +37,5 @@ public LaunchOptions options() {
3737
.setSlowMo(config().slowMotion());
3838
}
3939

40-
public abstract Browser createInstance(final Playwright playwright);
40+
public abstract Browser createInstance(Playwright playwright);
4141
}

src/main/java/io/github/tahanima/fixture/BaseFixture.java renamed to src/main/java/io/github/tahanima/testdata/BaseTestData.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.github.tahanima.fixture;
1+
package io.github.tahanima.testdata;
22

33
import com.univocity.parsers.annotations.Parsed;
44
import lombok.Getter;
@@ -9,7 +9,7 @@
99
*/
1010
@Getter
1111
@ToString
12-
public class BaseFixture {
12+
public class BaseTestData {
1313

1414
@Parsed(field = "Test Case ID", defaultNullRead = "")
1515
private String testCaseId;

src/main/java/io/github/tahanima/fixture/LoginFixture.java renamed to src/main/java/io/github/tahanima/testdata/LoginTestData.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.github.tahanima.fixture;
1+
package io.github.tahanima.testdata;
22

33
import com.univocity.parsers.annotations.Parsed;
44
import lombok.Getter;
@@ -9,7 +9,7 @@
99
*/
1010
@Getter
1111
@ToString(callSuper = true)
12-
public class LoginFixture extends BaseFixture {
12+
public class LoginTestData extends BaseTestData {
1313

1414
@Parsed(field = "Username", defaultNullRead = "")
1515
private String username;

0 commit comments

Comments
 (0)