forked from mirrors/probot
test: move server tests into `test/server.test.ts`
This commit is contained in:
parent
3d90806c95
commit
e0d34c7f80
|
@ -74,10 +74,17 @@ describe("Probot", () => {
|
|||
|
||||
new Probot({ Octokit: MyOctokit });
|
||||
});
|
||||
|
||||
it("sets version", async () => {
|
||||
const probot = new Probot({});
|
||||
expect(probot.version).toBe("0.0.0-development");
|
||||
});
|
||||
});
|
||||
|
||||
describe("webhook delivery", () => {
|
||||
describe("webhooks", () => {
|
||||
it("responds with the correct error if webhook secret does not match", async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
probot.log.error = jest.fn();
|
||||
probot.webhooks.on("push", () => {
|
||||
throw new Error("X-Hub-Signature does not match blob signature");
|
||||
|
@ -93,6 +100,8 @@ describe("Probot", () => {
|
|||
});
|
||||
|
||||
it("responds with the correct error if webhook secret is not found", async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
probot.log.error = jest.fn();
|
||||
probot.webhooks.on("push", () => {
|
||||
throw new Error("No X-Hub-Signature found on request");
|
||||
|
@ -108,6 +117,8 @@ describe("Probot", () => {
|
|||
});
|
||||
|
||||
it("responds with the correct error if webhook secret is wrong", async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
probot.log.error = jest.fn();
|
||||
probot.webhooks.on("push", () => {
|
||||
throw new Error(
|
||||
|
@ -125,6 +136,8 @@ describe("Probot", () => {
|
|||
});
|
||||
|
||||
it("responds with the correct error if the PEM file is missing", async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
probot.log.error = jest.fn();
|
||||
probot.webhooks.onAny(() => {
|
||||
throw new Error(
|
||||
|
@ -142,6 +155,8 @@ describe("Probot", () => {
|
|||
});
|
||||
|
||||
it("responds with the correct error if the jwt could not be decoded", async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
probot.log.error = jest.fn();
|
||||
probot.webhooks.onAny(() => {
|
||||
throw new Error(
|
||||
|
@ -159,111 +174,6 @@ describe("Probot", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("server", () => {
|
||||
it("prefixes paths with route name", () => {
|
||||
probot.load(({ app, getRouter }) => {
|
||||
const router = getRouter("/my-app");
|
||||
router.get("/foo", (req, res) => res.end("foo"));
|
||||
});
|
||||
|
||||
return request(probot.server).get("/my-app/foo").expect(200, "foo");
|
||||
});
|
||||
|
||||
it("allows routes with no path", () => {
|
||||
probot.load(({ app, getRouter }) => {
|
||||
const router = getRouter();
|
||||
router.get("/foo", (req, res) => res.end("foo"));
|
||||
});
|
||||
|
||||
return request(probot.server).get("/foo").expect(200, "foo");
|
||||
});
|
||||
|
||||
it("allows you to overwrite the root path", () => {
|
||||
probot.load(({ app, getRouter }) => {
|
||||
const router = getRouter();
|
||||
router.get("/", (req, res) => res.end("foo"));
|
||||
});
|
||||
|
||||
return request(probot.server).get("/").expect(200, "foo");
|
||||
});
|
||||
|
||||
it("isolates apps from affecting each other", async () => {
|
||||
["foo", "bar"].forEach((name) => {
|
||||
probot.load(({ app, getRouter }) => {
|
||||
const router = getRouter("/" + name);
|
||||
|
||||
router.use((req, res, next) => {
|
||||
res.append("X-Test", name);
|
||||
next();
|
||||
});
|
||||
|
||||
router.get("/hello", (req, res) => res.end(name));
|
||||
});
|
||||
});
|
||||
|
||||
await request(probot.server)
|
||||
.get("/foo/hello")
|
||||
.expect(200, "foo")
|
||||
.expect("X-Test", "foo");
|
||||
|
||||
await request(probot.server)
|
||||
.get("/bar/hello")
|
||||
.expect(200, "bar")
|
||||
.expect("X-Test", "bar");
|
||||
});
|
||||
|
||||
it("allows users to configure webhook paths", async () => {
|
||||
probot = new Probot({
|
||||
webhookPath: "/webhook",
|
||||
githubToken: "faketoken",
|
||||
});
|
||||
// Error handler to avoid printing logs
|
||||
// tslint:disable-next-line handle-callback-error
|
||||
probot.server.use(
|
||||
(error: any, req: Request, res: Response, next: NextFunction) => {}
|
||||
);
|
||||
|
||||
probot.load(({ getRouter }) => {
|
||||
const router = getRouter();
|
||||
router.get("/webhook", (req, res) => res.end("get-webhook"));
|
||||
router.post("/webhook", (req, res) => res.end("post-webhook"));
|
||||
});
|
||||
|
||||
// GET requests should succeed
|
||||
await request(probot.server).get("/webhook").expect(200, "get-webhook");
|
||||
|
||||
// POST requests should fail b/c webhook path has precedence
|
||||
await request(probot.server).post("/webhook").expect(400);
|
||||
});
|
||||
|
||||
it("defaults webhook path to `/`", async () => {
|
||||
// Error handler to avoid printing logs
|
||||
// tslint:disable-next-line handle-callback-error
|
||||
probot.server.use(
|
||||
(error: any, req: Request, res: Response, next: NextFunction) => {}
|
||||
);
|
||||
|
||||
// POST requests to `/` should 400 b/c webhook signature will fail
|
||||
await request(probot.server).post("/").expect(400);
|
||||
});
|
||||
|
||||
it("responds with 500 on error", async () => {
|
||||
probot.server.get("/boom", () => {
|
||||
throw new Error("boom");
|
||||
});
|
||||
|
||||
await request(probot.server).get("/boom").expect(500);
|
||||
});
|
||||
|
||||
it("responds with 500 on async error", async () => {
|
||||
probot.server.get("/boom", () => {
|
||||
return Promise.reject(new Error("boom"));
|
||||
});
|
||||
|
||||
await request(probot.server).get("/boom").expect(500);
|
||||
});
|
||||
});
|
||||
|
||||
describe("receive", () => {
|
||||
it("forwards events to each app", async () => {
|
||||
const spy = jest.fn();
|
||||
|
@ -400,54 +310,6 @@ describe("Probot", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("start", () => {
|
||||
beforeEach(() => {
|
||||
process.exit = jest.fn() as any; // we dont want to terminate the test
|
||||
});
|
||||
|
||||
it("should expect the correct error if port already in use", (next) => {
|
||||
expect.assertions(2);
|
||||
|
||||
// block port 3001
|
||||
const http = require("http");
|
||||
const blockade = http.createServer().listen(3001, () => {
|
||||
const testApp = new Probot({ port: 3001 });
|
||||
testApp.log.error = jest.fn();
|
||||
|
||||
const server = testApp.start().addListener("error", () => {
|
||||
expect(testApp.log.error).toHaveBeenCalledWith(
|
||||
"Port 3001 is already in use. You can define the PORT environment variable to use a different port."
|
||||
);
|
||||
expect(process.exit).toHaveBeenCalledWith(1);
|
||||
server.close(() => blockade.close(() => next()));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should listen to port when not in use", (next) => {
|
||||
expect.assertions(1);
|
||||
const testApp = new Probot({ port: 3001, webhookProxy: undefined });
|
||||
testApp.log.info = jest.fn();
|
||||
const server = testApp.start().on("listening", () => {
|
||||
expect(testApp.log.info).toHaveBeenCalledWith(
|
||||
"Listening on http://localhost:3001"
|
||||
);
|
||||
server.close(() => next());
|
||||
});
|
||||
});
|
||||
|
||||
it("respects host/ip config when starting up HTTP server", (next) => {
|
||||
const testApp = new Probot({ port: 3002, host: "127.0.0.1" });
|
||||
const spy = jest.spyOn(testApp.server, "listen");
|
||||
const server = testApp.start().on("listening", () => {
|
||||
expect(spy.mock.calls[0][0]).toBe(3002);
|
||||
expect(spy.mock.calls[0][1]).toBe("127.0.0.1");
|
||||
spy.mockRestore();
|
||||
server.close(() => next());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("load", () => {
|
||||
it("app sends request with JWT authentication", async () => {
|
||||
expect.assertions(3);
|
||||
|
|
101
test/run.test.ts
101
test/run.test.ts
|
@ -1,14 +1,16 @@
|
|||
import Stream from "stream";
|
||||
import path = require("path");
|
||||
|
||||
import request from "supertest";
|
||||
import { sign } from "@octokit/webhooks";
|
||||
|
||||
import { Probot, run, Server } from "../src";
|
||||
|
||||
import path = require("path");
|
||||
|
||||
// tslint:disable:no-empty
|
||||
describe("run", () => {
|
||||
let probot: Probot;
|
||||
let server: Server;
|
||||
let output: any;
|
||||
let env: NodeJS.ProcessEnv;
|
||||
|
||||
const streamLogsToOutput = new Stream.Writable({ objectMode: true });
|
||||
streamLogsToOutput._write = (object, encoding, done) => {
|
||||
|
@ -19,34 +21,26 @@ describe("run", () => {
|
|||
beforeEach(() => {
|
||||
// Clear log output
|
||||
output = [];
|
||||
process.env.DISABLE_WEBHOOK_EVENT_CHECK = "true";
|
||||
probot = new Probot({ githubToken: "faketoken" });
|
||||
env = {
|
||||
DISABLE_WEBHOOK_EVENT_CHECK: "true",
|
||||
APP_ID: "1",
|
||||
PRIVATE_KEY_PATH: path.join(__dirname, "test-private-key.pem"),
|
||||
WEBHOOK_PROXY_URL: "https://smee.io/EfHXC9BFfGAxbM6J",
|
||||
WEBHOOK_SECRET: "secret",
|
||||
LOG_LEVEL: "fatal",
|
||||
};
|
||||
});
|
||||
|
||||
describe("run", () => {
|
||||
let env: NodeJS.ProcessEnv;
|
||||
|
||||
beforeAll(() => {
|
||||
env = { ...process.env };
|
||||
process.env.APP_ID = "1";
|
||||
process.env.PRIVATE_KEY_PATH = path.join(
|
||||
__dirname,
|
||||
"test-private-key.pem"
|
||||
);
|
||||
process.env.WEBHOOK_PROXY_URL = "https://smee.io/EfHXC9BFfGAxbM6J";
|
||||
process.env.WEBHOOK_SECRET = "secret";
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
process.env = env;
|
||||
});
|
||||
|
||||
describe("params", () => {
|
||||
it("runs with a function as argument", async () => {
|
||||
let initialized = false;
|
||||
|
||||
server = await run(() => {
|
||||
initialized = true;
|
||||
});
|
||||
server = await run(
|
||||
() => {
|
||||
initialized = true;
|
||||
},
|
||||
{ env }
|
||||
);
|
||||
expect(initialized).toBeTruthy();
|
||||
await server.stop();
|
||||
});
|
||||
|
@ -58,28 +52,61 @@ describe("run", () => {
|
|||
|
||||
it("runs without config and loads the setup app", async () => {
|
||||
let initialized = false;
|
||||
delete process.env.PRIVATE_KEY_PATH;
|
||||
process.env.PORT = "3003";
|
||||
delete env.PRIVATE_KEY_PATH;
|
||||
env.PORT = "3003";
|
||||
|
||||
return new Promise(async (resolve) => {
|
||||
server = await run(({ app }: { app: Probot }) => {
|
||||
initialized = true;
|
||||
});
|
||||
server = await run(
|
||||
({ app }: { app: Probot }) => {
|
||||
initialized = true;
|
||||
},
|
||||
{ env }
|
||||
);
|
||||
expect(initialized).toBeFalsy();
|
||||
await server.stop();
|
||||
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("has version", async () => {
|
||||
return new Promise(async (resolve) => {
|
||||
server = await run(({ app }: { app: Probot }) => {});
|
||||
expect(probot.version).toBe("0.0.0-development");
|
||||
await server.stop();
|
||||
describe("webhooks", () => {
|
||||
it("POST /", async () => {
|
||||
server = await run(() => {}, { env });
|
||||
|
||||
resolve(null);
|
||||
const dataString = require("./fixtures/webhook/push.json");
|
||||
|
||||
await request(server.app)
|
||||
.post("/")
|
||||
.send(dataString)
|
||||
.set("x-github-event", "push")
|
||||
.set("x-hub-signature", sign("secret", dataString))
|
||||
.set("x-github-delivery", "123")
|
||||
.expect(200);
|
||||
|
||||
await server.stop();
|
||||
});
|
||||
|
||||
it("custom webhook path", async () => {
|
||||
server = await run(() => {}, {
|
||||
env: {
|
||||
...env,
|
||||
WEBHOOK_SECRET: "secret",
|
||||
WEBHOOK_PATH: "/custom-webhook",
|
||||
},
|
||||
});
|
||||
|
||||
const dataString = require("./fixtures/webhook/push.json");
|
||||
|
||||
await request(server.app)
|
||||
.post("/custom-webhook")
|
||||
.send(dataString)
|
||||
.set("x-github-event", "push")
|
||||
.set("x-hub-signature", sign("secret", dataString))
|
||||
.set("x-github-delivery", "123")
|
||||
.expect(200);
|
||||
|
||||
await server.stop();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -41,7 +41,7 @@ describe("Server", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("webhook handler", () => {
|
||||
describe("webhook handler (POST /)", () => {
|
||||
it("should 500 on a webhook error", async () => {
|
||||
webhook.mockImplementation(
|
||||
(req: Request, res: Response, callback: NextFunction) =>
|
||||
|
@ -53,11 +53,123 @@ describe("Server", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("with an unknown url", () => {
|
||||
describe("GET unknown URL", () => {
|
||||
it("responds with 404", async () => {
|
||||
await request(server.app).get("/notfound").expect(404);
|
||||
expect(output.length).toEqual(1);
|
||||
expect(output[0].msg).toContain("GET /notfound 404 -");
|
||||
});
|
||||
});
|
||||
|
||||
describe(".start() / .stop()", () => {
|
||||
it("should expect the correct error if port already in use", (next) => {
|
||||
expect.assertions(1);
|
||||
|
||||
// block port 3001
|
||||
const http = require("http");
|
||||
const blockade = http.createServer().listen(3001, async () => {
|
||||
const server = new Server({
|
||||
log: pino(streamLogsToOutput),
|
||||
port: 3001,
|
||||
});
|
||||
|
||||
try {
|
||||
await server.start();
|
||||
} catch (error) {
|
||||
expect(error.message).toEqual(
|
||||
"Port 3001 is already in use. You can define the PORT environment variable to use a different port."
|
||||
);
|
||||
}
|
||||
|
||||
await server.stop();
|
||||
blockade.close(() => next());
|
||||
});
|
||||
});
|
||||
|
||||
it("should listen to port when not in use", async () => {
|
||||
const testApp = new Server({ port: 3001, log: pino(streamLogsToOutput) });
|
||||
await testApp.start();
|
||||
|
||||
expect(output.length).toEqual(2);
|
||||
expect(output[1].msg).toEqual("Listening on http://localhost:3001");
|
||||
|
||||
await testApp.stop();
|
||||
});
|
||||
|
||||
it("respects host/ip config when starting up HTTP server", async () => {
|
||||
const testApp = new Server({
|
||||
port: 3002,
|
||||
host: "127.0.0.1",
|
||||
log: pino(streamLogsToOutput),
|
||||
});
|
||||
await testApp.start();
|
||||
|
||||
expect(output.length).toEqual(2);
|
||||
expect(output[1].msg).toEqual("Listening on http://127.0.0.1:3002");
|
||||
|
||||
await testApp.stop();
|
||||
});
|
||||
});
|
||||
|
||||
describe("router", () => {
|
||||
it("prefixes paths with route name", () => {
|
||||
const router = server.router("/my-app");
|
||||
router.get("/foo", (req, res) => res.end("foo"));
|
||||
|
||||
return request(server.app).get("/my-app/foo").expect(200, "foo");
|
||||
});
|
||||
|
||||
it("allows routes with no path", () => {
|
||||
const router = server.router();
|
||||
router.get("/foo", (req, res) => res.end("foo"));
|
||||
|
||||
return request(server.app).get("/foo").expect(200, "foo");
|
||||
});
|
||||
|
||||
it("allows you to overwrite the root path", () => {
|
||||
const router = server.router();
|
||||
router.get("/", (req, res) => res.end("foo"));
|
||||
|
||||
return request(server.app).get("/").expect(200, "foo");
|
||||
});
|
||||
|
||||
it("isolates apps from affecting each other", async () => {
|
||||
["foo", "bar"].forEach((name) => {
|
||||
const router = server.router("/" + name);
|
||||
|
||||
router.use((req, res, next) => {
|
||||
res.append("X-Test", name);
|
||||
next();
|
||||
});
|
||||
|
||||
router.get("/hello", (req, res) => res.end(name));
|
||||
});
|
||||
|
||||
await request(server.app)
|
||||
.get("/foo/hello")
|
||||
.expect(200, "foo")
|
||||
.expect("X-Test", "foo");
|
||||
|
||||
await request(server.app)
|
||||
.get("/bar/hello")
|
||||
.expect(200, "bar")
|
||||
.expect("X-Test", "bar");
|
||||
});
|
||||
|
||||
it("responds with 500 on error", async () => {
|
||||
server.app.get("/boom", () => {
|
||||
throw new Error("boom");
|
||||
});
|
||||
|
||||
await request(server.app).get("/boom").expect(500);
|
||||
});
|
||||
|
||||
it("responds with 500 on async error", async () => {
|
||||
server.app.get("/boom", () => {
|
||||
return Promise.reject(new Error("boom"));
|
||||
});
|
||||
|
||||
await request(server.app).get("/boom").expect(500);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue