summary refs log tree commit diff
path: root/api/tests/routes.test.ts
blob: a9c75df1b2558b71a3d6903c64a05958644f0c69 (plain) (blame)
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
// TODO: check every route based on route() parameters: https://github.com/fosscord/fosscord-server/issues/308
// TODO: check every route with different database engine

import getRouteDescriptions from "../jest/getRouteDescriptions";
import { join } from "path";
import fs from "fs";
import Ajv from "ajv";
import addFormats from "ajv-formats";
import fetch from "node-fetch";
import { User } from "@fosscord/util";

const SchemaPath = join(__dirname, "..", "assets", "schemas.json");
const schemas = JSON.parse(fs.readFileSync(SchemaPath, { encoding: "utf8" }));
export const ajv = new Ajv({
	allErrors: true,
	parseDate: true,
	allowDate: true,
	schemas,
	messages: true,
	strict: true,
	strictRequired: true,
	coerceTypes: true
});
addFormats(ajv);

var token: string;
var user: User;
beforeAll(async (done) => {
	try {
		const response = await fetch("http://localhost:3001/api/auth/register", {
			method: "POST",
			body: JSON.stringify({
				fingerprint: "805826570869932034.wR8vi8lGlFBJerErO9LG5NViJFw",
				email: "test@example.com",
				username: "tester",
				password: "wtp9gep9gw",
				invite: null,
				consent: true,
				date_of_birth: "2000-01-01",
				gift_code_sku_id: null,
				captcha_key: null
			}),
			headers: {
				"content-type": "application/json"
			}
		});
		const json = await response.json();
		token = json.token;
		user = await (
			await fetch(`http://localhost:3001/api/users/@me`, {
				headers: { authorization: token }
			})
		).json();

		done();
	} catch (error) {
		done(error);
	}
});

describe("Automatic unit tests with route description middleware", () => {
	const routes = getRouteDescriptions();

	routes.forEach((route, pathAndMethod) => {
		const [path, method] = pathAndMethod.split("|");

		test(`${method.toUpperCase()} ${path}`, async (done) => {
			if (!route.test) {
				console.log(`${(route as any).file}\nrouter.${method} is missing the test property`);
				return done();
			}
			const urlPath = path.replace(":id", user.id) || route.test?.path;
			var validate: any;
			if (route.test.body) {
				validate = ajv.getSchema(route.test.body);
				if (!validate) return done(new Error(`Response schema ${route.test.body} not found`));
			}

			var body = "";

			try {
				const response = await fetch(`http://localhost:3001/api${urlPath}`, {
					method: method.toUpperCase(),
					body: JSON.stringify(route.test.body),
					headers: { ...route.test.headers, authorization: token }
				});

				body = await response.text();

				expect(response.status, body).toBe(route.test.response.status || 200);

				// TODO: check headers
				// TODO: expect event

				if (validate) {
					body = JSON.parse(body);
					const valid = validate(body);
					if (!valid) return done(validate.errors);
				}
			} catch (error) {
				return done(error);
			}

			return done();
		});
	});
});