mcpbeat Sign in

Testing Agent Skill

>- Unit/integration testing standards for RedisInsight using Jest and for test data, mocking patterns, and `waitFor` instead of fixed time waits. Use when writing or modifying any `*.spec.ts` or `*.spec.tsx` file, when adding component or slice tests, when debugging flaky tests, or when the user mentions jest, testing library, faker, or test patterns.

3k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
8685
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/redis/RedisInsight --skill testing

The instruction itself

24 sections, as written by the author

Testing Standards and Practices

Core Principles

  • Write tests for all new features
  • Follow AAA pattern: Arrange, Act, Assert
  • Use descriptive test names: "should do X when Y"
  • CRITICAL: Never use fixed time waits - tests must be deterministic
  • CRITICAL: Use faker library (@faker-js/faker) for test data

Test Organization

describe('FeatureService', () => {
  describe('findById', () => {
    it('should return entity when found', () => {});
    it('should throw NotFoundException when not found', () => {});
  });

  describe('create', () => {
    it('should create entity with valid data', () => {});
    it('should throw error with invalid data', () => {});
  });
});

Frontend Testing (Jest + Testing Library)

Running Specific Tests

# Run a specific test file
node 'node_modules/.bin/jest' 'redisinsight/ui/src/path/to/Component.spec.tsx' -c 'jest.config.cjs'

# Run a specific test by name (use -t flag)
node 'node_modules/.bin/jest' 'redisinsight/ui/src/path/to/Component.spec.tsx' -c 'jest.config.cjs' -t 'test name pattern'

# Example:
node 'node_modules/.bin/jest' 'redisinsight/ui/src/slices/tests/browser/keys.spec.ts' -c 'jest.config.cjs' -t 'refreshKeyInfoAction'

CRITICAL: Always Use Shared renderComponent Helper

Create a renderComponent helper for each component test file:

import { faker } from '@faker-js/faker';
// Pull structured data from a shared factory (redisinsight/ui/src/mocks/factories/);
// only build ad-hoc primitives/callbacks inline.

describe('MyComponent', () => {
  // Default props: factory for the entity, inline only for callbacks/primitives
  const mockUser = UserFactory.build();
  const defaultProps: MyComponentProps = {
    user: mockUser,
    onComplete: jest.fn(),
  };

  // Shared render helper
  const renderComponent = (propsOverride?: Partial<MyComponentProps>) => {
    const props = { ...defaultProps, ...propsOverride };

    return render(
      <Provider store={store}>
        <MyComponent {...props} />
      </Provider>
    );
  };

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

  it('should render component', () => {
    renderComponent();
    expect(screen.getByText(defaultProps.name)).toBeInTheDocument();
  });

  it('should handle click', async () => {
    const mockOnComplete = jest.fn();
    renderComponent({ onComplete: mockOnComplete });

    fireEvent.click(screen.getByRole('button'));

    await waitFor(() => {
      expect(mockOnComplete).toHaveBeenCalledTimes(1);
    });
  });
});

Benefits:

  • Centralized setup (providers, router, theme)
  • Default props defined once
  • Easy prop overrides per test
  • No duplicate setup code

Complex Component Setup

For components requiring Router, ThemeProvider, etc., include them in renderComponent:

const renderComponent = (propsOverride?: Partial<Props>) => {
  const props = { ...defaultProps, ...propsOverride }

  return render(
    <Provider store={store}>
      <BrowserRouter>
        <ThemeProvider theme={theme}>
          <Component {...props} />
        </ThemeProvider>
      </BrowserRouter>
    </Provider>
  )
}

Testing with Redux

Create a test store with configureStore for Redux-connected components:

const createTestStore = (initialState = {}) => {
  return configureStore({
    reducer: { user: userSlice.reducer },
    preloadedState: initialState,
  });
};

const renderComponent = (propsOverride?: Partial<Props>, storeState = {}) => {
  const testStore = createTestStore(storeState);
  // render with testStore
};

Query Priorities (Testing Library)

Prefer accessible queries (as users would interact):

// ✅ PREFERRED
screen.getByRole('button', { name: /submit/i });
screen.getByLabelText('Email');
screen.getByPlaceholderText('Enter name');

// ⚠️ LAST RESORT
screen.getByTestId('user-profile');

// ❌ AVOID
wrapper.find('.button-class');

Testing Async Behavior

// ✅ GOOD: waitFor with proper queries
await waitFor(() => {
  expect(screen.getByText('Data loaded')).toBeInTheDocument();
});

// ✅ GOOD: waitForElementToBeRemoved
await waitForElementToBeRemoved(() => screen.queryByText('Loading...'));

// ✅ GOOD: findBy queries (built-in waiting)
const element = await screen.findByText('Async content');

