mirror of
https://github.com/cypress-io/cypress.git
synced 2026-04-23 15:39:28 -05:00
feat: add cloud recommendation message to CI output (#24680)
This commit is contained in:
Vendored
+3
@@ -229,6 +229,7 @@ declare namespace CypressCommandLine {
|
||||
startedAt: dateTimeISO
|
||||
endedAt: dateTimeISO
|
||||
duration: ms
|
||||
wallClockDuration?: number
|
||||
}
|
||||
/**
|
||||
* Reporter name like "spec"
|
||||
@@ -259,8 +260,10 @@ declare namespace CypressCommandLine {
|
||||
* resolved filename of the spec
|
||||
*/
|
||||
absolute: string
|
||||
relativeToCommonRoot: string
|
||||
}
|
||||
shouldUploadVideo: boolean
|
||||
skippedSpec: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,10 @@ import path from 'node:path'
|
||||
const debug = Debug('test')
|
||||
|
||||
describe('config/src/project/utils', () => {
|
||||
beforeEach(function () {
|
||||
delete process.env.CYPRESS_COMMERCIAL_RECOMMENDATIONS
|
||||
})
|
||||
|
||||
before(function () {
|
||||
this.env = process.env;
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ import {
|
||||
} from '../src/project/utils'
|
||||
|
||||
describe('config/src/utils', () => {
|
||||
beforeEach(function () {
|
||||
delete process.env.CYPRESS_COMMERCIAL_RECOMMENDATIONS
|
||||
})
|
||||
|
||||
describe('hideKeys', () => {
|
||||
it('removes middle part of the string', () => {
|
||||
const hidden = hideKeys('12345-xxxx-abcde')
|
||||
|
||||
@@ -351,3 +351,59 @@ exports['Long Cypress Cloud URL'] = `
|
||||
Recorded Run: http://cloud.cypress.io/this-is-a-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-long-url
|
||||
|
||||
`
|
||||
|
||||
exports['CLOUD_RECOMMENDATION_MESSAGE'] = `
|
||||
|
||||
====================================================================================================
|
||||
|
||||
(Run Starting)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Cypress: 1.2.3 │
|
||||
│ Browser: FooBrowser 88 │
|
||||
│ Specs: 1 found (test1.js) │
|
||||
│ Searched: tests/test1.js │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: test1.js (1 of 1)
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: undefined │
|
||||
│ Passing: undefined │
|
||||
│ Failing: 1 │
|
||||
│ Pending: undefined │
|
||||
│ Skipped: undefined │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: false │
|
||||
│ Duration: undefined seconds │
|
||||
│ Spec Ran: test1.js │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
====================================================================================================
|
||||
|
||||
(Run Finished)
|
||||
|
||||
|
||||
Spec Tests Passing Failing Pending Skipped
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ ✖ test1.js XX:XX - - 1 - - │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
✖ 1 of 1 failed (100%) XX:XX - - 1 - -
|
||||
|
||||
----------------------------------------------------------------------------------------------------
|
||||
|
||||
Having trouble debugging your CI failures?
|
||||
|
||||
Record your runs to Cypress Cloud to watch video recordings for each test,
|
||||
debug failing and flaky tests, and integrate with your favorite tools.
|
||||
|
||||
>> https://on.cypress.io/cloud-get-started
|
||||
|
||||
----------------------------------------------------------------------------------------------------
|
||||
`
|
||||
|
||||
@@ -1012,6 +1012,7 @@ async function ready (options: { projectRoot: string, record: boolean, key: stri
|
||||
|
||||
if (!options.quiet) {
|
||||
printResults.renderSummaryTable(runUrl, results)
|
||||
printResults.maybeLogCloudRecommendationMessage(results.runs || [], record)
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
const _ = require('lodash')
|
||||
const isCi = require('is-ci')
|
||||
const debug = require('debug')('cypress:server')
|
||||
|
||||
const getIsCi = () => isCi
|
||||
|
||||
const join = (char, ...pieces) => {
|
||||
return _.chain(pieces).compact().join(char).value()
|
||||
}
|
||||
@@ -668,6 +671,8 @@ const detectableCiBuildIdProviders = () => {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getIsCi,
|
||||
|
||||
list,
|
||||
|
||||
provider,
|
||||
|
||||
@@ -9,6 +9,7 @@ import duration from './duration'
|
||||
import newlines from './newlines'
|
||||
import env from './env'
|
||||
import terminal from './terminal'
|
||||
import { getIsCi } from './ci_provider'
|
||||
import * as experiments from '../experiments'
|
||||
import type { SpecFile } from '@packages/types'
|
||||
import type { Cfg } from '../project-base'
|
||||
@@ -22,11 +23,18 @@ type Screenshot = {
|
||||
specName: string
|
||||
}
|
||||
|
||||
export const cloudRecommendationMessage = `
|
||||
Having trouble debugging your CI failures?
|
||||
|
||||
Record your runs to Cypress Cloud to watch video recordings for each test,
|
||||
debug failing and flaky tests, and integrate with your favorite tools.
|
||||
`
|
||||
|
||||
function color (val: any, c: string) {
|
||||
return chalk[c](val)
|
||||
}
|
||||
|
||||
function gray (val: any) {
|
||||
export function gray (val: any) {
|
||||
return color(val, 'gray')
|
||||
}
|
||||
|
||||
@@ -274,7 +282,21 @@ export function displaySpecHeader (name: string, curr: number, total: number, es
|
||||
}
|
||||
}
|
||||
|
||||
export function renderSummaryTable (runUrl: string | undefined, results: any) {
|
||||
export function maybeLogCloudRecommendationMessage (runs: CypressCommandLine.RunResult[], record: boolean) {
|
||||
if (!getIsCi() || env.get('CYPRESS_COMMERCIAL_RECOMMENDATIONS') === '0' || record) {
|
||||
return
|
||||
}
|
||||
|
||||
if (runs.some((run) => run.stats.failures > 0)) {
|
||||
terminal.divider('-')
|
||||
console.log(cloudRecommendationMessage)
|
||||
console.log(` >>`, color('https://on.cypress.io/cloud-get-started', 'cyan'))
|
||||
console.log('')
|
||||
terminal.divider('-')
|
||||
}
|
||||
}
|
||||
|
||||
export function renderSummaryTable (runUrl: string | undefined, results: CypressCommandLine.CypressRunResult) {
|
||||
const { runs } = results
|
||||
|
||||
console.log('')
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
"http-proxy": "https://github.com/cypress-io/node-http-proxy.git#9322b4b69b34f13a6f3874e660a35df3305179c6",
|
||||
"human-interval": "1.0.0",
|
||||
"image-size": "0.8.3",
|
||||
"is-ci": "^3.0.0",
|
||||
"is-fork-pr": "2.5.0",
|
||||
"is-html": "2.0.0",
|
||||
"jimp": "0.14.0",
|
||||
|
||||
@@ -44,6 +44,7 @@ const electronApp = require('../../lib/util/electron-app')
|
||||
const savedState = require(`../../lib/saved_state`)
|
||||
const { getCtx, clearCtx, setCtx, makeDataContext } = require(`../../lib/makeDataContext`)
|
||||
const { BrowserCriClient } = require(`../../lib/browsers/browser-cri-client`)
|
||||
const { cloudRecommendationMessage } = require('../../lib/util/print-run')
|
||||
|
||||
const TYPICAL_BROWSERS = [
|
||||
{
|
||||
@@ -349,6 +350,58 @@ describe('lib/cypress', () => {
|
||||
sinon.stub(commitInfo, 'getRemoteOrigin').resolves('remoteOrigin')
|
||||
})
|
||||
|
||||
describe('cloud recommendation message', () => {
|
||||
it('gets logged when in CI and there is a failure', function () {
|
||||
const relativePath = path.relative(cwd(), this.todosPath)
|
||||
|
||||
sinon.stub(ciProvider, 'getIsCi').returns(true)
|
||||
delete process.env.CYPRESS_COMMERCIAL_RECOMMENDATIONS
|
||||
globalThis.CY_TEST_MOCK.listenForProjectEnd = { stats: { failures: 1 } }
|
||||
|
||||
return cypress.start([`--run-project=${this.todosPath}`, `--spec=${relativePath}/tests/test1.js`]).then(() => {
|
||||
expect(console.log).to.be.calledWith(cloudRecommendationMessage)
|
||||
|
||||
snapshotConsoleLogs('CLOUD_RECOMMENDATION_MESSAGE')
|
||||
})
|
||||
})
|
||||
|
||||
it('does not get logged if CYPRESS_COMMERCIAL_RECOMMENDATIONS is set to 0', function () {
|
||||
const relativePath = path.relative(cwd(), this.todosPath)
|
||||
|
||||
sinon.stub(ciProvider, 'getIsCi').returns(true)
|
||||
process.env.CYPRESS_COMMERCIAL_RECOMMENDATIONS = '0'
|
||||
globalThis.CY_TEST_MOCK.listenForProjectEnd = { stats: { failures: 1 } }
|
||||
|
||||
return cypress.start([`--run-project=${this.todosPath}`, `--spec=${relativePath}/tests/test1.js`]).then(() => {
|
||||
expect(console.log).not.to.be.calledWith(cloudRecommendationMessage)
|
||||
})
|
||||
})
|
||||
|
||||
it('does not get logged if all tests pass', function () {
|
||||
const relativePath = path.relative(cwd(), this.todosPath)
|
||||
|
||||
sinon.stub(ciProvider, 'getIsCi').returns(true)
|
||||
delete process.env.CYPRESS_COMMERCIAL_RECOMMENDATIONS
|
||||
globalThis.CY_TEST_MOCK.listenForProjectEnd = { stats: { failures: 0 } }
|
||||
|
||||
return cypress.start([`--run-project=${this.todosPath}`, `--spec=${relativePath}/tests/test1.js`]).then(() => {
|
||||
expect(console.log).not.to.be.calledWith(cloudRecommendationMessage)
|
||||
})
|
||||
})
|
||||
|
||||
it('does not get logged if not running in CI', function () {
|
||||
const relativePath = path.relative(cwd(), this.todosPath)
|
||||
|
||||
sinon.stub(ciProvider, 'getIsCi').returns(undefined)
|
||||
delete process.env.CYPRESS_COMMERCIAL_RECOMMENDATIONS
|
||||
globalThis.CY_TEST_MOCK.listenForProjectEnd = { stats: { failures: 1 } }
|
||||
|
||||
return cypress.start([`--run-project=${this.todosPath}`, `--spec=${relativePath}/tests/test1.js`]).then(() => {
|
||||
expect(console.log).not.to.be.calledWith(cloudRecommendationMessage)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('runs project headlessly and exits with exit code 0', function () {
|
||||
return cypress.start([`--run-project=${this.todosPath}`])
|
||||
.then(() => {
|
||||
@@ -881,6 +934,10 @@ describe('lib/cypress', () => {
|
||||
})
|
||||
|
||||
describe('config overrides', () => {
|
||||
beforeEach(function () {
|
||||
delete process.env.CYPRESS_COMMERCIAL_RECOMMENDATIONS
|
||||
})
|
||||
|
||||
it('can override default values', function () {
|
||||
return cypress.start([`--run-project=${this.todosPath}`, '--config=requestTimeout=1234,videoCompression=false'])
|
||||
.then(() => {
|
||||
@@ -1069,6 +1126,7 @@ describe('lib/cypress', () => {
|
||||
describe('--env', () => {
|
||||
beforeEach(() => {
|
||||
process.env = _.omit(process.env, 'CYPRESS_DEBUG')
|
||||
delete process.env.CYPRESS_COMMERCIAL_RECOMMENDATIONS
|
||||
|
||||
globalThis.CY_TEST_MOCK.listenForProjectEnd = { stats: { failures: 0 } }
|
||||
})
|
||||
@@ -1566,6 +1624,25 @@ describe('lib/cypress', () => {
|
||||
return snapshotConsoleLogs('CLOUD_STALE_RUN 1')
|
||||
})
|
||||
})
|
||||
|
||||
describe('cloud recommendation message', () => {
|
||||
it('does not display if --record is passed', function () {
|
||||
sinon.stub(ciProvider, 'getIsCi').returns(true)
|
||||
delete process.env.CYPRESS_COMMERCIAL_RECOMMENDATIONS
|
||||
globalThis.CY_TEST_MOCK.listenForProjectEnd = { stats: { failures: 1 } }
|
||||
|
||||
return cypress.start([
|
||||
`--run-project=${this.recordPath}`,
|
||||
'--record',
|
||||
'--key=token-123',
|
||||
'--group=electron-smoke-tests',
|
||||
'--ciBuildId=ciBuildId123',
|
||||
])
|
||||
.then(() => {
|
||||
expect(console.log).not.to.be.calledWith(cloudRecommendationMessage)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('--return-pkg', () => {
|
||||
|
||||
@@ -25,6 +25,8 @@ describe('lib/config', () => {
|
||||
|
||||
context('.get', () => {
|
||||
beforeEach(async function () {
|
||||
delete process.env.CYPRESS_COMMERCIAL_RECOMMENDATIONS
|
||||
|
||||
this.ctx = getCtx()
|
||||
|
||||
this.projectRoot = '/_test-output/path/to/project'
|
||||
|
||||
@@ -69,4 +69,6 @@ export default [
|
||||
'node_modules/prettier/parser-meriyah.js',
|
||||
'node_modules/prettier/parser-typescript.js',
|
||||
'node_modules/prettier/third-party.js',
|
||||
'packages/server/node_modules/is-ci/index.js',
|
||||
'packages/server/node_modules/ci-info/index.js',
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user