mirror of
https://github.com/renovatebot/renovate.git
synced 2026-11-03 02:53:40 +00:00
05e1271376
Enables the vitest/prefer-expect-resolves oxlint rule and applies its autofix across the spec suite.
342 lines
9.9 KiB
TypeScript
342 lines
9.9 KiB
TypeScript
import * as httpMock from '~test/http-mock.ts';
|
|
import { logger } from '~test/util.ts';
|
|
import * as hostRules from '../host-rules.ts';
|
|
import { range } from '../range.ts';
|
|
import { BitbucketHttp, setBaseUrl } from './bitbucket.ts';
|
|
|
|
const baseUrl = 'https://api.bitbucket.org';
|
|
|
|
describe('util/http/bitbucket', () => {
|
|
let api: BitbucketHttp;
|
|
|
|
beforeEach(() => {
|
|
api = new BitbucketHttp();
|
|
|
|
// clean up hostRules
|
|
hostRules.clear();
|
|
hostRules.add({
|
|
hostType: 'bitbucket',
|
|
matchHost: baseUrl,
|
|
token: 'token',
|
|
});
|
|
|
|
setBaseUrl(baseUrl);
|
|
});
|
|
|
|
it('posts', async () => {
|
|
const body = ['a', 'b'];
|
|
httpMock.scope(baseUrl).post('/some-url').reply(200, body);
|
|
const res = await api.postJson('some-url');
|
|
expect(res.body).toEqual(body);
|
|
});
|
|
|
|
it('accepts custom baseUrl', async () => {
|
|
const customBaseUrl = 'https://api-test.bitbucket.org';
|
|
httpMock.scope(baseUrl).post('/some-url').reply(200, {});
|
|
httpMock.scope(customBaseUrl).post('/some-url').reply(200, {});
|
|
|
|
await expect(api.postJson('some-url')).resolves.toEqual({
|
|
authorization: true,
|
|
body: {},
|
|
headers: {
|
|
'content-type': 'application/json',
|
|
},
|
|
statusCode: 200,
|
|
});
|
|
|
|
setBaseUrl(customBaseUrl);
|
|
await expect(api.postJson('some-url')).resolves.toEqual({
|
|
authorization: false,
|
|
body: {},
|
|
headers: {
|
|
'content-type': 'application/json',
|
|
},
|
|
statusCode: 200,
|
|
});
|
|
});
|
|
|
|
it('warns when an endpoint announces a deprecation', async () => {
|
|
httpMock.scope(baseUrl).get('/some-url').reply(
|
|
200,
|
|
{},
|
|
{
|
|
deprecation: '@1771545600',
|
|
sunset: 'Fri, 21 Aug 2026 00:00:00 UTC',
|
|
link: '<https://developer.atlassian.com/cloud/bitbucket/changelog#CHANGE-3071>; rel="deprecation"; type="text/html"',
|
|
},
|
|
);
|
|
|
|
await api.getJsonUnchecked('some-url');
|
|
|
|
expect(logger.logger.once.warn).toHaveBeenCalledWith(
|
|
{
|
|
url: `${baseUrl}/some-url`,
|
|
deprecation: '2026-02-20T00:00:00.000Z',
|
|
sunset: '2026-08-21T00:00:00.000Z',
|
|
announcementUrl:
|
|
'https://developer.atlassian.com/cloud/bitbucket/changelog#CHANGE-3071',
|
|
},
|
|
'Bitbucket API endpoint has been marked as deprecated',
|
|
);
|
|
});
|
|
|
|
it('warns when only a sunset is announced', async () => {
|
|
httpMock
|
|
.scope(baseUrl)
|
|
.get('/some-url')
|
|
.reply(200, {}, { sunset: 'Fri, 21 Aug 2026 00:00:00 UTC' });
|
|
|
|
await api.getJsonUnchecked('some-url');
|
|
|
|
expect(logger.logger.once.warn).toHaveBeenCalledWith(
|
|
{
|
|
url: `${baseUrl}/some-url`,
|
|
deprecation: undefined,
|
|
sunset: '2026-08-21T00:00:00.000Z',
|
|
announcementUrl: undefined,
|
|
},
|
|
'Bitbucket API endpoint has been marked as deprecated',
|
|
);
|
|
});
|
|
|
|
it('formats HTTP dates which are already spec compliant', async () => {
|
|
httpMock
|
|
.scope(baseUrl)
|
|
.get('/some-url')
|
|
.reply(200, {}, { deprecation: 'Sun, 11 Nov 2018 23:59:59 GMT' });
|
|
|
|
await api.getJsonUnchecked('some-url');
|
|
|
|
expect(logger.logger.once.warn).toHaveBeenCalledWith(
|
|
expect.objectContaining({ deprecation: '2018-11-11T23:59:59.000Z' }),
|
|
'Bitbucket API endpoint has been marked as deprecated',
|
|
);
|
|
});
|
|
|
|
it('passes through values it cannot format', async () => {
|
|
httpMock
|
|
.scope(baseUrl)
|
|
.get('/some-url')
|
|
.reply(200, {}, { deprecation: '@99999999999999999999' })
|
|
.get('/other-url')
|
|
.reply(200, {}, { sunset: 'not a date' });
|
|
|
|
await api.getJsonUnchecked('some-url');
|
|
await api.getJsonUnchecked('other-url');
|
|
|
|
expect(logger.logger.once.warn).toHaveBeenCalledWith(
|
|
expect.objectContaining({ deprecation: '@99999999999999999999' }),
|
|
'Bitbucket API endpoint has been marked as deprecated',
|
|
);
|
|
expect(logger.logger.once.warn).toHaveBeenCalledWith(
|
|
expect.objectContaining({ sunset: 'not a date' }),
|
|
'Bitbucket API endpoint has been marked as deprecated',
|
|
);
|
|
});
|
|
|
|
it('does not warn when no deprecation is announced', async () => {
|
|
httpMock.scope(baseUrl).get('/some-url').reply(200, {});
|
|
|
|
await api.getJsonUnchecked('some-url');
|
|
|
|
expect(logger.logger.once.warn).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('warns about deprecated functionality', async () => {
|
|
httpMock
|
|
.scope(baseUrl)
|
|
.get('/some-url')
|
|
.reply(410, {
|
|
type: 'error',
|
|
error: {
|
|
message: 'CHANGE-3071 - Functionality has been deprecated',
|
|
detail: 'Please read the changelog entry for more details.',
|
|
data: {
|
|
announcement_url:
|
|
'https://developer.atlassian.com/cloud/bitbucket/changelog#CHANGE-3071',
|
|
},
|
|
},
|
|
});
|
|
|
|
await expect(api.getJsonUnchecked('some-url')).rejects.toThrow(
|
|
'Request failed with status code 410 (Gone)',
|
|
);
|
|
|
|
expect(logger.logger.once.warn).toHaveBeenCalledWith(
|
|
{
|
|
url: `${baseUrl}/some-url`,
|
|
message: 'CHANGE-3071 - Functionality has been deprecated',
|
|
detail: 'Please read the changelog entry for more details.',
|
|
announcementUrl:
|
|
'https://developer.atlassian.com/cloud/bitbucket/changelog#CHANGE-3071',
|
|
},
|
|
'Bitbucket API functionality has been deprecated or removed',
|
|
);
|
|
});
|
|
|
|
it('warns about deprecated functionality for non-JSON responses', async () => {
|
|
httpMock
|
|
.scope(baseUrl)
|
|
.get('/some-url')
|
|
.reply(
|
|
410,
|
|
JSON.stringify({
|
|
error: {
|
|
message: 'CHANGE-3071 - Functionality has been deprecated',
|
|
data: {
|
|
announcement_url:
|
|
'https://developer.atlassian.com/cloud/bitbucket/changelog#CHANGE-3071',
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
|
|
await expect(api.get('some-url')).rejects.toThrow(
|
|
'Request failed with status code 410 (Gone)',
|
|
);
|
|
|
|
expect(logger.logger.once.warn).toHaveBeenCalledWith(
|
|
{
|
|
url: `${baseUrl}/some-url`,
|
|
message: 'CHANGE-3071 - Functionality has been deprecated',
|
|
detail: undefined,
|
|
announcementUrl:
|
|
'https://developer.atlassian.com/cloud/bitbucket/changelog#CHANGE-3071',
|
|
},
|
|
'Bitbucket API functionality has been deprecated or removed',
|
|
);
|
|
});
|
|
|
|
it('does not warn when the request failed without a response', async () => {
|
|
httpMock.scope(baseUrl).get('/some-url').replyWithError('some error');
|
|
|
|
await expect(api.getJsonUnchecked('some-url')).rejects.toThrow(
|
|
'some error',
|
|
);
|
|
|
|
expect(logger.logger.once.warn).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('does not warn for unrelated errors', async () => {
|
|
httpMock
|
|
.scope(baseUrl)
|
|
.get('/some-url')
|
|
.reply(404, { type: 'error', error: { message: 'Not found' } });
|
|
|
|
await expect(api.getJsonUnchecked('some-url')).rejects.toThrow(
|
|
'Request failed with status code 404 (Not Found)',
|
|
);
|
|
|
|
expect(logger.logger.once.warn).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('paginates: adds default pagelen if non is present', async () => {
|
|
const valuesPageOne = [...range(1, 100)];
|
|
const valuesPageTwo = [...range(101, 200)];
|
|
const valuesPageThree = [...range(201, 210)];
|
|
|
|
httpMock
|
|
.scope(baseUrl)
|
|
.get('/some-url?foo=bar&pagelen=100')
|
|
.reply(200, {
|
|
values: valuesPageOne,
|
|
page: '1',
|
|
next: `${baseUrl}/some-url?foo=bar&pagelen=100&page=2`,
|
|
})
|
|
.get('/some-url?foo=bar&pagelen=100&page=2')
|
|
.reply(200, {
|
|
values: valuesPageTwo,
|
|
page: '2',
|
|
next: `${baseUrl}/some-url?foo=bar&pagelen=100&page=3`,
|
|
})
|
|
.get('/some-url?foo=bar&pagelen=100&page=3')
|
|
.reply(200, {
|
|
values: valuesPageThree,
|
|
page: '3',
|
|
});
|
|
const res = await api.getJsonUnchecked('/some-url?foo=bar', {
|
|
paginate: true,
|
|
});
|
|
expect(res.body).toEqual({
|
|
page: '1',
|
|
pagelen: 210,
|
|
size: 210,
|
|
values: [...valuesPageOne, ...valuesPageTwo, ...valuesPageThree],
|
|
next: undefined,
|
|
});
|
|
});
|
|
|
|
it('paginates: respects pagelen if already set in path', async () => {
|
|
const valuesPageOne = [...range(1, 10)];
|
|
const valuesPageTwo = [...range(11, 20)];
|
|
const valuesPageThree = [...range(21, 21)];
|
|
|
|
httpMock
|
|
.scope(baseUrl)
|
|
.get('/some-url?pagelen=10')
|
|
.reply(200, {
|
|
values: valuesPageOne,
|
|
page: '1',
|
|
next: `${baseUrl}/some-url?pagelen=10&page=2`,
|
|
})
|
|
.get('/some-url?pagelen=10&page=2')
|
|
.reply(200, {
|
|
values: valuesPageTwo,
|
|
page: '2',
|
|
next: `${baseUrl}/some-url?pagelen=10&page=3`,
|
|
})
|
|
.get('/some-url?pagelen=10&page=3')
|
|
.reply(200, {
|
|
values: valuesPageThree,
|
|
page: '3',
|
|
});
|
|
const res = await api.getJsonUnchecked('some-url?pagelen=10', {
|
|
paginate: true,
|
|
});
|
|
expect(res.body).toEqual({
|
|
page: '1',
|
|
pagelen: 21,
|
|
size: 21,
|
|
values: [...valuesPageOne, ...valuesPageTwo, ...valuesPageThree],
|
|
next: undefined,
|
|
});
|
|
});
|
|
|
|
it('paginates: respects pagelen if set in options', async () => {
|
|
const valuesPageOne = [...range(1, 20)];
|
|
const valuesPageTwo = [...range(21, 40)];
|
|
const valuesPageThree = [...range(41, 44)];
|
|
|
|
httpMock
|
|
.scope(baseUrl)
|
|
.get('/some-url?pagelen=20')
|
|
.reply(200, {
|
|
values: valuesPageOne,
|
|
page: '1',
|
|
next: `${baseUrl}/some-url?pagelen=20&page=2`,
|
|
})
|
|
.get('/some-url?pagelen=20&page=2')
|
|
.reply(200, {
|
|
values: valuesPageTwo,
|
|
page: '2',
|
|
next: `${baseUrl}/some-url?pagelen=20&page=3`,
|
|
})
|
|
.get('/some-url?pagelen=20&page=3')
|
|
.reply(200, {
|
|
values: valuesPageThree,
|
|
page: '3',
|
|
});
|
|
const res = await api.getJsonUnchecked('some-url', {
|
|
paginate: true,
|
|
pagelen: 20,
|
|
});
|
|
expect(res.body).toEqual({
|
|
page: '1',
|
|
pagelen: 44,
|
|
size: 44,
|
|
values: [...valuesPageOne, ...valuesPageTwo, ...valuesPageThree],
|
|
next: undefined,
|
|
});
|
|
});
|
|
});
|