Skip to content

Commit

Permalink
Merge pull request #30131 from storybookjs/valentin/enable-strict-mod…
Browse files Browse the repository at this point in the history
…e-for-test

Addon Test: Enable strict mode
  • Loading branch information
valentinpalkovic authored Dec 24, 2024
2 parents 3258fc7 + 3247e70 commit 537acf2
Show file tree
Hide file tree
Showing 19 changed files with 85 additions and 69 deletions.
7 changes: 5 additions & 2 deletions code/addons/test/src/components/Interaction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const MethodCallWrapper = styled.div(() => ({

const RowContainer = styled('div', {
shouldForwardProp: (prop) => !['call', 'pausedAt'].includes(prop.toString()),
})<{ call: Call; pausedAt: Call['id'] }>(
})<{ call: Call; pausedAt: Call['id'] | undefined }>(
({ theme, call }) => ({
position: 'relative',
display: 'flex',
Expand Down Expand Up @@ -117,6 +117,9 @@ const RowMessage = styled('div')(({ theme }) => ({

export const Exception = ({ exception }: { exception: Call['exception'] }) => {
const filter = useAnsiToHtmlFilter();
if (!exception) {
return null;
}
if (isJestError(exception)) {
return <MatcherResult {...exception} />;
}
Expand Down Expand Up @@ -187,7 +190,7 @@ export const Interaction = ({
</MethodCallWrapper>
</RowLabel>
<RowActions>
{childCallIds?.length > 0 && (
{(childCallIds?.length ?? 0) > 0 && (
<WithTooltip
hasChrome={false}
tooltip={<Note note={`${isCollapsed ? 'Show' : 'Hide'} interactions`} />}
Expand Down
4 changes: 2 additions & 2 deletions code/addons/test/src/components/MatcherResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ export const MatcherResult = ({
{lines.flatMap((line: string, index: number) => {
if (line.startsWith('expect(')) {
const received = getParams(line, 7);
const remainderIndex = received && 7 + received.length;
const remainderIndex = received ? 7 + received.length : 0;
const matcher = received && line.slice(remainderIndex).match(/\.(to|last|nth)[A-Z]\w+\(/);
if (matcher) {
const expectedIndex = remainderIndex + matcher.index + matcher[0].length;
const expectedIndex = remainderIndex + (matcher.index ?? 0) + matcher[0].length;
const expected = getParams(line, expectedIndex);
if (expected) {
return [
Expand Down
6 changes: 3 additions & 3 deletions code/addons/test/src/components/MethodCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export const Node = ({
case Object.prototype.hasOwnProperty.call(value, '__class__'):
return <ClassNode {...props} {...value.__class__} />;
case Object.prototype.hasOwnProperty.call(value, '__callId__'):
return <MethodCall call={callsById.get(value.__callId__)} callsById={callsById} />;
return <MethodCall call={callsById?.get(value.__callId__)} callsById={callsById} />;
/* eslint-enable no-underscore-dangle */

case Object.prototype.toString.call(value) === '[object Object]':
Expand Down Expand Up @@ -418,7 +418,7 @@ export const MethodCall = ({
callsById,
}: {
call?: Call;
callsById: Map<Call['id'], Call>;
callsById?: Map<Call['id'], Call>;
}) => {
// Call might be undefined during initial render, can be safely ignored.
if (!call) {
Expand All @@ -434,7 +434,7 @@ export const MethodCall = ({
const callId = (elem as CallRef).__callId__;
return [
callId ? (
<MethodCall key={`elem${index}`} call={callsById.get(callId)} callsById={callsById} />
<MethodCall key={`elem${index}`} call={callsById?.get(callId)} callsById={callsById} />
) : (
<span key={`elem${index}`}>{elem as any}</span>
),
Expand Down
25 changes: 11 additions & 14 deletions code/addons/test/src/components/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,6 @@ import type { API_StatusValue } from '@storybook/types';
import { ADDON_ID, STORYBOOK_ADDON_TEST_CHANNEL, TEST_PROVIDER_ID } from '../constants';
import { InteractionsPanel } from './InteractionsPanel';

interface Interaction extends Call {
status: Call['status'];
childCallIds: Call['id'][];
isHidden: boolean;
isCollapsed: boolean;
toggleCollapsed: () => void;
}

const INITIAL_CONTROL_STATES = {
start: false,
back: false,
Expand Down Expand Up @@ -60,19 +52,20 @@ export const getInteractions = ({
const childCallMap = new Map<Call['id'], Call['id'][]>();

return log
.map<Call & { isHidden: boolean }>(({ callId, ancestors, status }) => {
.map(({ callId, ancestors, status }) => {
let isHidden = false;
ancestors.forEach((ancestor) => {
if (collapsed.has(ancestor)) {
isHidden = true;
}
childCallMap.set(ancestor, (childCallMap.get(ancestor) || []).concat(callId));
});
return { ...calls.get(callId), status, isHidden };
return { ...calls.get(callId)!, status, isHidden };
})
.map<Interaction>((call) => {
.map((call) => {
const status =
call.status === CallStates.ERROR &&
call.ancestors &&
callsById.get(call.ancestors.slice(-1)[0])?.status === CallStates.ACTIVE
? CallStates.ACTIVE
: call.status;
Expand Down Expand Up @@ -131,7 +124,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
const calls = useRef<Map<Call['id'], Omit<Call, 'status'>>>(new Map());
const setCall = ({ status, ...call }: Call) => calls.current.set(call.id, call);

const endRef = useRef();
const endRef = useRef<HTMLDivElement>();
useEffect(() => {
let observer: IntersectionObserver;
if (global.IntersectionObserver) {
Expand All @@ -151,6 +144,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
{
[EVENTS.CALL]: setCall,
[EVENTS.SYNC]: (payload) => {
// @ts-expect-error TODO
set((s) => {
const list = getInteractions({
log: payload.logItems,
Expand Down Expand Up @@ -214,6 +208,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
);

useEffect(() => {
// @ts-expect-error TODO
set((s) => {
const list = getInteractions({
log: log.current,
Expand Down Expand Up @@ -250,16 +245,17 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
const hasException =
!!caughtException ||
!!unhandledErrors ||
// @ts-expect-error TODO
interactions.some((v) => v.status === CallStates.ERROR);

const storyStatus = storyStatuses[storyId]?.[TEST_PROVIDER_ID];
const storyTestStatus = storyStatus?.status;

const browserTestStatus = useMemo<CallStates | null>(() => {
const browserTestStatus = useMemo<CallStates | undefined>(() => {
if (!isPlaying && (interactions.length > 0 || hasException)) {
return hasException ? CallStates.ERROR : CallStates.DONE;
}
return isPlaying ? CallStates.ACTIVE : null;
return isPlaying ? CallStates.ACTIVE : undefined;
}, [isPlaying, interactions, hasException]);

const { testRunId } = storyStatus?.data || {};
Expand Down Expand Up @@ -315,6 +311,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
unhandledErrors={unhandledErrors}
isPlaying={isPlaying}
pausedAt={pausedAt}
// @ts-expect-error TODO
endRef={endRef}
onScrollToEnd={scrollTarget && scrollToTarget}
/>
Expand Down
2 changes: 1 addition & 1 deletion code/addons/test/src/components/RelativeTime.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';

export const RelativeTime = ({ timestamp }: { timestamp?: number }) => {
const [timeAgo, setTimeAgo] = useState(null);
const [timeAgo, setTimeAgo] = useState<number | null>(null);

useEffect(() => {
if (timestamp) {
Expand Down
4 changes: 2 additions & 2 deletions code/addons/test/src/components/StatusBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const StyledBadge = styled.div<StatusBadgeProps>(({ theme, status }) => {
[CallStates.ERROR]: theme.color.negative,
[CallStates.ACTIVE]: theme.color.warning,
[CallStates.WAITING]: theme.color.warning,
}[status];
}[status!];
return {
padding: '4px 6px 4px 8px;',
borderRadius: '4px',
Expand All @@ -36,7 +36,7 @@ export const StatusBadge: React.FC<StatusBadgeProps> = ({ status }) => {
[CallStates.ERROR]: 'Fail',
[CallStates.ACTIVE]: 'Runs',
[CallStates.WAITING]: 'Runs',
}[status];
}[status!];
return (
<StyledBadge aria-label="Status of the test run" status={status}>
{badgeText}
Expand Down
2 changes: 1 addition & 1 deletion code/addons/test/src/components/Subnav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ const RerunButton = styled(StyledIconButton)<
>(({ theme, animating, disabled }) => ({
opacity: disabled ? 0.5 : 1,
svg: {
animation: animating && `${theme.animation.rotate360} 200ms ease-out`,
animation: animating ? `${theme.animation.rotate360} 200ms ease-out` : undefined,
},
}));

Expand Down
7 changes: 3 additions & 4 deletions code/addons/test/src/components/TestDiscrepancyMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import React, { useEffect } from 'react';
import React 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_DISCREPANCY_LINK, STORYBOOK_ADDON_TEST_CHANNEL } from '../constants';
import { DOCUMENTATION_DISCREPANCY_LINK } from '../constants';

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

interface TestDiscrepancyMessageProps {
browserTestStatus: CallStates;
browserTestStatus?: CallStates;
}

export const TestDiscrepancyMessage = ({ browserTestStatus }: TestDiscrepancyMessageProps) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const baseState: TestProviderState<Details, Config> = {
cancellable: true,
cancelling: false,
crashed: false,
error: null,
error: undefined,
failed: false,
running: false,
watching: false,
Expand Down
14 changes: 9 additions & 5 deletions code/addons/test/src/components/TestProviderRender.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export const TestProviderRender: FC<
: undefined;

const a11ySkippedAmount =
state.running || !state?.details.config?.a11y || !state.config.a11y
state.running || !state?.details.config?.a11y || !state.config?.a11y
? null
: a11yResults?.filter((result) => !result).length;

Expand Down Expand Up @@ -304,9 +304,11 @@ export const TestProviderRender: FC<
const firstNotPassed = results.find(
(r) => r.status === 'failed' || r.status === 'warning'
);
openPanel(firstNotPassed.storyId, PANEL_ID);
if (firstNotPassed) {
openPanel(firstNotPassed.storyId, PANEL_ID);
}
}
: null
: undefined
}
icon={
state.crashed ? (
Expand Down Expand Up @@ -359,9 +361,11 @@ export const TestProviderRender: FC<
(report) => report.status === 'failed' || report.status === 'warning'
)
);
openPanel(firstNotPassed.storyId, A11y_ADDON_PANEL_ID);
if (firstNotPassed) {
openPanel(firstNotPassed.storyId, A11y_ADDON_PANEL_ID);
}
}
: null
: undefined
}
icon={<TestStatusIcon status={a11yStatus} aria-label={`status: ${a11yStatus}`} />}
right={isStoryEntry ? null : a11yNotPassedAmount || null}
Expand Down
9 changes: 7 additions & 2 deletions code/addons/test/src/manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ addons.register(ADDON_ID, (api) => {
runnable: true,
watchable: true,
name: 'Component tests',
// @ts-expect-error: TODO: Fix types
render: (state) => {
const [isModalOpen, setModalOpen] = useState(false);
return (
Expand All @@ -55,6 +56,7 @@ addons.register(ADDON_ID, (api) => {
);
},

// @ts-expect-error: TODO: Fix types
sidebarContextMenu: ({ context, state }) => {
if (context.type === 'docs') {
return null;
Expand All @@ -72,6 +74,7 @@ addons.register(ADDON_ID, (api) => {
);
},

// @ts-expect-error: TODO: Fix types
stateUpdater: (state, update) => {
const updated = {
...state,
Expand All @@ -89,6 +92,7 @@ addons.register(ADDON_ID, (api) => {
await api.experimental_updateStatus(
TEST_PROVIDER_ID,
Object.fromEntries(
// @ts-expect-error: TODO: Fix types
update.details.testResults.flatMap((testResult) =>
testResult.results
.filter(({ storyId }) => storyId)
Expand All @@ -113,6 +117,7 @@ addons.register(ADDON_ID, (api) => {
await api.experimental_updateStatus(
'storybook/addon-a11y/test-provider',
Object.fromEntries(
// @ts-expect-error: TODO: Fix types
update.details.testResults.flatMap((testResult) =>
testResult.results
.filter(({ storyId }) => storyId)
Expand Down Expand Up @@ -143,7 +148,7 @@ addons.register(ADDON_ID, (api) => {

return updated;
},
} as Addon_TestProviderType<Details, Config>);
} satisfies Omit<Addon_TestProviderType<Details, Config>, 'id'>);
}

const filter = ({ state }: Combo) => {
Expand All @@ -158,7 +163,7 @@ addons.register(ADDON_ID, (api) => {
match: ({ viewMode }) => viewMode === 'story',
render: ({ active }) => {
return (
<AddonPanel active={active}>
<AddonPanel active={!!active}>
<Consumer filter={filter}>{({ storyId }) => <Panel storyId={storyId} />}</Consumer>
</AddonPanel>
);
Expand Down
4 changes: 2 additions & 2 deletions code/addons/test/src/node/boot-test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const MAX_START_TIME = 30000;
const vitestModulePath = join(__dirname, 'node', 'vitest.mjs');

// Events that were triggered before Vitest was ready are queued up and resent once it's ready
const eventQueue: { type: string; args: any[] }[] = [];
const eventQueue: { type: string; args?: any[] }[] = [];

let child: null | ChildProcess;
let ready = false;
Expand Down Expand Up @@ -87,7 +87,7 @@ const bootTestRunner = async (channel: Channel) => {
if (result.type === 'ready') {
// Resend events that triggered (during) the boot sequence, now that Vitest is ready
while (eventQueue.length) {
const { type, args } = eventQueue.shift();
const { type, args } = eventQueue.shift()!;
child?.send({ type, args, from: 'server' });
}

Expand Down
4 changes: 2 additions & 2 deletions code/addons/test/src/node/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export class StorybookReporter implements Reporter {
(t) => t.status === 'failed' && t.results.length === 0
);

const reducedTestSuiteFailures = new Set<string>();
const reducedTestSuiteFailures = new Set<string | undefined>();

testSuiteFailures.forEach((t) => {
reducedTestSuiteFailures.add(t.message);
Expand All @@ -240,7 +240,7 @@ export class StorybookReporter implements Reporter {
message: Array.from(reducedTestSuiteFailures).reduce(
(acc, curr) => `${acc}\n${curr}`,
''
),
)!,
}
: {
name: `${unhandledErrors.length} unhandled error${unhandledErrors?.length > 1 ? 's' : ''}`,
Expand Down
3 changes: 2 additions & 1 deletion code/addons/test/src/node/test-manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ const vitest = vi.hoisted(() => ({
configOverride: {
actualTestNamePattern: undefined,
get testNamePattern() {
return this.actualTestNamePattern;
return this.actualTestNamePattern!;
},
set testNamePattern(value: string) {
setTestNamePattern(value);
// @ts-expect-error Ignore for testing
this.actualTestNamePattern = value;
},
},
Expand Down
Loading

0 comments on commit 537acf2

Please sign in to comment.