Skip to content

Commit

Permalink
feat: tests coverage block
Browse files Browse the repository at this point in the history
  • Loading branch information
atanasster committed Apr 23, 2021
1 parent c0363db commit 3362c12
Show file tree
Hide file tree
Showing 17 changed files with 1,795 additions and 74 deletions.
9 changes: 3 additions & 6 deletions core/core/src/jest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ export interface CoverageMetrics {
pct: number;
}

export interface JestCoverage {
lines: CoverageMetrics;
functions: CoverageMetrics;
statements: CoverageMetrics;
branches: CoverageMetrics;
}
export type CoverageKind = 'lines' | 'functions' | 'statements' | 'branches';

export type JestCoverage = Record<CoverageKind, CoverageMetrics>;

export type JestResult = Pick<
JestTestResult,
Expand Down
181 changes: 181 additions & 0 deletions ui/blocks/src/TestsCoverage/BaseTestsCoverage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/* eslint-disable react/display-name */
/** @jsx jsx */
import { FC, useMemo } from 'react';
import { jsx, Box } from 'theme-ui';
import { mix } from 'polished';
import {
Table,
TableProps,
Column,
Tag,
useTheme,
} from '@component-controls/components';
import {
CoverageKind,
CoverageMetrics,
Component,
} from '@component-controls/core';

type TestRow = { filePath: string; kind: CoverageKind } & CoverageMetrics;

export type BaseTestsCoverageProps = {
component?: Component;
pagination?: TableProps<TestRow>['pagination'];
};

/**
* Displays commit history for a component
*/
export const BaseTestsCoverage: FC<BaseTestsCoverageProps> = ({
component,
pagination = { totalCountVisible : false},
}) => {
const theme = useTheme();
const columns = useMemo(() => {
return [
{
Header: 'Test file',
accessor: 'filePath',
Cell: ({ value }) => {
return <div>{value}</div>;
},
},
{
Header: 'Kind',
accessor: 'kind',
Cell: ({ value }) => {
return <Box sx={{ fontWeight: 'heading' }}>{value}</Box>;
},
},
{
Header: 'Total',
accessor: 'total',
Cell: ({ value }) => (
<div
sx={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
}}
>
{value}
</div>
),
},
{
Header: 'Covered',
accessor: 'covered',
Cell: ({ value }) => (
<div
sx={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
}}
>
{value}
</div>
),
},
{
Header: 'Sipped',
accessor: 'skipped',
Cell: ({ value }) => (
<div
sx={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
}}
>
{value}
</div>
),
},
{
Header: '%',
accessor: 'pct',
Cell: ({ value }) =>
theme?.colors ? (
<div
sx={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
}}
>
<Tag
color={mix(
`${(value / 100).toFixed(1)}`,
theme.colors.status_passed as string,
theme.colors.status_failed as string,
)}
>
{`${value}%`}
</Tag>
</div>
) : null,
},
] as Column<TestRow>[];
}, []);
const data = useMemo(() => {
const coverage = component?.jest?.coverage;
return coverage
? Object.keys(coverage).reduce((acc: TestRow[], key) => {
return [
...acc,
{
filePath: key,
kind: 'lines' as CoverageKind,
...coverage[key].lines,
},
{
filePath: key,
kind: 'functions' as CoverageKind,
...coverage[key].functions,
},
{
filePath: key,
kind: 'statements' as CoverageKind,
...coverage[key].statements,
},
{
filePath: key,
kind: 'branches' as CoverageKind,
...coverage[key].branches,
},
];
}, [])
: undefined;
}, [component?.jest?.coverage]);
const expanded = useMemo(
() =>
component?.jest?.coverage
? Object.keys(component.jest.coverage).reduce(
(acc: Record<string, boolean>, filePath) => {
const key = `filePath:${filePath}`;
if (!acc[key]) {
return { ...acc, [key]: true };
}
return acc;
},
{},
)
: undefined,
[component?.jest?.coverage],
);
if (!component?.jest) {
return null;
}
return (
<Table<TestRow>
itemsLabel={null}
sorting={true}
data={data}
columns={columns}
expanded={expanded}
groupBy={['filePath']}
pagination={pagination}
/>
);
};
22 changes: 22 additions & 0 deletions ui/blocks/src/TestsCoverage/TestsCoverage.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { Document, Example } from '@component-controls/core';
import { TestsCoverage, TestsCoverageProps } from './TestsCoverage';
import { makeDecorators } from '../test/MockContext';

export default {
title: 'Blocks/TestsCoverage',
component: TestsCoverage,
category: ' Component',
decorators: makeDecorators('blocks-core-story-plain--controls'),
} as Document;

export const overview: Example = () => (
<TestsCoverage id="." name="Test results" />
);

export const pagination: Example<TestsCoverageProps['pagination']> = props => (
<TestsCoverage id="." name="Test results" pagination={props} />
);

pagination.smartControls = { smart: false };
pagination.controls = { pageSize: 4, pageVisible: true };
26 changes: 26 additions & 0 deletions ui/blocks/src/TestsCoverage/TestsCoverage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as path from 'path';
import { loadConfigurations } from '@component-controls/config';
import { renderDocument } from '@component-controls/test-renderers';
import { render, act } from '@testing-library/react';
import { renderErr } from '@component-controls/test-renderers';

import * as examples from './TestsCoverage.stories';

describe('TestsCoverage', () => {
const configPath = path.resolve(__dirname, '../../.config');
const config = loadConfigurations(configPath);
let renderedExamples: ReturnType<typeof renderDocument> = [];
act(() => {
renderedExamples = renderDocument(examples, config);
});
if (!renderedExamples) {
renderErr();
return;
}
renderedExamples.forEach(({ name, rendered }) => {
it(name, async () => {
const { asFragment } = render(rendered);
expect(asFragment()).toMatchSnapshot();
});
});
});
38 changes: 38 additions & 0 deletions ui/blocks/src/TestsCoverage/TestsCoverage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* eslint-disable react/display-name */
/** @jsx jsx */
import { FC } from 'react';
import { jsx } from 'theme-ui';
import {
BlockContainer,
BlockContainerProps,
} from '@component-controls/components';
import { StoryInputProps, useStoryComponent } from '@component-controls/store';
import { BaseTestsCoverage, BaseTestsCoverageProps } from './BaseTestsCoverage';
import { useCustomProps } from '../context';

export type TestsCoverageProps = BlockContainerProps &
StoryInputProps &
Pick<BaseTestsCoverageProps, 'pagination'>;

/**
* Displays jest tests coverage for a component, within a block
*/
export const TestsCoverage: FC<TestsCoverageProps> = ({
id,
name,
pagination,
...rest
}) => {
const props = useCustomProps<TestsCoverageProps>('tests_coverage', rest);
const component = useStoryComponent({ id, name });
console.log(component);
if (!component?.jest) {
return null;
}

return (
<BlockContainer {...props}>
<BaseTestsCoverage component={component} pagination={pagination} />
</BlockContainer>
);
};
Loading

0 comments on commit 3362c12

Please sign in to comment.