Playwright
is a Node.js
-based device for automating browsers. It helps all trendy rendering engines together with Chromium
, WebKit
and Firefox
. Playwright
can be utilized with JavaScript
, TypeScript
, Python
, .NET
and Java
. On this tutorial, we’ll discover the setup of a check automation venture utilizing Playwright
for Java
, JUnit 5
and Gradle
. Additionally, you will be taught some fundamentals of Playwright
instruments like codegen
, Playwright Inspector
and hint viewer. I can even present some fundamental setup for Docker
in addition to GitHub Actions
. Let’s get began!
Introduction
Disclaimer
- The venture setup introduced on this article relies on
Gradle
, nevertheless it must be famous thatPlaywright
forJava
is meant for use withMaven
, as indicated within the venture documentation and supply code. In case you are contemplating utilizingPlaywright
forJava
in your subsequent venture, think about usingMaven
. - The setup introduced on this article is a results of my eagerness to be taught and experiment with
Playwright
forJava
. Nevertheless, please word that some facets of the setup might not be future-proof. When you have any strategies or enhancements, please be at liberty to contact me through Twitter, LinkedIn, or report a difficulty within the venture repository. - This text was edited and proofread with the assistance of
ChatGPT
, to make sure that it’s well-written and error-free. Nevertheless, please word that the Content material and concepts introduced on this article are solely mine, and any opinions expressed are my very own. The AI language mannequin was used purely for modifying functions and didn’t affect the Content material of this text in any approach.
Why Playwright
?
I began utilizing Playwright
(with Node.js
) in June 2022, and I’m actually impressed with this device. Listed below are a number of the options I discover most necessary about Playwright
:
- Straightforward to make use of: Among the best issues about
Playwright
is that it’s packaged multi function and simple to arrange and use. Not like withSelenium
, there’s no have to combine completely different instruments collectively. - Multi-language help:
Playwright
helps a number of programming languages, together withJavaScript
,TypeScript
,Python
,.NET
, andJava
. Whereas the nativeNode.js
model supplies the perfect expertise, for my part, due to its built-in check runner with highly effective configuration and reporting capabilities,Playwright
makes it simpler for builders to put in writing assessments within the language they’re most snug with. - Multi-browser help:
Playwright
helpsChromium
,Firefox
,WebKit
, andOpera
. Configuration is straightforward, and there’s no want to put in extra drivers or seek the advice of third-party documentation. All these browsers’ drivers are maintained by the identical group. - Auto-wait performance:
Playwright
routinely waits for web page parts to be seen and interactive earlier than performing actions on them. This helps keep away from flakiness in assessments and makes them extra dependable. - Web page and browser context isolation:
Playwright
means that you can create a number of browser contexts and isolate assessments from one another simply. This supplies extra robustness and stability when operating assessments. - Tooling:
Playwright
comes with instruments that make it simple to handle and execute assessments from the command line, and combine with construct techniques and automation instruments. Codegen is one such device that means that you can file your interactions with an online utility and generate the code routinely. - Structure and limitations: Not like
Cypress
, which runs assessments in the identical runtime as the applying being examined,Playwright
runs assessments in a separate course of. This supplies extra isolation and avoids potential points.Playwright
has no issues with operating assessments in parallel, which may be a difficulty withCypress
except you pay. - Documentation: The
Playwright
documentation is well-organized, simple to navigate, and perceive. It incorporates a variety of examples and code snippets. I discovered it very useful and was capable of finding what I wanted with none issues. There are matters thought that aren’t that nicely defined or lack data (like for instanceDocker
part), however I’m certain will probably be improved sooner or later.
Playwright
: Java
vs Node.js
Though I don’t have a lot expertise with the Java
model of Playwright
but, I can say that because it goes to the API it is vitally just like the Node.js
model. The principle distinction is that the Java
model doesn’t have a built-in check runner, so you need to use a third-party one, equivalent to JUnit 5
. And Node.js
built-in check runner supplies a variety of helpful options equivalent to:
- Visible testing out of the field through
count on
API. - Numerous configuration choices like timeout, retries, headless mode, browsers, viewports, reporters and way more.
- Simply configurable tracing and video recording.
- Constructed-in reporters together with the
HTML
reporter.
Why Playwright
for Java
?
Though the Node.js
model at the moment seems to be superior to the Java
model, I imagine it’s nonetheless worthwhile to think about using Playwright
for Java
. Listed below are some explanation why I feel it’s a related choice:
- I feel that
Playwright
forJava
is usually a trendy, dependable, and user-friendly different toSelenium
for end-to-end testing inJava-based
tasks – solely if you’re prepared for some compromises and further work round configuration. - I imagine that some groups might not be capable of use
Node.js
for numerous causes, soPlaywright
forJava
could possibly be a superb different. Playwright
forJava
can be utilized as a device for automating duties (like crawling net pages, scraping information, and many others.) and never essential to create end-to-end assessments. If that’s the case, the shortage of a built-in check runner is just not an issue.
Supply code
The whole code for this text may be discovered on GitHub: junit5-playwright-demo.
Conditions
What you’ll want to get began:
- Terminal of your alternative
- Git
- Java 17 or greater
- IntelliJ IDEA (or every other IDE of your alternative)
For Java
I like to recommend asdf
model supervisor. Yow will discover extra details about on my weblog: Handle a number of Java SDKs with asdf with ease .
Organising the venture with Gradle
To hurry up the method of organising the venture, I’ll use the junit5-gradle-template repository. It’s a template venture for JUnit 5
and Gradle
particularly.
Be aware: There may be additionally an official starter by JUnit
group that may be discovered right here: junit5-jupiter-starter-gradle
Steps:
- Clone the template repository:
git clone --depth=0 https://github.com/kolorobot/junit5-gradle-template my-playwright-project && cd my-playwright-project
- Take away the
.git
listing:rm -rf .git
- Execute
./gradlew clear check
to confirm that all the pieces works as anticipated - Import venture to your IDE
Including Playwright
dependency
To make use of Playwright
with Java
, we have to add the playwright
dependency to construct.gradle
file:
buildscript { ext { playwrightVersion = '1.30.0' } } implementation "com.microsoft.playwright:playwright:${playwrightVersion}"
The library is added as implementation
dependency, so will probably be obtainable within the runtime classpath as nicely. This can enable us to make use of the library not solely in our assessments, but additionally in our utility code.
Playwright
with no check runner
With dependency added, we will create a easy app that may open a browser and navigate to an internet site.
- Create a brand new bundle in
src/fundamental/java
listing (e.g.pl.codeleak.demos.playwright
) - Create a brand new class
App
in that bundle and add the next code:
bundle pl.codeleak.demos.playwright; import com.microsoft.playwright.Browser; import com.microsoft.playwright.BrowserType; import com.microsoft.playwright.Web page; import com.microsoft.playwright.Playwright; public class App { public static void fundamental(String[] args) { strive (Playwright playwright = Playwright.create()) { Browser browser = playwright.chromium().launch(); Web page web page = browser.newPage(); web page.navigate("https://weblog.codeleak.pl/"); System.out.println(web page.title()); } } }
The above code creates a Playwright
occasion and launches a browser (on this case, Chromium
) in headless mode and creates a brand new web page.
The web page navigates to an internet site, will get its title and prints it to the console. The code makes use of a try-with-resources
assertion, which routinely closes the playwright
object when the strive block is completed.
To run the browser in non-headless mode, we will modify the code as follows:
bundle pl.codeleak.demos.playwright; import com.microsoft.playwright.Browser; import com.microsoft.playwright.BrowserType; import com.microsoft.playwright.Web page; import com.microsoft.playwright.Playwright; public class App { public static void fundamental(String[] args) { BrowserType.LaunchOptions launchOptions = new BrowserType.LaunchOptions() .setHeadless(false); strive (Playwright playwright = Playwright.create()) { Browser browser = playwright.chromium().launch(launchOptions); Web page web page = browser.newPage(); web page.navigate("https://weblog.codeleak.pl/"); System.out.println(web page.title()); } } }
To run the app, we will use run
command, however first we have to modify construct.gradle
file and configure the utility
plugin:
plugins { id("utility") } utility { mainClass = "pl.codeleak.demos.playwright.App" }
Now, we will run the app with ./gradlew run
command.
❯ ./gradlew run > Activity :run weblog.codeleak.pl BUILD SUCCESSFUL in 5s 2 actionable duties: 1 executed, 1 up-to-date
Working Playwright CLI
instruments with Gradle
Playwright
comes with a CLI
instruments that may be helpful for code era, operating and debugging assessments or viewing the traces.
To run Playwright CLI
with Gradle
, we have to modify construct.gradle
, add utility
plugin, and create a customized playwright
activity that executes com.microsoft.playwright.CLI
:
apply plugin: 'utility' duties.register('playwright', JavaExec) { classpath = sourceSets.fundamental.runtimeClasspath mainClass="com.microsoft.playwright.CLI" }
Now, we will run Playwright CLI
with Gradle:
./gradlew playwright --args="--help"
Generate code with codegen
As we arrange the Playwright CLI
, we will use it to run codegen
command. codegen
is a device that may generate code snippets for you based mostly on the consumer interactions with an internet site utilizing Playwright Inspector
. It means that you can file your interactions with an online web page after which generate code snippets in Java
that can be utilized to automate these interactions.
As per the official documentation, Playwright Inspector
is a GUI device that helps writing and debugging Playwright scripts. That’s our default advisable device for scripts troubleshooting.
To be taught extra about codegen
device and its choices, we will execute the next command:
./gradlew playwright --args="codegen --help"
As you observe the output, the codegen
command supplies loads of choices. For instance, we will specify the browser to make use of or the machine to emulate, and many others. Let’s strive:
./gradlew playwright --args="codegen --browser chromium --device 'iPhone 13' https://weblog.codeleak.pl/"
As soon as the above command is executed, two home windows can be opened: Playwright Inspector
and the browser that can be navigated to the desired URL. Now, we will work together with the web site and the codegen
will generate code snippets for us. As soon as we’re completed with the interplay, we will copy the code and use it in our scripts.
JUnit 5
meets Playwright
Organising the bottom Playwright
check
Within the earlier part, we realized easy methods to use Playwright
as browser device in a easy utility. Now, we’ll discover ways to use it with JUnit 5
.
Let’s create a base check class that can be utilized by all our assessments. It is going to arrange Playwright
and create a browser occasion. The bottom check class can even create a brand new browser context and a brand new web page for every check methodology.
@TestInstance(TestInstance.Lifecycle.PER_CLASS) summary class PlaywrightTest { Playwright playwright; Browser browser; BrowserContext context; Web page web page; @BeforeAll void launchBrowser() { playwright = Playwright.create(); browser = playwright.chromium().launch(); } @AfterAll void closeBrowser() { browser.shut(); playwright.shut(); } @BeforeEach void createBrowserContext() { context = browser.newContext(); web page = context.newPage(); } @AfterEach void closeBrowserContext() { web page.shut(); context.shut(); } }
Let’s rapidly look at the above code:
- The category is annotated with
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
, which implies that just one occasion of the check class is created for all check strategies, and the identical occasion is used for all check strategies within the class. - The category has 4
JUnit 5
lifecycle strategies:@BeforeAll
: thelaunchBrowser
methodology launches aChromium
browser utilizingPlaywright
. It’s executed earlier than all check strategies within the class.@AfterAll
: thecloseBrowser
methodology closes thebrowser
andPlaywright
gracefully. It’s executed in any case check strategies within the class.@BeforeEach
: thecreateBrowserContext
methodology creates a brand new browser context and a brand new web page object for interacting with a browser. It’s executed earlier than every check methodology within the class.@AfterEach
: thecloseBrowserContext
methodology closes the web page and context after every check.
To set the default check occasion lifecycle to PER_CLASS
for all assessments in JUnit 5, create a file referred to as junit-platform.properties
in src/check/sources
with the next Content material:
junit.jupiter.testinstance.lifecycle.default=per_class
JUnit 5
is the most recent model of the favored JUnit testing framework. It’s a full rewrite of the unique JUnit 4 framework. JUnit 5
is the primary model of JUnit to help Java 8 options equivalent to lambda expressions and default strategies. In case you are not conversant in JUnit 5
, you may examine my JUnit 5 – Fast Tutorial publish.
Creating a primary check
Now, we will create our first check. Let’s create a check class that extends the PlaywrightTest
class and create a easy check that navigates to this weblog and searches for “junit 5” time period. The check class will appear to be this:
bundle pl.codeleak.demos.playwright; import org.junit.jupiter.api.Check; import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat; class BlogSearchTest extends PlaywrightTest { @Check void searchesForTermAndGetsResults() { web page.navigate("https://weblog.codeleak.pl"); web page.locator("button[aria-label="Search"]").click on(); web page.getByPlaceholder("Search this weblog").fill("junit 5"); web page.getByPlaceholder("Search this weblog").press("Enter"); assertThat(web page).hasURL("https://weblog.codeleak.pl/search?q=junit+5"); assertThat(web page.locator("article .publish")).hasCount(20); assertThat(web page.getByText("Present posts matching the seek for junit 5")) .isVisible(); } }
Let’s rapidly look at the above code:
- The check class extends the
PlaywrightTest
class, which implies that it inherits all of the setup and teardown strategies. - The check methodology makes use of the
web page
object to navigate to the weblog, clicks the search button, fills the search enter and press theEnter
key. - It makes use of
Playwright
built-in assertions to examine that:- the URL incorporates the search time period
- the search outcomes are displayed and there are 20 of them
- the search outcomes header is seen
Now, we will run the check and observe the consequence:
./gradlew check --tests BlogSearchTest > Activity :check BlogSearchTest > searchesForTermAndGetsResults() FAILED org.opentest4j.AssertionFailedError at BlogSearchTest.java:19 1 check accomplished, 1 failed > Activity :check FAILED FAILURE: Construct failed with an exception. * What went unsuitable: Execution failed for activity ':check'. > There have been failing assessments. See the report at: file:///construct/stories/assessments/check/index.html
Oops, the check failed (not less than it ought to). You may look at the report at construct/stories/assessments/check/index.html
to see the small print. The rationale of failure may be rapidly seen within the report:
org.opentest4j.AssertionFailedError: Locator anticipated to be seen Name log: Locator.count on with timeout 5000ms ready for getByText("Present posts matching the seek for junit 5")
As you may see, the check failed as a result of the anticipated search outcomes header is just not seen. To repair this we will look at the applying by manually executing the state of affairs, we will debug the check in IDE, or we will run the check in a debug mode with Playwright.
Let’s strive the final choice to be taught extra about Playwright Inspector
.
Debugging the check with Playwright Inspector
You might be already conversant in Playwright Inspector
from the earlier part. Now, we will use it to debug our check. To do this, we have to run the check in a debug mode:
PWDEBUG=1 PLAYWRIGHT_JAVA_SRC=./src/check/java ./gradlew check --tests BlogSearchTest
PWDEBUG=1
allows the debug mode and begins the browser in headed mode (it’s possible you’ll recall that the bottom class launches the browser in headless mode).PLAYWRIGHT_JAVA_SRC=./src/check/java
tells Playwright to make use of the supply code from thesrc/check/java
listing. It’s wanted to have the ability to see the supply code within thePlaywright Inspector
.
The inspector opens a browser window and highlights parts because the check is being executed. The toolbar supplies choices to play the check, step via every motion utilizing Step over
, or resume the script. You’ve got entry to Actionability Logs
that present some helpful information about actions being carried out. You may as well look at the web page by utilizing the Discover
choice. Final however not least, you should utilize the browser developer instruments.
Recording a hint
You may as well file a hint of the check execution. To do this, you’ll want to use BrowserContext.tracing()
API. Modify @BeforeEach
and @AfterEach
annotated strategies in PlaywrightTest
as follows:
@BeforeEach void createBrowserContext() { context = browser.newContext(); context.tracing().begin(new Tracing.StartOptions() .setScreenshots(true) .setSnapshots(true)); web page = context.newPage(); } @AfterEach void closeBrowserContext(TestInfo testInfo) { var traceName = testInfo.getTestClass().get().getSimpleName() + "-" + testInfo.getTestMethod().get().getName() + "-trace.zip"; context.tracing().cease(new Tracing.StopOptions() .setPath(Paths.get("construct/stories/traces/" + traceName))); web page.shut(); context.shut(); }
When you re-run the check, you will discover the hint within the construct/stories/traces
listing. You may open it within the trace-view
device like this:
./gradlew playwright --args="show-trace construct/stories/traces/BlogSearchTest-searchesForTermAndGetsResults-trace.zip"
Fixing the check
Since we positioned the rationale check was failing, we will repair it by modifying the final assertion (the textual content must be: “Exhibiting posts matching the seek for junit 5”:
assertThat(web page.getByText("Exhibiting posts matching the seek for junit 5")) .isVisible();
Web page Object
sample with Playwright
As soon as the primary check is passing, we will transfer on to the subsequent one. This time can be creating assessments for TodoMVC Vanilla.js-based utility obtainable right here: http://todomvc.com/examples/vanillajs. The applying is a Single Web page Utility
(SPA
) and makes use of native storage as a activity repository. The doable situations to be applied embody including and modifying todo, eradicating todo, marking single or a number of todos as completed. The implementation can be completed utilizing Web page Object
sampleaka
POP`.
The aim of POP
is to summary the applying pages and performance from the precise assessments. POP
improves re-usability of the code throughout assessments and fixtures but additionally makes the code simpler to keep up.
Let’s create an interface with the strategies that characterize situations that we are going to be automating:
bundle pl.codeleak.demos.playwright; import java.util.Checklist; interface TodoMvc { void navigateTo(); void createTodo(String todoName); void createTodos(String... todoNames); int getTodosLeft(); boolean todoExists(String todoName); int getTodoCount(); Checklist<String> getTodos(); void renameTodo(String todoName, String newTodoName); void removeTodo(String todoName); void completeTodo(String todoName); void completeAllTodos(); void showActive(); void showCompleted(); void clearCompleted(); }
Implementing TodoMVC web page API
We’ll create a category TodoMvcPage
that may implement the TodoMvc
interface:
bundle pl.codeleak.demos.playwright; import com.microsoft.playwright.Locator; import com.microsoft.playwright.Web page; import java.util.Checklist; import java.util.Objects; public class TodoMvcPage implements TodoMvc { non-public Web page web page; public TodoMvcPage(Web page web page) { Objects.requireNonNull(web page, "Web page is required"); this.web page = web page; } @Override public void navigateTo() { web page.navigate("https://todomvc.com/examples/vanillajs"); } public void createTodo(String todoName) { web page.locator(".new-todo").kind(todoName); web page.locator(".new-todo").press("Enter"); } public void createTodos(String... todoNames) { for (String todoName : todoNames) { createTodo(todoName); } } public int getTodosLeft() { return Integer.parseInt(web page.locator(".todo-count > sturdy").textContent()); } public boolean todoExists(String todoName) { return getTodos().stream().anyMatch(todoName::equals); } public int getTodoCount() { return web page.locator(".todo-list li").depend(); } public Checklist<String> getTodos() { return web page.locator(".todo-list li") .allTextContents(); } public void renameTodo(String todoName, String newTodoName) { Locator todoToEdit = getTodoElementByName(todoName); todoToEdit.dblclick(); Locator todoEditInput = todoToEdit.locator("enter.edit"); todoEditInput.clear(); todoToEdit.kind(newTodoName); todoToEdit.press("Enter"); } public void removeTodo(String todoName) { Locator todoToRemove = getTodoElementByName(todoName); todoToRemove.hover(); todoToRemove.locator("button.destroy").click on(); } public void completeTodo(String todoName) { Locator todoToComplete = getTodoElementByName(todoName); todoToComplete.locator("enter.toggle").click on(); } public void completeAllTodos() { web page.locator(".toggle-all").click on(); } public void showActive() { web page.locator("a[href="#/active"]").click on(); } public void showCompleted() { web page.locator("a[href="#/completed"]").click on(); } public void clearCompleted() { web page.locator(".clear-completed").click on(); } non-public Locator getTodoElementByName(String todoName) { return web page.locator(".todo-list li") .all() .stream() .filter(locator -> todoName.equals(locator.textContent())) .findFirst() .orElseThrow(() -> new RuntimeException("Todo with identify " + todoName + " not discovered!")); } }
First, we navigate to the applying utilizing navigate
methodology. Parts on that web page are positioned utilizing the locator
methodology of the Playwright
s Web page
object. This methodology takes a selector (on this case CSS
selector) as an argument and returns a Locator
object that represents the set of parts matching that selector. The returned Locator
object supplies strategies to work together with the positioned parts, equivalent to depend
(returns the variety of parts), textContent
(returns the textual content Content material of the primary ingredient), allTextContents
(returns an inventory of textual content Contents of all parts), click on
and dbclick
(simulates a click on occasion on the primary ingredient), clear
(clears the Content material of the primary ingredient), and kind
(sorts textual content into the primary ingredient).
Learn extra about locators within the Playwright
documentation right here and right here, and about actions right here.
Creating TodoMVC assessments
Earlier than creating precise assessments, let’s add AssertJ
to our venture. We’ll use it to make assertions in our assessments.
Add the next dependency to construct.gradle
:
buildscript { ext { assertJVersion = '3.21.0' } } dependencies { testImplementation "org.assertj:assertj-core:${assertJVersion}" }
Now, we’re able to create the check class. Let’s see the code:
bundle pl.codeleak.demos.playwright; import org.junit.jupiter.api.*; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; @DisplayName("Managing Todos") class TodoMvcTests extends PlaywrightTest { TodoMvc todoMvc; non-public ultimate String buyTheMilk = "Purchase the milk"; non-public ultimate String cleanupTheRoom = "Clear up the room"; non-public ultimate String readTheBook = "Learn the e-book"; @BeforeEach void navigateTo() { todoMvc = new TodoMvcPage(web page); todoMvc.navigateTo(); } @Check @DisplayName("Creates Todo with given identify") void createsTodo() { // act todoMvc.createTodo(buyTheMilk); // assert assertAll( () -> assertThat(todoMvc.getTodosLeft()).isOne(), () -> assertThat(todoMvc.todoExists(buyTheMilk)).isTrue() ); } @Check @DisplayName("Edits inline double-clicked Todo") void editsTodo() { // organize todoMvc.createTodos(buyTheMilk, cleanupTheRoom); // act todoMvc.renameTodo(buyTheMilk, readTheBook); // assert assertAll( () -> assertThat(todoMvc.todoExists(buyTheMilk)).isFalse(), () -> assertThat(todoMvc.todoExists(readTheBook)).isTrue(), () -> assertThat(todoMvc.todoExists(cleanupTheRoom)).isTrue() ); } @Check @DisplayName("Removes chosen Todo") void removesTodo() { // organize todoMvc.createTodos(buyTheMilk, cleanupTheRoom, readTheBook); // act todoMvc.removeTodo(buyTheMilk); // assert assertAll( () -> assertThat(todoMvc.todoExists(buyTheMilk)).isFalse(), () -> assertThat(todoMvc.todoExists(cleanupTheRoom)).isTrue(), () -> assertThat(todoMvc.todoExists(readTheBook)).isTrue() ); } @Check @DisplayName("Toggles chosen Todo as accomplished") void togglesTodoCompleted() { todoMvc.createTodos(buyTheMilk, cleanupTheRoom, readTheBook); todoMvc.completeTodo(buyTheMilk); assertThat(todoMvc.getTodosLeft()).isEqualTo(2); todoMvc.showCompleted(); assertThat(todoMvc.getTodoCount()).isOne(); todoMvc.showActive(); assertThat(todoMvc.getTodoCount()).isEqualTo(2); } // The remainder of the assessments omitted for brevity. }
Let’s look at the code a bit:
- The
navigateTo
methodology can be referred to as earlier than every check, however after lifecycle strategies outlined within the base class. It is going to create a brand new occasion ofTodoMvcPage
class and navigate to the TodoMVC utility. - The
@DisplayName
annotation is used to supply a extra descriptive identify for the check. Will probably be displayed within the check report. - The
assertAll
methodology is used to group assertions. It is going to fail the check if any of the assertions fails. That is JUnit 5 characteristic. - The
assertThat
methodology is used to make assertions. It’s offered byAssertJ
library. NoPlaywright
built-in assertions are used as we wish to preserve the check code impartial of the underlying implementation.
Be aware: TodoMvc
interface in addition to the check was adopted from the code I created for my Selenium and JUnit 5 tutorial. The tutorial may be discovered right here and the supply code right here.
Working the assessments
To run the assessments, execute the next command:
./gradlew check --tests TodoMvcTests > Activity :check Managing Todos > Creates Todo with given identify PASSED Managing Todos > Creates Todos all with the identical identify PASSED Managing Todos > Edits inline double-clicked Todo PASSED Managing Todos > Removes chosen Todo PASSED Managing Todos > Toggles chosen Todo as accomplished PASSED Managing Todos > Toggles all Todos as accomplished PASSED Managing Todos > Clears all accomplished Todos PASSED BUILD SUCCESSFUL in 9s
Parameterized assessments
The final thought of parameterized unit assessments is to run the identical check methodology for various check information. To create a parameterized check in JUnit 5
you annotate a check methodology with @ParameterizedTest
and supply the argument supply for the check methodology. There are a number of argument sources obtainable together with:
@ValueSource
– offered entry to array of literal values i.e.shorts
,ints
,strings
and many others.@MethodSource
– supplies entry to values returned from manufacturing unit strategies@CsvSource
– which reads comma-separated values (CSV) from a number of provided CSV traces@CsvFileSource
– which is used to load comma-separated worth (CSV) information
Create check information
In our instance, we’ll use CSV file as a supply of check information with the next Content material:
todo;completed Purchase the milk;false Clear up the room;true Learn the e-book;false
Add this file to the src/check/sources
listing.
Add dependency
To make use of parameterized assessments, we have to add the next dependency to the construct.gradle
file:
testImplementation "org.junit.jupiter:junit-jupiter-params:${junitJupiterVersion}"
Create assessments
To create a parameterized check, we have to annotate the check methodology with @ParameterizedTest
and supply the argument supply. The whole supply code of the TodoMvcParameterizedTests
class is proven under:
bundle pl.codeleak.demos.playwright; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.supplier.CsvFileSource; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; class TodoMvcParameterizedTests extends PlaywrightTest { TodoMvcPage todoMvc; @BeforeEach void navigateTo() { todoMvc = new TodoMvcPage(web page); todoMvc.navigateTo(); } @ParameterizedTest @CsvFileSource(sources = "/todos.csv", numLinesToSkip = 1, delimiter=";") @DisplayName("Creates Todo with given identify") void createsTodo(String todo) { todoMvc.createTodo(todo); assertSingleTodoShown(todo); } @ParameterizedTest(identify = "{index} - {0}, completed = {1}") @CsvFileSource(sources = "/todos.csv", numLinesToSkip = 1, delimiter=";") @DisplayName("Creates and optionally removes Todo with given identify") void createsAndRemovesTodo(String todo, boolean completed) { todoMvc.createTodo(todo); assertSingleTodoShown(todo); todoMvc.showActive(); assertSingleTodoShown(todo); if (completed) { todoMvc.completeTodo(todo); assertNoTodoShown(todo); todoMvc.showCompleted(); assertSingleTodoShown(todo); } todoMvc.removeTodo(todo); assertNoTodoShown(todo); } non-public void assertSingleTodoShown(String todo) { assertAll( () -> assertThat(todoMvc.getTodoCount()).isOne(), () -> assertThat(todoMvc.todoExists(todo)).isTrue() ); } non-public void assertNoTodoShown(String todo) { assertAll( () -> assertThat(todoMvc.getTodoCount()).isZero(), () -> assertThat(todoMvc.todoExists(todo)).isFalse() ); } }
Run the parameterized assessments
To run the assessments, execute the next command:
./gradlew check --tests TodoMvcParameterizedTests TodoMvcParameterizedTests > Creates and optionally removes Todo with given identify > pl.codeleak.demos.playwright.TodoMvcParameterizedTests.createsAndRemovesTodo(String, boolean)[1] PASSED TodoMvcParameterizedTests > Creates and optionally removes Todo with given identify > pl.codeleak.demos.playwright.TodoMvcParameterizedTests.createsAndRemovesTodo(String, boolean)[2] PASSED TodoMvcParameterizedTests > Creates and optionally removes Todo with given identify > pl.codeleak.demos.playwright.TodoMvcParameterizedTests.createsAndRemovesTodo(String, boolean)[3] PASSED TodoMvcParameterizedTests > Creates Todo with given identify > pl.codeleak.demos.playwright.TodoMvcParameterizedTests.createsTodo(String)[1] PASSED TodoMvcParameterizedTests > Creates Todo with given identify > pl.codeleak.demos.playwright.TodoMvcParameterizedTests.createsTodo(String)[2] PASSED TodoMvcParameterizedTests > Creates Todo with given identify > pl.codeleak.demos.playwright.TodoMvcParameterizedTests.createsTodo(String)[3] PASSED BUILD SUCCESSFUL in 8s
Learn additionally: Cleaner Parameterized Assessments with JUnit 5
Run all of the assessments
Thus far, we’ve fairly some assessments. Let’s run all them and see how lengthy it takes:
./gradlew clear check BUILD SUCCESSFUL in 17s
Fairly lengthy. Can we pace it up?
Parallel assessments execution
JUnit 5
has built-in help for parallel assessments execution however by default assessments are executed sequentially. To alter this, we have to present a number of properties, however we additionally have to be sure that our Playwright
based mostly assessments may be executed in parallel.
Playwright
and thread-safety
Playwright
for Java is just not thread-safe, which means that its strategies, in addition to the strategies of objects created by it (equivalent to BrowserContext
, Browser
, Web page
, and many others.), ought to solely be accessed on the thread the place the Playwright
object was created, or correct synchronization should be put in place to make sure that just one thread is accessing Playwright
strategies at a time.
Provided that utilizing the identical Playwright
objects throughout a number of threads with out correct synchronization is just not secure, it is strongly recommended to create a separate Playwright
occasion for every thread and use it solely on that thread.
As it’s possible you’ll recall, our PlaywrightTest
base class is annotated with @TestInstance(TestInstance.Lifecycle.PER_CLASS)
to be sure that the Playwright
occasion is created solely as soon as for the lifecycle of that class. This little trick does the job. No less than, a part of it. We nonetheless have to configure JUnit to run assessments in parallel.
JUnit 5
configuration for parallel execution
To allow parallel execution, we have to set a number of properties. We will present the properties on the command line or through junit-platform.prperties
file.
For that, create junit-platform.properties
file within the src/check/sources
listing and add the next properties to it:
junit.jupiter.execution.parallel.enabled=true junit.jupiter.execution.parallel.mode.courses.default=concurrent junit.jupiter.execution.parallel.config.dynamic.issue=0.5
What it does, is that it allows parallel execution of separate check courses (check strategies in every class are executed sequentially) and dynamically makes use of as much as 50%
of the obtainable CPU cores.
Let’s see if it really works:
./gradlew clear check 5 actionable duties: 5 executed ❯ ./gradlew clear check <===========--> 87% EXECUTING [5s] > :check > 0 assessments accomplished > :check > Executing check pl.codeleak.demos.playwright.TodoMvcParameterizedTests > :check > Executing check pl.codeleak.demos.playwright.BlogSearchTest > :check > Executing check pl.codeleak.demos.playwright.TodoMvcTests BUILD SUCCESSFUL in 11s
It really works! The assessments are executed in parallel, and it took solely 11 seconds to run all of them. You may need observed that each one 3 courses had been executed in parallel.
Learn extra about parallel execution of assessments in JUnit 5 Person Information
Primary GitHub Actions
workflow
Organising a fundamental GitHub Actions
workflow is fairly easy. One necessary half to recollect is that Playwright
obtain all of the browsers on every run (~300 MB) so it could be a good suggestion to make use of cache. This will barely enhance the efficiency of the next workflow runs. Gradle
construct motion helps caching its dependencies by default, however with Playwright
we have to do it manually.
Let’s create a brand new workflow file referred to as run-tests.yml
within the .github/workflows
listing:
identify: Playwright Assessments on: workflow_dispatch: push: branches: fundamental jobs: construct: runs-on: ubuntu-latest steps: - identify: Checkout makes use of: actions/checkout@v3 - identify: Arrange JDK 17 makes use of: actions/setup-java@v3 with: java-version: '17' distribution: 'temurin' - identify: Validate Gradle wrapper makes use of: gradle/wrapper-validation-action@v1 - identify: Setup Gradle makes use of: gradle/gradle-build-action@v2 - identify: Playwright cache makes use of: actions/cache@v3 with: path: | ~/.cache/ms-playwright key: ms-playwright-${{ hashFiles('**/construct.gradle') }} - identify: Run assessments run: ./gradlew clear check
This workflow will run on each push to the fundamental
department and on demand (workflow_dispatch). It is going to checkout the code, setup JDK 17, validate
Gradlewrapper, setup
Gradleand cache
Playwright's
ms-playwright` instantly. Lastly, it would run all of the assessments.
👉 No-cache run:
👉 With-cache run:
It’s possible you’ll additional analyze the ends in the Actions
tab of your repository.
Please word, that is actually easy setup, and it doesn’t cowl all of the doable situations. For instance, it doesn’t run assessments on a number of browsers because the venture itself is just not ready for that.
Playwright
for Java
and Docker
Official Docker
picture may be discovered right here. It incorporates all the required dependencies to run Playwright
for Java
assessments that are Java
, Maven
and the browsers. No Gradle
is pre-installed, however since we’re utilizing Gradle Wrapper
, we don’t really need it.
Working assessments in Docker
Let’s get began with pulling the picture and operating assessments manually. As a way to that, run the next instructions contained in the venture listing:
docker pull mcr.microsoft.com/playwright/java:v1.30.0-focal docker run -it --rm --ipc=host -v $PWD:/assessments mcr.microsoft.com/playwright/java:v1.30.0-focal /bin/bash
The above instructions will pull the picture and run a container with the picture. The container can be eliminated after it exits. The --ipc=host
flag is used to share the host’s IPC namespace with the container, and it is strongly recommended for Playwright
to work correctly. The -v $PWD:/assessments
flag is used to mount the present listing as a quantity contained in the container. The amount is mounted to the /assessments
listing contained in the container.
As soon as the container is operating, we will run the assessments:
root@0644b3386f94:/# cd assessments/ root@0644b3386f94:/assessments# ./gradlew clear check Downloading https://providers.gradle.org/distributions/gradle-8.0-bin.zip Welcome to Gradle 8.0! Beginning a Gradle Daemon (subsequent builds can be quicker) Invalid Java set up discovered at '/usr/lib/jvm/openjdk-17' (Widespread Linux Areas). Will probably be re-checked within the subsequent construct. This may need efficiency impression if it retains failing. Run the 'javaToolchains' activity for extra particulars. > Activity :check <===========--> 87% EXECUTING [13s] > :check > 11 assessments accomplished > :check > Executing check pl.codeleak.demos.playwright.TodoMvcParameterizedTests > :check > Executing check pl.codeleak.demos.playwright.TodoMvcTests BUILD SUCCESSFUL in 51s 5 actionable duties: 5 executed
Be aware: Because it goes to Invalid Java set up discovered error, there appear to be answer within the subsequent model of Gradle: https://github.com/gradle/gradle/pull/23643
Making a Dockerfile
So, we confirmed the picture can be utilized to run the assessments, however we nonetheless have to create a Dockerfile
to construct our personal picture. Let’s create a Dockerfile
within the venture listing:
# Prolong official Playwright for Java picture FROM mcr.microsoft.com/playwright/java:v1.30.0-focal # Set the work listing for the applying WORKDIR /assessments # Copy the wanted information to the app folder in Docker picture COPY gradle /assessments/gradle COPY src /assessments/src COPY construct.gradle /assessments COPY gradle.properties /assessments COPY gradlew /assessments COPY settings.gradle /assessments # Set up dependencies to hurry up subsequent check runs RUN ./gradlew --version
This Dockerfile
extends the official Playwright
for Java
picture and units the working listing for the assessments
. It copies the required information to the app
and installs the dependencies to hurry up subsequent check runs.
Now, we will construct the picture:
docker construct -t playwright-java-tests .
And run assessments within the container:
docker run -it --rm --ipc=host playwright-java-tests ./gradlew clear check
Conclusion
I imagine that Playwright
for Java
is a contemporary and developer-friendly different to Selenium
and Selenium-based
instruments and frameworks for end-to-end testing in Java-based
tasks. Nevertheless, utilizing Playwright
for Java
might require some compromises and further work for correct configuration. It’s necessary to notice that the Node.js
model of Playwright
is highly effective sufficient to deal with complicated end-to-end testing.
Though I at the moment think about the Node.js
model of Playwright
to be superior, I nonetheless imagine that the Playwright
for Java
choice is price contemplating for just a few causes. Firstly, for groups which can be unable to make use of Node.js
, Playwright
for Java
supplies a viable different for end-to-end testing. Secondly, it will also be used for automating duties equivalent to crawling net pages and scraping information and even Robotic Course of Automation
(RPA
) and never only for creating end-to-end assessments.
When you have any strategies or enhancements, please be at liberty to contact me through Twitter, LinkedIn, or report a difficulty within the venture repository.
References
Revealed on Java Code Geeks with permission by Rafal Borowiec, accomplice at our JCG program. See the unique article right here: Playwright meets JUnit 5 Opinions expressed by Java Code Geeks contributors are their very own. |