How to Automate tests using Taiko with Cucumber in JavaScript

How to Automate tests using Taiko with Cucumber in JavaScript

Hello! In this blog, I will be exploring how to automate tests using Taiko with Cucumber in JavaScript. The Taiko tool is easy to automate and is very reliable, and it works faster to execute and run test cases. It is a user-friendly tool as well. 

What is Takio?

A Taiko is an automation tool that is available for free and it is an open-source browser automation tool. It is built by the ThoughtWorks team. It uses the Node.js library to automate the chrome browser. Taiko is very useful to create maintainable and highly readable JavaScript tests.  

Taiko Features:

The Taiko was explicitly built to test modern web applications. 

The features of Taiko that set it apart from other browser automation solutions are listed below.

  1. Easy Installation
  2. Interactive Recorder
  3. Smart Selectors
  4. Handle XHR and dynamic content
  5. Request/Response stubbing and mocking

We can use Taiko on three platforms:

  1. Windows
  2. macOS
  3. Linux

How to install Taiko?

A Taiko is available on npm: You can use the following NPM command to install the taiko on your system.

npm install -g taiko

What is cucumber?

A Cucumber is a testing tool that allows BDD.  It offers a way to write tests that everyone, regardless of technical ability, can follow. Before developers build their code in BDD, users (business analysts, product owners) first write scenarios or acceptance tests that describe the system behavior from the perspective of the customer. Such scenarios and acceptance tests then are reviewed and approved by the product owners.

How to install Cucumber?

Basically, cucumber is available on npm: You can use the following NPM command to install the cucumber on your system.

npm install --save-dev @cucumber/cucumber

Getting Started 

We will be using Visual Studio code to write our test automation code in JavaScript. We will create a feature file first, then click on the left side of the panel and choose “new file” from the menu that appears. Give a file name after that, such as the Calculator. feature

I’ll start out by introducing the Taiko framework, which integrates BDD and Cucumber. You will be guided through the code in the next step.

Feature: Calculator operations
  @smoke
  Scenario: Addition of 2 numbers
    Given I launch calculator application
    When I click on number 2
    And I click on operator +
    And I click on number 2
    Then I verify the result is 4

I’ll describe how to automate the calculator page in this place. The code shown below builds calculator steps where we must import statements provided by cucumber before navigating to the support folder. 

After that, we can import the cucumber and assertion statements and that will build a page where all the steps are generally placed. 

Basically, this is the step definition file where we need to map the feature file steps and call methods declared in the page file.

After that, we have to import the page file in the step definition file.  And we need to call the methods declared in the page file. 

Following is the code snippet for the step definition file.

const { Given, When, Then } = require('@cucumber/cucumber')
const calculate = require('../../pages/calculatorPage')
Given('I launch calculator application', async function () {
  await new calculate().launch()
})
When('I click on number {string}', async function (num) {
  await new calculate().click_number(num)
})
When('I click on operator {string}', async function (num) {
  await new calculate().click_operator(num)
})
Then('I verify the result is {string}', async function (num) {
  await new calculate().verify_result(num)
})

Now let’s create a page(We are using Page Object Model (POM) structure here) file where we have to declare the class and all the methods cleaning in step definitions.

Following is the code snippet for the page file.

const { Before } = require('@cucumber/cucumber')
var { setDefaultTimeout } = require('@cucumber/cucumber')
setDefaultTimeout(60 * 1000)
const {
  openBrowser,
  goto,
  write,
  click,
  $,
  closeBrowser,
  setConfig,
  button,
  waitFor,
} = require('taiko')
const assert = require('assert')
setConfig({ observeTime: 30000, retryTimeout: 30000, navigationTimeout: 30000 })
class calculate {
  async launch() {
    await openBrowser({ headless: false })
    return goto('calculator.net')
  }
  async click_number(num) {
    waitFor(5000)
    await click($('span[onclick="r(' + num + ')"]'))
  }
  async click_operator(num) {
    await click($(`span[onclick="r('` + num + `')"]`))
  }
  async verify_result(num) {
    waitFor(5000)
    assert.equal(await $('#sciOutPut').text(), num)
    closeBrowser()
  }
}
module.exports = calculate

And, In the above code snippet, methods contain actions like opening the browser, visiting a website, CSS selectors and actions to be performed on it (click), and Assertions. You may notice that we are doing open browser and close browser actions into this page file itself which is not the best practice. You can move it to Before/After hooks and create a nice framework. However, that is for a later blog 🙂

So, to execute the test case, you can run the following command from the terminal.

npx cucumber-js --publish

Happy testing !!!

Conclusion:

We can automate tests using taiko with Cucumber with JavaScript very easily. Taiko is a very powerful tool and easy to implement. It will definitely compete with Selenium and Playwright in the coming years.

Read more blogs here

How to download a File using Python and Selenium

How to download a File using Python and Selenium

This article provides you with a solution for downloading a file using python and selenium in a folder. Handling files can be a tedious task at times. Especially, when you have test scenarios like downloading a file and verifying if the file is downloaded and if yes then delete the downloaded file. 

Despite visiting many websites and reading many articles, I was not able to find the right solution. Here, I am providing all the solutions in one place, as visiting multiple web pages to find a single solution is tiring. Here, we are using the python and selenium combination to download a file in a folder. You can use the language you like for example, java, javascript, c#, etc. After reading this article, you will get to know how you can handle this type of scenario and we will solve this issue together. So just follow the steps described. 

Traditional Approach:

When you download any file from the website it generally gets downloaded in your download folder i.e. on your local system, but here, is what we are doing we are creating a folder download in our framework. Then we download that file in this newly created folder. 

Till this point, I assume you have understood the test scenario and also we will be passing the file name to delete the particular file. Also, to verify whether the particular file is getting downloaded or not.

It would help if you imported some packages of python and selenium they have listed below.  

To change the download folder path from our local system to the framework folder we need to add some script here, that will set the new download folder as our default folder, to download the files from the webpage. 

Step1:

Import the following packages.

from selenium import webdriver
import os
From selenium.webdriver.common.by import By
From webdriver_manager.chrome import ChromeDriverManager

After adding the above imports now we will have to change the path to do so see the script and you will get an idea. 

op = webdriver.ChromeOptions()
op.add_argument('--no-sandbox')
op.add_argument('--verbose')
op.add_argument("--disable-notifications")
op.add_experimental_option("prefs", {
  "download.default_directory": "G:/Python/Download/",
  "download.prompt_for_download": False,
  "download.directory_upgrade": True,
  "safebrowsing.enabled": True})
op.add_argument('--disable-gpu')
op.add_argument('--disable-software-rasterizer')

Now we have set the download path to our new folder now we have to set the driver. 

Step2:

Here, I have used the web driver manager you can use the chrome driver and provide the path if you want to. But, I suggest using web driver manager, as it is a good practice to use. Because it will download all the updated chrome driver versions automatically and you will save lots of your time. 

driver = webdriver.Chrome(ChromeDriverManager().install(), chrome_options=op)

I hope no one has any problems or doubts till this point, as these steps are crucial and if you have any doubts go through the steps again.  Now you can launch your webpage URL. 

Step3:

Here, I want you to write your script to locate the web element and click on that element for example refer to the following scrip

driver.find_element(By.XPATH, “//span[@type = ‘button’]”).click()

After clicking, the file will get downloaded in the new download folder that we have created in our framework. 

Step4:

The next step is to see if the file is present in the newly created download folder. In order to achieve this just go through the following script. 

def download_file_verify(self,filename):
       dir_path = "G:/Python/Download/"
        res = os.listdir(dir_path)
        try:
            name = os.path.isfile("Download/" + res[0])
            if res[0].__contains__(filename):
                print("file downloaded successfully")
        except "file is not downloaded":
            name = False
        return name

Here, you can provide the name of your downloaded file to the filename argument to avoid the hard coding of the script, as it is not a good practice. 

Explanation:

For instance, the name of my downloaded file is extent report so now the value of the filename argument becomes extent report.

So, first of all, it will go to the directory path we have provided now it will store all the file names already present in the folder in a list format. 

Here we have stored that list in the res variable. Now we can iterate over the list and verify if our desired file is present in the folder or not. 

Take note here, that the newly downloaded file will always be present in the zeroth index of our download folder. That is why we have used res[0] to check, if the downloaded file is present at the zeroth index or not. 

Now, it will check if the zeroth index file name is equal to that of the name of the file we have provided. So, if yes then it will print(“file downloaded successfully”), and if not then it will throw an exception and will print(“file is not downloaded”)

Here I have used assertion to verify whether the file is downloaded or not. I will suggest you use the same as it is good practice. You will get to know the assertion while handling the file. 

Congratulations, we are done with the first part. We have successfully downloaded the file in the newly created download folder. We have also verified whether the file is downloaded or not. 

Step5:

The next task is to delete the downloaded file by passing the name of the file. So, let’s get started then. 

Script to delete the file from the download folder by passing the name of the file. 

def delete_previous_file(self,filename):
        try:
            d_path = "G:/Python/Download/"
            list = os.listdir(d_path)
            for file in list:
                print("present file is: " + file)
                path = ("Download/" + file)
                if file.__contains__(filename):
                    os.remove(path)
                    print("Present file is deleted")
        except:
            pass

Explanation:

Here, we don’t have to only delete the file that is present at the zeroth index. But we have to delete all the files present in the download folder with the same file name. So, that when a new file gets downloaded there will be only one file present. 

So the above code will first go to the directory path. Store all the file names present as a list. So, now we have to iterate over that list and see if the same file is present. If yes then we have to delete that file. 

Use try and except block. Here, if there is no file present, then our code will not raise any exceptions or will fail. 

Congratulations now we have successfully completed the file handling with selenium python. 

Output:

If you have any queries comment them down. We will solve that problem together like we just solved one. Also, if you have any suggestions then let me know. I will implement that in our next article. Also, don’t forget to share the article with your friends. Follow our pages on LinkedIn, Instagram, and Facebook. and subscribe to our blog. So, whenever we post some amazing content you will get to know it and, you will not have to wait for it. 

For Reference: https://pynative.com/python/file-handling/

Conclusion:

In my opinion, validation of file downloading at a particular location is a very easy process. Only, if you have the right solution for reference. In this article, I am sure I have provided the right solution for all your file-downloading problems and validations.

Read more blogs here

Easy way to verify the MD5 checksum of a downloaded file in Test Automation

Easy way to verify the MD5 checksum of a downloaded file in Test Automation

There are many instances during test automation when you would download the files and then would want to verify the completeness of your files downloaded. The MD5 checksum verification is to validate the authenticity of the file so we can ensure that the received file is exactly the same as at the source. This blog explains what MD5 checksum is and also, how we can use it in test automation.

Let’s understand the need for MD5 checksum Verification for a file.

Different kinds of files are distributed on the network or any storage media at different destinations. So, there is a chance that the file can be corrupted because of a few missing bits during data transfer due to some different reasons. Below are a few factors that can cause this to happen, such as:

  •    An interruption to the Internet or network connection.
  •    Storage or space problems, including hard drive-related problems.
  •    A corrupted disk or corrupted file.
  •    A third party interfering with the transfer of data.

After receiving the file, we need to check if the file received is correct or incorrect. It also becomes necessary to verify that our copy of the file is authentic and does not contain any error by applying some sort of test.

We basically use the special key string for this file integrity test known as a checksum. Also, we can refer to checksum as a hash sum or a hash value, hash code, or simply a hash. The most famous and widely used checksum technique is nothing but the MD5 checksum.

the digest, MD5, or hash checksum has been extensively used in the software world to provide some assurance that an uploaded file arrived intact from its source

What is MD5?

The message-digest algorithm(MD5) is a cryptographic hash function whose main purpose is to verify that a file has not been altered.

MD5 hashes are 128 bits long and are usually displayed as their 32-digit hexadecimal equivalents. It doesn’t matter how large or small the file or text is.

For Reference:https://www.intel.com/content/www/us/en/support/programmable/articles/000078103.html

What is the MD5 checksum of a file?

As we learn, it is a 32-character hexadecimal number that is computed on a file. Various Checksum programs are used to generate checksum key strings from the files and verify the integrity of the files. Later by using that checksum string with the original ones shared by the file servers. The file servers often provide a pre-computed MD5, so that a user can compare the checksum of the downloaded file to it. There is a high probability that two files with the same MD5 checksum are the same.

How to calculate MD5 checksum for a file:

1. Calculate MD5 checksum for a file for windows:

With a command prompt, PowerShell command, or third-party applications like Hash Generator or MD5 Checksum Utility, you can generate a checksum for a file. 

a. With the command prompt:

Basically, the command line tool is built-in into the Microsoft Windows 10 operating system, as a certificate service, which is “CertUtil”.

This command line offers a switch, “Hashfile”; We can generate a hash string. Here is a specific algorithm that we can use, such as MD5:

certutil -hashfile <file> <algorithm>           

certutil -hashfile Example.txt MD5

It generates an MD5 file checksum in the command prompt on Windows…

b. With PowerShell:

Since there is no coding, this is the most efficient and easiest method. If PowerShell 4.0 is used then a command line, i.e., cmdlet exists in it.

 This cmdlet can also reffer as “Get-FileHash”. Thanks to this command line, because of that command line we can generate hash files easily:

Get-FileHash -Path <file> -Algorithm <name>

Get-FileHash -Path explorer.exe -Algorithm MD5

Use Get-FileHash in Powershell. It returns the hexadecimal string/hash.

2. Calculate MD5 checksum for a file using some Third Party Tools:

Also, you can find out which tools to use in the right-click menu in a file. Following are some tools we generally can use:

·        Hash Generator

·        MD5 & SHA Checksum Utility.

·      HashMyFiles 

3. Calculate MD5 checksum for a file through automation using C# :

Here, you can calculate programmatically using .net, Java, Python, etc.

To calculate it for a file in C#, .net provides an inbuilt functionality for generating these hash functions, For that reason, we need to import the following NuGet package: https://www.nuget.org/packages/Security.Cryptography

System.Security.Cryptography.MD5

Firstly we need to instantiate the Message Digest Object.

The Compute Hash method of the instance returns the computed hash of the file (bypassing the file stream).

Later, we can convert it to hex, the Bit Converter allows you to represent it as a string for conversion.

So, below is an example code showing a method (GetMD5HashFromFile ()).

It accepts the file name along with the path and then returns the calculated checksum. Also, generates the checksum, After that, it converts into a hex string, and removes dashes. This is the typical format.

The hash string for the file returned by this method can be compared with the one provided by the file servers and checked if the file is altered or not.

private string GetMD5HashFromFile(string fileName)
       using (var md5 = MD5.Create())
       {
                using (var stream = File.OpenRead(fileName))
                 {
                       var hash= md5.ComputeHash(stream);
                      return BitConverter.ToString(hash).Replace("-", string.Empty);
              }
         }

You can call the above function wherever you need to get the checksum. For example:

void verifyChecksum()
{
string filePath = "../../../Resources/test.pdf";
string hash = GetMD5HashFromFile (filePath);
Assert.Equal("A152F13B6EE1EA3D047A6AB99D12A1A1", hash);
}

Conclusion:

As I have implemented and tested this in a test case automation, so, I believe this is a most simple and easier way to verify MD5 checksums for a file in automation using C#

Read more blogs here

How to Create Click-up issues on failed tests using Cypress?

How to Create Click-up issues on failed tests using Cypress?

The purpose of this blog is to provide an overview of Create Click-up issues on failed tests using Cypress for reporting bugs during testing or when automated tests are failed. Click-up is a cloud-based collaboration and project management tool suitable for all team sizes to adopt as an Application Lifecycle Management tool. In our context, we will use it to create bug tasks for failed tests.

In this blog, we will have a quick overview of:-
  • What is Click-up?
  • What is Click-up API and how to use them?
  • How to automate the Click API using cypress.
  • How To create a task automatically when a Cypress test fails with Screenshots.
Requirements:-
  • Node.js to be installed.
  • Any IDE recommended is VS Code.
  • Cypress 10 or any version of Cypress installed.
  • Click-up account.
Now let’s start with our agenda

What is Click-up?

It is a project management tool that is easy to customize and use.

What are Click-up API and how do use them?

Click API  is a service provided by Click-up through which you can operate Click-up without UI.

You can find more information about this by visiting this page:-https://clickup.com/api

We can use them through API client tools like the postman or you can use them in any programming language/ technology which supports HTTPS protocols. In this blog, we are using the Cypress testing tool which is Node.js-based technology using JavaScript as a programming language.

How to automate the Click-API using Cypress?

Cypress’s cy.request API module helps you to automate API quickly.

How to create a task automatically when a Cypress test fails with Screenshots.

Requirements.
  • Personal access token for Click-up.
  • Postman or any API client tool.
  • List Id, Folder Id, Space Id, and Team id of Click-up workspace. 
Let’s see how can we get the personal access token for Click-up:-
  1. Navigate to your personal Settings. 

2. Click Apps in the left sidebar.

3. Click Generate to create your API token.

4. Click Copy to copy the key to your clipboard.

Note:- You can use this personal access token in API for authentication. 

 Get the Team Id 

This endpoint is used to view teams: user groups in your workspace. Use the following API request in postman or any other API client tool for getting the team id which needs to pass as a URI parameter to get the Space id.

Request:- https://api.clickup.com/api/v2/team

Method:- GET

Headers: key:- Authorization

Value:-Personal access token 

Response JSON:

{
    "teams": [
        {
            "id": "33131480",
        }
             ]
 }
Now we need to get the Space Id

View the spaces available in a workspace.

Request:-https://api.clickup.com/api/v2/team/<team_id>/space

Method:-GET

Headers: key:- Authorization

               Value:-Personal access token 

Response JSON

{
    "spaces": [
        {
            "id": "1236491",
        }
              ]
}

Till now we have fetched responses of two endpoints

Let’s get the folder id 

View the folders in space.

Request:-https://api.clickup.com/api/v2/space/<space_id>/folder

Method:-GET

Headers: key:- Authorization

               Value:-Personal access token 

Response JSON

{
    "folders": [
        {
            "id": "34231390",
            "name": "Product Roadmap",
            "orderindex": 0,
            "override_statuses": true,
            "hidden": false,
            "space": {
                "id": "3376891",
                "name": "New Space"
                     }
       }
               ]
}
Now The last thing to get is a List of id 

View the lists within a folder.

Request:- https://api.clickup.com/api/v2/folder/<folder>/list

Method:-GET

Headers: key:- Authorization

               Value:-Personal access token 

Response JSON:

{
    "lists": [
        {
            "id": "7623172",
            "name": "Jan",
            "orderindex": 2,
            "status": null,
            "priority": null,
            "assignee": null,
            "task_count": 2,
            "due_date": "1612045800000",
            "start_date": "1609453800000",
            "folder": {
                "id": "3488090",
                "name": "Product Roadmap",
                "hidden": false,
                "access": true
        }
      }
     ]
}

We have fetched all the required Uri parameters for getting the list id now we can use this list id as a Uri parameter for generating tickets through automation using cypress

  •  How to create a task automatically when a cypress test fails with screenshots.

We have successfully extracted the list id which we will be using as a Uri parameter for creating a task. The cypress “command.js” file is a  file where we have to place reusable code inside that we have the “cypress.command.add” method so we can use that code anywhere in cypress tests.

Paste the following code in Cypress/ Supports/ Command.js

Below is create task method name and we are passing the feature name, scenario name, and steps as a parameter which will be added to the ticket in Click-up

Cypress.Commands.add("CreateTask",(featurename,scenarioname,allsteps)=>

Now to call the endpoint with cy.request we will require the endpoint, the request method, and the access token, so we will store everything in a variable and access in the below code.  mention all endpoints, request methods, and access tokens as variables. 

let endpoint = 'https://api.clickup.com/api/v2/list/<listid>/task'
    let req = 'POST'
    let token = Access_Token '
    const headers = {
        'Authorization': token,
        'Content-Type': 'application/json'
                    }

We are passing all the variables to the cy.request which we mentioned above.

Calling API:- This API will create a ticket for us and the response that we yield will give the id of the ticket which we can use to attach a screenshot in the next request.

cy.request({ method: req, url: endpoint, 'headers': headers, body: body }).then((response) => {
        cy.log(JSON.stringify(response))
        id = response.body.id
        Getting the Response 
        cy.log(id)

In this case, we are getting the id of the ticket which we can use in the next request as a Uri parameter. Now we need to get the path of the failed screenshot dynamically and pass it to the API so that screenshot should get attached to the same click-up ticket.

The below code will attach a screenshot to the ticket which we have created through automation.

const screenshotsFolder = Cypress.config("screenshotsFolder");
         
            const screenshotFileName = `${featurename} -- ${scenarioname} (failed).png`;
Attaching ScreenShot
            cy.request("https://clickup.com")
 var data = new FormData();
            data.append("filename", screenshotFileName);
            cy.log(id)

We have to attach a screenshot as multipart form data and pass it as a Blob as a request for the above ticket which we have created. Here we have used XMLHttp request as cy.request does not support multipart form data.

                cy.intercept({
                method: "POST",
                url: "https://api.clickup.com/api/v2/task/"+id+"/attachment?custom_task_ids=false&team_id=3344860"
            }).as('uploadFile')
                .window()
                .then((win) => {
                    cy.wait(3000)

Here we are reading the screenshot file and creating Blob and passing it as a binary.

cy.readFile(`${screenshotsFolder}/${Cypress.spec.name}/${screenshotFileName}`, 'binary')
                        .then((binary) => Cypress.Blob.binaryStringToBlob(binary))
                        .then((blob) => {
                            const xhr = new win.XMLHttpRequest();
                            data.set("attachment", blob, `${screenshotsFolder}/${Cypress.spec.name}/${screenshotFileName}`);
                            xhr.open("POST", "https://api.clickup.com/api/v2/task/"+id+"/attachment?custom_task_ids=false&team_id=3344860");
                            let token = Access_Token

We have used XMLHttp request to process and send multipart form data in the request.

 xhr.setRequestHeader('Access-Control-Allow-Headers', '*')
                            xhr.setRequestHeader("Authorization", token);
                            xhr.send(data);
                        })
                })
            cy.wait('@uploadFile').then((response) => {
                cy.log(response)
            })
})
}) 

Now when the test fails this part of the code will get executed which will call the method mentioned in the command.js file and automatically create the ticket with a failed screenshot and description.

Paste the code in Cypress/Beforeafter.js.
afterEach(() => {

This Code Will Execute after each test
   cy.on("test:after:run", (test, runnable) => {
      setTimeout(() => {
            Cypress.env("ok",test)
      }, 4000);         
        }).then(()=>
        {

Now we have to extract the feature file name, scenario name, and steps so that we can pass it to the Click-up ticket. We have a test state as a window object which yields all the properties related to the test like test name, test status, etc…

cy.wait(6000)
          let chip = Cypress.env("ok")
          let status = chip.state
          let scenario = chip.title
          let allsteps = ""
          let Featurename = testState.gherkinDocument.feature.name
       let current = chip._testConfig.testConfigList[0].overrides.env.__cypress_cucumber_preprocessor_dont_use_this.currentStep.pickleStep.text
         let a = chip._testConfig.testConfigList[0].overrides.env.__cypress_cucumber_preprocessor_dont_use_this.allSteps
          for (let index = 0; index < a.length; index++) {
              const element = a[index]      
              allsteps += element.pickleStep.text
          }

Calling the custom command which will create a ticket every time the test fails. Passing the feature name scenario name and all steps as parameters to be added to the ticket.

This will create a ticket in Click-up. 

cy.CreateTask(Featurename,scenario,allsteps)
        })
                })
  • The task will be created in Click-up as shown below in the screenshot:-
Conclusion:-

We can create tasks with screenshots attachments for failed test cases using click-up APIs and automate them using Cypress automation.

Read more blogs here

How to Skip Authentication in test automation using Playwright

How to Skip Authentication in test automation using Playwright

Every software application identifies, recognizes, and authenticates the user trying to access the system using some type of credentials (i.e Username and password). And once the user is verified/authenticated, that user is granted permission to access authorized resources.

So, while testing the software application for every test case, the first step we perform is the login step.

If the test suite consists of 100+ test cases, then the step of logging in to the application will be performed for each test case. You can imagine the unnecessary time that will consume for logging in to the application each time for all those 100+ test cases.

Can we find a way to reduce the time required for logging in to the application for every test case? or can we skip logging in to the software application altogether?

This is where Playwright comes into the picture.

The playwright is an open-source test automation tool created by Microsoft. It is a cross-platform tool and has a set of features like Test Generator (codegen), Trace viewer, Inspector, etc, and the most important feature of Playwright which will help us to skip authentication in test automation is full isolation with browser context.

In addition, you can refer to the official document on playwright basic authentication.

First Off, we will have to login into the application via UI and reuse the authentication state in different and multiple scenarios using the browser context.

Let’s see how we can do it.

First, we are going to create a GenerateSession.java class where all of our own logical and automated login steps will be implemented,

Code:

import com.microsoft.playwright.*;
import java.nio.file.Paths;
public class GenerateSession {

        Playwright playwright = Playwright.create();
        Browser browser = playwright.chromium().launch(new      BrowserType.LaunchOptions().setHeadless(false));
        BrowserContext browserContext = browser.newContext();

        Page page = browserContext.newPage();
        page.navigate(BASE URL);
        page.fill("//*[@id=\"username\"]",USERNAME);
        page.fill("//*[@id=\"password\"]",PASSWORD);
        page.click("//*[@id=\"Login\"]");

So, what we did here is, launched the browser and created a new page.

In BrowserContext browserContext = browser.newContext();
we have created a browser context. This browserContext will store our authentication state i.e it will store the session, cookies, local storage, etc.

As you can see, we created the browser context browserContext, but the question here is, where will this authentication state (browserContex) will be stored?

The best way to store this browser context in a .json file.

The playwright provides a method called storageState() which will help us store the authentication state.

browserContext.storageState(new BrowserContext.StorageStateOptions().setPath(Paths.get("appLoginInfo.json")));

The above code snippet will store the authentication state, cookies, local storage, etc in json format in appLoginInfo.json file.

If the appLoginInfo.json file is not created then the playwright will create a new file with the provided name appLoginInfo.json at the provided location in setPath(Paths.get(“appLoginInfo.json”)));

If you have the appLoginInfo.json file already created, each time you execute the above snippet, a new authentication state with cookies and local storage will be overwritten in the appLoginInfo.json file.

Now, we are all set up with our authentication state, cookies, and local storage. Our next question is

How do we use that authentication state and skip login for each scenario?

We can use a Playwright to skip authentication scenarios. As we all know, Web applications use cookies and token-based authentications. These authentications are stored in the form of cookies or local storage. The playwright provides us with methods that can store these authentication state and then create a new browser context with the previously restored session, which in turn help us skip login/authentication for the scenarios.

Here, we will set the stored authentication state using the methods above to the new browser context created for each scenario we run.

The playwright provides us with a method newContext()  which will create a new browser context.

And by using NewContextOptions(), we can add/set the stored authentication state in the appLoginInfo.json file.

Let’s look at how we can do it in the code snippet below.

BrowserContext brContext = browser.newContext(new Browser.NewContextOptions().

setStorageStatePath(Paths.get("appLoginInfo.json")));

Here, setStorageStatePath(Paths.get(“appLoginInfo.json”))will set the authentication state stored in appLoginInfo.json to the new browser context created in the previous step.

So, every time we execute the above code snippet, the browser context that is stored in appLoginInfo.json file will be set to the new browser context and the previous session will be restored.

Please refer to the methods listed below. I used these methods to skip authentication scenarios for one of the Salesforce apps.

        @Test
        public void generateSessionCookies() throws InterruptedException {
        Playwright playwright = Playwright.create();
        Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
        BrowserContext browserContext = browser.newContext();
        Page page = browserContext.newPage();
        page.navigate("BASE URL");
        page.fill("//*[@id=\"username\"]", "USERNAME");
        page.fill("//*[@id=\"password\"]", "PASSWORD");
        page.click("//*[@id=\"Login\"]");
        page.click("//*[@id=\"save\"]");
        browserContext.storageState(new BrowserContext.StorageStateOptions().setPath(Paths.get("appLoginInfo.json")));
        page.close();
}
         @Test
         public void useSavedSessionCookies() throws InterruptedException {
         Playwright playwright = Playwright.create();
         Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
         BrowserContext browserContext = browser.newContext();
         Page page = browserContext.newPage();
         browserContext.storageState(new BrowserContext.StorageStateOptions().setPath(Paths.get("appLoginInfo.json")));
         page.close();
}

Conclusion:

In this way, Playwright helps us to store the authentication state, cookies, local storage, etc. And we can use this authentication state and set it to our new browser context and restore the previous session, which will in turn help us skip the login step for the n number of scenarios for a software application.

I hope this article has served you well. 

Read more blogs here