// ❌ BAD: Fixed timeouts (flaky tests)
await new Promise((resolve) => setTimeout(resolve, 1000));

Mocking API Calls (MSW)

Use Mock Service Worker for API mocking:

import { rest } from 'msw';
import { setupServer } from 'msw/node';

const server = setupServer(
  rest.get('/api/users/:id', (req, res, ctx) => {
    return res(
      ctx.json({
        id: req.params.id,
        name: faker.person.fullName(),
      }),
    );
  }),
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

Backend Testing (NestJS/Jest)

Service Test Pattern

import { Factory } from 'fishery';
import { faker } from '@faker-js/faker';

// Define factory for User entity
const userFactory = Factory.define<User>(() => ({
  id: faker.string.uuid(),
  name: faker.person.fullName(),
  email: faker.internet.email(),
}));

describe('UserService', () => {
  let service: UserService;
  let repository: Repository<User>;

  const mockRepository = {
    find: jest.fn(),
    findOne: jest.fn(),
    save: jest.fn(),
    update: jest.fn(),
    delete: jest.fn(),
  };

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        UserService,
        {
          provide: getRepositoryToken(User),
          useValue: mockRepository,
        },
      ],
    }).compile();

    service = module.get<UserService>(UserService);
    repository = module.get<Repository<User>>(getRepositoryToken(User));
  });

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

  it('should return user when found', async () => {
    const mockUser = userFactory.build();
    mockRepository.findOne.mockResolvedValue(mockUser);

    const result = await service.findById(mockUser.id);

    expect(result).toEqual(mockUser);
  });
});

Controller Test Pattern

import { Factory } from 'fishery';
import { faker } from '@faker-js/faker';

const userFactory = Factory.define<User>(() => ({
  id: faker.string.uuid(),
  name: faker.person.fullName(),
  email: faker.internet.email(),
}));

describe('UserController', () => {
  let controller: UserController;
  let service: UserService;

  const mockService = {
    findAll: jest.fn(),
    findById: jest.fn(),
    create: jest.fn(),
  };

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      controllers: [UserController],
      providers: [{ provide: UserService, useValue: mockService }],
    }).compile();

    controller = module.get<UserController>(UserController);
  });

  it('should return user from service', async () => {
    const mockUser = userFactory.build();
    mockService.findById.mockResolvedValue(mockUser);

    const result = await controller.findById(mockUser.id);

    expect(result).toEqual(mockUser);
  });
});

Integration Tests (E2E)

describe('UserController (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = module.createNestApplication();
    await app.init();
  });

  afterAll(async () => {
    await app.close();
  });

  it('/users (GET)', () => {
    return request(app.getHttpServer())
      .get('/users')
      .expect(200)
      .expect((res) => {
        expect(Array.isArray(res.body)).toBe(true);
      });
  });
});

E2E Testing (Playwright)

import { Factory } from 'fishery';
import { faker } from '@faker-js/faker';

const userDataFactory = Factory.define(() => ({
  name: faker.person.fullName(),
  email: faker.internet.email(),
}));

test.describe('User Management', () => {
  test('should create new user', async ({ page }) => {
    const userData = userDataFactory.build();

    await page.goto('/users');
    await page.click('text=Add User');
    await page.fill('[name="name"]', userData.name);
    await page.fill('[name="email"]', userData.email);
    await page.click('text=Submit');

    // ✅ Use proper waits
    await expect(page.locator(`text=${userData.name}`)).toBeVisible();
  });
});

Best Practices

Always Use Faker for Test Data

// ✅ GOOD: Use faker
const user = {
  id: faker.string.uuid(),
  name: faker.person.fullName(),
  email: faker.internet.email(),
  age: faker.number.int({ min: 18, max: 100 }),
};

// ❌ BAD: Hardcoded data
const user = { id: '123', name: 'Test User' };

Use Factories Instead of Static Mocks

Use Fishery for creating test data factories with sensible defaults and overrides.

CRITICAL — UI factories live in redisinsight/ui/src/mocks/factories/, organized by

domain (<domain>/<TypeName>.factory.ts), exported as <TypeName>Factory. Before writing

test data in a UI spec, check for an existing factory there and reuse it; if none fits,

add a new factory file in that directory rather than inlining mocks in the spec.

// ✅ GOOD: reuse the shared factory (redisinsight/ui/src/mocks/factories/database/DBInstance.factory.ts)
import { DBInstanceFactory } from 'uiSrc/mocks/factories/database/DBInstance.factory';

const instance = DBInstanceFactory.build();
const cluster = DBInstanceFactory.build({
  connectionType: ConnectionType.Cluster,
});
const many = DBInstanceFactory.buildList(5);

