Files
renovate/lib/modules/platform/azure/azure-helper.spec.ts
Sebastian Poxhofer 05e1271376 test: use expect().resolves instead of awaiting inside expect (#45672)
Enables the vitest/prefer-expect-resolves oxlint rule and applies its
autofix across the spec suite.
2026-09-04 10:40:46 +00:00

538 lines
15 KiB
TypeScript

import { Readable } from 'node:stream';
import type { ICoreApi } from 'azure-devops-node-api/CoreApi.js';
import type { IGitApi } from 'azure-devops-node-api/GitApi.js';
import { GitPullRequestMergeStrategy } from 'azure-devops-node-api/interfaces/GitInterfaces.js';
import type { PolicyConfiguration } from 'azure-devops-node-api/interfaces/PolicyInterfaces.js';
import type { IPolicyApi } from 'azure-devops-node-api/PolicyApi.js';
import type { MockedObject } from 'vitest';
import { mockDeep } from 'vitest-mock-extended';
import { partial } from '~test/util.ts';
vi.mock('./azure-got-wrapper.ts', () => mockDeep());
describe('modules/platform/azure/azure-helper', () => {
let azureHelper: typeof import('./azure-helper.ts');
let azureApi: MockedObject<typeof import('./azure-got-wrapper.ts')>;
beforeEach(async () => {
// reset module
vi.resetModules();
azureHelper = await vi.importActual('./azure-helper.ts');
azureApi = await vi.importMock('./azure-got-wrapper.ts');
});
describe('getRef', () => {
it('should get the ref with short ref name', async () => {
azureApi.gitApi.mockResolvedValueOnce(
partial<IGitApi>({
getRefs: vi.fn().mockResolvedValue([{ objectId: 132 }]),
}),
);
const res = await azureHelper.getRefs('123', 'branch');
expect(res).toEqual([
{
objectId: 132,
},
]);
});
it('should not get ref', async () => {
azureApi.gitApi.mockResolvedValueOnce(
partial<IGitApi>({
getRefs: vi.fn().mockResolvedValue([]),
}),
);
const res = await azureHelper.getRefs('123');
expect(res).toHaveLength(0);
});
it('should get the ref with full ref name', async () => {
azureApi.gitApi.mockResolvedValueOnce(
partial<IGitApi>({
getRefs: vi.fn().mockResolvedValue([{ objectId: '132' }]),
}),
);
const res = await azureHelper.getRefs('123', 'refs/head/branch1');
expect(res).toEqual([
{
objectId: '132',
},
]);
});
});
describe('getAzureBranchObj', () => {
it('should get the branch object', async () => {
azureApi.gitApi.mockResolvedValueOnce(
partial<IGitApi>({
getRefs: vi.fn().mockResolvedValue([{ objectId: '132' }]),
}),
);
const res = await azureHelper.getAzureBranchObj(
'123',
'branchName',
'base',
);
expect(res).toEqual({
name: 'refs/heads/branchName',
oldObjectId: '132',
});
});
it('should get the branch object when ref missing', async () => {
azureApi.gitApi.mockResolvedValueOnce(
partial<IGitApi>({
getRefs: vi.fn().mockResolvedValue([]),
}),
);
const res = await azureHelper.getAzureBranchObj('123', 'branchName');
expect(res).toEqual({
name: 'refs/heads/branchName',
oldObjectId: '0000000000000000000000000000000000000000',
});
});
});
describe('getFile', () => {
it('should return null error GitItemNotFoundException', async () => {
let eventCount = 0;
const mockEventStream = new Readable({
objectMode: true,
read() {
if (eventCount < 1) {
eventCount += 1;
return this.push('{"typeKey": "GitItemNotFoundException"}');
}
return this.push(null);
},
});
azureApi.gitApi.mockResolvedValueOnce(
partial<IGitApi>({
getItemText: vi.fn().mockResolvedValue(mockEventStream),
}),
);
const res = await azureHelper.getFile(
'123',
'repository',
'./myFilePath/test',
);
expect(res).toBeNull();
});
it('should return null error GitUnresolvableToCommitException', async () => {
let eventCount = 0;
const mockEventStream = new Readable({
objectMode: true,
read() {
if (eventCount < 1) {
eventCount += 1;
return this.push('{"typeKey": "GitUnresolvableToCommitException"}');
}
return this.push(null);
},
});
azureApi.gitApi.mockResolvedValueOnce(
partial<IGitApi>({
getItemText: vi.fn().mockResolvedValue(mockEventStream),
}),
);
const res = await azureHelper.getFile(
'123',
'repository',
'./myFilePath/test',
);
expect(res).toBeNull();
});
it('should return the file content because it is not a json', async () => {
let eventCount = 0;
const mockEventStream = new Readable({
objectMode: true,
read() {
if (eventCount < 1) {
eventCount += 1;
return this.push('{"hello"= "test"}');
}
return this.push(null);
},
});
azureApi.gitApi.mockResolvedValueOnce(
partial<IGitApi>({
getItemText: vi.fn().mockResolvedValue(mockEventStream),
}),
);
const res = await azureHelper.getFile(
'123',
'repository',
'./myFilePath/test',
);
expect(res).toBe('{"hello"= "test"}');
});
it('should return null because the file is not readable', async () => {
azureApi.gitApi.mockResolvedValueOnce(
partial<IGitApi>({
getItemText: vi.fn().mockResolvedValue({
readable: false,
}),
}),
);
const res = await azureHelper.getFile(
'123',
'repository',
'./myFilePath/test',
);
expect(res).toBeNull();
});
});
describe('getCommitDetails', () => {
it('should get commit details', async () => {
azureApi.gitApi.mockResolvedValueOnce(
partial<IGitApi>({
getCommit: vi.fn().mockResolvedValue({
parents: ['123456'],
}),
}),
);
const res = await azureHelper.getCommitDetails('123', '123456');
expect(res).toEqual({
parents: ['123456'],
});
});
});
describe('getMergeMethod', () => {
it('should default to NoFastForward', async () => {
azureApi.policyApi.mockResolvedValueOnce(
partial<IPolicyApi>({
getPolicyConfigurations: vi.fn().mockResolvedValue([]),
}),
);
await expect(azureHelper.getMergeMethod('', '')).resolves.toEqual(
GitPullRequestMergeStrategy.NoFastForward,
);
});
it('should return NoFastForward when policy explicitly set', async () => {
azureApi.policyApi.mockResolvedValueOnce(
partial<IPolicyApi>({
getPolicyConfigurations: vi.fn().mockResolvedValue([
{
settings: {
allowNoFastForward: true,
scope: [
{
repositoryId: '',
},
],
},
type: {
id: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
},
},
]),
}),
);
await expect(azureHelper.getMergeMethod('', '')).resolves.toEqual(
GitPullRequestMergeStrategy.NoFastForward,
);
});
it('should return RebaseMerge', async () => {
azureApi.policyApi.mockResolvedValueOnce(
partial<IPolicyApi>({
getPolicyConfigurations: vi.fn().mockResolvedValue([
{
settings: {
allowRebaseMerge: true,
scope: [
{
repositoryId: '',
},
],
},
type: {
id: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
},
},
]),
}),
);
await expect(azureHelper.getMergeMethod('', '')).resolves.toEqual(
GitPullRequestMergeStrategy.RebaseMerge,
);
});
it('should return Squash', async () => {
azureApi.policyApi.mockResolvedValueOnce(
partial<IPolicyApi>({
getPolicyConfigurations: vi.fn().mockResolvedValue([
{
settings: {
allowSquash: true,
scope: [
{
repositoryId: '',
},
],
},
type: {
id: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
},
},
]),
}),
);
await expect(azureHelper.getMergeMethod('', '')).resolves.toEqual(
GitPullRequestMergeStrategy.Squash,
);
});
it('should return Squash when Project wide exact branch policy exists', async () => {
const refMock = 'refs/heads/ding';
azureApi.policyApi.mockResolvedValueOnce(
partial<IPolicyApi>({
getPolicyConfigurations: vi.fn(() =>
Promise.resolve([
partial<PolicyConfiguration>({
settings: {
allowSquash: true,
scope: [
{
// null here means project wide
repositoryId: null,
matchKind: 'Exact',
refName: refMock,
},
],
},
}),
]),
),
}),
);
await expect(
azureHelper.getMergeMethod('', '', refMock),
).resolves.toEqual(GitPullRequestMergeStrategy.Squash);
});
it('should return default branch policy', async () => {
azureApi.policyApi.mockResolvedValueOnce(
partial<IPolicyApi>({
getPolicyConfigurations: vi.fn().mockResolvedValue([
{
settings: {
allowSquash: true,
scope: [
{
repositoryId: 'doo-dee-doo-repository-id',
},
],
},
type: {
id: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
},
},
{
settings: {
allowRebase: true,
scope: [
{
matchKind: 'DefaultBranch',
},
],
},
type: {
id: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
},
},
]),
}),
);
await expect(azureHelper.getMergeMethod('', '')).resolves.toEqual(
GitPullRequestMergeStrategy.Rebase,
);
});
it('should return most specific exact branch policy', async () => {
const refMock = 'refs/heads/ding';
const defaultBranchMock = 'dong';
azureApi.policyApi.mockResolvedValueOnce(
partial<IPolicyApi>({
getPolicyConfigurations: vi.fn().mockResolvedValue([
{
settings: {
allowSquash: true,
scope: [
{
repositoryId: 'doo-dee-doo-repository-id',
},
],
},
type: {
id: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
},
},
{
settings: {
allowSquash: true,
scope: [
{
repositoryId: '',
},
],
},
type: {
id: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
},
},
{
settings: {
allowSquash: true,
scope: [
{
matchKind: 'DefaultBranch',
},
],
},
type: {
id: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
},
},
{
settings: {
allowRebase: true,
scope: [
{
matchKind: 'Exact',
refName: refMock,
repositoryId: '',
},
],
},
type: {
id: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
},
},
]),
}),
);
await expect(
azureHelper.getMergeMethod('', '', refMock, defaultBranchMock),
).resolves.toEqual(GitPullRequestMergeStrategy.Rebase);
});
it('should return most specific prefix branch policy', async () => {
const refMock = 'refs/heads/ding-wow';
const defaultBranchMock = 'dong-wow';
azureApi.policyApi.mockResolvedValueOnce(
partial<IPolicyApi>({
getPolicyConfigurations: vi.fn().mockResolvedValue([
{
settings: {
allowSquash: true,
scope: [
{
repositoryId: '',
},
],
},
type: {
id: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
},
},
{
settings: {
allowSquash: true,
scope: [
{
matchKind: 'DefaultBranch',
},
],
},
type: {
id: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
},
},
{
settings: {
allowRebase: true,
scope: [
{
matchKind: 'Prefix',
refName: 'refs/heads/ding',
repositoryId: '',
},
],
},
type: {
id: 'fa4e907d-c16b-4a4c-9dfa-4916e5d171ab',
},
},
]),
}),
);
await expect(
azureHelper.getMergeMethod('', '', refMock, defaultBranchMock),
).resolves.toEqual(GitPullRequestMergeStrategy.Rebase);
});
});
describe('getPolicyEvaluations', () => {
it('should get the policy evaluations for a pull request', async () => {
const policyEvaluations = [{ status: 2 }];
const getPolicyEvaluationsMock = vi
.fn()
.mockResolvedValue(policyEvaluations);
azureApi.policyApi.mockResolvedValueOnce(
partial<IPolicyApi>({
getPolicyEvaluations: getPolicyEvaluationsMock,
}),
);
const res = await azureHelper.getPolicyEvaluations(
'projectId',
'artifactId',
);
expect(getPolicyEvaluationsMock).toHaveBeenCalledWith(
'projectId',
'artifactId',
);
expect(res).toEqual(policyEvaluations);
});
});
describe('getAllProjectTeams', () => {
it('should get all teams', async () => {
const team1 = Array.from({ length: 100 }, (_, index) => ({
description: `team1 ${index + 1}`,
}));
const team2 = Array.from({ length: 3 }, (_, index) => ({
description: `team2 ${index + 1}`,
}));
const allTeams = team1.concat(team2);
azureApi.coreApi.mockResolvedValueOnce(
partial<ICoreApi>({
getTeams: vi
.fn()
.mockResolvedValueOnce(team1)
.mockResolvedValueOnce(team2),
}),
);
const res = await azureHelper.getAllProjectTeams('projectId');
expect(res).toEqual(allTeams);
});
});
});