mirror of
https://github.com/langgenius/dify.git
synced 2026-10-04 13:47:55 +08:00
chore: migrate workspace to Vitest 5 (#42782)
This commit is contained in:
57 files changed
+823
-1220
No files matched your search
@@ -0,0 +1 @@
|
||||
.vitest/
|
||||
@@ -49,7 +49,6 @@
|
||||
"js-yaml": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
"vite": "catalog:",
|
||||
"vite-plus": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
"vite-plus": "catalog:"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
.vitest/
|
||||
@@ -35,8 +35,7 @@
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native": "catalog:",
|
||||
"vite": "catalog:",
|
||||
"vite-plus": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
"vite-plus": "catalog:"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^24.20.0"
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
/.vitest-browser
|
||||
/dist
|
||||
/storybook-static
|
||||
.vitest/
|
||||
@@ -27,6 +27,9 @@ Use regular Vitest tests for Dify integration behavior that does not need a docu
|
||||
such as submitted values, store behavior, or a known regression reached through a public API.
|
||||
Prop passthrough alone does not justify a test. Assert the resulting behavior instead of CSS class
|
||||
names or private structure, and do not duplicate behavior already owned by Base UI or the browser.
|
||||
Vitest 5 browser locators match string names exactly by default. Assert a control's accessible name
|
||||
or description when that is the contract. `toHaveTextContent` also checks the full text exactly;
|
||||
use `toMatchTextContent` only when the complete text is intentionally outside the test's scope.
|
||||
|
||||
Storybook [accessibility testing] uses `a11y.test = 'error'`, so enabled violations fail the test.
|
||||
Color contrast is the only globally disabled rule because it is a known design-token gap. Do not
|
||||
|
||||
@@ -39,8 +39,9 @@ describe('Dialog wrapper', () => {
|
||||
</Dialog>,
|
||||
)
|
||||
|
||||
await expect.element(screen.getByRole('dialog')).toHaveTextContent('Dialog Title')
|
||||
await expect.element(screen.getByRole('dialog')).toHaveTextContent('Dialog Description')
|
||||
await expect
|
||||
.element(screen.getByRole('dialog', { name: 'Dialog Title' }))
|
||||
.toHaveAccessibleDescription('Dialog Description')
|
||||
})
|
||||
|
||||
it('should apply backdrop props to a nested dialog backdrop', async () => {
|
||||
|
||||
@@ -47,8 +47,10 @@ describe('Drawer wrapper', () => {
|
||||
const dialog = asHTMLElement(document.body.querySelector('[role="dialog"]')!)
|
||||
expect(document.body).toContainElement(dialog)
|
||||
expect(screen.container).not.toContainElement(dialog)
|
||||
await expect.element(dialog).toHaveTextContent('Workspace controls')
|
||||
await expect.element(screen.getByText('Configure the current workspace.')).toBeInTheDocument()
|
||||
await expect
|
||||
.element(screen.getByRole('dialog', { name: 'Settings' }))
|
||||
.toHaveAccessibleDescription('Configure the current workspace.')
|
||||
await expect.element(screen.getByText('Workspace controls')).toBeInTheDocument()
|
||||
await expect.element(screen.getByTestId('drawer-backdrop')).toBeInTheDocument()
|
||||
|
||||
await screen.getByRole('button', { name: 'Close drawer' }).click()
|
||||
|
||||
@@ -13,10 +13,6 @@ function useFileTreeLevel() {
|
||||
return React.useContext(FileTreeLevelContext)
|
||||
}
|
||||
|
||||
function getLabelText(children: React.ReactNode) {
|
||||
return typeof children === 'string' || typeof children === 'number' ? String(children) : undefined
|
||||
}
|
||||
|
||||
function renderGuides(level: number) {
|
||||
return Array.from({ length: Math.max(level - 1, 0) }, (_, index) => <FileTreeGuide key={index} />)
|
||||
}
|
||||
@@ -258,23 +254,16 @@ function FileTreeIcon({ type = 'file', render, className, children, ...props }:
|
||||
}
|
||||
|
||||
type FileTreeLabelProps = useRender.ComponentProps<'span'>
|
||||
type FileTreeLabelElementProps = useRender.ElementProps<'span'> & {
|
||||
'data-label'?: string
|
||||
}
|
||||
|
||||
function FileTreeLabel({ render, className, children, ...props }: FileTreeLabelProps) {
|
||||
const labelText = getLabelText(children)
|
||||
const defaultProps = {
|
||||
'data-label': labelText,
|
||||
className: cn(
|
||||
'w-0 min-w-0 flex-1 truncate rounded-[5px] px-1 py-0.5',
|
||||
labelText &&
|
||||
'after:invisible after:block after:h-0 after:overflow-hidden after:system-sm-medium after:content-[attr(data-label)]',
|
||||
'system-sm-regular text-text-secondary group-data-selected/file-tree-row:system-sm-medium group-data-selected/file-tree-row:text-text-primary',
|
||||
className,
|
||||
),
|
||||
children,
|
||||
} satisfies FileTreeLabelElementProps
|
||||
} satisfies useRender.ElementProps<'span'>
|
||||
|
||||
return useRender({
|
||||
defaultTagName: 'span',
|
||||
|
||||
@@ -95,8 +95,8 @@ describe('PopoverContent', () => {
|
||||
</Popover>,
|
||||
)
|
||||
|
||||
const popup = screen.getByRole('dialog', { name: 'default popover' })
|
||||
await expect.element(popup).toHaveTextContent('Default content')
|
||||
const popup = screen.getByRole('dialog', { name: 'Default popover' })
|
||||
await expect.element(screen.getByText('Default content')).toBeInTheDocument()
|
||||
const popupStyle = getComputedStyle(popup.element())
|
||||
expect(popupStyle.borderTopWidth).not.toBe('0px')
|
||||
expect(popupStyle.borderTopLeftRadius).not.toBe('0px')
|
||||
@@ -194,7 +194,7 @@ describe('Popover anatomy', () => {
|
||||
.element(screen.getByTestId('anatomy-positioner'))
|
||||
.toHaveAttribute('data-align', 'end')
|
||||
const popup = screen.getByRole('dialog', { name: 'Anatomy popover' })
|
||||
await expect.element(popup).toHaveTextContent('Anatomy content')
|
||||
await expect.element(popup).toHaveAccessibleDescription('Anatomy content')
|
||||
const popupStyle = getComputedStyle(popup.element())
|
||||
expect(popupStyle.borderTopWidth).toBe('0px')
|
||||
expect(popupStyle.borderTopLeftRadius).toBe('0px')
|
||||
|
||||
@@ -202,7 +202,7 @@ describe('@langgenius/dify-ui/toast', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('should dismiss an expanded background toast from its current row when swiped right', async () => {
|
||||
it('should dismiss an expanded background toast when swiped right', async () => {
|
||||
const baseUIAnimationGlobal = globalThis as BaseUIAnimationGlobal
|
||||
const animationState = baseUIAnimationGlobal.BASE_UI_ANIMATIONS_DISABLED
|
||||
baseUIAnimationGlobal.BASE_UI_ANIMATIONS_DISABLED = false
|
||||
@@ -238,11 +238,10 @@ describe('@langgenius/dify-ui/toast', () => {
|
||||
|
||||
const backgroundToast = screen.getByRole('dialog', { name: 'Background notification' })
|
||||
await expect.element(backgroundToast).toBeInTheDocument()
|
||||
await backgroundToast.hover()
|
||||
await screen.getByRole('dialog', { name: 'Front notification' }).hover()
|
||||
await expect.element(backgroundToast).toHaveAttribute('data-expanded')
|
||||
|
||||
const toastElement = backgroundToast.element()
|
||||
const bounds = toastElement.getBoundingClientRect()
|
||||
|
||||
await userEvent.dragAndDrop(toastElement, screen.getByLabelText('Swipe destination'), {
|
||||
steps: 10,
|
||||
@@ -250,10 +249,10 @@ describe('@langgenius/dify-ui/toast', () => {
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(toastElement).toHaveAttribute('data-ending-style')
|
||||
expect(toastElement).toHaveAttribute('data-swipe-direction', 'right')
|
||||
})
|
||||
expect(toastElement.getBoundingClientRect().top).toBeCloseTo(bounds.top, 0)
|
||||
} finally {
|
||||
await userEvent.unhover(document.body)
|
||||
} finally {
|
||||
baseUIAnimationGlobal.BASE_UI_ANIMATIONS_DISABLED = animationState
|
||||
}
|
||||
})
|
||||
|
||||
@@ -20,6 +20,7 @@ export default defineConfig({
|
||||
},
|
||||
test: {
|
||||
browser: {
|
||||
expect: { toMatchScreenshot: { screenshotDirectory: './.vitest-browser/screenshots' } },
|
||||
enabled: true,
|
||||
provider: playwright(),
|
||||
instances: [{ browser: 'chromium' }],
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
.vitest/
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { TestContext } from 'vitest'
|
||||
import type { TestContext } from 'vite-plus/test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { Buffer } from 'node:buffer'
|
||||
import { spawnSync } from 'node:child_process'
|
||||
@@ -10,7 +10,7 @@ import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { crc32, deflateSync, inflateSync } from 'node:zlib'
|
||||
import sharp from 'sharp'
|
||||
import { it, vi } from 'vitest'
|
||||
import { it, vi } from 'vite-plus/test'
|
||||
import {
|
||||
escapeAnnotation,
|
||||
exceedsThreshold,
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
"@types/picomatch": "catalog:",
|
||||
"@typescript/native": "catalog:",
|
||||
"vite": "catalog:",
|
||||
"vite-plus": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
"vite-plus": "catalog:"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^24.20.0"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { defineConfig } from 'vite-plus'
|
||||
|
||||
export default defineConfig({
|
||||
test: { environment: 'node', restoreMocks: true },
|
||||
test: {
|
||||
environment: 'node',
|
||||
restoreMocks: true,
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
.vitest/
|
||||
@@ -20,8 +20,7 @@
|
||||
"jotai": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
"vite": "catalog:",
|
||||
"vite-plus": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
"vite-plus": "catalog:"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tanstack/form-core": "catalog:",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
.vitest/
|
||||
@@ -32,8 +32,7 @@
|
||||
"react-dom": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
"vite": "catalog:",
|
||||
"vite-plus": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
"vite-plus": "catalog:"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"jotai": "catalog:",
|
||||
|
||||
Reference in new issue
Block a user