Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add testing documentation for webforJ applications #382

Merged
merged 4 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/.styles/config/vocabularies/webforj/accept.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ Auto-Detection
CLI
POM
disabled
E2E
End-to-End
8 changes: 8 additions & 0 deletions docs/testing/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"label": "Testing",
"position": 36,
"link": {
"type": "doc",
"id": "overview"
}
}
35 changes: 35 additions & 0 deletions docs/testing/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
sidebar_position: 1
title: Testing
hide_table_of_contents: true
---

<Head>
<style>{`
.container {
max-width: 65em !important;
}
`}</style>
</Head>


# Testing in webforJ
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [vale] reported by reviewdog 🐶
[Google.Headings] 'Testing in webforJ' should use sentence-style capitalization.


Testing in webforJ applications combines traditional Java unit testing with end-to-end (E2E) testing to ensure robust functionality and user experience.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [vale] reported by reviewdog 🐶
[Google.WordList] Use 'capability' or 'feature' instead of 'functionality'.


## Unit testing

Unit tests in webforJ follow standard Java practices using frameworks like JUnit. These tests focus on backend logic and individual components, ensuring each unit functions as expected.

## End-to-End testing

Since webforJ generates dynamic, single-page web applications, end-to-end testing is essential for validating user interactions and UI behavior. Tools like Selenium and Playwright allow you to:
- Automate browser interactions (e.g., button clicks, form submissions).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 [vale] reported by reviewdog 🐶
[Google.Parens] Use parentheses judiciously.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [vale] reported by reviewdog 🐶
[Google.Latin] Use 'for example' instead of 'e.g.'.

- Verify the rendering and functionality of dynamic components.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [vale] reported by reviewdog 🐶
[Google.WordList] Use 'capability' or 'feature' instead of 'functionality'.

- Ensure consistent behavior across different browsers.

By combining unit and E2E testing, you can build reliable, well-tested webforJ applications.

## Topics

<DocCardList className="topics-section" />
115 changes: 115 additions & 0 deletions docs/testing/playwright.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
sidebar_position: 2
title: Testing with Playwright
---

This documentation outlines the process for testing `webforJ` applications using Playwright, specifically focusing on the `HelloWorldView` from the `webforj-archetype-hello-world`.

## Prerequisites

Before running the Playwright tests, ensure the following:
- The `webforJ` app is correctly set up and running on your local server.
- You have installed:
- Playwright Java bindings.
- A compatible browser (Playwright can automatically install browsers during setup).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 [vale] reported by reviewdog 🐶
[Google.Parens] Use parentheses judiciously.

- Maven for project dependencies.

## Maven configuration

Add the necessary dependencies in your `pom.xml` for Playwright and other testing libraries:

```xml
<dependencies>
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.49.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
```

## Testing example: `HelloWorldView`

The following code demonstrates a Playwright-based test for the `HelloWorldView` component.

```java
package com.example.views;

import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserType;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;

class HelloWorldViewTest {

static Playwright playwright = Playwright.create();
Browser browser;
Page page;
String port = System.getProperty("server.port", "8080");

@BeforeEach
void setUp() {
browser = playwright.chromium().launch();
page = browser.newPage();
page.navigate("http://localhost:" + port + "/");
}

@Test
void shouldClickButton() {
page.locator("input").fill("webforJ");
page.getByText("Say Hello").click();

assertThat(page.locator("dwc-toast").first())
.containsText("Welcome to webforJ Starter webforJ!");
}
}
```

### Key steps

1. **Initialize Playwright**:
- Create a `Playwright` instance.
- Launch a browser instance using `playwright.chromium().launch()`.

2. **Set Up Test Environment**:
- Open a new browser page with `browser.newPage()`.
- Navigate to the `HelloWorldView` page using the `navigate` method.

3. **Interact with Elements**:
- Use [Playwright's locators](https://playwright.dev/java/docs/api/class-locator) to interact with DOM elements.
- Fill input fields using `locator("input").fill()` and trigger actions using `getByText("Say Hello").click()`.

4. **Assertions**:
- Verify the displayed toast message with `PlaywrightAssertions.assertThat()`.

5. **Teardown**:
- Playwright automatically handles browser cleanup when the test finishes. For manual cleanup, you can close the browser using `browser.close()`.

### Running tests

1. Start the `webforJ` server:
```bash
mvn jetty:run
```

2. Execute the test cases:
```bash
mvn test
```

## Expected behavior

- On visiting `http://localhost:<port>/`, the `HelloWorldView` page loads.
- Input `webforJ` into the text field and click the `Say Hello` button.
- A toast message should appear with the text: `Welcome to webforJ Starter webforJ!`.
119 changes: 119 additions & 0 deletions docs/testing/property-descriptor-tester.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
sidebar_position: 4
title: PropertyDescriptorTester
---

The `PropertyDescriptorTester` in webforJ is a tool designed to simplify testing for **third-party web components** integrated into your app. It ensures that properties defined with [`PropertyDescriptor`](https://javadoc.io/doc/com.webforj/webforj-foundation/latest/com/webforj/component/element/PropertyDescriptor.html) are correctly linked to their getter and setter methods, and that default behaviors are consistent.

This is particularly useful when integrating third-party components that expose properties as part of their API, allowing you to validate their functionality without needing to write repetitive test logic.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [vale] reported by reviewdog 🐶
[Google.WordList] Use 'capability' or 'feature' instead of 'functionality'.


:::warning
The webforJ PropertyDescriptorTester adapter is currently an experimental feature. Breaking changes may be introduced at any time.
:::

## Purpose

When working with third-party web components, you need to ensure that:
1. Properties exposed by the components work as expected.
2. Default values, custom methods, and attributes are properly handled.
3. Integration issues are detected early, such as incorrect property names or mismatched methods.

`PropertyDescriptorTester` automates these checks, ensuring that the properties of these components can be tested quickly and reliably.

## Key features of `PropertyDescriptorTester`

1. **Automated Validation**:
- Sets default property values using setter methods.
- Retrieves values using getter methods.
- Compares results to ensure correctness.

2. **Support for Annotations**:
- **`@PropertyExclude`**: Exclude properties that don't require testing.
- **`@PropertyMethods`**: Handle custom getter/setter method names or target classes.

3. **Error Handling**:
- Detects and reports mismatched getters and setters.
- Flags inconsistencies in default property values.

## How it works

1. **Scan Class**:
- Identifies all `PropertyDescriptor` fields in the component class using `PropertyDescriptorScanner`.
- Skips fields annotated with `@PropertyExclude`.

2. **Resolve Methods**:
- Determines getter and setter methods based on standard conventions (`get<PropertyName>`/`set<PropertyName>`).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 [vale] reported by reviewdog 🐶
[Google.Parens] Use parentheses judiciously.

- Uses custom methods or target classes if specified via `@PropertyMethods`.

3. **Set and Get Validation**:
- Calls the setter to assign the default value.
- Calls the getter to retrieve the value.
- Compares the retrieved value with the expected default.

4. **Error Reporting**:
- If a property fails validation, an `AssertionError` is thrown, detailing the issue.

## Writing tests with `PropertyDescriptorTester`

### Example: Basic validation

```java
public class AppLayout {
private final PropertyDescriptor<Boolean> drawerOpened =
PropertyDescriptor.property("drawerOpened", false);
private final PropertyDescriptor<String> headerTitle =
PropertyDescriptor.property("headerTitle", "Default Title");

// setters and getters
}
```

#### Test case:

```java
import com.webforj.component.element.PropertyDescriptorTester;
import org.junit.jupiter.api.Test;

class AppLayoutTest {

AppLayout component = new AppLayout();

@Test
void validateProperties() {
AppLayout component = new AppLayout();
PropertyDescriptorTester.run(AppLayout.class, component);
}
}
```

This automatically validates:
- The `drawerOpened` property has the correct getter and setter methods.
- The `headerTitle` property defaults to `"Default Title"`.

## Annotations for advanced use cases

### 1. `@PropertyExclude`

Exclude a property from validation when:
- It depends on external systems.
- It’s not relevant for the current test.

**Example**:
```java
@PropertyExclude
private final PropertyDescriptor<String> excludedProperty =
PropertyDescriptor.property("excludedProperty", "Excluded");
```

### 2. `@PropertyMethods`

Customize the getter, setter, or target class for a property when:
- The method names don't follow the standard conventions.
- The methods are in a different class.

**Example**:
```java
@PropertyMethods(getter = "retrieveValue", setter = "updateValue", target = SomeClass.class)
private final PropertyDescriptor<String> customProperty =
PropertyDescriptor.property("customProperty", "Default Value");
```
Loading
Loading