Skip to content

Commit 6d85a5f

Browse files
kasperpeulenstorybook-bot
authored andcommitted
Merge pull request #29110 from storybookjs/kasper/fix-ansi-chars
Addon-Interactions: Use ansi-to-html for colored test errors (cherry picked from commit 1d27f37)
1 parent e159e49 commit 6d85a5f

File tree

7 files changed

+41
-9
lines changed

7 files changed

+41
-9
lines changed

code/addons/interactions/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"@devtools-ds/object-inspector": "^1.1.2",
6363
"@storybook/icons": "^1.2.5",
6464
"@types/node": "^22.0.0",
65+
"ansi-to-html": "^0.7.2",
6566
"formik": "^2.2.9",
6667
"react": "^18.2.0",
6768
"react-dom": "^18.2.0",

code/addons/interactions/src/components/Interaction.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { type Call, CallStates, type ControlStates } from '@storybook/instrument
88

99
import { transparentize } from 'polished';
1010

11-
import { isChaiError, isJestError } from '../utils';
11+
import { isChaiError, isJestError, useAnsiToHtmlFilter } from '../utils';
1212
import type { Controls } from './InteractionsPanel';
1313
import { MatcherResult } from './MatcherResult';
1414
import { MethodCall } from './MethodCall';
@@ -116,6 +116,7 @@ const RowMessage = styled('div')(({ theme }) => ({
116116
}));
117117

118118
export const Exception = ({ exception }: { exception: Call['exception'] }) => {
119+
const filter = useAnsiToHtmlFilter();
119120
if (isJestError(exception)) {
120121
return <MatcherResult {...exception} />;
121122
}
@@ -135,7 +136,7 @@ export const Exception = ({ exception }: { exception: Call['exception'] }) => {
135136
const more = paragraphs.length > 1;
136137
return (
137138
<RowMessage>
138-
<pre>{paragraphs[0]}</pre>
139+
<pre dangerouslySetInnerHTML={{ __html: filter.toHtml(paragraphs[0]) }}></pre>
139140
{more && <p>See the full stack trace in the browser console.</p>}
140141
</RowMessage>
141142
);

code/addons/interactions/src/components/InteractionsPanel.tsx

+8-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { type Call, CallStates, type ControlStates } from '@storybook/instrument
66

77
import { transparentize } from 'polished';
88

9-
import { isTestAssertionError } from '../utils';
9+
import { isTestAssertionError, useAnsiToHtmlFilter } from '../utils';
1010
import { Empty } from './EmptyState';
1111
import { Interaction } from './Interaction';
1212
import { Subnav } from './Subnav';
@@ -97,6 +97,7 @@ export const InteractionsPanel: React.FC<InteractionsPanelProps> = React.memo(
9797
onScrollToEnd,
9898
endRef,
9999
}) {
100+
const filter = useAnsiToHtmlFilter();
100101
return (
101102
<Container>
102103
{(interactions.length > 0 || hasException) && (
@@ -131,9 +132,12 @@ export const InteractionsPanel: React.FC<InteractionsPanelProps> = React.memo(
131132
<CaughtExceptionTitle>
132133
Caught exception in <CaughtExceptionCode>play</CaughtExceptionCode> function
133134
</CaughtExceptionTitle>
134-
<CaughtExceptionStack data-chromatic="ignore">
135-
{printSerializedError(caughtException)}
136-
</CaughtExceptionStack>
135+
<CaughtExceptionStack
136+
data-chromatic="ignore"
137+
dangerouslySetInnerHTML={{
138+
__html: filter.toHtml(printSerializedError(caughtException)),
139+
}}
140+
></CaughtExceptionStack>
137141
</CaughtException>
138142
)}
139143
{unhandledErrors && (

code/addons/interactions/src/components/MatcherResult.tsx

+9-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22

33
import { styled, typography } from 'storybook/internal/theming';
44

5+
import { useAnsiToHtmlFilter } from '../utils';
56
import { Node } from './MethodCall';
67

78
const getParams = (line: string, fromIndex = 0): string => {
@@ -59,6 +60,7 @@ export const MatcherResult = ({
5960
message: string;
6061
style?: React.CSSProperties;
6162
}) => {
63+
const filter = useAnsiToHtmlFilter();
6264
const lines = message.split('\n');
6365
return (
6466
<pre
@@ -131,7 +133,13 @@ export const MatcherResult = ({
131133
];
132134
}
133135

134-
return [<span key={line + index}>{line}</span>, <br key={`br${index}`} />];
136+
return [
137+
<span
138+
key={line + index}
139+
dangerouslySetInnerHTML={{ __html: filter.toHtml(line) }}
140+
></span>,
141+
<br key={`br${index}`} />,
142+
];
135143
})}
136144
</pre>
137145
);

code/addons/interactions/src/utils.ts

+16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import { type StorybookTheme, useTheme } from 'storybook/internal/theming';
2+
3+
import Filter from 'ansi-to-html';
4+
15
export function isTestAssertionError(error: unknown) {
26
return isChaiError(error) || isJestError(error);
37
}
@@ -21,3 +25,15 @@ export function isJestError(error: unknown) {
2125
error.message.startsWith('expect(')
2226
);
2327
}
28+
29+
export function createAnsiToHtmlFilter(theme: StorybookTheme) {
30+
return new Filter({
31+
fg: theme.color.defaultText,
32+
bg: theme.background.content,
33+
});
34+
}
35+
36+
export function useAnsiToHtmlFilter() {
37+
const theme = useTheme();
38+
return createAnsiToHtmlFilter(theme);
39+
}

code/renderers/react/src/__test__/portable-stories.test.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import React from 'react';
88

99
import { addons } from 'storybook/internal/preview-api';
1010

11-
import type { Meta } from '@storybook/react';
11+
import type { ProjectAnnotations } from '@storybook/csf';
12+
import type { Meta, ReactRenderer } from '@storybook/react';
1213

1314
import * as addonActionsPreview from '@storybook/addon-actions/preview';
1415

@@ -124,7 +125,7 @@ describe('projectAnnotations', () => {
124125
const Story = composeStory(
125126
ButtonStories.WithActionArgType,
126127
ButtonStories.default,
127-
addonActionsPreview
128+
addonActionsPreview as ProjectAnnotations<ReactRenderer>
128129
);
129130
expect(Story.args.someActionArg).toHaveProperty('isAction', true);
130131
});

code/yarn.lock

+1
Original file line numberDiff line numberDiff line change
@@ -5492,6 +5492,7 @@ __metadata:
54925492
"@storybook/instrumenter": "workspace:*"
54935493
"@storybook/test": "workspace:*"
54945494
"@types/node": "npm:^22.0.0"
5495+
ansi-to-html: "npm:^0.7.2"
54955496
formik: "npm:^2.2.9"
54965497
polished: "npm:^4.2.2"
54975498
react: "npm:^18.2.0"

0 commit comments

Comments
 (0)