Use Cypress to retrieve a token from an API, store it in local storage, and then use it in the header of another API request. Once the token is successfully incorporated, capture and return the

There is an API (referred to as getToken) that generates a token in its response body. This token is then called and stored in the header of another API (known as returnBody). It seems logical to utilize localStorage for the getToken API since the token can be reused for multiple APIs. However, there are uncertainties about using localStorage when it comes to returning or displaying the response body of subsequent APIs like returnBody. In the function/command of the API, the response body is logged. Yet, when invoked through the test file, it yields null. Sample code provided below:

commands.js:

Cypress.Commands.add('getToken', () => { //API for token generation
    cy.request({
        method: 'POST',
        url: 'https://someAPItoGenerateToken',
        form: true, //set to application/x-www-form-urlencoded
        body: {
            grant_type: 'credentials',
            scope: 'all-apis'
        },
        auth: {
            username: Cypress.env('api_username'),
            password: Cypress.env('api_password')
        }
    })
        .its('body')
        .then(bearerToken => {
            cy.setLocalStorage('bearerToken', JSON.stringify(bearerToken))
            cy.log('Token generated: ' + bearerToken.token)
            }
        )
})

Cypress.Commands.add('returnBody', (url, token) => { //API to retrieve certain values
    return cy.request({
        method: 'GET',
        url: url,
        auth: {
            bearer: token
        }
    })
        .then((response) => {
            // Stringify the JSON body.
            let body = JSON.stringify(response.body)
            cy.log(body)
        })
})

test file:

describe('Return value of 2nd API', ()=> {
    before(() => {
        cy.getToken() //Execute this once to generate token for the entire test suite
        cy.saveLocalStorage()
    })

    beforeEach(() => {
        cy.restoreLocalStorage()
    })

    it('Return value of 2nd API', () => {
        cy.getLocalStorage('bearerToken').should('exist')
        cy.getLocalStorage('bearerToken').then(bearerToken => {
            const tokenJSON = JSON.parse(bearerToken)
            const url = 'https://someAPItoReturnJSONbody'
            cy.returnBody(url, tokenJSON.token).then((returned_value) => {
                cy.log(returned_value)
            })
        })

    })
})

The body returned by the returnBody command consists of the JSON response. Nonetheless, the returned_value from the test file shows null.

Answer №1

It has been noted in this particular issue: "It is not possible to return a promise from a third-party source within a custom command as it disrupts the chain of cypress commands. This occurs because the .then methods do not align."

Instead, simply retrieve the request body like so:

Cypress.Commands.add('returnBody', (url, token) => {
  return cy.request({ /* options */ })
    .its("body");
});

Afterwards, you can use it in your test like this:

it("should retrieve the foo value", () => {
  cy.returnBody(url, token).then(returned_value => {
    cy.log(returned_value);
    expect(returned_value).to.deep.equal("foo-value");
  })
})

Answer №2

To retrieve the response body in your Cypress test, make sure to include the following code snippet in your custom command:

Cypress.Commands.add('returnBody', (url, token) => {
  return cy.request({ /* options */ })
    .then(response => {
      let body = JSON.stringify(response.body);
      Cypress.log(body);
      return body; // Remember to add this line
    });
});

Answer №3

One approach could involve storing the token on the cypress side using fixtures.

fixture.json:

{"bearerToken":""
.
.
.}

commands.js:

cy.fixture('testData.json').as('testData')
.
.
.then(bearerToken => {
            this.testData.bearerToken = JSON.stringify(bearerToken)
            cy.log('Token generated: ' + bearerToken.token)
            }
        )

test.js

describe('Obtain output from 2nd API', ()=> {
    before(() => {
        cy.getToken() //Execute this once to generate token for the whole test suite
    })

    it('Obtain output from 2nd API', () => {
        cy.fixture('testData.json').as('testData')
        .then(testData => {
            const tokenJSON = JSON.parse(testData.bearerToken)
            const url = 'https://someAPItoReturnJSONbody'
            cy.returnBody(url, tokenJSON.token).then((output) => {
                cy.log(output)
            })
        })

    })
})

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Updating React props using useState?

Below is a component that aims to enable users to update the opening times of a store. The original opening times are passed as a prop, and state is created using these props for initial state. The goal is to use the new state for submitting changes, while ...

Tips on activating the CSS style while typing using the onChange event in React

Is it possible to dynamically adjust the width of an input as we type in React? Currently, my input has a default width of 1ch. I would like it to increase or decrease based on the number of characters entered, so that the percentage sign stays at the end ...

