-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Test runner hangs with RangeError: Maximum call stack size exceeded #4346
Comments
any update on this, I am also facing this. |
I was able to reproduce this issue within the I recreated it like 10 times and now the test just passes when I run it. Why? What changed? My internet source changed? But I can't recreate even going back to older internet source and it seems unlikely that's it anyway. I'm confused, ugh. Plugins file module.exports = (on, config) => {
on('before:browser:launch', (browser = {}, args) => {
if (browser.name === 'chrome' || browser.name === 'chromium' || browser.name === 'canary') {
args.push('--auto-open-devtools-for-tabs')
return args
}
if (browser.name === 'electron') {
console.log('WEBPREFERENCES', args['webPreferences'])
args['webPreferences']['devTools'] = true
return args
}
})
} Spec file that was failing. /// <reference types="Cypress" />
/// JSON fixture file can be loaded directly using
// the built-in JavaScript bundler
// @ts-ignore
const requiredExample = require('../fixtures/example')
context('Files', () => {
beforeEach(() => {
cy.visit('http://localhost:8080/commands/files')
})
beforeEach(() => {
// load example.json fixture file and store
// in the test context object
cy.fixture('example.json').as('example')
})
it('cy.fixture() - load a fixture', () => {
// https://on.cypress.io/fixture
// Instead of writing a response inline you can
// use a fixture file's content.
cy.server()
cy.fixture('example.json').as('comment')
// when application makes an Ajax request matching "GET comments/*"
// Cypress will intercept it and reply with object
// from the "comment" alias
cy.route('GET', 'comments/*', '@comment').as('getComment')
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.fixture-btn').click()
cy.wait('@getComment').its('responseBody')
.should('have.property', 'name')
.and('include', 'Using fixtures to represent data')
// you can also just write the fixture in the route
cy.route('GET', 'comments/*', 'fixture:example.json').as('getComment')
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.fixture-btn').click()
cy.wait('@getComment').its('responseBody')
.should('have.property', 'name')
.and('include', 'Using fixtures to represent data')
// or write fx to represent fixture
// by default it assumes it's .json
cy.route('GET', 'comments/*', 'fx:example').as('getComment')
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.fixture-btn').click()
cy.wait('@getComment').its('responseBody')
.should('have.property', 'name')
.and('include', 'Using fixtures to represent data')
})
it('cy.fixture() or require - load a fixture', function () {
// we are inside the "function () { ... }"
// callback and can use test context object "this"
// "this.example" was loaded in "beforeEach" function callback
expect(this.example, 'fixture in the test context')
.to.deep.equal(requiredExample)
// or use "cy.wrap" and "should('deep.equal', ...)" assertion
// @ts-ignore
cy.wrap(this.example, 'fixture vs require')
.should('deep.equal', requiredExample)
})
it('cy.readFile() - read a files contents', () => {
// https://on.cypress.io/readfile
// You can read a file and yield its contents
// The filePath is relative to your project's root.
cy.readFile('cypress.json').then((json) => {
expect(json).to.be.an('object')
})
})
it.only('cy.writeFile() - write to a file', () => {
// https://on.cypress.io/writefile
// You can write to a file
// Use a response from a request to automatically
// generate a fixture file for use later
cy.request('https://jsonplaceholder.cypress.io/users')
.then((response) => {
cy.writeFile('cypress/fixtures/users.json', response.body)
})
cy.fixture('users').should((users) => {
expect(users[0].name).to.exist
})
// JavaScript arrays and objects are stringified
// and formatted into text.
cy.writeFile('cypress/fixtures/profile.json', {
id: 8739,
name: 'Jane',
email: 'jane@example.com',
})
cy.fixture('profile').should((profile) => {
expect(profile.name).to.eq('Jane')
})
})
}) Log:
|
We were getting this error too while working on the 3.3.0 network changes, but thought it was isolated. I guess it makes sense to break the circular references in the errors sent over socket.io to fix this. |
if it's any help, I started seeing this error after updating cypress from 3.2.0 to 3.3.1. Rolled back to 3.2.0 for now... |
@JohnnyFun Do you happen to have any test code that can reliably cause this error? |
Yeah, I have a test that sends a
I'll look into why my server didn't start to maybe get more info for you as to how it can pop up. |
Oh and here's my cy.request call, if you need it:
|
@JohnnyFun Interesting, is there a circular reference in your cy.request({
method: "POST",
url: "http://0.0.0.0/",
form: true,
body: {
username: "test"
}
}) But when I add a circular reference to the let c = {}
c.c = c
cy.request({
method: "POST",
url: "http://0.0.0.0/",
form: true,
body: {
username: "test",
c
}
}) It looks like there's two situations where a maximum call stack exceeded can be thrown by socket.io:
I think we should just switch to using a custom socket.io parser that supports circular JSON, instead of trying to check every place where a message is sent to prevent circular references. EDIT: Okay, in addition to allowing circular bodies to be sent over socket.io, the PR will also prevent users from sending circular bodies with requests because that's never going to make sense: |
Circular ref shouldn't be the issue in my case. Those "_authnRequest" are just base64 encoded string values For example: "eyJyZWxheVN0YXRlIjoiV2s2LVN2Rm5reDNDdGJxTmZjNk4wR2VXIiwiaWQiOiJpZDgyYjVmODE3MmZlNTQ4ZGI4YWFjNGY3Y2FkMzAxOGJhIiwiaXNzdWVyIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQzMDAiLCJkZXN0aW5hdGlvbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMC9zYW1sL3NzbyIsImFjc1VybCI6Imh0dHBzOi8vbG9jYWxob3N0OjQ0MzAwL3NhbWwyL2hjYS9BY3MiLCJmb3JjZUF1dGhuIjpmYWxzZX0=". |
I narrowed it further. Seems to happen if the failing call is inside another cy.request call like:
|
I am getting the error consistently at the moment. I tried doing console.log in
So apparently, a HUGE error object (probably the request object is referenced, which might reference the socket) is passed to has_binary. Hope this helps |
The code for this is done in cypress-io/cypress#4407, but has yet to be released. |
@flotwig not sure if you saw my narrowed example with the nested failing |
@JohnnyFun You're right, #4407 doesn't seem to fix that particular issue. Looking in to it. |
Seems like nesting
...which contains a circular reference at |
I think any case of |
The code for this is done in cypress-io/cypress#4469, but has yet to be released. |
Do you have an ETA for release on #4469? |
Released in |
Current behavior:
The following can be experienced when running cypress headlessly on a particular error.
This effectively hangs the process.
Desired behavior:
This should not happen.
Steps to reproduce: (app code and test code)
It is consistent in our test suite, but it seems that giving a minimally reproducible case is not easy, as merely changing the order of tests will not yield this error.
That said, tracing back the issue, here is what has been found:
The library request-promise-core on error throws the following Error object on a particular error (in our case ECONNREFUSED).
The important part is that this object contains circular references:
On request error, this object is sent to socket.io's callback function
https://github.com/cypress-io/cypress/blob/develop/packages/server/lib/socket.coffee#L315-L319
This is a problem because Socket.io scans arguments for binary data that doesn't deal with circular reference.
https://github.com/socketio/socket.io/blob/master/lib/socket.js#L374-L391
https://github.com/expanse-org/socketio-app/blob/master/node_modules/has-binary2/index.js
There is already some filtering done to errors captured and raised back to the execution flow.
https://github.com/cypress-io/cypress/blob/develop/packages/server/lib/errors.coffee#L808-L828
An additional operation to would be to make sure that it doesn't contain circular reference.
I'd suggest using a library like fclone for this.
https://github.com/soyuka/fclone
Versions
Note: OSX with electron or chrome did not reproduce the issue.
The text was updated successfully, but these errors were encountered: