diff --git a/web/AGENTS.md b/web/AGENTS.md index 38057e6b046..bb060c71be1 100644 --- a/web/AGENTS.md +++ b/web/AGENTS.md @@ -9,6 +9,7 @@ - User-facing strings must use `web/i18n/en-US/` keys. When adding or renaming a key, update every supported locale with the correct localized value. - For new backend calls and migrated surfaces, use generated `consoleQuery` / `consoleClient` APIs from `@/service/client`. Do not add handwritten REST helpers or DTO mirrors, mock-backed app state, or direct edits to generated contracts. - Prefer `@langgenius/dify-ui/*` primitives, data attributes, and design tokens. Preserve a visible focus indicator on the final focusable element. +- Use `Button` for actions with visible text and `IconButton` for icon-only actions. Every `IconButton` needs an `aria-label` or `aria-labelledby`; compose Menu, Popover, Toggle, and Collapsible through `render` so those primitives keep ownership of their state. - Follow `docs/overlay.md` for overlay selection and migration. Migrate a legacy overlay only when the current behavior change actually involves that overlay boundary. - For custom SVG icons, follow `../packages/iconify-collections/README.md`; do not add generated React icons under `app/components/base/icons/src/`. - `docs/test.md` is the single source of truth for frontend automated-test policy. Skills may route and execute that policy but must not redefine it. diff --git a/web/README.md b/web/README.md index 06cb738ed2d..2bb71fd1a05 100644 --- a/web/README.md +++ b/web/README.md @@ -132,12 +132,6 @@ vp test run If a test fails only in CI, inspect the failing job and reproduce it locally when possible. A rerun can help identify a flaky test, but it does not replace diagnosing or reporting the failure. -### Example Code - -If you are not familiar with writing tests, refer to: - -- [index.spec.tsx] - Component test example - ## Documentation Visit to view the full documentation. @@ -155,7 +149,6 @@ The Dify community can be found on [Discord community], where you can ask questi [Storybook]: https://storybook.js.org [Vite+]: https://viteplus.dev [Vitest]: https://vitest.dev -[index.spec.tsx]: ./app/components/base/action-button/__tests__/index.spec.tsx [pnpm]: https://pnpm.io [vinext]: https://github.com/cloudflare/vinext [web/docs/test.md]: ./docs/test.md diff --git a/web/app/components/base/chat/chat-with-history/sidebar/__tests__/operation.spec.tsx b/web/app/components/base/chat/chat-with-history/sidebar/__tests__/operation.spec.tsx index 49e4284388f..7e46c9fab03 100644 --- a/web/app/components/base/chat/chat-with-history/sidebar/__tests__/operation.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/sidebar/__tests__/operation.spec.tsx @@ -36,11 +36,6 @@ describe('Operation', () => { expect(screen.getByText('explore.sidebar.action.pin')).toBeInTheDocument() }) - it('should apply active state to ActionButton', () => { - render() - expect(getTrigger()).toBeInTheDocument() - }) - it('should call togglePin when pin/unpin is clicked', async () => { const user = userEvent.setup() render() diff --git a/web/app/components/base/chat/chat/answer/__tests__/operation.spec.tsx b/web/app/components/base/chat/chat/answer/__tests__/operation.spec.tsx index bf8742b74f5..21c11633b32 100644 --- a/web/app/components/base/chat/chat/answer/__tests__/operation.spec.tsx +++ b/web/app/components/base/chat/chat/answer/__tests__/operation.spec.tsx @@ -885,21 +885,6 @@ describe('Operation', () => { screen.getByTestId('operation-bar').querySelectorAll('.i-ri-thumb-up-line').length, ).toBe(0) }) - - it('should render action buttons with Default state when feedback rating is undefined', () => { - // Setting a malformed feedback object with no rating but triggers the wrapper to see undefined fallbacks - const item = { - ...baseItem, - feedback: {} as unknown as Record, - adminFeedback: {} as unknown as Record, - } as ChatItem - renderOperation({ ...baseProps, item }) - // Since it renders the 'else' block for hasAdminFeedback (which is false due to !) - // the like/dislike regular ActionButtons should hit the Default state - // Since it renders the 'else' block for hasAdminFeedback (which is false due to !) - // the like/dislike regular ActionButtons should hit the Default state - expect(screen.getByTestId('operation-bar'))!.toBeInTheDocument() - }) }) describe('Positioning and layout', () => { diff --git a/web/app/components/base/copy-feedback/index.stories.tsx b/web/app/components/base/copy-feedback/index.stories.tsx index 4deeea4273c..c105a0cdb4c 100644 --- a/web/app/components/base/copy-feedback/index.stories.tsx +++ b/web/app/components/base/copy-feedback/index.stories.tsx @@ -8,8 +8,7 @@ const meta = { parameters: { docs: { description: { - component: - 'Copy-to-clipboard button that shows instant feedback and a tooltip. Includes the original ActionButton wrapper and the newer ghost-button variant.', + component: 'Copy-to-clipboard icon buttons that show instant feedback and a tooltip.', }, }, }, diff --git a/web/app/components/base/file-uploader/file-uploader-in-attachment/__tests__/index.spec.tsx b/web/app/components/base/file-uploader/file-uploader-in-attachment/__tests__/index.spec.tsx index 72054e86aea..e29d74617e9 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-attachment/__tests__/index.spec.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-attachment/__tests__/index.spec.tsx @@ -196,7 +196,7 @@ describe('FileUploaderInAttachmentWrapper', () => { />, ) - // ReplayLine is inside ActionButton (a