Leveraging dependency injection in Angular 2+ with pre-loaded models

I desire the ability to create an instance of a model using a constructor while also providing injected services to that model. To clarify, I envision something like this: var book = new Book({ id: 5 }); // creates instance, sets id = 5 book.makeHttpCa ...

`Developing data-driven applications with MVC3 using object binding`

Currently, I am facing a challenge with my project that involves using Entity Framework. To provide context on the database model: public class AssetType{ public ICollection<Field> Fields { get; set; } } public class Field{ public int Id {g ...

I am unable to extract the information from a JSON formatted string

Looking to extract some option data from a JSON encoded string, this is the current code: <?php $json = json_decode('{"1":"{\"QID\":\"1\",\"Type\":\"MC\",\"Question\":\"Question here\",&b ...

What is the conventional method for incorporating style elements into Vue.js components?

Imagine I have a Vue component with data retrieved from an external API, containing information about various books: data: () => ({ books: [ {name: 'The Voyage of the Beagle', author: 'Charles Darwin'}, {name: &ap ...

Unable to open modals in Bootstrap using jQuery script: modal not popping up

My attempt to create functionality for two buttons and two modals - reserve a campsite (id="reserveButton" should open id="reserveModal") and Log in (id="loginButton" should open id="loginModal") is not working. I ha ...

Adjust the height of the list when including or excluding floated list items that are not in the final row

Within my ul are li elements with varying widths that wrap around inside a container into multiple rows. When removing an li element from the ul, I want the container's height to adjust dynamically in case a row is eliminated. If the removal happens ...

What is the best way to extract integer values from a JSON file using Java?

I am looking to extract the "ids" and store them in an arraylist. This information is located in the config.json file below: { "users":[ {"user id":1,"user name":"A","user type":"bot1", &quo ...

The ASP.NET MVC controller falling behind due to a delay in conversion process

Currently, I am transferring an array of DTOs from a local application to ASP.NET MVC. This process is being tested on my personal machine. The local application, being a Web Forms system, sends the data through a service without utilizing JsonResult. Al ...

Tips on obtaining a Firebase ID

Does anyone have a solution for retrieving the unique id from Firebase? I've attempted using name(), name, key, and key() without any success. Although I can view the data, I'm struggling to find a way to retrieve the id. This information is cru ...

Include a numerical suffix to the file name of an image if the corresponding value is already present within the database (using Codeigniter

When users upload images to the 'gambar' folder directory, I want to save the image path and data to a database table. The code below dynamically adds a counter to the file name if it already exists (e.g. my-path.jpg, my-path.png, my-path1.jpg) ...

What folder layout is best suited for organizing Protractor end-to-end test cases?

Is it best practice to maintain the folder structure for e2e test cases in Protractor identical to that of the application? ...

"Transforming a Python list of numbers into a JSON object: A step-by-step

I need help transforming a python list of numbers into a JSON object. input: The input should be a single number, for example 22 Expected result: { "budget" : 22 } ...

Update the referenced lists in ng-admin

I'm currently working with ng-admin alongside a restful API, I have various referenced lists that undergo frequent updates from the server side. Is there a method to automatically refresh these referenced lists every 5 seconds using ng-admin? EDIT: ...

Alter the properties based on the size of the window

I am working with React-Spring and I need to adjust the offset of a component when the window size changes. I attempted the following solution, but it is not functioning correctly and requires me to refresh the browser each time. <ParallaxLayer ...

Having issues with socket.io connectivity on my Node server

I am setting up my node server to update all connected clients with real-time information. However, when I run the code provided below, the io.sockets.on('connection') callback keeps firing constantly, flooding the console with the message Client ...

Issue with Android app for user registration and login

I have developed an application that is designed to store new user information in a database (mySQL) for login purposes. However, I am encountering an issue where pressing the login or register button results in an error stating "can't turn java strin ...

Revise the line graph

Currently, I am utilizing dimple js and have a line chart code. However, there seems to be an issue with the event I set up - whenever a button is clicked, the chart should redraw using chart.draw(), but this function doesn't seem to work. Any insight ...

Interacting with the header component within the renderHeader property of the MUI Data Grid Pro will update the sortModel

Currently, I am utilizing the Material UI DataGridPro component to construct a React Js application. I am interested in developing a customized filtering feature. In the image below, you can see a red box representing an IconButton for the filtering view ...