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-10-04 21:57:24 +02:00
|
|
|
import { Event, User, events, Guild, Channel } 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;
|
2021-10-04 21:57:24 +02:00
|
|
|
var guild: Guild;
|
|
|
|
var channel: Channel;
|
|
|
|
|
|
|
|
const request = async (path: string, opts: any = {}): Promise<any> => {
|
|
|
|
const response = await fetch(`http://localhost:3001/api${path}`, {
|
|
|
|
...opts,
|
|
|
|
method: opts.method || opts.body ? "POST" : "GET",
|
|
|
|
body: opts.body && JSON.stringify(opts.body),
|
|
|
|
headers: {
|
|
|
|
authorization: token,
|
|
|
|
...(opts.body ? { "content-type": "application/json" } : {}),
|
|
|
|
...(opts.header || {})
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (response.status === 204) return;
|
|
|
|
|
|
|
|
var data = await response.text();
|
|
|
|
try {
|
2021-10-15 13:00:23 +02:00
|
|
|
data = JSON.parse(data);
|
2021-10-04 21:57:24 +02:00
|
|
|
if (response.status >= 400) throw data;
|
|
|
|
return data;
|
|
|
|
} catch (error) {
|
|
|
|
throw data;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-09-20 23:35:37 +02:00
|
|
|
beforeAll(async (done) => {
|
|
|
|
try {
|
2021-10-04 21:57:24 +02:00
|
|
|
const response = await request("/auth/register", {
|
|
|
|
body: {
|
2021-09-20 23:35:37 +02:00
|
|
|
fingerprint: "805826570869932034.wR8vi8lGlFBJerErO9LG5NViJFw",
|
|
|
|
username: "tester",
|
|
|
|
invite: null,
|
|
|
|
consent: true,
|
|
|
|
date_of_birth: "2000-01-01",
|
|
|
|
gift_code_sku_id: null,
|
|
|
|
captcha_key: null
|
|
|
|
}
|
|
|
|
});
|
2021-10-04 21:57:24 +02:00
|
|
|
token = response.token;
|
|
|
|
user = await request(`/users/@me`);
|
|
|
|
const { id: guild_id } = await request("/guilds", { body: { name: "test server" } });
|
|
|
|
guild = await request(`/guilds/${guild_id}`);
|
|
|
|
channel = (await request(`/guilds/${guild_id}/channels`))[0];
|
2021-09-20 23:35:37 +02:00
|
|
|
|
|
|
|
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-10-04 21:57:24 +02:00
|
|
|
const urlPath =
|
|
|
|
path.replace(":id", user.id).replace(":guild_id", guild.id).replace(":channel_id", channel.id) || route.test?.path;
|
2021-09-20 23:35:37 +02:00
|
|
|
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
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|