From e134c1e0d590ee6da69ec7ac1b3d34cdf2988ea3 Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Mon, 11 May 2026 11:53:03 +0800 Subject: [PATCH] feat(web): improve a11y and remove data-testid (#35999) --- .agents/skills/frontend-testing/SKILL.md | 9 +- .../step-definitions/apps/share-app.steps.ts | 2 +- .../base/notion-page-selector-flow.test.tsx | 4 +- .../text-generation-run-once-flow.test.tsx | 10 +- .../(commonLayout)/datasets/layout.spec.tsx | 12 +- .../(commonLayout)/role-route-guard.spec.tsx | 16 +- .../app/annotation/__tests__/filter.spec.tsx | 5 +- .../app/annotation/batch-action.tsx | 20 ++- .../__tests__/csv-uploader.spec.tsx | 4 +- .../__tests__/index.spec.tsx | 8 + .../csv-uploader.tsx | 19 ++- .../batch-add-annotation-modal/index.tsx | 11 +- .../__tests__/access-control.spec.tsx | 8 +- .../specific-groups-or-members.spec.tsx | 6 +- .../add-member-or-group-pop.tsx | 30 +++- .../specific-groups-or-members.tsx | 13 +- .../__tests__/version-info-modal.spec.tsx | 16 ++ .../app/app-publisher/version-info-modal.tsx | 11 +- .../config-var/__tests__/index.spec.tsx | 22 +-- .../config-var/__tests__/var-item.spec.tsx | 2 +- .../config-select/__tests__/index.spec.tsx | 9 +- .../config-var/config-select/index.tsx | 11 +- .../app/configuration/config-var/var-item.tsx | 23 ++- .../agent-tools/__tests__/index.spec.tsx | 2 +- .../config/agent/agent-tools/index.tsx | 24 +-- .../__tests__/instruction-editor.spec.tsx | 2 +- .../config/automatic/instruction-editor.tsx | 8 +- .../app/configuration/configuration-view.tsx | 1 - .../ctrl-btn-group/__tests__/index.spec.tsx | 8 +- .../configuration/ctrl-btn-group/index.tsx | 4 +- .../settings-modal/__tests__/index.spec.tsx | 2 +- .../dataset-config/settings-modal/index.tsx | 8 +- .../__tests__/index.spec.tsx | 2 +- .../prompt-value-panel/index.tsx | 12 +- .../__tests__/index.spec.tsx | 26 +-- .../create-app-dialog/app-list/sidebar.tsx | 39 +++-- .../components/app/create-app-modal/index.tsx | 14 +- .../__tests__/uploader.spec.tsx | 2 +- .../app/create-from-dsl-modal/uploader.tsx | 8 +- .../duplicate-modal/__tests__/index.spec.tsx | 21 +++ .../components/app/duplicate-modal/index.tsx | 11 +- .../log-annotation/__tests__/index.spec.tsx | 16 +- .../app/log/__tests__/empty-element.spec.tsx | 5 +- .../app/log/__tests__/filter.spec.tsx | 2 +- .../app/overview/app-card-sections.tsx | 70 ++++---- .../customize/__tests__/index.spec.tsx | 2 +- .../app/overview/customize/index.tsx | 2 +- .../switch-app-modal/__tests__/index.spec.tsx | 9 + .../components/app/switch-app-modal/index.tsx | 19 ++- .../workflow-log/__tests__/detail.spec.tsx | 13 +- .../workflow-log/__tests__/filter.spec.tsx | 12 +- .../components/app/workflow-log/detail.tsx | 15 +- web/app/components/app/workflow-log/list.tsx | 9 +- .../components/base/__tests__/alert.spec.tsx | 5 +- .../agent-log-modal/__tests__/detail.spec.tsx | 6 +- .../agent-log-modal/__tests__/index.spec.tsx | 2 +- .../base/agent-log-modal/detail.tsx | 18 +- .../components/base/agent-log-modal/index.tsx | 11 +- web/app/components/base/alert.tsx | 13 +- .../app-icon-picker/__tests__/index.spec.tsx | 4 +- web/app/components/base/audio-btn/index.tsx | 3 +- .../base/audio-gallery/AudioPlayer.tsx | 10 +- .../__tests__/AudioPlayer.spec.tsx | 41 +++-- .../__tests__/chat-wrapper.spec.tsx | 4 +- .../__tests__/header-in-mobile.spec.tsx | 8 +- .../mobile-operation-dropdown.spec.tsx | 12 +- .../header/mobile-operation-dropdown.tsx | 17 +- .../sidebar/__tests__/item.spec.tsx | 36 ++-- .../chat/__tests__/chat-log-modals.spec.tsx | 2 +- .../chat/chat/__tests__/question.spec.tsx | 68 ++++---- .../chat/answer/__tests__/operation.spec.tsx | 16 +- .../__tests__/human-input-form.spec.tsx | 2 +- .../human-input-content/human-input-form.tsx | 1 - .../base/chat/chat/answer/operation.tsx | 3 +- .../chat-input-area/__tests__/index.spec.tsx | 30 ++-- .../__tests__/operation.spec.tsx | 9 +- .../chat/chat/chat-input-area/operation.tsx | 11 +- .../chat/citation/__tests__/popup.spec.tsx | 32 ++-- .../base/chat/chat/citation/popup.tsx | 3 +- .../components/base/chat/chat/question.tsx | 14 +- .../header/__tests__/index.spec.tsx | 20 +-- .../chat/embedded-chatbot/header/index.tsx | 36 ++-- .../inputs-form/__tests__/index.spec.tsx | 14 +- .../embedded-chatbot/inputs-form/index.tsx | 3 - .../copy-feedback/__tests__/index.spec.tsx | 22 ++- .../components/base/copy-feedback/index.tsx | 18 +- .../base/copy-icon/__tests__/index.spec.tsx | 13 +- web/app/components/base/copy-icon/index.tsx | 4 +- .../date-picker/__tests__/index.spec.tsx | 5 +- .../date-picker/index.tsx | 9 +- .../time-picker/index.tsx | 9 +- .../components/base/emoji-picker/Inner.tsx | 60 +++++-- .../emoji-picker/__tests__/Inner.spec.tsx | 24 +-- .../emoji-picker/__tests__/index.spec.tsx | 4 +- .../__tests__/modal.spec.tsx | 10 +- .../conversation-opener/modal.tsx | 19 +-- .../__tests__/setting-content.spec.tsx | 10 +- .../file-upload/setting-content.tsx | 19 +-- .../moderation-setting-modal.spec.tsx | 16 +- .../moderation/moderation-setting-modal.tsx | 18 +- .../__tests__/param-config-content.spec.tsx | 4 +- .../text-to-speech/param-config-content.tsx | 8 +- .../__tests__/audio-preview.spec.tsx | 6 +- .../__tests__/video-preview.spec.tsx | 10 +- .../base/file-uploader/audio-preview.tsx | 13 +- .../base/file-uploader/file-list-in-log.tsx | 19 ++- .../__tests__/file-item.spec.tsx | 4 +- .../__tests__/file-image-item.spec.tsx | 93 ++-------- .../__tests__/file-item.spec.tsx | 22 +-- .../file-image-item.tsx | 35 ++-- .../file-uploader-in-chat-input/file-item.tsx | 19 ++- .../base/file-uploader/video-preview.tsx | 13 +- .../__tests__/index.spec.tsx | 2 +- .../base/float-right-container/index.tsx | 1 - .../field/__tests__/checkbox.spec.tsx | 2 +- .../base/form/components/field/checkbox.tsx | 1 + .../__tests__/audio-preview.spec.tsx | 5 +- .../__tests__/image-list.spec.tsx | 11 +- .../__tests__/image-preview.spec.tsx | 12 +- .../__tests__/video-preview.spec.tsx | 2 +- .../base/image-uploader/audio-preview.tsx | 14 +- .../base/image-uploader/image-list.tsx | 18 +- .../base/image-uploader/image-preview.tsx | 14 +- .../base/image-uploader/video-preview.tsx | 13 +- .../input-with-copy/__tests__/index.spec.tsx | 17 +- .../components/base/input-with-copy/index.tsx | 7 +- .../base/input/__tests__/index.spec.tsx | 2 +- web/app/components/base/input/index.tsx | 11 +- .../markdown-blocks/__tests__/form.spec.tsx | 4 +- .../base/mermaid/__tests__/index.spec.tsx | 4 +- .../__tests__/index.spec.tsx | 2 +- .../base/message-log-modal/index.tsx | 11 +- .../base/new-audio-button/index.tsx | 3 +- .../__tests__/base.spec.tsx | 6 +- .../__tests__/index.spec.tsx | 4 +- .../credential-selector/index.tsx | 2 +- .../search-input/__tests__/index.spec.tsx | 8 +- .../search-input/index.tsx | 19 ++- .../components/base/prompt-editor/hooks.ts | 6 +- .../__tests__/component.spec.tsx | 2 +- .../plugins/context-block/component.tsx | 23 ++- .../__tests__/component-ui.spec.tsx | 73 ++------ .../__tests__/type-switch.spec.tsx | 4 +- .../plugins/hitl-input-block/component-ui.tsx | 6 +- .../plugins/hitl-input-block/input-field.tsx | 4 +- .../plugins/hitl-input-block/type-switch.tsx | 10 +- .../prompt-log-modal/__tests__/index.spec.tsx | 4 +- .../base/prompt-log-modal/index.tsx | 13 +- .../base/qrcode/__tests__/index.spec.tsx | 22 +-- web/app/components/base/qrcode/index.tsx | 45 ++--- .../base/radio-card/__tests__/index.spec.tsx | 4 +- web/app/components/base/radio-card/index.tsx | 18 +- .../base/sort/__tests__/index.spec.tsx | 11 +- web/app/components/base/sort/index.tsx | 13 +- .../base/svg-gallery/__tests__/index.spec.tsx | 2 +- .../base/tag-input/__tests__/index.spec.tsx | 6 +- web/app/components/base/tag-input/index.tsx | 11 +- .../base/video-gallery/VideoPlayer.tsx | 21 ++- .../__tests__/VideoPlayer.spec.tsx | 21 ++- .../billing/annotation-full/modal.tsx | 2 +- .../custom-page/__tests__/index.spec.tsx | 2 +- .../components/custom/custom-page/index.tsx | 8 +- .../__tests__/status-with-action.spec.tsx | 14 +- .../status-with-action.tsx | 11 +- .../image-list/__tests__/index.spec.tsx | 2 +- .../common/image-list/__tests__/more.spec.tsx | 6 +- .../datasets/common/image-list/more.tsx | 14 +- .../__tests__/index.spec.tsx | 6 +- .../__tests__/uploader.spec.tsx | 4 +- .../create-from-dsl-modal/uploader.tsx | 8 +- .../__tests__/index.spec.tsx | 10 +- .../empty-dataset-creation-modal/index.tsx | 7 +- .../file-preview/__tests__/index.spec.tsx | 18 +- .../datasets/create/file-preview/index.tsx | 11 +- .../__tests__/index.spec.tsx | 13 +- .../create/notion-page-preview/index.tsx | 11 +- .../__tests__/index.spec.tsx | 64 +++---- .../create/stop-embedding-modal/index.tsx | 7 +- .../create/website/__tests__/preview.spec.tsx | 14 +- .../jina-reader/__tests__/base.spec.tsx | 12 +- .../website/jina-reader/base/url-input.tsx | 2 +- .../datasets/create/website/preview.tsx | 11 +- .../documents/components/operations.tsx | 46 ++--- .../file-list/__tests__/index.spec.tsx | 4 +- .../file-list/header/__tests__/index.spec.tsx | 10 +- .../documents/detail/__tests__/index.spec.tsx | 6 +- .../detail/__tests__/new-segment.spec.tsx | 15 +- .../__tests__/csv-uploader.spec.tsx | 25 ++- .../detail/batch-modal/csv-uploader.tsx | 19 ++- .../__tests__/child-segment-detail.spec.tsx | 12 +- .../__tests__/new-child-segment.spec.tsx | 12 +- .../__tests__/segment-detail.spec.tsx | 12 +- .../detail/completed/child-segment-detail.tsx | 24 ++- .../components/__tests__/menu-bar.spec.tsx | 2 +- .../detail/completed/new-child-segment.tsx | 22 ++- .../segment-card/__tests__/index.spec.tsx | 14 +- .../detail/completed/segment-card/index.tsx | 16 +- .../detail/completed/segment-detail.tsx | 24 ++- .../datasets/documents/detail/index.tsx | 3 +- .../__tests__/doc-type-selector.spec.tsx | 2 +- .../metadata/components/doc-type-selector.tsx | 8 +- .../datasets/documents/detail/new-segment.tsx | 22 ++- .../segment-add/__tests__/index.spec.tsx | 4 +- .../documents/detail/segment-add/index.tsx | 20 ++- .../datasets/documents/style.module.css | 2 +- .../__tests__/modify-retrieval-modal.spec.tsx | 14 +- .../__tests__/chunk-detail-modal.spec.tsx | 2 +- .../__tests__/result-item-footer.spec.tsx | 3 +- .../components/chunk-detail-modal.tsx | 1 - .../components/result-item-external.tsx | 2 +- .../components/result-item-footer.tsx | 9 +- .../hit-testing/modify-retrieval-modal.tsx | 11 +- .../base/__tests__/date-picker.spec.tsx | 71 ++++---- .../datasets/metadata/base/date-picker.tsx | 62 ++++--- .../__tests__/edited-beacon.spec.tsx | 14 +- .../edit-metadata-batch/edited-beacon.tsx | 11 +- .../metadata/edit-metadata-batch/modal.tsx | 2 +- .../__tests__/create-content.spec.tsx | 4 +- .../dataset-metadata-drawer.spec.tsx | 83 ++------- .../__tests__/select-metadata.spec.tsx | 20 +-- .../metadata-dataset/create-content.tsx | 8 +- .../dataset-metadata-drawer.tsx | 24 ++- .../metadata-dataset/select-metadata.tsx | 29 ++-- .../__tests__/info-group.spec.tsx | 34 ++-- .../metadata/metadata-document/info-group.tsx | 11 +- .../rename-modal/__tests__/index.spec.tsx | 12 +- .../datasets/rename-modal/index.tsx | 11 +- .../__tests__/index.spec.tsx | 2 +- .../develop/__tests__/ApiServer.spec.tsx | 16 +- .../secret-key/__tests__/input-copy.spec.tsx | 9 +- .../develop/secret-key/input-copy.tsx | 15 +- .../explore/app-list/__tests__/index.spec.tsx | 2 +- .../try-app/app/__tests__/chat.spec.tsx | 6 +- .../components/explore/try-app/app/chat.tsx | 8 +- .../__tests__/maintenance-notice.spec.tsx | 6 +- .../account-about/__tests__/index.spec.tsx | 8 +- .../components/header/account-about/index.tsx | 11 +- .../collapse/__tests__/index.spec.tsx | 8 +- .../header/account-setting/collapse/index.tsx | 21 ++- .../install-from-marketplace.tsx | 11 +- .../members-page/__tests__/index.spec.tsx | 2 +- .../__tests__/index.spec.tsx | 18 +- .../edit-workspace-modal/index.tsx | 6 +- .../account-setting/members-page/index.tsx | 12 +- .../invite-modal/__tests__/index.spec.tsx | 4 +- .../__tests__/role-selector.spec.tsx | 39 +++-- .../members-page/invite-modal/index.tsx | 10 +- .../invite-modal/role-selector.tsx | 44 ++--- .../__tests__/invitation-link.spec.tsx | 6 +- .../invited-modal/invitation-link.tsx | 23 ++- .../__tests__/index.spec.tsx | 18 +- .../transfer-ownership-modal/index.tsx | 21 ++- .../__tests__/index.spec.tsx | 6 +- .../provider-added-card/index.tsx | 5 +- .../components/header/maintenance-notice.tsx | 21 ++- .../install-plugin/install-bundle/index.tsx | 2 +- .../install-from-github/index.tsx | 2 +- .../install-from-local-package/index.tsx | 2 +- .../install-from-marketplace/index.tsx | 2 +- .../__tests__/add-oauth-button.spec.tsx | 6 +- .../__tests__/api-key-modal.spec.tsx | 2 +- .../__tests__/authorize-components.spec.tsx | 17 +- .../__tests__/oauth-client-settings.spec.tsx | 4 +- .../authorize/add-oauth-button.tsx | 43 +++-- .../plugin-auth/authorize/api-key-modal.tsx | 1 - .../authorize/oauth-client-settings.tsx | 2 - .../create/__tests__/common-modal.spec.tsx | 2 +- .../subscription-list/create/common-modal.tsx | 1 - .../subscription-list/create/oauth-client.tsx | 2 +- .../edit/__tests__/index.spec.tsx | 161 +++++++++--------- .../edit/apikey-edit-modal.tsx | 5 +- .../edit/manual-edit-modal.tsx | 4 +- .../edit/oauth-edit-modal.tsx | 4 +- .../plugins/plugin-mutation-model/index.tsx | 2 +- .../plugin-page/__tests__/index.spec.tsx | 4 +- .../components/plugins/plugin-page/index.tsx | 4 +- .../plugins/plugin-page/plugin-info.tsx | 2 +- .../__tests__/index.spec.tsx | 19 +-- .../__tests__/plugins-picker.spec.tsx | 2 +- .../auto-update-setting/index.tsx | 15 +- .../auto-update-setting/plugins-picker.tsx | 8 +- .../plugins/reference-setting-modal/index.tsx | 2 +- .../components/__tests__/index.spec.tsx | 2 +- ...blish-as-knowledge-pipeline-modal.spec.tsx | 2 +- .../editor/__tests__/index.spec.tsx | 4 +- .../form/__tests__/show-all-settings.spec.tsx | 2 +- .../editor/form/show-all-settings.tsx | 10 +- .../panel/input-field/editor/index.tsx | 6 +- .../field-list/__tests__/index.spec.tsx | 10 +- .../panel/input-field/field-list/index.tsx | 6 +- .../publish-as-knowledge-pipeline-modal.tsx | 11 +- .../components/update-dsl-modal.tsx | 11 +- .../text-generation-result-panel.spec.tsx | 4 +- .../share/text-generation/info-modal.tsx | 2 +- .../run-once/__tests__/index.spec.tsx | 6 +- .../share/text-generation/run-once/index.tsx | 1 - .../text-generation-result-panel.tsx | 8 +- .../signin/__tests__/countdown.spec.tsx | 16 +- web/app/components/signin/countdown.tsx | 10 +- .../tools/__tests__/provider-list.spec.tsx | 2 +- web/app/components/tools/labels/filter.tsx | 9 +- .../mcp/__tests__/mcp-server-modal.spec.tsx | 10 +- .../tools/mcp/__tests__/modal.spec.tsx | 12 +- .../components/tools/mcp/mcp-server-modal.tsx | 11 +- web/app/components/tools/mcp/modal.tsx | 11 +- .../__tests__/configure-button.spec.tsx | 2 +- .../confirm-modal/__tests__/index.spec.tsx | 12 +- .../workflow-tool/confirm-modal/index.tsx | 11 +- .../components/tools/workflow-tool/index.tsx | 1 - .../tools/workflow-tool/method-selector.tsx | 20 ++- .../__tests__/selection-contextmenu.spec.tsx | 8 +- .../__tests__/update-dsl-modal.spec.tsx | 9 + .../__tests__/index-bar.spec.tsx | 2 +- .../workflow/block-selector/index-bar.tsx | 9 +- .../_base/components/before-run-form/form.tsx | 13 +- .../var-reference-picker.branches.spec.tsx | 2 +- .../__tests__/var-reference-picker.spec.tsx | 2 +- .../var-reference-picker.trigger.spec.tsx | 4 +- .../variable/var-reference-picker.trigger.tsx | 24 ++- .../nodes/code/__tests__/panel.spec.tsx | 12 +- .../components/workflow/nodes/code/panel.tsx | 28 ++- .../nodes/end/__tests__/panel.spec.tsx | 4 +- .../components/workflow/nodes/end/panel.tsx | 11 +- .../human-input/__tests__/panel.spec.tsx | 7 +- .../__tests__/single-run-form.spec.tsx | 102 +++++++++++ .../__tests__/test-email-sender.spec.tsx | 2 +- .../delivery-method/test-email-sender.tsx | 19 ++- .../components/single-run-form.tsx | 10 +- .../workflow/nodes/human-input/panel.tsx | 21 ++- .../__tests__/integration.spec.tsx | 4 +- .../components/add-dataset.tsx | 6 +- .../components/dataset-item.tsx | 2 - .../condition-list/condition-date.tsx | 67 ++++---- .../json-importer.tsx | 11 +- .../generated-result.tsx | 11 +- .../json-schema-generator/prompt-editor.tsx | 11 +- .../components/workflow/nodes/llm/panel.tsx | 11 +- .../__tests__/integration.spec.tsx | 6 +- .../__tests__/update.spec.tsx | 4 +- .../components/extract-parameter/update.tsx | 11 +- .../components/__tests__/class-list.spec.tsx | 4 +- .../components/class-list.tsx | 11 +- .../nodes/start/__tests__/panel.spec.tsx | 2 +- .../components/__tests__/var-item.spec.tsx | 38 +++++ .../nodes/start/components/var-item.tsx | 22 ++- .../components/workflow/nodes/start/panel.tsx | 11 +- .../__tests__/integration.spec.tsx | 4 +- .../__tests__/panel.spec.tsx | 4 +- .../nodes/template-transform/panel.tsx | 11 +- .../panel/__tests__/workflow-preview.spec.tsx | 4 +- .../conversation-variable-modal.spec.tsx | 3 +- .../conversation-variable-modal.tsx | 22 ++- .../workflow/panel/workflow-preview.tsx | 11 +- .../run/__tests__/loop-result-panel.spec.tsx | 9 +- .../run/__tests__/result-text.spec.tsx | 2 +- .../workflow/run/loop-result-panel.tsx | 38 +++-- .../components/workflow/run/result-text.tsx | 8 +- .../workflow/selection-contextmenu.tsx | 3 - .../components/workflow/update-dsl-modal.tsx | 11 +- .../variable-inspect/__tests__/group.spec.tsx | 10 +- .../workflow/variable-inspect/group.tsx | 53 +++--- .../education-apply/expire-notice-modal.tsx | 2 +- web/docs/test.md | 16 +- .../__tests__/dataset-card-tags.spec.tsx | 22 +-- .../__tests__/tag-filter.spec.tsx | 15 +- .../__tests__/tag-item-editor.spec.tsx | 42 +++-- .../__tests__/tag-management-modal.spec.tsx | 25 ++- .../__tests__/tag-panel.spec.tsx | 9 +- .../__tests__/tag-selector.spec.tsx | 2 +- .../__tests__/tag-trigger.spec.tsx | 5 +- .../__tests__/app-card-tags.spec.tsx | 15 +- .../tag-management/components/tag-filter.tsx | 9 +- .../components/tag-item-editor.tsx | 23 ++- .../components/tag-management-modal.tsx | 4 +- .../tag-management/components/tag-panel.tsx | 2 - .../tag-management/components/tag-trigger.tsx | 7 +- web/i18n/en-US/common.json | 7 + 377 files changed, 2806 insertions(+), 2135 deletions(-) create mode 100644 web/app/components/workflow/nodes/human-input/components/__tests__/single-run-form.spec.tsx create mode 100644 web/app/components/workflow/nodes/start/components/__tests__/var-item.spec.tsx diff --git a/.agents/skills/frontend-testing/SKILL.md b/.agents/skills/frontend-testing/SKILL.md index 86675dfeba..21c46d75bc 100644 --- a/.agents/skills/frontend-testing/SKILL.md +++ b/.agents/skills/frontend-testing/SKILL.md @@ -38,13 +38,13 @@ Run these commands from `web/`. From the repository root, prefix them with `pnpm pnpm test # Watch mode -pnpm test:watch +pnpm test --watch # Run specific file pnpm test path/to/file.spec.tsx # Generate coverage report -pnpm test:coverage +pnpm test --coverage # Analyze component complexity pnpm analyze-component @@ -220,7 +220,10 @@ Every test should clearly separate: ### 2. Black-Box Testing - Test observable behavior, not implementation details -- Use semantic queries (getByRole, getByLabelText) +- Use semantic queries (`getByRole` with accessible `name`, `getByLabelText`, `getByPlaceholderText`, `getByText`, and scoped `within(...)`) +- Treat `getByTestId` as a last resort. If a control cannot be found by role/name, label, landmark, or dialog scope, fix the component accessibility first instead of adding or relying on `data-testid`. +- Remove production `data-testid` attributes when semantic selectors can cover the behavior. Keep them only for non-visual mocked boundaries, editor/browser shims such as Monaco, canvas/chart output, or third-party widgets with no accessible DOM in the test environment. +- Do not assert decorative icons by test id. Assert the named control that contains them, or mark decorative icons `aria-hidden`. - Avoid testing internal state directly - **Prefer pattern matching over hardcoded strings** in assertions: diff --git a/e2e/features/step-definitions/apps/share-app.steps.ts b/e2e/features/step-definitions/apps/share-app.steps.ts index d5742bdaa8..3ec038b065 100644 --- a/e2e/features/step-definitions/apps/share-app.steps.ts +++ b/e2e/features/step-definitions/apps/share-app.steps.ts @@ -40,7 +40,7 @@ Then('the shared app page should be accessible', async function (this: DifyWorld When('I run the shared workflow app', async function (this: DifyWorld) { const page = this.getPage() - const runButton = page.getByTestId('run-button') + const runButton = page.getByRole('button', { name: 'Execute' }) await expect(runButton).toBeEnabled({ timeout: 15_000 }) await runButton.click() diff --git a/web/__tests__/base/notion-page-selector-flow.test.tsx b/web/__tests__/base/notion-page-selector-flow.test.tsx index 6295d2dc00..ef813ee4bc 100644 --- a/web/__tests__/base/notion-page-selector-flow.test.tsx +++ b/web/__tests__/base/notion-page-selector-flow.test.tsx @@ -111,7 +111,7 @@ describe('Base Notion Page Selector Flow', () => { await user.type(screen.getByTestId('notion-search-input'), 'missing-page') expect(screen.getByText('common.dataSource.notion.selector.noSearchResult')).toBeInTheDocument() - await user.click(screen.getByTestId('notion-search-input-clear')) + await user.click(screen.getByRole('button', { name: 'common.operation.clear' })) expect(screen.getByTestId('notion-page-name-root-1')).toBeInTheDocument() await user.click(screen.getByTestId('notion-page-preview-root-1')) @@ -134,7 +134,7 @@ describe('Base Notion Page Selector Flow', () => { expect(onSelectCredential).toHaveBeenCalledWith('c1') - await user.click(screen.getByTestId('notion-credential-selector-btn')) + await user.click(screen.getByRole('combobox', { name: /Workspace 1/ })) await user.click(screen.getByTestId('notion-credential-item-c2')) expect(mockInvalidPreImportNotionPages).toHaveBeenCalledWith({ datasetId: 'dataset-1', credentialId: 'c2' }) diff --git a/web/__tests__/share/text-generation-run-once-flow.test.tsx b/web/__tests__/share/text-generation-run-once-flow.test.tsx index 2a5d1b882c..1471effa2d 100644 --- a/web/__tests__/share/text-generation-run-once-flow.test.tsx +++ b/web/__tests__/share/text-generation-run-once-flow.test.tsx @@ -119,7 +119,7 @@ describe('RunOnce – integration flow', () => { fireEvent.change(screen.getByPlaceholderText('Bio'), { target: { value: 'Hello' } }) // Phase 3 – submit - fireEvent.click(screen.getByTestId('run-button')) + fireEvent.click(screen.getByRole('button', { name: 'share.generation.run' })) expect(onSend).toHaveBeenCalledTimes(1) // Phase 4 – simulate "running" state @@ -132,7 +132,7 @@ describe('RunOnce – integration flow', () => { />, ) - const stopBtn = screen.getByTestId('stop-button') + const stopBtn = screen.getByRole('button', { name: 'share.generation.stopRun:{"defaultValue":"Stop Run"}' }) expect(stopBtn).toBeInTheDocument() fireEvent.click(stopBtn) expect(onStop).toHaveBeenCalledTimes(1) @@ -145,7 +145,7 @@ describe('RunOnce – integration flow', () => { runControl={{ onStop, isStopping: true }} />, ) - expect(screen.getByTestId('stop-button')).toBeDisabled() + expect(screen.getByRole('button', { name: 'share.generation.stopRun:{"defaultValue":"Stop Run"}' })).toBeDisabled() }) it('clear resets all field types and allows re-submit', async () => { @@ -174,7 +174,7 @@ describe('RunOnce – integration flow', () => { // Re-fill and submit fireEvent.change(screen.getByPlaceholderText('Question'), { target: { value: 'New' } }) - fireEvent.click(screen.getByTestId('run-button')) + fireEvent.click(screen.getByRole('button', { name: 'share.generation.run' })) expect(onSend).toHaveBeenCalledTimes(1) }) @@ -212,7 +212,7 @@ describe('RunOnce – integration flow', () => { fireEvent.change(screen.getByPlaceholderText('Text'), { target: { value: 'hello' } }) fireEvent.change(screen.getByTestId('code-editor'), { target: { value: '{"a":1}' } }) - fireEvent.click(screen.getByTestId('run-button')) + fireEvent.click(screen.getByRole('button', { name: 'share.generation.run' })) expect(onSend).toHaveBeenCalledTimes(1) }) }) diff --git a/web/app/(commonLayout)/datasets/layout.spec.tsx b/web/app/(commonLayout)/datasets/layout.spec.tsx index 9c01cffba8..7abc2253ce 100644 --- a/web/app/(commonLayout)/datasets/layout.spec.tsx +++ b/web/app/(commonLayout)/datasets/layout.spec.tsx @@ -63,12 +63,12 @@ describe('DatasetsLayout', () => { render(( -
datasets
+
datasets
)) expect(screen.getByRole('status')).toBeInTheDocument() - expect(screen.queryByTestId('datasets-content')).not.toBeInTheDocument() + expect(screen.queryByText('datasets')).not.toBeInTheDocument() expect(mockReplace).not.toHaveBeenCalled() }) @@ -80,11 +80,11 @@ describe('DatasetsLayout', () => { render(( -
datasets
+
datasets
)) - expect(screen.queryByTestId('datasets-content')).not.toBeInTheDocument() + expect(screen.queryByText('datasets')).not.toBeInTheDocument() await waitFor(() => { expect(mockReplace).toHaveBeenCalledWith('/apps') }) @@ -98,11 +98,11 @@ describe('DatasetsLayout', () => { render(( -
datasets
+
datasets
)) - expect(screen.getByTestId('datasets-content')).toBeInTheDocument() + expect(screen.getByText('datasets')).toBeInTheDocument() expect(mockReplace).not.toHaveBeenCalled() }) }) diff --git a/web/app/(commonLayout)/role-route-guard.spec.tsx b/web/app/(commonLayout)/role-route-guard.spec.tsx index ca1550f0b8..ef409393b0 100644 --- a/web/app/(commonLayout)/role-route-guard.spec.tsx +++ b/web/app/(commonLayout)/role-route-guard.spec.tsx @@ -48,12 +48,12 @@ describe('RoleRouteGuard', () => { render(( -
content
+
content
)) expect(screen.getByRole('status')).toBeInTheDocument() - expect(screen.queryByTestId('guarded-content')).not.toBeInTheDocument() + expect(screen.queryByText('content')).not.toBeInTheDocument() expect(mockReplace).not.toHaveBeenCalled() }) @@ -64,11 +64,11 @@ describe('RoleRouteGuard', () => { render(( -
content
+
content
)) - expect(screen.queryByTestId('guarded-content')).not.toBeInTheDocument() + expect(screen.queryByText('content')).not.toBeInTheDocument() await waitFor(() => { expect(mockReplace).toHaveBeenCalledWith('/datasets') }) @@ -82,11 +82,11 @@ describe('RoleRouteGuard', () => { render(( -
content
+
content
)) - expect(screen.getByTestId('guarded-content')).toBeInTheDocument() + expect(screen.getByText('content')).toBeInTheDocument() expect(mockReplace).not.toHaveBeenCalled() }) @@ -98,11 +98,11 @@ describe('RoleRouteGuard', () => { render(( -
content
+
content
)) - expect(screen.getByTestId('guarded-content')).toBeInTheDocument() + expect(screen.getByText('content')).toBeInTheDocument() expect(screen.queryByRole('status')).not.toBeInTheDocument() expect(mockReplace).not.toHaveBeenCalled() }) diff --git a/web/app/components/app/annotation/__tests__/filter.spec.tsx b/web/app/components/app/annotation/__tests__/filter.spec.tsx index 8b69494e3f..5353a32c4b 100644 --- a/web/app/components/app/annotation/__tests__/filter.spec.tsx +++ b/web/app/components/app/annotation/__tests__/filter.spec.tsx @@ -243,10 +243,7 @@ describe('Filter', () => { ) // Act - const input = screen.getByPlaceholderText('common.operation.search') - const clearButton = input.parentElement?.querySelector('div.cursor-pointer') - if (clearButton) - fireEvent.click(clearButton) + fireEvent.click(screen.getByRole('button', { name: 'common.operation.clear' })) // Assert expect(setQueryParams).toHaveBeenCalledWith({ ...queryParams, keyword: '' }) diff --git a/web/app/components/app/annotation/batch-action.tsx b/web/app/components/app/annotation/batch-action.tsx index 938dcb03bd..961f313746 100644 --- a/web/app/components/app/annotation/batch-action.tsx +++ b/web/app/components/app/annotation/batch-action.tsx @@ -55,15 +55,23 @@ const BatchAction: FC = ({ {t(`${i18nPrefix}.selected`, { ns: 'appAnnotation' })} -
- - -
+ + - diff --git a/web/app/components/app/annotation/batch-add-annotation-modal/__tests__/csv-uploader.spec.tsx b/web/app/components/app/annotation/batch-add-annotation-modal/__tests__/csv-uploader.spec.tsx index 5fc1cd25e1..8e6dd6cc28 100644 --- a/web/app/components/app/annotation/batch-add-annotation-modal/__tests__/csv-uploader.spec.tsx +++ b/web/app/components/app/annotation/batch-add-annotation-modal/__tests__/csv-uploader.spec.tsx @@ -54,7 +54,7 @@ describe('CSVUploader', () => { const clickSpy = vi.spyOn(HTMLInputElement.prototype, 'click') renderComponent() - fireEvent.click(screen.getByText('appAnnotation.batchModal.browse')) + fireEvent.click(screen.getByRole('button', { name: 'appAnnotation.batchModal.browse' })) expect(clickSpy).toHaveBeenCalledTimes(1) clickSpy.mockRestore() @@ -137,7 +137,7 @@ describe('CSVUploader', () => { clickSpy.mockRestore() const valueSetter = vi.spyOn(fileInput, 'value', 'set') - const removeTrigger = screen.getByTestId('remove-file-button') + const removeTrigger = screen.getByRole('button', { name: /operation\.delete$/ }) fireEvent.click(removeTrigger) expect(updateFile).toHaveBeenCalledWith() diff --git a/web/app/components/app/annotation/batch-add-annotation-modal/__tests__/index.spec.tsx b/web/app/components/app/annotation/batch-add-annotation-modal/__tests__/index.spec.tsx index c5d7232e12..74b59ff79f 100644 --- a/web/app/components/app/annotation/batch-add-annotation-modal/__tests__/index.spec.tsx +++ b/web/app/components/app/annotation/batch-add-annotation-modal/__tests__/index.spec.tsx @@ -115,6 +115,14 @@ describe('BatchModal', () => { expect(props.onCancel).toHaveBeenCalledTimes(1) }) + it('should call onCancel when close button is clicked', () => { + const { props } = renderComponent() + + fireEvent.click(screen.getByRole('button', { name: /operation\.close$/ })) + + expect(props.onCancel).toHaveBeenCalledTimes(1) + }) + it('should submit the csv file, poll status, and notify when import completes', async () => { vi.useFakeTimers({ shouldAdvanceTime: true }) const { props } = renderComponent() diff --git a/web/app/components/app/annotation/batch-add-annotation-modal/csv-uploader.tsx b/web/app/components/app/annotation/batch-add-annotation-modal/csv-uploader.tsx index dc63b5c9be..75c3e8a66c 100644 --- a/web/app/components/app/annotation/batch-add-annotation-modal/csv-uploader.tsx +++ b/web/app/components/app/annotation/batch-add-annotation-modal/csv-uploader.tsx @@ -97,7 +97,13 @@ const CSVUploader: FC = ({
{t('batchModal.csvUploadTitle', { ns: 'appAnnotation' })} - {t('batchModal.browse', { ns: 'appAnnotation' })} +
{dragging &&
} @@ -113,9 +119,14 @@ const CSVUploader: FC = ({
-
- -
+
)} diff --git a/web/app/components/app/annotation/batch-add-annotation-modal/index.tsx b/web/app/components/app/annotation/batch-add-annotation-modal/index.tsx index 0f6c27fd5a..7f1905c025 100644 --- a/web/app/components/app/annotation/batch-add-annotation-modal/index.tsx +++ b/web/app/components/app/annotation/batch-add-annotation-modal/index.tsx @@ -91,9 +91,14 @@ const BatchModal: FC = ({
{t('batchModal.title', { ns: 'appAnnotation' })}
-
- -
+ { expect(screen.getByText(baseMember.name)).toBeInTheDocument() }) - const groupItem = screen.getByText(baseGroup.name).closest('div') - const groupRemove = groupItem?.querySelector('.h-4.w-4.cursor-pointer') as HTMLElement + const groupRemove = screen.getAllByRole('button', { name: /operation\.remove$/ })[0]! + fireEvent.click(groupRemove) await waitFor(() => { expect(screen.queryByText(baseGroup.name)).not.toBeInTheDocument() }) - const memberItem = screen.getByText(baseMember.name).closest('div') - const memberRemove = memberItem?.querySelector('.h-4.w-4.cursor-pointer') as HTMLElement + const memberRemove = screen.getAllByRole('button', { name: /operation\.remove$/ })[0]! + fireEvent.click(memberRemove) await waitFor(() => { diff --git a/web/app/components/app/app-access-control/__tests__/specific-groups-or-members.spec.tsx b/web/app/components/app/app-access-control/__tests__/specific-groups-or-members.spec.tsx index 7b198c4e66..e763521940 100644 --- a/web/app/components/app/app-access-control/__tests__/specific-groups-or-members.spec.tsx +++ b/web/app/components/app/app-access-control/__tests__/specific-groups-or-members.spec.tsx @@ -86,11 +86,13 @@ describe('SpecificGroupsOrMembers', () => { expect(screen.getByText(baseMember.name)).toBeInTheDocument() }) - const groupRemove = screen.getByText(baseGroup.name).closest('div')?.querySelector('.h-4.w-4.cursor-pointer') as HTMLElement + const removeButtons = screen.getAllByRole('button', { name: /operation\.remove$/ }) + const groupRemove = removeButtons[0]! + const memberRemove = removeButtons[1]! + fireEvent.click(groupRemove) expect(useAccessControlStore.getState().specificGroups).toEqual([]) - const memberRemove = screen.getByText(baseMember.name).closest('div')?.querySelector('.h-4.w-4.cursor-pointer') as HTMLElement fireEvent.click(memberRemove) expect(useAccessControlStore.getState().specificMembers).toEqual([]) }) diff --git a/web/app/components/app/app-access-control/add-member-or-group-pop.tsx b/web/app/components/app/app-access-control/add-member-or-group-pop.tsx index 38f9c2ab50..8d9bf19ea3 100644 --- a/web/app/components/app/app-access-control/add-member-or-group-pop.tsx +++ b/web/app/components/app/app-access-control/add-member-or-group-pop.tsx @@ -119,14 +119,40 @@ function SelectedGroupsBreadCrumb() { const handleReset = useCallback(() => { setSelectedGroupsForBreadcrumb([]) }, [setSelectedGroupsForBreadcrumb]) + const hasBreadcrumb = selectedGroupsForBreadcrumb.length > 0 + return (
- 0 && 'cursor-pointer text-text-accent')} onClick={handleReset}>{t('accessControlDialog.operateGroupAndMember.allMembers', { ns: 'app' })} + {hasBreadcrumb + ? ( + + ) + : ( + {t('accessControlDialog.operateGroupAndMember.allMembers', { ns: 'app' })} + )} {selectedGroupsForBreadcrumb.map((group, index) => { + const isLastGroup = index === selectedGroupsForBreadcrumb.length - 1 + return (
/ - handleBreadCrumbClick(index)}>{group.name} + {isLastGroup + ? {group.name} + : ( + + )}
) })} diff --git a/web/app/components/app/app-access-control/specific-groups-or-members.tsx b/web/app/components/app/app-access-control/specific-groups-or-members.tsx index 2cacd2cf03..ce6619ec80 100644 --- a/web/app/components/app/app-access-control/specific-groups-or-members.tsx +++ b/web/app/components/app/app-access-control/specific-groups-or-members.tsx @@ -120,6 +120,8 @@ type BaseItemProps = { onRemove?: () => void } function BaseItem({ icon, onRemove, children }: BaseItemProps) { + const { t } = useTranslation() + return (
@@ -128,9 +130,14 @@ function BaseItem({ icon, onRemove, children }: BaseItemProps) {
{children} -
- -
+
) } diff --git a/web/app/components/app/app-publisher/__tests__/version-info-modal.spec.tsx b/web/app/components/app/app-publisher/__tests__/version-info-modal.spec.tsx index 942a199a87..252eddb47e 100644 --- a/web/app/components/app/app-publisher/__tests__/version-info-modal.spec.tsx +++ b/web/app/components/app/app-publisher/__tests__/version-info-modal.spec.tsx @@ -103,6 +103,22 @@ describe('VersionInfoModal', () => { expect(handleClose).toHaveBeenCalledTimes(1) }) + it('should close when the close button is clicked', () => { + const handleClose = vi.fn() + + render( + , + ) + + fireEvent.click(screen.getByRole('button', { name: 'operation.close' })) + + expect(handleClose).toHaveBeenCalledTimes(1) + }) + it('should validate release note length and clear previous errors before publishing', () => { const handlePublish = vi.fn() const handleClose = vi.fn() diff --git a/web/app/components/app/app-publisher/version-info-modal.tsx b/web/app/components/app/app-publisher/version-info-modal.tsx index 264975a08b..4e5493d1b2 100644 --- a/web/app/components/app/app-publisher/version-info-modal.tsx +++ b/web/app/components/app/app-publisher/version-info-modal.tsx @@ -79,9 +79,14 @@ const VersionInfoModal: FC = ({
{versionInfo?.marked_name ? t('versionHistory.editVersionInfo', { ns: 'workflow' }) : t('versionHistory.nameThisVersion', { ns: 'workflow' })}
-
- -
+
diff --git a/web/app/components/app/configuration/config-var/__tests__/index.spec.tsx b/web/app/components/app/configuration/config-var/__tests__/index.spec.tsx index 51683ad948..604db8288a 100644 --- a/web/app/components/app/configuration/config-var/__tests__/index.spec.tsx +++ b/web/app/components/app/configuration/config-var/__tests__/index.spec.tsx @@ -233,9 +233,7 @@ describe('ConfigVar', () => { const item = screen.getByTitle('name · Name') const itemContainer = item.closest('div.group') expect(itemContainer).not.toBeNull() - const actionButtons = itemContainer!.querySelectorAll('div.h-6.w-6') - expect(actionButtons).toHaveLength(2) - fireEvent.click(actionButtons[0]!) + fireEvent.click(within(itemContainer as HTMLElement).getByRole('button', { name: 'common.operation.edit' })) const editDialog = await screen.findByRole('dialog') const saveButton = within(editDialog).getByRole('button', { name: 'common.operation.save' }) @@ -259,9 +257,7 @@ describe('ConfigVar', () => { const item = screen.getByTitle('first · First') const itemContainer = item.closest('div.group') expect(itemContainer).not.toBeNull() - const actionButtons = itemContainer!.querySelectorAll('div.h-6.w-6') - expect(actionButtons).toHaveLength(2) - fireEvent.click(actionButtons[0]!) + fireEvent.click(within(itemContainer as HTMLElement).getByRole('button', { name: 'common.operation.edit' })) const inputs = await screen.findAllByPlaceholderText('appDebug.variableConfig.inputPlaceholder') fireEvent.change(inputs[0]!, { target: { value: 'second' } }) @@ -285,9 +281,7 @@ describe('ConfigVar', () => { const item = screen.getByTitle('first · First') const itemContainer = item.closest('div.group') expect(itemContainer).not.toBeNull() - const actionButtons = itemContainer!.querySelectorAll('div.h-6.w-6') - expect(actionButtons).toHaveLength(2) - fireEvent.click(actionButtons[0]!) + fireEvent.click(within(itemContainer as HTMLElement).getByRole('button', { name: 'common.operation.edit' })) const inputs = await screen.findAllByPlaceholderText('appDebug.variableConfig.inputPlaceholder') fireEvent.change(inputs[1]!, { target: { value: 'Second' } }) @@ -318,7 +312,7 @@ describe('ConfigVar', () => { onPromptVariablesChange, }) - const removeBtn = screen.getByTestId('var-item-delete-btn') + const removeBtn = screen.getByRole('button', { name: 'common.operation.delete' }) fireEvent.click(removeBtn) expect(onPromptVariablesChange).toHaveBeenCalledWith([]) @@ -343,7 +337,7 @@ describe('ConfigVar', () => { }, ) - const deleteBtn = screen.getByTestId('var-item-delete-btn') + const deleteBtn = screen.getByRole('button', { name: 'common.operation.delete' }) fireEvent.click(deleteBtn) // confirmation modal should show up fireEvent.click(screen.getByRole('button', { name: 'common.operation.confirm' })) @@ -411,8 +405,7 @@ describe('ConfigVar', () => { const itemContainer = item.closest('div.group') expect(itemContainer).not.toBeNull() - const actionButtons = itemContainer!.querySelectorAll('div.h-6.w-6') - fireEvent.click(actionButtons[0]!) + fireEvent.click(within(itemContainer as HTMLElement).getByRole('button', { name: 'common.operation.edit' })) const modalState = setShowExternalDataToolModal.mock.calls.at(-1)?.[0] @@ -460,8 +453,7 @@ describe('ConfigVar', () => { const itemContainer = item.closest('div.group') expect(itemContainer).not.toBeNull() - const actionButtons = itemContainer!.querySelectorAll('div.h-6.w-6') - fireEvent.click(actionButtons[0]!) + fireEvent.click(within(itemContainer as HTMLElement).getByRole('button', { name: 'common.operation.edit' })) const modalState = setShowExternalDataToolModal.mock.calls.at(-1)?.[0] diff --git a/web/app/components/app/configuration/config-var/__tests__/var-item.spec.tsx b/web/app/components/app/configuration/config-var/__tests__/var-item.spec.tsx index aae00bb2b7..6f4fe5f11a 100644 --- a/web/app/components/app/configuration/config-var/__tests__/var-item.spec.tsx +++ b/web/app/components/app/configuration/config-var/__tests__/var-item.spec.tsx @@ -39,7 +39,7 @@ describe('VarItem', () => { />, ) - fireEvent.click(screen.getByTestId('var-item-delete-btn')) + fireEvent.click(screen.getByRole('button', { name: 'common.operation.delete' })) expect(onRemove).toHaveBeenCalledTimes(1) }) diff --git a/web/app/components/app/configuration/config-var/config-select/__tests__/index.spec.tsx b/web/app/components/app/configuration/config-var/config-select/__tests__/index.spec.tsx index 337b3bfe1c..24517eb341 100644 --- a/web/app/components/app/configuration/config-var/config-select/__tests__/index.spec.tsx +++ b/web/app/components/app/configuration/config-var/config-select/__tests__/index.spec.tsx @@ -44,12 +44,7 @@ describe('ConfigSelect Component', () => { it('handles option deletion', () => { render() - const optionContainer = screen.getByDisplayValue('Option 1').closest('div') - const deleteButton = optionContainer?.querySelector('div[role="button"]') - - if (!deleteButton) - return - fireEvent.click(deleteButton) + fireEvent.click(screen.getAllByRole('button', { name: 'common.operation.delete' })[0]!) expect(defaultProps.onChange).toHaveBeenCalledWith(['Option 2']) }) @@ -86,7 +81,7 @@ describe('ConfigSelect Component', () => { it('applies delete hover styles', () => { render() const optionContainer = screen.getByDisplayValue('Option 1').closest('div') - const deleteButton = optionContainer?.querySelector('div[role="button"]') + const deleteButton = screen.getAllByRole('button', { name: 'common.operation.delete' })[0] if (!deleteButton) return diff --git a/web/app/components/app/configuration/config-var/config-select/index.tsx b/web/app/components/app/configuration/config-var/config-select/index.tsx index 24bc3b4a06..42878852d9 100644 --- a/web/app/components/app/configuration/config-var/config-select/index.tsx +++ b/web/app/components/app/configuration/config-var/config-select/index.tsx @@ -67,9 +67,10 @@ const ConfigSelect: FC = ({ onFocus={() => setFocusID(index)} onBlur={() => setFocusID(null)} /> -
{ onChange(options.filter((_, i) => index !== i)) setDeletingID(null) @@ -77,8 +78,8 @@ const ConfigSelect: FC = ({ onMouseEnter={() => setDeletingID(index)} onMouseLeave={() => setDeletingID(null)} > - -
+
))} diff --git a/web/app/components/app/configuration/config-var/var-item.tsx b/web/app/components/app/configuration/config-var/var-item.tsx index 80c0bf6ac6..17568683d2 100644 --- a/web/app/components/app/configuration/config-var/var-item.tsx +++ b/web/app/components/app/configuration/config-var/var-item.tsx @@ -9,6 +9,7 @@ import { } from '@remixicon/react' import * as React from 'react' import { useState } from 'react' +import { useTranslation } from 'react-i18next' import Badge from '@/app/components/base/badge' import { BracketsX as VarIcon } from '@/app/components/base/icons/src/vender/line/development' import IconTypeIcon from './input-type-icon' @@ -36,6 +37,7 @@ const VarItem: FC = ({ onRemove, canDrag, }) => { + const { t } = useTranslation() const [isDeleting, setIsDeleting] = useState(false) return ( @@ -58,21 +60,24 @@ const VarItem: FC = ({
-
- -
- +
diff --git a/web/app/components/app/configuration/config/agent/agent-tools/__tests__/index.spec.tsx b/web/app/components/app/configuration/config/agent/agent-tools/__tests__/index.spec.tsx index d668737a0a..628e34bbe0 100644 --- a/web/app/components/app/configuration/config/agent/agent-tools/__tests__/index.spec.tsx +++ b/web/app/components/app/configuration/config/agent/agent-tools/__tests__/index.spec.tsx @@ -368,7 +368,7 @@ describe('AgentTools', () => { it('should remove tool when delete action is clicked', async () => { const { getModelConfig } = renderAgentTools() - const deleteButton = screen.getByTestId('delete-removed-tool') + const deleteButton = screen.getByRole('button', { name: /operation\.delete/i }) if (!deleteButton) throw new Error('Delete button not found') await userEvent.click(deleteButton) diff --git a/web/app/components/app/configuration/config/agent/agent-tools/index.tsx b/web/app/components/app/configuration/config/agent/agent-tools/index.tsx index 3242bcdcf8..8ad9ad1f8f 100644 --- a/web/app/components/app/configuration/config/agent/agent-tools/index.tsx +++ b/web/app/components/app/configuration/config/agent/agent-tools/index.tsx @@ -96,6 +96,7 @@ const AgentTools: FC = () => { } const [isDeleting, setIsDeleting] = useState(-1) + const getDeleteToolLabel = (tool: AgentTool) => `${t('operation.delete', { ns: 'common' })} ${tool.tool_label || tool.tool_name}` const getToolValue = (tool: ToolDefaultValue) => { const currToolInCollections = collectionList.find(c => c.id === tool.provider_id) const currToolWithConfigs = currToolInCollections?.tools.find(t => t.name === tool.tool_name) @@ -249,7 +250,7 @@ const AgentTools: FC = () => {
{t('toolNameUsageTip', { ns: 'tools' })}
)} {!item.isDeleted && !readonly && ( @@ -320,8 +323,10 @@ const AgentTools: FC = () => { )} -
{ const newModelConfig = produce(modelConfig, (draft) => { draft.agentConfig.tools.splice(index, 1) @@ -331,10 +336,9 @@ const AgentTools: FC = () => { }} onMouseOver={() => setIsDeleting(index)} onMouseLeave={() => setIsDeleting(-1)} - data-testid="delete-removed-tool" > - -
+