mirror of
https://github.com/langgenius/dify.git
synced 2026-06-16 22:11:09 +08:00
test(dify-ui): add strict Storybook a11y checks (#37459)
This commit is contained in:
parent
1e8329f02c
commit
6c3857a4c8
25
.github/workflows/web-tests.yml
vendored
25
.github/workflows/web-tests.yml
vendored
@ -113,7 +113,7 @@ jobs:
|
||||
run: vp exec playwright install --with-deps chromium
|
||||
|
||||
- name: Run dify-ui tests
|
||||
run: vp test run --coverage --silent=passed-only
|
||||
run: vp test run --project unit --coverage --silent=passed-only
|
||||
|
||||
- name: Report coverage
|
||||
if: ${{ env.CODECOV_TOKEN != '' }}
|
||||
@ -123,3 +123,26 @@ jobs:
|
||||
flags: dify-ui
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ env.CODECOV_TOKEN }}
|
||||
|
||||
dify-ui-storybook-test:
|
||||
name: dify-ui Storybook Tests
|
||||
runs-on: depot-ubuntu-24.04-4
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: ./packages/dify-ui
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup web environment
|
||||
uses: ./.github/actions/setup-web
|
||||
|
||||
- name: Install Chromium for Browser Mode
|
||||
run: vp exec playwright install --with-deps chromium
|
||||
|
||||
- name: Run dify-ui Storybook tests
|
||||
run: vp run test:storybook
|
||||
|
||||
@ -8,6 +8,8 @@ const config: StorybookConfig = {
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-docs',
|
||||
'@storybook/addon-themes',
|
||||
'@storybook/addon-a11y',
|
||||
'@storybook/addon-vitest',
|
||||
'@chromatic-com/storybook',
|
||||
],
|
||||
framework: '@storybook/react-vite',
|
||||
|
||||
@ -24,6 +24,9 @@ const preview: Preview = {
|
||||
docs: {
|
||||
toc: true,
|
||||
},
|
||||
a11y: {
|
||||
test: 'error',
|
||||
},
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
}
|
||||
|
||||
@ -157,8 +157,9 @@
|
||||
"scripts": {
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"storybook:build": "storybook build",
|
||||
"test": "vp test",
|
||||
"test:watch": "vp test --watch",
|
||||
"test": "vp test --project unit",
|
||||
"test:storybook": "vp test --project storybook --run",
|
||||
"test:watch": "vp test --project unit --watch",
|
||||
"type-check": "tsgo"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@ -178,9 +179,11 @@
|
||||
"@dify/tsconfig": "workspace:*",
|
||||
"@egoist/tailwindcss-icons": "catalog:",
|
||||
"@iconify-json/ri": "catalog:",
|
||||
"@storybook/addon-a11y": "catalog:",
|
||||
"@storybook/addon-docs": "catalog:",
|
||||
"@storybook/addon-links": "catalog:",
|
||||
"@storybook/addon-themes": "catalog:",
|
||||
"@storybook/addon-vitest": "catalog:",
|
||||
"@storybook/react-vite": "catalog:",
|
||||
"@tailwindcss/vite": "catalog:",
|
||||
"@tanstack/react-hotkeys": "catalog:",
|
||||
|
||||
@ -297,8 +297,9 @@ const CommandPaletteList = () => {
|
||||
<AutocompleteList className="max-h-72 rounded-lg border border-divider-subtle bg-components-panel-bg p-1 shadow-xs">
|
||||
{groups.map((group, groupIndex) => (
|
||||
<AutocompleteGroup key={group.label} items={group.items}>
|
||||
{groupIndex > 0 && <AutocompleteSeparator />}
|
||||
<AutocompleteGroupLabel>{group.label}</AutocompleteGroupLabel>
|
||||
<AutocompleteGroupLabel className={groupIndex > 0 ? 'mt-1 border-t border-divider-subtle pt-2' : undefined}>
|
||||
{group.label}
|
||||
</AutocompleteGroupLabel>
|
||||
<AutocompleteCollection>
|
||||
{(item: Suggestion) => (
|
||||
<AutocompleteItem key={item.value} value={item} className="grid grid-cols-[1fr_auto]">
|
||||
@ -691,7 +692,7 @@ export const CommandPalette: Story = {
|
||||
>
|
||||
<AutocompleteInputGroup className="mb-2">
|
||||
<span className="i-ri-search-line ml-2 size-4 shrink-0 text-text-tertiary" aria-hidden="true" />
|
||||
<AutocompleteInput placeholder="Run a command…" aria-label="Run a command" />
|
||||
<AutocompleteInput placeholder="Run a command…" aria-label="Run a command" aria-expanded="true" />
|
||||
<AutocompleteClear />
|
||||
</AutocompleteInputGroup>
|
||||
<CommandPaletteList />
|
||||
|
||||
@ -141,6 +141,7 @@ export const AsLink: Story = {
|
||||
args: {
|
||||
variant: 'ghost-accent',
|
||||
render: <a href="https://example.com" />,
|
||||
nativeButton: false,
|
||||
children: 'Link Button',
|
||||
},
|
||||
}
|
||||
|
||||
@ -207,6 +207,11 @@ export const States: Story = {
|
||||
</FieldRoot>
|
||||
</div>
|
||||
),
|
||||
parameters: {
|
||||
a11y: {
|
||||
test: 'todo',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
function ControlledDemo() {
|
||||
|
||||
@ -9,10 +9,12 @@ function PaginationExample({
|
||||
initialPage = 2,
|
||||
initialPageSize = 25,
|
||||
totalPages = 200,
|
||||
label = 'Pagination',
|
||||
}: {
|
||||
initialPage?: number
|
||||
initialPageSize?: number
|
||||
totalPages?: number
|
||||
label?: string
|
||||
}) {
|
||||
const [page, setPage] = React.useState(initialPage)
|
||||
const [pageSize, setPageSize] = React.useState(initialPageSize)
|
||||
@ -21,6 +23,7 @@ function PaginationExample({
|
||||
<Pagination
|
||||
page={page}
|
||||
totalPages={totalPages}
|
||||
aria-label={label}
|
||||
onPageChange={setPage}
|
||||
pageSize={{
|
||||
value: pageSize,
|
||||
@ -42,10 +45,10 @@ function PaginationDemo(props: React.ComponentProps<typeof PaginationExample>) {
|
||||
function DesignSpecDemo() {
|
||||
return (
|
||||
<div className="flex w-236 max-w-full flex-col gap-6 bg-components-panel-bg px-16 py-10">
|
||||
<PaginationExample />
|
||||
<PaginationExample initialPage={2} initialPageSize={25} />
|
||||
<PaginationExample initialPage={2} initialPageSize={25} />
|
||||
<PaginationExample initialPage={2} initialPageSize={25} />
|
||||
<PaginationExample label="Default pagination" />
|
||||
<PaginationExample label="Hover pagination" initialPage={2} initialPageSize={25} />
|
||||
<PaginationExample label="Focused pagination" initialPage={2} initialPageSize={25} />
|
||||
<PaginationExample label="Page size pagination" initialPage={2} initialPageSize={25} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -74,11 +77,19 @@ type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Playground: Story = {
|
||||
render: () => <PaginationDemo />,
|
||||
parameters: {
|
||||
a11y: {
|
||||
test: 'todo',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const DesignSpec: Story = {
|
||||
render: () => <DesignSpecDemo />,
|
||||
parameters: {
|
||||
a11y: {
|
||||
test: 'todo',
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story: 'Pagination rows with default, hover-like, focused, page-size, and skeleton examples.',
|
||||
|
||||
@ -127,9 +127,9 @@ export const Infotip: Story = {
|
||||
closeDelay={200}
|
||||
aria-label="Set which resource to use first when running models."
|
||||
render={(
|
||||
<span className="inline-flex h-4 w-4 shrink-0 items-center justify-center">
|
||||
<button type="button" className="inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-sm outline-hidden focus-visible:ring-2 focus-visible:ring-state-accent-solid">
|
||||
<span aria-hidden className="i-ri-question-line h-3.5 w-3.5 text-text-quaternary hover:text-text-tertiary" />
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
/>
|
||||
<PopoverContent
|
||||
|
||||
@ -113,6 +113,9 @@ export const DesignSpec: Story = {
|
||||
</div>
|
||||
),
|
||||
parameters: {
|
||||
a11y: {
|
||||
test: 'todo',
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story: 'Figma node 2473:9851: segmented control examples with text+icon and icon-only rows, with and without outer padding.',
|
||||
@ -168,6 +171,9 @@ export const DataAttributeStates: Story = {
|
||||
</div>
|
||||
),
|
||||
parameters: {
|
||||
a11y: {
|
||||
test: 'todo',
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story: '`SegmentedControlItem` gets `data-pressed` and `data-disabled` from Base UI Toggle. Accent, neutral, and multiple-selection examples are composed through props and className.',
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { defineConfig } from 'vite-plus'
|
||||
import { playwright } from 'vite-plus/test/browser-playwright'
|
||||
|
||||
const isCI = !!process.env.CI
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
@ -16,25 +13,4 @@ export default defineConfig({
|
||||
'@base-ui/react/use-render',
|
||||
],
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
setupFiles: ['./vitest.setup.ts'],
|
||||
browser: {
|
||||
enabled: true,
|
||||
provider: playwright(),
|
||||
instances: [{ browser: 'chromium' }],
|
||||
headless: true,
|
||||
},
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
include: ['src/**/*.{ts,tsx}'],
|
||||
exclude: [
|
||||
'src/**/*.stories.{ts,tsx}',
|
||||
'src/**/__tests__/**',
|
||||
'src/themes/**',
|
||||
'src/styles/**',
|
||||
],
|
||||
reporter: isCI ? ['json', 'json-summary'] : ['text', 'json', 'json-summary'],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
71
packages/dify-ui/vitest.config.ts
Normal file
71
packages/dify-ui/vitest.config.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { defineConfig } from 'vite-plus'
|
||||
import { playwright } from 'vite-plus/test/browser-playwright'
|
||||
|
||||
const dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const configDir = path.join(dirname, '.storybook')
|
||||
const isCI = !!process.env.CI
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
tsconfigPaths: true,
|
||||
},
|
||||
optimizeDeps: {
|
||||
include: [
|
||||
'@base-ui/react/form',
|
||||
'@base-ui/react/merge-props',
|
||||
'@base-ui/react/use-render',
|
||||
],
|
||||
},
|
||||
test: {
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
include: ['src/**/*.{ts,tsx}'],
|
||||
exclude: [
|
||||
'src/**/*.stories.{ts,tsx}',
|
||||
'src/**/__tests__/**',
|
||||
'src/themes/**',
|
||||
'src/styles/**',
|
||||
],
|
||||
reporter: isCI ? ['json', 'json-summary'] : ['text', 'json', 'json-summary'],
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
extends: true,
|
||||
test: {
|
||||
name: 'unit',
|
||||
globals: true,
|
||||
setupFiles: ['./vitest.setup.ts'],
|
||||
include: ['src/**/__tests__/**/*.spec.{ts,tsx}'],
|
||||
browser: {
|
||||
enabled: true,
|
||||
provider: playwright(),
|
||||
instances: [{ browser: 'chromium' }],
|
||||
headless: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
extends: true,
|
||||
plugins: [
|
||||
storybookTest({
|
||||
configDir,
|
||||
}),
|
||||
],
|
||||
test: {
|
||||
name: 'storybook',
|
||||
browser: {
|
||||
enabled: true,
|
||||
provider: playwright(),
|
||||
instances: [{ browser: 'chromium' }],
|
||||
headless: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
845
pnpm-lock.yaml
generated
845
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -85,10 +85,12 @@ catalog:
|
||||
'@remixicon/react': 4.9.0
|
||||
'@rgrove/parse-xml': 4.2.0
|
||||
'@sentry/react': 10.57.0
|
||||
'@storybook/addon-a11y': 10.4.4
|
||||
'@storybook/addon-docs': 10.4.4
|
||||
'@storybook/addon-links': 10.4.4
|
||||
'@storybook/addon-onboarding': 10.4.4
|
||||
'@storybook/addon-themes': 10.4.4
|
||||
'@storybook/addon-vitest': 10.4.4
|
||||
'@storybook/nextjs-vite': 10.4.4
|
||||
'@storybook/react': 10.4.4
|
||||
'@storybook/react-vite': 10.4.4
|
||||
|
||||
Loading…
Reference in New Issue
Block a user