Using Playwright in GitHub Actions
Tags: playwright, github, azure, weblogic
Published: 2021-11-18 03:29:15

# Story
A few months ago, we started working on a project which demos a path of modernizing traditional Java application(WebLogic + PostgreSQL). And we implemented a pipeline that builds and deploys the [Eclipse Cargo Tracker](https://github.com/Azure-Samples/cargotracker-azure) application to a WebLogic on Azure Kubernetes Service ([AKS](https://azure.microsoft.com/en-us/services/kubernetes-service/#overview)) environment as part of the CI/CD experience.

For the sake of completeness, in the pipeline, a final step of validating the deployed application is the latest version is necessary.

# Our approach
After researching around, we decided to add an invisible stamp in the index page of the Cargo Tracker. Every time we build the app, this stamp will be updated with an unique value. And then at the end of the pipeline, we add a validation step to run a Java Playwright application, which fetches the **version string** from the deployed Cargo Tracker app, and compares it with the valued we pre-stored in earlier steps(Where new version string is generated and the app is not deployed).

The steps are as follow:
* Create the Playwright application
```java
package com.microsoft.azure.javaee;

import com.microsoft.playwright.*;

public class FetchBuildVersion {
  public static void main(String[] args) {
    try (Playwright playwright = Playwright.create()) {
      BrowserType webkit = playwright.webkit();
      Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(true));
      Page page = browser.newPage();
      // take first parameter as Cargo Tracker url
      page.navigate(args[0]);

      ElementHandle p = page.querySelector("xpath=/html/body/div[1]/div/div[2]/p");

      // take second parameter as pre-stored version string
      if (!p.innerText().equals(args[1])) {
        throw new RuntimeException("Build Version is not updated!");
      }
    }
  }
}
```
* Add property to Cargo Track called **version string**, which is a combined string of **Maven project version** and **Maven project build time**. And every time the app is built, a new string will be generated.
```shell
# src/main/resources/org/eclipse/cargotracker/messages.properties
versionString=${project.version} ${project.build.time}
```
* Embed the version string into the index page
```html
<!-- src/main/webapp/index.xhtml -->
<div class="container text-muted">
    <p><h:outputText value="#{messages.versionString}" /></p>
</div>
```
* In the GitHub workflow, add step to query build version and store it as an environment variable.
```yaml
- name: Build the app
  run: |
    echo "build the Cargo Tracker web app"
    mvn clean install -PweblogicOnAks --file cargotracker/pom.xml
- name: Query version string for deployment verification
  run: |
    PROPERTY_FILE="cargotracker/target/cargo-tracker/WEB-INF/classes/org/eclipse/cargotracker/messages.properties"
    PROP_KEY=versionString
    deployVersion=$(cat $PROPERTY_FILE | grep "$PROP_KEY" | cut -d '=' -f 2)
    echo "deployVersion=${deployVersion}" >> $GITHUB_ENV
```
* Add the step to call the Playwright application
```yaml
- name: Verify that the app is update
  run: |
    # install dependencies
    sudo apt-get install libegl1\
                      libopus0\
                      libwoff1\
                      libharfbuzz-icu0\
                      libgstreamer-plugins-base1.0-0\
                      libgstreamer-gl1.0-0\
                      libgstreamer-plugins-bad1.0-0\
                      libopenjp2-7\
                      libwebpdemux2\
                      libenchant1c2a\
                      libhyphen0\
                      libgles2\
                      gstreamer1.0-libav -y
    appURL=http://${{ env.appGatewayURL }}/cargo-tracker/
    cd cargotracker/src/test/aks/playwright-ui-test
    mvn clean install
    mvn exec:java -e -Dexec.mainClass=com.microsoft.azure.javaee.FetchBuildVersion -Dexec.args="'${appURL}' '${{ env.deployVersion }}'"
```

# A brief introduction to our work
[Oracle WebLogic Server](https://www.oracle.com/java/weblogic/) is a scalable, enterprise-ready Java application server. We are a team from Microsoft works on bringing the Oracle WebLogic Server experience on Azure which includes:

* **WebLogic Server on AKS**: The WebLogic Server on AKS offer automates provisioning an AKS cluster, the WebLogic Kubernetes Operator, WLS Docker images and the Azure Container Registry (ACR). The offer also supports configuring load balancing with Azure App Gateway or the Azure Load Balancer, easing database connectivity, publishing metrics to Azure Monitor as well as mounting Azure Files as Kubernetes Persistent Volumes.

* **WebLogic Server on Virtual Machines**: The WebLogic Server on virtual machines offers automate provisioning virtual network, storage, and Linux resources, installing WLS, setting up security with a network security group, easing database connectivity, configuring load-balancing with App Gateway or Oracle HTTP Server, connecting to Azure Active Directory, enabling centralized logging via ELK as well as integrating distributed caching with Oracle Coherence.

_If you want to learn more about our offers or work closely on your migration scenarios with us, just go to this [CONTACT ME](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/oracle.oraclelinux-wls-cluster?tab=Overview) page and hit the button! Program managers, architects and engineers will reach back out to you shortly and initiate collaboration!_


# Reference
[Playwright](https://playwright.dev/) is built to enable cross-browser web automation. And it can be easily introduced into a Java project using Maven.

[GitHub Actions](https://github.com/features/actions) makes it easy to develop a lightweight but powerful CI/CD experience for your code from GitHub.

[Eclipse Cargo Tracker](https://github.com/Azure-Samples/cargotracker-azure) is a project demonstrates how you can develop applications with Jakarta EE using widely adopted architectural best practices like Domain-Driven Design (DDD). **This is the repo contains the pipeline described above**