Files
renovate/lib/modules/manager/cocoapods/artifacts.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

318 lines
11 KiB
TypeScript

import upath from 'upath';
import { mockDeep } from 'vitest-mock-extended';
import { envMock, mockExecAll } from '~test/exec-util.ts';
import { env, fs, git, partial } from '~test/util.ts';
import { GlobalConfig } from '../../../config/global.ts';
import type {
InternalGlobalConfigOptions,
RepoGlobalConfig,
} from '../../../config/types.ts';
import * as docker from '../../../util/exec/docker/index.ts';
import type { StatusResult } from '../../../util/git/types.ts';
import * as _datasource from '../../datasource/index.ts';
import type { UpdateArtifactsConfig } from '../types.ts';
import { updateArtifacts } from './index.ts';
vi.mock('../../../util/exec/env.ts');
vi.mock('../../../util/fs/index.ts');
vi.mock('../../datasource/index.ts', () => mockDeep());
const datasource = vi.mocked(_datasource);
delete process.env.CP_HOME_DIR;
process.env.CONTAINERBASE = 'true';
const config: UpdateArtifactsConfig = {};
const adminConfig: RepoGlobalConfig & InternalGlobalConfigOptions = {
localDir: upath.join('/tmp/github/some/repo'),
cacheDir: upath.join('/tmp/cache'),
containerbaseDir: upath.join('/tmp/cache/containerbase'),
dockerSidecarImage: 'ghcr.io/renovatebot/base-image',
binarySource: 'global',
};
describe('modules/manager/cocoapods/artifacts', () => {
beforeEach(() => {
env.getChildProcessEnv.mockReturnValue(envMock.basic);
vi.spyOn(docker, 'removeDockerContainer').mockResolvedValue();
// can't be mocked
docker.resetPrefetchedImages();
GlobalConfig.set(adminConfig);
// ruby
datasource.getPkgReleases.mockResolvedValue({
releases: [
{ version: '2.7.4' },
{ version: '3.0.0' },
{ version: '3.1.0' },
],
});
});
afterEach(() => {
GlobalConfig.reset();
});
it('returns null if no Podfile.lock found', async () => {
const execSnapshots = mockExecAll();
await expect(
updateArtifacts({
packageFileName: 'Podfile',
updatedDeps: [{ depName: 'foo' }],
newPackageFileContent: '',
config,
}),
).resolves.toBeNull();
expect(execSnapshots).toEqual([]);
});
it('returns null if no updatedDeps were provided', async () => {
const execSnapshots = mockExecAll();
await expect(
updateArtifacts({
packageFileName: 'Podfile',
updatedDeps: [],
newPackageFileContent: '',
config,
}),
).resolves.toBeNull();
expect(execSnapshots).toEqual([]);
});
it('returns null for invalid local directory', async () => {
const execSnapshots = mockExecAll();
GlobalConfig.set({
localDir: '',
});
await expect(
updateArtifacts({
packageFileName: 'Podfile',
updatedDeps: [{ depName: 'foo' }],
newPackageFileContent: '',
config: {},
}),
).resolves.toBeNull();
expect(execSnapshots).toEqual([]);
});
it('returns null if updatedDeps is empty', async () => {
const execSnapshots = mockExecAll();
await expect(
updateArtifacts({
packageFileName: 'Podfile',
updatedDeps: [],
newPackageFileContent: '',
config,
}),
).resolves.toBeNull();
expect(execSnapshots).toEqual([]);
});
it('returns null if unchanged', async () => {
const execSnapshots = mockExecAll();
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile.lock');
fs.readLocalFile.mockResolvedValueOnce('Current Podfile');
git.getRepoStatus.mockResolvedValueOnce(
partial<StatusResult>({
modified: [],
}),
);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile.lock');
fs.readLocalFile.mockResolvedValueOnce('Current Podfile');
await expect(
updateArtifacts({
packageFileName: 'Podfile',
updatedDeps: [{ depName: 'foo' }],
newPackageFileContent: '',
config,
}),
).resolves.toBeNull();
expect(execSnapshots).toMatchObject([{ cmd: 'pod install' }]);
});
it('returns updated Podfile', async () => {
const execSnapshots = mockExecAll();
GlobalConfig.set({ ...adminConfig, binarySource: 'docker' });
fs.getSiblingFileName.mockReturnValueOnce('Podfile.lock');
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile');
fs.readLocalFile.mockResolvedValueOnce('Old Podfile');
git.getRepoStatus.mockResolvedValueOnce(
partial<StatusResult>({
modified: ['Podfile.lock'],
}),
);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile');
fs.readLocalFile.mockResolvedValueOnce('New Podfile');
await expect(
updateArtifacts({
packageFileName: 'Podfile',
updatedDeps: [{ depName: 'foo' }],
newPackageFileContent: 'plugin "cocoapods-acknowledgements"',
config,
}),
).resolves.toMatchObject([{ file: { contents: 'New Podfile' } }]);
expect(execSnapshots).toMatchObject([
{ cmd: 'docker pull ghcr.io/renovatebot/base-image' },
{
cmd: 'docker run --rm --name=renovate_sidecar --label=renovate_child -v "/tmp/github/some/repo":"/tmp/github/some/repo" -v "/tmp/cache":"/tmp/cache" -e CI -e CONTAINERBASE_CACHE_DIR -w "/tmp/github/some/repo" ghcr.io/renovatebot/base-image bash -l -c \'install-tool ruby 3.1.0 && install-tool cocoapods 3.1.0 && gem install cocoapods-acknowledgements && pod install\'',
},
]);
});
it('returns updated Podfile and Pods files', async () => {
const execSnapshots = mockExecAll();
GlobalConfig.set({ ...adminConfig, binarySource: 'docker' });
fs.getSiblingFileName.mockReturnValueOnce('Podfile.lock');
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile.lock');
fs.readLocalFile.mockResolvedValueOnce('Old Manifest.lock');
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile.lock');
fs.readLocalFile.mockResolvedValueOnce('New Podfile');
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Pods/Manifest.lock');
fs.readLocalFile.mockResolvedValueOnce('Pods manifest');
git.getRepoStatus.mockResolvedValueOnce(
partial<StatusResult>({
not_added: ['Pods/New'],
modified: ['Podfile.lock', 'Pods/Manifest.lock'],
deleted: ['Pods/Deleted'],
}),
);
await expect(
updateArtifacts({
packageFileName: 'Podfile',
updatedDeps: [{ depName: 'foo' }],
newPackageFileContent: '',
config,
}),
).resolves.toMatchObject([
{ file: { type: 'addition', path: 'Podfile.lock' } },
{ file: { type: 'addition', path: 'Pods/Manifest.lock' } },
{ file: { type: 'addition', path: 'Pods/New' } },
{ file: { type: 'deletion', path: 'Pods/Deleted' } },
]);
expect(execSnapshots).toMatchObject([
{ cmd: 'docker pull ghcr.io/renovatebot/base-image' },
{
cmd: 'docker run --rm --name=renovate_sidecar --label=renovate_child -v "/tmp/github/some/repo":"/tmp/github/some/repo" -v "/tmp/cache":"/tmp/cache" -e CI -e CONTAINERBASE_CACHE_DIR -w "/tmp/github/some/repo" ghcr.io/renovatebot/base-image bash -l -c \'install-tool ruby 3.1.0 && install-tool cocoapods 3.1.0 && pod install\'',
},
]);
});
it('catches write error', async () => {
const execSnapshots = mockExecAll();
fs.getSiblingFileName.mockReturnValueOnce('Podfile.lock');
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile.lock');
fs.readLocalFile.mockResolvedValueOnce('Current Podfile');
fs.writeLocalFile.mockImplementationOnce(() => {
throw new Error('not found');
});
await expect(
updateArtifacts({
packageFileName: 'Podfile',
updatedDeps: [{ depName: 'foo' }],
newPackageFileContent: '',
config,
}),
).resolves.toEqual([
{ artifactError: { fileName: 'Podfile.lock', stderr: 'not found' } },
]);
expect(execSnapshots).toBeEmpty();
});
it('returns pod exec error', async () => {
const execSnapshots = mockExecAll(new Error('exec exception'));
fs.getSiblingFileName.mockReturnValueOnce('Podfile.lock');
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile.lock');
fs.readLocalFile.mockResolvedValueOnce('Old Podfile.lock');
fs.outputCacheFile.mockResolvedValueOnce();
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile.lock');
fs.readLocalFile.mockResolvedValueOnce('Old Podfile.lock');
await expect(
updateArtifacts({
packageFileName: 'Podfile',
updatedDeps: [{ depName: 'foo' }],
newPackageFileContent: '',
config,
}),
).resolves.toEqual([
{ artifactError: { fileName: 'Podfile.lock', stderr: 'exec exception' } },
]);
expect(execSnapshots).toMatchObject([{ cmd: 'pod install' }]);
});
it('dynamically selects Docker image tag', async () => {
const execSnapshots = mockExecAll();
GlobalConfig.set({ ...adminConfig, binarySource: 'docker' });
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile.lock');
fs.readLocalFile.mockResolvedValueOnce('COCOAPODS: 1.2.4');
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile.lock');
fs.readLocalFile.mockResolvedValueOnce('New Podfile');
git.getRepoStatus.mockResolvedValueOnce(
partial<StatusResult>({
modified: ['Podfile.lock'],
}),
);
await updateArtifacts({
packageFileName: 'Podfile',
updatedDeps: [{ depName: 'foo' }],
newPackageFileContent: '',
config,
});
expect(execSnapshots).toMatchObject([
{ cmd: 'docker pull ghcr.io/renovatebot/base-image' },
{
cmd:
'docker run --rm --name=renovate_sidecar --label=renovate_child ' +
'-v "/tmp/github/some/repo":"/tmp/github/some/repo" ' +
'-v "/tmp/cache":"/tmp/cache" ' +
'-e CI ' +
'-e CONTAINERBASE_CACHE_DIR ' +
'-w "/tmp/github/some/repo" ' +
'ghcr.io/renovatebot/base-image' +
" bash -l -c '" +
'install-tool ruby 3.1.0' +
' && ' +
'install-tool cocoapods 1.2.4' +
' && ' +
'pod install' +
"'",
},
]);
});
it('supports install mode', async () => {
const execSnapshots = mockExecAll();
GlobalConfig.set({ ...adminConfig, binarySource: 'install' });
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile.lock');
fs.readLocalFile.mockResolvedValueOnce('COCOAPODS: 1.2.4');
fs.findLocalSiblingOrParent.mockResolvedValueOnce('Podfile.lock');
fs.readLocalFile.mockResolvedValueOnce('New Podfile');
git.getRepoStatus.mockResolvedValueOnce(
partial<StatusResult>({
modified: ['Podfile.lock'],
}),
);
await updateArtifacts({
packageFileName: 'Podfile',
updatedDeps: [{ depName: 'foo' }],
newPackageFileContent: '',
config,
});
expect(execSnapshots).toMatchObject([
{ cmd: 'install-tool ruby 3.1.0' },
{ cmd: 'install-tool cocoapods 1.2.4' },
{ cmd: 'pod install' },
]);
});
});