Skip to content

Commit

Permalink
fix(proxy-logging): use constant consoleProps object (#18207)
Browse files Browse the repository at this point in the history
Co-authored-by: Chris Breiding <chrisbreiding@users.noreply.github.com>
  • Loading branch information
2 people authored and mjhenkes committed Jul 27, 2022
1 parent 063128b commit d5c41e8
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ const testFail = (cb, expectedDocsUrl = 'https://on.cypress.io/intercept') => {
})
}

// TODO: Network retries leak between tests, causing flake.
describe('network stubbing', { retries: 2 }, function () {
describe('network stubbing', function () {
const { $, _, sinon, state, Promise } = Cypress

beforeEach(function () {
Expand Down
4 changes: 2 additions & 2 deletions packages/driver/cypress/integration/commands/xhr_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2407,12 +2407,12 @@ describe('src/cy/commands/xhr', () => {
it('logs response', () => {
cy.then(function () {
cy.wrap(this).its('lastLog').invoke('invoke', 'consoleProps').should((consoleProps) => {
expect(consoleProps['Response Body']).to.deep.eq({
expect(consoleProps['Response Body'].trim()).to.deep.eq(JSON.stringify({
some: 'json',
foo: {
bar: 'baz',
},
})
}, null, 2))
})
})
})
Expand Down
45 changes: 39 additions & 6 deletions packages/driver/cypress/integration/cypress/proxy-logging-spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { expect } from 'chai'

describe('Proxy Logging', () => {
const { _ } = Cypress

Expand Down Expand Up @@ -43,12 +45,6 @@ describe('Proxy Logging', () => {
}
}

beforeEach(() => {
// block race conditions caused by log update debouncing
// @ts-ignore
Cypress.config('logAttrsDelay', 0)
})

context('request logging', () => {
it('fetch log shows resource type, url, method, and status code and has expected snapshots and consoleProps', (done) => {
fetch('/some-url')
Expand Down Expand Up @@ -106,6 +102,43 @@ describe('Proxy Logging', () => {
})
})

// @see https://github.com/cypress-io/cypress/issues/17656
it('xhr log has response body/status code', (done) => {
cy.window()
.then((win) => {
cy.on('log:changed', (log) => {
try {
expect(log.snapshots.map((v) => v.name)).to.deep.eq(['request', 'response'])
expect(log.consoleProps['Response Headers']).to.include({
'x-powered-by': 'Express',
})

expect(log.consoleProps['Response Body']).to.include('Cannot GET /some-url')
expect(log.consoleProps['Response Status Code']).to.eq(404)

expect(log.renderProps).to.include({
indicator: 'bad',
message: 'GET 404 /some-url',
})

expect(Object.keys(log.consoleProps)).to.deep.eq(
['Event', 'Resource Type', 'Method', 'URL', 'Request went to origin?', 'XHR', 'groups', 'Request Headers', 'Response Status Code', 'Response Headers', 'Response Body'],
)

done()
} catch (err) {
// eslint-disable-next-line no-console
console.log('assertion error, retrying', err)
}
})

const xhr = new win.XMLHttpRequest()

xhr.open('GET', '/some-url')
xhr.send()
})
})

it('does not log an unintercepted non-xhr/fetch request', (done) => {
const img = new Image()
const logs: any[] = []
Expand Down
11 changes: 0 additions & 11 deletions packages/driver/src/cypress/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ const SNAPSHOT_PROPS = 'id snapshots $el url coords highlightAttr scrollBy viewp
const DISPLAY_PROPS = 'id alias aliasType callCount displayName end err event functionName hookId instrument isStubbed group message method name numElements showError numResponses referencesAlias renderProps state testId timeout type url visible wallClockStartedAt testCurrentRetry'.split(' ')
const BLACKLIST_PROPS = 'snapshots'.split(' ')

let delay = null
let counter = 0

const { HIGHLIGHT_ATTR } = $Snapshots
Expand Down Expand Up @@ -113,10 +112,6 @@ const setCounter = (num) => {
return counter = num
}

const setDelay = (val) => {
return delay = val != null ? val : 4
}

const defaults = function (state, config, obj) {
const instrument = obj.instrument != null ? obj.instrument : 'command'

Expand Down Expand Up @@ -523,12 +518,6 @@ export default {
counter = 0
const logs = {}

// give us the ability to change the delay for firing
// the change event, or default it to 4
if (delay == null) {
delay = setDelay(config('logAttrsDelay'))
}

const trigger = function (log, event) {
// bail if we never fired our initial log event
if (!log._hasInitiallyLogged) {
Expand Down
152 changes: 91 additions & 61 deletions packages/driver/src/cypress/proxy-logging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,66 +87,7 @@ function getRequestLogConfig (req: Omit<ProxyRequest, 'log'>): Partial<Cypress.L
url: req.preRequest.url,
method: req.preRequest.method,
timeout: 0,
consoleProps: () => {
// high-level request information
const consoleProps = {
'Resource Type': req.preRequest.resourceType,
Method: req.preRequest.method,
URL: req.preRequest.url,
'Request went to origin?': req.flags.stubbed ? 'no (response was stubbed, see below)' : 'yes',
}

if (req.flags.reqModified) consoleProps['Request modified?'] = 'yes'

if (req.flags.resModified) consoleProps['Response modified?'] = 'yes'

// details on matched XHR/intercept
if (req.xhr) consoleProps['XHR'] = req.xhr.xhr

if (req.interceptions.length) {
if (req.interceptions.length > 1) {
consoleProps['Matched `cy.intercept()`s'] = req.interceptions.map(formatInterception)
} else {
consoleProps['Matched `cy.intercept()`'] = formatInterception(req.interceptions[0])
}
}

if (req.stack) {
consoleProps['groups'] = () => {
return [
{
name: 'Initiator',
items: [req.stack],
label: false,
},
]
}
}

// details on request/response/errors
consoleProps['Request Headers'] = req.preRequest.headers

if (req.responseReceived) {
_.assign(consoleProps, {
'Response Status Code': req.responseReceived.status,
'Response Headers': req.responseReceived.headers,
})
}

let resBody

if (req.xhr) {
consoleProps['Response Body'] = req.xhr.responseBody
} else if ((resBody = _.chain(req.interceptions).last().get('interception.response.body').value())) {
consoleProps['Response Body'] = resBody
}

if (req.error) {
consoleProps['Error'] = req.error
}

return consoleProps
},
consoleProps: () => req.consoleProps,
renderProps: () => {
function getIndicator (): 'aborted' | 'pending' | 'successful' | 'bad' {
if (!req.responseReceived) {
Expand Down Expand Up @@ -211,9 +152,89 @@ class ProxyRequest {
resModified?: boolean
} = {}

// constant reference to consoleProps so changes reach the console
// @see https://github.com/cypress-io/cypress/issues/17656
readonly consoleProps: any

constructor (preRequest: BrowserPreRequest, opts?: Partial<ProxyRequest>) {
this.preRequest = preRequest
opts && _.assign(this, opts)

// high-level request information
this.consoleProps = {
'Resource Type': preRequest.resourceType,
Method: preRequest.method,
URL: preRequest.url,
}

this.updateConsoleProps()
}

updateConsoleProps () {
const { consoleProps } = this

consoleProps['Request went to origin?'] = this.flags.stubbed ? 'no (response was stubbed, see below)' : 'yes'

if (this.flags.reqModified) consoleProps['Request modified?'] = 'yes'

if (this.flags.resModified) consoleProps['Response modified?'] = 'yes'

// details on matched XHR/intercept
if (this.xhr) consoleProps['XHR'] = this.xhr.xhr

if (this.interceptions.length) {
if (this.interceptions.length > 1) {
consoleProps['Matched `cy.intercept()`s'] = this.interceptions.map(formatInterception)
} else {
consoleProps['Matched `cy.intercept()`'] = formatInterception(this.interceptions[0])
}
}

if (this.stack) {
consoleProps['groups'] = () => {
return [
{
name: 'Initiator',
items: [this.stack],
label: false,
},
]
}
}

// ensure these fields are always ordered correctly regardless of when they are added
['Response Status Code', 'Response Headers', 'Response Body', 'Request Headers', 'Request Body'].forEach((k) => delete consoleProps[k])

// details on request
consoleProps['Request Headers'] = this.preRequest.headers

const reqBody = _.chain(this.interceptions).last().get('interception.request.body').value()

if (reqBody) consoleProps['Request Body'] = reqBody

if (this.responseReceived) {
_.assign(consoleProps, {
'Response Status Code': this.responseReceived.status,
'Response Headers': this.responseReceived.headers,
})
}

// details on response
let resBody

if (this.xhr) {
if (!consoleProps['Response Headers']) consoleProps['Response Headers'] = this.xhr.responseHeaders

if (!consoleProps['Response Status Code']) consoleProps['Response Status Code'] = this.xhr.xhr.status

consoleProps['Response Body'] = this.xhr.xhr.response
} else if ((resBody = _.chain(this.interceptions).last().get('interception.response.body').value())) {
consoleProps['Response Body'] = resBody
}

if (this.error) {
consoleProps['Error'] = this.error
}
}

setFlag = (flag: keyof ProxyRequest['flags']) => {
Expand Down Expand Up @@ -310,7 +331,15 @@ export default class ProxyLogging {
}

proxyRequest.responseReceived = responseReceived
proxyRequest.log?.snapshot('response').end()

proxyRequest.updateConsoleProps()

// @ts-ignore
const hasResponseSnapshot = proxyRequest.log?.get('snapshots')?.find((v) => v.name === 'response')

if (!hasResponseSnapshot) proxyRequest.log?.snapshot('response')

proxyRequest.log?.end()
}

private updateRequestWithError (error: RequestError): void {
Expand All @@ -321,6 +350,7 @@ export default class ProxyLogging {
}

proxyRequest.error = $errUtils.makeErrFromObj(error.error)
proxyRequest.updateConsoleProps()
proxyRequest.log?.snapshot('error').error(proxyRequest.error)
}

Expand Down

1 comment on commit d5c41e8

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on d5c41e8 Jul 27, 2022

Choose a reason for hiding this comment

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

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/8.6.0/circle-matth/fix/hang-investigation-d5c41e8a00cbebc9faf47eb86c6f04cd1a837928/cypress.tgz

Please sign in to comment.