Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 137 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<div align="center">ant-design-testing</div>

_Easier testing for ant-design-based UI library_
_Easier testing for ant-design-based UI library with Jest and Vitest support_

This library is based on `Jest` and `React-Testing-Library`
This library is based on `React-Testing-Library` and supports both `Jest` and `Vitest` testing frameworks

## Usage

Expand All @@ -17,22 +17,61 @@ $ yarn add ant-design-testing -D
$ pnpm add ant-design-testing -D
```

Then, modify the prefixCls if you need it, default prefixCls is `ant`
Then, configure the library in your test setup file:

```tsx
// setupTests.ts
import { provider } from 'ant-design-testing';

provider({ prefixCls: 'ant' });
// Configure prefix class (default: 'ant')
// Configure test framework (default: 'jest')
provider({
prefixCls: 'ant',
testFramework: 'jest' // or 'vitest'
});
```

### For Jest Users

No additional setup required. The library defaults to Jest compatibility.

### For Vitest Users

Configure Vitest in your setup:

```tsx
// setupTests.ts
import { provider } from 'ant-design-testing';

provider({
prefixCls: 'ant',
testFramework: 'vitest'
});
```

Or create a `vitest.config.js`:

```js
import { defineConfig } from 'vitest/config';

export default defineConfig({
test: {
environment: 'jsdom',
setupFiles: ['./tests/setupTests.ts'],
globals: true,
},
});
```

## Basic Usage

```tsx
// yourInput.test.tsx
import { input } from 'ant-design-testing';
import { input, testFn } from 'ant-design-testing';

