forked from SmartDropLabs/smartdrop-backend
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi-docs.test.js
More file actions
142 lines (118 loc) · 4.86 KB
/
Copy pathapi-docs.test.js
File metadata and controls
142 lines (118 loc) · 4.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"use strict";
const path = require("path");
const fs = require("fs");
const express = require("express");
const request = require("supertest");
const helmet = require("helmet");
describe("OpenAPI specification", () => {
test("openapi.yaml exists and is valid YAML", () => {
const specPath = path.join(__dirname, "..", "openapi.yaml");
expect(fs.existsSync(specPath)).toBe(true);
const content = fs.readFileSync(specPath, "utf8");
expect(content).toContain("openapi: 3.0.3");
expect(content).toContain("SmartDrop API");
});
test("spec defines all required endpoints from the issue", () => {
const specPath = path.join(__dirname, "..", "openapi.yaml");
const content = fs.readFileSync(specPath, "utf8");
expect(content).toContain("/health");
expect(content).toContain("/api/v1/prices/{asset_code}");
expect(content).toContain("/api/v1/prices/batch");
expect(content).toContain("/api/v1/webhooks");
expect(content).toContain("/api/v1/keys");
expect(content).toContain("/api/v1/keys/{id}");
expect(content).toContain("/api/v1/indexer/status");
expect(content).toContain("/ws");
expect(content).toContain("x-draft: true");
});
test("spec documents key management schemas and operations", () => {
const specPath = path.join(__dirname, "..", "openapi.yaml");
const content = fs.readFileSync(specPath, "utf8");
expect(content).toContain("operationId: listApiKeys");
expect(content).toContain("operationId: createApiKey");
expect(content).toContain("operationId: revokeApiKey");
expect(content).toContain("ApiKeyCreateRequest");
expect(content).toContain("ApiKeyCreateResponse");
expect(content).toContain("ApiKeyListResponse");
expect(content).toContain("ApiKeyRevokeResponse");
});
test("spec includes Bearer security scheme", () => {
const specPath = path.join(__dirname, "..", "openapi.yaml");
const content = fs.readFileSync(specPath, "utf8");
expect(content).toContain("BearerAuth");
expect(content).toContain("apiKey");
expect(content).toContain("Authorization");
});
test("spec includes all required error responses", () => {
const specPath = path.join(__dirname, "..", "openapi.yaml");
const content = fs.readFileSync(specPath, "utf8");
expect(content).toContain("ValidationError");
expect(content).toContain("Unauthorized");
expect(content).toContain("NotFound");
expect(content).toContain("UnprocessableEntity");
expect(content).toContain("RateLimited");
expect(content).toContain("InternalError");
});
});
describe("Swagger UI", () => {
let app;
beforeAll(() => {
jest.isolateModules(() => {
const apiDocsRouter = require("../src/routes/apiDocs");
app = express();
app.use("/api-docs", apiDocsRouter);
});
});
test("GET /api-docs/openapi.yaml serves the spec file", async () => {
const res = await request(app).get("/api-docs/openapi.yaml");
expect(res.status).toBe(200);
expect(res.headers["content-type"]).toMatch(/yaml/);
expect(res.text).toContain("openapi: 3.0.3");
});
test("GET /api-docs/openapi.yaml matches the file on disk", async () => {
const res = await request(app).get("/api-docs/openapi.yaml");
const specPath = path.join(__dirname, "..", "openapi.yaml");
const fileContent = fs.readFileSync(specPath, "utf8");
expect(res.text).toBe(fileContent);
});
test("Swagger UI HTML is served at /api-docs in development mode", () => {
const NODE_ENV = process.env.NODE_ENV;
process.env.NODE_ENV = "development";
jest.resetModules();
const devRouter = require("../src/routes/apiDocs");
const devApp = express();
devApp.use("/api-docs", devRouter);
return request(devApp)
.get("/api-docs/")
.expect(200)
.then((res) => {
expect(res.text).toContain("swagger-ui");
expect(res.text).toContain("SmartDrop API Docs");
process.env.NODE_ENV = NODE_ENV;
});
});
});
describe('Swagger UI CSP exception (#129)', () => {
test('docs route sends a relaxed CSP allowing inline scripts/styles (Swagger UI needs them)', () => {
const NODE_ENV = process.env.NODE_ENV;
process.env.NODE_ENV = 'development';
jest.resetModules();
const apiDocsRouter = require('../src/routes/apiDocs');
const { docsCspMiddleware } = require('../src/middleware/csp');
const app = express();
app.use(helmet());
app.use('/api-docs', docsCspMiddleware);
app.use('/api-docs', apiDocsRouter);
return request(app)
.get('/api-docs/')
.expect(200)
.then((res) => {
const csp = res.headers['content-security-policy'];
expect(csp).toBeDefined();
expect(csp).toContain("script-src 'self' 'unsafe-inline'");
expect(csp).toContain("style-src 'self' 'unsafe-inline'");
expect(res.text).toContain('swagger-ui');
process.env.NODE_ENV = NODE_ENV;
});
});
});