cypress: When accessing multiple sessions with origin I get "cannot read properties of undefined reading 'message'" on azureAD with Chrome

Current behavior

I have a test that tries to login with different session_id (string, string[], object) and with the use of origin on each step, with the same login provider (Azure AD). When the tests are run on Chrome or Electron (headless/browser) after the 1st login/session for an approx 80% of the times the rest of the tests will fail (see attached error).

cannot read properties

When I run on firefox the same tests will have lower chance of failing (approx 10% -20%)

I couldnt manage to scope the reason that it fails but it could be either the security of chrome (it is disabled) or the cookies.

Another lead is that some times the failed step is showed that has no “url” during the call of the step when I check the snapshots of the stack trace

Desired behavior

No response

Test code to reproduce

-----Login helper commands ----------

cy.session(session as string | string[] | object, () => {
       loginWithAzureAD(username, password);
       cy.visit('/');
 });

export const loginWithAzureAD = (username: string, password: string): void => {
 cy.origin(
   'https://login.microsoftonline.com',
   { args: { username, password } },
   ({ username, password }) => {
     cy.visit('/');
     // Set email and wait
     cy.get('[type="email"]').should('be.visible').type(username);
     cy.get('[type="submit"]').click();
     //cy.wait(3000);
     // Validation that the email input and progress bar do not exist
     cy.get('[type="email"]', { timeout: 5000 }).should('not.exist');
     cy.get('[class=progress]', { timeout: 5000 }).should('not.exist');
     // Set password and wait
     cy.get('[type="password"]', { timeout: 5000 })
       .should('be.visible')
       .type(password);
     cy.get('[type="submit"]').click();
     //cy.wait(2000);
     // Validation that the password input does not exist
     cy.get('[type="password"]', { timeout: 5000 }).should('not.exist');
   }
 );
};

-------Spec ----------------------

describe('Test Azure AD Authentication with origin', () => {
  // beforeEach(function () {
  //   //In a real scenario here we place the cy.loginAzureADwithOrigin command
  //   //The login will cache the cookies and local storage
  // });

  it('Direct login with the exported cridentials', () => {
    cy.login('ad');
    cy.visit('/');
    cy.get('[data-testid="search-icon"]').should('exist');
  });

  it('Direct login with the exported cridentials and custom session id', () => {
    cy.login('ad', 'test_user');
    cy.visit('/');
    cy.get('[data-testid="search-icon"]').should('exist');
  });

  it('Custom login with credentials in array, and unique session id', () => {
    cy.login('ad', [Cypress.env('username'), Cypress.env('password')]);
    cy.visit('/');
    cy.get('[data-testid="search-icon"]').should('exist');
  });

  it('Custom login with credentials in object, and unique session id', () => {
    cy.login('ad', {
      username: Cypress.env('username'),
      password: Cypress.env('password'),
    });
    cy.visit('/');
    cy.get('[data-testid="search-icon"]').should('exist');
  });
});

Cypress Version

10.8.0

Node version

v14.17.0

Operating System

macOS 12.5.1

Debug Logs

No response

Other

No response

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 33 (12 by maintainers)

Most upvoted comments

Let me take another look at this and see if I can get further.

@jennifer-shehane I could be wrong (I don’t have time today to test it), but it seems that the error is not correctly caught due to these lines: https://github.com/cypress-io/cypress/blob/ede4a6fd601cb74b1fa4f71f722aa3a3bdcef772/packages/driver/src/cypress/cy.ts#L881-L886

which run before the uncaught:exception action should be triggered, at this line: https://github.com/cypress-io/cypress/blob/ede4a6fd601cb74b1fa4f71f722aa3a3bdcef772/packages/driver/src/cypress/cy.ts#L898

createUncaughtException is calling modifyErrMsg which itself assumes that err is an object where it can set a stack property and read/set a message property: https://github.com/cypress-io/cypress/blob/ede4a6fd601cb74b1fa4f71f722aa3a3bdcef772/packages/driver/src/cypress/error_utils.ts#L167-L177

In my opinion, the fix should be:

  • createUncaughtException should run err = makeErrFromErr(err) before calling modifyErrMsg
  • modify makeErrFromErr so it supports any JavaScript type, including undefined.
  • modify makeErrFromObj so it supports any JavaScript type, including undefined.

For the last 2 steps, I suggest adding this after the 2 isString checks:

if (typeof v !== "object" || !("message" in (v ?? {}))) {
  return new Error(`${err}`);  // Shows `[object Object]` for objects, find a better alternative.
}

Then, since err returned by createUncaughtException gets passed downstream to fail, the error should have a proper format everywhere, solving the various forms of this issue. But again I might be wrong, I don’t know Cypress internals at all.

I did look into this a bit yesterday. It’s not as simple of a fix as accepting Strings in this case, as it was on this line here:

https://github.com/cypress-io/cypress/blob/develop/packages/driver/src/cypress/error_utils.ts#L192

I can fix the message error by making a new Error if the obj is undefined on that line above, but the uncaught:exception handler still doesn’t register properly, where the test keeps failing.

You can throw a debugger after this line when running the above project through Cypress locally (Instructions here to watch) and see that the results are returning an empty array [] instead of ['false'] like it does for normal errors to indicate there was a handler that returned false.

https://github.com/cypress-io/cypress/blob/develop/packages/driver/src/cypress/cy.ts#L898

@BertrandBordage Thanks, I can reproduce.

Stack trace:

"TypeError: Cannot read properties of undefined (reading 'message')
    at makeErrFromObj (https://checkout.stripe.com/__cypress/runner/cypress_cross_origin_runner.js:91576:30)
    at errorFromProjectRejectionEvent (https://checkout.stripe.com/__cypress/runner/cypress_cross_origin_runner.js:91897:10)
    at Object.errorFromUncaughtEvent (https://checkout.stripe.com/__cypress/runner/cypress_cross_origin_runner.js:91902:65)
    at https://checkout.stripe.com/__cypress/runner/cypress_cross_origin_runner.js:197375:72"

The issue happens when the application throws undefined instead of a valid error or object (in @Helveg’s case and my case, Stripe is throwing that undefined exception for no good reason).

And Cypress does not seem to be expecting an undefined error. As a developer, we unfortunately have no control over this issue: Cypress fails to parse undefined, meaning that Cypress.on('uncaught:exception', …) is not even called. So our test fails, whether we set an uncaught:exception listener or not.

EDIT: I contacted the Stripe support to report the problem from their side, but even if it ends up being resolved, I think Cypress should handle cases like this more gracefully.

Same issue: cross-origin call that was working fine to Stripe Checkout with experimentalModifyObstructiveThirdPartyCode turned on suddenly gives this error.

Started noticing this error in a cy.origin in our test cases. It started happening without changes to the test or code. We did upgrade Cypress from 13.6.8 to 13.7.2, but downgrading didn’t fix it. While we got this mostly happening locally (100% of the time now), we also got 1 failure of it in Cypress Cloud. I realize the issue has been closed due to challenges in reproducing, so happy to share the Cypress Cloud execution link with Cypress support if it helps investigating this issue.

@jennifer-shehane I managed to reproduce this error! Cannot read properties of undefined (reading 'message')

I could only get it with Stripe, so I isolated it with the demo checkout page from Stripe. In case the generated Stripe URL I used is not going to work in the future:

  • Go to https://checkout.stripe.dev/preview
  • Inspect the code to copy the full iframe URL (including its anchor, #…)
  • Paste the iframe URL in the cy.visit of the snippet below.
  • Run the snippet, with or without experimentalModifyObstructiveThirdPartyCode. In both cases it should fail.
Cypress.on("uncaught:exception", (err, runnable) => {
  // returning false here prevents Cypress from
  // failing the test
  return false
});

it.only("Should catch the exception", () => {
  cy.visit("https://www.cypress.io/");
  cy.origin("checkout.stripe.com", () => {
    cy.visit("https://checkout.stripe.com/c/pay/cs_test_b1ME8Ug7h3E2qvMqgXJKiR0fQV0F5lTmRujFdpktg37k3v4cCocLmXCTO0?demoWallet=applePay&demoPolicies=false#fidkdWxOYHwnPyd1blpxYHZxWjA0TUM1Yl9GT1c0a25sZjdSa2ppakZgQzdxVz1qYk9pcUBnNTc9Z11kVnc9b0F%2FREgxfE5oQ31Dd2dGME9sQVx2Tm1wc3RyRGhPZjIwTzRLYmd3TnJDSjJMNTVJMUBtbWNMQycpJ2N3amhWYHdzYHcnP3F3cGApJ2lkfGpwcVF8dWAnPydocGlxbFpscWBoJyknYGtkZ2lgVWlkZmBtamlhYHd2Jz9xd3BgeCUl");
    cy.location("host").should("equal", "checkout.stripe.com");
    cy.log("Success!");
  });
});

image

Moving the uncaught:exception listener inside cy.origin or disabling it has no effect on the error.

For info, I got a reply from the Stripe support, they don’t plan on fixing this error but are interested in seeing Cypress resolve this side of the problem 🤦