Gitlab CI/CD: JAVA/Playwright

Basic GitLab CI/CD & aqua workflow

This guide demonstrates integrating automated testing into your GitLab CI/CD pipeline, specifically using Maven project with JAVA/Playwright. However, the steps can be adapted for any test automation tool or framework to submit results to aqua.

Prerequisites

  • a GitLab project with CI/CD enabled

  • an aqua account to submit test results

  • an application or project configured with Maven project (e.g. using Visual Studi Code)

First, generate clean maven project or use existing one.

Make sure the following dependencies are added to the pom.xml file We will need Playwright, JUnit and JSON libraries.

Create a TestBase class to keep all general methods and implementations of the common logic and hooks: BeforeAll, BeforeEach, AfterAll, AfterEach, etc.

Create a TestCase class which extends the TestBase class and implements actual logic of a particular test. Here and further we assume that this class has an aqua Test Case instance so we will update its execution info in aqua web app. Test Case has one Step (Step 1) in aqua.

TestCase class implements simple actions: open www.wikipedia.org web site using playwright actions, do a few clicks there and check actual Web URL:

Using @AfterEach hook in TestBase class connect to aqua and get bearer token from REST GET request sent by playwright

The above token will be needed for POST request to create an aqua Test Case execution. We will use the following endpoint and JSON schema:

https://app.aqua-cloud.io/aquaWebNG/Help#tag/TestExecution/operation/TestExecution_Create

Example implementation in TestBase class for the above request looks as follows:

static void createTCExecution(TestInfo tcInfo, String status){ 

   Map<String, String> headers = new HashMap<>(); 

   headers.put("authorization", "Bearer " + bearerToken); 

   headers.put("content-type", "application/json"); 

   headers.put("accept", "application/json"); 

   headers.put("Connection", "keep-alive"); 

   

 

   APIRequestContext tcExecutionRequest = playwright.request().newContext(new APIRequest.NewContextOptions() 

     .setExtraHTTPHeaders(headers)); 

     

     JSONArray finalArr = new JSONArray(); 

     JSONObject json = new JSONObject(); 

 

     int tcId = Integer.parseInt(tcInfo.getTags().iterator().next()); 

 

 

     json.put("Guid", JSONObject.NULL); 

     json.put("TestCaseId", tcId); 

     json.put("TestCaseName", JSONObject.NULL); 

     json.put("Finalize", false); 

     json.put("ValueSetName", JSONObject.NULL); 

     json.put("TestScenarioInfo", JSONObject.NULL); 

     

     JSONArray stepsArr = new JSONArray(); 

     JSONObject jsonSteps = new JSONObject(); 

     

     jsonSteps.put("Index", 1); 

     jsonSteps.put("Name", "Step 1"); 

     jsonSteps.put("StepType", "Step"); 

     jsonSteps.put("Status", status); 

     jsonSteps.put("Description", JSONObject.NULL); 

     jsonSteps.put("ExpectedResults", JSONObject.NULL); 

     jsonSteps.put("ActualResults", JSONObject.NULL); 

     jsonSteps.put("ActualResultsLastUpdatedBy", JSONObject.NULL); 

     jsonSteps.put("ActualResultsLastUpdated","0001-01-01T00:00:00"); 

 

     stepsArr.put(jsonSteps); 

 

     json.put("Steps", stepsArr); 

     json.put("TestedVersion", JSONObject.NULL); 

     json.put("Status", JSONObject.NULL); 

     

      JSONObject execDuration = new JSONObject(); 

      execDuration.put("FieldValueType","TimeSpan"); 

      execDuration.put("Text","20 second"); 

      execDuration.put("Value",20); 

      execDuration.put("Unit","Second"); 

      

     json.put("ExecutionDuration", execDuration); 

     json.put("AttachedLabels", new JSONArray()); 

     json.put("CustomFields", new JSONArray()); 

     json.put("Attachments", JSONObject.NULL); 

     json.put("TesterId", JSONObject.NULL); 

     json.put("ExecutionDate", JSONObject.NULL); 

     json.put("AttachedFiles", new JSONArray()); 

 

     finalArr.put(json); 

 

     APIResponse tcExcutionResponse = tcExecutionRequest.post(appUrl + "api/TestExecution", RequestOptions.create().setData(finalArr.toString())); 

 

     assertTrue(tcExcutionResponse.ok()); 

 } 

In the above request we are passing “logResult” variable. It represents the actual JUnit test result (“Pass”, “Failed”, “NotRun”, etc.) To obtain this status from JUnit run we implement Test Watcher Interface in the TestBase Class:

In this class we should implement Interface Methods as below:

@Override 

 public void testSuccessful(ExtensionContext context) { 

   System.out.println("Call Success extension"); 

   logResult = "Pass"; 

 } 

 

 @Override 

 public void testAborted(ExtensionContext context, Throwable cause) { 

   System.out.println("Call Abort extension"); 

   logResult = "NotRun"; 

 } 

 

 @Override 

 public void testFailed(ExtensionContext context, Throwable cause) { 

   System.out.println("Call Fail extension"); 

   logResult = "Failed"; 

 } 

We assume that Test Class name is based on actual aqua Test Case Id: e.g in the case above we updated aqua Test Case with Id=270.

This Id variable can be passed from Test Class by using TestInfo from org.junit.jupiter.api.TestInfo;

After successful JUnit test execution we should see corresponding single Test Case execution in aqua

To be able to run the above Maven Project using GitLab CI/CD we need to create corresponding workflow file .gitlab-ci.yml. Simple Example of .gitlab-ci.yml script is shown below:

image: maven:latest 

 

stages:          

 - test 

 

maven-build-job:    

 stage: test     

 script: 

   - pwd  

   - sleep 10 

   - cd aqua-demo/ 

   - mvn compile 

   - mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" 

   - mvn clean test 

Once a GitLab test runner is configured and connected to your GitLab projects we can Run GitLab Pipeline using the above workflow:

Full TestBase class listing:

package com.aqua; 

 

import com.google.gson.Gson; 

import com.google.gson.JsonObject; 

import com.microsoft.playwright.APIRequest; 

import com.microsoft.playwright.APIRequestContext; 

import com.microsoft.playwright.APIResponse; 

import com.microsoft.playwright.Browser; 

import com.microsoft.playwright.BrowserContext; 

import com.microsoft.playwright.BrowserType; 

import com.microsoft.playwright.Page; 

import com.microsoft.playwright.Playwright; 

import com.microsoft.playwright.options.FormData; 

import com.microsoft.playwright.options.RequestOptions; 

 

import org.junit.jupiter.api.AfterAll; 

import org.junit.jupiter.api.AfterEach; 

import org.junit.jupiter.api.BeforeAll; 

import org.junit.jupiter.api.BeforeEach; 

import org.junit.jupiter.api.TestInfo; 

import org.junit.jupiter.api.extension.ExtensionContext; 

import org.junit.jupiter.api.extension.TestWatcher; 

import org.json.*; 

 

import static org.junit.jupiter.api.Assertions.assertTrue; 

 

import java.util.HashMap; 

import java.util.Map; 

 

public class TestBase implements TestWatcher 

{ 

 private static Playwright playwright; 

 private static Browser browser; 

 private static String appUrl = "https://aqua-auto-aqamasterpla.aqua-testing.com/aquawebng/"; 

 private static String bearerToken; 

 private static APIRequestContext request; 

 private static BrowserContext context; 

 private static TestInfo testInfo; 

 private static String logResult; 

 Page page; 

 

 static void getBearerToken() { 

   Map<String, String> headers = new HashMap<>(); 

   headers.put("content-type", "application/x-www-form-urlencoded"); 

 

   request = playwright.request().newContext(new APIRequest.NewContextOptions() 

     .setExtraHTTPHeaders(headers)); 

   APIResponse response = request.post(appUrl + "api/token", RequestOptions.create().setForm( 

     FormData.create() 

       .set("grant_type", "password") 

       .set("username","start") 

       .set("password","default"))); 

 

   assertTrue(response.ok()); 

 

   JsonObject j = new Gson().fromJson(response.text(), JsonObject.class); 

   bearerToken = j.get("access_token").getAsString(); 

 } 

 

