Files
cypress/system-tests/lib/protocol-stubs/protocolStub.ts
T
Ryan Manuel bd4774fb57 chore: pass file preprocesor override to protocol as debug data (#31171)
* chore: set up sharing of react via module federation in studio

* chore: add ability to load types from the studio bundle

* fix build

* fix build

* fix build

* chore: pass file preprocesor override to protocol as debug data

* fix tests

* PR comments

* PR comment

* update types
2025-03-03 12:52:01 -06:00

203 lines
5.0 KiB
TypeScript

import path from 'path'
import fs from 'fs-extra'
import type { AppCaptureProtocolInterface, ProtocolManagerOptions, ResponseEndedWithEmptyBodyOptions, ResponseStreamOptions, ResponseStreamTimedOutOptions } from '@packages/types'
import type { Readable } from 'stream'
const getFilePath = (filename) => {
return path.join(
path.resolve(__dirname),
'cypress',
'system-tests-protocol-dbs',
`${filename}.json`,
)
}
const CDP_EVENT_DRAIN_DURATION = 1
const AUT_EVENT_DRAIN_DURATION = 5
const BODY_PROMISES_DURATION = 7
const CLOSE_DB_DURATION = 11
const TEARDOWN_BINDINGS_DURATION = 13
const DURATIONS = {
drainCDPEvents: CDP_EVENT_DRAIN_DURATION,
drainAUTEvents: AUT_EVENT_DRAIN_DURATION,
resolveBodyPromises: BODY_PROMISES_DURATION,
closeDb: CLOSE_DB_DURATION,
teardownBindings: TEARDOWN_BINDINGS_DURATION,
}
export class AppCaptureProtocol implements AppCaptureProtocolInterface {
private filename: string
private events = {
debugData: {},
beforeSpec: [],
afterSpec: [],
beforeTest: [],
preAfterTest: [],
afterTest: [],
addRunnables: [],
connectToBrowser: [],
commandLogAdded: [],
commandLogChanged: [],
viewportChanged: [],
urlChanged: [],
pageLoading: [],
resetTest: [],
responseEndedWithEmptyBody: [],
responseStreamTimedOut: [],
}
private cdpClient: any
private scriptToEvaluateId: any
constructor (options: ProtocolManagerOptions) {
this.events.debugData = options.debugData
}
getDbMetadata (): { offset: number, size: number } {
return {
offset: 0,
size: 0,
}
}
responseStreamReceived (options: ResponseStreamOptions): Readable {
return options.responseStream
}
resetEvents () {
this.events.beforeTest = []
this.events.preAfterTest = []
this.events.afterTest = []
this.events.commandLogAdded = []
this.events.commandLogChanged = []
this.events.viewportChanged = []
this.events.urlChanged = []
this.events.pageLoading = []
this.events.responseEndedWithEmptyBody = []
this.events.responseStreamTimedOut = []
}
connectToBrowser = async (cdpClient) => {
if (cdpClient) {
this.events.connectToBrowser.push(true)
this.cdpClient = cdpClient
}
const scriptToEvaluateResult = await this.cdpClient.send(
'Page.addScriptToEvaluateOnNewDocument',
{
source: `(function () {})()`,
},
)
this.scriptToEvaluateId = scriptToEvaluateResult.identifier
}
addRunnables = (runnables) => {
this.events.addRunnables.push(runnables)
return Promise.resolve()
}
beforeSpec = ({ archivePath, db }) => {
this.events.beforeSpec.push(db)
this.filename = getFilePath(path.basename(db.name))
if (!fs.existsSync(archivePath)) {
// If a dummy file hasn't been created by the test, write a tar file so that it can be fake uploaded
fs.writeFileSync(archivePath, '')
}
}
async afterSpec () {
this.events.afterSpec.push(true)
// since the order of the logs can vary per run, we sort them by id to ensure the snapshot can be compared
this.events.commandLogChanged.sort((log1, log2) => {
return log1.id.localeCompare(log2.id)
})
try {
fs.outputFileSync(this.filename, JSON.stringify(this.events, null, 2))
} catch (e) {
console.log('error writing protocol events', e)
}
await this.cdpClient.send('Page.removeScriptToEvaluateOnNewDocument', {
identifier: this.scriptToEvaluateId || '',
})
.catch(() => {
})
return { durations: DURATIONS }
}
beforeTest = (test) => {
this.events.beforeTest.push(test)
return Promise.resolve()
}
commandLogAdded = (log) => {
// we only care about logs that occur during a test
if (log.testId) {
this.events.commandLogAdded.push(log)
}
}
commandLogChanged = (log) => {
// we only care about logs that occur during a test and
// since the number of log changes can vary per run, we only want to record
// the passed/failed ones to ensure the snapshot can be compared
if (log.testId && (log.state === 'passed' || log.state === 'failed')) {
this.events.commandLogChanged.push(log)
}
}
viewportChanged = (input) => {
this.events.viewportChanged.push(input)
}
urlChanged = (input) => {
this.events.urlChanged.push(input)
}
pageLoading = (input) => {
this.events.pageLoading.push(input)
}
preAfterTest = (test, options) => {
this.events.preAfterTest.push({ test, options })
return Promise.resolve()
}
afterTest = (test) => {
this.events.afterTest.push(test)
return Promise.resolve()
}
responseEndedWithEmptyBody = (options: ResponseEndedWithEmptyBodyOptions) => {
this.events.responseEndedWithEmptyBody.push(options)
}
responseStreamTimedOut (options: ResponseStreamTimedOutOptions): void {
this.events.responseStreamTimedOut.push(options)
}
resetTest (testId: string): void {
this.resetEvents()
this.events.resetTest.push(testId)
}
async cdpReconnect (): Promise<void> {
}
}