diff --git a/packages/driver/cypress/e2e/commands/sessions/sessions.cy.js b/packages/driver/cypress/e2e/commands/sessions/sessions.cy.js
index b9dc24937e4a..b1235fe7823d 100644
--- a/packages/driver/cypress/e2e/commands/sessions/sessions.cy.js
+++ b/packages/driver/cypress/e2e/commands/sessions/sessions.cy.js
@@ -193,6 +193,7 @@ describe('cy.session', { retries: 0 }, () => {
it('groups session logs correctly', () => {
expect(logs[0].get()).to.deep.contain({
name: 'session',
+ state: 'passed',
id: sessionGroupId,
sessionInfo: {
id: 'session-1',
@@ -282,6 +283,7 @@ describe('cy.session', { retries: 0 }, () => {
it('groups session logs correctly', () => {
expect(logs[0].get()).to.deep.contain({
name: 'session',
+ state: 'passed',
id: sessionGroupId,
sessionInfo: {
id: sessionId,
@@ -344,6 +346,7 @@ describe('cy.session', { retries: 0 }, () => {
expect(err.message).to.contain('This error occurred while validating the created session')
expect(logs[0].get()).to.deep.contain({
name: 'session',
+ state: 'failed',
id: sessionGroupId,
sessionInfo: {
id: `session-${Cypress.state('test').id}`,
@@ -427,6 +430,7 @@ describe('cy.session', { retries: 0 }, () => {
it('groups session logs correctly', () => {
expect(logs[0].get()).to.contain({
name: 'session',
+ state: 'passed',
id: sessionGroupId,
})
@@ -490,6 +494,7 @@ describe('cy.session', { retries: 0 }, () => {
it('groups session logs correctly', () => {
expect(logs[0].get()).to.contain({
name: 'session',
+ state: 'passed',
id: sessionGroupId,
})
@@ -572,6 +577,7 @@ describe('cy.session', { retries: 0 }, () => {
it('groups session logs correctly', () => {
expect(logs[0].get()).to.contain({
name: 'session',
+ state: 'warned',
id: sessionGroupId,
})
@@ -678,6 +684,7 @@ describe('cy.session', { retries: 0 }, () => {
expect(logs[0].get()).to.contain({
name: 'session',
+ state: 'failed',
id: sessionGroupId,
})
@@ -914,6 +921,7 @@ describe('cy.session', { retries: 0 }, () => {
it('groups session logs correctly', () => {
expect(logs[0].get()).to.deep.contain({
name: 'session',
+ state: 'passed',
id: sessionGroupId,
sessionInfo: {
id: 'session-1',
@@ -992,6 +1000,7 @@ describe('cy.session', { retries: 0 }, () => {
it('groups session logs correctly', () => {
expect(logs[0].get()).to.deep.contain({
name: 'session',
+ state: 'passed',
id: sessionGroupId,
sessionInfo: {
id: sessionId,
@@ -1044,6 +1053,7 @@ describe('cy.session', { retries: 0 }, () => {
expect(err.message).to.contain('Your `cy.session` **validate** promise rejected with false')
expect(logs[0].get()).to.deep.contain({
name: 'session',
+ state: 'failed',
id: sessionGroupId,
sessionInfo: {
id: `session-${Cypress.state('test').id}`,
@@ -1121,6 +1131,7 @@ describe('cy.session', { retries: 0 }, () => {
it('groups session logs correctly', () => {
expect(logs[0].get()).to.contain({
name: 'session',
+ state: 'passed',
id: sessionGroupId,
})
@@ -1178,6 +1189,7 @@ describe('cy.session', { retries: 0 }, () => {
it('groups session logs correctly', () => {
expect(logs[0].get()).to.contain({
name: 'session',
+ state: 'passed',
id: sessionGroupId,
})
@@ -1254,6 +1266,7 @@ describe('cy.session', { retries: 0 }, () => {
it('groups session logs correctly', () => {
expect(logs[0].get()).to.contain({
name: 'session',
+ state: 'warned',
id: sessionGroupId,
})
@@ -1345,6 +1358,7 @@ describe('cy.session', { retries: 0 }, () => {
expect(logs[0].get()).to.contain({
name: 'session',
+ state: 'failed',
id: sessionGroupId,
})
diff --git a/packages/driver/src/cy/commands/sessions/index.ts b/packages/driver/src/cy/commands/sessions/index.ts
index 83e66dfec70a..866110835f20 100644
--- a/packages/driver/src/cy/commands/sessions/index.ts
+++ b/packages/driver/src/cy/commands/sessions/index.ts
@@ -8,6 +8,7 @@ import SessionsManager from './manager'
import {
getConsoleProps,
navigateAboutBlank,
+ SESSION_STEPS,
statusMap,
} from './utils'
@@ -39,8 +40,6 @@ export default function (Commands, Cypress, cy) {
const sessionsManager = new SessionsManager(Cypress, cy)
const sessions = sessionsManager.sessions
- type SESSION_STEPS = 'create' | 'restore' | 'recreate' | 'validate'
-
Cypress.on('run:start', () => {
// @ts-ignore
Object.values(Cypress.state('activeSessions') || {}).forEach((sessionData: ServerSessionData) => {
@@ -149,6 +148,7 @@ export default function (Commands, Cypress, cy) {
function setSessionLogStatus (status: string) {
_log.set({
+ state: statusMap.commandState(status),
sessionInfo: {
id: session.id,
isGlobalSession: session.cacheAcrossSpecs,
@@ -232,7 +232,7 @@ export default function (Commands, Cypress, cy) {
return sessions.setSessionData(testSession)
}
- function validateSession (existingSession, step: SESSION_STEPS) {
+ function validateSession (existingSession, step: keyof typeof SESSION_STEPS) {
const isValidSession = true
if (!existingSession.validate) {
@@ -321,11 +321,7 @@ export default function (Commands, Cypress, cy) {
// skip all commands between this command which errored and _commandToRunAfterValidation
for (let i = cy.queue.index; i < index; i++) {
- const cmd = commands[i]
-
- if (!cmd.get('restore-within')) {
- commands[i].skip()
- }
+ commands[i].skip()
}
// restore within subject back to the original subject used when
@@ -369,7 +365,7 @@ export default function (Commands, Cypress, cy) {
}
const failValidation = (err) => {
- if (step === 'restore') {
+ if (step === SESSION_STEPS.restore) {
enhanceErr(err)
// move to recreate session flow
@@ -442,13 +438,13 @@ export default function (Commands, Cypress, cy) {
.then(() => validateSession(existingSession, step))
.then(async (isValidSession: boolean) => {
if (!isValidSession) {
- throw new Error('not a valid session :(')
+ return 'failed'
}
sessionsManager.registeredSessions.set(existingSession.id, true)
await sessions.saveSessionData(existingSession)
- setSessionLogStatus(statusMap.complete(step))
+ return statusMap.complete(step)
})
}
@@ -460,19 +456,19 @@ export default function (Commands, Cypress, cy) {
*/
const restoreSessionWorkflow = (existingSession: SessionData) => {
return cy.then(async () => {
- setSessionLogStatus('restoring')
+ setSessionLogStatus(statusMap.inProgress(SESSION_STEPS.restore))
await navigateAboutBlank()
await sessions.clearCurrentSessionData()
return restoreSession(existingSession)
})
- .then(() => validateSession(existingSession, 'restore'))
+ .then(() => validateSession(existingSession, SESSION_STEPS.restore))
.then((isValidSession: boolean) => {
if (!isValidSession) {
- return createSessionWorkflow(existingSession, 'recreate')
+ return createSessionWorkflow(existingSession, SESSION_STEPS.recreate)
}
- setSessionLogStatus('restored')
+ return statusMap.complete(SESSION_STEPS.restore)
})
}
@@ -503,15 +499,15 @@ export default function (Commands, Cypress, cy) {
_.extend(session, _.omit(serverStoredSession, 'setup', 'validate'))
session.hydrated = true
} else {
- return createSessionWorkflow(session, 'create')
+ return createSessionWorkflow(session, SESSION_STEPS.create)
}
}
return restoreSessionWorkflow(session)
- }).then(() => {
+ }).then((status: 'created' | 'restored' | 'recreated' | 'failed') => {
return navigateAboutBlank()
.then(() => {
- _log.set({ state: 'passed' })
+ setSessionLogStatus(status)
})
})
})
diff --git a/packages/driver/src/cy/commands/sessions/utils.ts b/packages/driver/src/cy/commands/sessions/utils.ts
index bac14834bc91..03c78351cdb4 100644
--- a/packages/driver/src/cy/commands/sessions/utils.ts
+++ b/packages/driver/src/cy/commands/sessions/utils.ts
@@ -208,7 +208,28 @@ function navigateAboutBlank (session: boolean = true) {
})
}
+const enum SESSION_STEPS {
+ create = 'create',
+ restore = 'restore',
+ recreate = 'recreate',
+ validate = 'validate',
+}
+
const statusMap = {
+ commandState: (status: string) => {
+ switch (status) {
+ case 'failed':
+ return 'failed'
+ case 'recreating':
+ case 'recreated':
+ return 'warned'
+ case 'created':
+ case 'restored':
+ return 'passed'
+ default:
+ return 'pending'
+ }
+ },
inProgress: (step) => {
switch (step) {
case 'create':
@@ -255,5 +276,6 @@ export {
getConsoleProps,
getPostMessageLocalStorage,
navigateAboutBlank,
+ SESSION_STEPS,
statusMap,
}
diff --git a/packages/reporter/cypress/e2e/commands.cy.ts b/packages/reporter/cypress/e2e/commands.cy.ts
index 86ef15d6c461..50da592c0591 100644
--- a/packages/reporter/cypress/e2e/commands.cy.ts
+++ b/packages/reporter/cypress/e2e/commands.cy.ts
@@ -848,7 +848,7 @@ describe('commands', { viewportHeight: 1000 }, () => {
})
it('shows a tooltip', () => {
- cy.get('.command-name-within').click()
+ cy.get('.command-name-within').click('top')
cy.get('.cy-tooltip').should('have.text', 'Printed output to your console')
})
diff --git a/packages/reporter/src/commands/command.cy.tsx b/packages/reporter/src/commands/command.cy.tsx
index aa8867a54163..73aa58a1884d 100644
--- a/packages/reporter/src/commands/command.cy.tsx
+++ b/packages/reporter/src/commands/command.cy.tsx
@@ -1,31 +1,91 @@
import React from 'react'
import Command from './command'
import CommandModel from './command-model'
+import type { SessionStatus } from '../sessions/utils'
+import type { TestState } from '@packages/types'
describe('commands', () => {
+ describe('test states', () => {
+ it('warned command', () => {
+ cy.mount(
+
+
+
,
+ )
+
+ cy.percySnapshot()
+ })
+ })
+
describe('sessionPill', () => {
- const statusList = [
- 'creating',
- 'created',
- 'restoring',
- 'restored',
- 'recreating',
- 'recreated',
- 'failed',
+ const statusList: Array<{
+ state: TestState
+ status: SessionStatus
+ }> = [
+ {
+ state: 'pending',
+ status: 'creating',
+ },
+ {
+ state: 'passed',
+ status: 'created',
+ },
+ {
+ state: 'pending',
+ status: 'restoring',
+ },
+ {
+ state: 'passed',
+ status: 'restored',
+ },
+ {
+ state: 'warned',
+ status: 'recreating',
+ },
+ {
+ state: 'warned',
+ status: 'recreated',
+ },
+ {
+ state: 'failed',
+ status: 'failed',
+ },
]
it('session status in command', () => {
cy.mount(
- {statusList.map((status, index) => (
+ {statusList.map(({ state, status }, index) => (
{
{isSessionCommand && (
)}
{!model.visible && (
diff --git a/packages/reporter/src/commands/commands.scss b/packages/reporter/src/commands/commands.scss
index ecc29616a416..0d124e2c8a2f 100644
--- a/packages/reporter/src/commands/commands.scss
+++ b/packages/reporter/src/commands/commands.scss
@@ -252,6 +252,30 @@
}
}
+ .command-state-warned {
+ color: $warn-text;
+
+ &:not(.command-type-system) {
+ border-left: $warn-border;
+ }
+
+ .command-number-column,
+ .command-method,
+ .command-message {
+ color: $warn-text;
+ }
+
+ .command-group {
+ border-color: $warn-text;
+ @include nested-command-dashes($warn-text);
+
+ .command-group-block {
+ border-color: $warn-text;
+ @include nested-command-dashes($warn-text);
+ }
+ }
+ }
+
.command-state-failed {
color: $err-header-text;
@@ -286,6 +310,7 @@
}
// Custom Styles for Specific Commands
+ // NOTE: assert does not support warned state
.command-name-assert {
.command-method {
span {
diff --git a/packages/reporter/src/errors/errors.scss b/packages/reporter/src/errors/errors.scss
index 1f3f5b2056ba..d18932bbbafe 100644
--- a/packages/reporter/src/errors/errors.scss
+++ b/packages/reporter/src/errors/errors.scss
@@ -61,10 +61,15 @@ $code-border-radius: 4px;
border-left: 1px dotted $err-header-text;
border-image-slice: 0 0 0 1;
border-image-source: repeating-linear-gradient(0deg, transparent, $err-header-text, $err-header-text 4px);
- width: 13px;
- min-width: 13px;
- }
- }
+ width: 12px;
+ min-width: 12px;
+
+ &:first-of-type {
+ width: 13px;
+ min-width: 13px;
+ }
+ }
+ }
.runnable-err-header > .runnable-err-name {
padding: 5px 4px 5px 15px;
diff --git a/packages/reporter/src/lib/tag.cy.tsx b/packages/reporter/src/lib/tag.cy.tsx
index 5a3a1e226583..1390c618b155 100644
--- a/packages/reporter/src/lib/tag.cy.tsx
+++ b/packages/reporter/src/lib/tag.cy.tsx
@@ -11,6 +11,7 @@ describe('Tag', () => {
const statuses = [
'successful-status',
+ 'warned-status',
'failed-status',
]
diff --git a/packages/reporter/src/lib/tag.scss b/packages/reporter/src/lib/tag.scss
index 0951e7f94896..46c7cec4df53 100644
--- a/packages/reporter/src/lib/tag.scss
+++ b/packages/reporter/src/lib/tag.scss
@@ -37,9 +37,14 @@
color: $jade-300;
}
+ &.warned-status {
+ background-color: $gray-1000;
+ border: $gray-900 1px solid;
+ color: $warn-text;
+ }
+
&.failed-status {
background-color: $red-500;
- font-weight: 500;
}
&.reporter-tag-has-count {
diff --git a/packages/reporter/src/lib/variables.scss b/packages/reporter/src/lib/variables.scss
index 5dc085420b5d..a7e778827755 100644
--- a/packages/reporter/src/lib/variables.scss
+++ b/packages/reporter/src/lib/variables.scss
@@ -104,7 +104,6 @@ $fail: $red-400;
$pending: $indigo-400;
$pinned: $purple-400;
$retried: $orange-400;
-$yellow-medium: $orange-800;
$link-text: $indigo-600;
@@ -118,10 +117,8 @@ $err-text: $red-400;
$reporter-section-background: #171926; // not a brand color
-$warn-background: $red-1000;
-$warn-header-background: $orange-1000;
-$warn-header-text: $orange-700;
-$warn-text: $orange-600;
+$warn-border: 2px solid $orange-300;
+$warn-text: $orange-300;
$header-height: 64px;
$reporter-contents-min-width: 170px;
diff --git a/packages/reporter/src/sessions/sessions-model.ts b/packages/reporter/src/sessions/sessions-model.ts
index 1e1028704672..aa5a596a902e 100644
--- a/packages/reporter/src/sessions/sessions-model.ts
+++ b/packages/reporter/src/sessions/sessions-model.ts
@@ -1,5 +1,7 @@
import { observable } from 'mobx'
import Instrument, { InstrumentProps } from '../instruments/instrument-model'
+import { determineTagType } from './utils'
+import type { SessionStatus } from './utils'
export interface SessionProps extends InstrumentProps {
name: string
@@ -8,7 +10,7 @@ export interface SessionProps extends InstrumentProps {
sessionInfo: {
id: string
isGlobalSession: boolean
- status: 'creating' | 'created' | 'restored' |'restored' | 'recreating' | 'recreated' | 'failed'
+ status: SessionStatus
}
}
@@ -16,19 +18,22 @@ export default class Session extends Instrument {
@observable name: string
@observable status: string
@observable isGlobalSession: boolean = false
+ @observable tagType: string
constructor (props: SessionProps) {
super(props)
- const { sessionInfo: { isGlobalSession, id, status } } = props
+ const { state, sessionInfo: { isGlobalSession, id, status } } = props
this.isGlobalSession = isGlobalSession
this.name = id
this.status = status
+ this.tagType = determineTagType(state)
}
update (props: Partial) {
- const { sessionInfo } = props
+ const { state, sessionInfo } = props
this.status = sessionInfo?.status || ''
+ this.tagType = determineTagType(state || '')
}
}
diff --git a/packages/reporter/src/sessions/sessions.cy.tsx b/packages/reporter/src/sessions/sessions.cy.tsx
index 64206563ab50..5079fad1e0ff 100644
--- a/packages/reporter/src/sessions/sessions.cy.tsx
+++ b/packages/reporter/src/sessions/sessions.cy.tsx
@@ -41,6 +41,20 @@ describe('sessions instrument panel', { viewportWidth: 400 }, () => {
},
})
+ const warnedSpecSession = new SessionsModel({
+ name: 'session',
+ state: 'warned',
+ type: 'parent',
+ testId: '1',
+ id: 3,
+ sessionInfo: {
+ id: 'spec_session_warned',
+ isGlobalSession: false,
+ status: 'recreated',
+ },
+ testCurrentRetry: 1,
+ })
+
const failedSpecSession = new SessionsModel({
name: 'session',
state: 'failed',
@@ -56,7 +70,7 @@ describe('sessions instrument panel', { viewportWidth: 400 }, () => {
})
beforeEach(() => {
- cy.mount()
+ cy.mount()
cy.get('.sessions-container').should('exist')
cy.get('.hook-header > .collapsible-header').as('header')
@@ -74,7 +88,7 @@ describe('sessions instrument panel', { viewportWidth: 400 }, () => {
cy.get('@header').should('have.attr', 'aria-expanded', 'true')
cy.get('.session-item')
- .should('have.length', 3)
+ .should('have.length', 4)
.should('be.visible')
cy.percySnapshot()
@@ -106,11 +120,24 @@ describe('sessions instrument panel', { viewportWidth: 400 }, () => {
cy.percySnapshot()
})
- it('has failed session item', () => {
+ it('has warned session item', () => {
cy.get('@header').click()
cy.get('.session-item')
.eq(2)
+ .within(() => {
+ cy.contains('spec_session_warned').should('have.class', 'spec-session')
+ cy.get('.session-status').should('have.class', 'warned-status')
+ })
+
+ cy.percySnapshot()
+ })
+
+ it('has failed session item', () => {
+ cy.get('@header').click()
+
+ cy.get('.session-item')
+ .eq(3)
.within(() => {
cy.contains('spec_session_failed').should('have.class', 'spec-session')
cy.get('.global-session-icon').should('not.exist')
@@ -125,7 +152,7 @@ describe('sessions instrument panel', { viewportWidth: 400 }, () => {
cy.get('@header').click()
- cy.get('.session-item').eq(2).click()
+ cy.get('.session-item').eq(3).click()
cy.get('.cy-tooltip')
.should('have.text', 'Printed output to your console')
diff --git a/packages/reporter/src/sessions/sessions.tsx b/packages/reporter/src/sessions/sessions.tsx
index 86149b5339f2..dd38395afd8e 100644
--- a/packages/reporter/src/sessions/sessions.tsx
+++ b/packages/reporter/src/sessions/sessions.tsx
@@ -13,7 +13,9 @@ export interface SessionPanelProps {
model: Record
}
-const SessionRow = ({ name, isGlobalSession, id, status, testId }: SessionsModel) => {
+const SessionRow = (model: SessionsModel) => {
+ const { name, isGlobalSession, id, status, testId } = model
+
const printToConsole = (id) => {
events.emit('show:command', testId, id)
}
@@ -34,7 +36,7 @@ const SessionRow = ({ name, isGlobalSession, id, status, testId }: SessionsModel
diff --git a/packages/reporter/src/sessions/utils.ts b/packages/reporter/src/sessions/utils.ts
new file mode 100644
index 000000000000..34fecd367076
--- /dev/null
+++ b/packages/reporter/src/sessions/utils.ts
@@ -0,0 +1,16 @@
+function determineTagType (state: string) {
+ switch (state) {
+ case 'failed':
+ return 'failed-status'
+ case 'warned':
+ return 'warned-status'
+ default:
+ return 'successful-status'
+ }
+}
+
+export type SessionStatus = 'creating' | 'created' | 'restoring' |'restored' | 'recreating' | 'recreated' | 'failed'
+
+export {
+ determineTagType,
+}
diff --git a/packages/types/src/driver.ts b/packages/types/src/driver.ts
index 3335a1bb926e..8392302421dc 100644
--- a/packages/types/src/driver.ts
+++ b/packages/types/src/driver.ts
@@ -43,4 +43,4 @@ export interface CachedTestState {
export type Instrument = 'agent' | 'command' | 'route'
-export type TestState = 'active' | 'failed' | 'pending' | 'passed' | 'processing'
+export type TestState = 'active' | 'failed' | 'pending' | 'passed' | 'processing' | 'warned'