diff --git a/packages/backend-core/src/events/constants.js b/packages/backend-core/src/events/constants.js index c35fc71ab8..7ea68c5a98 100644 --- a/packages/backend-core/src/events/constants.js +++ b/packages/backend-core/src/events/constants.js @@ -64,8 +64,10 @@ exports.Events = { ROLE_ASSIGNED: "role:assigned", ROLE_UNASSIGNED: "role:unassigned", - // APP / CLIENT - CLIENT_SERVED: "client:served", + // SERVE + SERVED_BUILDER: "served:builder", + SERVED_APP: "served:app", + SERVED_APP_PREVIEW: "served:app:preview", // DATASOURCE DATASOURCE_CREATED: "datasource:created", @@ -102,9 +104,6 @@ exports.Events = { // ROW // ROW_CREATED: "row:created", - // BUILDER - BUILDER_SERVED: "builder:served", - // COMPONENT COMPONENT_CREATED: "component:created", COMPONENT_DELETED: "component:deleted", diff --git a/packages/backend-core/src/events/handlers/screen.js b/packages/backend-core/src/events/handlers/screen.js index 53bc2b4fc7..0e2b4d268d 100644 --- a/packages/backend-core/src/events/handlers/screen.js +++ b/packages/backend-core/src/events/handlers/screen.js @@ -1,13 +1,11 @@ const events = require("../events") const { Events } = require("../constants") -// TODO exports.created = () => { const properties = {} events.processEvent(Events.SCREEN_CREATED, properties) } -// TODO exports.deleted = () => { const properties = {} events.processEvent(Events.SCREEN_DELETED, properties) diff --git a/packages/backend-core/src/events/handlers/serve.js b/packages/backend-core/src/events/handlers/serve.js index 29c67d00ab..169d7338c2 100644 --- a/packages/backend-core/src/events/handlers/serve.js +++ b/packages/backend-core/src/events/handlers/serve.js @@ -1,14 +1,19 @@ const events = require("../events") const { Events } = require("../constants") -// TODO -exports.builderServed = () => { +/* eslint-disable */ + +exports.servedBuilder = version => { const properties = {} - events.processEvent(Events.BUILDER_SERVED, properties) + events.processEvent(Events.SERVED_BUILDER, properties) } -// TODO -exports.clientServed = () => { +exports.servedApp = appMetadata => { const properties = {} - events.processEvent(Events.CLIENT_SERVED, properties) + events.processEvent(Events.SERVED_APP, properties) +} + +exports.servedAppPreview = appMetadata => { + const properties = {} + events.processEvent(Events.SERVED_APP_PREVIEW, properties) } diff --git a/packages/backend-core/src/tests/utilities/mocks/events.js b/packages/backend-core/src/tests/utilities/mocks/events.js index 14a9012d1f..0489d0d250 100644 --- a/packages/backend-core/src/tests/utilities/mocks/events.js +++ b/packages/backend-core/src/tests/utilities/mocks/events.js @@ -90,7 +90,11 @@ jest.mock("../../../events", () => { passwordResetRequested: jest.fn(), passwordReset: jest.fn(), }, - serve: {}, + serve: { + servedBuilder: jest.fn(), + servedApp: jest.fn(), + servedAppPreview: jest.fn(), + }, table: {}, view: {}, } diff --git a/packages/server/src/api/controllers/static/index.js b/packages/server/src/api/controllers/static/index.js index 82e66ab545..73790db3ac 100644 --- a/packages/server/src/api/controllers/static/index.js +++ b/packages/server/src/api/controllers/static/index.js @@ -15,10 +15,12 @@ const env = require("../../../environment") const { clientLibraryPath } = require("../../../utilities") const { upload } = require("../../../utilities/fileSystem") const { attachmentsRelativeURL } = require("../../../utilities") -const { DocumentTypes } = require("../../../db/utils") +const { DocumentTypes, isDevAppID } = require("../../../db/utils") const { getAppDB, updateAppId } = require("@budibase/backend-core/context") const AWS = require("aws-sdk") const AWS_REGION = env.AWS_REGION ? env.AWS_REGION : "eu-west-1" +const { events } = require("@budibase/backend-core") +const version = require("../../../../package.json").version async function prepareUpload({ s3Key, bucket, metadata, file }) { const response = await upload({ @@ -57,6 +59,7 @@ async function getAppIdFromUrl(ctx) { exports.serveBuilder = async function (ctx) { let builderPath = resolve(TOP_LEVEL_PATH, "builder") await send(ctx, ctx.file, { root: builderPath }) + events.serve.servedBuilder(version) } exports.uploadFile = async function (ctx) { @@ -82,24 +85,35 @@ exports.uploadFile = async function (ctx) { exports.serveApp = async function (ctx) { let appId = await getAppIdFromUrl(ctx) - const App = require("./templates/BudibaseApp.svelte").default const db = getAppDB({ skip_setup: true }) const appInfo = await db.get(DocumentTypes.APP_METADATA) - const { head, html, css } = App.render({ - title: appInfo.name, - production: env.isProd(), - appId, - clientLibPath: clientLibraryPath(appId, appInfo.version), - }) + if (!env.isJest()) { + const App = require("./templates/BudibaseApp.svelte").default + const { head, html, css } = App.render({ + title: appInfo.name, + production: env.isProd(), + appId, + clientLibPath: clientLibraryPath(appId, appInfo.version), + }) - const appHbs = loadHandlebarsFile(`${__dirname}/templates/app.hbs`) - ctx.body = await processString(appHbs, { - head, - body: html, - style: css.code, - appId, - }) + const appHbs = loadHandlebarsFile(`${__dirname}/templates/app.hbs`) + ctx.body = await processString(appHbs, { + head, + body: html, + style: css.code, + appId, + }) + } else { + // just return the app info for jest to assert on + ctx.body = appInfo + } + + if (isDevAppID(appInfo.appId)) { + events.serve.servedAppPreview(appInfo) + } else { + events.serve.servedApp(appInfo) + } } exports.serveClientLibrary = async function (ctx) { diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js index bcb111db50..582bb1eef9 100644 --- a/packages/server/src/api/index.js +++ b/packages/server/src/api/index.js @@ -72,10 +72,8 @@ router.use(async (ctx, next) => { validationErrors: err.validation, error, } - if (env.NODE_ENV !== "jest") { - ctx.log.error(err) - console.trace(err) - } + ctx.log.error(err) + console.trace(err) } }) diff --git a/packages/server/src/api/routes/tests/static.spec.js b/packages/server/src/api/routes/tests/static.spec.js index 2ba9a6e8c8..d0a89d1fa4 100644 --- a/packages/server/src/api/routes/tests/static.spec.js +++ b/packages/server/src/api/routes/tests/static.spec.js @@ -14,8 +14,10 @@ jest.mock("aws-sdk", () => ({ })) const setup = require("./utilities") +const { events } = require("@budibase/backend-core") +const version = require("../../../../package.json").version -describe("/attachments", () => { +describe("/static", () => { let request = setup.getRequest() let config = setup.getConfig() let app @@ -26,73 +28,133 @@ describe("/attachments", () => { app = await config.init() }) - describe("generateSignedUrls", () => { - let datasource - - beforeEach(async () => { - datasource = await config.createDatasource({ - datasource: { - type: "datasource", - name: "Test", - source: "S3", - config: {}, - }, - }) - }) - - it("should be able to generate a signed upload URL", async () => { - const bucket = "foo" - const key = "bar" + describe("/builder", () => { + it("should serve the builder", async () => { const res = await request - .post(`/api/attachments/${datasource._id}/url`) - .send({ bucket, key }) + .get("/builder/portal") .set(config.defaultHeaders()) - .expect("Content-Type", /json/) + .expect("Content-Type", /text\/html/) .expect(200) - expect(res.body.signedUrl).toEqual("my-url") - expect(res.body.publicUrl).toEqual( - `https://${bucket}.s3.eu-west-1.amazonaws.com/${key}` - ) - }) - it("should handle an invalid datasource ID", async () => { - const res = await request - .post(`/api/attachments/foo/url`) - .send({ - bucket: "foo", - key: "bar", - }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(400) - expect(res.body.message).toEqual( - "The specified datasource could not be found" - ) - }) - - it("should require a bucket parameter", async () => { - const res = await request - .post(`/api/attachments/${datasource._id}/url`) - .send({ - bucket: undefined, - key: "bar", - }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(400) - expect(res.body.message).toEqual("bucket and key values are required") - }) - - it("should require a key parameter", async () => { - const res = await request - .post(`/api/attachments/${datasource._id}/url`) - .send({ - bucket: "foo", - }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(400) - expect(res.body.message).toEqual("bucket and key values are required") + expect(res.text).toContain("Budibase") + expect(events.serve.servedBuilder).toBeCalledTimes(1) + expect(events.serve.servedBuilder).toBeCalledWith(version) }) }) + + describe("/app", () => { + + beforeEach(() => { + jest.clearAllMocks() + }) + + it("should serve the app by id", async () => { + const res = await request + .get(`/${config.prodAppId}`) + .set(config.defaultHeaders()) + .expect(200) + + expect(res.body.appId).toBe(config.prodAppId) + expect(events.serve.servedApp).toBeCalledTimes(1) + expect(events.serve.servedApp).toBeCalledWith(res.body) + expect(events.serve.servedAppPreview).not.toBeCalled() + }) + + it("should serve the app by url", async () => { + const res = await request + .get(`${config.prodApp.url}`) + .set(config.defaultHeaders()) + .expect(200) + + expect(res.body.appId).toBe(config.prodAppId) + expect(events.serve.servedApp).toBeCalledTimes(1) + expect(events.serve.servedApp).toBeCalledWith(res.body) + expect(events.serve.servedAppPreview).not.toBeCalled() + }) + + it("should serve the app preview by id", async () => { + const res = await request + .get(`/${config.appId}`) + .set(config.defaultHeaders()) + .expect(200) + + expect(res.body.appId).toBe(config.appId) + expect(events.serve.servedAppPreview).toBeCalledTimes(1) + expect(events.serve.servedAppPreview).toBeCalledWith(res.body) + expect(events.serve.servedApp).not.toBeCalled() + }) + }) + + describe("/attachments", () => { + describe("generateSignedUrls", () => { + let datasource + + beforeEach(async () => { + datasource = await config.createDatasource({ + datasource: { + type: "datasource", + name: "Test", + source: "S3", + config: {}, + }, + }) + }) + + it("should be able to generate a signed upload URL", async () => { + const bucket = "foo" + const key = "bar" + const res = await request + .post(`/api/attachments/${datasource._id}/url`) + .send({ bucket, key }) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + expect(res.body.signedUrl).toEqual("my-url") + expect(res.body.publicUrl).toEqual( + `https://${bucket}.s3.eu-west-1.amazonaws.com/${key}` + ) + }) + + it("should handle an invalid datasource ID", async () => { + const res = await request + .post(`/api/attachments/foo/url`) + .send({ + bucket: "foo", + key: "bar", + }) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(400) + expect(res.body.message).toEqual( + "The specified datasource could not be found" + ) + }) + + it("should require a bucket parameter", async () => { + const res = await request + .post(`/api/attachments/${datasource._id}/url`) + .send({ + bucket: undefined, + key: "bar", + }) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(400) + expect(res.body.message).toEqual("bucket and key values are required") + }) + + it("should require a key parameter", async () => { + const res = await request + .post(`/api/attachments/${datasource._id}/url`) + .send({ + bucket: "foo", + }) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(400) + expect(res.body.message).toEqual("bucket and key values are required") + }) + }) + }) + }) diff --git a/packages/server/src/environment.js b/packages/server/src/environment.js index 62d3d70cea..60648b48b2 100644 --- a/packages/server/src/environment.js +++ b/packages/server/src/environment.js @@ -1,7 +1,10 @@ function isTest() { + return isCypress() || isJest() +} + +function isJest() { return ( process.env.NODE_ENV === "jest" || - process.env.NODE_ENV === "cypress" || (process.env.JEST_WORKER_ID != null && process.env.JEST_WORKER_ID !== "null") ) @@ -73,6 +76,7 @@ module.exports = { module.exports[key] = value }, isTest, + isJest, isCypress, isDev, isProd: () => {