skip to Main Content

I’m trying to merge bunch of tests that have same actions and checks using parametrized testing, but keep getting errors. I’m new to Cypress and JS in general, coming from .net background. Any help would be appreciated.

My fixture looks something like this:

{
  "username": "username",
  "password": "password",
  "inputErrorMessageText": "Invalid username or password.",
  "homePageWelcomeText": "Welcome, bla bla bla",
  "testCases": [
    {
      "description": "blank username and password",
      "username": "",
      "password": ""
    },
    {
      "description": "blank password",
      "username": "username",
      "password": ""
    }
  ]
}

I’ve tried both Cypress.each and data.testCases.forEach:

describe("Tests for login page", () => {
    let loginPage;
    let homePage;
    let data;

    before(() => {
        cy.fixture("login_data").then((fixtureData) => {
            data = fixtureData;
            cy.wrap(fixtureData).should("have.property", "testCases");
        });
    });

    beforeEach(() => {
        loginPage = new LoginPage();
        homePage = new HomePage();
        cy.visit("/");
    });

    Cypress.each(data.testCases, (testCase) => {
        it(`Invalid username or password error appears when attempting login with ${testCase.description}`, () => {
            loginPage.login(testCase.username, testCase.password);
            loginPage.verifyErrorMessage(data.inputErrorMessageText);
        });
    });

    it("Successful login with valid username and password", () => {
        loginPage.login(data.username, data.password);
        homePage.verifyProfileDropDownExists();
    });

    it("Welcome text is displayed after successful log in", () => {
        loginPage.login(data.username, data.password);
        homePage.verifyWelcomeText(data.homePageWelcomeText);
    });
    data.testCases.forEach((testCase) => {
        it(`Invalid username or password error appears when attempting login with ${testCase.description}`, function () {
            loginPage.login(testCase.username, testCase.password);
            loginPage.verifyErrorMessage(data.inputErrorMessageText);
        });
    });

Keep getting the following error:

TypeError: The following error originated from your test code, not from Cypress.
> Cannot read properties of undefined (reading ‘testCases’)

2

Answers


  1. Issues

    1. (This is the main culprit) Directly using data.testCases.forEach() is not working, as Cypress (Mocha, but splitting hairs here) needs to know what tests to run before the tests actually start running. In this case, since data.testCases won’t have a value when Cypress starts gathering the tests to run (as the data is set in the before() block), it’s running into an error when data.testCases is undefined.
    2. I don’t think Cypress.each is a function. There is Cypress._.each() (using Cypress Lodash) and cy.each() (which isn’t what you want here).

    Solution

    Import the fixture directly, instead of loading it via cy.fixture(), which should grant you access to the data.testCases variable prior to Cypress discovering what tests to run. Then you should be able to have multiple tests run, either via data.testCases.forEach() or Cypress._.each().

    import data from '../path/to/data.json';
    
    describe("Tests for login page", () => {
      ...
      Cypress._.each(data.testCases, (testCase) => {
        it(`Invalid username or password error appears when attempting login with ${testCase.description}`, () => {
                loginPage.login(testCase.username, testCase.password);
                loginPage.verifyErrorMessage(data.inputErrorMessageText);
            });
      });
    });
    

    You can still run your data validation that data has property of testCases, without the cy.fixture().

    Login or Signup to reply.
  2. Please see the Cypress recipe fundamentals__dynamic-tests/cypress/e2e
    /fixture-spec.cy.js
    .

    /// <reference types="cypress" />
    describe('generated from fixture', () => {
      // We cannot load JSON file using "cy.fixture"
      // because it means the test is already running.
      // Same with using "before" hook - new tests cannot be created from "before" hook.
      // Instead we need to load JSON file using "require" at the start time
      // and generate tests.
      const colors = require('../fixtures/colors')
      const rainbow = ['red', 'orange', 'yellow', 'green', 'blue', 'violet']
    
      colors.forEach((color) => {
        it(`🌈 has color ${color}`, () => {
          cy.wrap(color).should('be.oneOf', rainbow)
        })
      })
    })
    

    While a fixture is technically fine, I would suggest putting the data at the top of the test.

    This is much more readable, so you can refactor and add cases easily. Plus you can include the expected error in the same place.

    const testCases = [
        {
          "description": "blank username and password",
          "username": "",
          "password": "",
          "error": "user name must be filled in"
        },
        {
          "description": "blank password",
          "username": "username",
          "password": "",
          "error": "password must be filled in"
        },
        {
          "description": "invalid username",
          "username": "not-a-valid-user",
          "password": "pword",
          "error": "username or password is incorrect, please try again"
        }
      ]
    
    testcases.forEach((case) => {
      
      it(case.description, () => {
        loginPage.login(login.username, login.password);
        loginPage.verifyErrorMessage(case.error);
      })
    })
    ``
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search