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

TestAddon: Refactor UI & add config options #29662

Merged
merged 26 commits into from
Nov 26, 2024
Merged

Conversation

ndelangen
Copy link
Member

@ndelangen ndelangen commented Nov 19, 2024

What I did

  • refactor the UI components structure in addon-test
  • extract the render into a component
  • add a config property to the TestProviderState
  • add isEditing state to addon test's render

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

🦋 Canary release

This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

core team members can create a canary release here or locally with gh workflow run --repo storybookjs/storybook canary-release-pr.yml --field pr=<PR_NUMBER>

name before after diff z %
createSize 0 B 0 B 0 B - -
generateSize 78.5 MB 77.7 MB -799 kB -52.38 -1%
initSize 144 MB 143 MB -787 kB -15.22 -0.6%
diffSize 65.2 MB 65.2 MB 12.1 kB 0.83 0%
buildSize 6.83 MB 6.83 MB 1.48 kB -0.33 0%
buildSbAddonsSize 1.51 MB 1.51 MB 199 B 0.14 0%
buildSbCommonSize 195 kB 195 kB 0 B - 0%
buildSbManagerSize 1.86 MB 1.86 MB 1.15 kB -0.33 0.1%
buildSbPreviewSize 271 kB 271 kB 140 B 0.17 0.1%
buildStaticSize 0 B 0 B 0 B - -
buildPrebuildSize 3.83 MB 3.83 MB 1.48 kB -0.33 0%
buildPreviewSize 3 MB 3 MB 0 B 0.51 0%
testBuildSize 0 B 0 B 0 B - -
testBuildSbAddonsSize 0 B 0 B 0 B - -
testBuildSbCommonSize 0 B 0 B 0 B - -
testBuildSbManagerSize 0 B 0 B 0 B - -
testBuildSbPreviewSize 0 B 0 B 0 B - -
testBuildStaticSize 0 B 0 B 0 B - -
testBuildPrebuildSize 0 B 0 B 0 B - -
testBuildPreviewSize 0 B 0 B 0 B - -
name before after diff z %
createTime 6.4s 23.7s 17.3s 1.04 72.9%
generateTime 18.6s 18.9s 243ms -0.88 1.3%
initTime 13.5s 13.1s -400ms -0.88 -3%
buildTime 8.7s 8.8s 86ms 0.07 1%
testBuildTime 0ms 0ms 0ms - -
devPreviewResponsive 5.5s 6.1s 627ms 0.61 10.1%
devManagerResponsive 3.5s 3.7s 262ms 0.55 6.9%
devManagerHeaderVisible 677ms 587ms -90ms -0.02 -15.3%
devManagerIndexVisible 744ms 667ms -77ms 0.02 -11.5%
devStoryVisibleUncached 929ms 1s 149ms 0.23 13.8%
devStoryVisible 701ms 666ms -35ms 0.16 -5.3%
devAutodocsVisible 376ms 536ms 160ms 0.59 29.9%
devMDXVisible 577ms 431ms -146ms -1.02 -33.9%
buildManagerHeaderVisible 717ms 576ms -141ms -0.02 -24.5%
buildManagerIndexVisible 753ms 589ms -164ms -0.08 -27.8%
buildStoryVisible 716ms 575ms -141ms -0.03 -24.5%
buildAutodocsVisible 549ms 558ms 9ms 0.8 1.6%
buildMDXVisible 503ms 463ms -40ms -0.23 -8.6%

Greptile Summary

Here's a concise summary of the key changes in this pull request:

Refactors the Test addon UI components and adds configuration support for improved organization and functionality.

  • Added new Description component in code/addons/test/src/components/ to handle test status display with proper state management
  • Enhanced RelativeTime component with Intl.RelativeTimeFormat for localized time formatting
  • Created TestProviderRender component to handle test configuration and execution UI
  • Added configuration options (a11y and coverage) through new Config interface in constants.ts
  • Improved dynamic height handling and collapse animations in TestingModule component

The changes focus on better component organization, type safety, and new configuration capabilities while maintaining core functionality.

💡 (3/5) Reply to the bot's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!

@ndelangen ndelangen self-assigned this Nov 19, 2024
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

8 file(s) reviewed, 10 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +24 to +25
} else if (state.failed && !errorMessage) {
description = '';
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Setting description to empty string when failed without error message could lead to confusing UI state. Consider showing a default failure message instead.

@@ -1,6 +1,23 @@
import { useEffect, useState } from 'react';

import { getRelativeTimeString } from '../manager';
export function getRelativeTimeString(date: Date): string {
const delta = Math.round((date.getTime() - Date.now()) / 1000);
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: delta calculation will be negative for future dates, but Math.abs is only used later - could cause incorrect time displays

const divisor = unitIndex ? cutoffs[unitIndex - 1] : 1;
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
return rtf.format(Math.floor(delta / divisor), units[unitIndex]);
}

export const RelativeTime = ({ timestamp, testCount }: { timestamp: Date; testCount: number }) => {
const [relativeTimeString, setRelativeTimeString] = useState(null);
Copy link
Contributor

Choose a reason for hiding this comment

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

style: initial state should be typed as useState<string | null>(null)

import { TestProviderRender } from './TestProviderRender';

type Story = StoryObj<typeof TestProviderRender>;
const managerContext: any = {
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Avoid using 'any' type for managerContext. Consider creating a proper type definition based on ManagerContext requirements.

code/addons/test/src/components/TestProviderRender.tsx Outdated Show resolved Hide resolved
code/addons/test/src/constants.ts Outdated Show resolved Hide resolved
code/addons/test/src/constants.ts Outdated Show resolved Hide resolved
import { Title } from './components/Title';
import { ADDON_ID, PANEL_ID, TEST_PROVIDER_ID } from './constants';
import type { TestResult } from './node/reporter';
import { ADDON_ID, type Details, PANEL_ID, TEST_PROVIDER_ID } from './constants';

const statusMap: Record<any['status'], API_StatusValue> = {
Copy link
Contributor

Choose a reason for hiding this comment

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

style: statusMap uses 'any' type for status key which could be more strictly typed

@@ -4,7 +4,8 @@ type DateNow = number;

export type TestProviderId = Addon_TestProviderType['id'];
export type TestProviderConfig = Addon_TestProviderType;
export type TestProviderState = Addon_TestProviderState;
export type TestProviderState<Details extends { [key: string]: any } = NonNullable<unknown>> =
Addon_TestProviderState<Details>;

export type TestProviders = Record<TestProviderId, TestProviderConfig & TestProviderState>;
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: TestProviders type needs to be updated to use the generic parameter, should be Record<TestProviderId, TestProviderConfig & TestProviderState>

@ndelangen ndelangen changed the title TestAddon: Refactor UI TestAddon: Refactor UI & add config options Nov 19, 2024
Copy link

nx-cloud bot commented Nov 20, 2024

☁️ Nx Cloud Report

CI is running/has finished running commands for commit 3f34f9d. As they complete they will appear below. Click to see the status, the terminal output, and the build insights.

📂 See all runs for this CI Pipeline Execution


✅ Successfully ran 1 target

Sent with 💌 from NxCloud.

@ndelangen ndelangen changed the base branch from next to determine-total-test-count November 21, 2024 09:19
@storybook-pr-benchmarking
Copy link

storybook-pr-benchmarking bot commented Nov 21, 2024

Package Benchmarks

Commit: 3f34f9d, ran on 26 November 2024 at 12:39:50 UTC

The following packages have significant changes to their size or dependencies:

@storybook/addon-storysource

Before After Difference
Dependency count 7 7 0
Self size 1.89 MB 1.89 MB 0 B
Dependency size 10.12 MB 10.27 MB 🚨 +142 KB 🚨
Bundle Size Analyzer Link Link

@storybook/builder-webpack5

Before After Difference
Dependency count 223 223 0
Self size 79 KB 79 KB 0 B
Dependency size 29.56 MB 29.60 MB 🚨 +42 KB 🚨
Bundle Size Analyzer Link Link

@storybook/angular

Before After Difference
Dependency count 258 258 0
Self size 362 KB 362 KB 0 B
Dependency size 34.49 MB 34.54 MB 🚨 +42 KB 🚨
Bundle Size Analyzer Link Link

@storybook/ember

Before After Difference
Dependency count 250 250 0
Self size 22 KB 22 KB 0 B
Dependency size 31.96 MB 32.00 MB 🚨 +42 KB 🚨
Bundle Size Analyzer Link Link

@storybook/html-webpack5

Before After Difference
Dependency count 233 233 0
Self size 6 KB 6 KB 0 B
Dependency size 30.10 MB 30.15 MB 🚨 +42 KB 🚨
Bundle Size Analyzer Link Link

@storybook/nextjs

Before After Difference
Dependency count 587 587 0
Self size 464 KB 464 KB 0 B
Dependency size 83.77 MB 83.81 MB 🚨 +42 KB 🚨
Bundle Size Analyzer Link Link

@storybook/preact-webpack5

Before After Difference
Dependency count 231 231 0
Self size 6 KB 6 KB 0 B
Dependency size 29.68 MB 29.72 MB 🚨 +42 KB 🚨
Bundle Size Analyzer Link Link

@storybook/react-webpack5

Before After Difference
Dependency count 309 309 0
Self size 6 KB 6 KB 0 B
Dependency size 40.84 MB 40.88 MB 🚨 +42 KB 🚨
Bundle Size Analyzer Link Link

@storybook/server-webpack5

Before After Difference
Dependency count 241 241 0
Self size 14 KB 14 KB 0 B
Dependency size 31.08 MB 31.12 MB 🚨 +42 KB 🚨
Bundle Size Analyzer Link Link

@storybook/svelte-webpack5

Before After Difference
Dependency count 296 296 0
Self size 6 KB 6 KB 0 B
Dependency size 37.67 MB 37.71 MB 🚨 +42 KB 🚨
Bundle Size Analyzer Link Link

@storybook/vue3-vite

Before After Difference
Dependency count 107 107 0
Self size 15 KB 15 KB 0 B
Dependency size 42.52 MB 42.55 MB 🚨 +33 KB 🚨
Bundle Size Analyzer Link Link

@storybook/vue3-webpack5

Before After Difference
Dependency count 483 483 0
Self size 6 KB 6 KB 0 B
Dependency size 54.08 MB 54.12 MB 🚨 +42 KB 🚨
Bundle Size Analyzer Link Link

@storybook/web-components-webpack5

Before After Difference
Dependency count 231 231 0
Self size 5 KB 5 KB 0 B
Dependency size 29.73 MB 29.77 MB 🚨 +42 KB 🚨
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 390 390 0
Self size 484 KB 484 KB 0 B
Dependency size 74.48 MB 74.64 MB 🚨 +154 KB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 270 270 0
Self size 612 KB 612 KB 0 B
Dependency size 64.48 MB 64.63 MB 🚨 +154 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 105 105 0
Self size 1.11 MB 1.11 MB 0 B
Dependency size 42.34 MB 42.48 MB 🚨 +145 KB 🚨
Bundle Size Analyzer Link Link

@storybook/source-loader

Before After Difference
Dependency count 5 5 0
Self size 41 KB 41 KB 0 B
Dependency size 10.07 MB 10.21 MB 🚨 +142 KB 🚨
Bundle Size Analyzer Link Link

@storybook/preset-vue3-webpack

Before After Difference
Dependency count 366 366 0
Self size 9 KB 9 KB 0 B
Dependency size 45.00 MB 45.04 MB 🚨 +42 KB 🚨
Bundle Size Analyzer Link Link

@ndelangen ndelangen marked this pull request as draft November 22, 2024 15:43
Base automatically changed from determine-total-test-count to next November 25, 2024 14:04
An error occurred while trying to automatically change base from determine-total-test-count to next November 25, 2024 14:04
@ndelangen ndelangen marked this pull request as ready for review November 26, 2024 11:32
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

18 file(s) reviewed, 19 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +153 to +157
play: async ({ canvasElement }) => {
const screen = within(canvasElement);

screen.getByLabelText('Edit').click();
},
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Add error handling in case Edit button is not found

Comment on lines +119 to +126
{!isEditing ? (
<Fragment>
{Object.entries(config).map(([key, value]) => (
<div key={key}>
{key}: {value ? 'ON' : 'OFF'}
</div>
))}
</Fragment>
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Missing semantic HTML and accessibility attributes for clickable config toggles. Consider using buttons or checkboxes with proper ARIA roles.

Comment on lines +157 to +162
function useConfig(id: string, config: Config, api: API) {
const data = useRef<Config>(config);
data.current = config || {
a11y: false,
coverage: false,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: data.current is reassigned on every render, defeating the purpose of useRef. Consider using useState instead.

}}
onRerun={() => {
setIsModalOpen(false);
api.runTestProvider(TEST_PROVIDER_ID);
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Using hardcoded TEST_PROVIDER_ID here but state.id is used elsewhere. Should be consistent and use state.id.

Comment on lines 107 to 110
const resizeObserver = new ResizeObserver(() => {
if (spacer && wrapper) {
spacer.style.height = `${wrapper.clientHeight}px`;
if (spacerRef.current && wrapperRef.current) {
spacerRef.current.style.height = `${wrapperRef.current.scrollHeight}px`;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

style: scrollHeight may cause layout issues if content includes margins - consider using offsetHeight or getBoundingClientRect() for more reliable measurements

Comment on lines +187 to +193
requestAnimationFrame(() => {
if (contentRef.current && !isCollapsed) {
const height = contentRef.current?.getBoundingClientRect().height || DEFAULT_HEIGHT;

setMaxHeight(height);
}
});
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: requestAnimationFrame callback may run after component unmount, causing memory leak if contentRef.current is accessed

Comment on lines +204 to +206
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: timeoutRef cleanup missing in useEffect, could cause memory leak on unmount

Comment on lines 233 to 235
transition: isSlow ? 'max-height 250ms' : 'max-height 0ms',
display: hasTestProviders ? 'block' : 'none',
maxHeight: isCollapsed ? 0 : maxHeight,
Copy link
Contributor

Choose a reason for hiding this comment

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

style: redundant hasTestProviders check in display style since parent already checks condition

@@ -66,7 +66,7 @@ test.describe("component testing", () => {
testStoryElement.click();
}

const testingModuleDescription = await page.locator('[data-module-id="storybook/test/test-provider"]').locator('#testing-module-description');
const testingModuleDescription = await page.locator('#testing-module-description');
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Selector change from '[data-module-id="storybook/test/test-provider"].locator(#testing-module-description)' to '#testing-module-description' could make the test more fragile if multiple elements with this ID exist.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

18 file(s) reviewed, 8 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +34 to +42
<LinkComponent
isButton
onClick={() => {
setIsModalOpen(true);
}}
>
{state.error?.name || 'View full error'}
</LinkComponent>
</>
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Fragment wrapper is unnecessary since LinkComponent is the only child

Comment on lines +26 to +28
description = state.progress
? `Testing... ${state.progress.numPassedTests}/${state.progress.numTotalTests}`
: 'Starting...';
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: numTotalTests could be undefined here, which would show 'Testing... 5/undefined'

aria-label={`Start ${state.name}`}
variant="ghost"
padding="small"
onClick={() => api.runTestProvider(state.id, {})}
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: missing config parameter here but it's used in the useConfig hook. Should pass current config: api.runTestProvider(state.id, { config })

Comment on lines +129 to +138
{Object.entries(config).map(([key, value]) => (
<div
key={key}
onClick={() => {
changeConfig({ [key]: !value });
}}
>
{key}: {value ? 'ON' : 'OFF'}
</div>
))}
Copy link
Contributor

Choose a reason for hiding this comment

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

style: duplicate code block from non-editing state. Consider extracting to a shared component to avoid maintenance issues

<div
style={{
height,
transition: '1s height',
Copy link
Contributor

Choose a reason for hiding this comment

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

style: transition duration (1s) should match the one used in TestingModule component for consistency

Comment on lines +156 to +160
const screen = await within(canvasElement);

const toggleButton = await screen.getByLabelText('Collapse testing module');
const content = await screen.findByText('CUSTOM CONTENT WITH DYNAMIC HEIGHT');
const collapse = await screen.getByTestId('collapse');
Copy link
Contributor

Choose a reason for hiding this comment

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

style: queries should have explicit timeouts since dynamic content may take longer to appear

const crashed = testProviders.some((tp) => tp.crashed);
const failed = testProviders.some((tp) => tp.failed);
const testing = testProviders.length > 0;
if (!hasTestProviders && (!errorCount || !warningCount)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: condition should be (!hasTestProviders && !errorCount && !warningCount) to properly handle case when only warnings exist

@ndelangen ndelangen merged commit 995f9f3 into next Nov 26, 2024
58 of 60 checks passed
@ndelangen ndelangen deleted the norbert/testmodule-options branch November 26, 2024 13:04
@github-actions github-actions bot mentioned this pull request Nov 26, 2024
12 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants