---
name: test-migration-specialist
description: This skill should be used when migrating Angular libraries from Jest + Spectator to Vitest + Angular Testing Utilities. It handles test configuration updates, test file refactoring, mock pattern conversion, and validation. Use this skill when the user requests test framework migration, specifically for the 40 remaining Jest-based libraries in the ISA-Frontend monorepo.
---

# Test Migration Specialist

## Overview

Automate the migration of Angular library tests from Jest + Spectator to Vitest + Angular Testing Utilities. This skill handles the complete migration workflow including configuration updates, test file refactoring, dependency management, and validation.

**Current Migration Status**: 40 libraries use Jest (65.6%), 21 libraries use Vitest (34.4%)

## When to Use This Skill

Invoke this skill when:
- User requests test migration for a specific library
- User mentions "migrate tests" or "Jest to Vitest"
- User wants to update test framework for a library
- User references the 40 remaining libraries to migrate

## Migration Workflow

### Step 1: Pre-Migration Analysis

Before making any changes, analyze the current state:

1. **Read Testing Guidelines**
   - Use `docs-researcher` agent to read `docs/guidelines/testing.md`
   - Understand migration patterns and best practices
   - Note JUnit and Cobertura configuration requirements

2. **Analyze Library Structure**
   - Read `libs/[path]/project.json` to identify current test executor
   - Count test files using Glob: `**/*.spec.ts`
   - Scan for Spectator usage patterns using Grep: `createComponentFactory|createServiceFactory|Spectator`
   - Identify complex mocking scenarios (ng-mocks, jest.mock patterns)

3. **Determine Library Depth**
   - Calculate directory levels from workspace root
   - This affects relative paths in vite.config.mts (../../../ vs ../../../../)

### Step 2: Update Test Configuration

Update the library's test configuration to use Vitest:

1. **Update project.json**
   Replace Jest executor with Vitest:
   ```json
   {
     "test": {
       "executor": "@nx/vite:test",
       "options": {
         "configFile": "vite.config.mts"
       }
     }
   }
   ```

2. **Create vite.config.mts**
   Create configuration with JUnit and Cobertura reporters:
   ```typescript
   /// <reference types='vitest' />
   import { defineConfig } from 'vite';
   import angular from '@analogjs/vite-plugin-angular';
   import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
   import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';

   export default
   // @ts-expect-error - Vitest reporter tuple types have complex inference issues
   defineConfig(() => ({
     root: __dirname,
     cacheDir: '../../../node_modules/.vite/libs/[path]',
     plugins: [angular(), nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
     test: {
       watch: false,
       globals: true,
       environment: 'jsdom',
       include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
       setupFiles: ['src/test-setup.ts'],
       reporters: [
         'default',
         ['junit', { outputFile: '../../../testresults/junit-[library-name].xml' }],
       ],
       coverage: {
         reportsDirectory: '../../../coverage/libs/[path]',
         provider: 'v8' as const,
         reporter: ['text', 'cobertura'],
       },
     },
   }));
   ```

   **Critical**: Adjust `../../../` depth based on library location

### Step 3: Migrate Test Files

For each `.spec.ts` file, perform these conversions:

1. **Update Imports**
   ```typescript
   // REMOVE
   import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';

   // ADD
   import { ComponentFixture, TestBed } from '@angular/core/testing';
   import { describe, it, expect, beforeEach } from 'vitest';
   ```

2. **Convert Component Tests**
   ```typescript
   // OLD (Spectator)
   const createComponent = createComponentFactory({
     component: MyComponent,
     imports: [CommonModule],
     mocks: [MyService]
   });

   let spectator: Spectator<MyComponent>;
   beforeEach(() => spectator = createComponent());

   it('should display title', () => {
     spectator.setInput('title', 'Test');
     expect(spectator.query('h1')).toHaveText('Test');
   });

   // NEW (Angular Testing Utilities)
   describe('MyComponent', () => {
     let fixture: ComponentFixture<MyComponent>;
     let component: MyComponent;

     beforeEach(async () => {
       await TestBed.configureTestingModule({
         imports: [MyComponent, CommonModule],
         providers: [{ provide: MyService, useValue: mockService }]
       }).compileComponents();

       fixture = TestBed.createComponent(MyComponent);
       component = fixture.componentInstance;
     });

     it('should display title', () => {
       component.title = 'Test';
       fixture.detectChanges();
       expect(fixture.nativeElement.querySelector('h1').textContent).toContain('Test');
     });
   });
   ```

3. **Convert Service Tests**
   ```typescript
   // OLD (Spectator)
   const createService = createServiceFactory({
     service: MyService,
     mocks: [HttpClient]
   });

   // NEW (Angular Testing Utilities)
   describe('MyService', () => {
     let service: MyService;
     let httpMock: HttpTestingController;

     beforeEach(() => {
       TestBed.configureTestingModule({
         imports: [HttpClientTestingModule],
         providers: [MyService]
       });

       service = TestBed.inject(MyService);
       httpMock = TestBed.inject(HttpTestingController);
     });

     afterEach(() => {
       httpMock.verify();
     });
   });
   ```

