Skip to content

Commit b49940b

Browse files
committed
add vitest to ami-housekeeper
1 parent b7a0d56 commit b49940b

File tree

5 files changed

+184
-9
lines changed

5 files changed

+184
-9
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Setup AWS SDK client mock matchers
2+
import 'aws-sdk-client-mock-jest/vitest';
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/usr/bin/env node
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
6+
// Find all test files in the package
7+
const findTestFiles = (dir) => {
8+
let results = [];
9+
const files = fs.readdirSync(dir);
10+
11+
for (const file of files) {
12+
const filePath = path.join(dir, file);
13+
const stat = fs.statSync(filePath);
14+
15+
if (stat.isDirectory()) {
16+
results = results.concat(findTestFiles(filePath));
17+
} else if (file.endsWith('.test.ts')) {
18+
results.push(filePath);
19+
}
20+
}
21+
22+
return results;
23+
};
24+
25+
// Convert Jest syntax to Vitest syntax
26+
const convertJestToVitest = (filePath) => {
27+
console.log(`Converting ${filePath}`);
28+
let content = fs.readFileSync(filePath, 'utf8');
29+
30+
// Add import for Vitest functions if it doesn't already exist
31+
if (!content.includes('import { describe, it, expect, beforeEach, vi } from \'vitest\';')) {
32+
// Find the last import statement
33+
const lastImportIndex = content.lastIndexOf('import ');
34+
if (lastImportIndex !== -1) {
35+
const endOfImportIndex = content.indexOf(';', lastImportIndex);
36+
if (endOfImportIndex !== -1) {
37+
content =
38+
content.slice(0, endOfImportIndex + 1) +
39+
'\nimport { describe, it, expect, beforeEach, vi } from \'vitest\';\n' +
40+
content.slice(endOfImportIndex + 1);
41+
}
42+
}
43+
}
44+
45+
// Replace Jest specific functions with Vitest equivalents
46+
content = content.replace(/jest\./g, 'vi.');
47+
content = content.replace(/jest\(/g, 'vi(');
48+
49+
// Replace test() with it()
50+
content = content.replace(/test\(/g, 'it(');
51+
52+
// Replace mocked with vi.mocked
53+
if (content.includes('import { mocked } from \'jest-mock\';')) {
54+
content = content.replace('import { mocked } from \'jest-mock\';', '');
55+
content = content.replace(/mocked\(/g, 'vi.mocked(');
56+
}
57+
58+
fs.writeFileSync(filePath, content, 'utf8');
59+
console.log(`Converted ${filePath}`);
60+
};
61+
62+
// Create a custom matcher utility function if it doesn't exist
63+
const createTestUtilsFile = () => {
64+
const utilsPath = path.join(__dirname, 'src', 'test-utils.ts');
65+
66+
// Check if directory exists, create if not
67+
const dir = path.dirname(utilsPath);
68+
if (!fs.existsSync(dir)) {
69+
fs.mkdirSync(dir, { recursive: true });
70+
}
71+
72+
// If file doesn't exist, create it
73+
if (!fs.existsSync(utilsPath)) {
74+
console.log(`Creating test utilities file at ${utilsPath}`);
75+
const content = `import { AwsClientStubSpy } from 'aws-sdk-client-mock';
76+
import { expect } from 'vitest';
77+
78+
/**
79+
* Helper function to check if a command was received with specific input.
80+
* This provides similar functionality to toHaveReceivedCommandWith from aws-sdk-client-mock-jest.
81+
*/
82+
export function expectCommandCalledWith(mockClient: AwsClientStubSpy, command: any, expectedInput: any) {
83+
const calls = mockClient.commandCalls(command);
84+
expect(calls.length).toBeGreaterThan(0);
85+
expect(calls[0].args[0].input).toEqual(expectedInput);
86+
}
87+
88+
/**
89+
* Helper function to check if a command was called a specific number of times.
90+
* This provides similar functionality to toHaveReceivedCommandTimes from aws-sdk-client-mock-jest.
91+
*/
92+
export function expectCommandCalledTimes(mockClient: AwsClientStubSpy, command: any, times: number) {
93+
const calls = mockClient.commandCalls(command);
94+
expect(calls.length).toBe(times);
95+
}
96+
97+
/**
98+
* Helper function to check if a command was called at all.
99+
* This provides similar functionality to toHaveReceivedCommand from aws-sdk-client-mock-jest.
100+
*/
101+
export function expectCommandCalled(mockClient: AwsClientStubSpy, command: any) {
102+
const calls = mockClient.commandCalls(command);
103+
expect(calls.length).toBeGreaterThan(0);
104+
}
105+
106+
/**
107+
* Helper function to check if a command was not called.
108+
*/
109+
export function expectCommandNotCalled(mockClient: AwsClientStubSpy, command: any) {
110+
const calls = mockClient.commandCalls(command);
111+
expect(calls.length).toBe(0);
112+
}`;
113+
114+
fs.writeFileSync(utilsPath, content, 'utf8');
115+
console.log(`Created test utilities file at ${utilsPath}`);
116+
} else {
117+
console.log(`Test utilities file already exists at ${utilsPath}`);
118+
}
119+
120+
return utilsPath;
121+
};
122+
123+
// Main function
124+
const main = () => {
125+
// Create test utilities file
126+
createTestUtilsFile();
127+
128+
const rootDir = path.join(__dirname, 'src');
129+
const testFiles = findTestFiles(rootDir);
130+
131+
console.log(`Found ${testFiles.length} test files to convert`);
132+
133+
let processed = 0;
134+
let failed = 0;
135+
136+
for (const file of testFiles) {
137+
try {
138+
convertJestToVitest(file);
139+
processed++;
140+
} catch (error) {
141+
console.error(`Error processing ${file}:`, error);
142+
failed++;
143+
}
144+
}
145+
146+
console.log(`\nSummary:`);
147+
console.log(`- Total: ${testFiles.length} files`);
148+
console.log(`- Processed: ${processed} files`);
149+
console.log(`- Failed: ${failed} files`);
150+
};
151+
152+
main();

lambdas/functions/ami-housekeeper/src/ami.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ import {
1414
SSMClient,
1515
} from '@aws-sdk/client-ssm';
1616
import { mockClient } from 'aws-sdk-client-mock';
17-
import 'aws-sdk-client-mock-jest';
1817

1918
import { AmiCleanupOptions, amiCleanup, defaultAmiCleanupOptions } from './ami';
19+
import { describe, it, expect, beforeEach, vi } from 'vitest';
20+
2021

2122
process.env.AWS_REGION = 'eu-east-1';
2223
const deleteAmisOlderThenDays = 30;
@@ -76,7 +77,7 @@ const ssmParameters: DescribeParametersCommandOutput = {
7677

7778
describe("delete AMI's", () => {
7879
beforeEach(() => {
79-
jest.resetAllMocks();
80+
vi.resetAllMocks();
8081
mockEC2Client.reset();
8182
mockSSMClient.reset();
8283

lambdas/functions/ami-housekeeper/src/lambda.test.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { logger } from '@aws-github-runner/aws-powertools-util';
22
import { Context } from 'aws-lambda';
3-
import { mocked } from 'jest-mock';
3+
44

55
import { AmiCleanupOptions, amiCleanup } from './ami';
66
import { handler } from './lambda';
7+
import { describe, it, expect, beforeEach, beforeAll, vi } from 'vitest';
8+
79

8-
jest.mock('./ami');
9-
jest.mock('@aws-github-runner/aws-powertools-util');
10+
vi.mock('./ami');
11+
vi.mock('@aws-github-runner/aws-powertools-util');
1012

1113
const amiCleanupOptions: AmiCleanupOptions = {
1214
minimumDaysOld: undefined,
@@ -42,11 +44,11 @@ const context: Context = {
4244
// Docs for testing async with jest: https://jestjs.io/docs/tutorial-async
4345
describe('Housekeeper ami', () => {
4446
beforeAll(() => {
45-
jest.resetAllMocks();
47+
vi.resetAllMocks();
4648
});
4749

4850
it('should not throw or log in error.', async () => {
49-
const mock = mocked(amiCleanup);
51+
const mock = vi.mocked(amiCleanup);
5052
mock.mockImplementation(() => {
5153
return new Promise((resolve) => {
5254
resolve();
@@ -56,10 +58,10 @@ describe('Housekeeper ami', () => {
5658
});
5759

5860
it('should not thow only log in error in case of an exception.', async () => {
59-
const logSpy = jest.spyOn(logger, 'error');
61+
const logSpy = vi.spyOn(logger, 'error');
6062

6163
const error = new Error('An error.');
62-
const mock = mocked(amiCleanup);
64+
const mock = vi.mocked(amiCleanup);
6365
mock.mockRejectedValue(error);
6466
await expect(handler(undefined, context)).resolves.toBeUndefined();
6567

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { mergeConfig } from 'vitest/config';
2+
import defaultConfig from '../../vitest.base.config';
3+
4+
export default mergeConfig(defaultConfig, {
5+
test: {
6+
setupFiles: ['./aws-vitest-setup.ts'],
7+
coverage: {
8+
include: ['src/**/*.ts'],
9+
exclude: ['src/**/*.test.ts', 'src/**/*.d.ts'],
10+
thresholds: {
11+
statements: 100,
12+
branches: 100,
13+
functions: 100,
14+
lines: 100,
15+
}
16+
},
17+
},
18+
});

0 commit comments

Comments
 (0)