190 lines
5.5 KiB
JavaScript
190 lines
5.5 KiB
JavaScript
'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();
|
||
});
|
||
});
|
||
});
|