4. **Update Mock Patterns**
   - Replace `jest.fn()` → `vi.fn()`
   - Replace `jest.spyOn()` → `vi.spyOn()`
   - Replace `jest.mock()` → `vi.mock()`
   - For complex mocks, use `ng-mocks` library if needed

5. **Update Matchers**
   - Replace Spectator matchers (`toHaveText`, `toExist`) with standard Jest/Vitest matchers
   - Use `expect().toBeTruthy()`, `expect().toContain()`, etc.

### Step 4: Verify E2E Attributes

Check component templates for E2E testing attributes:

1. **Scan Templates**
   Use Grep to find templates: `**/*.html`

2. **Validate Attributes**
   Ensure interactive elements have:
   - `data-what`: Semantic description (e.g., "submit-button")
   - `data-which`: Unique identifier (e.g., "form-primary")
   - Dynamic `data-*` for list items: `[attr.data-item-id]="item.id"`

3. **Add Missing Attributes**
   If missing, add them to components. See `dev:add-e2e-attrs` command or use that skill.

### Step 5: Run Tests and Validate

Execute tests to verify migration:

1. **Run Tests**
   ```bash
   npx nx test [library-name] --skip-nx-cache
   ```

2. **Run with Coverage**
   ```bash
   npx nx test [library-name] --coverage.enabled=true --skip-nx-cache
   ```

3. **Verify Output Files**
   Check that CI/CD integration files are created:
   - JUnit XML: `testresults/junit-[library-name].xml`
   - Cobertura XML: `coverage/libs/[path]/cobertura-coverage.xml`

4. **Address Failures**
   If tests fail:
   - Review test conversion (common issues: missing fixture.detectChanges(), incorrect selectors)
   - Check mock configurations
   - Verify imports are correct
   - Ensure async tests use proper patterns

### Step 6: Clean Up

Remove legacy configurations:

1. **Remove Jest Files**
   - Delete `jest.config.ts` or `jest.config.js` if present
   - Remove Jest-specific setup files

2. **Update Dependencies**
   - Note if Spectator can be removed (check if other libs still use it)
   - Note if Jest can be removed (check if other libs still use it)
   - Don't actually remove from package.json unless all libs migrated

3. **Update Documentation**
   Update library README.md with new test commands:
   ```markdown
   ## Testing

   This library uses Vitest + Angular Testing Utilities.

   ```bash
   # Run tests
   npx nx test [library-name] --skip-nx-cache

   # Run with coverage
   npx nx test [library-name] --coverage.enabled=true --skip-nx-cache
   ```
   ```

### Step 7: Generate Migration Report

Provide comprehensive migration summary:

```
Test Migration Complete
=======================

Library: [library-name]
Framework: Jest + Spectator → Vitest + Angular Testing Utilities

📊 Migration Statistics
-----------------------
Test files migrated: XX
Component tests: XX
Service tests: XX
Total test cases: XX

✅ Test Results
---------------
Passing: XX/XX (100%)
Coverage: XX%

📝 Configuration
----------------
- project.json: ✅ Updated to @nx/vite:test
- vite.config.mts: ✅ Created with JUnit + Cobertura
- E2E attributes: ✅ Validated

📁 CI/CD Integration
--------------------
- JUnit XML: ✅ testresults/junit-[name].xml
- Cobertura XML: ✅ coverage/libs/[path]/cobertura-coverage.xml

🧹 Cleanup
----------
- Jest config removed: ✅
- README updated: ✅

💡 Next Steps
-------------
1. Verify tests in CI/CD pipeline
2. Monitor for any edge cases
3. Consider migrating related libraries

📚 Remaining Libraries
----------------------
Jest libraries remaining: XX/40
Progress: XX% complete
```

## Error Handling

### Common Migration Issues

**Issue 1: Tests fail after migration**
- Check `fixture.detectChanges()` is called after setting inputs
- Verify async tests use `async/await` properly
- Check component imports are correct (standalone components)

**Issue 2: Mocks not working**
- Verify `vi.fn()` syntax is correct
- Check providers array in TestBed configuration
- For complex mocks, consider using `ng-mocks`

**Issue 3: Coverage files not generated**
- Verify path depth in vite.config.mts matches library location
- Check reporters array includes `'cobertura'`
- Ensure `provider: 'v8'` is set

**Issue 4: Type errors in vite.config.mts**
- Add `// @ts-expect-error` comment before `defineConfig()`
- This is expected due to Vitest reporter type complexity

## References

Use `docs-researcher` agent to access:
- `docs/guidelines/testing.md` - Comprehensive migration guide with examples
- `CLAUDE.md` - Testing Framework section for project conventions

**Key Documentation Sections:**
- Vitest Configuration with JUnit and Cobertura
- Angular Testing Utilities examples
- Migration patterns and best practices
- E2E attribute requirements