// ✅ GOOD: a new factory file, when none exists yet
// redisinsight/ui/src/mocks/factories/<domain>/<TypeName>.factory.ts
import { Factory } from 'fishery';
import { faker } from '@faker-js/faker';

const userFactory = Factory.define<User>(({ sequence }) => ({
  id: faker.string.uuid(),
  name: faker.person.fullName(),
  email: faker.internet.email(),
  age: faker.number.int({ min: 18, max: 100 }),
}));

// Usage - flexible and reusable
const user1 = userFactory.build();
const user2 = userFactory.build({ age: 25 });
const user3 = userFactory.build({ name: 'Specific Name' });
const users = userFactory.buildList(5); // Create multiple

// ❌ BAD: Static mock objects
const mockUser1 = {
  id: '123',
  name: 'User 1',
  email: '[email protected]',
  age: 30,
};

Benefits of Fishery factories:

  • Easy to override specific properties per test
  • Consistent default values across tests
  • Single source of truth for mock structure
  • Better maintainability when types change
  • Built-in support for sequences and traits

Never Use Fixed Timeouts

// ❌ BAD: Fixed timeout
await new Promise((resolve) => setTimeout(resolve, 1000));
await page.waitForTimeout(2000);

// ✅ GOOD: Wait for condition
await waitFor(() => {
  expect(element).toBeInTheDocument();
});

await page.waitForSelector('[data-test="result"]');

Mock External Dependencies

// ✅ GOOD: Mock services
jest.mock('uiSrc/services/api', () => ({
  apiService: {
    get: jest.fn(),
    post: jest.fn(),
  },
}));

Parameterized Tests with it.each

Use it.each for multiple tests with the same body but different inputs:

// ✅ GOOD: Parameterized tests
it.each([
  { description: 'null', value: null },
  { description: 'undefined', value: undefined },
  { description: 'empty string', value: '' },
  { description: 'whitespace only', value: '   ' },
])('should return error when input is $description', async ({ value }) => {
  const result = await service.processInput(value);
  expect(result.status).toBe('error');
});

Benefits:

  • DRY: Single test body shared across all cases
  • Maintainability: Changes to test logic only need to be made once
  • Readability: Test cases are clearly defined in a table
  • Easier to extend: Adding new test cases is just adding a new row

Test Edge Cases

Always test:

  • Empty arrays/objects
  • Null/undefined values
  • Error scenarios
  • Boundary conditions
  • Loading states

Testing Checklist

  • [ ] All new features have tests
  • [ ] Tests use faker for data generation
  • [ ] No fixed timeouts (use waitFor)
  • [ ] Tests follow AAA pattern
  • [ ] Descriptive test names
  • [ ] Shared renderComponent helper used
  • [ ] Default props defined
  • [ ] Edge cases covered
  • [ ] Error scenarios tested
  • [ ] Mocks cleaned up between tests
  • [ ] Integration tests for API endpoints
  • [ ] E2E tests for critical flows
  • [ ] Coverage meets thresholds (80%+)

Other skills for the same job

different authors, same section of the catalogue
Webapp Testing
by anthropics
vendor ×12

Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.

6k tokens scripts
Finishing A Development Branch
by ZhanlinCui
×7

Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup

1k tokens
Test Driven Development
by w95
×7

Use when implementing any feature or bugfix, before writing implementation code

2k tokens
Systematic Debugging
by ratacat
×7

Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes

10k tokens scripts
Verification Before Completion
by ZhanlinCui
×6

Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always

1k tokens
Backtest Expert
by BaggaT236
×3

Expert guidance for systematic backtesting of trading strategies. Use when developing, testing, stress-testing, or validating quantitative trading strategies. Covers "beating ideas to death" methodology, parameter robustness testing, slippage modeling, bias prevention, and interpreting backtest results. Applicable when user asks about backtesting, strategy validation, robustness testing, avoiding overfitting, or systematic trading development.

15k tokens scripts
Adaptyv
by christophacham
×3

Cloud laboratory platform for automated protein testing and validation. Use when designing proteins and needing experimental validation including binding assays, expression testing, thermostability measurements, enzyme activity assays, or protein sequence optimization. Also use for submitting experiments via API, tracking experiment status, downloading results, optimizing protein sequences for better expression using computational tools (NetSolP, SoluProt, SolubleMPNN, ESM), or managing protein design workflows with wet-lab validation.

16k tokens
Aeon
by christophacham
×3

This skill should be used for time series machine learning tasks including classification, regression, clustering, forecasting, anomaly detection, segmentation, and similarity search. Use when working with temporal data, sequential patterns, or time-indexed observations requiring specialized algorithms beyond standard ML approaches. Particularly suited for univariate and multivariate time series analysis with scikit-learn compatible APIs.

19k tokens

How to use it

Copy the folder

Take redis/redisinsight-testing from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.