Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f61e780
sync cloud validations in server on postinstall
cacieprins Oct 2, 2025
b35c26e
use cloud validation types in api calls
cacieprins Oct 2, 2025
f7a85d5
only download dts
cacieprins Oct 2, 2025
b4fe99b
fix logic error
cacieprins Oct 2, 2025
f0e7345
additional pre-scripts
cacieprins Oct 2, 2025
753cee9
consolidate zod versions
cacieprins Oct 2, 2025
c9a4bcf
Merge branch 'develop' into chore/use-api-typedefs
cacieprins Oct 2, 2025
36318c2
consolidate zod versions
cacieprins Oct 2, 2025
b14d51f
fix logic regarding post instance tests responses
cacieprins Oct 2, 2025
681153e
Merge branch 'develop' into chore/use-api-typedefs
cacieprins Oct 3, 2025
331519c
Update record.ts - add onError back to postInstanceTests
cacieprins Oct 7, 2025
a720aef
Merge branch 'develop' into chore/use-api-typedefs
cacieprins Oct 7, 2025
d7e2dd8
Merge branch 'develop' into chore/use-api-typedefs
cacieprins Oct 8, 2025
e108bab
lint
cacieprins Oct 10, 2025
5ff0444
Merge branch 'develop' into chore/use-api-typedefs
cacieprins Oct 10, 2025
ad06422
Merge branch 'develop' into chore/use-api-typedefs
cacieprins Oct 14, 2025
0ffa759
add packages/server as an implicit dep to v8-snapshot tooling
cacieprins Oct 14, 2025
65256e4
fetch cloud validations before @tooling/v8-snapshot build
cacieprins Oct 14, 2025
cb8b59f
run specific data-context targets to prevent circular dependency
cacieprins Oct 14, 2025
c537692
manually build server typedefs @@
cacieprins Oct 14, 2025
4485c3b
Merge branch 'develop' into chore/use-api-typedefs
cacieprins Oct 28, 2025
9b51fad
Merge branch 'develop' into chore/use-api-typedefs
cacieprins Oct 30, 2025
dfe3934
do not lint server validations
cacieprins Oct 30, 2025
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
1 change: 1 addition & 0 deletions packages/server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lib/validations
2 changes: 1 addition & 1 deletion packages/server/eslint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ export default [
},
},
{
ignores: ['test/support/fixtures/server/**/*'],
ignores: ['test/support/fixtures/server/**/*', 'lib/validations/**/*'],
},
]
28 changes: 6 additions & 22 deletions packages/server/lib/cloud/api/create_instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,13 @@ import { asyncRetry, exponentialBackoff } from '../../util/async_retry'
import * as errors from '../../errors'
import { isAxiosError } from 'axios'

const MAX_RETRIES = 3

export interface CreateInstanceResponse {
spec: string | null
instanceId: string | null
claimedInstances: number
estimatedWallClockDuration: number | null
totalInstances: number
}
// Import cloud validation types for better type safety
import type {
PostRunInstanceRequest_v2Type as CreateInstanceRequestBody,
PostRunInstanceResponse_v2 as CreateInstanceResponse,
} from '../../validations/cloudValidations'

export interface CreateInstanceRequestBody {
spec: string | null
groupId: string
machineId: string
platform: {
browserName: string
browserVersion: string
osCpus: any[]
osMemory: Record<string, any> | null
osName: string
osVersion: string
}
}
const MAX_RETRIES = 3

export const createInstance = async (runId: string, instanceData: CreateInstanceRequestBody, timeout: number = 0): Promise<CreateInstanceResponse> => {
let attemptNumber = 0
Expand Down
90 changes: 34 additions & 56 deletions packages/server/lib/cloud/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,25 @@ import type { ProjectBase } from '../../project-base'

import { PUBLIC_KEY_VERSION } from '../constants'

// axios implementation disabled until proxy issues can be diagnosed/fixed
// TODO: https://github.com/cypress-io/cypress/issues/31490
//import { createInstance } from './create_instance'
import type { CreateInstanceRequestBody, CreateInstanceResponse } from './create_instance'

import { transformError } from './axios_middleware/transform_error'
import { DecryptionError } from './cloud_request_errors'
import { isNonRetriableCertErrorCode } from '../network/non_retriable_cert_error_codes'

// Import cloud validation types for better type safety
import type {
PostRunRequest_v3Type as CreateRunRequestType,
PostRunResponse_v3Type as CreateRunResponseType,
PostRunInstanceRequest_v2Type as CreateInstanceRequestType,
PostRunInstanceResponse_v2 as CreateInstanceResponse,
PostInstanceResultsRequest_v1Type as PostInstanceResultsRequestType,
PostInstanceResultsResponse_v1Type as PostInstanceResultsResponseType,
PostInstanceTestsResponse_v1Type as PostInstanceTestsResponseType,
PutInstanceResponse_v2Type as UpdateInstanceStdoutResponseType,
PutInstanceStdoutRequest_v1Type as UpdateInstanceStdoutRequestType,
} from '../../validations/cloudValidations'

// Define response type for putInstanceArtifacts (returns z.ZodAny with resExample: {})
type PutInstanceArtifactsResponseType = any
const debug = debugModule('cypress:server:cloud:api')
const debugProtocol = debugModule('cypress:server:protocol')

Expand Down Expand Up @@ -255,47 +265,15 @@ function noProxyPreflightTimeout (): number {
}
}

export type CreateRunOptions = {
// Use cloud validation types for better type safety
export type CreateRunOptions = CreateRunRequestType & {
projectRoot: string
ci: {
params: string
provider: string
}
ciBuildId: string
projectId: string
recordKey: string
commit: string
specs: string[]
group: string
platform: string
parallel: boolean
specPattern: string[]
tags: string[]
testingType: 'e2e' | 'component'
timeout?: number
project: ProjectBase
autoCancelAfterFailures?: number | undefined
timeout?: number
}

type CreateRunResponse = {
groupId: string
machineId: string
runId: string
tags: string[] | null
runUrl: string
warnings: (Record<string, unknown> & {
code: string
message: string
name: string
})[]
captureProtocolUrl?: string | undefined
capture?: {
url?: string
tags: string[] | null
mountVersion?: number
disabledMessage?: string
} | undefined
}
// Use cloud validation types for better type safety
type CreateRunResponse = CreateRunResponseType

export type ArtifactMetadata = {
url: string
Expand Down Expand Up @@ -354,26 +332,26 @@ export default {
rp,

// For internal testing
setPreflightResult (toSet) {
setPreflightResult (toSet: any): void {
preflightResult = {
...preflightResult,
...toSet,
}
},

resetPreflightResult () {
resetPreflightResult (): void {
recordRoutes = apiRoutes
preflightResult = {
encrypt: true,
}
},

ping () {
ping (): Bluebird<any> {
return rp.get(apiRoutes.ping())
.catch(tagError)
},

getAuthUrls () {
getAuthUrls (): Bluebird<any> {
return rp.get({
url: apiRoutes.auth(),
json: true,
Expand Down Expand Up @@ -459,7 +437,7 @@ export default {
}
}

if (script) {
if (script && (options.testingType === 'e2e' || options.testingType === 'component')) {
const config = options.project.getConfig()

await options.project.protocolManager.prepareAndSetupProtocol(script, {
Expand All @@ -484,7 +462,7 @@ export default {
.catch(tagError)
},

createInstance (runId: string, body: CreateInstanceRequestBody, timeout?: number): Bluebird<CreateInstanceResponse> {
createInstance (runId: string, body: CreateInstanceRequestType, timeout?: number): Bluebird<CreateInstanceResponse> {
return retryWithBackoff((attemptIndex) => {
return rp.post({
body,
Expand All @@ -503,7 +481,7 @@ export default {
}) as Bluebird<CreateInstanceResponse>
},

postInstanceTests (options) {
postInstanceTests (options: { instanceId: string, runId: string, timeout?: number, [key: string]: any }): Bluebird<PostInstanceTestsResponseType> {
const { instanceId, runId, timeout, ...body } = options

return retryWithBackoff((attemptIndex) => {
Expand All @@ -524,7 +502,7 @@ export default {
})
},

updateInstanceStdout (options) {
updateInstanceStdout (options: UpdateInstanceStdoutRequestType & { instanceId: string, runId: string, timeout?: number }): Bluebird<UpdateInstanceStdoutResponseType> {
return retryWithBackoff((attemptIndex) => {
return rp.put({
url: recordRoutes.instanceStdout(options.instanceId),
Expand All @@ -544,7 +522,7 @@ export default {
})
},

updateInstanceArtifacts (options: UpdateInstanceArtifactsOptions, body: UpdateInstanceArtifactsPayload) {
updateInstanceArtifacts (options: UpdateInstanceArtifactsOptions, body: UpdateInstanceArtifactsPayload): Bluebird<PutInstanceArtifactsResponseType> {
debug('PUT %s %o', recordRoutes.instanceArtifacts(options.instanceId), body)

return retryWithBackoff((attemptIndex) => {
Expand All @@ -564,7 +542,7 @@ export default {
})
},

postInstanceResults (options) {
postInstanceResults (options: PostInstanceResultsRequestType & { instanceId: string, runId: string, timeout?: number }): Bluebird<PostInstanceResultsResponseType> {
return retryWithBackoff((attemptIndex) => {
return rp.post({
url: recordRoutes.instanceResults(options.instanceId),
Expand All @@ -591,7 +569,7 @@ export default {
})
},

createCrashReport (body, authToken, timeout = 3000) {
createCrashReport (body: any, authToken: string, timeout = 3000): Bluebird<any> {
return rp.post({
url: apiRoutes.exceptions(),
json: true,
Expand All @@ -604,7 +582,7 @@ export default {
.catch(tagError)
},

postLogout (authToken) {
postLogout (authToken: string): Bluebird<any> {
return Bluebird.join(
this.getAuthUrls(),
machineId(),
Expand All @@ -625,11 +603,11 @@ export default {
)
},

clearCache () {
clearCache (): void {
responseCache = {}
},

sendPreflight (preflightInfo) {
sendPreflight (preflightInfo: any): Bluebird<any> {
return retryWithBackoff(async (attemptIndex) => {
const { projectRoot, timeout, ...preflightRequestBody } = preflightInfo

Expand Down
6 changes: 4 additions & 2 deletions packages/server/lib/cloud/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ export = {
return cache.setUser(user)
},

getBaseLoginUrl (): string {
return api.getAuthUrls().get('dashboardAuthUrl')
async getBaseLoginUrl (): Promise<string> {
const res = await api.getAuthUrls()

return res!.dashboardAuthUrl
},

logOut () {
Expand Down
79 changes: 36 additions & 43 deletions packages/server/lib/modes/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ async function createInstance (options: InstanceOptions) {
}
}

const _postInstanceTests = ({
async function _postInstanceTests ({
runId,
instanceId,
config,
Expand All @@ -556,17 +556,18 @@ const _postInstanceTests = ({
parallel,
ciBuildId,
group,
}) => {
return api.postInstanceTests({
runId,
instanceId,
config,
tests,
hooks,
})
.catch((err: any) => {
throwCloudCannotProceed({ parallel, ciBuildId, group, err })
})
}) {
try {
return await api.postInstanceTests({
runId,
instanceId,
config,
tests,
hooks,
})
} catch (err: unknown) {
throw cloudCannotProceedErr({ parallel, ciBuildId, group, err })
}
}

const createRunAndRecordSpecs = (options: any = {}) => {
Expand Down Expand Up @@ -793,42 +794,34 @@ const createRunAndRecordSpecs = (options: any = {}) => {
})
.value()

const responseDidFail = {}
const response = await _postInstanceTests({
runId,
instanceId,
config: resolvedRuntimeConfig,
tests,
hooks,
parallel,
ciBuildId,
group,
})
.catch((err: any) => {
onError(err)

return responseDidFail
Copy link
Contributor

Choose a reason for hiding this comment

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

do we no longer need this logic?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's still there, just without the boolean flag. This "hanging" behavior is further down in the catch block that BugBot is complaining about.

})

if (response === responseDidFail) {
debug('`responseDidFail` equals `response`, allowing browser to hang until it is killed: Response %o', { responseDidFail })
try {
const response = await _postInstanceTests({
runId,
instanceId,
config: resolvedRuntimeConfig,
tests,
hooks,
parallel,
ciBuildId,
group,
})

// dont call the cb, let the browser hang until it's killed
return
}
if (_.some(response.actions, { type: 'SPEC', action: 'SKIP' })) {
errorsWarning('CLOUD_CANCEL_SKIPPED_SPEC')

if (_.some(response.actions, { type: 'SPEC', action: 'SKIP' })) {
errorsWarning('CLOUD_CANCEL_SKIPPED_SPEC')
// set a property on the response so the browser runner
// knows not to start executing tests
project.emit('end', { skippedSpec: true, stats: {} })

// set a property on the response so the browser runner
// knows not to start executing tests
project.emit('end', { skippedSpec: true, stats: {} })
// dont call the cb, let the browser hang until it's killed
return
}

// dont call the cb, let the browser hang until it's killed
return
return cb(response)
} catch (err: unknown) {
onError(err)
debug('postInstanceTests failed, allowing browser to hang until it is killed: Error %o', { err })
}

return cb(response)
})

return runAllSpecs({
Expand Down
Loading
Loading