UNPKG

atlassian-connect-express

Version:

Library for building Atlassian Add-ons on top of Express

232 lines (202 loc) 6.13 kB
const jwt = require("atlassian-jwt"); const bodyParser = require("body-parser"); const express = require("express"); const http = require("http"); const request = require("request"); const moment = require("moment"); const nock = require("nock"); const logger = require("./logger"); const requireOptional = require("../lib/internal/require-optional"); const jiraGlobalSchema = require("./jira-global-schema"); const helper = require("./test_helper"); const ac = require("../index"); // Helps failures be reported to the test framework process.on("unhandledRejection", err => { throw err; }); describe("Auto registration (UPM)", () => { let requireOptionalStub; let requestGetStub; let server; let app; let addon; beforeEach(() => { requireOptionalStub = jest.spyOn(requireOptional, "requireOptional"); app = express(); addon = {}; app.set("env", "development"); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.get("/rest/plugins/1.0/", (req, res) => { res.setHeader("upm-token", "123"); res.json({ plugins: [] }); res.status(200).end(); }); // Post request to UPM installer app.post("/confluence/rest/plugins/1.0/", (req, res) => { request({ url: `${helper.addonBaseUrl}/installed`, qs: { jwt: createJwtToken() }, method: "POST", json: helper.installedPayload }); res.status(200).end(); }); app.delete(/plugins\/1.0\/(.*?)-key/, (req, res) => { res.status(200).end(); }); ac.store.register("teststore", (logger, opts) => { return require("../lib/store/sequelize")(logger, opts); }); nock("https://developer.atlassian.com") .get("/static/connect/docs/latest/schema/jira-global-schema.json") .reply(200, jiraGlobalSchema); }); afterEach(() => { delete process.env.AC_LOCAL_BASE_URL; requireOptionalStub.mockRestore(); if (requestGetStub) { requestGetStub.mockRestore(); } if (server) { server.close(); } }); function createJwtToken() { const jwtPayload = { iss: helper.installedPayload.clientKey, iat: moment().utc().unix(), exp: moment().utc().add(10, "minutes").unix() }; return jwt.encode(jwtPayload, helper.installedPayload.sharedSecret); } function createAddon(hosts) { addon = ac( app, { config: { development: { store: { adapter: "teststore", type: "memory" }, hosts } } }, logger ); } function startServer(cb) { server = http.createServer(app).listen(helper.addonPort, cb); } // eslint-disable-next-line no-unused-vars function stubInstalledPluginsResponse(key) { requestGetStub = jest.spyOn(request, "get"); requestGetStub.mockImplementation((reqObject, callback) => { callback( null, null, JSON.stringify({ plugins: [ { key: "my-test-app-key" } ] }) ); }); } function stubNgrokV2() { requireOptionalStub.mockReturnValue( Promise.resolve({ // eslint-disable-next-line no-unused-vars connect(port, cb) { return undefined; } }) ); } function stubNgrokWorking() { requireOptionalStub.mockReturnValue( Promise.resolve({ // eslint-disable-next-line no-unused-vars connect(port) { return Promise.resolve("https://test.ngrok.io"); } }) ); } // eslint-disable-next-line no-unused-vars function stubNgrokUnavailable() { const error = new Error( "Cannot find module 'ngrok' (no worries, this error is thrown on purpose by stubNgrokUnavailable in test)" ); error.code = "MODULE_NOT_FOUND"; requireOptionalStub.returns(Promise.reject(error)); } it("registration works with local host and does not involve ngrok", async () => { createAddon([helper.productBaseUrl]); return new Promise(resolve => { startServer(async () => { await addon.register(); expect(requireOptionalStub).not.toHaveBeenCalled(); resolve(); }); }); }); it("registration works with remote host via ngrok", async () => { stubNgrokWorking(); stubInstalledPluginsResponse("my-test-app-key"); createAddon(["http://admin:admin@example.atlassian.net/wiki"]); await addon.register(); expect(requireOptionalStub).toHaveBeenCalled(); }); it("registration does not work with ngrok 2.x (error will print to console)", async () => { stubNgrokV2(); stubInstalledPluginsResponse("my-test-app-key"); createAddon(["http://admin:admin@example.atlassian.net/wiki"]); await expect(async () => { await addon.register(); }).rejects.toThrow(); expect(requireOptionalStub).toHaveBeenCalled(); }); it("validator works with an invalid connect descriptor", async () => { createAddon([helper.productBaseUrl]); addon.descriptor = { key: "my-test-app-key", name: "My Test App Name", baseUrl: "http://something", description: "My test app description.", apiMigrtios: { gdpr: true } }; const results = await addon.validateDescriptor(); expect(results.length).toBeGreaterThan(0); }); it("validator works with a valid connect descriptor", async () => { createAddon([helper.productBaseUrl]); addon.descriptor = { key: "my-test-app-key", name: "My Test App Name", description: "My test app description.", baseUrl: "https://ngrok.io", authentication: { type: "jwt" }, modules: { generalPages: [ { key: "hello-world-page-jira", location: "system.top.navigation.bar", name: { value: "Hello World" }, url: "/hello-world" } ] } }; const results = await addon.validateDescriptor(); expect(results.length).toEqual(0); }); });