Skip to content

Commit ece2089

Browse files
committed
WIP
1 parent da36d92 commit ece2089

Some content is hidden

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

49 files changed

+564
-1201
lines changed

package-lock.json

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

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"dependencies": {
2828
"@cucumber/gherkin-utils": "9.2.0",
2929
"@cucumber/messages": "27.2.0",
30-
"@cucumber/query": "13.2.0",
30+
"@cucumber/query": "13.5.0",
3131
"@cucumber/tag-expressions": "6.1.2",
3232
"@fortawesome/fontawesome-svg-core": "6.2.1",
3333
"@fortawesome/free-solid-svg-icons": "6.2.1",
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { TestStepResultStatus } from '@cucumber/messages'
2+
import { faChevronRight } from '@fortawesome/free-solid-svg-icons'
3+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
4+
import React, { FC, ReactNode } from 'react'
5+
import {
6+
Accordion,
7+
AccordionItem,
8+
AccordionItemButton,
9+
AccordionItemHeading,
10+
AccordionItemPanel,
11+
} from 'react-accessible-accordion'
12+
13+
import { StatusIcon } from '../gherkin/index.js'
14+
import styles from './DocumentAccordion.module.scss'
15+
import { UriProvider } from './UriProvider.js'
16+
17+
const idByUri = new Map<string, string>()
18+
function getIdByUri(uri: string): string {
19+
if (!idByUri.has(uri)) {
20+
idByUri.set(uri, crypto.randomUUID())
21+
}
22+
return idByUri.get(uri) as string
23+
}
24+
25+
interface DocumentAccordionProps {
26+
expanded: ReadonlyArray<string>
27+
children: ReactNode
28+
}
29+
30+
interface DocumentAccordionItemProps {
31+
status: TestStepResultStatus
32+
uri: string
33+
children: ReactNode
34+
}
35+
36+
export const DocumentAccordion: FC<DocumentAccordionProps> = ({ expanded, children }) => {
37+
const preExpand = expanded.map((uri) => getIdByUri(uri))
38+
return (
39+
<Accordion
40+
allowMultipleExpanded={true}
41+
allowZeroExpanded={true}
42+
preExpanded={preExpand}
43+
className={styles.accordion}
44+
>
45+
{children}
46+
</Accordion>
47+
)
48+
}
49+
50+
export const DocumentAccordionItem: FC<DocumentAccordionItemProps> = ({
51+
status,
52+
uri,
53+
children,
54+
}) => {
55+
const id = getIdByUri(uri)
56+
return (
57+
<AccordionItem uuid={id} className={styles.accordionItem}>
58+
<AccordionItemHeading>
59+
<AccordionItemButton className={styles.accordionButton}>
60+
<FontAwesomeIcon
61+
className={styles.accordionChevron}
62+
aria-hidden="true"
63+
icon={faChevronRight}
64+
/>
65+
<span className={styles.icon}>
66+
<StatusIcon status={status} />
67+
</span>
68+
<span>{uri}</span>
69+
</AccordionItemButton>
70+
</AccordionItemHeading>
71+
<AccordionItemPanel className={styles.accordionPanel}>
72+
<UriProvider uri={uri}>{children}</UriProvider>
73+
</AccordionItemPanel>
74+
</AccordionItem>
75+
)
76+
}
Lines changed: 18 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,10 @@
11
import * as messages from '@cucumber/messages'
22
import { getWorstTestStepResult } from '@cucumber/messages'
3-
import { faChevronRight } from '@fortawesome/free-solid-svg-icons'
4-
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
53
import React, { FC, useMemo, useState } from 'react'
6-
import {
7-
Accordion,
8-
AccordionItem,
9-
AccordionItemButton,
10-
AccordionItemHeading,
11-
AccordionItemPanel,
12-
} from 'react-accessible-accordion'
134

145
import { useQueries } from '../../hooks/index.js'
15-
import { GherkinDocument, MDG, StatusIcon } from '../gherkin/index.js'
16-
import styles from './GherkinDocumentList.module.scss'
17-
import { UriProvider } from './UriProvider.js'
6+
import { GherkinDocument } from '../gherkin/index.js'
7+
import { DocumentAccordion, DocumentAccordionItem } from './DocumentAccordion.js'
188

199
interface ValidGherkinDocument extends messages.GherkinDocument {
2010
uri: string
@@ -26,14 +16,6 @@ interface Props {
2616
preExpand?: boolean
2717
}
2818

29-
const idByUri = new Map<string, string>()
30-
function getIdByUri(uri: string): string {
31-
if (!idByUri.has(uri)) {
32-
idByUri.set(uri, crypto.randomUUID())
33-
}
34-
return idByUri.get(uri) as string
35-
}
36-
3719
export const GherkinDocumentList: FC<Props> = ({ gherkinDocuments, preExpand }) => {
3820
const { gherkinQuery, cucumberQuery } = useQueries()
3921
const documents = gherkinDocuments.filter(
@@ -52,59 +34,33 @@ export const GherkinDocumentList: FC<Props> = ({ gherkinDocuments, preExpand })
5234
)
5335
return new Map(entries)
5436
}, [documents, gherkinQuery, cucumberQuery])
55-
const [expanded, setExpanded] = useState<Array<string | number>>(() => {
37+
const [expanded] = useState<ReadonlyArray<string>>(() => {
5638
// Pre-expand any document that is *not* passed - assuming this is what people want to look at first
5739
return preExpand
5840
? (documents
5941
.filter((doc) => statusByUri.get(doc.uri) !== messages.TestStepResultStatus.PASSED)
60-
.map((doc) => getIdByUri(doc.uri)) as string[])
42+
.map((doc) => doc.uri) as string[])
6143
: []
6244
})
6345

6446
return (
65-
<Accordion
66-
allowMultipleExpanded={true}
67-
allowZeroExpanded={true}
68-
preExpanded={expanded}
69-
onChange={setExpanded}
70-
className={styles.accordion}
71-
>
72-
{documents.map((doc) => {
73-
const id = getIdByUri(doc.uri)
74-
const status = statusByUri.get(doc.uri)
75-
if (!status) throw new Error(`No status for ${doc.uri}`)
76-
const source = gherkinQuery.getSource(doc.uri)
77-
if (!source) throw new Error(`No source for ${doc.uri}`)
47+
<DocumentAccordion expanded={expanded}>
48+
{documents.map((gherkinDocument) => {
49+
const status = statusByUri.get(gherkinDocument.uri)
50+
if (!status) {
51+
throw new Error(`No status for ${gherkinDocument.uri}`)
52+
}
7853

7954
return (
80-
<AccordionItem key={id} uuid={id} className={styles.accordionItem}>
81-
<AccordionItemHeading>
82-
<AccordionItemButton className={styles.accordionButton}>
83-
<FontAwesomeIcon
84-
className={styles.accordionChevron}
85-
aria-hidden="true"
86-
icon={faChevronRight}
87-
/>
88-
<span className={styles.icon}>
89-
<StatusIcon status={status} />
90-
</span>
91-
<span>{doc.uri}</span>
92-
</AccordionItemButton>
93-
</AccordionItemHeading>
94-
{expanded.includes(id) && (
95-
<AccordionItemPanel className={styles.accordionPanel}>
96-
<UriProvider uri={doc.uri}>
97-
{source.mediaType === messages.SourceMediaType.TEXT_X_CUCUMBER_GHERKIN_PLAIN ? (
98-
<GherkinDocument gherkinDocument={doc} source={source} />
99-
) : (
100-
<MDG uri={doc.uri}>{source.data}</MDG>
101-
)}
102-
</UriProvider>
103-
</AccordionItemPanel>
104-
)}
105-
</AccordionItem>
55+
<DocumentAccordionItem
56+
key={gherkinDocument.uri}
57+
uri={gherkinDocument.uri}
58+
status={status}
59+
>
60+
<GherkinDocument gherkinDocument={gherkinDocument} />
61+
</DocumentAccordionItem>
10662
)
10763
})}
108-
</Accordion>
64+
</DocumentAccordion>
10965
)
11066
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { TestStepResultStatus } from '@cucumber/messages'
2+
3+
export function findMostSevereTestStepResultStatus(
4+
statuses: Iterable<TestStepResultStatus>
5+
): TestStepResultStatus {
6+
return (
7+
[...statuses].sort((a, b) => statusOrdinal(a) - statusOrdinal(b)).at(-1) ??
8+
TestStepResultStatus.UNKNOWN
9+
)
10+
}
11+
12+
function statusOrdinal(status: TestStepResultStatus) {
13+
return [
14+
TestStepResultStatus.UNKNOWN,
15+
TestStepResultStatus.PASSED,
16+
TestStepResultStatus.SKIPPED,
17+
TestStepResultStatus.PENDING,
18+
TestStepResultStatus.UNDEFINED,
19+
TestStepResultStatus.AMBIGUOUS,
20+
TestStepResultStatus.FAILED,
21+
].indexOf(status)
22+
}

0 commit comments

Comments
 (0)