-
-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
Migrate @storybook/addon-jest to TS #6403
Changes from all commits
afa2fd3
17e8592
c3e21c0
435ab82
18c7907
9654bb1
fe2488b
6a4a14b
8e919f8
bbe53db
3502a03
1147dda
f8db8e5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,18 +23,18 @@ | |
"license": "MIT", | ||
"author": "Renaud Tertrais <[email protected]> (https://github.com/renaudtertrais)", | ||
"main": "dist/index.js", | ||
"jsnext:main": "src/index.js", | ||
"types": "dist/index.d.ts", | ||
"scripts": { | ||
"prepare": "node ../../scripts/prepare.js" | ||
}, | ||
"dependencies": { | ||
"@storybook/addons": "5.1.0-alpha.22", | ||
"@storybook/api": "^5.1.0-alpha.22", | ||
"@storybook/components": "5.1.0-alpha.22", | ||
"@storybook/core-events": "5.1.0-alpha.22", | ||
"@storybook/theming": "5.1.0-alpha.22", | ||
"core-js": "^2.6.5", | ||
"global": "^4.3.2", | ||
"prop-types": "^15.7.2", | ||
"react": "^16.8.4", | ||
"upath": "^1.1.0", | ||
"util-deprecate": "^1.0.2" | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,202 @@ | ||||||
/* tslint:disable:object-literal-sort-keys */ | ||||||
|
||||||
import React from 'react'; | ||||||
import { styled } from '@storybook/theming'; | ||||||
import colors from '../colors'; | ||||||
|
||||||
const patterns = [/^\x08+/, /^\x1b\[[012]?K/, /^\x1b\[?[\d;]{0,3}/]; | ||||||
|
||||||
const Pre = styled.pre({ | ||||||
margin: 0, | ||||||
}); | ||||||
|
||||||
const Positive = styled.strong({ | ||||||
color: colors.success, | ||||||
fontWeight: 500, | ||||||
}); | ||||||
const Negative = styled.strong({ | ||||||
color: colors.error, | ||||||
fontWeight: 500, | ||||||
}); | ||||||
|
||||||
interface StackTraceProps { | ||||||
trace: MsgElement[]; | ||||||
className?: string; | ||||||
} | ||||||
|
||||||
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: 'silver', | ||||||
padding: 10, | ||||||
overflow: 'auto', | ||||||
}); | ||||||
|
||||||
const Main = styled(({ msg, className }) => <section className={className}>{msg}</section>)({ | ||||||
padding: 10, | ||||||
borderBottom: '1px solid silver', | ||||||
}); | ||||||
|
||||||
interface SubProps { | ||||||
msg: MsgElement[]; | ||||||
className?: string; | ||||||
} | ||||||
|
||||||
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') { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. seems odd you filter for anything that isn't a string, then do something for only strings. seems like this code could be clearer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It filters for not empty strings, then removes line breaks for those strings |
||||||
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, | ||||||
}); | ||||||
|
||||||
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'; | ||||||
} | ||||||
|
||||||
// push item in correct aggregator | ||||||
if (mode === 'inject') { | ||||||
grouped.push(item); | ||||||
} else { | ||||||
accList.push(item); | ||||||
} | ||||||
|
||||||
// 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); | ||||||
} | ||||||
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)); | ||||||
} | ||||||
// do not inject | ||||||
return eacc.concat(el); | ||||||
}, []); | ||||||
} | ||||||
return acc; | ||||||
}; | ||||||
|
||||||
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), []) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case TS throws error |
||||||
.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 default Message; |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these colours should come from the theme if possible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I don't find similar colors in
lib/theming/src/base.ts