2021-09-18 01:50:29 +02:00
|
|
|
// 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";
|
2021-09-18 11:56:06 +02:00
|
|
|
import { join } from "path";
|
2021-09-18 01:50:29 +02:00
|
|
|
import fs from "fs";
|
|
|
|
import Ajv from "ajv";
|
|
|
|
import addFormats from "ajv-formats";
|
2021-09-20 23:35:37 +02:00
|
|
|
import fetch from "node-fetch";
|
2021-09-21 23:13:31 +02:00
|
|
|
import { Event, User, events } from "@fosscord/util";
|
2021-09-18 01:50:29 +02:00
|
|
|
|
2021-09-21 22:52:30 +02:00
|
|
|
const SchemaPath = join(__dirname, "..", "assets", "schemas.json");
|
2021-09-18 01:50:29 +02:00
|
|
|
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,
|
2021-09-20 23:35:37 +02:00
|
|
|
strictRequired: true,
|
|
|
|
coerceTypes: true
|
2021-09-18 01:50:29 +02:00
|
|
|
});
|
|
|
|
addFormats(ajv);
|
|
|
|
|
2021-09-20 23:35:37 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-09-21 23:13:31 +02:00
|
|
|
const emit = events.emit;
|
|
|
|
events.emit = (event: string | symbol, ...args: any[]) => {
|
|
|
|
events.emit("event", args[0]);
|
|
|
|
return emit(event, ...args);
|
|
|
|
};
|
|
|
|
|
2021-09-18 01:50:29 +02:00
|
|
|
describe("Automatic unit tests with route description middleware", () => {
|
|
|
|
const routes = getRouteDescriptions();
|
|
|
|
|
|
|
|
routes.forEach((route, pathAndMethod) => {
|
|
|
|
const [path, method] = pathAndMethod.split("|");
|
2021-09-18 11:56:06 +02:00
|
|
|
|
2021-09-21 22:52:30 +02:00
|
|
|
test(`${method.toUpperCase()} ${path}`, async (done) => {
|
2021-09-20 23:35:37 +02:00
|
|
|
if (!route.test) {
|
2021-09-18 11:56:06 +02:00
|
|
|
console.log(`${(route as any).file}\nrouter.${method} is missing the test property`);
|
2021-09-18 01:50:29 +02:00
|
|
|
return done();
|
|
|
|
}
|
2021-09-20 23:35:37 +02:00
|
|
|
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 = "";
|
2021-09-21 23:13:31 +02:00
|
|
|
let eventEmitted = Promise.resolve();
|
|
|
|
|
|
|
|
if (route.test.event) {
|
|
|
|
if (!Array.isArray(route.test.event)) route.test.event = [route.test.event];
|
|
|
|
|
|
|
|
eventEmitted = new Promise((resolve, reject) => {
|
|
|
|
const timeout = setTimeout(() => reject, 1000);
|
|
|
|
const received = [];
|
|
|
|
|
|
|
|
events.on("event", (event: Event) => {
|
|
|
|
if (!route.test.event.includes(event.event)) return;
|
|
|
|
|
|
|
|
received.push(event.event);
|
|
|
|
if (received.length === route.test.event.length) resolve();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
2021-09-18 01:50:29 +02:00
|
|
|
|
2021-09-20 23:35:37 +02:00
|
|
|
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 }
|
2021-09-18 01:50:29 +02:00
|
|
|
});
|
2021-09-20 23:35:37 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-09-21 23:13:31 +02:00
|
|
|
try {
|
|
|
|
await eventEmitted;
|
|
|
|
} catch (error) {
|
|
|
|
return done(new Error(`Event ${route.test.event} was not emitted`));
|
|
|
|
}
|
|
|
|
|
2021-09-20 23:35:37 +02:00
|
|
|
return done();
|
2021-09-18 01:50:29 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|