Files
Sebastian Poxhofer 5ad36a2387 test(linters): add linting rule to enforce usage of host rules test util (#44692)
* ci(linter): add renovate/no-host-rules-mock rule

Flags vi.mock()/vi.doMock() calls whose module specifier contains
"host-rules" in spec files. Tests should configure real rules via
hostRules.add() instead of mocking the host-rules module.

Enabled at "warn" severity instead of "error": the repo currently has
35 pre-existing violations across 34 spec files, which exceeds the
agreed fix threshold of 12 files. No violation fixes are included;
migrating each spec to real hostRules.add()/clear() setup is a
semantic test rewrite that should be done incrementally, after which
the rule can be promoted to "error".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci(linter): enforce renovate/no-host-rules-mock at error

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(datasource): use real host-rules instead of mocking

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(manager): use real host-rules instead of mocking

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(platform): use real host-rules instead of mocking

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(util,workers): use real host-rules instead of mocking

Also narrow renovate/no-host-rules-mock to the host-rules module itself so that mocking e.g. host-rules-from-env is not flagged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci(linter): mention '~test/host-rules.ts' util in no-host-rules-mock message

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 10:36:12 +00:00

149 lines
4.5 KiB
TypeScript

import { hostRules } from '~test/host-rules.ts';
import * as githubGraphql from '../../../util/github/graphql/index.ts';
import type { Timestamp } from '../../../util/timestamp.ts';
import { getDigest, getPkgReleases } from '../index.ts';
import { GithubReleaseAttachmentsDatasource } from './index.ts';
import { GitHubReleaseAttachmentMocker } from './test/index.ts';
const githubApiHost = 'https://api.github.com';
describe('modules/datasource/github-release-attachments/index', () => {
beforeEach(() => {
hostRules.add({ token: 'some-token' });
});
describe('getReleases', () => {
it('returns releases', async () => {
vi.spyOn(githubGraphql, 'queryReleases').mockResolvedValueOnce([
{
id: 1,
url: 'https://example.com',
name: 'some/dep2',
description: 'some description',
version: 'a',
releaseTimestamp: '2020-03-09T13:00:00Z' as Timestamp,
},
{
id: 2,
url: 'https://example.com',
name: 'some/dep2',
description: 'some description',
version: 'v',
releaseTimestamp: '2020-03-09T12:00:00Z' as Timestamp,
},
{
id: 3,
url: 'https://example.com',
name: 'some/dep2',
description: 'some description',
version: '1.0.0',
releaseTimestamp: '2020-03-09T11:00:00Z' as Timestamp,
},
{
id: 4,
url: 'https://example.com',
name: 'some/dep2',
description: 'some description',
version: 'v1.1.0',
releaseTimestamp: '2020-03-09T10:00:00Z' as Timestamp,
},
{
id: 5,
url: 'https://example.com',
name: 'some/dep2',
description: 'some description',
version: '2.0.0',
releaseTimestamp: '2020-04-09T10:00:00Z' as Timestamp,
isStable: false,
},
]);
const res = await getPkgReleases({
datasource: GithubReleaseAttachmentsDatasource.id,
packageName: 'some/dep',
});
expect(res).toMatchObject({
registryUrl: 'https://github.com',
releases: [
{ releaseTimestamp: '2020-03-09T11:00:00.000Z', version: '1.0.0' },
{ version: 'v1.1.0', releaseTimestamp: '2020-03-09T10:00:00.000Z' },
{
version: '2.0.0',
releaseTimestamp: '2020-04-09T10:00:00.000Z',
isStable: false,
},
],
sourceUrl: 'https://github.com/some/dep',
});
});
});
describe('getDigest', () => {
const packageName = 'some/dep';
const currentValue = 'v1.0.0';
const currentDigest = 'v1.0.0-digest';
const releaseMock = new GitHubReleaseAttachmentMocker(
githubApiHost,
packageName,
);
it('requires currentDigest', async () => {
const digest = await getDigest(
{ datasource: GithubReleaseAttachmentsDatasource.id, packageName },
currentValue,
);
expect(digest).toBeNull();
});
it('defaults to currentDigest when currentVersion is missing', async () => {
const digest = await getDigest(
{
datasource: GithubReleaseAttachmentsDatasource.id,
packageName,
currentDigest,
},
currentValue,
);
expect(digest).toEqual(currentDigest);
});
it('returns updated digest in new release', async () => {
releaseMock.withDigestFileAsset(
currentValue,
`${currentDigest} asset.zip`,
);
const nextValue = 'v1.0.1';
const nextDigest = 'updated-digest';
releaseMock.withDigestFileAsset(nextValue, `${nextDigest} asset.zip`);
const digest = await getDigest(
{
datasource: GithubReleaseAttachmentsDatasource.id,
packageName,
currentValue,
currentDigest,
},
nextValue,
);
expect(digest).toEqual(nextDigest);
});
// This is awkward, but I found returning `null` in this case to not produce an update
// I'd prefer a PR with the old digest (that I can manually patch) to no PR, so I made this decision.
it('ignores failures verifying currentDigest', async () => {
releaseMock.release(currentValue);
const digest = await getDigest(
{
datasource: GithubReleaseAttachmentsDatasource.id,
packageName,
currentValue,
currentDigest,
},
currentValue,
);
expect(digest).toEqual(currentDigest);
});
});
});