Dify Frontend Testing

Generate Vitest + React Testing Library tests for Dify frontend components, hooks, and utilities.

You say
Install this skill Read the source first Free Written by langgenius · unverified publisher
Context cost
20.2k tokensestimated from the bundle, loaded when it triggers
Bundle
9 files · 80.9 kB2 scripts among them — read before you run
Licence
Source-availablefree to use
Last change
no release on file
Servers it uses
Noneruns standalone

What it does

Generate Vitest + React Testing Library tests for Dify frontend components, hooks, and utilities. Triggers on testing, spec files, coverage, Vitest, RTL, unit tests, integration tests, or write/review test requests.

Installed, it changes the agent in these ways.

What this skill changes about the agent is not written down here yet. The listing was collected from its source, and the description is in its own SKILL.md.

Guardrail

Constrains what the agent is allowed to do.

securitytestingreactvitest

The skill itself

This is the whole product. A skill is instructions the model reads, so there is nothing behind the listing you cannot see first — the front matter loads with every session, and the body below it loads when the skill triggers.

SKILL.md10.2 kB · 323 lines
--- name: frontend-testing description: Generate Vitest + React Testing Library tests for Dify frontend components, hooks, and utilities. Triggers on testing, spec files, coverage, Vitest, RTL, unit tests, integration tests, or write/review test requests. ---
6# Dify Frontend Testing Skill
7
8This skill enables Claude to generate high-quality, comprehensive frontend tests for the Dify project following established conventions and best practices.
9
10> **⚠️ Authoritative Source**: This skill is derived from web/testing/testing.md. Use Vitest mock/timer APIs (vi.*).
11
12## When to Apply This Skill
13
14Apply this skill when the user:
15
16- Asks to **write tests** for a component, hook, or utility
17- Asks to **review existing tests** for completeness
18- Mentions **Vitest**, **React Testing Library**, **RTL**, or **spec files**
19- Requests **test coverage** improvement
20- Uses pnpm analyze-component output as context
21- Mentions **testing**, **unit tests**, or **integration tests** for frontend code
22- Wants to understand **testing patterns** in the Dify codebase
23
24**Do NOT apply** when:
25
26- User is asking about backend/API tests (Python/pytest)
27- User is asking about E2E tests (Playwright/Cypress)
28- User is only asking conceptual questions without code context
29
30## Quick Reference
31
32### Tech Stack
33
34| Tool | Version | Purpose |
35|------|---------|---------|
36| Vitest | 4.0.16 | Test runner |
37| React Testing Library | 16.0 | Component testing |
38| jsdom | - | Test environment |
39| nock | 14.0 | HTTP mocking |
40| TypeScript | 5.x | Type safety |
41
42### Key Commands
43
44```bash
45# Run all tests
46pnpm test
47
48# Watch mode
49pnpm test:watch
50
51# Run specific file
52pnpm test path/to/file.spec.tsx
53
54# Generate coverage report
55pnpm test:coverage
56
57# Analyze component complexity
58pnpm analyze-component <path>
59
60# Review existing test
61pnpm analyze-component <path> --review
62```
63
64### File Naming
65
66- Test files: ComponentName.spec.tsx (same directory as component)
67- Integration tests: web/__tests__/ directory
68
69## Test Structure Template
70
71```typescript
72import { render, screen, fireEvent, waitFor } from '@testing-library/react'
73import Component from './index'
74
75// ✅ Import real project components (DO NOT mock these)
76// import Loading from '@/app/components/base/loading'
77// import { ChildComponent } from './child-component'
78
79// ✅ Mock external dependencies only
80vi.mock('@/service/api')
81vi.mock('next/navigation', () => ({
82 useRouter: () => ({ push: vi.fn() }),
83 usePathname: () => '/test',
84}))
85
86// Shared state for mocks (if needed)
87let mockSharedState = false
88
89describe('ComponentName', () => {
90 beforeEach(() => {
91 vi.clearAllMocks() // ✅ Reset mocks BEFORE each test
92 mockSharedState = false // ✅ Reset shared state
93 })
94
95 // Rendering tests (REQUIRED)
96 describe('Rendering', () => {
97 it('should render without crashing', () => {
98 // Arrange
99 const props = { title: 'Test' }
100
101 // Act
102 render(<Component {...props} />)
103
104 // Assert
105 expect(screen.getByText('Test')).toBeInTheDocument()
106 })
107 })
108
109 // Props tests (REQUIRED)
110 describe('Props', () => {
111 it('should apply custom className', () => {
112 render(<Component className="custom" />)
113 expect(screen.getByRole('button')).toHaveClass('custom')
114 })
115 })
116
117 // User Interactions
118 describe('User Interactions', () => {
119 it('should handle click events', () => {
120 const handleClick = vi.fn()
121 render(<Component onClick={handleClick} />)
122
123 fireEvent.click(screen.getByRole('button'))
124
125 expect(handleClick).toHaveBeenCalledTimes(1)
126 })
127 })
128
129 // Edge Cases (REQUIRED)
130 describe('Edge Cases', () => {
131 it('should handle null data', () => {
132 render(<Component data={null} />)
133 expect(screen.getByText(/no data/i)).toBeInTheDocument()
134 })
135
136 it('should handle empty array', () => {
137 render(<Component items={[]} />)
138 expect(screen.getByText(/empty/i)).toBeInTheDocument()
139 })
140 })
141})
142```
143
144## Testing Workflow (CRITICAL)
145
146### ⚠️ Incremental Approach Required
147
148**NEVER generate all test files at once.** For complex components or multi-file directories:
149
1501. **Analyze & Plan**: List all files, order by complexity (simple → complex)
1511. **Process ONE at a time**: Write test → Run test → Fix if needed → Next
1521. **Verify before proceeding**: Do NOT continue to next file until current passes
153
154```
155For each file:
156 ┌────────────────────────────────────────┐
157 │ 1. Write test │
158 │ 2. Run: pnpm test <file>.spec.tsx │
159 │ 3. PASS? → Mark complete, next file │
160 │ FAIL? → Fix first, then continue │
161 └────────────────────────────────────────┘
162```
163
164### Complexity-Based Order
165
166Process in this order for multi-file testing:
167
1681. 🟢 Utility functions (simplest)
1691. 🟢 Custom hooks
1701. 🟡 Simple components (presentational)
1711. 🟡 Medium components (state, effects)
1721. 🔴 Complex components (API, routing)
1731. 🔴 Integration tests (index files - last)
174
175### When to Refactor First
176
177- **Complexity > 50**: Break into smaller pieces before testing
178- **500+ lines**: Consider splitting before testing
179- **Many dependencies**: Extract logic into hooks first
180
181> 📖 See references/workflow.md for complete workflow details and todo list format.
182
183## Testing Strategy
184
185### Path-Level Testing (Directory Testing)
186
187When assigned to test a directory/path, test **ALL content** within that path:
188
189- Test all components, hooks, utilities in the directory (not just index file)
190- Use incremental approach: one file at a time, verify each before proceeding
191- Goal: 100% coverage of ALL files in the directory
192
193### Integration Testing First
194
195**Prefer integration testing** when writing tests for a directory:
196
197- ✅ **Import real project components** directly (including base components and siblings)
198- ✅ **Only mock**: API services (@/service/*), next/navigation, complex context providers
199- ❌ **DO NOT mock** base components (@/app/components/base/*)
200- ❌ **DO NOT mock** sibling/child components in the same directory
201
202> See [Test Structure Template](#test-structure-template) for correct import/mock patterns.
203
204## Core Principles
205
206### 1. AAA Pattern (Arrange-Act-Assert)
207
208Every test should clearly separate:
209
210- **Arrange**: Setup test data and render component
211- **Act**: Perform user actions
212- **Assert**: Verify expected outcomes
213
214### 2. Black-Box Testing
215
216- Test observable behavior, not implementation details
217- Use semantic queries (getByRole, getByLabelText)
218- Avoid testing internal state directly
219- **Prefer pattern matching over hardcoded strings** in assertions:
220
221```typescript
222// ❌ Avoid: hardcoded text assertions
223expect(screen.getByText('Loading...')).toBeInTheDocument()
224
225// ✅ Better: role-based queries
226expect(screen.getByRole('status')).toBeInTheDocument()
227
228// ✅ Better: pattern matching
229expect(screen.getByText(/loading/i)).toBeInTheDocument()
230```
231
232### 3. Single Behavior Per Test
233
234Each test verifies ONE user-observable behavior:
235
236```typescript
237// ✅ Good: One behavior
238it('should disable button when loading', () => {
239 render(<Button loading />)
240 expect(screen.getByRole('button')).toBeDisabled()
241})
242
243// ❌ Bad: Multiple behaviors
244it('should handle loading state', () => {
245 render(<Button loading />)
246 expect(screen.getByRole('button')).toBeDisabled()
247 expect(screen.getByText('Loading...')).toBeInTheDocument()
248 expect(screen.getByRole('button')).toHaveClass('loading')
249})
250```
251
252### 4. Semantic Naming
253
254Use should <behavior> when <condition>:
255
256```typescript
257it('should show error message when validation fails')
258it('should call onSubmit when form is valid')
259it('should disable input when isReadOnly is true')
260```
261
262## Required Test Scenarios
263
264### Always Required (All Components)
265
2661. **Rendering**: Component renders without crashing
2671. **Props**: Required props, optional props, default values
2681. **Edge Cases**: null, undefined, empty values, boundary conditions
269
270### Conditional (When Present)
271
272| Feature | Test Focus |
273|---------|-----------|
274| useState | Initial state, transitions, cleanup |
275| useEffect | Execution, dependencies, cleanup |
276| Event handlers | All onClick, onChange, onSubmit, keyboard |
277| API calls | Loading, success, error states |
278| Routing | Navigation, params, query strings |
279| useCallback/useMemo | Referential equality |
280| Context | Provider values, consumer behavior |
281| Forms | Validation, submission, error display |
282
283## Coverage Goals (Per File)
284
285For each test file generated, aim for:
286
287- ✅ **100%** function coverage
288- ✅ **100%** statement coverage
289- ✅ **>95%** branch coverage
290- ✅ **>95%** line coverage
291
292> **Note**: For multi-file directories, process one file at a time with full coverage each. See references/workflow.md.
293
294## Detailed Guides
295
296For more detailed information, refer to:
297
298- references/workflow.md - **Incremental testing workflow** (MUST READ for multi-file testing)
299- references/mocking.md - Mock patterns and best practices
300- references/async-testing.md - Async operations and API calls
301- references/domain-components.md - Workflow, Dataset, Configuration testing
302- references/common-patterns.md - Frequently used testing patterns
303- references/checklist.md - Test generation checklist and validation steps
304
305## Authoritative References
306
307### Primary Specification (MUST follow)
308
309- **web/testing/testing.md** - The canonical testing specification. This skill is derived from this document.
310
311### Reference Examples in Codebase
312
313- web/utils/classnames.spec.ts - Utility function tests
314- web/app/components/base/button/index.spec.tsx - Component tests
315- web/__mocks__/provider-context.ts - Mock factory example
316
317### Project Configuration
318
319- web/vitest.config.ts - Vitest configuration
320- web/vitest.setup.ts - Test environment setup
321- web/scripts/analyze-component.js - Component analysis tool
322- Modules are not mocked automatically. Global mocks live in web/vitest.setup.ts (for example react-i18next, next/image); mock other modules like ky or mime locally in test files.
323
In the file
SKILL.md1,290 words
Files9
LicenceSource-available
Why you can read it

Nothing in a skill executes. The client loads the text and the model follows it, so a skill can be audited the way a runbook is — by reading it.

What it costs in context

Skills are not billed by the call. They are paid for in context: every token the instructions occupy is a token your code, your diff and your conversation cannot use. Here is what this one takes and when it takes it.

≈60
always loaded
The name and description, so the model knows the skill exists and when to reach for it.
20,165
on trigger
The instruction body and 8 supporting files, read only when the skill fires.
10.1%
of a 200k window
Ten skills this size would take about 101% of the window before you open a file.
050k100k150k200k context window

20.2k tokens, estimated from the bundle at four bytes to the token, held for the rest of the session once it triggers. Heavy. Teams tend to install this one per project rather than globally, and load it only when the job comes up.

Servers bill, skills cost

A server charges by the month. A skill charges once per session, in context, and then keeps charging it for as long as the session lives.

Before and after

The same question, put to the same model twice: once as it comes, and once with these instructions loaded.

No worked example has been published for this skill yet.

Adoption
Installsnone yet
Ratingno reviews yet

The procedure it runs

The procedure has not been published here. It is in the skill’s own SKILL.md, which its author has not sent to the marketplace yet.

Prose, not code

These steps are written for a model to follow, not executed by a runtime. It can still be told to skip one, and it will say so when it does.

Servers it uses

None. This skill calls no MCP servers at all.

Everything it needs is in the instructions, so it works in a project with nothing connected — the model reads the file and changes how it works with what it can already reach.

It writes no files and reaches no network. All it changes is how the model reasons and writes.

What it asks for
Writes filesno
Network accessno

Read from the allowed-tools line of this skill’s own SKILL.md. A skill grants no permissions of its own — it can only ask for tools your client already has.

What it will not do

Every skill is narrow, and the useful ones say where they stop. These are the jobs this one is the wrong tool for.

What this skill is not for has not been published here. Nothing is implied by that: it is a section the author has not filled in.

What is in the bundle

9 files, 80.9 kB on disk. Mostly text — the instructions the model reads — with 2 scripts in it that your client would run only if the instructions tell it to.

  • SKILL.md10.2 kB
  • assets/hook-test.template.ts6.8 kB
  • assets/utility-test.template.ts5.1 kB
  • references/async-testing.md8.5 kB
  • references/checklist.md5.9 kB
  • references/common-patterns.md11.7 kB
  • references/domain-components.md15.3 kB
  • references/mocking.md9.4 kB
  • references/workflow.md8.0 kB
What is not in it

A skill installs nothing and depends on nothing: it is a folder your client reads. This one carries 2 scripts beside the text, so the bundle is 9 files you can review in full before installing. The Source-available licence covers the templates and examples as well as the instructions.

Install

Installing copies the bundle into your project. Nothing runs at install time — the files sit on disk until the model reads them.

# Dify Frontend Testing · 20.2k tokens when loaded npx mcprush@latest skill add langgenius/dify-frontend-testing

Writes to .claude/skills/dify-frontend-testing/ in the current project. Add --global to put it in your home directory instead, for every project.

Which clients pick it up on their own

A skill is a folder of text. A client with a skills folder reads it without being told; everywhere else the same text works, it is just handed to the model rather than found.

Claude Code.claude/skills/
Claude Desktop
ChatGPT
Cursor.cursor/skills/
VS Code.github/skills/
Codex CLI.agents/skills/
Gemini CLI.gemini/skills/
Grok.grok/skills/
Zed.agents/skills/
Windsurf.windsurf/skills/
Agent SDK.claude/skills/
HTTP / API
This release
Versionnot versioned
Publishedno release date on file
PriceFree
Referencelanggenius/dify-frontend-testing

Versions

Its author publishes no version number, so there is nothing here to pin to: what you install is the folder as it stands today. Instructions change more often than APIs do — a skill can be rewritten entirely without anything it depends on moving.

v
  • No earlier releases have been published to the marketplace.
Pinning

Nothing to pin to: this skill carries no version number of its own. What you install is what the folder holds on the day you install it.

Reviews

no reviews yet · no installs yet

Nobody has reviewed this skill yet. The rating is the mean of the reviews written here, so there is none until somebody writes the first.

Who can post

Only accounts that have had the skill installed for fourteen days, so a review is written after living with it rather than after reading it. Publishers may reply once.

Who wrote it

LA
langgenius

Publishes on mcprush.

0 servers listed1 skill listednot claimed
Profile
Publisher
Servers0
Claim this skill