-
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
Automatically retry verify and run commands on Linux if suspect DISPLAY problem #4165
Changes from 8 commits
142a830
ff9e26e
5a9f586
6bb8e1d
8b329d0
51d5389
a7a74a7
8d0d9fc
7747152
04b5891
4ad307c
8c2c367
fa00621
66a2d83
2b50102
cc9c06b
afacdc1
859c1bf
4aa038b
8850c04
080d3b2
ac5915d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,14 +2,18 @@ const os = require('os') | |
const chalk = require('chalk') | ||
const { stripIndent, stripIndents } = require('common-tags') | ||
const { merge } = require('ramda') | ||
const la = require('lazy-ass') | ||
const is = require('check-more-types') | ||
|
||
const util = require('./util') | ||
const state = require('./tasks/state') | ||
|
||
const issuesUrl = 'https://github.com/cypress-io/cypress/issues' | ||
const docsUrl = 'https://on.cypress.io' | ||
const requiredDependenciesUrl = `${docsUrl}/required-dependencies` | ||
|
||
// TODO it would be nice if all error objects could be enforced via types | ||
// to only have description + solution properties | ||
|
||
// common errors Cypress application can encounter | ||
const failedDownload = { | ||
description: 'The Cypress App could not be downloaded.', | ||
|
@@ -21,7 +25,7 @@ const failedUnzip = { | |
solution: stripIndent` | ||
Search for an existing issue or open a GitHub issue at | ||
|
||
${chalk.blue(issuesUrl)} | ||
${chalk.blue(util.issuesUrl)} | ||
`, | ||
} | ||
|
||
|
@@ -102,23 +106,48 @@ const smokeTestFailure = (smokeTestCommand, timedOut) => { | |
} | ||
} | ||
|
||
const isDisplayOnLinuxSet = () => { | ||
return os.platform() === 'linux' && | ||
Boolean(process.env.DISPLAY) | ||
} | ||
|
||
const missingDependency = { | ||
description: 'Cypress failed to start.', | ||
// this message is too Linux specific | ||
solution: stripIndent` | ||
This is usually caused by a missing library or dependency. | ||
solution: () => { | ||
let text = stripIndent` | ||
This is usually caused by a missing library or dependency. | ||
|
||
The error below should indicate which dependency is missing. | ||
The error below should indicate which dependency is missing. | ||
|
||
${chalk.blue(requiredDependenciesUrl)} | ||
${chalk.blue(requiredDependenciesUrl)} | ||
|
||
If you are using Docker, we provide containers with all required dependencies installed. | ||
`, | ||
If you are using Docker, we provide containers with all required dependencies installed. | ||
` | ||
|
||
if (isDisplayOnLinuxSet()) { | ||
const issueUrl = util.getGitHubIssueUrl(4034) | ||
|
||
text += `\n\n${stripIndent` | ||
We have noticed that DISPLAY variable is set to "${process.env.DISPLAY}" | ||
This might be a problem if X11 server is not responding. | ||
|
||
${chalk.blue(issueUrl)} | ||
|
||
Try deleting the DISPLAY variable and running the command again. | ||
`}` | ||
} | ||
|
||
return text | ||
}, | ||
} | ||
|
||
const invalidCacheDirectory = { | ||
description: 'Cypress cannot write to the cache directory due to file permissions', | ||
solution: '', | ||
solution: stripIndent` | ||
See discussion and possible solutions at | ||
${chalk.blue(util.getGitHubIssueUrl(1281))} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. at least give the relevant issue url |
||
`, | ||
} | ||
|
||
const versionMismatch = { | ||
|
@@ -135,7 +164,7 @@ const unexpected = { | |
|
||
Check if there is a GitHub issue describing this crash: | ||
|
||
${chalk.blue(issuesUrl)} | ||
${chalk.blue(util.issuesUrl)} | ||
|
||
Consider opening a new issue. | ||
`, | ||
|
@@ -205,10 +234,14 @@ function formErrorText (info, msg) { | |
) | ||
} | ||
|
||
const solution = is.fn(obj.solution) ? obj.solution() : obj.solution | ||
|
||
la(is.unemptyString(solution), 'expected solution to be text', solution) | ||
|
||
add(` | ||
${obj.description} | ||
|
||
${obj.solution} | ||
${solution} | ||
|
||
`) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,9 +2,11 @@ const os = require('os') | |
const Promise = require('bluebird') | ||
const Xvfb = require('@cypress/xvfb') | ||
const R = require('ramda') | ||
const { stripIndent } = require('common-tags') | ||
const debug = require('debug')('cypress:cli') | ||
const debugXvfb = require('debug')('cypress:xvfb') | ||
const { throwFormErrorText, errors } = require('../errors') | ||
const util = require('../util') | ||
|
||
const xvfb = Promise.promisifyAll(new Xvfb({ | ||
timeout: 5000, // milliseconds | ||
|
@@ -41,7 +43,33 @@ module.exports = { | |
}, | ||
|
||
isNeeded () { | ||
return os.platform() === 'linux' && !process.env.DISPLAY | ||
if (os.platform() !== 'linux') { | ||
return false | ||
} | ||
|
||
if (process.env.DISPLAY) { | ||
const issueUrl = util.getGitHubIssueUrl(4034) | ||
|
||
const message = stripIndent` | ||
DISPLAY environment variable is set to ${process.env.DISPLAY} on Linux | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. being verbose is good, hopefully, someone reads it and understand the problem, even if we work around it using our XVFB |
||
Assuming this DISPLAY points at working X11 server, | ||
Cypress will not spawn own XVFB | ||
|
||
NOTE: if the X11 server is NOT working, Cypress will exit without explanation, | ||
see ${issueUrl} | ||
Solution: Unset the DISPLAY variable and try again: | ||
DISPLAY= npx cypress run ... | ||
` | ||
|
||
debug(message) | ||
|
||
return false | ||
} | ||
|
||
debug('undefined DISPLAY environment variable') | ||
debug('Cypress will spawn its own XVFB') | ||
|
||
return true | ||
}, | ||
|
||
// async method, resolved with Boolean | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ const os = require('os') | |
const snapshot = require('../support/snapshot') | ||
const { errors, formErrorText } = require(`${lib}/errors`) | ||
const util = require(`${lib}/util`) | ||
const mockedEnv = require('mocked-env') | ||
|
||
describe('errors', function () { | ||
const { missingXvfb } = errors | ||
|
@@ -29,5 +30,51 @@ describe('errors', function () { | |
snapshot(text) | ||
}) | ||
}) | ||
|
||
it('calls solution if a function', () => { | ||
const solution = sinon.stub().returns('a solution') | ||
const error = { | ||
description: 'description', | ||
solution, | ||
} | ||
|
||
return formErrorText(error) | ||
.then((text) => { | ||
snapshot(text) | ||
expect(solution).to.have.been.calledOnce | ||
}) | ||
}) | ||
|
||
it('expects solution to be a string', () => { | ||
const error = { | ||
description: 'description', | ||
solution: 42, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 42 is never a good answer |
||
} | ||
|
||
return expect(formErrorText(error)).to.be.rejected | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. chai-as-promised is nice |
||
}) | ||
|
||
describe('custom solution', () => { | ||
let restore | ||
|
||
beforeEach(() => { | ||
restore = mockedEnv({ | ||
DISPLAY: 'wrong-display-address', | ||
}) | ||
}) | ||
|
||
afterEach(() => { | ||
restore() | ||
}) | ||
|
||
it('returns specific solution if on Linux DISPLAY env is set', () => { | ||
os.platform.returns('linux') | ||
|
||
return formErrorText(errors.missingDependency) | ||
.then((text) => { | ||
snapshot(text) | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,7 @@ | |
"clean-deps": "npm run all clean-deps && rm -rf node_modules", | ||
"docker": "./scripts/run-docker-local.sh", | ||
"lint-js": "eslint --fix scripts/*.js packages/ts/*.js cli/*.js cli/**/*.js", | ||
"lint-changed": "git diff --name-only | grep '\\.js$' | xargs npx eslint --fix", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. little utility to fix all changes JS files before committing |
||
"lint-coffee": "coffeelint scripts/**/*.coffee", | ||
"lint": "npm run lint-js && npm run lint-coffee", | ||
"pretest": "npm run lint && npm run all lint && npm run test-scripts", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filled missing solution for this error, pointing at the GH issue