 static void createTCExecution(TestInfo tcInfo, String status){ 

   Map<String, String> headers = new HashMap<>(); 

   headers.put("authorization", "Bearer " + bearerToken); 

   headers.put("content-type", "application/json"); 

   headers.put("accept", "application/json"); 

   headers.put("Connection", "keep-alive"); 

   

 

   APIRequestContext tcExecutionRequest = playwright.request().newContext(new APIRequest.NewContextOptions() 

     .setExtraHTTPHeaders(headers)); 

     

     JSONArray finalArr = new JSONArray(); 

     JSONObject json = new JSONObject(); 

 

     int tcId = Integer.parseInt(tcInfo.getTags().iterator().next()); 

 

 

     json.put("Guid", JSONObject.NULL); 

     json.put("TestCaseId", tcId); 

     json.put("TestCaseName", JSONObject.NULL); 

     json.put("Finalize", false); 

     json.put("ValueSetName", JSONObject.NULL); 

     json.put("TestScenarioInfo", JSONObject.NULL); 

     

     JSONArray stepsArr = new JSONArray(); 

     JSONObject jsonSteps = new JSONObject(); 

     

     jsonSteps.put("Index", 1); 

     jsonSteps.put("Name", "Step 1"); 

     jsonSteps.put("StepType", "Step"); 

     jsonSteps.put("Status", status); 

     jsonSteps.put("Description", JSONObject.NULL); 

     jsonSteps.put("ExpectedResults", JSONObject.NULL); 

     jsonSteps.put("ActualResults", JSONObject.NULL); 

     jsonSteps.put("ActualResultsLastUpdatedBy", JSONObject.NULL); 

     jsonSteps.put("ActualResultsLastUpdated","0001-01-01T00:00:00"); 

 

     stepsArr.put(jsonSteps); 

 

     json.put("Steps", stepsArr); 

     json.put("TestedVersion", JSONObject.NULL); 

     json.put("Status", JSONObject.NULL); 

     

      JSONObject execDuration = new JSONObject(); 

      execDuration.put("FieldValueType","TimeSpan"); 

      execDuration.put("Text","20 second"); 

      execDuration.put("Value",20); 

      execDuration.put("Unit","Second"); 

      

     json.put("ExecutionDuration", execDuration); 

     json.put("AttachedLabels", new JSONArray()); 

     json.put("CustomFields", new JSONArray()); 

     json.put("Attachments", JSONObject.NULL); 

     json.put("TesterId", JSONObject.NULL); 

     json.put("ExecutionDate", JSONObject.NULL); 

     json.put("AttachedFiles", new JSONArray()); 

 

     finalArr.put(json); 

 

     APIResponse tcExcutionResponse = tcExecutionRequest.post(appUrl + "api/TestExecution", RequestOptions.create().setData(finalArr.toString())); 

 

     assertTrue(tcExcutionResponse.ok()); 

 } 

 

 @BeforeAll 

 static void berforeAll() { 

   playwright = Playwright.create(); 

   browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setSlowMo(50)); 

 } 

 

 @AfterAll 

 static void closeBrowser() { 

   createTCExecution(testInfo, logResult); 

   context.close(); 

   playwright.close(); 

 } 

 

 @BeforeEach 

 void createContextAndPage(TestInfo testInfo) { 

   TestBase.testInfo = testInfo; 

   context = browser.newContext(); 

   page = context.newPage(); 

 } 

 @Override 

 public void testSuccessful(ExtensionContext context) { 

   System.out.println("Call Success extension"); 

   logResult = "Pass"; 

 } 

 

 @Override 

 public void testAborted(ExtensionContext context, Throwable cause) { 

   System.out.println("Call Abort extension"); 

   logResult = "NotRun"; 

 } 

 

 @Override 

 public void testFailed(ExtensionContext context, Throwable cause) { 

   System.out.println("Call Fail extension"); 

   logResult = "Failed"; 

 } 

 

 @AfterEach 

 void closeContext() { 

   getBearerToken(); 

   System.out.println("Aqua TC Id being executed: " + testInfo.getTags().iterator().next()); 

 } 

 

} 

 

Full Test Class listing:

package com.aqua; 

 

import static org.junit.jupiter.api.Assertions.assertEquals; 

 

import org.junit.jupiter.api.Tag; 

import org.junit.jupiter.api.Test; 

import org.junit.jupiter.api.TestInfo; 

import org.junit.jupiter.api.extension.ExtendWith; 

 

@ExtendWith(TestBase.class) 

public class TestCase270 extends TestBase{ 

 

   @Test 

   @Tag("270") 

   void shouldSearchWiki(TestInfo testInfo) { 

     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()); 

     System.out.println("Test Case executed"); 

   } 

 

} 

Last updated