Token导航 LogoToken导航TokenDH.com
前端设计操作浏览器unknown未标认证来源可访问许可证需确认审计未展示

test-generator测试发生器

Agent Skill

用于辅助测试设计、自动化测试、用例整理和回归验证。它适合让 Agent 编写单元测试、端到端测试、测试计划或根据失败日志定位问题。使用时需要确认项目测试框架、运行命令和夹具数据,避免为了通过测试而改坏真实逻辑;涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境。

总安装

404

周安装

17

下载量

141
Local Agent

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:test-generator(测试发生器)
来源仓库:https://smithery.ai
仓库路径:test-generator
安装命令:
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。当前暂无明确安装命令,请以来源页面说明为准。

简介

test-generator 用于辅助测试设计、自动化测试和回归验证,适合在 Local Agent 中自动生成测试用例时使用。

  • 支持基于代码结构或接口定义生成基础测试桩。
  • 可用于提升测试覆盖率和减少重复劳动。
  • 使用前需确认是否修改生产代码或仅生成独立测试文件。
  • 建议核对生成的测试是否符合实际业务场景。

SKILL.md

Test Generator

Generates comprehensive tests for Ishkul's React Native frontend and Go backend.

Tech Stack

  • Frontend: Jest, React Testing Library, React Native Testing Library
  • Backend: Go testing, testify (assert/require)
  • E2E: Playwright (web), Maestro (mobile), Newman (API)

Frontend Test Generation

Test File Locations

frontend/src/
├── screens/__tests__/ScreenName.test.tsx
├── components/__tests__/ComponentName.test.tsx
├── hooks/__tests__/useHookName.test.ts
└── utils/__tests__/utilName.test.ts

Screen Test Template

Generate tests for screens with all states and transitions:

import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react-native';
import { ScreenName } from '../ScreenName';

// Mock dependencies
jest.mock('../../hooks/useTheme', () => ({
  useTheme: () => ({
    colors: {
      primary: '#0066FF',
      background: '#FFFFFF',
      text: '#1A1A1A',
      error: '#DC2626',
    },
  }),
}));

jest.mock('../../state/lessonStore', () => ({
  useLessonStore: jest.fn(),
}));

jest.mock('@react-navigation/native', () => ({
  useNavigation: () => ({
    navigate: jest.fn(),
    goBack: jest.fn(),
  }),
  useRoute: () => ({
    params: { id: 'test-id' },
  }),
}));

import { useLessonStore } from '../../state/lessonStore';

const mockUseLessonStore = useLessonStore as jest.MockedFunction<typeof useLessonStore>;

