Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ _Released 11/18/2025 (PENDING)_
- Fixed an issue where [`cy.wrap()`](https://docs.cypress.io/api/commands/wrap) would cause infinite recursion and freeze the Cypress App when called with objects containing circular references. Fixes [#24715](https://github.com/cypress-io/cypress/issues/24715). Addressed in [#32917](https://github.com/cypress-io/cypress/pull/32917).
- Fixed an issue where top changes on test retries could cause attempt numbers to show up more than one time in the reporter and cause attempts to be lost in Test Replay. Addressed in [#32888](https://github.com/cypress-io/cypress/pull/32888).
- Fixed an issue where stack traces that are used to determine a test's invocation details are sometimes incorrect. Addressed in [#32699](https://github.com/cypress-io/cypress/pull/32699)
- Fixed an issue where larger than expected config values were causing issues in certain cases when recording to the Cypress Cloud. Addressed in [#32957](https://github.com/cypress-io/cypress/pull/32957)


**Misc:**

Expand Down
8 changes: 6 additions & 2 deletions packages/server/lib/cloud/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import type { CreateInstanceRequestBody, CreateInstanceResponse } from './create
import { transformError } from './axios_middleware/transform_error'
import { DecryptionError } from './cloud_request_errors'
import { isNonRetriableCertErrorCode } from '../network/non_retriable_cert_error_codes'
import { filterRuntimeConfigForRecording } from '../../config'

const debug = debugModule('cypress:server:cloud:api')
const debugProtocol = debugModule('cypress:server:protocol')
Expand Down Expand Up @@ -506,7 +507,7 @@ export default {
},

postInstanceTests (options) {
const { instanceId, runId, timeout, ...body } = options
const { instanceId, runId, timeout, config, ...body } = options

return retryWithBackoff((attemptIndex) => {
return rp.post({
Expand All @@ -519,7 +520,10 @@ export default {
'x-cypress-run-id': runId,
'x-cypress-request-attempt': attemptIndex,
},
body,
body: {
...body,
config: filterRuntimeConfigForRecording(config ?? {}),
},
})
.catch(RequestErrors.StatusCodeError, transformError)
.catch(tagError)
Expand Down
28 changes: 21 additions & 7 deletions packages/server/lib/config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
import _ from 'lodash'
import type { ResolvedFromConfig } from '@packages/types'
import * as configUtils from '@packages/config'

export const setUrls = configUtils.setUrls

export function getResolvedRuntimeConfig (config, runtimeConfig) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this as it's no longer needed if we're dropping resolved from the API call

const resolvedRuntimeFields = _.mapValues(runtimeConfig, (v): ResolvedFromConfig => ({ value: v, from: 'runtime' }))
// Strips out values that can be aribitrarily sized / are duplicated from config
// payload sent for recording
export function filterRuntimeConfigForRecording (config) {
const { rawJson, devServer, env, resolved, ...configRest } = config
const { webpackConfig, viteConfig, ...devServerRest } = devServer ?? {}
const resultConfig = { ...configRest }

return {
...config,
...runtimeConfig,
resolved: { ...config.resolved, ...resolvedRuntimeFields },
if (env) {
resultConfig.env = _.mapValues(env ?? {}, (val, key) => `omitted: ${typeof val}`)
}

if (devServer) {
resultConfig.devServer = { ...devServerRest }
if (typeof webpackConfig !== 'undefined') {
resultConfig.devServer.webpackConfig = `omitted`
}

if (typeof viteConfig !== 'undefined') {
resultConfig.devServer.viteConfig = `omitted`
}
}

return resultConfig
}
3 changes: 1 addition & 2 deletions packages/server/lib/modes/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { getError } from '@packages/errors'
import type { AllCypressErrorNames } from '@packages/errors'
import { get as getErrors, warning as errorsWarning, throwErr } from '../errors'
import * as capture from '../capture'
import { getResolvedRuntimeConfig } from '../config'
import * as env from '../util/env'
import ciProvider from '../util/ci_provider'
import { flattenSuiteIntoRunnables } from '../util/tests_utils'
Expand Down Expand Up @@ -754,7 +753,7 @@ const createRunAndRecordSpecs = (options: any = {}) => {

const r = flattenSuiteIntoRunnables(runnables)
const runtimeConfig = runnables.runtimeConfig
const resolvedRuntimeConfig = getResolvedRuntimeConfig(config, runtimeConfig)
const resolvedRuntimeConfig = { ...config, ...runtimeConfig }

const tests = _.chain(r[0])
.uniqBy('id')
Expand Down
56 changes: 55 additions & 1 deletion packages/server/test/unit/cloud/api/api_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require('../../../spec_helper')
const _ = require('lodash')
const os = require('os')
const encryption = require('../../../../lib/cloud/encryption')
const { filterRuntimeConfigForRecording } = require('../../../../lib/config')

const {
agent,
Expand Down Expand Up @@ -987,7 +988,7 @@ describe('lib/cloud/api', () => {
this.bodyProps = _.omit(this.props, 'instanceId', 'runId')
})

it('POSTs /instances/:id/results', function () {
it('POSTs /instances/:id/tests', function () {
nock(API_BASEURL)
.matchHeader('x-route-version', '1')
.matchHeader('x-cypress-run-id', this.props.runId)
Expand All @@ -1000,6 +1001,59 @@ describe('lib/cloud/api', () => {
return api.postInstanceTests(this.props)
})

it('POSTs /instances/:id/tests strips arbitrarily large config values', function () {
this.props.config = {
projectId: 'abcd1234',
devServer: {
bundler: 'webpack',
framework: 'react',
webpackConfig: 'a'.repeat(10000),
viteConfig: 'a'.repeat(10000),
},
env: {
NUMERIC_VALUE: 1,
TRUTHY_VALUE: true,
SOME_REALLY_LONG_VALUE: 'a'.repeat(10000),
},
resolved: {
env: {
'NUMERIC_VALUE': { 'value': 1, 'from': 'env' },
'TRUTHY_VALUE': { 'value': true, 'from': 'env' },
'SOME_REALLY_LONG_VALUE': { 'value': 'a'.repeat(10000), 'from': 'env' },
},
},
}

this.props.config.rawJson = _.cloneDeep(this.props.config)

const expectedConfig = filterRuntimeConfigForRecording(this.props.config)

nock(API_BASEURL)
.matchHeader('x-route-version', '1')
.matchHeader('x-cypress-run-id', this.props.runId)
.matchHeader('x-cypress-request-attempt', '0')
.matchHeader('x-os-name', OS_PLATFORM)
.matchHeader('x-cypress-version', pkg.version)
.post('/instances/instance-id-123/tests', {
...this.bodyProps,
config: expectedConfig,
})
.reply(200)

expect(expectedConfig.projectId).to.eq('abcd1234')
expect(expectedConfig.env).to.eql({
NUMERIC_VALUE: `omitted: number`,
TRUTHY_VALUE: `omitted: boolean`,
SOME_REALLY_LONG_VALUE: `omitted: string`,
})

expect(expectedConfig.resolved).to.be.undefined
expect(expectedConfig.devServer.webpackConfig).to.equal('omitted')
expect(expectedConfig.devServer.viteConfig).to.equal('omitted')

return api.postInstanceTests(this.props)
})

it('PUT /instances/:id failure formatting', () => {
nock(API_BASEURL)
.matchHeader('x-route-version', '1')
Expand Down
9 changes: 0 additions & 9 deletions system-tests/test/record_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -602,16 +602,7 @@ describe('e2e record', () => {
const requests = getRequests()

expect(requests[2].body.config.defaultCommandTimeout).eq(1111)
expect(requests[2].body.config.resolved.defaultCommandTimeout).deep.eq({
value: 1111,
from: 'runtime',
})

expect(requests[2].body.config.pageLoadTimeout).eq(3333)
expect(requests[2].body.config.resolved.pageLoadTimeout).deep.eq({
value: 3333,
from: 'runtime',
})

expect(requests[2].body.tests[0].config).deep.eq({
defaultCommandTimeout: 1234,
Expand Down
Loading