Skip to content

Commit

Permalink
add telemetry on discrepancy results
Browse files Browse the repository at this point in the history
  • Loading branch information
yannbf committed Oct 11, 2024
1 parent 26bfe92 commit 04d8ce0
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 5 deletions.
1 change: 1 addition & 0 deletions code/addons/test/src/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
pausedAt={pausedAt}
endRef={endRef}
onScrollToEnd={scrollTarget && scrollToTarget}
storyId={storyId}
/>
</Fragment>
);
Expand Down
2 changes: 2 additions & 0 deletions code/addons/test/src/components/InteractionsPanel.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const managerContext: any = {
state: {},
api: {
getDocsUrl: fn().mockName('api::getDocsUrl'),
emit: fn().mockName('api::emit'),
},
};

Expand Down Expand Up @@ -57,6 +58,7 @@ const meta = {
endRef: null,
// prop for the AddonPanel used as wrapper of Panel
active: true,
storyId: 'story-id',
},
} as Meta<typeof InteractionsPanel>;

Expand Down
7 changes: 6 additions & 1 deletion code/addons/test/src/components/InteractionsPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';

import { styled } from 'storybook/internal/theming';
import type { StoryId } from 'storybook/internal/types';

import type { CallStates } from '@storybook/instrumenter';
import { type Call, type ControlStates } from '@storybook/instrumenter';
Expand Down Expand Up @@ -43,6 +44,7 @@ interface InteractionsPanelProps {
onScrollToEnd?: () => void;
hasResultMismatch?: boolean;
browserTestStatus?: CallStates;
storyId: StoryId;
}

const Container = styled.div(({ theme }) => ({
Expand Down Expand Up @@ -102,12 +104,15 @@ export const InteractionsPanel: React.FC<InteractionsPanelProps> = React.memo(
endRef,
hasResultMismatch,
browserTestStatus,
storyId,
}) {
const filter = useAnsiToHtmlFilter();

return (
<Container>
{hasResultMismatch && <TestDiscrepancyMessage browserTestStatus={browserTestStatus} />}
{hasResultMismatch && (
<TestDiscrepancyMessage browserTestStatus={browserTestStatus} storyId={storyId} />
)}
{(interactions.length > 0 || hasException) && (
<Subnav
controls={controls}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const managerContext: any = {
state: {},
api: {
getDocsUrl: fn().mockName('api::getDocsUrl'),
emit: fn().mockName('api::emit'),
},
};

Expand All @@ -22,6 +23,9 @@ export default {
parameters: {
layout: 'fullscreen',
},
args: {
storyId: 'story-id',
},
decorators: [
(storyFn) => (
<ManagerContext.Provider value={managerContext}>{storyFn()}</ManagerContext.Provider>
Expand Down
25 changes: 22 additions & 3 deletions code/addons/test/src/components/TestDiscrepancyMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';
import React, { useEffect } from 'react';

import { Link } from 'storybook/internal/components';
import { useStorybookApi } from 'storybook/internal/manager-api';
import { styled } from 'storybook/internal/theming';
import type { StoryId } from 'storybook/internal/types';

import { CallStates } from '@storybook/instrumenter';

import { DOCUMENTATION_LINK } from '../constants';
import { DOCUMENTATION_LINK, STORYBOOK_ADDON_TEST_CHANNEL } from '../constants';

const Wrapper = styled.div(({ theme: { color, typography, background } }) => ({
textAlign: 'start',
Expand All @@ -32,8 +33,12 @@ const Wrapper = styled.div(({ theme: { color, typography, background } }) => ({

interface TestDiscrepancyMessageProps {
browserTestStatus: CallStates;
storyId: StoryId;
}
export const TestDiscrepancyMessage = ({ browserTestStatus }: TestDiscrepancyMessageProps) => {
export const TestDiscrepancyMessage = ({
browserTestStatus,
storyId,
}: TestDiscrepancyMessageProps) => {
const api = useStorybookApi();
const docsUrl = api.getDocsUrl({
subpath: DOCUMENTATION_LINK,
Expand All @@ -42,6 +47,20 @@ export const TestDiscrepancyMessage = ({ browserTestStatus }: TestDiscrepancyMes
});
const message = `This component test passed in ${browserTestStatus === CallStates.DONE ? 'this browser' : 'CLI'}, but the tests failed in ${browserTestStatus === CallStates.ERROR ? 'this browser' : 'CLI'}.`;

useEffect(
() =>
api.emit(STORYBOOK_ADDON_TEST_CHANNEL, {
type: 'test-discrepancy',
payload: {
browserStatus: browserTestStatus === CallStates.DONE ? 'PASS' : 'FAIL',
cliStatus: browserTestStatus === CallStates.DONE ? 'FAIL' : 'PASS',
message,
storyId,
},
}),
[api, message, browserTestStatus, storyId]
);

return (
<Wrapper>
{message}{' '}
Expand Down
1 change: 1 addition & 0 deletions code/addons/test/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const ADDON_ID = 'storybook/test';
export const TEST_PROVIDER_ID = `${ADDON_ID}/test-provider`;
export const PANEL_ID = `${ADDON_ID}/panel`;
export const STORYBOOK_ADDON_TEST_CHANNEL = 'STORYBOOK_ADDON_TEST_CHANNEL';

export const TUTORIAL_VIDEO_LINK = 'https://youtu.be/Waht9qq7AoA';
export const DOCUMENTATION_LINK = 'writing-tests/component-testing';
Expand Down
35 changes: 34 additions & 1 deletion code/addons/test/src/preset.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { readFileSync } from 'node:fs';
import { isAbsolute, join } from 'node:path';

import type { Channel } from 'storybook/internal/channels';
Expand All @@ -7,8 +8,10 @@ import {
TESTING_MODULE_RUN_REQUEST,
TESTING_MODULE_WATCH_MODE_REQUEST,
} from 'storybook/internal/core-events';
import type { Options } from 'storybook/internal/types';
import { oneWayHash, telemetry } from 'storybook/internal/telemetry';
import type { Options, StoryId } from 'storybook/internal/types';

import { STORYBOOK_ADDON_TEST_CHANNEL } from './constants';
import { bootTestRunner } from './node/boot-test-runner';

export const checkActionsLoaded = (configDir: string) => {
Expand All @@ -28,6 +31,16 @@ export const checkActionsLoaded = (configDir: string) => {
});
};

type Event = {
type: 'test-discrepancy';
payload: {
storyId: StoryId;
browserStatus: 'PASS' | 'FAIL';
cliStatus: 'FAIL' | 'PASS';
message: string;
};
};

// eslint-disable-next-line @typescript-eslint/naming-convention
export const experimental_serverChannel = async (channel: Channel, options: Options) => {
const core = await options.presets.apply('core');
Expand Down Expand Up @@ -65,5 +78,25 @@ export const experimental_serverChannel = async (channel: Channel, options: Opti
}
});

if (!core.disableTelemetry) {
const packageJsonPath = require.resolve('@storybook/experimental-addon-test/package.json');

const { version: addonVersion } = JSON.parse(
readFileSync(packageJsonPath, { encoding: 'utf-8' })
);

channel.on(STORYBOOK_ADDON_TEST_CHANNEL, (event: Event) => {
// @ts-expect-error This telemetry is not a core one, so we don't have official types for it (similar to onboarding addon)
telemetry('addon-test', {
...event,
payload: {
...event.payload,
storyId: oneWayHash(event.payload.storyId),
},
addonVersion,
});
});
}

return channel;
};

0 comments on commit 04d8ce0

Please sign in to comment.