describe('ScreenName', () => {
  const defaultProps = {
    navigation: { navigate: jest.fn(), goBack: jest.fn() },
    route: { params: { id: 'test-id' } },
  };

  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('Loading State', () => {
    it('should display loading indicator when loading', () => {
      mockUseLessonStore.mockReturnValue({
        currentLesson: null,
        lessonLoading: true,
        error: null,
      });

      const { getByTestId, queryByText } = render(<ScreenName {...defaultProps} />);

      expect(getByTestId('loading-indicator')).toBeTruthy();
      expect(queryByText(/error/i)).toBeNull();
    });

    it('should not display content while loading', () => {
      mockUseLessonStore.mockReturnValue({
        currentLesson: null,
        lessonLoading: true,
        error: null,
      });

      const { queryByTestId } = render(<ScreenName {...defaultProps} />);

      expect(queryByTestId('content-container')).toBeNull();
    });
  });

  describe('Error State', () => {
    it('should display error message when error occurs', () => {
      mockUseLessonStore.mockReturnValue({
        currentLesson: null,
        lessonLoading: false,
        error: 'Failed to load lesson',
      });

      const { getByText } = render(<ScreenName {...defaultProps} />);

      expect(getByText(/failed to load/i)).toBeTruthy();
    });

    it('should display retry button on error', () => {
      mockUseLessonStore.mockReturnValue({
        currentLesson: null,
        lessonLoading: false,
        error: 'Network error',
      });

      const { getByText } = render(<ScreenName {...defaultProps} />);

      expect(getByText(/retry/i)).toBeTruthy();
    });

    it('should call refetch when retry pressed', () => {
      const mockFetch = jest.fn();
      mockUseLessonStore.mockReturnValue({
        currentLesson: null,
        lessonLoading: false,
        error: 'Error',
        fetchLesson: mockFetch,
      });

      const { getByText } = render(<ScreenName {...defaultProps} />);
      fireEvent.press(getByText(/retry/i));

      expect(mockFetch).toHaveBeenCalled();
    });
  });

  describe('Empty State', () => {
    it('should display empty message when no data', () => {
      mockUseLessonStore.mockReturnValue({
        currentLesson: null,
        lessonLoading: false,
        error: null,
      });

      const { getByText } = render(<ScreenName {...defaultProps} />);

      expect(getByText(/no lesson found/i)).toBeTruthy();
    });
  });

  describe('Success State', () => {
    const mockLesson = {
      id: 'lesson-1',
      title: 'Test Lesson',
      blocks: [{ id: 'block-1', type: 'text', title: 'Block 1' }],
    };

    it('should display lesson content when loaded', () => {
      mockUseLessonStore.mockReturnValue({
        currentLesson: mockLesson,
        lessonLoading: false,
        error: null,
      });

      const { getByText } = render(<ScreenName {...defaultProps} />);

      expect(getByText('Test Lesson')).toBeTruthy();
    });

    it('should display all blocks', () => {
      mockUseLessonStore.mockReturnValue({
        currentLesson: mockLesson,
        lessonLoading: false,
        error: null,
      });

      const { getByText } = render(<ScreenName {...defaultProps} />);

      expect(getByText('Block 1')).toBeTruthy();
    });
  });

  // CRITICAL: State Transition Tests (Prevents React Hooks Violations)
  describe('State Transitions (Rules of Hooks)', () => {
    it('should handle transition from loading to success without crashing', () => {
      // Start with loading state
      mockUseLessonStore.mockReturnValue({
        currentLesson: null,
        lessonLoading: true,
        error: null,
      });

      const { rerender, getByTestId, getByText } = render(<ScreenName {...defaultProps} />);

      // Verify loading state
      expect(getByTestId('loading-indicator')).toBeTruthy();

      // Transition to success state
      mockUseLessonStore.mockReturnValue({
        currentLesson: { id: '1', title: 'Loaded Lesson', blocks: [] },
        lessonLoading: false,
        error: null,
      });

      // Should NOT crash on rerender
      expect(() => rerender(<ScreenName {...defaultProps} />)).not.toThrow();

      // Verify success state
      expect(getByText('Loaded Lesson')).toBeTruthy();
    });

    it('should handle transition from loading to error without crashing', () => {
      mockUseLessonStore.mockReturnValue({
        currentLesson: null,
        lessonLoading: true,
        error: null,
      });

      const { rerender, getByTestId, getByText } = render(<ScreenName {...defaultProps} />);

      expect(getByTestId('loading-indicator')).toBeTruthy();

      // Transition to error state
      mockUseLessonStore.mockReturnValue({
        currentLesson: null,
        lessonLoading: false,
        error: 'Network error',
      });

      expect(() => rerender(<ScreenName {...defaultProps} />)).not.toThrow();
      expect(getByText(/network error/i)).toBeTruthy();
    });

    it('should handle transition from error to loading (retry)', () => {
      mockUseLessonStore.mockReturnValue({
        currentLesson: null,
        lessonLoading: false,
        error: 'Error',
      });

      const { rerender, getByText, getByTestId } = render(<ScreenName {...defaultProps} />);

      expect(getByText(/error/i)).toBeTruthy();

      // User triggers retry
      mockUseLessonStore.mockReturnValue({
        currentLesson: null,
        lessonLoading: true,
        error: null,
      });

      expect(() => rerender(<ScreenName {...defaultProps} />)).not.toThrow();
      expect(getByTestId('loading-indicator')).toBeTruthy();
    });

    it('should handle rapid state changes without crashing', async () => {
      const states = [
        { currentLesson: null, lessonLoading: true, error: null },
        { currentLesson: null, lessonLoading: false, error: 'Error' },
        { currentLesson: null, lessonLoading: true, error: null },
        { currentLesson: { id: '1', title: 'Lesson', blocks: [] }, lessonLoading: false, error: null },
      ];

      mockUseLessonStore.mockReturnValue(states[0]);
      const { rerender } = render(<ScreenName {...defaultProps} />);

      for (const state of states.slice(1)) {
        mockUseLessonStore.mockReturnValue(state);
        expect(() => rerender(<ScreenName {...defaultProps} />)).not.toThrow();
      }
    });
  });

  describe('User Interactions', () => {
    it('should navigate back when back button pressed', () => {
      const mockGoBack = jest.fn();
      const props = {
        ...defaultProps,
        navigation: { ...defaultProps.navigation, goBack: mockGoBack },
      };

      mockUseLessonStore.mockReturnValue({
        currentLesson: { id: '1', title: 'Lesson', blocks: [] },
        lessonLoading: false,
        error: null,
      });

      const { getByTestId } = render(<ScreenName {...props} />);
      fireEvent.press(getByTestId('back-button'));

      expect(mockGoBack).toHaveBeenCalled();
    });
  });
});

Component Test Template

import React from 'react';
import { render, fireEvent } from '@testing-library/react-native';
import { Button } from '../Button';

jest.mock('../../hooks/useTheme', () => ({
  useTheme: () => ({
    colors: { primary: '#0066FF', text: '#1A1A1A' },
  }),
}));

describe('Button', () => {
  describe('Rendering', () => {
    it('should render with title', () => {
      const { getByText } = render(<Button title="Click me" onPress={() => {}} />);
      expect(getByText('Click me')).toBeTruthy();
    });

    it('should render loading indicator when loading', () => {
      const { queryByText, getByTestId } = render(
        <Button title="Submit" onPress={() => {}} loading />
      );
      expect(queryByText('Submit')).toBeNull();
      expect(getByTestId('loading-indicator')).toBeTruthy();
    });
  });

  describe('Variants', () => {
    const variants = ['primary', 'secondary', 'outline', 'ghost', 'danger'] as const;

    variants.forEach((variant) => {
      it(`should render ${variant} variant`, () => {
        const { getByText } = render(
          <Button title={variant} onPress={() => {}} variant={variant} />
        );
        expect(getByText(variant)).toBeTruthy();
      });
    });
  });

  describe('Sizes', () => {
    const sizes = ['small', 'medium', 'large'] as const;

    sizes.forEach((size) => {
      it(`should render ${size} size`, () => {
        const { getByText } = render(
          <Button title={size} onPress={() => {}} size={size} />
        );
        expect(getByText(size)).toBeTruthy();
      });
    });
  });

  describe('Interactions', () => {
    it('should call onPress when pressed', () => {
      const onPressMock = jest.fn();
      const { getByText } = render(<Button title="Press me" onPress={onPressMock} />);

      fireEvent.press(getByText('Press me'));

      expect(onPressMock).toHaveBeenCalledTimes(1);
    });

    it('should not call onPress when disabled', () => {
      const onPressMock = jest.fn();
      const { getByText } = render(
        <Button title="Disabled" onPress={onPressMock} disabled />
      );

      fireEvent.press(getByText('Disabled'));

      expect(onPressMock).not.toHaveBeenCalled();
    });

    it('should not call onPress when loading', () => {
      const onPressMock = jest.fn();
      const { getByTestId } = render(
        <Button title="Loading" onPress={onPressMock} loading />
      );

      fireEvent.press(getByTestId('loading-indicator'));

      expect(onPressMock).not.toHaveBeenCalled();
    });
  });

  describe('Edge Cases', () => {
    it('should handle empty title', () => {
      const { container } = render(<Button title="" onPress={() => {}} />);
      expect(container).toBeTruthy();
    });

    it('should handle very long title', () => {
      const longTitle = 'A'.repeat(100);
      const { getByText } = render(<Button title={longTitle} onPress={() => {}} />);
      expect(getByText(longTitle)).toBeTruthy();
    });
  });
});

Backend Test Generation

Test File Location

backend/internal/handlers/handler_name_test.go

Handler Test Template

package handlers

import (
    "bytes"
    "context"
    "encoding/json"
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/mesbahtanvir/ishkul/backend/internal/middleware"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/require"
)

// Helper to create authenticated request
func createRequest(method, path string, body interface{}, userID, email string) *http.Request {
    var req *http.Request

    if body != nil {
        bodyBytes, _ := json.Marshal(body)
        req = httptest.NewRequest(method, path, bytes.NewBuffer(bodyBytes))
        req.Header.Set("Content-Type", "application/json")
    } else {
        req = httptest.NewRequest(method, path, nil)
    }

    if userID != "" {
        ctx := context.WithValue(req.Context(), middleware.UserIDKey, userID)
        ctx = context.WithValue(ctx, middleware.UserEmailKey, email)
        req = req.WithContext(ctx)
    }

    return req
}

