'use strict'; /** * Integration tests – api_key controller (controllers/api_key.js) * * Note: bcrypt operations are slow (10 rounds) – jest timeout is raised to * 30 seconds per test. */ jest.setTimeout(30000); const { connectDB, disconnectDB, clearCollection } = require('./jest.setup'); const { mockApplicator, mockReq, mockRes, newId } = require('./mock_data'); let ApiKey, Customer; beforeAll(async () => { await connectDB(); ApiKey = require('../../model/api_key'); Customer = require('../../model/customer'); }); afterAll(async () => { await disconnectDB(); }); const apiKeyCtl = require('../../controllers/api_key'); describe('api_key controller – data methods', () => { let applicator; beforeAll(async () => { await clearCollection(ApiKey); applicator = await Customer.create(mockApplicator()); }); afterAll(async () => { await clearCollection(ApiKey); await Customer.deleteMany({ _id: applicator._id }); }); const makeReq = (extra = {}) => mockReq({ uid: applicator._id, puid: applicator._id, ut: '1', ...extra }); // ------------------------------------------------------------------------- describe('createKey', () => { it('creates an API key and returns the raw key once', async () => { const req = makeReq({ body: { label: 'Key 1' } }); const res = mockRes(); await apiKeyCtl.createKey(req, res); expect(res.json).toHaveBeenCalled(); expect(res._data.key).toBeDefined(); expect(typeof res._data.key).toBe('string'); expect(res._data.key.length).toBeGreaterThan(10); }); it('throws when owner already has 10 keys', async () => { await clearCollection(ApiKey); // Create 10 keys first const docs = []; for (let i = 0; i < 10; i++) { docs.push({ owner: applicator._id, label: `Key ${i}`, keyHash: `fakehash${i}`, prefix: `pfx${i}`, }); } await ApiKey.insertMany(docs); const req = makeReq({ body: { label: 'Extra Key' } }); const res = mockRes(); await expect(apiKeyCtl.createKey(req, res)).rejects.toThrow(); }); }); // ------------------------------------------------------------------------- describe('listKeys', () => { beforeAll(async () => { await clearCollection(ApiKey); const req = makeReq({ body: { label: 'Listed Key' } }); const res = mockRes(); await apiKeyCtl.createKey(req, res); }); it('returns list of API keys without hash field', async () => { const req = makeReq(); const res = mockRes(); await apiKeyCtl.listKeys(req, res); expect(res.json).toHaveBeenCalled(); expect(Array.isArray(res._data)).toBe(true); expect(res._data.length).toBeGreaterThan(0); expect(res._data[0].hash).toBeUndefined(); }); }); // ------------------------------------------------------------------------- describe('revokeKey', () => { let keyId; beforeAll(async () => { await clearCollection(ApiKey); const req = makeReq({ body: { label: 'Key to Revoke' } }); const res = mockRes(); await apiKeyCtl.createKey(req, res); const listReq = makeReq(); const listRes = mockRes(); await apiKeyCtl.listKeys(listReq, listRes); keyId = String(listRes._data[0]._id); }); it('revokes an active API key', async () => { const req = makeReq({ params: { keyId }, ut: '0' }); const res = mockRes(); await apiKeyCtl.revokeKey(req, res); expect(res.end).toHaveBeenCalled(); const doc = await ApiKey.findById(keyId); expect(doc.active).toBe(false); }); it('returns 404 when key not found', async () => { const req = makeReq({ params: { keyId: String(newId()) }, ut: '0' }); const res = mockRes(); await apiKeyCtl.revokeKey(req, res); expect(res.statusCode).toBe(404); }); }); // ------------------------------------------------------------------------- describe('regenerateKey', () => { let keyId; beforeAll(async () => { await clearCollection(ApiKey); const req = makeReq({ body: { label: 'Key to Regen' } }); const res = mockRes(); await apiKeyCtl.createKey(req, res); const listReq = makeReq(); const listRes = mockRes(); await apiKeyCtl.listKeys(listReq, listRes); keyId = String(listRes._data[0]._id); }); it('regenerates key and returns new raw key', async () => { const req = makeReq({ params: { keyId } }); const res = mockRes(); await apiKeyCtl.regenerateKey(req, res); expect(res.json).toHaveBeenCalled(); expect(res._data.key).toBeDefined(); expect(typeof res._data.key).toBe('string'); }); }); // ------------------------------------------------------------------------- describe('deleteKey', () => { let keyId; beforeAll(async () => { await clearCollection(ApiKey); const req = makeReq({ body: { label: 'Key to Delete' } }); const res = mockRes(); await apiKeyCtl.createKey(req, res); const listReq = makeReq(); const listRes = mockRes(); await apiKeyCtl.listKeys(listReq, listRes); keyId = String(listRes._data[0]._id); }); it('permanently deletes an API key', async () => { const req = makeReq({ params: { keyId } }); const res = mockRes(); await apiKeyCtl.deleteKey(req, res); expect(res.end).toHaveBeenCalled(); const found = await ApiKey.findById(keyId); expect(found).toBeNull(); }); }); });