Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cypress Promise behavior differs between local run and CI run #2651

Closed
SaladFork opened this issue Oct 24, 2018 · 4 comments
Closed

Cypress Promise behavior differs between local run and CI run #2651

SaladFork opened this issue Oct 24, 2018 · 4 comments

Comments

@SaladFork
Copy link

Is this a Feature or Bug?

Bug

Current behavior:

  • In the browser: Promise chain works as expected
  • In Cypress open (local): Promise chain works as expected
  • In Cypress run (CI): Promise finally not defined

Desired behavior:

Promises behave consistently between environments and a Promise's finally method is defined and supported in cypress run.

Steps to reproduce:

I created a simple example page for reproduction:

// package.json
{
  "name": "cypress-finally-example",
  "private": true,
  "devDependencies": {
    "cypress": "^3.1.0",
    "serve": "^10.0.2"
  }
}
<!-- index.html -->
<html>
<head>
  <title>Cypress Finally Example</title>
</head>
<body>

  <div id="then"></div>
  <div id="catch"></div>
  <div id="finally"></div>

  <script type="text/javascript">
    let promise = Promise.resolve(42)

    promise
      .then((value)  => updateDiv('then', `then: ${value}`))
      .catch((value) => updateDiv('catch', `catch: ${value}`))
      .finally(()    => updateDiv('finally', 'finally'))

    function updateDiv(id, text) {
      document.getElementById(id).textContent = text;
    }
  </script>

</body>
</html>
// cypress/integration/promise.spec.js
describe('Cypress Promise behavior', () => {
  it('works', () => {
    cy.visit('localhost:5000');

    cy.get('#then').should('have.text', 'then: 42');
    cy.get('#catch').should('have.text', '');
    cy.get('#finally').should('have.text', 'finally');
  });
});

To reproduce:

$ yarn run serve   # start server to serve index.html
$ yarn run cypress open   # open Cypress and click on the promise spec

Observe it works as expected (and mirrors browser behavior):
All tests pass

Use the runner (assuming server still running):

$ yarn run cypress run
# ...
  0 passing (1s)
  1 failing

  1) Cypress Promise behavior works:
     Uncaught TypeError: promise.then(...).catch(...).finally is not a function
#...

Versions

  • Cypress: 3.1.0
  • OS: Mac OS X High Sierra / Mojave (same behavior on both)
  • Browsers:
    • Chrome 69.0.3497.100 (Official Build) (64-bit)
    • Electron 59 (Headless)

(I've tried all of the above using npm instead of yarn just to make sure and it succeeded/failed the same way)

@SaladFork
Copy link
Author

SaladFork commented Oct 24, 2018

This fails the same way with:

promise.then((value)  => updateDiv('then', `then: ${value}`))
promise.catch((value) => updateDiv('catch', `catch: ${value}`))
promise.finally(()    => updateDiv('finally', 'finally'))
Uncaught TypeError: promise.finally is not a function

So does not seem to simply be a problem with the return value of Promise.prototype.catch.

@chrisbreiding
Copy link
Contributor

Promise.prototype.finally was added in Chrome 63 and headless Cypress uses Electron 59, which is the equivalent of Chrome 59.

Cypress really only guarantees that its own code and your test code will run in the browser. Since this is your app code, it's out of Cypress's jurisdiction. If you were to run your code in IE or Edge, it would fail for the same reason, regardless of Cypress.

I guess the bug here is that you can currently only run in Electron headlessly and you can't control that version. We plan to add support for other headless browsers in the future so you'll have more control over what's running headlessly.

In any case, we'll be bumping the Electron version in the near future, which will 'fix' this.

@SaladFork
Copy link
Author

Ah, that would explain it, thanks.

I did add:

throw new Error(Promise.prototype.finally)

to the spec (console.* didn't seem to log) and it did output a defined function:

  1) Cypress Promise behavior works:
     Error: function (onFinally) {
  var C = speciesConstructor(this, core.Promise || global.Promise);
  var isFunction = typeof onFinally == 'function';
  return this.then(
    isFunction ? function (x) {
      return promiseResolve(C, onFinally()).then(function () { return x; });
    } : onFinally,
    isFunction ? function (e) {
      return promiseResolve(C, onFinally()).then(function () { throw e; });
    } : onFinally
  );
}

so I mistakenly thought it was available. I also tried adding a promise finally shim but got the same result. Thanks again!

I've refactored my actual code to use async/await and try/catch (Babel transpiled) which seem to work fine. Looking forward to the new version.

@jennifer-shehane
Copy link
Member

You can run Chrome in cypress run mode by passing the --browser flag while having Chrome installed where Cypress is run, but videos will not be recorded.

Closing this issue in favor of the issue to upgrade Electron, which would solve your issue: #2559

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants