Files
binect-chrome/tests/binect-api.test.ts
tegwick b09290cb83 Release 0.1: Complete BinectChrome implementation
Implements all requirements from ProductRequirementsDocument.md:
- PDF detection via Chrome Downloads API
- Secure credential storage with AES-GCM encryption
- Binect API integration for PDF uploads
- Popup UI with Binect branding
- Local transfer tracking (500 entry cap)
- Help page with tracking view and CSV export
- 60-day credential retention with auto-expiry
- Accessibility compliance (WCAG 2.1 AA)

Technical implementation:
- Chrome Extension Manifest V3
- TypeScript with strict mode
- Webpack build system
- Jest test suite (22/22 passing)
- ESLint configured (0 errors)

Build output: 13 KB total (production minified)
Test coverage: crypto, pdf-detector, tracker, binect-api

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-13 00:30:39 +01:00

117 lines
3.2 KiB
TypeScript

/**
* Tests for Binect API client
*/
import { authenticate, uploadPDF, BinectAPIError } from '../src/utils/binect-api';
describe('Binect API', () => {
beforeEach(() => {
jest.clearAllMocks();
});
describe('authenticate', () => {
test('should authenticate successfully', async () => {
const mockResponse = {
token: 'test-token',
expiresAt: '2024-12-31T23:59:59Z'
};
(fetch as jest.Mock).mockResolvedValue({
ok: true,
json: async () => mockResponse
});
const result = await authenticate('user', 'pass');
expect(result.token).toBe('test-token');
expect(fetch).toHaveBeenCalledWith(
'https://api.binect.de/auth/login',
expect.objectContaining({
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: 'user', password: 'pass' })
})
);
});
test('should throw on invalid credentials', async () => {
(fetch as jest.Mock).mockResolvedValue({
ok: false,
status: 401,
statusText: 'Unauthorized'
});
await expect(authenticate('user', 'wrong')).rejects.toThrow(
BinectAPIError
);
await expect(authenticate('user', 'wrong')).rejects.toThrow(
'Invalid credentials'
);
});
test('should handle network errors', async () => {
(fetch as jest.Mock).mockRejectedValue(new Error('Network failure'));
await expect(authenticate('user', 'pass')).rejects.toThrow(
BinectAPIError
);
});
});
describe('uploadPDF', () => {
test('should upload PDF successfully', async () => {
const mockResponse = {
documentId: 'doc-123',
status: 'received',
uploadedAt: '2024-01-01T00:00:00Z'
};
(fetch as jest.Mock).mockResolvedValue({
ok: true,
json: async () => mockResponse
});
const pdfData = new ArrayBuffer(1024);
const result = await uploadPDF(pdfData, 'test.pdf', 'token-123');
expect(result.documentId).toBe('doc-123');
expect(fetch).toHaveBeenCalledWith(
'https://api.binect.de/documents/upload',
expect.objectContaining({
method: 'POST',
headers: {
Authorization: 'Bearer token-123'
}
})
);
});
test('should throw on authentication failure', async () => {
(fetch as jest.Mock).mockResolvedValue({
ok: false,
status: 401,
statusText: 'Unauthorized',
json: async () => ({ error: 'Invalid token' })
});
const pdfData = new ArrayBuffer(1024);
await expect(uploadPDF(pdfData, 'test.pdf', 'bad-token')).rejects.toThrow(
BinectAPIError
);
});
test('should throw on file size exceeded', async () => {
(fetch as jest.Mock).mockResolvedValue({
ok: false,
status: 413,
statusText: 'Payload Too Large',
json: async () => ({ error: 'File too large' })
});
const pdfData = new ArrayBuffer(10 * 1024 * 1024); // 10MB
await expect(uploadPDF(pdfData, 'test.pdf', 'token')).rejects.toThrow(
'File size exceeds limit'
);
});
});
});