appstore-cli
Version:
A command-line interface (CLI) to interact with the Apple App Store Connect API.
111 lines (87 loc) • 3.73 kB
text/typescript
import { generateJwt } from './auth';
import { saveConfig, loadConfig, getPrivateKey } from './config';
import fs from 'fs';
import os from 'os';
import path from 'path';
// Mock the getPrivateKey function
jest.mock('./config', () => ({
...jest.requireActual('./config'),
getPrivateKey: jest.fn(),
loadConfig: jest.fn(),
saveConfig: jest.fn(),
}));
describe('generateJwt', () => {
beforeEach(() => {
// Clear all mocks before each test
jest.clearAllMocks();
});
it('should generate a valid JWT', async () => {
const privateKey = `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIOYriRfibkZYrlSonyD6VdtLIdTA441NVN6YlWISx1vOoAoGCCqGSM49
AwEHoUQDQgAEwuUcB7BECWqneFzvrokoo5l6H5CV0GaEdMc/VNbWfayJTH1HAhHP
5orIL0/lYReSbUhVjvSVT6cogV0wd5vDvw==
-----END EC PRIVATE KEY-----`;
const keyId = 'test-key-id';
const issuerId = 'test-issuer-id';
// Mock the getPrivateKey function to return our test key
(getPrivateKey as jest.Mock).mockResolvedValue(privateKey);
const config = { keyId, issuerId };
const token = await generateJwt(config);
expect(token).toBeDefined();
expect(typeof token).toBe('string');
// Split the token and check it has 3 parts
const tokenParts = token.split('.');
expect(tokenParts.length).toBe(3);
});
it('should reject invalid configuration', async () => {
const privateKey = `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIOYriRfibkZYrlSonyD6VdtLIdTA441NVN6YlWISx1vOoAoGCCqGSM49
AwEHoUQDQgAEwuUcB7BECWqneFzvrokoo5l6H5CV0GaEdMc/VNbWfayJTH1HAhHP
5orIL0/lYReSbUhVjvSVT6cogV0wd5vDvw==
-----END EC PRIVATE KEY-----`;
// Mock the getPrivateKey function to return our test key
(getPrivateKey as jest.Mock).mockResolvedValue(privateKey);
// Test with missing issuerId
const configWithoutIssuerId = {
keyId: 'test-key-id',
issuerId: '',
};
await expect(generateJwt(configWithoutIssuerId)).rejects.toThrow('Issuer ID is required but not provided');
// Test with missing keyId
const configWithoutKeyId = {
keyId: '',
issuerId: 'test-issuer-id',
};
await expect(generateJwt(configWithoutKeyId)).rejects.toThrow('Key ID is required but not provided');
});
it('should reject invalid private key', async () => {
// Mock getPrivateKey to return an invalid key
(getPrivateKey as jest.Mock).mockResolvedValue('invalid-key');
const config = {
keyId: 'test-key-id',
issuerId: 'test-issuer-id',
};
await expect(generateJwt(config)).rejects.toThrow('Invalid private key format');
});
it('should have appropriate expiration time', async () => {
const privateKey = `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIOYriRfibkZYrlSonyD6VdtLIdTA441NVN6YlWISx1vOoAoGCCqGSM49
AwEHoUQDQgAEwuUcB7BECWqneFzvrokoo5l6H5CV0GaEdMc/VNbWfayJTH1HAhHP
5orIL0/lYReSbUhVjvSVT6cogV0wd5vDvw==
-----END EC PRIVATE KEY-----`;
const keyId = 'test-key-id';
const issuerId = 'test-issuer-id';
// Mock the getPrivateKey function to return our test key
(getPrivateKey as jest.Mock).mockResolvedValue(privateKey);
const config = { keyId, issuerId };
const token = await generateJwt(config);
// Decode the token to check expiration
const tokenParts = token.split('.');
const payload = JSON.parse(Buffer.from(tokenParts[1], 'base64').toString());
// Check that expiration is set (20 minutes from now)
const expectedExpiration = Math.floor(Date.now() / 1000) + (20 * 60);
const tolerance = 5; // 5 seconds tolerance
expect(payload.exp).toBeGreaterThanOrEqual(expectedExpiration - tolerance);
expect(payload.exp).toBeLessThanOrEqual(expectedExpiration + tolerance);
});
});