Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addon-jest: UI Redesign #7424

Merged
merged 47 commits into from
Jul 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
c68deb5
removed color file from message class
CodeByAlex Jun 18, 2019
eb42c1a
removed colors file from jest addon
CodeByAlex Jun 18, 2019
20d3f8e
removed indicator component from jest addon
CodeByAlex Jun 18, 2019
08fc66f
modified panel and result of the jest testing addon to look and feel …
CodeByAlex Jun 18, 2019
3a93467
removed console.log from message component
CodeByAlex Jun 18, 2019
58e3d6e
changed green and red progress colors to theme colors
CodeByAlex Jun 23, 2019
189f785
changed tab button to accept text color variable
CodeByAlex Jun 23, 2019
616dbbb
added story for tab components to show button text color being set
CodeByAlex Jun 23, 2019
bca648b
used textColor in the panel to set tab buttons
CodeByAlex Jun 23, 2019
4847b51
added background color prop to bar props
CodeByAlex Jun 24, 2019
8586060
added background color in tabs component
CodeByAlex Jun 24, 2019
3f0bc57
added background color to panel where tabs component is used
CodeByAlex Jun 24, 2019
660178e
modified jest config so that jest tests could run in the official sto…
CodeByAlex Jun 28, 2019
6a0961d
refactored message component to reduce code complexity - still need t…
CodeByAlex Jun 28, 2019
35dbfbb
Update Message.tsx
CodeByAlex Jun 28, 2019
1cad06a
added test vs tests condition for display value
CodeByAlex Jun 30, 2019
59a78ea
hide pointer and hover state on passing tests
CodeByAlex Jun 30, 2019
6af0198
Merge branch 'feature/jest-redesign' of https://github.com/CodeByAlex…
CodeByAlex Jun 30, 2019
b74209c
added trim to stack trace and !== instead of !=
CodeByAlex Jun 30, 2019
2a7a2cf
pulled out message parse functionality from component into separate …
CodeByAlex Jul 2, 2019
071a69c
colorized text in message component of the jest addon
CodeByAlex Jul 2, 2019
c55b0da
bumped jest versions in official example
CodeByAlex Jul 2, 2019
bd3f0fa
Merge branch 'next' into feature/jest-redesign
CodeByAlex Jul 2, 2019
9f232c5
updated message component to be less specific in the result condition…
CodeByAlex Jul 7, 2019
847d90d
changed variable name i to index
CodeByAlex Jul 7, 2019
aaa476b
Ensured backwards compatibility with previous test result formatting …
CodeByAlex Jul 12, 2019
b8f709d
used theme colors where possible and fixed commit hook errors
CodeByAlex Jul 12, 2019
f969b5f
removed unused code
CodeByAlex Jul 13, 2019
c61518a
Merge branch 'next' of https://github.com/storybooks/storybook into f…
CodeByAlex Jul 13, 2019
9eabbbb
removed console log
CodeByAlex Jul 13, 2019
045c024
added spacing
CodeByAlex Jul 13, 2019
47829cc
updated yarn lock
CodeByAlex Jul 13, 2019
5d0c2ec
Fixed flex bar props
CodeByAlex Jul 13, 2019
2accbf0
Fixed ts lint issues
CodeByAlex Jul 13, 2019
3d0790e
fixed ts issues
CodeByAlex Jul 14, 2019
b8c8b00
Fixed tabs story
CodeByAlex Jul 14, 2019
5842e84
Merge branch 'next' of https://github.com/storybooks/storybook into f…
CodeByAlex Jul 14, 2019
2954e2a
modified font size and color for the test detail section
CodeByAlex Jul 16, 2019
4df0199
made the progress information mobile friendly
CodeByAlex Jul 16, 2019
1da3506
pulll width out
CodeByAlex Jul 16, 2019
87bba55
Increased width breakpoint
CodeByAlex Jul 16, 2019
c197a9b
Removed @ts-ignore from jest panel
CodeByAlex Jul 17, 2019
9c57cfa
converted colors to tokens and removed passing rate
CodeByAlex Jul 17, 2019
0669a80
Merge branch 'feature/jest-redesign' of ssh://github.com/storybookjs/…
CodeByAlex Jul 17, 2019
1948cc2
corrected theme usage
CodeByAlex Jul 17, 2019
b1d31db
convert result component to hook
CodeByAlex Jul 18, 2019
214504a
Merge branch 'next' into feature/jest-redesign
ndelangen Jul 19, 2019
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 addons/jest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"core-js": "^3.0.1",
"global": "^4.3.2",
"react": "^16.8.3",
"react-sizeme": "^2.5.2",
"upath": "^1.1.0",
"util-deprecate": "^1.0.2"
},
Expand Down
6 changes: 0 additions & 6 deletions addons/jest/src/colors.ts

This file was deleted.

37 changes: 0 additions & 37 deletions addons/jest/src/components/Indicator.ts

This file was deleted.

315 changes: 137 additions & 178 deletions addons/jest/src/components/Message.tsx
Original file line number Diff line number Diff line change
@@ -1,205 +1,164 @@
/* eslint-disable react/no-array-index-key */
/* eslint-disable no-param-reassign */
/* eslint-disable no-control-regex */
/* tslint:disable:object-literal-sort-keys */

import React from 'react';
import React, { Fragment } from 'react';
import { styled } from '@storybook/theming';
import colors from '../colors';

const patterns = [/^\x08+/, /^\x1b\[[012]?K/, /^\x1b\[?[\d;]{0,3}/];
const positiveConsoleRegex = /\[32m(.*?)\[39m/;
const negativeConsoleRegex = /\[31m(.*?)\[39m/;
const positiveType = 'positive';
const negativeType = 'negative';
const endToken = '[39m';
const failStartToken = '[31m';
const passStartToken = '[32m';
const stackTraceStartToken = 'at';
const titleEndToken = ':';

const Pre = styled.pre({
margin: 0,
});
type MsgElement = string | JSX.Element;

const Positive = styled.strong({
color: colors.success,
fontWeight: 500,
});
const Negative = styled.strong({
color: colors.error,
fontWeight: 500,
});
class TestDetail {
description: MsgElement[];

interface StackTraceProps {
trace: MsgElement[];
className?: string;
}
result: MsgElement[];

const StackTrace = styled(({ trace, className }: StackTraceProps) => (
<details className={className}>
<summary>Callstack</summary>
{trace
.join('')
.trim()
.split(/\n/)
.map((traceLine, traceLineIndex) => (
<div key={traceLineIndex}>{traceLine.trim()}</div>
))}
</details>
))({
background: '#e2e2e2',
padding: 10,
stackTrace: string;
}
const StackTrace = styled.pre<{}>(({ theme }) => ({
background: theme.color.lighter,
paddingTop: '4px',
paddingBottom: '4px',
paddingLeft: '6px',
borderRadius: '2px',
overflow: 'auto',
margin: '10px 30px 10px 30px',
whiteSpace: 'pre',
}));

const Results = styled.div({
paddingTop: '10px',
marginLeft: '31px',
marginRight: '30px',
});

const Main = styled(({ msg, className }) => <section className={className}>{msg}</section>)({
padding: 10,
borderBottom: '1px solid #e2e2e2',
});

interface SubProps {
msg: MsgElement[];
className?: string;
}
const Description = styled.div<{}>(({ theme }) => ({
paddingBottom: '10px',
paddingTop: '10px',
borderBottom: theme.appBorderColor,
marginLeft: '31px',
marginRight: '30px',
overflowWrap: 'break-word',
}));

const StatusColor = styled.strong<{ status: string }>(({ status, theme }) => ({
color: status === positiveType ? theme.color.positive : theme.color.negative,
fontWeight: 500,
}));

const Sub = styled(({ msg, className }: SubProps) => (
<section className={className}>
{msg
.filter(item => typeof item !== 'string' || item.trim() !== '')
.map((item, index, list) => {
if (typeof item === 'string') {
if (index === 0 && index === list.length - 1) {
return item.trim();
}
if (index === 0) {
return item.replace(/^[\s\n]*/, '');
}
if (index === list.length - 1) {
return item.replace(/[\s\n]*$/, '');
}
}
return item;
})}
</section>
))({
padding: 10,
const Main = styled(({ msg, className }) => <section className={className}>{msg}</section>)({
padding: 5,
});

interface SubgroupOptions {
startTrigger: (e: MsgElement) => boolean;
endTrigger: (e: MsgElement) => boolean;
grouper: (list: MsgElement[], key: number) => JSX.Element;
accList?: MsgElement[];
grouped?: MsgElement[];
grouperIndex?: number;
mode?: 'inject' | 'stop';
injectionPoint?: number;
}

const createSubgroup = ({
startTrigger,
endTrigger,
grouper,
accList = [],
grouped = [],
grouperIndex = 0,
mode,
injectionPoint,
}: SubgroupOptions) => (acc: MsgElement[], item: MsgElement, i: number, list: MsgElement[]) => {
grouperIndex += 1;

// start or stop extraction
if (startTrigger(item)) {
mode = 'inject';
injectionPoint = i;
}
if (endTrigger(item)) {
mode = 'stop';
const colorizeText: (msg: string, type: string) => MsgElement[] = (msg: string, type: string) => {
if (type) {
return msg
.split(type === positiveType ? positiveConsoleRegex : negativeConsoleRegex)
.map((i, index) =>
index % 2 ? (
<StatusColor key={`${type}_${i}`} status={type}>
{i}
</StatusColor>
) : (
i
)
);
}
return [msg];
};

// push item in correct aggregator
if (mode === 'inject') {
grouped.push(item);
} else {
accList.push(item);
}
const getConvertedText: (msg: string) => MsgElement[] = (msg: string) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a couple unit tests for this?

let elementArray: MsgElement[] = [];

if (!msg) return elementArray;

// on last iteration inject at detected injection point, and group
if (i === list.length - 1) {
// Provide a "safety net" when Jest returns a partially recognized "group"
// (recognized by acc.startTrigger but acc.endTrigger was never found) and
// it's the only group in output for a test result. In that case, accList
// will be empty, so return whatever was found, even if it will be unstyled
// and prevent next createSubgroup calls from throwing due to empty lists.
accList.push(null);

return accList.reduce<MsgElement[]>((eacc, el, ei) => {
if (injectionPoint === 0 && ei === 0) {
// at index 0, inject before
return eacc.concat(grouper(grouped, grouperIndex)).concat(el);
const splitText = msg
.split(/\[2m/)
.join('')
.split(/\[22m/);

splitText.forEach(element => {
if (element && element.trim()) {
if (
element.indexOf(failStartToken) > -1 &&
element.indexOf(failStartToken) < element.indexOf(endToken)
) {
elementArray = elementArray.concat(colorizeText(element, negativeType));
} else if (
element.indexOf(passStartToken) > -1 &&
element.indexOf(passStartToken) < element.indexOf(endToken)
) {
elementArray = elementArray.concat(colorizeText(element, positiveType));
} else {
elementArray = elementArray.concat(element);
}
if (injectionPoint > 0 && injectionPoint === ei + 1) {
// at index > 0, and next index WOULD BE injectionPoint, inject after
return eacc.concat(el).concat(grouper(grouped, grouperIndex));
}
});
return elementArray;
};

const getTestDetail: (msg: string) => TestDetail = (msg: string) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a couple unit tests for this?

const lines = msg.split('\n').filter(Boolean);

const testDetail: TestDetail = new TestDetail();
testDetail.description = getConvertedText(lines[0]);
testDetail.stackTrace = '';
testDetail.result = [];

for (let index = 1; index < lines.length; index += 1) {
const current = lines[index];
const next = lines[index + 1];

if (
current
.trim()
.toLowerCase()
.indexOf(stackTraceStartToken) === 0
) {
testDetail.stackTrace += `${current.trim()}\n`;
} else if (current.trim().indexOf(titleEndToken) > -1) {
let title;
let value = null;
if (current.trim().indexOf(titleEndToken) === current.length - 1) {
// there are breaks in the middle of result
title = current.trim();
value = getConvertedText(next);
index += 1;
} else {
// results come in a single line
title = current.substring(0, current.indexOf(titleEndToken)).trim();
value = getConvertedText(current.substring(current.indexOf(titleEndToken), current.length));
}
// do not inject
return eacc.concat(el);
}, []);
testDetail.result = [...testDetail.result, title, ' ', ...value, <br key={index} />];
} else {
// results come in an unexpected format
testDetail.result = [...testDetail.result, ' ', ...getConvertedText(current)];
}
}
return acc;

return testDetail;
};

interface MessageProps {
msg: string;
}

type MsgElement = string | JSX.Element;

const Message = ({ msg }: MessageProps) => {
const data = patterns
.reduce((acc, regex) => acc.replace(regex, ''), msg)
.split(/\[2m/)
.join('')
.split(/\[22m/)
.reduce((acc, item) => acc.concat(item), [] as string[])
.map((item, li) =>
item
.split(/\[32m(.*?)\[39m/)
.map((i, index) => (index % 2 ? <Positive key={`p_${li}_${i}`}>{i}</Positive> : i))
)
.reduce((acc, item) => acc.concat(item))
.map((item, li) =>
typeof item === 'string'
? item
.split(/\[31m(.*?)\[39m/)
.map((i, index) => (index % 2 ? <Negative key={`n_${li}_${i}`}>{i}</Negative> : i))
: item
)
.reduce<MsgElement[]>((acc, item) => acc.concat(item), [])
.reduce(
createSubgroup({
startTrigger: e => typeof e === 'string' && e.indexOf('Error: ') === 0,
endTrigger: e => typeof e === 'string' && Boolean(e.match('Expected ')),
grouper: (list, key) => <Main key={key} msg={list} />,
}),
[]
)
.reduce(
(acc, it) =>
typeof it === 'string' ? acc.concat(it.split(/(at(.|\n)+\d+:\d+\))/)) : acc.concat(it),
[] as MsgElement[]
)
.reduce((acc, item) => acc.concat(item), [] as MsgElement[])
.reduce(
createSubgroup({
startTrigger: e => typeof e === 'string' && e.indexOf('Expected ') !== -1,
endTrigger: e => typeof e === 'string' && Boolean(e.match(/^at/)),
grouper: (list, key) => <Sub key={key} msg={list} />,
}),
[]
)
.reduce(
createSubgroup({
startTrigger: e => typeof e === 'string' && Boolean(e.match(/at(.|\n)+\d+:\d+\)/)),
endTrigger: () => false,
grouper: (list, key) => <StackTrace key={key} trace={list} />,
}),
[]
);

return <Pre>{data}</Pre>;
export const Message = (props: any) => {
const { msg } = props;

const detail: TestDetail = getTestDetail(msg);
return (
<Fragment>
{detail.description ? <Description>{detail.description}</Description> : null}
{detail.result ? <Results>{detail.result}</Results> : null}
{detail.stackTrace ? <StackTrace>{detail.stackTrace}</StackTrace> : null}
</Fragment>
);
};

export default Message;
Loading