docs(java): JUnit fixtures

This commit is contained in:
jfgreffier 2024-02-24 10:08:08 +01:00
parent 9a38aedf09
commit 5b8338279f
5 changed files with 195 additions and 0 deletions

View file

@ -238,3 +238,5 @@ public class HomepageTests extends AxeTestFixtures {
}
}
```
See experimental [JUnit integration](./junit.md) to automatically initialize [Playwright] objects and more.

View file

@ -375,6 +375,8 @@ public class TestGitHubAPI {
}
```
See experimental [JUnit integration](./junit.md) to automatically initialize [Playwright] objects and more, thanks to fixtures.
## Prepare server state via API calls
The following test creates a new issue via API and then navigates to the list of all issues in the

187
docs/src/junit-java.md Normal file
View file

@ -0,0 +1,187 @@
---
id: junit
title: "JUnit (experimental)"
---
## Introduction
With a few lines of code, you can hook up Playwright to your favorite Java test runner.
In [JUnit](https://junit.org/junit5/), you can use Playwright [fixtures](./junit.md#fixtures) to automatically initialize [Playwright], [Browser], [BrowserContext] or [Page]. In the example below, all three test methods use the same
[Browser]. Each test uses its own [BrowserContext] and [Page].
<!-- TOC -->
```java
package org.example;
import com.microsoft.playwright.junit.UsePlaywright;
import com.microsoft.playwright.Page;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@UsePlaywright
public class TestExample {
@Test
void shouldClickButton(Page page) {
page.navigate("data:text/html,<script>var result;</script><button onclick='result=\"Clicked\"'>Go</button>");
page.locator("button").click();
assertEquals("Clicked", page.evaluate("result"));
}
@Test
void shouldCheckTheBox(Page page) {
page.setContent("<input id='checkbox' type='checkbox'></input>");
page.locator("input").check();
assertTrue((Boolean) page.evaluate("() => window['checkbox'].checked"));
}
@Test
void shouldSearchWiki(Page page) {
page.navigate("https://www.wikipedia.org/");
page.locator("input[name=\"search\"]").click();
page.locator("input[name=\"search\"]").fill("playwright");
page.locator("input[name=\"search\"]").press("Enter");
assertEquals("https://en.wikipedia.org/wiki/Playwright", page.url());
}
}
```
## Fixtures
You should add JUnit annotation `@UsePlaywright` to your test classes to use fixtures. Test fixtures are used to establish environment for each test, giving the test everything it needs and nothing else.
```java
@UsePlaywright
public class TestExample {
@Test
void basicTest(Page page) {
page.navigate("https://playwright.dev/");
assertThat(page).hasTitle(Pattern.compile("Playwright"));
}
}
```
The `Page page` argument tells JUnit to setup the `page` fixture and provide it to your test method.
Here is a list of the pre-defined fixtures:
|Fixture |Type |Description |
|:-------------|:------------------|:--------------------------------|
|page |[Page] |Isolated page for this test run.|
|browserContext|[BrowserContext] |Isolated context for this test run. The `page` fixture belongs to this context as well.|
|browser |[Browser] |Browsers are shared across tests to optimize resources.|
|playwright |[Playwright] |Playwright instance is shared between tests.|
|request |[APIRequestContext]|Isolated APIRequestContext for this test run. Learn how to do [API testing](./api-testing).|
## Customizing options
To customize fixture options, you should implement an `OptionsFactory` and specify the class in the `@UsePlaywright()` annotation.
You can easily override launch options for [`method: BrowserType.launch`], or context options for [`method: Browser.newContext`] and [`method: APIRequest.newContext`]. See the following example:
```java
import com.microsoft.playwright.junit.Options;
import com.microsoft.playwright.junit.OptionsFactory;
import com.microsoft.playwright.junit.UsePlaywright;
@UsePlaywright(MyTest.CustomOptions.class)
public class MyTest {
public static class CustomOptions implements OptionsFactory {
@Override
public Options getOptions() {
return new Options()
.setHeadless(false)
.setContextOption(new Browser.NewContextOptions()
.setBaseURL("https://github.com"))
.setApiRequestOptions(new APIRequest.NewContextOptions()
.setBaseURL("https://playwright.dev"));
}
}
@Test
public void testWithCustomOptions(Page page, APIRequestContext request) {
page.navigate("/");
assertThat(page).hasURL(Pattern.compile("github"));
APIResponse response = request.get("/");
assertTrue(response.text().contains("Playwright"));
}
}
```
## Running Tests in Parallel
By default JUnit will run all tests sequentially on a single thread. Since JUnit 5.3 you can change this behavior to run tests in parallel
to speed up execution (see [this page](https://junit.org/junit5/docs/snapshot/user-guide/index.html#writing-tests-parallel-execution)).
Since it is not safe to use same Playwright objects from multiple threads without extra synchronization we recommend you create Playwright
instance per thread and use it on that thread exclusively. Here is an example how to run multiple test classes in parallel.
Use [`@TestInstance(TestInstance.Lifecycle.PER_CLASS)`](https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/TestInstance.html)
annotation to make JUnit create one instance of a class for all test methods within that class (by default each JUnit will create a new instance of the class
for each test method). Store [Playwright] and [Browser] objects in instance fields. They will be shared between tests. Each instance of the class will use its
own copy of Playwright. This is done automatically if you use the `@UsePlaywright` JUnit annotation.
```java
@UsePlaywright
class Test1 {
@Test
void shouldClickButton(Page page) {
page.navigate("data:text/html,<script>var result;</script><button onclick='result=\"Clicked\"'>Go</button>");
page.locator("button").click();
assertEquals("Clicked", page.evaluate("result"));
}
@Test
void shouldCheckTheBox(Page page) {
page.setContent("<input id='checkbox' type='checkbox'></input>");
page.locator("input").check();
assertTrue((Boolean) page.evaluate("() => window['checkbox'].checked"));
}
@Test
void shouldSearchWiki(Page page) {
page.navigate("https://www.wikipedia.org/");
page.locator("input[name=\"search\"]").click();
page.locator("input[name=\"search\"]").fill("playwright");
page.locator("input[name=\"search\"]").press("Enter");
assertEquals("https://en.wikipedia.org/wiki/Playwright", page.url());
}
}
@UsePlaywright
class Test2 {
@Test
void shouldReturnInnerHTML(Page page) {
page.setContent("<div>hello</div>");
assertEquals("hello", page.innerHTML("css=div"));
}
@Test
void shouldClickButton(Page page) {
Page popup = page.waitForPopup(() -> {
page.evaluate("window.open('about:blank');");
});
assertEquals("about:blank", popup.url());
}
}
```
Configure JUnit to run tests in each class sequentially and run multiple classes on parallel threads (with max
number of thread equal to 1/2 of the number of CPU cores):
```bash
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = same_thread
junit.jupiter.execution.parallel.mode.classes.default = concurrent
junit.jupiter.execution.parallel.config.strategy=dynamic
junit.jupiter.execution.parallel.config.dynamic.factor=0.5
```

View file

@ -83,6 +83,8 @@ public class TestExample {
See [here](./test-runners.md) for further details on how to run tests in parallel, etc.
See experimental [JUnit integration](./junit.md) to automatically initialize [Playwright] objects and more, thanks to fixtures.
## What's Next
- [Debugging tests](./debug.md)

View file

@ -87,6 +87,8 @@ public class TestExample {
}
```
See experimental [JUnit integration](./junit.md) to automatically initialize [Playwright] objects and more, thanks to fixtures.
### Running Tests in Parallel
By default JUnit will run all tests sequentially on a single thread. Since JUnit 5.3 you can change this behavior to run tests in parallel