Skip to content

Commit f9ddde2

Browse files
author
Shawn Taylor
authoredOct 29, 2021
feat(unify): reporter header design (#18471)
* display duration in runnable header * reporter header design * fix a couple issues * style tweaks * fix bug * use new icons * split filename and style * add unit tests for splitting filename * fix tests * address feedback * update pending icon; use icons from frontend-shared * update filename muted extension functionality * change duration display * fix test
1 parent 924ce03 commit f9ddde2

31 files changed

+392
-152
lines changed
 
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading

‎packages/reporter/cypress/integration/header_spec.ts

-23
Original file line numberDiff line numberDiff line change
@@ -85,21 +85,6 @@ describe('header', () => {
8585
cy.get('.failed .num').should('have.text', '--')
8686
cy.get('.pending .num').should('have.text', '--')
8787
})
88-
89-
it('displays the time taken in seconds', () => {
90-
const start = new Date(2000, 0, 1)
91-
const now = new Date(2000, 0, 1, 0, 0, 12, 340)
92-
93-
cy.clock(now).then(() => {
94-
runner.emit('reporter:start', { startTime: start.toISOString() })
95-
})
96-
97-
cy.get('.duration .num').should('have.text', '12.34')
98-
})
99-
100-
it('displays "--" if no time taken', () => {
101-
cy.get('.duration .num').should('have.text', '--')
102-
})
10388
})
10489

10590
describe('controls', () => {
@@ -160,10 +145,6 @@ describe('header', () => {
160145
})
161146

162147
describe('pause controls', () => {
163-
it('does not display paused label', () => {
164-
cy.get('.paused-label').should('not.exist')
165-
})
166-
167148
it('does not display play button', () => {
168149
cy.get('.play').should('not.exist')
169150
})
@@ -183,10 +164,6 @@ describe('header', () => {
183164
runner.emit('paused', 'find')
184165
})
185166

186-
it('displays paused label', () => {
187-
cy.get('.paused-label').should('be.visible')
188-
})
189-
190167
it('displays play button', () => {
191168
cy.get('.play').should('be.visible')
192169
})

‎packages/reporter/cypress/integration/meta_&%_spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ describe('special characters', () => {
44
it('displays file name with decoded special characters', () => {
55
cy.wrap(Cypress.$(window.top.document.body))
66
.find('.reporter .runnable-header a')
7-
.should('have.text', 'cypress/integration/meta_&%_spec.ts')
7+
.should('have.text', 'meta_&%_spec.ts')
88
})
99
})

‎packages/reporter/cypress/integration/runnables_spec.ts

+19
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,25 @@ describe('runnables', () => {
114114
cy.get('.error li').should('have.length', 2)
115115
})
116116

117+
it('displays the time taken in seconds', () => {
118+
start()
119+
120+
const startTime = new Date(2000, 0, 1)
121+
const now = new Date(2000, 0, 1, 0, 0, 12, 340)
122+
123+
cy.clock(now).then(() => {
124+
runner.emit('reporter:start', { startTime: startTime.toISOString() })
125+
})
126+
127+
cy.get('.runnable-header span:last').should('have.text', '00:12')
128+
})
129+
130+
it('does not display time if no time taken', () => {
131+
start()
132+
cy.get('.runnable-header span:first').should('have.text', 'foo')
133+
cy.get('.runnable-header span:last').should('not.have.text', '--')
134+
})
135+
117136
describe('when there are no tests', () => {
118137
beforeEach(() => {
119138
runnables.suites = []

‎packages/reporter/cypress/integration/spec_title_spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ describe('spec title', () => {
5454
})
5555
})
5656

57-
it('displays relative spec path', () => {
58-
cy.get('.runnable-header').find('a').should('have.text', 'relative/path/to/foo.js')
57+
it('displays name without path', () => {
58+
cy.get('.runnable-header').find('a').should('have.text', 'foo.js')
5959

6060
cy.percySnapshot()
6161
})

‎packages/reporter/cypress/integration/suites_spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ describe('suites', () => {
130130

131131
describe('studio button', () => {
132132
it('displays studio icon with half transparency when hovering over test title', () => {
133-
cy.contains('suite 1')
133+
cy.contains('nested suite 1')
134134
.closest('.runnable-wrapper')
135135
.realHover()
136136
.find('.runnable-controls-studio')
@@ -139,7 +139,7 @@ describe('suites', () => {
139139
})
140140

141141
it('displays studio icon with no transparency and tooltip on hover', () => {
142-
cy.contains('suite 1')
142+
cy.contains('nested suite 1')
143143
.closest('.collapsible-header')
144144
.find('.runnable-controls-studio')
145145
.realHover()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { formatDuration, getFilenameParts } from '../../../src/lib/util'
2+
3+
const compare = (filename, array) => {
4+
expect(getFilenameParts(filename)).to.deep.equal(array)
5+
}
6+
7+
describe('utils', () => {
8+
context('formatDuration', () => {
9+
it('formats no time', () => {
10+
expect(formatDuration(0)).to.equal('--')
11+
})
12+
13+
it('formats time of <1s', () => {
14+
expect(formatDuration(1)).to.equal('1ms')
15+
expect(formatDuration(999)).to.equal('999ms')
16+
})
17+
18+
it('formats time of >=1s', () => {
19+
expect(formatDuration(1000)).to.equal('00:01')
20+
expect(formatDuration(1400)).to.equal('00:01')
21+
expect(formatDuration(35620)).to.equal('00:36')
22+
expect(formatDuration(59200)).to.equal('00:59')
23+
})
24+
25+
it('formats time of >=1m', () => {
26+
expect(formatDuration(60000)).to.equal('01:00')
27+
expect(formatDuration(600000)).to.equal('10:00')
28+
expect(formatDuration(3599000)).to.equal('59:59')
29+
})
30+
31+
it('formats time of >=1h', () => {
32+
expect(formatDuration(3600000)).to.equal('1:00:00')
33+
expect(formatDuration(4200000)).to.equal('1:10:00')
34+
expect(formatDuration(7199000)).to.equal('1:59:59')
35+
})
36+
37+
it('displays larger times in hours', () => {
38+
expect(formatDuration(360000000)).to.equal('100:00:00')
39+
})
40+
})
41+
42+
context('getFilenameParts', () => {
43+
it('splits basic filenames', () => {
44+
compare('something.foo.ts', ['something.foo', '.ts'])
45+
compare('first-user.js', ['first-user', '.js'])
46+
compare('model.coffee', ['model', '.coffee'])
47+
})
48+
49+
it('handles .spec, .test, and .cy', () => {
50+
compare('basic.spec.ts', ['basic', '.spec.ts'])
51+
compare('spies_stubs_clocks.spec.js', ['spies_stubs_clocks', '.spec.js'])
52+
compare('newIssuanceWorkflow.test.js', ['newIssuanceWorkflow', '.test.js'])
53+
compare('Button.cy.js', ['Button', '.cy.js'])
54+
})
55+
56+
it('does not consider "_spec" to be part of the extension', () => {
57+
// might want to change this functionality later, but for now this is working as intended
58+
compare('warning_spec.js', ['warning_spec', '.js'])
59+
})
60+
61+
it('behaves as expected if "spec" is in the filename', () => {
62+
compare('spec.ts', ['spec', '.ts'])
63+
compare('spec_spec.ts', ['spec_spec', '.ts'])
64+
})
65+
66+
it('handles no file extension', () => {
67+
compare('no-extension', ['no-extension', ''])
68+
})
69+
70+
it('strips directory path', () => {
71+
compare('unit/spec_split_spec.ts', ['spec_split_spec', '.ts'])
72+
compare('dir/unit/spec_split_spec.ts', ['spec_split_spec', '.ts'])
73+
})
74+
75+
it('displays filename with special characters', () => {
76+
compare('cypress/integration/meta_&%_spec.ts', ['meta_&%_spec', '.ts'])
77+
})
78+
79+
it('handles an unexpected number of extensions', () => {
80+
compare('reporter.hooks.spec.js', ['reporter.hooks', '.spec.js'])
81+
})
82+
})
83+
})

‎packages/reporter/index.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,8 @@ declare namespace Cypress {
1616
percySnapshot (): Chainable
1717
}
1818
}
19+
20+
declare module "*.svg" {
21+
const content: any;
22+
export default content;
23+
}

‎packages/reporter/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"prop-types": "15.7.2",
3434
"react": "16.8.6",
3535
"react-dom": "16.8.6",
36+
"react-svg-loader": "3.0.3",
3637
"rimraf": "3.0.2",
3738
"sinon": "7.5.0",
3839
"webpack": "4.35.3",

‎packages/reporter/src/errors/errors.scss

-7
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,6 @@ $code-border-radius: 4px;
233233
margin: 0 10px 10px;
234234

235235
.runnable-err-file-path {
236-
&:before {
237-
@extend .#{$fa-css-prefix};
238-
@extend .#{$fa-css-prefix}-file;
239-
color: $gray-700;
240-
margin-right: 5px;
241-
}
242-
243236
background: rgba($gray-900, 0.5);
244237
border-top-left-radius: $code-border-radius;
245238
border-top-right-radius: $code-border-radius;

‎packages/reporter/src/header/controls.tsx

+13-9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ import Tooltip from '@cypress/react-tooltip'
88
import defaultEvents, { Events } from '../lib/events'
99
import { AppState } from '../lib/app-state'
1010

11+
import NextIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/action-next_x16.svg'
12+
import PlayIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/action-play_x16.svg'
13+
import RestartIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/action-restart_x16.svg'
14+
import StopIcon from '-!react-svg-loader!@packages/frontend-shared/src/assets/icons/action-stop_x16.svg'
15+
1116
const ifThen = (condition: boolean, component: React.ReactNode) => (
1217
condition ? component : null
1318
)
@@ -26,15 +31,10 @@ const Controls = observer(({ events = defaultEvents, appState }: Props) => {
2631

2732
return (
2833
<div className='controls'>
29-
{ifThen(appState.isPaused, (
30-
<span className='paused-label'>
31-
<label>Paused</label>
32-
</span>
33-
))}
3434
{ifThen(appState.isPaused, (
3535
<Tooltip placement='bottom' title={<p>Resume <span className='kbd'>C</span></p>} className='cy-tooltip'>
3636
<button aria-label='Resume' className='play' onClick={emit('resume')}>
37-
<i className='fas fa-play' />
37+
<PlayIcon />
3838
</button>
3939
</Tooltip>
4040
))}
@@ -53,21 +53,25 @@ const Controls = observer(({ events = defaultEvents, appState }: Props) => {
5353
{ifThen(appState.isRunning && !appState.isPaused, (
5454
<Tooltip placement='bottom' title={<p>Stop Running <span className='kbd'>S</span></p>} className='cy-tooltip' visible={appState.studioActive ? false : null}>
5555
<button aria-label='Stop' className='stop' onClick={emit('stop')} disabled={appState.studioActive}>
56-
<i className='fas fa-stop' />
56+
<StopIcon />
5757
</button>
5858
</Tooltip>
5959
))}
6060
{ifThen(!appState.isRunning, (
6161
<Tooltip placement='bottom' title={<p>Run All Tests <span className='kbd'>R</span></p>} className='cy-tooltip'>
6262
<button aria-label='Rerun all tests' className='restart' onClick={emit('restart')}>
63-
<i className={appState.studioActive ? 'fas fa-undo' : 'fas fa-redo'} />
63+
{appState.studioActive ? (
64+
<RestartIcon transform="scale(-1 1)" />
65+
) : (
66+
<RestartIcon />
67+
)}
6468
</button>
6569
</Tooltip>
6670
))}
6771
{ifThen(!!appState.nextCommandName, (
6872
<Tooltip placement='bottom' title={<p>Next <span className='kbd'>[N]:</span>{appState.nextCommandName}</p>} className='cy-tooltip'>
6973
<button aria-label={`Next '${appState.nextCommandName}'`} className='next' onClick={emit('next')}>
70-
<i className='fas fa-step-forward' />
74+
<NextIcon />
7175
</button>
7276
</Tooltip>
7377
))}

0 commit comments

Comments
 (0)
Please sign in to comment.