@biorate/vitest
v1.9.0
Published
OOP test decorators for vitest with Allure support
Maintainers
Readme
@biorate/vitest
OOP test decorators for Vitest with Allure support.
Features
- OOP Style: Write tests using classes and decorators
- Allure Integration: Full support for Allure reporting
- Clean Architecture: Modular design with separation of concerns
- TypeScript: Full type safety
- Scenario Pattern: Support for reusable test scenarios
Installation
pnpm i -D @biorate/vitest vitest allure-js-commons allure-vitest reflect-metadataUsage
Basic Test
import { suite, test, expect } from '@biorate/vitest';
import 'reflect-metadata';
@suite('My Test Suite')
class MyTest {
@test('should pass')
async shouldPass() {
expect(1 + 1).toBe(2);
}
}Allure Annotations
import {
suite,
test,
epic,
feature,
story,
severity,
owner,
label,
tags,
issue,
description,
} from '@biorate/vitest';
import { Severity } from 'allure-js-commons';
@suite('Authentication')
class AuthTest {
@epic('Security')
@feature('Login')
@story('User Authentication')
@severity(Severity.CRITICAL)
@owner('user-id-123')
@tags('auth', 'login')
@label('priority', 'high')
@issue('JIRA-123', 'https://jira.example.com/JIRA-123')
@description('Tests user login functionality')
@test('should login user')
async shouldLoginUser() {
// test implementation
}
}Lifecycle Hooks
@suite('Database Tests')
class DatabaseTest {
protected static async beforeAll() {
// Setup before all tests
}
protected static async afterAll() {
// Cleanup after all tests
}
protected async before() {
// Setup before each test
}
protected async after() {
// Cleanup after each test
}
@test('should connect')
async shouldConnect() {
// test implementation
}
}Test Modifiers
import { suite, test, skip, only, todo, timeout, repeats } from '@biorate/vitest';
@suite('Edge Cases')
class EdgeCasesTest {
@skip()
@test('skip this test')
async skippedTest() {
// will be skipped
}
@only()
@test('run only this test')
async exclusiveTest() {
// only this test will run in the suite
}
@todo()
@test('todo test')
async todoTest() {
// marked as todo
}
@timeout(5000)
@test('test with timeout')
async timeoutTest() {
// will timeout after 5 seconds
}
@repeats(3, { mode: 'series' })
@test('flaky test')
async flakyTest() {
// will run 3 times in series
}
}Scenario Pattern
import { Scenario, Step, Context } from '@biorate/vitest';
export class LoginScenario extends Scenario {
@Step('Open login page')
protected async openLoginPage() {
await this.context.page.goto('/login');
}
@Step('Enter credentials')
protected async enterCredentials() {
await this.context.page.fill('#username', 'user');
await this.context.page.fill('#password', 'pass');
}
@Step('Submit form')
protected async submitForm() {
await this.context.page.click('button[type=submit]');
}
}
// Usage in test
@suite('Login Flow')
class LoginTest {
@test('should login successfully')
async testLogin() {
await Context.run([LoginScenario], {
page: this.page
});
}
}Suite Options
import { suite, test } from '@biorate/vitest';
@suite('Serial Suite', { mode: 'serial' })
class SerialTest {
@test('test 1')
async test1() {
// tests will run sequentially
}
@test('test 2')
async test2() {}
}
@suite('Parallel Suite', { mode: 'parallel' })
class ParallelTest {
@test('test 1')
async test1() {
// tests will run in parallel
}
@test('test 2')
async test2() {}
}
@suite('Suite with Timeout', { timeout: 10000 })
class TimeoutTest {
@test('test with suite timeout')
async test1() {
// suite has 10 second timeout
}
}
@suite('Suite with Retries', { retries: 2 })
class RetryTest {
@test('flaky test')
async test1() {
// will retry up to 2 times on failure
}
}
@suite('Full Options', {
mode: 'serial',
timeout: 10000,
retries: 2
})
class FullOptionsTest {
@test('test')
async test() {}
}@test('test 1') async test1() {}
@test('test 2') async test2() {} }
## Migration from Mocha
For smooth migration from `@biorate/mocha` to `@biorate/vitest`, we provide deprecated decorators that maintain backward compatibility.
### Deprecated Decorators
The following decorators are available for Mocha compatibility but are **deprecated**. Use the recommended alternatives:
| Deprecated Decorator | Recommended Alternative | Description |
|---------------------|------------------------|-------------|
| `@retries(n)` | `@repeats(n, { mode: 'series' })` | Retry failed tests |
| `@parallel(true)` | `@suite('name', { mode: 'parallel' })` | Enable parallel execution |
| `@slow(ms)` | `@timeout(ms)` | Mark slow tests |
| `@pending()` | `@skip()` or `@todo()` | Mark test as pending |
| `@params(...)` | Use Vitest's native parameterized tests | Parameterized tests |
| `context` (symbol) | Use Vitest's test context directly | Test context symbol |
| `@allureStep(name)` | Use `allure.step()` directly | Allure step decorator |
| `@attachment(name, content, type)` | Use `allure.attachment()` directly | Allure attachment decorator |
| `@testCaseId(id)` | `@id(id)` | Test case ID decorator |
| `@data(params, name?)` | Use Vitest's native parameterized tests | Parameterized test data |
| `decorate(instance)` | Use Allure API directly | Decorate Allure instance |
| `assignPmsUrl(url)` | Use environment variables | Assign PMS URL |
| `assignTmsUrl(url)` | Use environment variables | Assign TMS URL |
### Deprecation Warnings
When using deprecated decorators, you will see a warning message in the console **once per decorator type**:
[@biorate/vitest] Deprecated decorator: @retries. Use @repeats(count, { mode: "series" }) instead.
This helps you identify which decorators need to be updated during migration.
### Migration Example
**Before (Mocha):**
```typescript
import { suite, parallel, retries, test } from '@biorate/mocha';
@suite
@parallel(true)
class MyTest {
@retries(2)
@test('should work')
async myTest() {
// test implementation
}
}After (Vitest):
import { suite, repeats, test } from '@biorate/vitest';
@suite('My Test', { mode: 'parallel', retries: 2 })
class MyTest {
@test('should work')
async myTest() {
// test implementation
}
}Compatibility Mode
You can still use deprecated decorators during migration:
import { suite, parallel, retries, test } from '@biorate/vitest';
@suite('My Test')
@parallel(true) // deprecated, but works
class MyTest {
@retries(2) // deprecated, but works
@test('should work')
async myTest() {
// test implementation
}
}Note: Deprecated decorators will be removed in future versions. Please update your code to use the recommended alternatives.
API Reference
Decorators
Test Definition
@suite(name?, options?)- Define a test suite class@test(name?)- Define a test method
Modifiers
@skip()- Skip test/suite@only()- Run only this test/suite@todo()- Mark as TODO@timeout(ms)- Set timeout@repeats(count, options)- Repeat test
Allure
@epic(name)- Set epic@feature(name)- Set feature@story(name)- Set story@severity(level)- Set severity@owner(name)- Set owner@tag(tag)- Add single tag@tags(...tags)- Add multiple tags@label(name, value)- Add custom label@link(url, name?, type?)- Add link@id(id)- Set test ID@allureSuite(name)- Set Allure suite@parentSuite(name)- Set parent suite@subSuite(name)- Set sub suite@issue(name, url?)- Add issue link@description(value)- Add description
Vitest Configuration
Create vitest.config.ts:
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
reporter: [
'default',
['allure-vitest', { outputFolder: 'allure-results' }],
],
},
});License
MIT
