Migration Guide
Migrating from Traditional Tests to Adaptive Tests
This guide helps you migrate existing test suites to adaptive tests, whether you’re starting fresh or maintaining both approaches side-by-side.
Table of Contents
- Quick Migration
- Gradual Migration Strategy
- Framework-Specific Guides
- Common Patterns
- Troubleshooting Migration
Quick Migration
For a single test file:
# 1. Install adaptive-tests
npm install @adaptive-tests/javascript
# 2. Generate adaptive version of existing test
npx adaptive-tests scaffold src/components/Button.js --output-dir tests/adaptive
# 3. Compare traditional vs adaptive
npm test -- tests/traditional/Button.test.js # Traditional
npm test -- tests/adaptive/Button.test.js # Adaptive
Gradual Migration Strategy
Phase 1: Parallel Testing (Recommended)
Run both traditional and adaptive tests during transition:
// package.json
{
"scripts": {
"test": "npm run test:traditional && npm run test:adaptive",
"test:traditional": "jest tests/traditional",
"test:adaptive": "jest tests/adaptive",
"test:watch": "jest --watch"
}
}
Phase 2: File-by-File Migration
- Start with leaf components (no dependencies):
npx adaptive-tests scaffold src/utils/validators.js
npx adaptive-tests scaffold src/components/Button.js
- Move to service layers:
npx adaptive-tests scaffold src/services/AuthService.js
npx adaptive-tests scaffold src/services/DataService.js
- Finish with integration tests:
npx adaptive-tests scaffold src/api/endpoints.js
Phase 3: Consolidation
Once confident, remove traditional tests:
rm -rf tests/traditional
mv tests/adaptive tests
Framework-Specific Guides
React Applications
Before (Traditional Test)
// tests/Button.test.js
import Button from '../src/components/Button';
import { render, fireEvent } from '@testing-library/react';
test('handles click', () => {
const onClick = jest.fn();
const { getByText } = render(<Button onClick={onClick}>Click me</Button>);
fireEvent.click(getByText('Click me'));
expect(onClick).toHaveBeenCalled();
});
After (Adaptive Test)
// tests/adaptive/Button.test.js
const { discover } = require('@adaptive-tests/javascript');
const { render, fireEvent } = require('@testing-library/react');
test('handles click', async () => {
const Button = await discover({
name: 'Button',
type: 'function', // or 'class' for class components
exports: 'default'
});
const onClick = jest.fn();
const { getByText } = render(<Button onClick={onClick}>Click me</Button>);
fireEvent.click(getByText('Click me'));
expect(onClick).toHaveBeenCalled();
});
Express APIs
Before (Traditional Express Test)
// tests/userRoutes.test.js
const request = require('supertest');
const app = require('../src/app');
test('GET /users returns list', async () => {
const response = await request(app).get('/users');
expect(response.status).toBe(200);
expect(Array.isArray(response.body)).toBe(true);
});
After (Adaptive Express Test)
// tests/adaptive/userRoutes.test.js
const { discover } = require('@adaptive-tests/javascript');
const request = require('supertest');
test('GET /users returns list', async () => {
const app = await discover({
name: 'app',
type: 'const',
exports: 'default'
});
const response = await request(app).get('/users');
expect(response.status).toBe(200);
expect(Array.isArray(response.body)).toBe(true);
});
Vue.js Components
Before
import { mount } from '@vue/test-utils';
import Counter from '@/components/Counter.vue';
test('increments count', () => {
const wrapper = mount(Counter);
wrapper.find('button').trigger('click');
expect(wrapper.text()).toContain('1');
});
After
const { discover } = require('@adaptive-tests/javascript');
const { mount } = require('@vue/test-utils');
test('increments count', async () => {
const Counter = await discover({
name: 'Counter',
type: 'vue-component',
exports: 'default'
});
const wrapper = mount(Counter);
wrapper.find('button').trigger('click');
expect(wrapper.text()).toContain('1');
});
Angular Services
Before (Traditional Angular Test)
import { TestBed } from '@angular/core/testing';
import { AuthService } from '../src/services/auth.service';
describe('AuthService', () => {
let service: AuthService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AuthService);
});
it('authenticates user', () => {
expect(service.login('user', 'pass')).toBeTruthy();
});
});
After (Adaptive Angular Test)
import { discover } from 'adaptive-tests';
import { TestBed } from '@angular/core/testing';
describe('AuthService', () => {
let AuthService: any;
beforeAll(async () => {
AuthService = await discover({
name: 'AuthService',
type: 'class',
methods: ['login', 'logout']
});
});
it('authenticates user', () => {
TestBed.configureTestingModule({});
const service = TestBed.inject(AuthService);
expect(service.login('user', 'pass')).toBeTruthy();
});
});
Common Patterns
Pattern 1: Testing Multiple Exports
// When a module exports multiple items
const { discover } = require('@adaptive-tests/javascript');
test('uses multiple exports', async () => {
const validators = await discover({
name: 'validators',
exports: ['isEmail', 'isPhone', 'isURL']
});
expect(validators.isEmail('test@example.com')).toBe(true);
expect(validators.isPhone('555-1234')).toBe(true);
expect(validators.isURL('https://example.com')).toBe(true);
});
Pattern 2: Mocking Dependencies
// Adaptive tests work seamlessly with jest.mock
jest.mock('axios');
test('fetches data', async () => {
const DataService = await discover({
name: 'DataService',
type: 'class',
methods: ['fetchUsers']
});
const axios = require('axios');
axios.get.mockResolvedValue({ data: ['user1', 'user2'] });
const service = new DataService();
const users = await service.fetchUsers();
expect(users).toEqual(['user1', 'user2']);
});
Pattern 3: Testing Private Methods
// Adaptive tests can discover internal methods
const InternalAPI = await discover({
name: 'InternalAPI',
type: 'class',
methods: ['_validateInput', '_processData'], // Private methods
internal: true // Enable internal discovery
});
Pattern 4: Dynamic Imports
// For code-splitting and lazy loading
test('lazy loads component', async () => {
const LazyComponent = await discover({
name: 'LazyComponent',
lazy: true, // Enables dynamic import handling
chunk: 'components' // Optional: specify webpack chunk
});
// Component is loaded only when needed
const instance = await LazyComponent();
expect(instance).toBeDefined();
});
Troubleshooting Migration
Issue: Discovery Can’t Find Module
Symptom: Error: No candidates found for signature
Solutions:
# 1. Check if module is in search paths
npx adaptive-tests why '{"name":"YourModule"}'
# 2. Verify export structure
npx adaptive-tests analyze src/YourModule.js
# 3. Add custom search paths
const { discover } = require('@adaptive-tests/javascript');
const Module = await discover({
name: 'Module'
}, {
searchPaths: ['./src', './lib', './custom-folder']
});
Issue: TypeScript Types Not Recognized
Solution: Install TypeScript support:
npm install --save-dev ts-node @types/node
// tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"esModuleInterop": true
}
}
Issue: Tests Pass Individually but Fail Together
Cause: Module caching conflicts
Solution: Clear cache between tests:
beforeEach(() => {
// Clear adaptive cache
const { clearCache } = require('adaptive-tests');
clearCache();
});
Issue: Performance Degradation
Solutions:
- Enable persistent caching:
// jest.setup.js
const { enablePersistentCache } = require('adaptive-tests');
enablePersistentCache({
cacheDir: '.adaptive-cache',
maxAge: 7 * 24 * 60 * 60 * 1000 // 1 week
});
- Limit search scope:
const Component = await discover({
name: 'Component'
}, {
searchPaths: ['./src/components'], // Don't search entire project
maxDepth: 3 // Limit directory depth
});
Migration Checklist
- Install adaptive-tests package
- Set up parallel test structure (traditional + adaptive)
- Migrate leaf components first
- Update CI/CD pipelines
- Train team on adaptive patterns
- Monitor test performance
- Remove traditional tests once confident
- Document team-specific patterns
Getting Help
- GitHub Discussions: Join the discussion
- Examples: See
languages/javascript/examples/
for JavaScript migrations andlanguages/typescript/examples/
for TypeScript samples - Issues: GitHub Issues
- Docs: Full documentation
Next Steps
- Start with a single test file
- Run both versions side-by-side
- Gradually expand coverage
- Share your migration story!
Remember: You don’t need to migrate everything at once. Adaptive tests can coexist with traditional tests indefinitely.