describe("Test input's fire functions", () => {
test('fireChange', () => {
const fn = jest.fn();
const fn = testFn(); // Framework-agnostic mock function
const { container } = render(<Input onChange={fn} />);
input.fireChange(container, 'test');
expect(fn).toBeCalled();
Expand All @@ -41,6 +80,7 @@ describe("Test input's fire functions", () => {
```

Otherwise, you can use query to find ant-design element quickly, like this

```tsx
// yourInput.test.tsx
import { input } from 'ant-design-testing';
Expand All @@ -56,6 +96,7 @@ test('query', () => {
```

A simple example form demo, like this

```tsx
// your form Component
const MyForm = ({ onSubmit }: any) => {
Expand Down Expand Up @@ -85,12 +126,13 @@ const MyForm = ({ onSubmit }: any) => {
);
};
```

```tsx
// your test file
import { select, input, button } from 'ant-design-testing';
import { select, input, button, testFn } from 'ant-design-testing';

it('test MyForm', () => {
const fn = jest.fn();
const fn = testFn(); // Framework-agnostic mock function
const { container } = render(
<MyForm onSubmit={fn}/>
);
Expand All @@ -107,7 +149,9 @@ it('test MyForm', () => {
expect(fn).toBeCalledWith({username: 'zhangsan', password: '123456', role: 'admin'});
});
```

All query methods support chain calling

```tsx
// basic usage
const userName = input.query(container)!;
Expand All @@ -118,5 +162,89 @@ input.fireChange(password, '123456');
// chain usage
input.query(container)?.fireChange('zhangsan');
input.query(container, 1)?.fireChange('123456');
```

## Test Framework Agnostic APIs

The library provides framework-agnostic APIs that work with both Jest and Vitest:

### Mock Functions

```tsx
import { testFn } from 'ant-design-testing';

const mockFn = testFn(); // Works with both Jest and Vitest
```

```
### Timer Control

```tsx
import { useFakeTimers, useRealTimers, runAllTimers, advanceTimersByTime } from 'ant-design-testing';

// Setup fake timers
useFakeTimers();

// Advance timers
runAllTimers();
advanceTimersByTime(1000);

// Restore real timers
useRealTimers();
```

### Spy Functions

```tsx
import { spyOn } from 'ant-design-testing';

const spy = spyOn(console, 'log');
```

## Migration from Jest-only Code

If you have existing Jest-specific code, you can use our migration script:

```bash
npm run migrate-tests
```

This script will automatically update your test files to use framework-agnostic APIs.

## Framework Configuration

### Jest Configuration (jest.config.js)

```js
module.exports = {
setupFilesAfterEnv: ['./tests/setupTests.ts'],
testEnvironment: 'jsdom',
// ... other Jest config
};
```

### Vitest Configuration (vitest.config.js)

```js
import { defineConfig } from 'vitest/config';

export default defineConfig({
test: {
environment: 'jsdom',
setupFiles: ['./tests/setupTests.ts'],
globals: true,
},
});
```

## Running Tests

```bash
# Run with Jest
npm run test:jest

# Run with Vitest
npm run test:vitest

# Default (Jest)
npm test
```
33 changes: 24 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ant-design-testing",
"version": "2.0.0",
"description": "Easier testing for ant-design-based UI library",
"description": "Easier testing for ant-design-based UI library with Jest and Vitest support",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/cjs/index.d.ts",
Expand All @@ -12,6 +12,9 @@
"prepublishOnly": "father doctor && npm run build",
"generate": "node scripts/generate.js",
"test": "jest",
"test:jest": "jest",
"test:vitest": "vitest",
"migrate-tests": "node scripts/migrate-tests.js",
"lint": "eslint src/**",
"lint:fix": "prettier --write src/** && eslint --fix src/**",
"release": "standard-version",
Expand All @@ -26,8 +29,10 @@
"Ant Design",
"UI library",
"Jest",
"Vitest",
"Unit Test",
"React Testing Library"
"React Testing Library",
"Test Framework Agnostic"
],
"authors": [
"mortalYoung <[email protected]>",
Expand All @@ -45,37 +50,47 @@
"peerDependencies": {
"@testing-library/react": "*",
"antd": "5",
"dayjs": "*",
"rc-resize-observer": "*"
"jest": "*",
"vitest": "*"
},
"peerDependenciesMeta": {
"jest": {
"optional": true
},
"vitest": {
"optional": true
}
},
"devDependencies": {
"@swc/core": "^1.3.58",
"@swc/jest": "^0.2.26",
"@testing-library/react": "^13.0.0",
"@types/jest": "^29.5.1",
"@vitest/ui": "3.2.4",
"antd": "5",
"dayjs": "^1.11.8",
"bumpp": "^9.1.0",
"standard-version": "^9.5.0",
"dayjs": "^1.11.8",
"eslint-plugin-jsdoc": "^46.8.2",
"father": "^4.3.0",
"husky": "^8.0.3",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"jsdom": "^23.0.0",
"ko-lint-config": "^2.2.20",
"lint-staged": "^13.2.2",
"moment": "^2.29.4",
"prettier": "^2.8.8",
"rc-resize-observer": "*",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"standard-version": "^9.5.0",
"ts-morph": "^19.0.0",
"typescript": "^4.8.0"
"typescript": "^4.8.0",
"vitest": "^3.2.4"
},
"lint-staged": {
"*.{ts,js,tsx}": [
"eslint --fix",
"prettier --write"
]
}
}
}
73 changes: 73 additions & 0 deletions scripts/fix-test-imports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env node

/**
* Fix test imports to use relative imports instead of package name
*/

const fs = require('fs');
const path = require('path');

function findTestFiles(dir) {
const files = [];
const entries = fs.readdirSync(dir);

for (const entry of entries) {
const fullPath = path.join(dir, entry);
const stat = fs.statSync(fullPath);

if (stat.isDirectory() && entry !== 'node_modules' && entry !== 'dist') {
files.push(...findTestFiles(fullPath));
} else if (entry.endsWith('.test.tsx') || entry.endsWith('.test.ts')) {
files.push(fullPath);
}
}

return files;
}

function fixTestFile(filePath) {
console.log(`Processing: ${filePath}`);

const content = fs.readFileSync(filePath, 'utf8');

// Replace import from 'ant-design-testing' with relative import
const newContent = content.replace(
/import\s*{([^}]+)}\s*from\s*'ant-design-testing';/g,
"import { $1 } from '../../testFramework';"
);

if (newContent !== content) {
fs.writeFileSync(filePath, newContent, 'utf8');
console.log(`✅ Updated: ${filePath}`);
return true;
} else {
console.log(`⚪ No changes: ${filePath}`);
return false;
}
}

function main() {
console.log('🔧 Fixing test imports...\n');

const srcDir = path.join(__dirname, '../src');
const testFiles = findTestFiles(srcDir);

console.log(`Found ${testFiles.length} test files\n`);

let updatedCount = 0;

for (const file of testFiles) {
if (fixTestFile(file)) {
updatedCount++;
}
}

console.log(`\n✨ Import fix completed!`);
console.log(`📊 Updated ${updatedCount} out of ${testFiles.length} test files`);
}

if (require.main === module) {
main();
}

module.exports = { fixTestFile, findTestFiles };
Loading