github-app-installation-token
Version:
npm/script and binary 📦 to get a token from a GitHub App
200 lines (173 loc) • 6.19 kB
text/typescript
import { mockProcessExit } from 'jest-mock-process';
import { readFileSync } from 'fs';
import { stopAndPersist, fail } from '../__mocks__/ora';
import { mockConsole, unMockConsole } from './helper';
import nock from 'nock';
import { getToken, getTokenCommand } from '../src/index';
const GITHUB_URL = 'https://api.github.com';
describe('getToken', () => {
let consoleLogMock: jest.Mock;
beforeAll(() => {
consoleLogMock = mockConsole('log');
});
afterAll(() => {
unMockConsole('log');
});
beforeEach(() => {
consoleLogMock.mockReset();
stopAndPersist.mockReset();
fail.mockReset();
});
const APP_ID = 1;
const KEY_LOCATION = '__mocks__/private.key';
const PRIVATE_KEY = readFileSync(KEY_LOCATION).toString();
const getAccessTokensURL = (installationID: number) => `/app/installations/${installationID}/access_tokens`;
const installationID = 1234;
// The response object has to be in snake_case because is how the API returns fields, octokit will camelCase every field
const response = {
type: 'token',
token_type: 'installation',
token: 'secret-installation-token-1234',
installation_id: 12400204,
permissions: {
actions: 'write',
administration: 'admin',
checks: 'write',
contents: 'write',
issues: 'write',
metadata: 'read',
pull_requests: 'write',
statuses: 'admin',
},
created_at: new Date('2020-12-14').toDateString(),
expires_at: new Date('2020-12-15').toDateString(),
repository_selection: 'all',
};
it('It tries to get the token, but it gets a malformed response from Github', async () => {
const { token, ...responseWithoutToken } = response;
const github = nock(GITHUB_URL).post(getAccessTokensURL(installationID)).reply(201, responseWithoutToken);
try {
await getToken({
appId: APP_ID,
installationId: installationID,
privateKey: PRIVATE_KEY,
});
} catch (e) {
expect(e.message).toMatchInlineSnapshot(
'"Something went wrong on the token retrieval, enable debug to inspect further"'
);
}
expect(github.isDone()).toBe(true);
});
it('Retrieves the token', async () => {
const github = nock(GITHUB_URL).post(getAccessTokensURL(123456)).reply(201, response);
const { token } = await getToken({
appId: APP_ID,
installationId: 123456,
privateKey: PRIVATE_KEY,
});
expect(token).toMatchInlineSnapshot('"secret-installation-token-1234"');
expect(github.isDone()).toBe(true);
});
it('fails when invoking the command', async () => {
const mockExit = mockProcessExit();
const github = nock(GITHUB_URL)
.post(getAccessTokensURL(installationID))
.replyWithError('failed with some server error');
await getTokenCommand({
appId: APP_ID,
installationId: installationID,
privateKey: PRIVATE_KEY,
});
expect(mockExit).toHaveBeenCalled();
expect(fail).toHaveBeenCalledTimes(1);
expect(github.isDone()).toBe(true);
});
it('invokes getToken via command', async () => {
const github = nock(GITHUB_URL).post(getAccessTokensURL(installationID)).reply(201, response);
const mockExit = mockProcessExit();
await getTokenCommand({
appId: APP_ID,
installationId: installationID,
privateKey: PRIVATE_KEY,
});
expect(consoleLogMock.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
"secret-installation-token-1234",
],
]
`);
expect(mockExit).not.toHaveBeenCalled();
expect(stopAndPersist).toHaveBeenCalledTimes(1);
expect(github.isDone()).toBe(true);
});
it('invokes getToken via command providing a private.key location(with raw Response)', async () => {
const github = nock(GITHUB_URL).post(getAccessTokensURL(installationID)).reply(201, response);
const mockExit = mockProcessExit();
await getTokenCommand({
appId: APP_ID,
installationId: installationID,
privateKeyLocation: KEY_LOCATION,
rawResponse: true,
});
expect(mockExit).not.toHaveBeenCalled();
expect(stopAndPersist).toHaveBeenCalledTimes(1);
expect(stopAndPersist.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
Object {
"symbol": "💫",
"text": "The token is: secret-installation-token-1234 and expires Tue Dec 15 2020",
},
],
]
`);
expect(github.isDone()).toBe(true);
});
it('invokes getToken via command providing a private.key location', async () => {
const github = nock(GITHUB_URL).post(getAccessTokensURL(installationID)).reply(201, response);
const mockExit = mockProcessExit();
await getTokenCommand({
appId: APP_ID,
installationId: installationID,
privateKeyLocation: KEY_LOCATION,
});
expect(mockExit).not.toHaveBeenCalled();
expect(stopAndPersist).toHaveBeenCalledTimes(1);
expect(stopAndPersist.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
Object {
"symbol": "💫",
"text": "The token is: secret-installation-token-1234 and expires Tue Dec 15 2020",
},
],
]
`);
expect(github.isDone()).toBe(true);
});
it('invokes getToken via command not providing a private.key or private.keyLocation', async () => {
const mockExit = mockProcessExit();
await getTokenCommand({
appId: APP_ID,
installationId: installationID,
});
expect(mockExit).toHaveBeenCalled();
expect(fail.mock.calls[0][0]).toMatchInlineSnapshot(
'"Input is not valid, either privateKey or privateKeyLocation should be provided"'
);
});
it('Uses other baseUrl if provided', async () => {
const other_url = 'https://test.de';
const github = nock(other_url).post(getAccessTokensURL(123456)).reply(201, response);
const { token } = await getToken({
appId: APP_ID,
installationId: 123456,
privateKey: PRIVATE_KEY,
baseUrl: other_url,
});
expect(token).toMatchInlineSnapshot('"secret-installation-token-1234"');
expect(github.isDone()).toBe(true);
});
});