Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: adding beforeTest and AfterTest to protocol #26216

Merged
merged 12 commits into from
Mar 27, 2023
20 changes: 10 additions & 10 deletions packages/app/src/runner/event-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,10 +551,6 @@ export class EventManager {
})
})

Cypress.on('test:after:run', (test, _runnable) => {
this.reporterBus.emit('test:after:run', test, Cypress.config('isInteractive'))
})

Cypress.on('run:start', async () => {
if (Cypress.config('experimentalMemoryManagement') && Cypress.isBrowser({ family: 'chromium' })) {
await Cypress.backend('start:memory:profiling', Cypress.config('spec'))
Expand Down Expand Up @@ -597,29 +593,33 @@ export class EventManager {
})

Cypress.on('test:before:run:async', async (...args) => {
const [attr, test] = args
const [attributes, test] = args

this.reporterBus.emit('test:before:run:async', attr)
this.reporterBus.emit('test:before:run:async', attributes)

this.studioStore.interceptTest(test)

// if the experimental flag is on and we are in a chromium based browser,
// check the memory pressure to determine if garbage collection is needed
if (Cypress.config('experimentalMemoryManagement') && Cypress.isBrowser({ family: 'chromium' })) {
await Cypress.backend('check:memory:pressure', {
test: { title: test.title, order: test.order, currentRetry: test.currentRetry() },
test: { title: attributes.title, order: attributes.order, currentRetry: attributes.currentRetry },
})
}

await Cypress.backend('protocol:test:before:run:async', { id: test.id, title: test.title, wallClockStartedAt: test.wallClockStartedAt.getTime() })
await Cypress.backend('protocol:test:before:run:async', attributes)
mschile marked this conversation as resolved.
Show resolved Hide resolved

Cypress.primaryOriginCommunicator.toAllSpecBridges('test:before:run:async', ...args)
})

Cypress.on('test:after:run', (test) => {
if (this.studioStore.isOpen && test.state !== 'passed') {
Cypress.on('test:after:run', (attributes) => {
this.reporterBus.emit('test:after:run', attributes, Cypress.config('isInteractive'))

if (this.studioStore.isOpen && attributes.state !== 'passed') {
this.studioStore.testFailed()
}

Cypress.backend('protocol:test:after:run', attributes)
})

handlePausing(this.getCypress, this.reporterBus)
Expand Down
56 changes: 28 additions & 28 deletions packages/driver/cypress/e2e/commands/files.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('src/cy/commands/files', () => {

describe('#readFile', () => {
it('triggers \'read:file\' with the right options', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('read:file').resolves(okResponse)

cy.readFile('foo.json').then(() => {
expect(Cypress.backend).to.be.calledWith(
Expand All @@ -27,7 +27,7 @@ describe('src/cy/commands/files', () => {
})

it('can take encoding as second argument', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('read:file').resolves(okResponse)

cy.readFile('foo.json', 'ascii').then(() => {
expect(Cypress.backend).to.be.calledWith(
Expand All @@ -40,7 +40,7 @@ describe('src/cy/commands/files', () => {

// https://github.com/cypress-io/cypress/issues/1558
it('passes explicit null encoding through to server and decodes response', () => {
Cypress.backend.resolves({
Cypress.backend.withArgs('read:file').resolves({
contents: Buffer.from('\n'),
filePath: '/path/to/foo.json',
})
Expand All @@ -55,7 +55,7 @@ describe('src/cy/commands/files', () => {
})

it('sets the contents as the subject', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('read:file').resolves(okResponse)

cy.readFile('foo.json').then((subject) => {
expect(subject).to.equal('contents')
Expand Down Expand Up @@ -127,7 +127,7 @@ describe('src/cy/commands/files', () => {
})

it('can turn off logging', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('read:file').resolves(okResponse)

cy.readFile('foo.json', { log: false }).then(function () {
const logs = _.filter(this.logs, (log) => {
Expand All @@ -139,7 +139,7 @@ describe('src/cy/commands/files', () => {
})

it('logs immediately before resolving', function () {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('read:file').resolves(okResponse)

cy.on('log:added', (attrs, log) => {
if (attrs.name === 'readFile') {
Expand Down Expand Up @@ -238,12 +238,12 @@ describe('src/cy/commands/files', () => {
err.code = 'EISDIR'
err.filePath = '/path/to/foo'

Cypress.backend.rejects(err)
Cypress.backend.withArgs('read:file').rejects(err)

cy.on('fail', (err) => {
const { fileLog } = this

assertLogLength(this.logs, 2)
assertLogLength(this.logs, 3)
expect(fileLog.get('error')).to.eq(err)
expect(fileLog.get('state')).to.eq('failed')
expect(err.message).to.eq(stripIndent`\
Expand All @@ -270,7 +270,7 @@ describe('src/cy/commands/files', () => {
err.code = 'ENOENT'
err.filePath = '/path/to/foo.json'

Cypress.backend.rejects(err)
Cypress.backend.withArgs('read:file').rejects(err)

cy.on('fail', (err) => {
const { fileLog } = this
Expand Down Expand Up @@ -299,7 +299,7 @@ describe('src/cy/commands/files', () => {
err.code = 'ENOENT'
err.filePath = '/path/to/foo.json'

Cypress.backend.rejects(err)
Cypress.backend.withArgs('read:file').rejects(err)
let hasRetried = false

cy.on('command:retry', () => {
Expand Down Expand Up @@ -328,7 +328,7 @@ describe('src/cy/commands/files', () => {
})

it('throws a specific error when file exists when it shouldn\'t', function (done) {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('read:file').resolves(okResponse)

cy.on('fail', (err) => {
const { fileLog, logs } = this
Expand All @@ -355,7 +355,7 @@ describe('src/cy/commands/files', () => {
})

it('passes through assertion error when not about existence', function (done) {
Cypress.backend.resolves({
Cypress.backend.withArgs('read:file').resolves({
contents: 'foo',
})

Expand All @@ -378,7 +378,7 @@ describe('src/cy/commands/files', () => {
})

it('throws when the read timeout expires', function (done) {
Cypress.backend.callsFake(() => {
Cypress.backend.withArgs('read:file').callsFake(() => {
return new Cypress.Promise(() => { /* Broken promise for timeout */ })
})

Expand All @@ -402,7 +402,7 @@ describe('src/cy/commands/files', () => {
it('uses defaultCommandTimeout config value if option not provided', {
defaultCommandTimeout: 42,
}, function (done) {
Cypress.backend.callsFake(() => {
Cypress.backend.withArgs('read:file').callsFake(() => {
return new Cypress.Promise(() => { /* Broken promise for timeout */ })
})

Expand All @@ -427,7 +427,7 @@ describe('src/cy/commands/files', () => {

describe('#writeFile', () => {
it('triggers \'write:file\' with the right options', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('write:file').resolves(okResponse)

cy.writeFile('foo.txt', 'contents').then(() => {
expect(Cypress.backend).to.be.calledWith(
Expand All @@ -443,7 +443,7 @@ describe('src/cy/commands/files', () => {
})

it('can take encoding as third argument', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('write:file').resolves(okResponse)

cy.writeFile('foo.txt', 'contents', 'ascii').then(() => {
expect(Cypress.backend).to.be.calledWith(
Expand All @@ -460,7 +460,7 @@ describe('src/cy/commands/files', () => {

// https://github.com/cypress-io/cypress/issues/1558
it('explicit null encoding is sent to server as Buffer', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('write:file').resolves(okResponse)

cy.writeFile('foo.txt', Buffer.from([0, 0, 54, 255]), null).then(() => {
expect(Cypress.backend).to.be.calledWith(
Expand All @@ -476,7 +476,7 @@ describe('src/cy/commands/files', () => {
})

it('can take encoding as part of options', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('write:file').resolves(okResponse)

cy.writeFile('foo.txt', 'contents', { encoding: 'ascii' }).then(() => {
expect(Cypress.backend).to.be.calledWith(
Expand All @@ -492,27 +492,27 @@ describe('src/cy/commands/files', () => {
})

it('yields null', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('write:file').resolves(okResponse)

cy.writeFile('foo.txt', 'contents').then((subject) => {
expect(subject).to.eq(null)
})
})

it('can write a string', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('write:file').resolves(okResponse)

cy.writeFile('foo.txt', 'contents')
})

it('can write an array as json', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('write:file').resolves(okResponse)

cy.writeFile('foo.json', [])
})

it('can write an object as json', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('write:file').resolves(okResponse)

cy.writeFile('foo.json', {})
})
Expand All @@ -527,7 +527,7 @@ describe('src/cy/commands/files', () => {

describe('.flag', () => {
it('sends a flag if specified', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('write:file').resolves(okResponse)

cy.writeFile('foo.txt', 'contents', { flag: 'a+' }).then(() => {
expect(Cypress.backend).to.be.calledWith(
Expand Down Expand Up @@ -564,7 +564,7 @@ describe('src/cy/commands/files', () => {
})

it('can turn off logging', () => {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('write:file').resolves(okResponse)

cy.writeFile('foo.txt', 'contents', { log: false }).then(function () {
const logs = _.filter(this.logs, (log) => {
Expand All @@ -576,7 +576,7 @@ describe('src/cy/commands/files', () => {
})

it('logs immediately before resolving', function () {
Cypress.backend.resolves(okResponse)
Cypress.backend.withArgs('write:file').resolves(okResponse)

cy.on('log:added', (attrs, log) => {
if (attrs.name === 'writeFile') {
Expand Down Expand Up @@ -679,7 +679,7 @@ describe('src/cy/commands/files', () => {
err.code = 'WHOKNOWS'
err.filePath = '/path/to/foo.txt'

Cypress.backend.rejects(err)
Cypress.backend.withArgs('write:file').rejects(err)

cy.on('fail', (err) => {
const { lastLog } = this
Expand All @@ -705,7 +705,7 @@ describe('src/cy/commands/files', () => {
})

it('throws when the write timeout expires', function (done) {
Cypress.backend.callsFake(() => {
Cypress.backend.withArgs('write:file').callsFake(() => {
return new Cypress.Promise(() => {})
})

Expand All @@ -730,7 +730,7 @@ describe('src/cy/commands/files', () => {
it('uses defaultCommandTimeout config value if option not provided', {
defaultCommandTimeout: 42,
}, function (done) {
Cypress.backend.callsFake(() => {
Cypress.backend.withArgs('write:file').callsFake(() => {
return new Cypress.Promise(() => { /* Broken promise for timeout */ })
})

Expand Down
9 changes: 4 additions & 5 deletions packages/driver/src/cypress/runner.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable prefer-rest-params */
import _ from 'lodash'
import dayjs from 'dayjs'
import Promise from 'bluebird'
Expand All @@ -16,11 +15,11 @@ const mochaCtxKeysRe = /^(_runnable|test)$/
const betweenQuotesRe = /\"(.+?)\"/

const HOOKS = ['beforeAll', 'beforeEach', 'afterEach', 'afterAll'] as const
const TEST_BEFORE_RUN_ASYNC_EVENT = 'runner:test:before:run:async'
// event fired before hooks and test execution
const TEST_BEFORE_RUN_ASYNC_EVENT = 'runner:test:before:run:async'
const TEST_BEFORE_RUN_EVENT = 'runner:test:before:run'
const TEST_AFTER_RUN_EVENT = 'runner:test:after:run'
const TEST_AFTER_RUN_ASYNC_EVENT = 'runner:runnable:after:run:async'
const RUNNABLE_AFTER_RUN_ASYNC_EVENT = 'runner:runnable:after:run:async'

const RUNNABLE_LOGS = ['routes', 'agents', 'commands', 'hooks'] as const
const RUNNABLE_PROPS = [
Expand All @@ -34,7 +33,7 @@ const RUNNER_EVENTS = [
TEST_BEFORE_RUN_ASYNC_EVENT,
TEST_BEFORE_RUN_EVENT,
TEST_AFTER_RUN_EVENT,
TEST_AFTER_RUN_ASYNC_EVENT,
RUNNABLE_AFTER_RUN_ASYNC_EVENT,
] as const

export type HandlerType = 'error' | 'unhandledrejection'
Expand Down Expand Up @@ -76,7 +75,7 @@ const runnableAfterRunAsync = (runnable, Cypress) => {

return Promise.try(() => {
// NOTE: other events we do not fire more than once, but this needed to change for test-retries
return fire(TEST_AFTER_RUN_ASYNC_EVENT, runnable, Cypress)
return fire(RUNNABLE_AFTER_RUN_ASYNC_EVENT, runnable, Cypress)
})
}

Expand Down
7 changes: 6 additions & 1 deletion packages/server/lib/cloud/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,15 @@ class ProtocolManagerImpl implements ProtocolManager {
}

beforeTest (test) {
debug('initialize new test %O', test)
debug('before test %O', test)
this.protocol?.beforeTest(test)
}

afterTest (test) {
debug('after test %O', test)
this.protocol?.afterTest(test)
}

close () {
debug('closing')
this.protocol?.close()
Expand Down
2 changes: 2 additions & 0 deletions packages/server/lib/socket-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,8 @@ export class SocketBase {
return memory.checkMemoryPressure({ ...args[0], automation })
case 'protocol:test:before:run:async':
return this.protocolManager?.beforeTest(args[0])
case 'protocol:test:after:run':
return this.protocolManager?.afterTest(args[0])
default:
throw new Error(`You requested a backend event we cannot handle: ${eventName}`)
}
Expand Down
3 changes: 2 additions & 1 deletion packages/types/src/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ export interface AppCaptureProtocolInterface {
connectToBrowser (options: { target: string, host: string, port: number }): Promise<void>
beforeSpec (spec: SpecFile & { instanceId: string }): void
afterSpec (): void
beforeTest (test: { id: string, title: string, wallClockStartedAt: number }): void
beforeTest(test: Record<string, any>): void
afterTest(test: Record<string, any>): void
close(): void
}

Expand Down