diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index dc1499f62142..d990cb00f785 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -3,6 +3,10 @@ _Released 6/3/2025 (PENDING)_ +**Misc:** + +- The design of commands that display as grouped (such as `.within()` and `cy.session()`) has been updated to provide better clarity when collapsing groups. Addressed in [#31739](https://github.com/cypress-io/cypress/pull/31739). + **Dependency Updates:** - Updated `@sinonjs/fake-timers` from `10.3.0` to `11.3.1`. Addressed in [#31746](https://github.com/cypress-io/cypress/pull/31746). diff --git a/packages/app/cypress/e2e/runner/support/snapshot-reporter.ts b/packages/app/cypress/e2e/runner/support/snapshot-reporter.ts index dc4e91125ae4..1107cf56dccc 100644 --- a/packages/app/cypress/e2e/runner/support/snapshot-reporter.ts +++ b/packages/app/cypress/e2e/runner/support/snapshot-reporter.ts @@ -1,26 +1,37 @@ // Takes percy snapshot with navigation/AUT/reporter hidden export const snapshotReporter = () => { - cy.percySnapshot({ - width: 450, - elementOverrides: { - '.cy-tooltip': true, - '[data-cy=sidebar]': ($el) => { - $el.attr('style', 'display: none !important') - }, - '[data-cy=aut-panel]': ($el) => { - $el.attr('style', 'display: none !important') - }, - '[data-cy=reporter-panel]': ($el) => { - $el.attr('style', 'width: 450px !important') - }, - '[data-cy=reporter-running-icon]': ($el) => { - // remove 'fa-spin' class so that the icon is not animated - $el.attr('class', '') - }, - '.command-progress': ($el) => { - // don't display command progress bar in snapshot - $el.attr('style', 'display: none !important') + let sidebarWidth = 0 + + cy.get('[data-cy=sidebar]') + .invoke('width') + .then((w) => { + if (w) { + sidebarWidth = w + } + }).then(() => { + cy.get('[data-cy=reporter-panel]') + }) + .invoke('width') + .then((w) => { + cy.percySnapshot({ + width: w + sidebarWidth, + elementOverrides: { + '.cy-tooltip': true, + '[data-cy=sidebar]': ($el) => { + $el.attr('style', 'display: none !important') + }, + '[data-cy=aut-panel]': ($el) => { + $el.attr('style', 'display: none !important') + }, + '[data-cy=reporter-running-icon]': ($el) => { + // remove 'fa-spin' class so that the icon is not animated + $el.attr('class', '') + }, + '.command-progress': ($el) => { + // don't display command progress bar in snapshot + $el.attr('style', 'display: none !important') + }, }, - }, + }) }) } diff --git a/packages/app/cypress/e2e/runner/ui-states.cy.ts b/packages/app/cypress/e2e/runner/ui-states.cy.ts index 8429223b6024..21830b93f65a 100644 --- a/packages/app/cypress/e2e/runner/ui-states.cy.ts +++ b/packages/app/cypress/e2e/runner/ui-states.cy.ts @@ -1,3 +1,4 @@ +import { snapshotReporter } from './support/snapshot-reporter' import { loadSpec } from './support/spec-loader' describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 600000 }, () => { @@ -12,7 +13,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('test hooks').should('be.visible') - cy.percySnapshot() + snapshotReporter() }) it('nested tests', () => { @@ -22,7 +23,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('Nested Tests').should('be.visible') - cy.percySnapshot() + snapshotReporter() }) describe('commands', () => { @@ -33,7 +34,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('part 1 - basic commands').should('be.visible').click() - cy.percySnapshot() + snapshotReporter() }) it('part 2 - traversal and navigation', () => { @@ -45,7 +46,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 cy.contains('part 2 - traversal and navigation').should('be.visible') .click() - cy.percySnapshot() + snapshotReporter() }) it('part 3 - element manipulation', () => { @@ -57,7 +58,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 cy.contains('part 3 - element manipulation').should('be.visible') .click() - cy.percySnapshot() + snapshotReporter() }) it('part 4 - advanced interactions', () => { @@ -69,7 +70,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 cy.contains('part 4 - advanced interactions').should('be.visible') .click() - cy.percySnapshot() + snapshotReporter() }) it('commands that do not appear in command log', () => { @@ -79,7 +80,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('commands that do not appear in command log').should('be.visible').click() - cy.percySnapshot() + snapshotReporter() }) it('form interaction command options', () => { @@ -89,7 +90,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('form interaction command options').should('be.visible').click() - cy.percySnapshot() + snapshotReporter() }) it('DOM traversal command options', () => { @@ -99,7 +100,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('DOM traversal command options').should('be.visible').click() - cy.percySnapshot() + snapshotReporter() }) it('element state and navigation command options', () => { @@ -109,7 +110,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('element state and navigation command options').should('be.visible').click() - cy.percySnapshot() + snapshotReporter() }) it('element traversal and file operations command options', () => { @@ -119,7 +120,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('element traversal and file operations command options').should('be.visible').click() - cy.percySnapshot() + snapshotReporter() }) it('scrolling and form interaction command options', () => { @@ -129,7 +130,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('scrolling and form interaction command options').should('be.visible').click() - cy.percySnapshot() + snapshotReporter() }) it('user interaction and window command options', () => { @@ -139,7 +140,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('user interaction and window command options').should('be.visible').click() - cy.percySnapshot() + snapshotReporter() }) it('verify element visibility state', () => { @@ -149,7 +150,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('verify element visibility state').should('be.visible').click() - cy.percySnapshot() + snapshotReporter() }) }) @@ -160,7 +161,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('Request Statuses').should('be.visible') - cy.percySnapshot() + snapshotReporter() }) it('page events', () => { @@ -170,7 +171,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('events - page events').should('be.visible') - cy.percySnapshot() + snapshotReporter() }) describe('errors', () => { @@ -181,7 +182,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 }) cy.contains('simple error with docs link').should('be.visible') - cy.percySnapshot() + snapshotReporter() }) it('long error', () => { @@ -192,7 +193,7 @@ describe('src/cypress/runner ui states', { retries: 0, defaultCommandTimeout: 60 cy.contains('simple error with docs link').click() cy.contains('long error').should('be.visible') - cy.percySnapshot() + snapshotReporter() }) }) }) diff --git a/packages/reporter/src/commands/command.tsx b/packages/reporter/src/commands/command.tsx index ab5dd6a5d2a4..83d813126a53 100644 --- a/packages/reporter/src/commands/command.tsx +++ b/packages/reporter/src/commands/command.tsx @@ -124,7 +124,7 @@ const NavColumns: React.FC = observer(({ model, isPinned, toggl {(!model._isPending() && isPinned) && } {(!model._isPending() && !isPinned) && model.number} - {model.hasChildren && ( + {model.hasChildren && !model.group && (
model.toggleOpen()}>
@@ -326,7 +326,7 @@ interface CommandProps { const CommandDetails: React.FC = observer(({ model, groupId, aliasesWithDuplicates }) => ( - + {model.event && model.type !== 'system' ? `(${displayName(model)})` : displayName(model)} @@ -432,7 +432,10 @@ const Command: React.FC = observer(({ model, aliasesWithDuplicates groupLevel = model.groupLevel < 6 ? model.groupLevel : 5 for (let i = 1; i < groupLevel; i++) { - groupPlaceholder.push() + groupPlaceholder.push( { + e.stopPropagation() + model.toggleOpen() + }} />) } } @@ -520,14 +523,26 @@ const Command: React.FC = observer(({ model, aliasesWithDuplicates message='Printed output to your console' onClick={_toggleColumnPin} shouldShowMessage={_shouldShowClickMessage} - wrapperClassName={cs('command-pin-target', { 'command-group': !!groupId })} + wrapperClassName={cs('command-pin-target', { 'command-group': !!groupId, 'command-group-no-children': !model.hasChildren && model.group })} >
_snapshot(true)} onMouseLeave={() => _snapshot(false)} > {groupPlaceholder} + + {model.hasChildren && groupId && ( +
{ + e.stopPropagation() + model.toggleOpen() + }}> + +
+ )}
diff --git a/packages/reporter/src/commands/commands.scss b/packages/reporter/src/commands/commands.scss index 0ea33b2bddff..290869c55e0f 100644 --- a/packages/reporter/src/commands/commands.scss +++ b/packages/reporter/src/commands/commands.scss @@ -1,7 +1,7 @@ @mixin nested-command-dashes($color) { border-left: 1px dotted $color; border-image-slice: 0 0 0 1; - border-image-source: repeating-linear-gradient(0deg, transparent, $color, $color 4px); + border-image-source: repeating-linear-gradient(0deg, transparent, $color, $color 2px); } .reporter { @@ -52,7 +52,7 @@ // Child Styles .command-type-child { - .command-method { + .command-method-child { &:before { float: left; content: "-"; @@ -108,42 +108,56 @@ } .command-number-column { + @include gutter-alignment; + color: #5a5f7a; - flex-shrink: 0; - min-height: 1px; // because some numbers are empty - max-height: 28px; // because some numbers are empty - padding-top: 4px; - padding-bottom: 4px; - text-align: right; - width: 24px; } // when no children, add padding to act as the .command-expander-column's width // to prevent adding another element to the page .command-number-column + span.command-pin-target { - margin-left: 25px; + margin-left: $gutter-margin; } .command-pin-target.command-group { - @include nested-command-dashes($gray-600); - padding-left: 12px; + @include nested-command-dashes($gray-700); min-height: 28px; .command-group-block { - @include nested-command-dashes($gray-600); - width: 12px; + @include nested-command-dashes($gray-700); + @include group-indent-width; min-height: 28px; - min-width: 12px; + } + } + + .command-group-no-children { + padding-left: 15px; + } + + .command-wrapper-text-group { + padding-left: 15px; + width: 100%; + + } + + .command-wrapper-text-group-parent { + padding-left: 5px; + } + + .nested-group-expander { + .command-expander { + position: relative; + margin-left: -16px !important; // Adjust this value to center the caret on the border } } .command-info { + @include command-info-padding; + display: -webkit-box; font-weight: 600; margin-left: 0; overflow: hidden; - padding-top: 4px; - padding-bottom: 4px; width: 100%; -webkit-line-clamp: 100; -webkit-box-orient: vertical; @@ -454,7 +468,7 @@ font-size: 12px; line-height: 1; margin-top: -1px; - margin-left: 10px; + margin-left: 12px; outline: none; text-align: right; width: 15px; @@ -465,20 +479,14 @@ } } - .command-expander-column { + %command-expander-base { flex-shrink: 0; - padding-left: 10px; - padding-right: 5px; - padding-top: 4px; - padding-bottom: 4px; - width: 25px; display: flex; .command-expander { color: $gray-500; transform: rotate(-90deg); transition: transform 150ms ease-out; - margin-top: 5px; path { stroke: $gray-700; @@ -490,6 +498,31 @@ } } + .command-expander-column { + @extend %command-expander-base; + padding: 4px 5px 4px 11px; + width: 25px; + + .command-expander { + margin-top: 5px; + } + } + + + + .command-expander-column-group { + @extend %command-expander-base; + @include group-indent-width; + + padding: 0; + align-items: center; + justify-content: center; + + .command-expander { + margin: 0; + } + } + .command-is-pinned { background: $indigo-1000; border-left: 2px solid $pinned; diff --git a/packages/reporter/src/errors/errors.scss b/packages/reporter/src/errors/errors.scss index 203672a2c8dd..c9bd40049ddf 100644 --- a/packages/reporter/src/errors/errors.scss +++ b/packages/reporter/src/errors/errors.scss @@ -54,26 +54,23 @@ $code-border-radius: 4px; .recovered-test-err { .runnable-err-header, .runnable-err-body { - padding-left: 49px; + padding-left: 38px; display: flex; .err-group-block { + @include group-indent-width; + 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: 12px; - min-width: 12px; + border-image-source: repeating-linear-gradient(0deg, transparent, $err-header-text, $err-header-text 2px); &:first-of-type { - width: 13px; - min-width: 13px; + width: 16px; + min-width: 16px; } } } - .runnable-err-header > .runnable-err-name { - padding: 5px 4px 5px 15px; - } .runnable-err-content { padding: 0 12px 0 0; @@ -110,20 +107,31 @@ $code-border-radius: 4px; display: flex; font-weight: bold; justify-content: space-between; - padding-left: 18px; - svg { - color: $red-400; - align-self: center + .runnable-err-icon { + @include gutter-alignment; + + &.runnable-err-icon-group { + width: auto; + } + + svg { + color: $red-400; + align-self: center + } } + .runnable-err-name { + @include command-info-padding; + color: $err-header-text; flex: auto; font-size: 12px; font-weight: 600; line-height: 20px; - padding: 5px 4px 5px 24px; + + margin-left: $gutter-margin; } } diff --git a/packages/reporter/src/errors/test-error.tsx b/packages/reporter/src/errors/test-error.tsx index c27bac1b841d..a4cbb6d1224e 100644 --- a/packages/reporter/src/errors/test-error.tsx +++ b/packages/reporter/src/errors/test-error.tsx @@ -74,7 +74,9 @@ const TestError: React.FC = ({ err, groupLevel = 0, testId, comm
{groupPlaceholder} - +
0 })}> + +
{err.name}
diff --git a/packages/reporter/src/lib/mixins.scss b/packages/reporter/src/lib/mixins.scss index 6939b841b53c..a8f51eb474f8 100644 --- a/packages/reporter/src/lib/mixins.scss +++ b/packages/reporter/src/lib/mixins.scss @@ -29,3 +29,25 @@ bottom: 0; } } + +@mixin gutter-alignment { + flex-shrink: 0; + min-height: 1px; // because some numbers are empty + max-height: 28px; // because some numbers are empty + padding-top: 4px; + padding-bottom: 4px; + text-align: right; + width: 24px; +} + +@mixin command-info-padding { + padding-top: 4px; + padding-bottom: 4px; + align-self: center; +} + +@mixin group-indent-width { + width: 18px; + min-width: 18px; + max-width: 18px; +} \ No newline at end of file diff --git a/packages/reporter/src/lib/variables.scss b/packages/reporter/src/lib/variables.scss index 88dfbb021245..77726a86f22c 100644 --- a/packages/reporter/src/lib/variables.scss +++ b/packages/reporter/src/lib/variables.scss @@ -127,3 +127,5 @@ $font-sans: 'Fira Mono', 'Helvetica Neue', 'Arial', sans-serif; $open-sans: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; $monospace: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", "Fira Mono", "Droid Sans Mono", "Courier New", monospace; $font-system: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + +$gutter-margin: 14px; \ No newline at end of file diff --git a/system-tests/project-fixtures/runner-specs/cypress/e2e/runner/ui-states/commandsToDisplay.cy.js b/system-tests/project-fixtures/runner-specs/cypress/e2e/runner/ui-states/commandsToDisplay.cy.js index 41a9df7c18b6..2f4c5b0a396a 100644 --- a/system-tests/project-fixtures/runner-specs/cypress/e2e/runner/ui-states/commandsToDisplay.cy.js +++ b/system-tests/project-fixtures/runner-specs/cypress/e2e/runner/ui-states/commandsToDisplay.cy.js @@ -112,7 +112,8 @@ describe('Commands to display in UI', () => { cy.window() cy.get('div').first().within(() => { - + cy.log('message') + cy.expect(1).to.equal(1) }) cy.wrap({ foo: 'bar' })