func TestHandlerName(t *testing.T) {
    t.Run("Method Validation", func(t *testing.T) {
        unsupportedMethods := []string{http.MethodGet, http.MethodPut, http.MethodDelete}

        for _, method := range unsupportedMethods {
            t.Run(method+" should be rejected", func(t *testing.T) {
                req := createRequest(method, "/api/resource", nil, "user123", "test@example.com")
                rr := httptest.NewRecorder()

                HandlerName(rr, req)

                assert.Equal(t, http.StatusMethodNotAllowed, rr.Code)
            })
        }
    })

    t.Run("Authentication", func(t *testing.T) {
        t.Run("should reject unauthenticated request", func(t *testing.T) {
            req := createRequest(http.MethodPost, "/api/resource", nil, "", "")
            rr := httptest.NewRecorder()

            HandlerName(rr, req)

            assert.Equal(t, http.StatusUnauthorized, rr.Code)
        })
    })

    t.Run("Input Validation", func(t *testing.T) {
        t.Run("should reject empty body", func(t *testing.T) {
            req := httptest.NewRequest(http.MethodPost, "/api/resource", nil)
            ctx := context.WithValue(req.Context(), middleware.UserIDKey, "user123")
            req = req.WithContext(ctx)
            rr := httptest.NewRecorder()

            HandlerName(rr, req)

            assert.Equal(t, http.StatusBadRequest, rr.Code)

            var response ErrorResponse
            json.Unmarshal(rr.Body.Bytes(), &response)
            assert.Equal(t, ErrCodeInvalidRequest, response.Code)
        })

        t.Run("should reject invalid JSON", func(t *testing.T) {
            req := createRequest(http.MethodPost, "/api/resource", nil, "user123", "test@example.com")
            req.Body = io.NopCloser(bytes.NewBufferString("{invalid json"))
            rr := httptest.NewRecorder()

            HandlerName(rr, req)

            assert.Equal(t, http.StatusBadRequest, rr.Code)
        })

        t.Run("should reject missing required field", func(t *testing.T) {
            body := map[string]interface{}{
                "optionalField": "value",
                // missing "requiredField"
            }
            req := createRequest(http.MethodPost, "/api/resource", body, "user123", "test@example.com")
            rr := httptest.NewRecorder()

            HandlerName(rr, req)

            assert.Equal(t, http.StatusBadRequest, rr.Code)
        })
    })

    t.Run("Success Cases", func(t *testing.T) {
        t.Run("should create resource successfully", func(t *testing.T) {
            body := map[string]interface{}{
                "requiredField": "value",
            }
            req := createRequest(http.MethodPost, "/api/resource", body, "user123", "test@example.com")
            rr := httptest.NewRecorder()

            HandlerName(rr, req)

            require.Equal(t, http.StatusCreated, rr.Code)

            var response map[string]interface{}
            err := json.Unmarshal(rr.Body.Bytes(), &response)
            require.NoError(t, err)

            assert.NotEmpty(t, response["id"])
        })
    })

    t.Run("Edge Cases", func(t *testing.T) {
        t.Run("should handle very long input", func(t *testing.T) {
            body := map[string]interface{}{
                "requiredField": string(make([]byte, 10000)),
            }
            req := createRequest(http.MethodPost, "/api/resource", body, "user123", "test@example.com")
            rr := httptest.NewRecorder()

            HandlerName(rr, req)

            // Should either accept or reject gracefully (not panic)
            assert.Contains(t, []int{http.StatusCreated, http.StatusBadRequest}, rr.Code)
        })

        t.Run("should handle special characters in input", func(t *testing.T) {
            body := map[string]interface{}{
                "requiredField": "Test <script>alert('xss')</script>",
            }
            req := createRequest(http.MethodPost, "/api/resource", body, "user123", "test@example.com")
            rr := httptest.NewRecorder()

            HandlerName(rr, req)

            // Should handle without crashing
            assert.NotEqual(t, http.StatusInternalServerError, rr.Code)
        })
    })
}

When to Use

  • When creating new screens in frontend/src/screens/
  • When creating new components in frontend/src/components/
  • When creating new handlers in backend/internal/handlers/
  • When adding coverage to existing code
  • When fixing bugs (add regression tests)

Output

Generate the complete test file with:

  • All required imports and mocks
  • Tests for all states (loading, error, success)
  • State transition tests (critical!)
  • User interaction tests
  • Edge case tests

Place the generated file in the correct __tests__ directory.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Local Agent

87.13%
按下载量换算123

安全审计

暂无安全审计结果可展示。

权限和风险

操作浏览器

该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills