Skip to content

Commit

Permalink
Merge branch 'develop' into feature-multidomain
Browse files Browse the repository at this point in the history
  • Loading branch information
mjhenkes committed Apr 6, 2022
2 parents 81e9283 + d0fc93b commit 0772f85
Show file tree
Hide file tree
Showing 23 changed files with 761 additions and 197 deletions.
2 changes: 1 addition & 1 deletion circle.yml
Expand Up @@ -40,7 +40,7 @@ macWorkflowFilters: &mac-workflow-filters
or:
- equal: [ develop, << pipeline.git.branch >> ]
- equal: [ feature-multidomain, << pipeline.git.branch >> ]
- equal: [ use-contexts, << pipeline.git.branch >> ]
- equal: [ new-cmd-group-9.x, << pipeline.git.branch >> ]
- matches:
pattern: "-release$"
value: << pipeline.git.branch >>
Expand Down
1 change: 1 addition & 0 deletions cli/types/cypress.d.ts
Expand Up @@ -5764,6 +5764,7 @@ declare namespace Cypress {
name: string
/** Override *name* for display purposes only */
displayName: string
/** additional information to include in the log */
message: any
/** Set to false if you want to control the finishing of the command in the log yourself */
autoEnd: boolean
Expand Down
2 changes: 1 addition & 1 deletion packages/driver/src/cy/commands/xhr.ts
Expand Up @@ -201,7 +201,7 @@ const startXhrServer = (cy, state, config) => {

Cypress.ProxyLogging.addXhrLog({ xhr, route, log, stack })

return log.snapshot('request')
return log?.snapshot('request')
},

onLoad: (xhr) => {
Expand Down
42 changes: 42 additions & 0 deletions packages/driver/src/cy/logGroup.ts
@@ -0,0 +1,42 @@
import { $Command } from '../cypress/command'
import $errUtils from '../cypress/error_utils'

export default (Cypress, userOptions: Cypress.LogGroup.Config, fn: Cypress.LogGroup.ApiCallback) => {
const cy = Cypress.cy

const shouldEmitLog = userOptions.log === undefined ? true : userOptions.log

const options: Cypress.InternalLogConfig = {
...userOptions,
instrument: 'command',
groupStart: true,
emitOnly: !shouldEmitLog,
}

const log = Cypress.log(options)

if (!_.isFunction(fn)) {
$errUtils.throwErrByPath('group.missing_fn', { onFail: log })
}

// An internal command is inserted to create a divider between
// commands inside group() callback and commands chained to it.
const restoreCmdIndex = cy.state('index') + 1

const endLogGroupCmd = $Command.create({
name: 'end-logGroup',
injected: true,
})

const forwardYieldedSubject = () => {
if (log) {
log.endGroup()
}

return endLogGroupCmd.get('prev').get('subject')
}

cy.queue.insert(restoreCmdIndex, endLogGroupCmd.set('fn', forwardYieldedSubject))

return fn(log)
}
2 changes: 1 addition & 1 deletion packages/driver/src/cy/multi-domain/index.ts
Expand Up @@ -128,7 +128,7 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,

const _reject = (err) => {
cleanup()
log.error(err)
log?.error(err)
reject(err)
}

Expand Down
4 changes: 2 additions & 2 deletions packages/driver/src/cy/net-stubbing/route-matcher-log.ts
Expand Up @@ -22,8 +22,8 @@ export function getDisplayUrlMatcher (matcher: RouteMatcherOptions): string {
return $utils.stringify(displayMatcher)
}

export function getRouteMatcherLogConfig (matcher: RouteMatcherOptions, isStubbed: boolean, alias: string | void, staticResponse?: StaticResponse): Partial<Cypress.LogConfig> {
const obj: Partial<Cypress.LogConfig> = {
export function getRouteMatcherLogConfig (matcher: RouteMatcherOptions, isStubbed: boolean, alias: string | void, staticResponse?: StaticResponse): Partial<Cypress.InternalLogConfig> {
const obj: Partial<Cypress.InternalLogConfig> = {
name: 'route',
method: String(matcher.method || '*'),
url: getDisplayUrlMatcher(matcher),
Expand Down
4 changes: 3 additions & 1 deletion packages/driver/src/cypress/error_messages.ts
Expand Up @@ -583,7 +583,9 @@ export default {
docsUrl: 'https://on.cypress.io/go',
},
},

group: {
missing_fn: '`group` API must be called with a function.',
},
hover: {
not_implemented: {
message: [
Expand Down
40 changes: 22 additions & 18 deletions packages/driver/src/cypress/log.ts
Expand Up @@ -112,7 +112,7 @@ export const LogUtils = {
},
}

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

// dont set any defaults if this
Expand All @@ -129,7 +129,7 @@ const defaults = function (state, config, obj) {
// but in cases where the command purposely does not log
// then it could still be logged during a failure, which
// is why we normalize its type value
if (!parentOrChildRe.test(obj.type)) {
if (typeof obj.type === 'string' && !parentOrChildRe.test(obj.type)) {
// does this command have a previously linked command
// by chainer id
obj.type = (current != null ? current.hasPreviouslyLinkedCommand() : undefined) ? 'child' : 'parent'
Expand Down Expand Up @@ -206,26 +206,26 @@ const defaults = function (state, config, obj) {
},
})

const logGroup = _.last(state('logGroup'))
const logGroupIds = state('logGroupIds') || []

if (logGroup) {
obj.group = logGroup
if (logGroupIds.length) {
obj.group = _.last(logGroupIds)
}

if (obj.groupEnd) {
state('logGroup', _.slice(state('logGroup'), 0, -1))
state('logGroupIds', _.slice(logGroupIds, 0, -1))
}

if (obj.groupStart) {
state('logGroup', (state('logGroup') || []).concat(obj.id))
state('logGroupIds', (logGroupIds).concat(obj.id))
}

return obj
}

class Log {
cy: any
state: any
state: Cypress.State
config: any
fireChangeEvent: ((log) => (void | undefined))
obj: any
Expand All @@ -236,7 +236,8 @@ class Log {
this.cy = cy
this.state = state
this.config = config
this.fireChangeEvent = fireChangeEvent
// only fire the log:state:changed event as fast as every 4ms
this.fireChangeEvent = _.debounce(fireChangeEvent, 4)
this.obj = defaults(state, config, obj)

extendEvents(this)
Expand Down Expand Up @@ -376,6 +377,13 @@ class Log {
}

error (err) {
const logGroupIds = this.state('logGroupIds') || []

// current log was responsible to creating the current log group so end the current group
if (_.last(logGroupIds) === this.attributes.id) {
this.endGroup()
}

this.set({
ended: true,
error: err,
Expand Down Expand Up @@ -404,6 +412,10 @@ class Log {
return this
}

endGroup () {
this.state('logGroupIds', _.slice(this.state('logGroupIds'), 0, -1))
}

getError (err) {
return err.stack || err.message
}
Expand Down Expand Up @@ -561,16 +573,8 @@ class LogManager {
this.logs[id] = true
}

// only fire the log:state:changed event
// as fast as every 4ms
fireChangeEvent (log) {
const triggerStateChanged = () => {
return this.trigger(log, 'command:log:changed')
}

const debounceFn = _.debounce(triggerStateChanged, 4)

return debounceFn()
return this.trigger(log, 'command:log:changed')
}

createLogFn (cy, state, config) {
Expand Down
6 changes: 3 additions & 3 deletions packages/driver/src/cypress/proxy-logging.ts
Expand Up @@ -50,7 +50,7 @@ function getDisplayUrl (url: string) {
return url
}

function getDynamicRequestLogConfig (req: Omit<ProxyRequest, 'log'>): Partial<Cypress.LogConfig> {
function getDynamicRequestLogConfig (req: Omit<ProxyRequest, 'log'>): Partial<Cypress.InternalLogConfig> {
const last = _.last(req.interceptions)
let alias = last ? last.interception.request.alias || last.route.alias : undefined

Expand All @@ -64,7 +64,7 @@ function getDynamicRequestLogConfig (req: Omit<ProxyRequest, 'log'>): Partial<Cy
}
}

function getRequestLogConfig (req: Omit<ProxyRequest, 'log'>): Partial<Cypress.LogConfig> {
function getRequestLogConfig (req: Omit<ProxyRequest, 'log'>): Partial<Cypress.InternalLogConfig> {
function getStatus (): string | undefined {
const { stubbed, reqModified, resModified } = req.flags

Expand Down Expand Up @@ -392,7 +392,7 @@ export default class ProxyLogging {
const proxyRequest = new ProxyRequest(preRequest)
const logConfig = getRequestLogConfig(proxyRequest as Omit<ProxyRequest, 'log'>)

proxyRequest.log = this.Cypress.log(logConfig).snapshot('request')
proxyRequest.log = this.Cypress.log(logConfig)?.snapshot('request')

this.proxyRequests.push(proxyRequest as ProxyRequest)

Expand Down
7 changes: 3 additions & 4 deletions packages/driver/src/cypress/runner.ts
Expand Up @@ -1774,10 +1774,9 @@ export default {
test = getTestById(testId)

if (test) {
// pluralize the instrument
// as a property on the runnable
let name
const logs = test[name = `${instrument}s`] != null ? test[name] : (test[name] = [])
// pluralize the instrument as a property on the runnable
const name = `${instrument}s`
const logs = test[name] != null ? test[name] : (test[name] = [])

// else push it onto the logs
return logs.push(attrs)
Expand Down
27 changes: 27 additions & 0 deletions packages/driver/types/cy/logGroup.d.ts
@@ -0,0 +1,27 @@
// The type declarations for Cypress Log Group & the corresponding configuration permutations
declare namespace Cypress {
declare namespace LogGroup {
type ApiCallback = (log: Cypress.Log) => Chainable<S>
type LogGroup = (cypress: Cypress.Cypress, options: Partial<LogGroupConfig>, callback: LogGroupCallback) => Chainable<S>

interface Config {
// the JQuery element for the command. This will highlight the command
// in the main window when debugging
$el?: JQuery
// whether or not to emit a log to the UI
// when disabled, child logs will not be nested in the UI
log?: boolean
// name of the group - defaults to current command's name
name?: string
// additional information to include in the log
message?: string
// timeout of the group command - defaults to defaultCommandTimeout
timeout?: number
// the type of log
// system - log generated by Cypress
// parent - log generated by Command
// child - log generated by Chained Command
type?: Cypress.InternalLogConfig['type']
}
}
}
119 changes: 119 additions & 0 deletions packages/driver/types/cypress/log.d.ts
@@ -0,0 +1,119 @@
// The type declarations for Cypress Logs & the corresponding configuration permutations
declare namespace Cypress {
interface Cypress {
log(options: Partial<LogConfig | InternalLogConfig>): Log | undefined
}

interface Log extends Log {
set<K extends keyof LogConfig | InternalLogConfig>(key: K, value: LogConfig[K]): InternalLog
set(options: Partial<LogConfig | InternalLogConfig>)
groupEnd(): void
}

type ReferenceAlias = {
cardinal: number,
name: string,
ordinal: string,
}

type Snapshot = {
body?: {get: () => any},
htmlAttrs?: {[key: string]: any},
name?: string
}

type ConsoleProps = {
Command?: string
Snapshot?: string
Elements?: number
Selector?: string
Yielded?: HTMLElement
Event?: string
Message?: string
actual?: any
expected?: any
}

type RenderProps = {
indicator?: 'aborted' | 'pending' | 'successful' | 'bad'
message?: string
}

interface InternalLogConfig {
// the JQuery element for the command. This will highlight the command
// in the main window when debugging
$el?: JQuery | string
alias?: string
aliasType?: 'agent' | 'route' | 'primitive' | 'dom' | undefined
browserPreRequest?: any
callCount?: number
chainerId?: string
commandName?: string
// provide the content to display in the dev tool's console when a log is
// clicked from the Reporter's Command Log
consoleProps?: () => Command | Command
coords?: {
left: number
leftCenter: number
top: number
topCenter: number
x: number
y: number
}
count?: number
// the name override for display purposes only
displayName?: string
// whether or not to show the log in the Reporter UI or only
// store the log details on the command and log manager
emitOnly?: boolean
end?: boolean
ended?: boolean
err?: Error
error?: Error
// whether or not the generated log was an event or command
event?: boolean
expected?: string
functionName?: string
// whether or not to start a new log group
groupStart?: boolean
hookId?: number
id?: string
// defaults to command
instrument?: 'agent' | 'command' | 'route'
// whether or not the xhr route had a corresponding response stubbed out
isStubbed?: boolean
// additional information to include in the log if not overridden
// the render props message
// defaults to command arguments for command instrument
message?: string | Array<string> | any[]
method?: string
// name of the log
name?: string
numElements?: number
// the number of xhr responses that occurred. This is only applicable to
// logs defined with instrument=route
numResponses?: number
referencesAlias?: ReferenceAlias[]
renderProps?: () => RenderProps | RenderProps
response?: string | object
selector?: any
snapshot?: boolean
snapshots?: []
state?: "failed" | "passed" | "pending" // representative of Mocha.Runnable.constants (not publicly exposed by Mocha types)
status?: number
testCurrentRetry?: number
testId?: string
// timeout of the group command - defaults to defaultCommandTimeout
timeout?: number
// the type of log
// system - log generated by Cypress
// parent - log generated by Command
// child - log generated by Chained Command
type?: 'system' | 'parent' | 'child' | ((current: State['state']['current'], subject: State['state']['subject']) => 'parent' | 'child')
url?: string
viewportHeight?: number
viewportWidth?: number
visible?: boolean
wallClockStartedAt?: string
}
}

2 comments on commit 0772f85

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 0772f85 Apr 6, 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/9.6.0/linux-x64/feature-multidomain-0772f8557be5d8beb8715b16ae33029b818e8c2f/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 0772f85 Apr 6, 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 win32 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/9.6.0/win32-x64/feature-multidomain-0772f8557be5d8beb8715b16ae33029b818e8c2f/cypress.tgz

Please sign in to comment.