/**
* @vitest-environment node
*/
import { vi } from 'vitest';
import nock from 'nock';
import { DeepSourceClient, MetricShortcode } from '../deepsource';
import { MetricKey } from '../types/metrics';
describe('DeepSourceClient Metric Validation', () => {
const API_KEY = 'test-api-key';
const PROJECT_KEY = 'test-project';
// Subclass DeepSourceClient to expose private methods for testing
class TestableDeepSourceClient extends DeepSourceClient {
async testValidateAndGetMetricInfo(params: {
projectKey: string;
metricShortcode: MetricShortcode;
metricKey: MetricKey;
}) {
// @ts-expect-error - accessing private method for testing
return this.validateAndGetMetricInfo(params);
}
}
let client: TestableDeepSourceClient;
beforeEach(() => {
nock.cleanAll();
client = new TestableDeepSourceClient(API_KEY);
});
afterAll(() => {
nock.restore();
});
describe('validateAndGetMetricInfo method', () => {
it('should return project, metric, and metric item when all are valid (lines 2931, 2934, 2939, 2942, 2946, 2952, 2959)', async () => {
// Mock the projects response
const mockProjects = [
{
key: PROJECT_KEY,
name: 'Test Project',
repository: {
id: 'repo123',
login: 'testorg',
provider: 'github',
},
},
];
// Mock the metrics response
const mockMetrics = [
{
shortcode: MetricShortcode.LCV,
name: 'Line Coverage',
items: [
{
id: 'metric123',
key: MetricKey.AGGREGATE,
threshold: 80,
},
],
},
];
// Mock the listProjects method to return our mock data (line 2931)
vi.spyOn(client, 'listProjects').mockResolvedValue(mockProjects);
// Mock the getQualityMetrics method to return our mock data (line 2942)
vi.spyOn(client, 'getQualityMetrics').mockResolvedValue(mockMetrics);
// Mock the static validateProjectRepository method (line 2939)
// This validation is bypassed because we're testing other aspects of the validation flow
vi.spyOn(DeepSourceClient, 'validateProjectRepository').mockImplementation(() => {
// Intentionally empty - validation is not the focus of this test
// We're just preventing it from throwing errors
});
// Call the method under test
const result = await client.testValidateAndGetMetricInfo({
projectKey: PROJECT_KEY,
metricShortcode: MetricShortcode.LCV,
metricKey: MetricKey.AGGREGATE,
});
// Verify the result contains the expected data
expect(result).toEqual({
project: mockProjects[0],
metric: mockMetrics[0],
metricItem: mockMetrics[0].items[0],
});
// Verify the method calls
expect(client.listProjects).toHaveBeenCalled(); // line 2931
expect(DeepSourceClient.validateProjectRepository).toHaveBeenCalledWith(
mockProjects[0],
PROJECT_KEY
); // line 2939
expect(client.getQualityMetrics).toHaveBeenCalledWith(PROJECT_KEY, {
shortcodeIn: [MetricShortcode.LCV],
}); // line 2942
});
it('should throw error when project is not found (line 2934)', async () => {
// Mock the listProjects method to return empty array (line 2931)
vi.spyOn(client, 'listProjects').mockResolvedValue([]);
// Call the method and expect it to throw
await expect(
client.testValidateAndGetMetricInfo({
projectKey: PROJECT_KEY,
metricShortcode: MetricShortcode.LCV,
metricKey: MetricKey.AGGREGATE,
})
).rejects.toThrow(`Project with key ${PROJECT_KEY} not found`);
// Verify the method call
expect(client.listProjects).toHaveBeenCalled(); // line 2931
});
it('should throw error when metric is not found (line 2946)', async () => {
// Mock the projects response
const mockProjects = [
{
key: PROJECT_KEY,
name: 'Test Project',
repository: {
id: 'repo123',
login: 'testorg',
provider: 'github',
},
},
];
// Mock empty metrics response
const mockMetrics: Array<{
shortcode: string;
name: string;
items: Array<{ id: string; key: string; threshold?: number }>;
}> = [];
// Mock the listProjects method to return our mock data (line 2931)
vi.spyOn(client, 'listProjects').mockResolvedValue(mockProjects);
// Mock the getQualityMetrics method to return empty array (line 2942)
vi.spyOn(client, 'getQualityMetrics').mockResolvedValue(mockMetrics);
// Mock the static validateProjectRepository method (line 2939)
// This validation is bypassed because we're testing other aspects of the validation flow
vi.spyOn(DeepSourceClient, 'validateProjectRepository').mockImplementation(() => {
// Intentionally empty - validation is not the focus of this test
// We're just preventing it from throwing errors
});
// Call the method and expect it to throw
await expect(
client.testValidateAndGetMetricInfo({
projectKey: PROJECT_KEY,
metricShortcode: MetricShortcode.LCV,
metricKey: MetricKey.AGGREGATE,
})
).rejects.toThrow(`Metric with shortcode ${MetricShortcode.LCV} not found in project`);
// Verify the method calls
expect(client.listProjects).toHaveBeenCalled(); // line 2931
expect(DeepSourceClient.validateProjectRepository).toHaveBeenCalled(); // line 2939
expect(client.getQualityMetrics).toHaveBeenCalled(); // line 2942
});
it('should throw error when metric item is not found (line 2952)', async () => {
// Mock the projects response
const mockProjects = [
{
key: PROJECT_KEY,
name: 'Test Project',
repository: {
id: 'repo123',
login: 'testorg',
provider: 'github',
},
},
];
// Mock metrics response with no items for the specific key
const mockMetrics = [
{
shortcode: MetricShortcode.LCV,
name: 'Line Coverage',
items: [
{
id: 'metric123',
key: 'DIFFERENT_KEY', // Different from what we're looking for
threshold: 80,
},
],
},
];
// Mock the listProjects method to return our mock data (line 2931)
vi.spyOn(client, 'listProjects').mockResolvedValue(mockProjects);
// Mock the getQualityMetrics method to return our mock data (line 2942)
vi.spyOn(client, 'getQualityMetrics').mockResolvedValue(mockMetrics);
// Mock the static validateProjectRepository method (line 2939)
// This validation is bypassed because we're testing other aspects of the validation flow
vi.spyOn(DeepSourceClient, 'validateProjectRepository').mockImplementation(() => {
// Intentionally empty - validation is not the focus of this test
// We're just preventing it from throwing errors
});
// Call the method and expect it to throw
await expect(
client.testValidateAndGetMetricInfo({
projectKey: PROJECT_KEY,
metricShortcode: MetricShortcode.LCV,
metricKey: MetricKey.AGGREGATE,
})
).rejects.toThrow(
`Metric item with key ${MetricKey.AGGREGATE} not found in metric ${MetricShortcode.LCV}`
);
// Verify the method calls
expect(client.listProjects).toHaveBeenCalled(); // line 2931
expect(DeepSourceClient.validateProjectRepository).toHaveBeenCalled(); // line 2939
expect(client.getQualityMetrics).toHaveBeenCalled(); // line 2942
});
});
});