Reject promise stub with an error instance (#3751)

* reject promise stub with Error instance

* pass linter
This commit is contained in:
Gleb Bahmutov
2019-03-20 09:47:13 -04:00
committed by GitHub
parent 9b889b678a
commit 1a7f631032
2 changed files with 215 additions and 133 deletions
+160 -44
View File
@@ -13,7 +13,13 @@ const state = require(`${lib}/tasks/state`)
const cacheDir = path.join('.cache/Cypress')
const versionDir = path.join(cacheDir, '1.2.3')
const binaryDir = path.join(versionDir, 'Cypress.app')
const binaryPkgPath = path.join(binaryDir, 'Contents', 'Resources', 'app', 'package.json')
const binaryPkgPath = path.join(
binaryDir,
'Contents',
'Resources',
'app',
'package.json'
)
describe('lib/tasks/state', function () {
beforeEach(function () {
@@ -25,43 +31,69 @@ describe('lib/tasks/state', function () {
})
context('.getBinaryPkgVersionAsync', function () {
it('resolves version from version file when it exists', function () {
sinon.stub(fs, 'pathExistsAsync').withArgs(binaryPkgPath).resolves(true)
sinon.stub(fs, 'readJsonAsync').withArgs(binaryPkgPath).resolves({ version: '2.0.48' })
return state.getBinaryPkgVersionAsync(binaryDir)
.then((binaryVersion) => {
sinon
.stub(fs, 'pathExistsAsync')
.withArgs(binaryPkgPath)
.resolves(true)
sinon
.stub(fs, 'readJsonAsync')
.withArgs(binaryPkgPath)
.resolves({ version: '2.0.48' })
return state.getBinaryPkgVersionAsync(binaryDir).then((binaryVersion) => {
expect(binaryVersion).to.equal('2.0.48')
})
})
it('returns null if no version found', function () {
sinon.stub(fs, 'pathExistsAsync').resolves(false)
return state.getBinaryPkgVersionAsync(binaryDir)
.then((binaryVersion) => expect(binaryVersion).to.equal(null))
return state
.getBinaryPkgVersionAsync(binaryDir)
.then((binaryVersion) => {
return expect(binaryVersion).to.equal(null)
})
})
it('returns correct version if passed binaryDir', function () {
const customBinaryDir = '/custom/binary/dir'
const customBinaryPackageDir = '/custom/binary/dir/Contents/Resources/app/package.json'
sinon.stub(fs, 'pathExistsAsync').withArgs(customBinaryPackageDir).resolves(true)
sinon.stub(fs, 'readJsonAsync').withArgs(customBinaryPackageDir).resolves({ version: '3.4.5' })
const customBinaryPackageDir =
'/custom/binary/dir/Contents/Resources/app/package.json'
return state.getBinaryPkgVersionAsync(customBinaryDir)
.then((binaryVersion) => expect(binaryVersion).to.equal('3.4.5'))
sinon
.stub(fs, 'pathExistsAsync')
.withArgs(customBinaryPackageDir)
.resolves(true)
sinon
.stub(fs, 'readJsonAsync')
.withArgs(customBinaryPackageDir)
.resolves({ version: '3.4.5' })
return state
.getBinaryPkgVersionAsync(customBinaryDir)
.then((binaryVersion) => {
return expect(binaryVersion).to.equal('3.4.5')
})
})
})
context('.getPathToExecutable', function () {
it('resolves path on macOS', function () {
const macExecutable = '.cache/Cypress/1.2.3/Cypress.app/Contents/MacOS/Cypress'
expect(state.getPathToExecutable(state.getBinaryDir())).to.equal(macExecutable)
const macExecutable =
'.cache/Cypress/1.2.3/Cypress.app/Contents/MacOS/Cypress'
expect(state.getPathToExecutable(state.getBinaryDir())).to.equal(
macExecutable
)
})
it('resolves path on linux', function () {
os.platform.returns('linux')
const linuxExecutable = '.cache/Cypress/1.2.3/Cypress/Cypress'
expect(state.getPathToExecutable(state.getBinaryDir())).to.equal(linuxExecutable)
expect(state.getPathToExecutable(state.getBinaryDir())).to.equal(
linuxExecutable
)
})
it('resolves path on windows', function () {
os.platform.returns('win32')
@@ -69,13 +101,18 @@ describe('lib/tasks/state', function () {
})
it('resolves from custom binaryDir', function () {
const customBinaryDir = 'home/downloads/cypress.app'
expect(state.getPathToExecutable(customBinaryDir)).to.equal('home/downloads/cypress.app/Contents/MacOS/Cypress')
expect(state.getPathToExecutable(customBinaryDir)).to.equal(
'home/downloads/cypress.app/Contents/MacOS/Cypress'
)
})
})
context('.getBinaryDir', function () {
it('resolves path on macOS', function () {
expect(state.getBinaryDir()).to.equal(path.join(versionDir, 'Cypress.app'))
expect(state.getBinaryDir()).to.equal(
path.join(versionDir, 'Cypress.app')
)
})
it('resolves path on linux', function () {
@@ -85,8 +122,10 @@ describe('lib/tasks/state', function () {
it('resolves path on windows', function () {
const state = proxyquire(`${lib}/tasks/state`, { path: path.win32 })
os.platform.returns('win32')
const pathToExec = state.getBinaryDir()
expect(pathToExec).to.be.equal(path.win32.join(versionDir, 'Cypress'))
})
@@ -95,12 +134,16 @@ describe('lib/tasks/state', function () {
})
it('resolves path to binary/installation from version', function () {
expect(state.getBinaryDir('4.5.6')).to.be.equal(path.join(cacheDir, '4.5.6', 'Cypress.app'))
expect(state.getBinaryDir('4.5.6')).to.be.equal(
path.join(cacheDir, '4.5.6', 'Cypress.app')
)
})
it('rejects on anything else', function () {
os.platform.returns('unknown')
expect(() => state.getBinaryDir().to.throw('Platform: "unknown" is not supported.')
expect(() => {
return state.getBinaryDir().to.throw('Platform: "unknown" is not supported.')
}
)
})
})
@@ -108,86 +151,159 @@ describe('lib/tasks/state', function () {
context('.getBinaryVerifiedAsync', function () {
it('resolves true if verified', function () {
sinon.stub(fs, 'readJsonAsync').resolves({ verified: true })
return state.getBinaryVerifiedAsync('/asdf')
.then((isVerified) => expect(isVerified).to.be.equal(true))
return state
.getBinaryVerifiedAsync('/asdf')
.then((isVerified) => {
return expect(isVerified).to.be.equal(true)
})
})
it('resolves undefined if not verified', function () {
sinon.stub(fs, 'readJsonAsync').rejects({ code: 'ENOENT' })
return state.getBinaryVerifiedAsync('/asdf')
.then((isVerified) => expect(isVerified).to.be.equal(undefined))
const err = new Error()
err.code = 'ENOENT'
sinon.stub(fs, 'readJsonAsync').rejects(err)
return state
.getBinaryVerifiedAsync('/asdf')
.then((isVerified) => {
return expect(isVerified).to.be.equal(undefined)
})
})
it('can accept custom binaryDir', function () {
const customBinaryDir = '/custom/binary/dir'
sinon.stub(fs, 'pathExistsAsync').withArgs('/custom/binary/dir/binary_state.json').resolves({ verified: true })
sinon.stub(fs, 'readJsonAsync').withArgs('/custom/binary/dir/binary_state.json').resolves({ verified: true })
return state.getBinaryVerifiedAsync(customBinaryDir)
.then((isVerified) => expect(isVerified).to.be.equal(true))
sinon
.stub(fs, 'pathExistsAsync')
.withArgs('/custom/binary/dir/binary_state.json')
.resolves({ verified: true })
sinon
.stub(fs, 'readJsonAsync')
.withArgs('/custom/binary/dir/binary_state.json')
.resolves({ verified: true })
return state
.getBinaryVerifiedAsync(customBinaryDir)
.then((isVerified) => {
return expect(isVerified).to.be.equal(true)
})
})
})
context('.writeBinaryVerified', function () {
it('writes to binary state verified:true', function () {
sinon.stub(fs, 'outputJsonAsync').resolves()
return state.writeBinaryVerifiedAsync(true, binaryDir)
.then(() => expect(fs.outputJsonAsync).to.be.calledWith(
path.join(binaryDir, 'binary_state.json'), { verified: true }), { spaces: 2 }
return state
.writeBinaryVerifiedAsync(true, binaryDir)
.then(
() => {
return expect(fs.outputJsonAsync).to.be.calledWith(
path.join(binaryDir, 'binary_state.json'),
{ verified: true }
)
},
{ spaces: 2 }
)
})
it('write to binary state verified:false', function () {
sinon.stub(fs, 'outputJsonAsync').resolves()
return state.writeBinaryVerifiedAsync(false, binaryDir)
.then(() => expect(fs.outputJsonAsync).to.be.calledWith(
path.join(binaryDir, 'binary_state.json'), { verified: false }, { spaces: 2 })
return state
.writeBinaryVerifiedAsync(false, binaryDir)
.then(() => {
return expect(fs.outputJsonAsync).to.be.calledWith(
path.join(binaryDir, 'binary_state.json'),
{ verified: false },
{ spaces: 2 }
)
}
)
})
})
context('.getCacheDir', function () {
it('uses cachedir()', function () {
const ret = state.getCacheDir()
expect(ret).to.equal(cacheDir)
})
it('uses env variable CYPRESS_CACHE_FOLDER', function () {
process.env.CYPRESS_CACHE_FOLDER = '/path/to/dir'
const ret = state.getCacheDir()
expect(ret).to.equal('/path/to/dir')
})
it('CYPRESS_CACHE_FOLDER resolves from relative path', () => {
process.env.CYPRESS_CACHE_FOLDER = './local-cache/folder'
const ret = state.getCacheDir()
expect(ret).to.eql(path.resolve('local-cache/folder'))
})
})
context('.parseRealPlatformBinaryFolderAsync', function () {
beforeEach(function () {
sinon.stub(fs, 'realpathAsync').callsFake((path) => Promise.resolve(path))
sinon.stub(fs, 'realpathAsync').callsFake((path) => {
return Promise.resolve(path)
})
})
it('can parse on darwin', function () {
os.platform.returns('darwin')
return state.parseRealPlatformBinaryFolderAsync('/Documents/Cypress.app/Contents/MacOS/Cypress').then((path) => expect(path).to.eql('/Documents/Cypress.app'))
return state
.parseRealPlatformBinaryFolderAsync(
'/Documents/Cypress.app/Contents/MacOS/Cypress'
)
.then((path) => {
return expect(path).to.eql('/Documents/Cypress.app')
})
})
it('can parse on linux', function () {
os.platform.returns('linux')
return state.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress').then((path) => expect(path).to.eql('/Documents/Cypress'))
return state
.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress')
.then((path) => {
return expect(path).to.eql('/Documents/Cypress')
})
})
it('can parse on darwin', function () {
os.platform.returns('win32')
return state.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress.exe').then((path) => expect(path).to.eql('/Documents/Cypress'))
return state
.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress.exe')
.then((path) => {
return expect(path).to.eql('/Documents/Cypress')
})
})
it('throws when invalid on darwin', function () {
os.platform.returns('darwin')
return state.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress.exe').then((path) => expect(path).to.eql(false))
return state
.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress.exe')
.then((path) => {
return expect(path).to.eql(false)
})
})
it('throws when invalid on linux', function () {
os.platform.returns('linux')
return state.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress.exe').then((path) => expect(path).to.eql(false))
return state
.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress.exe')
.then((path) => {
return expect(path).to.eql(false)
})
})
it('throws when invalid on windows', function () {
os.platform.returns('win32')
return state.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress').then((path) => expect(path).to.eql(false))
return state
.parseRealPlatformBinaryFolderAsync('/Documents/Cypress/Cypress')
.then((path) => {
return expect(path).to.eql(false)
})
})
})
})
+55 -89
View File
@@ -35,7 +35,6 @@ context('lib/tasks/verify', () => {
require('mocha-banner').register()
beforeEach(() => {
stdout = Stdout.capture()
spawnedProcess = {
code: 0,
@@ -58,10 +57,9 @@ context('lib/tasks/verify', () => {
sinon.stub(_, 'random').returns('222')
util.exec.withArgs(executablePath, [
'--smoke-test',
'--ping=222',
]).resolves(spawnedProcess)
util.exec
.withArgs(executablePath, ['--smoke-test', '--ping=222'])
.resolves(spawnedProcess)
})
afterEach(() => {
@@ -71,7 +69,8 @@ context('lib/tasks/verify', () => {
it('logs error and exits when no version of Cypress is installed', () => {
mockfs({})
return verify.start()
return verify
.start()
.then(() => {
throw new Error('should have caught error')
})
@@ -93,8 +92,7 @@ context('lib/tasks/verify', () => {
packageVersion,
})
return verify.start()
.then(() => {
return verify.start().then(() => {
// nothing should have been logged to stdout
// since no verification took place
expect(stdout.toString()).to.be.empty
@@ -104,14 +102,14 @@ context('lib/tasks/verify', () => {
})
it('logs warning when installed version does not match verified version', () => {
createfs({
alreadyVerified: true,
executable: mockfs.file({ mode: 0777 }),
packageVersion: 'bloop',
})
return verify.start()
return verify
.start()
.then(() => {
throw new Error('should have caught error')
})
@@ -124,18 +122,15 @@ context('lib/tasks/verify', () => {
})
it('logs error and exits when executable cannot be found', () => {
return verify.start()
return verify
.start()
.then(() => {
throw new Error('should have caught error')
})
.catch((err) => {
logger.error(err)
snapshot(
'executable cannot be found',
normalize(stdout.toString())
)
snapshot('executable cannot be found', normalize(stdout.toString()))
})
})
@@ -149,25 +144,23 @@ context('lib/tasks/verify', () => {
})
it('shows full path to executable when verifying', () => {
return verify.start({ force: true })
.then(() => {
snapshot(
'verification with executable',
normalize(stdout.toString())
)
return verify.start({ force: true }).then(() => {
snapshot('verification with executable', normalize(stdout.toString()))
})
})
it('clears verified version from state if verification fails', () => {
util.exec.restore()
sinon.stub(util, 'exec').withArgs(executablePath).rejects({
sinon
.stub(util, 'exec')
.withArgs(executablePath)
.rejects({
code: 1,
stderr: 'an error about dependencies',
})
return verify.start({ force: true })
return verify
.start({ force: true })
.then(() => {
throw new Error('Should have thrown')
})
@@ -191,7 +184,6 @@ context('lib/tasks/verify', () => {
describe('smoke test with DEBUG output', () => {
beforeEach(() => {
const stdoutWithDebugOutput = stripIndent`
some debug output
date: more debug output
@@ -211,13 +203,8 @@ context('lib/tasks/verify', () => {
})
it('finds ping value in the verbose output', () => {
return verify.start()
.then(() => {
snapshot(
'verbose stdout output',
normalize(stdout.toString())
)
return verify.start().then(() => {
snapshot('verbose stdout output', normalize(stdout.toString()))
})
})
})
@@ -229,7 +216,8 @@ context('lib/tasks/verify', () => {
packageVersion,
})
return verify.start()
return verify
.start()
.then(() => {
throw new Error('Should have thrown')
})
@@ -237,10 +225,7 @@ context('lib/tasks/verify', () => {
stdout = Stdout.capture()
logger.error(err)
return snapshot(
'no Cypress executable',
normalize(stdout.toString())
)
return snapshot('no Cypress executable', normalize(stdout.toString()))
})
})
@@ -252,7 +237,8 @@ context('lib/tasks/verify', () => {
packageVersion,
})
return verify.start()
return verify
.start()
.then(() => {
throw new Error('Should have thrown')
})
@@ -274,8 +260,7 @@ context('lib/tasks/verify', () => {
packageVersion,
})
return verify.start()
.then(() => {
return verify.start().then(() => {
return snapshot(
'current version has not been verified',
normalize(stdout.toString())
@@ -290,8 +275,7 @@ context('lib/tasks/verify', () => {
packageVersion: '7.8.9',
})
return verify.start()
.then(() => {
return verify.start().then(() => {
return snapshot(
'different version installed',
normalize(stdout.toString())
@@ -308,8 +292,7 @@ context('lib/tasks/verify', () => {
process.env.npm_config_loglevel = 'silent'
return verify.start()
.then(() => {
return verify.start().then(() => {
return snapshot(
'silent verify',
normalize(`[no output]${stdout.toString()}`)
@@ -324,14 +307,12 @@ context('lib/tasks/verify', () => {
packageVersion: '7.8.9',
})
return verify.start({
return verify
.start({
welcomeMessage: false,
})
.then(() => {
return snapshot(
'no welcome message',
normalize(stdout.toString())
)
return snapshot('no welcome message', normalize(stdout.toString()))
})
})
@@ -349,7 +330,8 @@ context('lib/tasks/verify', () => {
message: 'Error: EPERM NOT PERMITTED',
})
return verify.start()
return verify
.start()
.then(() => {
throw new Error('Should have thrown')
})
@@ -357,10 +339,7 @@ context('lib/tasks/verify', () => {
stdout = Stdout.capture()
logger.error(err)
return snapshot(
'fails with no stderr',
normalize(stdout.toString())
)
return snapshot('fails with no stderr', normalize(stdout.toString()))
})
})
@@ -375,15 +354,13 @@ context('lib/tasks/verify', () => {
})
it('starts xvfb', () => {
return verify.start()
.then(() => {
return verify.start().then(() => {
expect(xvfb.start).to.be.called
})
})
it('stops xvfb on spawned process close', () => {
return verify.start()
.then(() => {
return verify.start().then(() => {
expect(xvfb.stop).to.be.called
})
})
@@ -394,16 +371,12 @@ context('lib/tasks/verify', () => {
err.stack = 'xvfb? no dice'
xvfb.start.rejects(err)
return verify.start()
.catch((err) => {
return verify.start().catch((err) => {
expect(xvfb.stop).to.be.calledOnce
logger.error(err)
snapshot(
'xvfb fails',
normalize(slice(stdout.toString()))
)
snapshot('xvfb fails', normalize(slice(stdout.toString())))
})
})
})
@@ -419,34 +392,27 @@ context('lib/tasks/verify', () => {
})
it('uses verbose renderer', () => {
return verify.start()
.then(() => {
snapshot(
'verifying in ci',
normalize(stdout.toString())
)
return verify.start().then(() => {
snapshot('verifying in ci', normalize(stdout.toString()))
})
})
it('logs error when binary not found', () => {
mockfs({})
return verify.start()
return verify
.start()
.then(() => {
throw new Error('Should have thrown')
})
.catch((err) => {
logger.error(err)
snapshot(
'error binary not found in ci',
normalize(stdout.toString())
)
snapshot('error binary not found in ci', normalize(stdout.toString()))
})
})
})
describe('when env var CYPRESS_RUN_BINARY', () => {
it('can validate and use executable', () => {
const envBinaryPath = '/custom/Contents/MacOS/Cypress'
const realEnvBinaryPath = `/real${envBinaryPath}`
@@ -458,24 +424,22 @@ context('lib/tasks/verify', () => {
packageVersion,
customDir: '/real/custom',
})
util.exec.withArgs(realEnvBinaryPath, [
'--smoke-test',
'--ping=222',
]).resolves(spawnedProcess)
util.exec
.withArgs(realEnvBinaryPath, ['--smoke-test', '--ping=222'])
.resolves(spawnedProcess)
return verify.start()
.then(() => {
return verify.start().then(() => {
expect(util.exec.firstCall.args[0]).to.equal(realEnvBinaryPath)
snapshot('valid CYPRESS_RUN_BINARY', normalize(stdout.toString()))
})
})
;['darwin', 'linux', 'win32'].forEach((platform) => {
return it('can log error to user', () => {
process.env.CYPRESS_RUN_BINARY = '/custom/'
os.platform.returns(platform)
return verify.start()
return verify
.start()
.then(() => {
throw new Error('Should have thrown')
})
@@ -496,9 +460,11 @@ function createfs ({ alreadyVerified, executable, packageVersion, customDir }) {
[customDir ? customDir : '/cache/Cypress/1.2.3/Cypress.app']: {
'binary_state.json': `{"verified": ${alreadyVerified}}`,
Contents: {
MacOS: executable ? {
Cypress: executable,
} : {},
MacOS: executable
? {
Cypress: executable,
}
: {},
Resources: {
app: {
'package.json': `{"version": "${packageVersion}"}`,