Single Sign On with Multi Factor Authentication using Cypress 10

Single Sign On with Multi Factor Authentication using Cypress 10

Introduction:

With Cypress 10 we can automate  Single Sign On with Multi-Factor Authentication enabled. The new feature of Cypress 10 helps us to visit multi-domain in a single test. Now the cy.origin module helps us to do the same. We can visit the Single Sign-On site and make users authenticate and redirect to our main application domain. But usually, people find it difficult to automate Single Sign On-based applications and have multi-factor authentication for security. This Blog will help us to overcome both the challenges of Single Sign On with Multi-Factor Authentication using Cypress 10 and using a session that will make our test fast, saves time of login, and authenticate once login multiple times.

Test Goal: Automate Office 365 using Cypress 10

To Overcome both the challenges of SSO and the MFA  using Cypress 10 and using session.

What are the test requirements?

  1. Cypress 10 installed.
  2. The secret key for Office 365 account.
  3. And one npm package.

Let’s start the recipe.

How do I get a secret key for an office 365 account to generate OTP:

6th Choose the authenticator app option

7th Click on the link I want to use a different authenticator app 

8th Click on next

9th Click on the button can’t scan the image

10th Copy the secret key and paste it and click on next.

Installing NPM packages required using one of the below methods:-

  • npm i -D cypress-OTP
  • yarn add -D cypress-OTP

Single Sign On with Multi-Factor Authentication using Cypress 10

We are all set for the next steps now next part is in VS code

Open VS code 

Solution:

Go to supports/command.js

  • This is a custom command, we can use this command anywhere in the cypress test. We have to add parameters such as name, Email id, password, and token as a secret which we extracted for office 365 accounts. “login” is the command name we can use using cy.login()in our test.
Cypress.Commands. add("login", (email, password, token, path) => {
  const args = { email, password, token }
  • Visit the application URL
cy.visit(Cypress.config('apiLoginURL')) 
  cy.on('uncaught:exception', (err, runnable) => {
    return false
  })
  cy.wait(7000)
  • Here we have to click on the button which navigates us to the office 365 pages where we have to authenticate the user. This landed us on the office365 SSO page. 
cy.get('.microsoft').click()
  • The new feature for Cypress 10 is cy.origin which helps us navigate to multi-domain in the same test. Here we will pass the login URL for office 365.
 cy.origin('https://login.microsoftonline.com', { args }, ({ email, password, token }) => {
    cy.wait(7000)
    cy.get('body').then(body => {
      if (body.find('#otherTileText').length > 0) {
        cy.contains('Use another account').click()
  • Passing the Email address for office 365
cy.get('#i0116').type(email)
      }
      else {
        cy.get('#i0116').type(email)
      }  
    cy.get('#idSIButton9').click()
    cy.wait(3000)
  • Passing password for office 365
cy.get('#i0118').type(password)
    cy.contains('Sign in').click()
    cy.get('div.tile:nth-child(1) > div:nth-child(1) > div:nth-child(1) > div:nth-child(2)').click()
  • Now we have to pass the secret key which we have extracted in the above steps and pass it to the OTP-generate task. This step is responsible for generating the secret.
 cy.task("generateOTP", token).then(token => {
      cy.get("#idTxtBx_SAOTCC_OTC").type(token);
      cy.get('#idSubmit_SAOTCC_Continue').click()
      cy.wait(3000)
    })

For any exception, we are having the below block

 cy.on('uncaught:exception', (err, runnable) => {
      return false
    })
        cy.get('#idBtn_Back').click()
        cy.wait(16000)  
        })              
}) 
})
  • Now we have to use this custom command in our test. Generally, we have to log in each time before the actual test. So we can use Cypress hooks ‘before’ and ‘before each’ hook.

Let’s see the code

Create a file and name it ‘beforeafter.js’ inside the Cypress folder. And paste the below Code

before(() => {

Here, we are creating the session

  cy.session('1', () =>{

This is a custom command we are calling in the command.js file. It passes all required parameters like email, password, and Secret key.

cy.login(Cypress.env("email"),Cypress.env("password"),Cypress.env('secret'),Cypress.env('file'))
  })   
  })
beforeEach(() => {

  Here we are restoring the above session which will help us to authenticate the user and log in quickly to the application.

cy.session('1')
cy.wait(5000)
cy.visit(Cypress.config('apiLoginURL'))
cy.get('.microsoft').click()
cy.wait(15000) 
})

Usage in test

Cypress/Support/Command.js

Cypress.Commands.add("login", (email, password, token, path) => { 
  const args = { email, password, token }
  cy.visit(Cypress.config('apiLoginURL'))
  cy.on('uncaught:exception', (err, runnable) => {
    return false
  })
  cy.wait(7000)
  cy.get('.microsoft').click() 
  cy.origin('https://login.microsoftonline.com', { args }, ({ email, password, token }) => {
    cy.wait(7000)
    cy.get('body').then(body => {
      if (body.find('#otherTileText').length > 0) {
        cy.contains('Use another account').click()
        cy.get('#i0116').type(email)
      }
      else {
        cy.get('#i0116').type(email)
      }
    cy.get('#idSIButton9').click()
    cy.wait(3000)
    cy.get('#i0118').type(password)
    cy.contains('Sign in').click()
    cy.get('div.tile:nth-child(1) > div:nth-child(1) > div:nth-child(1) > div:nth-child(2)').click()
    cy.task("generateOTP", token).then(token => {
      cy.get("#idTxtBx_SAOTCC_OTC").type(token);
      cy.get('#idSubmit_SAOTCC_Continue').click()
      cy.wait(3000)
    })
    cy.on('uncaught:exception', (err, runnable) => {
      return false
    })  
        cy.get('#idBtn_Back').click()
        cy.wait(16000)      
        })            
}) 
})

Usage in test

BeforeAfter.js file

before(() => {
  cy.session('1', () =>{
    cy.login(Cypress.env("email"),Cypress.env("password"),Cypress.env('secret'),Cypress.env('file'))
  })
  })
Before(() => {
  cy.session('1')
cy.wait(5000)
cy.visit(Cypress.config('apiLoginURL'))
cy.get('.microsoft').click()
cy.wait(15000)
})

Conclusion:

We are successfully able to automate login to the application through SSO and automate MFA and reduce the login time using a session in Cypress. Here is a link to another good read around the same topic.

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

How to do web scraping/crawling using Python with Selenium

How to do web scraping/crawling using Python with Selenium

Have you ever wondered how online shopping sites such as Amazon, Flipkart, and Meesho suggest or recommend us products depending on our search or browsing history, how they do? This is because their server indexes all the information in their records so they can return the most relevant search-based results. Web crawlers use to handle this process.

Data is becoming the key to growth for any business over the past decade most successful organizations used data-driven decision-making.

with 5 billion users creating billions of data points per second. They get data primarily for price and brand monitoring, price comparison, and big data analysis that serve their decision-making process and business strategy

Web scraping/ crawling is used to find meaningful insights (Data) that will help in making decisions for business growth. Let’s see how we can achieve this.

Web scraping is used to gather a large amount of data from Websites. Doing such a thing manually is very difficult to manage because data available on the web is in an unstructured manner with the help of web scraping we can avoid this. Scraping stores data in a structured manner.

Example – Python web scraping/crawling for Flipkart

Prerequisites – We need the following lib to achieve the scraping of Flipkart, so to install these packages on your system, simply open cmd and run the following commands.

1.    Pip install python 3+

2.    Pip install selenium

3.    Pip install requests

4.    Pip install lxml

Once we install all required lib then we are good to go. Now we need to add request headers to scrap the information from the web. To find request headers on the web page follow the steps given below.

Step1:

Open the URL of the webpage you want to scrap/crawl and search for the product name in the search bar you want the information about, products list is displayed on the page, and then click on any product and right-click on the page and click on “inspect”.

Step2:

Now the Html format page is open then select the “Network” option, under this click on the first checkbox it will show all requests and response headers. Just copy the request headers that we need for scraping here.

Step 3:-

Create a python file (file name with .py extension) and import all required libraries which we are going to use.

Here create a file with name >python_scrapy_demo.py

import requests

from lxml import html

from csv import DictWriter

headers={‘Accept’: ‘text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9’,

‘Accept-Encoding’: ‘gzip, deflate, br’,

‘Accept-Language’: ‘en-US,en;q=0.9,mr;q=0.8’,

‘Cache-Control’: ‘max-age=0’,

‘Connection’: ‘keep-alive’,

‘Cookie’: ‘T=TI164041787357700171479106209992677828199995896121444018506202609225; _pxvid=9615f9eb-6555-11ec-a0e5-544468794e4b; Network-Type=4g; pxcts=e13bea52-9c71-11ec-8fbe-4e794558716a; _pxff_tm=1; AMCVS_17EB401053DAF4840A490D4C%40AdobeOrg=1; AMCV_17EB401053DAF4840A490D4C%40AdobeOrg=-227196251%7CMCIDTS%7C19057%7CMCMID%7C60020900103419608715489104597694502461%7CMCAID%7CNONE%7CMCOPTOUT-1646484547s%7CNONE%7CMCAAMLH-1647082147%7C3%7CMCAAMB-1647082147%7Cj8Odv6LonN4r3an7LhD3WZrU1bUpAkFkkiY1ncBR96t2PTI; _px3=517dd86b669bed026967b6bdfbfac15a6893b3fb6a0a48639f8c8cac65b3cd64:OFKVhuX/QOYMMgqjXTNst5364SHIk+eTiaOVpjTfYKc6cnY+68dfTvg1NUCBE2W7jjH0hr7tgdk6UkBvsJVm9A==:1000:rga8uP2RMWp7ee1XTv8PVYgqr/ZlUn4jscKqdAKTIK9OFsmlF4QbPjfaDpAcMZn18Eip7z8FZsgO3j/KJ5x3m7BeObZLpMhgigTALVggsTCobVWml0DqL55ZTywnb5ezOslK6Q9axT+/y3CK7meTirkm9bumQWlOwMSMinGilSmpFCek9gBrinbeKWgdDCzFIKhH9ZOdRDiYGKa0DUOu7w==; SN=VI1A3BE7DC80484037A949D48CB6847E12.TOKB37A0AFBA76F46BB84B8BC39EEE0C132.1646477414.LI; s_sq=flipkart-prd%3D%2526pid%253Dwww.flipkart.com%25253A%2526pidt%253D1%2526oid%253Dhttps%25253A%25252F%25252Fwww.flipkart.com%25252Fsearch%25253Fq%25253Diphone%252526sid%25253Dtyy%2525252C4io%252526as%25253Don%252526as-show%25253Don%252526otracker%25253DAS_QueryStore_Organ%2526ot%253DA; S=d1t13Pz8VPxZJPxkMPwA/GT8/P8fOp+2+MT5EGsfvlEGAzgqQGy0f0O82o91FZOXzCPWn/Wqqo3+892JiBWn5oEFyQg==; qH=0b3f45b266a97d70’,

‘Host’: ‘www.flipkart.com’,

‘Referrer’: ‘https://www.google.com/’,

‘sec-ch-ua’: ‘” Not A;Brand”;v=”99″, “Chromium”;v=”99″, “Google Chrome”;v=”99″‘,

‘sec-ch-ua-mobile’: ‘?0’,

‘sec-ch-ua-platform’: “Windows”,

‘Sec-Fetch-Dest’: ‘document’,

‘Sec-Fetch-Mode’: ‘navigate’,

‘Sec-Fetch-Site’: ‘same-origin’,

‘Sec-Fetch-User’: ‘?1’,

‘Upgrade-Insecure-Requests’: ‘1’,

‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36’ }

#write method to save html page data in the file

def save_html_page(page_data): 

with open(‘flipkart_page.html’,’w+’,encoding=’utf-8′) as fl:

   fl.write(page_data)

#write method to save the data in the csv file

def data_save_csv(dt):

    headings={‘product_name’,’product_price’}

with open(‘flipkartdata.csv’,’a+’,encoding=’utf-8′) as file:

        writer=DictWriter(file,fieldnames=headings)

        writer.writeheader()

        writer.writerow(dt)

     file.close()

In the above code, we are saving html page and writing data into a file, and then we save that data into csv file. Here we write a method for saving html page we use the file open() method to open the file and we use “w+”,encoding=’utf-8”  to write data into Unicode transformation. For extracting data (i.e here we extract product_name and product_price) follow the methods given below. We can extract the different types of data by using this code here just need to add xpath of what type of product description we need to extract and it will return the data. 

def crawling_data():

response=requests.get(url=’https://www.flipkart.com/search?q=iphone&otracker=search&otracker1=search&marketplace=FLIPKART&as-show=on&as=off’,headers=headers,timeout=30)

# print(response.text)

save_html_page(page_data=response.text)

if response.status_code==200:

  tree=html.fromstring(response.text)     

        product_name=tree.xpath(‘//div[@class=”_3pLy-c row”]/div[@class=”col col-7-12″]/div[@class=”_4rR01T”]/text()’)                                

        prod_price=tree.xpath(‘//div[@class=”col col-5-12 nlI3QM”]/div[@class=”_3tbKJL”]/div[@class=”_25b18c”]/div[@class=”_30jeq3 _1_WHN1″]/text()’)

        all_data=list(zip(product_name,prod_price))

     # print(all_data)

     product={}

     for item in all_data:

            product[‘product_name’]=item[0]

            product[‘product_price’]=item[1].replace(‘₹’,”) # regex

          print(product)

            data_save_csv(dt=product)

crawling_data()

Conclusion

We live in a world where technology continues to develop, particularly in the computer industry. The current market scenario and client demands change every second. Hence to satisfy customer needs and business growth simultaneously we need to make changes in business and it can be achieved using web scraping/crawling.

Read more blogs here

Using Visual Studio Code for Behave BDD tests in Python

Using Visual Studio Code for Behave BDD tests in Python

Most of us use PyCharm to automate the BDD tests using Behave using Python, however, it adds to the cost of test automation. The community version is also available for free, but we can’t run behave files through it. Visual Studio Code also supports Python. However, this blog explains how to use Visual Studio Code for Python + Behave BDD tests for FREE. PyCharm and VS Code are both excellent tools for writing Python code.

PyCharm Community edition and Visual Studio Code (VSCode) are both capable integrated development environments for Python coding. To conduct this evaluation, I chose the most frequently used IDE feature and compared the experience of PyCharm and VSCode.

Let’s see how can we use VSCode for “Python behave” Automation:

First, you should make sure that you have installed the Python extension. I recommend installing it because it will allow you to install libraries and run code. To run Python and Python behave in Visual Studio Code (VSCode), visit the Visual Studio Code Marketplace to get all the extensions you’ll need.

The following three extensions must be installed before proceeding to Python:-
  • Gherkin- for creating feature files
  • Pylance: This will install all libraries which are required to run Python
  • Python extension for VSCode
All of these extensions are available in the VSCode Marketplace, and you can install them manually.
  • Firstly, we have to create a launch.json file. From the “Run and Debug” option & this file can be generated.·      
  • Go to the “Run and Debug” option, where you will see “Create a launch.json file,” and put the below code into that file.

For reference, visit: https://go.microsoft.com/fwlink/?linkid=830387

{
  "version": "0.2.0",
  "configurations": [
{"name":"Python:Current File",  // You can change this name as per your convenient
"type":"python",
"request":"launch",
"program":"${file}",
"console":"integratedTerminal",
"justMyCode":true
},
 {
    "version": "0.2.0",
    "configurations": [
        {"name":"Python: Current File","type":"python","request":"launch","program":"${file}","console":"integratedTerminal","justMyCode":true},
        {
            "name": "Python: Behave current file",
            "type": "python",
            "request": "launch",
            "module": "behave",
            "console": "integratedTerminal",
            "env": {
                "BASE_DIR": "Your repository location",
                   },
            "args":[
                "--no-capture",
                "--no-capture-stderr",
                "${file}"
            ],
        }
    ]
}

With this code, you will be able to create a “launch.json” file that will aid in running Python behavior in Visual Studio Code. As soon as you are done with the “launch.json” file, you need to add some libraries to the “settings.json” file, which will help you run the code through the command line. Open a settings JSON file by pressing (ctrl + shift + p) and selecting “Open Settings.” JSON is an option.

Add the below code to the “Settings.json” file. The code below will assist users in integrating with GitHub and running files via the command line.

"terminal.external.windowsExec":"C:\\Program Files\\Git\bin\\bash.exe",
    "terminal.integrated.shell.windows":"C:\\ProgramFiles\\Git\bin\\bash.exe",
    "python.pythonPath":"D:\\testing-native\\venv",    

The final line of code, “python.pythonpath,” will show the virtual environment path. For instructions on how to set up a virtual environment for this, see https://code.visualstudio.com/docs/python/environments Now, the user can go to the “feature file” that he/she wanted to run by selecting “Run” from the “Run and Debug” option.

Cloud Environment:

To automate an application in a cloud environment like (BrowserStack/SauceLabs), add the following code to the “Settings.json” file. Users will be able to run code in a cloud environment. Execution mode determines which cloud environment the user wishes to automate the application in, whether it is BrowserStack or SauceLabs. You can run your tests on the cloud environment of your choice by using the username and access key provided.  

	"executionMode":"Browserstack/Saucelabs",
        "userName":"Your username Key",
        "accessKey":"Your acess key"
 Navigate to Specific Function or Method.

We’d all like to be able to navigate directly to that specific function or method from the feature file step, as we can in PyCharm (ctrl+click). This can be achieved by including the following code in Settings.json in VSCode: Your work in VS code will be faster and more flexible.  

"cucumberautocomplete.steps": [
        "Features/steps/*.py"
                              ],
    "cucumberautocomplete.syncfeatures": "Features/*feature",
Conclusion:-

Pycharm is used to run a Python behave file, but many of us are aware that it’s not free, so we’ve found a solution with Visual Studio Code that will help people save money and run Python behave freely on the VSCode IDE.

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