Tips for optimizing promise code in cypress

import SignInPage from '../pages/signInPage.cy'
import ValidateAccountPage from '../pages/validateAccountPage.cy'
import DeptPage from '../pages/deptPage.cy'
import HomePage from '../pages/homePage.cy'
import DeleteAccount from '../pages/deleteAccount.cy'

type NewAccountCredentials = { username: string, password: string, vcode: number, uid: string };

const URLS = {
    remote: {
        client: "http://54.39.177.218:8080",
        server: "http://54.39.177.218:3020/api/v2"
    }
}

const urlTarget = "remote";

const clientUrl = URLS[urlTarget].client;
const serverUrl = URLS[urlTarget].server;

const signIn = new SignInPage()
const validateAccount = new ValidateAccountPage()
const deptPage = new DeptPage()
const homePage = new HomePage()
const deleteAccount = new DeleteAccount()

describe('Smoke test', () => {

    let value
    let credentials

    beforeEach(async () => {

        cy.fixture('addDebtDetails').then(function (data) {
            value = data
        })

        cy.viewport(390, 844);

        // create a new non-validated account in the back-end
        credentials = await new Promise<NewAccountCredentials>((resolve, reject) => {
            cy.request(serverUrl + '/test-accounts/free').then(response => {
                expect(response.body).to.have.property("username");
                resolve(response.body);
            })
        });

        // load the app - should default to the sign-in page
        cy.visit(clientUrl, {
            onBeforeLoad: (win) => {
                win.sessionStorage.clear();
                win.localStorage.clear();
            }
        });
    })

    it('verifying home page before debts have been added', async () => {
        // sign-in
        signIn.SignInMethod(credentials.username, credentials.password)

        // validate account
        validateAccount.validateAccountMethod(credentials.vcode.toString())

        // verify that we are on the home page and see the correct greeting and workspace name
        homePage.HomePageMethod()

        /* CLEANUP AFTER EACH TEST */
        deleteAccount.DeleteAccountMethod(credentials.password)

        // must always delete the created account even if any of the above testing fails
        await new Promise<void>((resolve, reject) => {
            cy.request("DELETE", `${serverUrl}/test-accounts/uid/${credentials.uid}`).then(response => {
                expect(response.status).to.be.equal(200);
                resolve();
            })
        });
    })

    it('verifying debt page after debt is added', async () => {
        // sign-in
        signIn.SignInMethod(credentials.username, credentials.password)

        // validate account
        validateAccount.validateAccountMethod(credentials.vcode.toString())
        cy.wait(2000)

        // verify that we are on the home page and see the correct greeting and workspace name
        deptPage.AddDeptMethod(value.nickName, value.currentBalance, value.annualPercentageRate, value.minimumPayment)
        deptPage.AddCalenderDetails(value.calenderYear, value.calenderMonth, value.calenderMonthAndDay)
        homePage.HomePageMethodAfterDebt()

        /* CLEANUP AFTER EACH TEST */
        deleteAccount.DeleteAccountMethod(credentials.password)

        // must always delete the created account even if any of the above testing fails
        await new Promise<void>((resolve, reject) => {
            cy.request("DELETE", `${serverUrl}/test-accounts/uid/${credentials.uid}`).then(response => {
                expect(response.status).to.be.equal(200);
                resolve();
            })
        });
    })

})

It seems like there is an issue with handling promises in your code. To delay requests using Cypress, you can use commands like 'cy.wait' or wrap the request in a promise as shown in the code. Make sure to handle timeouts properly to avoid errors.

Answer №1

Cypress will automatically wait for all commands within the beforeEach() block before executing the it() block, eliminating the need for Promises.

For added security, consider checking the "username" property at the beginning of each test:

expect(credentials).to.have.property('username');

The same principle applies to cleanup code - moving it to afterEach() removes the need for a Promise in that section.

Complete Test:

describe('Smoke test', () => {

  let value
  let credentials

  beforeEach(() => {
    cy.fixture('addDebtDetails')
      .then((data) => value = data)

    // create a new non-validated account on the backend
    cy.request(serverUrl + '/test-accounts/free')
      .then(response => {
        expect(response.body).to.have.property("username");
        credentials = response.body;
      })
    });

    // load the app - should default to the sign-in page
    cy.viewport(390, 844);
    cy.visit(clientUrl, {
      onBeforeLoad: (win) => {
        win.sessionStorage.clear();
        win.localStorage.clear();
      }
    });
  })

  afterEach(() => {
    /* CLEANUP AFTER EACH TEST */
    deleteAccount.DeleteAccountMethod(credentials.password)

    // always delete the created account even if tests fail
    cy.request("DELETE", `${serverUrl}/test-accounts/uid/${credentials.uid}`)
      .then(response => {
        expect(response.status).to.be.equal(200);
      })
  })

  it('verify home page before adding debts', () => {

    // ensure username property check passes
    expect(credentials).to.have.property('username');   

    // sign in
    signIn.SignInMethod(credentials.username, credentials.password)

    // validate account
    validateAccount.validateAccountMethod(credentials.vcode.toString())

    // verify on home page...
    homePage.HomePageMethod()

  })

  it('verify debt page after adding debt', () => {

    // ensure username property check passes
    expect(credentials).to.have.property('username');   

    // sign in
    signIn.SignInMethod(credentials.username, credentials.password)

    // validate account
    validateAccount.validateAccountMethod(credentials.vcode.toString())

    // add debt and calendar details
    deptPage.AddDeptMethod(value.nickName, value.currentBalance, value.annualPercentageRate, value.minimumPayment)
    deptPage.AddCalenderDetails(value.calenderYear, value.calenderMonth, value.calenderMonthAndDay)

    homePage.HomePageMethodAfterDebt()

  })
})

Answer №2

Since Cypress commands are inherently asynchronous, using a Promise is unnecessary in this case. Instead, there are various ways to store variables, with my personal preference being Cypress environment variables. You can find more information on this topic here.

...
beforeEach(() => {
  cy.request(serverUrl + '/test-accounts/free').then(response => {
     expect(response.body).to.have.property("username");
     Cypress.env('credentials', response.body);
  })
  cy.visit(clientUrl, {
     onBeforeLoad: (win) => {
       win.sessionStorage.clear();
       win.localStorage.clear();
     }
  });
});

In the code snippet above, you can access the stored credentials using Cypress.env('credentials')

Answer №3

In the package.json file, you have the ability to define the timeout for jest tests. "jest": { "testTimeout": 15000, }

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

What causes the distinction between resolve("../....") and resolve("foo")?

Because of various node versions and incompatible ABIs, I have to load a C++ addon relatively since they are located in different locations with different ABI versions. However, the issue I am facing is quite simple. Why do these two calls produce differe ...

Documentation in TypeScript with JSDoc and using the new Rest type syntax

Encountering an issue while integrating TypeScript into a large existing React/Redux application. To test things out, I decided to convert one of my React files to a .ts file. My approach involves using JSDoc to add types to the imported JS files in order ...

Detecting the rectangular boundary of rotated elements on a dynamically generated canvas or SVG using JavaScript (TypeScript)

I've been struggling with a particular issue for some time now. Currently, I'm developing a web application using TypeScript, React, and Google Maps. For the markers on the map, I aim to use custom images generated at runtime based on various pa ...

Struggling to find a solution for directing to the featured homes page without the content overlapping with my navbar and search component. Any assistance would be greatly

Looking for assistance with routing to the featured homes page without the content overlapping my navbar and search component. I simply want it to direct to a new URL without importing the components unless specifically needed. Check out this link I suspe ...

The TypeScript error TS2339 states that the property "firestore" does not exist in the Cartservice type in Angular

