DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • The Next Evolution of Java: Faster Innovation, Simpler Adoption
  • 6 of the Best API Testing Tools in the Market
  • Designing a Java Connector for Software Integrations
  • Jakarta NoSQL 1.0: A Way To Bring Java and NoSQL Together

Trending

  • Build Your First AI Model in Python: A Beginner's Guide (1 of 3)
  • Mastering Fluent Bit: Installing and Configuring Fluent Bit on Kubernetes (Part 3)
  • Contextual AI Integration for Agile Product Teams
  • Operational Principles, Architecture, Benefits, and Limitations of Artificial Intelligence Large Language Models
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. Create a Custom Logger to Log Response Details With Playwright Java

Create a Custom Logger to Log Response Details With Playwright Java

This tutorial teaches how to create a custom logger for login response details using the Playwright Java framework for API testing.

By 
Faisal Khatri user avatar
Faisal Khatri
DZone Core CORE ·
Jan. 20, 25 · Tutorial
Likes (5)
Comment
Save
Tweet
Share
7.1K Views

Join the DZone community and get the full member experience.

Join For Free

While working on the series of tutorial blogs for GET, POST, PUT, PATCH, and DELETE requests for API Automation using Playwright Java. I noticed that there is no logging method provided by the Playwright Java framework to log the requests and responses.

In the REST-assured framework, we have the log().all() method available that is used for logging the request as well as the response. However, Playwright does not provide any such method. However, Playwright offers a text() method in the APIResponse interface that could be well used to extract the response text.

Playwright currently does not have the feature to access the request body and request headers while performing API Testing. The issue is already raised on GitHub for this feature, please add an upvote to this issue so this feature gets implemented soon in the framework.

In this blog, we will learn how to extract the response and create a custom logger to log the response of the API tests using Playwright Java.

How to Log Response Details in Playwright Java

Before we begin with actual coding and implementation for the logger, let’s discuss the dependencies, configuration, and setup required for logging the response details.

Getting Started

As we are working with Playwright Java using Maven, we will use the Log4J2 Maven dependency to log the response details. The dependency for Jackson Databind will be used for parsing the JSON response.

XML
 
<dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-api</artifactId>
                <version>${log4j-api-version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-core</artifactId>
                <version>${log4j-core-version}</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>${jackson-databind-version}</version>
            </dependency>


As a best practice, the versions of these dependencies will be added in the properties block as it allows users to easily check and update the newer version of dependencies in the project.

XML
 
<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <log4j-core-version>2.24.1</log4j-core-version>
        <log4j-api-version>2.24.1</log4j-api-version>
        <jackson-databind-version>2.18.0</jackson-databind-version>
    </properties>


The next step is to create a log4j2.xml file in the src/main/resources folder. This file stores the configuration for logs, such as log level, where the logs should be printed — to the console or to the file, the pattern of the log layout, etc.

XML
 
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="LogToConsole" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="io.github.mfaisalkhatri" level="info" additivity="false">
            <AppenderRef ref="LogToConsole"/>
        </Logger>
        <Root level="error">
            <AppenderRef ref="LogToConsole"/>
        </Root>
    </Loggers>
    <Loggers>
        <Logger name="io.github.mfaisalkhatri" level="trace" additivity="false">
            <AppenderRef ref="LogToConsole"/>
        </Logger>
        <Root level="error">
            <AppenderRef ref="LogToConsole"/>
        </Root>
    </Loggers>
</Configuration>


The <Appenders> section contains the information related to log printing and its pattern format to print. The <Loggers> section contains the log-level details and how it should be printed. There can be multiple blocks of <Loggers> in the file, each for different log levels, such as “info,” “debug,” “trace,” etc.

Available on GitHub


Implementing the Custom Logger

A new Java class Logger is created to implement the methods for logging the response details.

Java
 
public class Logger {

   private final APIResponse                     response;
   private final org.apache.logging.log4j.Logger log;

   public Logger (final APIResponse response) {
       this.response = response;
       this.log = LogManager.getLogger (getClass ());
   }

//...

}


This class has the APIResponse interface of Playwright and the Logger interface from Log4j declared at the class level to ensure that we can reuse it in further methods in the same class and avoid duplicate code lines.

The constructor of the Logger class is used for creating objects of the implementing classes. The APIResponse interface is added as a parameter as we need the response object to be supplied to this class for logging the respective details.

The logResponseDetails() method implements the function to log all the response details.

Java
 
public void logResponseDetails () {
        String responseBody = this.response.text ();
        this.log.info ("Logging Response Details....\n responseHeaders: {}, \nstatusCode: {},",
            this.response.headers (), this.response.status ());
        this.log.info ("\n Response body: {}", prettyPrintJson (responseBody));
        this.log.info ("End of Logs!");
    }


The responseBody variable will store the response received after executing the API. The next line of code will print the response details, Headers, and Status Code.

As the response returned is not pretty printed, meaning the JSON format is shown in String in multiple lines wrapped up, this makes the logs look untidy. Hence, we have created a prettyPrintJson() method that consumes the response in String format and returns it in pretty format.

Java
 
private String prettyPrintJson (final String text) {
        if (StringUtils.isNotBlank (text) && StringUtils.isNotEmpty (text)) {
            try {
                final ObjectMapper objectMapper = new ObjectMapper ();
                final Object jsonObject = objectMapper.readValue (text, Object.class);
                return objectMapper.writerWithDefaultPrettyPrinter ()
                    .writeValueAsString (jsonObject);
            } catch (final JsonProcessingException e) {
                this.log.error ("Failed to pretty print JSON: {}", e.getMessage (), e);
            }
        }
        return "No response body found!";

    }


This method accepts the String in the method parameter where the response object will be supplied.

A check is performed using the if() condition to verify that the text supplied is not blank, null and it is not empty. If the condition is satisfied, then the ObjectMapper class from the Jackson Databind dependency is instantiated.

Next, the text value of the response is read, and it is converted and returned as the JSON pretty print format using the writerWithDefaultPrettyPrinter() and writeValueAsString() methods of the ObjectMapper class.

If the response is null, empty, and blank, it will print the message “No response body found!” and the method will be exited.

How to Use the Logger in the API Automation Tests

The Logger class needs to be instantiated and its respective methods need to be called in order to get the response details printed while the tests are executed.

We need to make sure that we don’t write duplicate code everywhere in the tests to get the response details logged. In order to handle this, we would be using the BaseTest class and creating a new method, logResponse(APIResponse response).

This method will accept the APIResponse as parameter, and the logResponseDetails() method will be called after instantiating the Logger class.

Java
 
public class BaseTest {

//...

    protected void logResponse (final APIResponse response) {
        final Logger logger = new Logger (response);
        logger.logResponseDetails ();
    }
}


As the BaseTest class is extended to all the Test classes; it becomes easier to call the methods directly in the test class.

The HappyPathTests class that we have used in previous blogs for adding happy scenario tests for testing GET, POST, PUT, PATCH, and DELETE requests already extends the BaseTest class. Let’s print the response logs for the POST and GET API request test.

The testShouldCreateNewOrders() verifies that the new orders are created successfully. Let’s add the logResponse() method to this test and get the response printed in the logs.

Java
 
public class HappyPathTests extends BaseTest{
    @Test

    public void testShouldCreateNewOrders() {

        final int totalOrders = 4;

        for (int i = 0; i < totalOrders; i++) {
            this.orderList.add(getNewOrder());
        }

        final APIResponse response = this.request.post("/addOrder", RequestOptions.create()
                .setData(this.orderList));

        logResponse (response);

//...
// Assertion Statements...

  }
}


The logResponse() method will be called after the POST request is sent. This will enable us to know what response was received before we start performing assertions.

The testShouldGetAllOrders() verifies the GET /getAllOrder API request. Let’s add the logResponse() method to this test and check the response logs getting printed.

Java
 
public class HappyPathTests extends BaseTest{
    @Test
    public void testShouldGetAllOrders() {

        final APIResponse response = this.request.get("/getAllOrders");

        logResponse (response);

        final JSONObject responseObject = new JSONObject(response.text());
        final JSONArray ordersArray = responseObject.getJSONArray("orders");

        assertEquals(response.status(), 200);
        assertEquals(responseObject.get("message"), "Orders fetched successfully!");
        assertEquals(this.orderList.get(0).getUserId(), ordersArray.getJSONObject(0).get("user_id"));
        assertEquals(this.orderList.get(0).getProductId(), ordersArray.getJSONObject(0).get("product_id"));
        assertEquals(this.orderList.get(0).getTotalAmt(), ordersArray.getJSONObject(0).get("total_amt"));
    }
}


The logResponse() method is called after the GET request is sent and will print the response logs in the console.

Test Execution

The tests will be executed in order where POST request will be executed first so new orders are created and then the GET request will be executed. It will be done using the testng-restfulecommerce-postandgetorder.xml file.

XML
 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Restful ECommerce Test Suite">
    <test name="Testing Happy Path Scenarios of Creating and Updating Orders">
        <classes>
            <class name="io.github.mfaisalkhatri.api.restfulecommerce.HappyPathTests">
                <methods>
                    <include name="testShouldCreateNewOrders"/>
                    <include name="testShouldGetAllOrders"/>
                </methods>
            </class>
        </classes>
    </test>
</suite>


On executing the above testng-restfulecommerce-postandgetorder.xml file, the POST, as well as GET API requests, are executed, and the response is printed in the console, which can be seen in the screenshots below.

The response is printed in the console after executing the POST and GET API requests


POST API Response Logs

POST API Response Logs 1
POST API Response Logs 2


GET API Response Logs

GET API Response Logs 1
GET API Response Logs 2


It can be seen from the screenshots that the response logs are printed correctly in the console and can now help us know the exact results of the test execution.

Summary

Adding a custom logger in the project can help in multiple ways. It will provide us with the details of the test data that was processed along with the final output, giving us control over the tests. It also helps in debugging the issue for failed tests and finding a fix quickly for it.

If the response data is readily available we can quickly find the pattern of the issue and try for a quick fix. As Playwright does not provide any method for logging the response details, we can add our own custom logger that can help us in fetching the required details.

Happy testing!

API API testing Java (programming language)

Published at DZone with permission of Faisal Khatri. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • The Next Evolution of Java: Faster Innovation, Simpler Adoption
  • 6 of the Best API Testing Tools in the Market
  • Designing a Java Connector for Software Integrations
  • Jakarta NoSQL 1.0: A Way To Bring Java and NoSQL Together

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: