Skip to content

Commit 8f1f219

Browse files
committed
WIP redesign of report header
1 parent 9b3f277 commit 8f1f219

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+687
-440
lines changed

package-lock.json

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/ciCommitLink.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ describe('ciCommitLink(ci)', () => {
4040
name: 'SuperCI',
4141
}
4242

43-
expect(ciCommitLink(ci)).to.eq(null)
43+
expect(ciCommitLink(ci)).to.eq(undefined)
4444
})
4545
})
4646
})

src/ciCommitLink.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import * as messages from '@cucumber/messages'
1+
import { Ci } from '@cucumber/messages'
22

33
import toRepositoryId from './toRepositoryId.js'
44

5-
export default function ciCommitLink(ci: messages.Ci): string | null {
5+
// TODO move upstream to create-meta
6+
export default function ciCommitLink(ci: Ci): string | undefined {
67
if (ci.git && ci.git.remote) {
78
const repositoryId = toRepositoryId(ci.git.remote)
89
const github = repositoryId.startsWith('github.com') || ci.name === 'GitHub Actions'
910
if (ci.git.revision && github) {
1011
return `https://${repositoryId}/commit/${ci.git.revision}`
1112
}
1213
}
13-
return null
1414
}

src/components/app/CICommitLink.tsx

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,34 @@
1-
import * as messages from '@cucumber/messages'
2-
import { faLink } from '@fortawesome/free-solid-svg-icons'
1+
import { Ci } from '@cucumber/messages'
2+
import { faCodeCommit } from '@fortawesome/free-solid-svg-icons'
33
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
4-
import React from 'react'
4+
import React, { FC } from 'react'
55

66
import ciCommitLink from '../../ciCommitLink.js'
77

8-
interface IProps {
9-
ci: messages.Ci
10-
}
8+
export const CICommitLink: FC<{
9+
ci: Ci
10+
}> = ({ ci }) => {
11+
if (!ci.git) {
12+
return null
13+
}
1114

12-
export const CICommitLink: React.FunctionComponent<IProps> = ({ ci: ci }) => {
15+
const shortHash = ci.git.revision.substring(0, 7)
1316
const commitLink = ciCommitLink(ci)
1417

15-
if (commitLink && ci.git?.remote) {
18+
if (commitLink) {
1619
return (
1720
<>
18-
<FontAwesomeIcon icon={faLink} />
19-
Git Ref <a href={commitLink}>{ci.git.revision.substring(0, 7)}</a>
21+
<FontAwesomeIcon aria-hidden="true" style={{ opacity: 0.75 }} icon={faCodeCommit} />
22+
<a href={commitLink} target="_blank" rel="noreferrer">
23+
<code>{shortHash}</code>
24+
</a>
2025
</>
2126
)
2227
}
2328
return (
2429
<>
25-
<FontAwesomeIcon icon={faLink} /> Git Ref {ci.git?.revision.substring(0, 7)}
30+
<FontAwesomeIcon aria-hidden="true" style={{ opacity: 0.75 }} icon={faCodeCommit} />
31+
<code>{shortHash}</code>
2632
</>
2733
)
2834
}

src/components/app/CIJobLink.tsx

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
1-
import * as messages from '@cucumber/messages'
2-
import { faLink } from '@fortawesome/free-solid-svg-icons'
1+
import { Ci } from '@cucumber/messages'
2+
import { faServer } from '@fortawesome/free-solid-svg-icons'
33
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
4-
import React from 'react'
4+
import React, { FC } from 'react'
55

6-
interface IProps {
7-
ci: messages.Ci
8-
}
9-
10-
export const CIJobLink: React.FunctionComponent<IProps> = ({ ci: ci }) => {
11-
if (ci.url && ci.buildNumber) {
6+
export const CIJobLink: FC<{
7+
ci: Ci
8+
}> = ({ ci }) => {
9+
if (ci.url) {
1210
return (
1311
<>
14-
<FontAwesomeIcon icon={faLink} />
15-
Job <a href={ci.url}> {ci.buildNumber}</a>
12+
<FontAwesomeIcon aria-hidden="true" style={{ opacity: 0.75 }} icon={faServer} />
13+
<a href={ci.url} target="_blank" rel="noreferrer">
14+
{ci.name}
15+
</a>
1616
</>
1717
)
1818
}
19-
return <></>
19+
return (
20+
<>
21+
<FontAwesomeIcon aria-hidden="true" style={{ opacity: 0.75 }} icon={faServer} />
22+
<span>{ci.name}</span>
23+
</>
24+
)
2025
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@import '../../styles/theming';
2+
3+
.button {
4+
background-color: transparent;
5+
font-size: inherit;
6+
padding: 0;
7+
border: none;
8+
color: $anchorColor;
9+
cursor: pointer;
10+
11+
&:disabled {
12+
cursor: unset;
13+
}
14+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { render, screen, waitFor } from '@testing-library/react'
2+
import { userEvent } from '@testing-library/user-event'
3+
import { expect } from 'chai'
4+
import React from 'react'
5+
import sinon from 'sinon'
6+
7+
import { CopyButton } from './CopyButton.js'
8+
9+
describe('<CopyButton/>', () => {
10+
const originalClipboard = navigator.clipboard
11+
12+
before(() => {
13+
// @ts-expect-error overriding navigator.clipboard
14+
navigator.clipboard = {
15+
writeText: sinon.stub().resolves(),
16+
}
17+
})
18+
19+
after(() => {
20+
// @ts-expect-error overriding navigator.clipboard
21+
navigator.clipboard = originalClipboard
22+
})
23+
24+
it('should copy text to clipboard, then disable and show checkmark', async () => {
25+
render(<CopyButton text="test text" />)
26+
27+
await userEvent.click(screen.getByRole('button', { name: 'Copy' }))
28+
29+
await waitFor(() => {
30+
expect(screen.getByRole('button', { name: 'Copied' })).to.be.visible
31+
expect(screen.getByRole('button', { name: 'Copied' })).to.have.property('disabled', true)
32+
expect(navigator.clipboard.writeText).to.have.been.calledOnceWithExactly('test text')
33+
})
34+
})
35+
})

src/components/app/CopyButton.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons'
2+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
3+
import React, { FC, useState } from 'react'
4+
5+
import styles from './CopyButton.module.scss'
6+
7+
export const CopyButton: FC<{ text: string }> = ({ text }) => {
8+
const [copied, setCopied] = useState(false)
9+
10+
const handleCopy = () => {
11+
navigator.clipboard
12+
.writeText(text)
13+
.then(() => {
14+
setCopied(true)
15+
setTimeout(() => {
16+
setCopied(false)
17+
}, 3000)
18+
})
19+
.catch((err) => {
20+
console.error('Failed to copy', err)
21+
})
22+
}
23+
24+
return (
25+
<button
26+
onClick={handleCopy}
27+
aria-label={copied ? 'Copied' : 'Copy'}
28+
disabled={copied}
29+
className={styles.button}
30+
>
31+
<FontAwesomeIcon icon={copied ? faCheck : faCopy} />
32+
</button>
33+
)
34+
}
Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,5 @@
11
@import '../../styles/theming';
22

3-
.backdrop {
4-
background-color: $panelAccentColor;
5-
border: 1px solid transparent;
6-
}
7-
8-
.list {
9-
display: grid;
10-
grid-template-columns: repeat(12, 1fr);
11-
grid-template-rows: 1fr 1fr;
12-
gap: 1px;
13-
margin: 0;
14-
text-align: center;
15-
}
16-
17-
.item {
18-
grid-column-end: span 4;
19-
display: flex;
20-
flex-direction: column-reverse;
21-
justify-content: center;
22-
padding: 1.5em;
23-
background-color: $backgroundColor;
24-
color: $textColor;
25-
26-
&Ci,
27-
&Ci ~ & {
28-
grid-column-end: span 3;
29-
}
30-
}
31-
32-
.value {
33-
font-weight: bold;
34-
font-size: 1.25em;
35-
margin: 0;
36-
37-
svg {
38-
display: inline-block;
39-
max-width: 2em;
40-
}
41-
}
42-
43-
.suffix {
44-
font-size: 1em;
45-
margin-top: 0.25em;
3+
.conjunction {
464
color: $codeTextColor;
475
}
48-
49-
.gitItem {
50-
display: inline-flex;
51-
gap: 0.25em;
52-
53-
& + & {
54-
margin-left: 1em;
55-
}
56-
57-
a {
58-
color: $anchorColor;
59-
}
60-
}

src/components/app/ExecutionSummary.spec.tsx

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { Meta } from '@cucumber/messages'
2-
import { render } from '@testing-library/react'
2+
import { render, screen } from '@testing-library/react'
3+
import { userEvent } from '@testing-library/user-event'
34
import { expect } from 'chai'
45
import React from 'react'
6+
import sinon from 'sinon'
57

68
import examplesTablesFeature from '../../../acceptance/examples-tables/examples-tables.feature.js'
79
import { EnvelopesWrapper } from './EnvelopesWrapper.js'
@@ -25,30 +27,75 @@ const meta: Meta = {
2527
},
2628
}
2729

28-
describe('ExecutionSummary', () => {
29-
const envelopes = [...examplesTablesFeature, { meta }]
30+
const envelopes = [...examplesTablesFeature, { meta }]
31+
32+
describe('<ExecutionSummary/>', () => {
33+
const originalClipboard = navigator.clipboard
34+
35+
before(() => {
36+
// @ts-expect-error overriding navigator.clipboard
37+
navigator.clipboard = {
38+
writeText: sinon.stub().resolves(),
39+
}
40+
})
41+
42+
after(() => {
43+
// @ts-expect-error overriding navigator.clipboard
44+
navigator.clipboard = originalClipboard
45+
})
3046

3147
describe('meta', () => {
32-
it('should include the implementation name and version', () => {
33-
const { getByText } = render(
48+
it('should include a phrase for the setup details', () => {
49+
render(
3450
<EnvelopesWrapper envelopes={envelopes}>
3551
<ExecutionSummary />
3652
</EnvelopesWrapper>
3753
)
3854

39-
expect(getByText('cucumber-js 8.0.0-rc.1')).to.be.visible
55+
expect(screen.getByTestId('setup.phrase')).to.contain.text(
56+
57+
)
58+
})
59+
60+
it('should copy the setup details on request', async () => {
61+
render(
62+
<EnvelopesWrapper envelopes={envelopes}>
63+
<ExecutionSummary />
64+
</EnvelopesWrapper>
65+
)
66+
67+
await userEvent.click(screen.getByRole('button', { name: 'Copy' }))
68+
69+
expect(navigator.clipboard.writeText).to.have.been
70+
.calledOnceWithExactly(`Implementation: [email protected]
71+
72+
Platform: [email protected]`)
4073
})
4174

4275
it('should include the job link', () => {
43-
const { getByText } = render(
76+
render(
77+
<EnvelopesWrapper envelopes={envelopes}>
78+
<ExecutionSummary />
79+
</EnvelopesWrapper>
80+
)
81+
82+
expect(screen.getByRole('link', { name: 'GitHub Actions' }))
83+
.attr('href')
84+
.to.eq(meta?.ci?.url)
85+
})
86+
87+
it('should include the commit link', () => {
88+
render(
4489
<EnvelopesWrapper envelopes={envelopes}>
4590
<ExecutionSummary />
4691
</EnvelopesWrapper>
4792
)
4893

49-
const jobLinkElement = getByText(meta?.ci?.buildNumber as string)
50-
expect(jobLinkElement).to.be.visible
51-
expect(jobLinkElement.getAttribute('href')).to.eq(meta?.ci?.url)
94+
expect(screen.getByRole('link', { name: 'b53d820' }))
95+
.attr('href')
96+
.to.eq(
97+
'https://github.com/cucumber/cucumber-js/commit/b53d820504b31c8e4d44234dc5eaa58d6b7fdd4c'
98+
)
5299
})
53100
})
54101
})

0 commit comments

Comments
 (0)