I have integrated angularefire into the angular.io 'take a look tutorial' (shopping cart) in order to utilize firebase firestore for products data and orders processing. I have managed to partially replace products.ts and shipping.json, as well a ...

Similar to [JsonPropertyName] in C#, but for TypeScript

Need help deserializing JSON response into a class defined in Angular. Let's use the example class below: export class ChatHubInfo { hubUrl: string = undefined! accessToken: string = undefined! } However, the JSON response is structured different ...

Having difficulty retrieving JSON data from a NodeJS server built with Typescript

My project involves using NodeJS + Express on the back end to send JSON data as a POST response to the front end through JQuery. I'm facing an issue where the message is not reaching the front end, which utilizes a JQuery AJAX call. It's puzzling ...

What is the best way to find the clinic that matches the chosen province?

Whenever I try to choose a province from the dropdown menu in order to view clinics located within that province, an error 'TypeError: termSearch.toLowerCase is not a function' pops up. This part of the code seems confusing to me and any kind of ...

Refresh a doughnut chart in real-time using NG2Charts

Currently, I am in the process of developing a macronutrient calculator as part of a project. The idea is to have a form where users can input values, and a corresponding doughnut chart will display with initial values set at 0. However, upon clicking the ...

Personalized pagination - React data table

I'm looking to create a unique pagination design using react-table that fits my specific requirements: Currently, the default pagination I'm using looks like this: https://i.sstatic.net/xf1sE.png But I want it to resemble this: https://i.ssta ...

Issue with npm resolution due to package requiring another third-party dependency

I'm encountering an issue with a requirement and I'm hoping for some assistance. I currently have a package called @unicoderns/orm that relies on mysql, which can be found at https://github.com/unicoderns/ORM Now I'm working on developing ...

`Cannot retrieve object`

this.deleteValue = { LanguageId : '', LanguageName : '', LongName : '', CreatedBy : '', UpdatedBy : '', CreatedDate : '', ...

Expanding the property of an established type to a nested type

Let's talk about titles. Well, maybe not this one. I tried to come up with a good title, but it didn't work out as planned. In my coding journey, I have created a cool interface called DefaultTheme: export interface DefaultTheme { colors: ...

What is the correct way to add properties to an interface in TypeScript?

I have experience with styled-components "themes" and how they work by defining custom theme properties for TypeScript autocompletion within styled components. The process involves extending the DefaultTheme interface with our custom theme properties like ...

The MUI Select component I am using is not showing the placeholder or label properties

I'm currently facing an issue with the Select component in my app. Despite using the placeholder="Text" and label={"Text"} props, I am not getting the desired outcome. When utilizing the placeholder prop, the Select appears to be ...

An array comprising multiple arrays containing strings

I need help creating a nested array of strings like the one shown below: let rules : type = [ ["N"] ["N", "N"] ["N", "N", "N"] ] I'm struggling to set the correct type for this array. Can you assist me with this? ...

Uploading files using Remix.run: Transforming a File object into a string during the action

I'm currently developing a Remix application that allows users to upload files through a form. I have a handler function for handling the form submission, which takes all the form data, including file attachments, and sends it to my action. The probl ...

Creating a String-Helper component using Angular and TypeScript

One issue I'm facing is that when using the german ü, ä, ö characters in HTML, they are showing up as unknown symbols. To properly display them, you can write ü as "&uuml ;" and ä as "&auml ;", and so on. However, my challenge is coming f ...

Moving cookies between requests within nodejs/protractor

I am utilizing the request library for making HTTP requests to the server (https://github.com/request/request). Unfortunately, I received a 400 response because there is some missing data in my request, possibly due to cookies not being included. This is ...

Angular - How to fix the issue of Async pipe not updating the View after AfterViewInit emits a new value

I have a straightforward component that contains a BehaviorSubject. Within my template, I utilize the async pipe to display the most recent value from the BehaviorSubject. When the value is emitted during the OnInit lifecycle hook, the view updates correc ...