Merge pull request #223 from oke-py/refactor/testing-framework-vitest
refactor(testing): migrate from Jest to Vitest for testing framework
This commit is contained in:
@@ -30,7 +30,7 @@ This document outlines the development guidelines and best practices for our Typ
|
||||
- **Testing**
|
||||
- Write unit tests for all business logic
|
||||
- Aim for high test coverage (at least 80%)
|
||||
- Use Jest or Mocha for testing frameworks
|
||||
- Use Vitest as the testing framework
|
||||
- Implement integration tests for critical paths
|
||||
|
||||
- **Build Process**
|
||||
|
||||
10
.github/workflows/test.yml
vendored
10
.github/workflows/test.yml
vendored
@@ -17,15 +17,14 @@ jobs:
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- name: Install dependencies and run all scripts
|
||||
- name: Install dependencies and run tests
|
||||
run: |
|
||||
npm ci
|
||||
npm run all
|
||||
npm run test -- --run --coverage
|
||||
- uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Adding a comment to clarify the purpose of the Windows build job
|
||||
build-on-windows:
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -36,11 +35,10 @@ jobs:
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
# Node.js 20 already includes a recent npm version, so npm upgrade is not needed
|
||||
- name: Install dependencies and run all scripts
|
||||
- name: Install dependencies and run tests
|
||||
run: |
|
||||
npm ci
|
||||
npm run all
|
||||
npm run test -- --run
|
||||
|
||||
test: # make sure the action works on a clean machine without building
|
||||
strategy:
|
||||
|
||||
@@ -14,3 +14,25 @@
|
||||
### GitHub REST API v3
|
||||
|
||||
- https://developer.github.com/v3/
|
||||
|
||||
## Development Instructions
|
||||
|
||||
### Running Tests
|
||||
|
||||
This project uses [Vitest](https://vitest.dev/) for testing. To run the tests, use the following command:
|
||||
|
||||
```bash
|
||||
npm run test
|
||||
```
|
||||
|
||||
Vitest will execute all test files and provide a detailed report of the results.
|
||||
|
||||
### Generating Coverage Reports
|
||||
|
||||
To generate a test coverage report, use the following command:
|
||||
|
||||
```bash
|
||||
npm run test:coverage
|
||||
```
|
||||
|
||||
The coverage report will be available in the `coverage` directory.
|
||||
|
||||
22
README.md
22
README.md
@@ -73,6 +73,28 @@ jobs:
|
||||
dedupe_issues: true
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Running Tests
|
||||
|
||||
This project uses [Vitest](https://vitest.dev/) for testing. To run the tests, use the following command:
|
||||
|
||||
```bash
|
||||
npm run test
|
||||
```
|
||||
|
||||
Vitest will execute all test files and provide a detailed report of the results. For coverage reports, you can use:
|
||||
|
||||
```bash
|
||||
npm run test:coverage
|
||||
```
|
||||
|
||||
Ensure all dependencies are installed before running the tests:
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
```
|
||||
|
||||
- - -
|
||||
|
||||
This action is inspired by [homoluctus/gitrivy](https://github.com/homoluctus/gitrivy).
|
||||
|
||||
@@ -3,17 +3,17 @@ import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import {Audit} from '../src/audit'
|
||||
|
||||
jest.mock('child_process')
|
||||
vi.mock('child_process')
|
||||
|
||||
const audit = new Audit()
|
||||
|
||||
describe('run', () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(child_process).spawnSync.mockClear()
|
||||
vi.mocked(child_process).spawnSync.mockClear()
|
||||
})
|
||||
|
||||
test('finds vulnerabilities with default values', () => {
|
||||
jest.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
vi.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
const stdout = fs.readFileSync(
|
||||
path.join(__dirname, 'testdata/audit/error.txt')
|
||||
)
|
||||
@@ -34,7 +34,7 @@ describe('run', () => {
|
||||
})
|
||||
|
||||
test('finds vulnerabilities with production flag enabled', () => {
|
||||
jest.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
vi.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
const stdout = fs.readFileSync(
|
||||
path.join(__dirname, 'testdata/audit/error.txt')
|
||||
)
|
||||
@@ -55,7 +55,7 @@ describe('run', () => {
|
||||
})
|
||||
|
||||
test('finds vulnerabilities with json flag enabled', () => {
|
||||
jest.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
vi.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
const stdout = fs.readFileSync(
|
||||
path.join(__dirname, 'testdata/audit/error.json')
|
||||
)
|
||||
@@ -76,7 +76,7 @@ describe('run', () => {
|
||||
})
|
||||
|
||||
test('does not find vulnerabilities', () => {
|
||||
jest.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
vi.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
const stdout = fs.readFileSync(
|
||||
path.join(__dirname, 'testdata/audit/success.txt')
|
||||
)
|
||||
@@ -97,7 +97,7 @@ describe('run', () => {
|
||||
})
|
||||
|
||||
test('throws an error if error is not null', () => {
|
||||
jest.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
vi.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
return {
|
||||
pid: 100,
|
||||
output: '',
|
||||
@@ -115,7 +115,7 @@ describe('run', () => {
|
||||
})
|
||||
|
||||
test('throws an error if status is null', () => {
|
||||
jest.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
vi.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
return {
|
||||
pid: 100,
|
||||
output: '',
|
||||
@@ -133,7 +133,7 @@ describe('run', () => {
|
||||
})
|
||||
|
||||
test('throws an error if stderr is null', () => {
|
||||
jest.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
vi.mocked(child_process).spawnSync.mockImplementation((): any => {
|
||||
return {
|
||||
pid: 100,
|
||||
output: '',
|
||||
|
||||
@@ -68,7 +68,7 @@ describe('getExistingIssueNumber', () => {
|
||||
})
|
||||
|
||||
test('gets existing open issue', async () => {
|
||||
const getIssues = jest.fn()
|
||||
const getIssues = vi.fn()
|
||||
getIssues.mockResolvedValue({
|
||||
data: [
|
||||
{
|
||||
@@ -89,7 +89,7 @@ describe('getExistingIssueNumber', () => {
|
||||
})
|
||||
|
||||
test('returns null when there is no open issue', async () => {
|
||||
const getIssues = jest.fn()
|
||||
const getIssues = vi.fn()
|
||||
getIssues.mockResolvedValue({data: []})
|
||||
|
||||
const result = await issue.getExistingIssueNumber(getIssues, {repo, owner})
|
||||
@@ -104,7 +104,7 @@ describe('getExistingIssueNumber', () => {
|
||||
})
|
||||
|
||||
test('returns null when no issues match the issue title', async () => {
|
||||
const getIssues = jest.fn()
|
||||
const getIssues = vi.fn()
|
||||
getIssues.mockResolvedValue({
|
||||
data: [
|
||||
{
|
||||
|
||||
@@ -5,17 +5,17 @@ import {run} from '../src/main'
|
||||
import * as issue from '../src/issue'
|
||||
import * as pr from '../src/pr'
|
||||
|
||||
jest.mock('../src/audit')
|
||||
jest.mock('../src/issue')
|
||||
jest.mock('../src/pr')
|
||||
jest.mock('@octokit/rest', () => {
|
||||
vi.mock('../src/audit')
|
||||
vi.mock('../src/issue')
|
||||
vi.mock('../src/pr')
|
||||
vi.mock('@octokit/rest', () => {
|
||||
return {
|
||||
Octokit: jest.fn().mockImplementation(() => {
|
||||
Octokit: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
issues: {
|
||||
listForRepo: jest.fn(),
|
||||
createComment: jest.fn(),
|
||||
create: jest.fn()
|
||||
listForRepo: vi.fn(),
|
||||
createComment: vi.fn(),
|
||||
create: vi.fn()
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -25,8 +25,8 @@ jest.mock('@octokit/rest', () => {
|
||||
describe('run: pr', () => {
|
||||
beforeEach(() => {
|
||||
// initialize mock
|
||||
jest.mocked(Audit).mockClear()
|
||||
jest.mocked(pr).createComment.mockClear()
|
||||
vi.mocked(Audit).mockClear()
|
||||
vi.mocked(pr).createComment.mockClear()
|
||||
|
||||
process.env.INPUT_AUDIT_LEVEL = 'low'
|
||||
process.env.INPUT_PRODUCTION_FLAG = 'false'
|
||||
@@ -39,7 +39,7 @@ describe('run: pr', () => {
|
||||
})
|
||||
|
||||
test('does not call pr.createComment if vulnerabilities are not found', () => {
|
||||
jest.mocked(Audit).mockImplementation((): any => {
|
||||
vi.mocked(Audit).mockImplementation((): any => {
|
||||
return {
|
||||
stdout: fs.readFileSync(
|
||||
path.join(__dirname, 'testdata/audit/success.txt')
|
||||
@@ -57,14 +57,14 @@ describe('run: pr', () => {
|
||||
}
|
||||
})
|
||||
|
||||
jest.mocked(pr).createComment.mockResolvedValue()
|
||||
vi.mocked(pr).createComment.mockResolvedValue()
|
||||
|
||||
expect(run).not.toThrowError()
|
||||
expect(pr.createComment).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('calls pr.createComment if vulnerabilities are found in PR', () => {
|
||||
jest.mocked(Audit).mockImplementation((): any => {
|
||||
vi.mocked(Audit).mockImplementation((): any => {
|
||||
return {
|
||||
stdout: fs.readFileSync(
|
||||
path.join(__dirname, 'testdata/audit/error.txt')
|
||||
@@ -82,7 +82,7 @@ describe('run: pr', () => {
|
||||
}
|
||||
})
|
||||
|
||||
jest.mocked(pr).createComment.mockResolvedValue()
|
||||
vi.mocked(pr).createComment.mockResolvedValue()
|
||||
|
||||
expect(run).not.toThrowError()
|
||||
expect(pr.createComment).toHaveBeenCalled()
|
||||
@@ -91,7 +91,7 @@ describe('run: pr', () => {
|
||||
test('does not call pr.createComment if create_pr_comments is set to false', () => {
|
||||
process.env.INPUT_CREATE_PR_COMMENTS = 'false'
|
||||
|
||||
jest.mocked(Audit).mockImplementation((): any => {
|
||||
vi.mocked(Audit).mockImplementation((): any => {
|
||||
return {
|
||||
stdout: fs.readFileSync(
|
||||
path.join(__dirname, 'testdata/audit/error.txt')
|
||||
@@ -117,8 +117,8 @@ describe('run: pr', () => {
|
||||
describe('run: issue', () => {
|
||||
beforeEach(() => {
|
||||
// initialize mock
|
||||
jest.mocked(Audit).mockClear()
|
||||
jest.mocked(issue).getExistingIssueNumber.mockClear()
|
||||
vi.mocked(Audit).mockClear()
|
||||
vi.mocked(issue).getExistingIssueNumber.mockClear()
|
||||
|
||||
process.env.INPUT_AUDIT_LEVEL = 'low'
|
||||
process.env.INPUT_PRODUCTION_FLAG = 'false'
|
||||
@@ -133,7 +133,7 @@ describe('run: issue', () => {
|
||||
test('does not call octokit.rest.issues.create if create_issues is set to false', () => {
|
||||
process.env.INPUT_CREATE_ISSUES = 'false'
|
||||
|
||||
jest.mocked(Audit).mockImplementation((): any => {
|
||||
vi.mocked(Audit).mockImplementation((): any => {
|
||||
return {
|
||||
stdout: fs.readFileSync(
|
||||
path.join(__dirname, 'testdata/audit/error.txt')
|
||||
@@ -151,7 +151,7 @@ describe('run: issue', () => {
|
||||
}
|
||||
})
|
||||
|
||||
jest.mocked(issue).getExistingIssueNumber.mockResolvedValue(null)
|
||||
vi.mocked(issue).getExistingIssueNumber.mockResolvedValue(null)
|
||||
|
||||
expect(run).not.toThrowError()
|
||||
expect(issue.getExistingIssueNumber).not.toHaveBeenCalled()
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/*.test.ts'],
|
||||
testRunner: 'jest-circus/runner',
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest'
|
||||
},
|
||||
verbose: true
|
||||
}
|
||||
4150
package-lock.json
generated
4150
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@@ -13,8 +13,9 @@
|
||||
"format-check": "prettier --check **/*.ts",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"pack": "ncc build",
|
||||
"test": "jest",
|
||||
"all": "npm run build && npm run format && npm run lint && npm run pack && npm test -- --coverage"
|
||||
"test": "vitest",
|
||||
"test:coverage": "vitest --coverage",
|
||||
"all": "npm run build && npm run format && npm run lint && npm run pack && npm run test:coverage"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -35,18 +36,17 @@
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^20.0.0",
|
||||
"@typescript-eslint/parser": "^6.7.4",
|
||||
"@vercel/ncc": "^0.38.3",
|
||||
"@vitest/coverage-v8": "^3.1.2",
|
||||
"eslint": "^8.51.0",
|
||||
"eslint-plugin-github": "^4.10.1",
|
||||
"eslint-plugin-jest": "^27.4.2",
|
||||
"jest": "^29.7.0",
|
||||
"jest-circus": "^29.7.0",
|
||||
"js-yaml": "^4.0.0",
|
||||
"prettier": "^3.5.3",
|
||||
"ts-jest": "^29.3.2",
|
||||
"typescript": "^5.8.3"
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^6.3.4",
|
||||
"vitest": "^3.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
12
vitest.config.ts
Normal file
12
vitest.config.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'node',
|
||||
include: ['__tests__/**/*.test.ts'],
|
||||
coverage: {
|
||||
reporter: ['text', 'json', 'html', 'lcov'],
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user