Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Include duration for each test step ([#396](https://github.com/cucumber/react-components/pull/396))
- Include pass rate in execution summary ([#397](https://github.com/cucumber/react-components/pull/397))
- Add new `<Report/>` component ([#410](https://github.com/cucumber/react-components/pull/410))
- Add new `<TestRunHooks/>` component and include in report ([#408](https://github.com/cucumber/react-components/pull/408))

### Changed
- Render a more test case-centric report ([#396](https://github.com/cucumber/react-components/pull/396))
Expand Down
4 changes: 4 additions & 0 deletions src/components/app/Report.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ExecutionSummary } from './ExecutionSummary.js'
import { FilteredDocuments } from './FilteredDocuments.js'
import styles from './Report.module.scss'
import { SearchBar } from './SearchBar.js'
import { TestRunHooks } from './TestRunHooks.js'

export const Report: FC = () => {
return (
Expand All @@ -15,6 +16,9 @@ export const Report: FC = () => {
<section>
<FilteredDocuments />
</section>
<section>
<TestRunHooks />
</section>
</article>
)
}
16 changes: 16 additions & 0 deletions src/components/app/TestRunHooks.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.empty {
font-style: italic;
}

.hooks {
padding: 0;
list-style: none;

> li {
list-style: none;

&:not(:empty) {
padding: 0.125em 0;
}
}
}
52 changes: 52 additions & 0 deletions src/components/app/TestRunHooks.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Envelope } from '@cucumber/messages'
import { Story } from '@ladle/react'
import React from 'react'

import emptySample from '../../../acceptance/empty/empty.js'
import globalHooksSample from '../../../acceptance/global-hooks/global-hooks.js'
import globalHooksAfterAllErrorSample from '../../../acceptance/global-hooks-afterall-error/global-hooks-afterall-error.js'
import globalHooksAttachmentsSample from '../../../acceptance/global-hooks-attachments/global-hooks-attachments.js'
import globalHooksBeforeAllErrorSample from '../../../acceptance/global-hooks-beforeall-error/global-hooks-beforeall-error.js'
import { EnvelopesProvider } from './index.js'
import { TestRunHooks } from './TestRunHooks.js'

type TemplateArgs = {
envelopes: readonly Envelope[]
}

const Template: Story<TemplateArgs> = ({ envelopes }) => {
return (
<EnvelopesProvider envelopes={envelopes}>
<TestRunHooks />
</EnvelopesProvider>
)
}

export default {
title: 'App/TestRunHooks',
}

export const Empty = Template.bind({})
Empty.args = {
envelopes: emptySample,
}

export const Default = Template.bind({})
Default.args = {
envelopes: globalHooksSample,
}

export const WithAttachments = Template.bind({})
WithAttachments.args = {
envelopes: globalHooksAttachmentsSample,
}

export const BeforeAllError = Template.bind({})
BeforeAllError.args = {
envelopes: globalHooksBeforeAllErrorSample,
}

export const AfterAllError = Template.bind({})
AfterAllError.args = {
envelopes: globalHooksAfterAllErrorSample,
}
23 changes: 23 additions & 0 deletions src/components/app/TestRunHooks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { FC } from 'react'

import { useTestRunHooks } from '../../hooks/useTestRunHooks.js'
import { TestRunHookOutcome } from '../results/TestRunHookOutcome.js'
import styles from './TestRunHooks.module.scss'

export const TestRunHooks: FC = () => {
const hooks = useTestRunHooks()

if (hooks.length === 0) {
return <p className={styles.empty}>No test run hooks were executed.</p>
}

return (
<ol className={styles.hooks}>
{hooks.map(({ testRunHookFinished, hook }) => {
return (
<TestRunHookOutcome key={hook.id} hook={hook} testRunHookFinished={testRunHookFinished} />
)
})}
</ol>
)
}
1 change: 1 addition & 0 deletions src/components/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export * from './QueriesProvider.js'
export * from './Report.js'
export * from './SearchBar.js'
export * from './StatusesSummary.js'
export * from './TestRunHooks.js'
export * from './UrlSearchProvider.js'
36 changes: 36 additions & 0 deletions src/components/results/TestRunHookOutcome.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.header {
display: flex;
width: 100%;
gap: 0.25rem;
}

.status {
padding-top: 0.1em;
}

.title {
> * {
vertical-align: middle;

& + * {
margin-left: 0.5em;
}
}
}

.name {
font-size: 1em;
display: inline;
font-weight: normal;
padding: 0;
margin: 0;
}

.content {
margin-left: 1.125rem;

// bits of detail (doc string, data table, error, attachments) get consistent spacing between them
> * {
margin-top: 0.25rem !important;
}
}
35 changes: 35 additions & 0 deletions src/components/results/TestRunHookOutcome.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Hook, HookType, TestRunHookFinished } from '@cucumber/messages'
import React, { FC } from 'react'

import { StatusIcon } from '../gherkin/index.js'
import styles from './TestRunHookOutcome.module.scss'
import { TestStepAttachments } from './TestStepAttachments.js'
import { TestStepDuration } from './TestStepDuration.js'
import { TestStepResultDetails } from './TestStepResultDetails.js'

interface Props {
hook: Hook
testRunHookFinished: TestRunHookFinished
}

export const TestRunHookOutcome: FC<Props> = ({ hook, testRunHookFinished }) => {
return (
<li data-status={testRunHookFinished.result.status}>
<div className={styles.header}>
<div className={styles.status}>
<StatusIcon status={testRunHookFinished.result.status} />
</div>
<div className={styles.title}>
<h3 className={styles.name}>
{hook.name ?? (hook.type === HookType.BEFORE_TEST_RUN ? 'BeforeAll' : 'AfterAll')}
</h3>
<TestStepDuration duration={testRunHookFinished.result.duration} />
</div>
</div>
<div className={styles.content}>
<TestStepResultDetails {...testRunHookFinished.result} />
<TestStepAttachments testStepOrHookFinished={testRunHookFinished} />
</div>
</li>
)
}
8 changes: 4 additions & 4 deletions src/components/results/TestStepAttachments.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TestStepFinished } from '@cucumber/messages'
import { TestRunHookFinished, TestStepFinished } from '@cucumber/messages'
import React from 'react'
import { FC } from 'react'

Expand All @@ -7,12 +7,12 @@ import { Attachment } from '../gherkin/index.js'
import styles from './TestStepAttachments.module.scss'

interface Props {
testStepFinished: TestStepFinished
testStepOrHookFinished: TestStepFinished | TestRunHookFinished
}

export const TestStepAttachments: FC<Props> = ({ testStepFinished }) => {
export const TestStepAttachments: FC<Props> = ({ testStepOrHookFinished }) => {
const { cucumberQuery } = useQueries()
const attachments = cucumberQuery.findAttachmentsBy(testStepFinished)
const attachments = cucumberQuery.findAttachmentsBy(testStepOrHookFinished)
return (
<ol className={styles.attachments}>
{attachments.map((attachment, index) => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/results/TestStepOutcome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const TestStepOutcome: FC<Props> = ({ testStep, testStepFinished }) => {
<div className={styles.content}>
{testStep.pickleStepId && <PickleStepArgument testStep={testStep} />}
<TestStepResultDetails {...testStepFinished.testStepResult} />
<TestStepAttachments testStepFinished={testStepFinished} />
<TestStepAttachments testStepOrHookFinished={testStepFinished} />
</div>
</li>
)
Expand Down
6 changes: 6 additions & 0 deletions src/hooks/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export function ensure<T>(value: T | undefined, message: string): T {
if (!value) {
throw new Error(message)
}
return value
}
24 changes: 24 additions & 0 deletions src/hooks/useTestRunHooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Hook, TestRunHookFinished } from '@cucumber/messages'

import { ensure } from './helpers.js'
import { useQueries } from './useQueries.js'

type RunHooksList = { testRunHookFinished: TestRunHookFinished; hook: Hook }[]

export function useTestRunHooks(): RunHooksList {
const { cucumberQuery } = useQueries()
const testRunHooksFinished: ReadonlyArray<TestRunHookFinished> =
cucumberQuery.findAllTestRunHookFinished()

return testRunHooksFinished.map((testRunHookFinished) => {
const hook = ensure(
cucumberQuery.findHookBy(testRunHookFinished),
'Expected testRunHookFinished to resolve with a hook'
)

return {
testRunHookFinished,
hook,
}
})
}