smtp events + centralise worker test config

This commit is contained in:
Rory Powell 2022-04-06 16:57:56 +01:00
parent 266b34aaa0
commit befb61c915
18 changed files with 600 additions and 530 deletions

View File

@ -60,6 +60,26 @@ class TestConfiguration {
return this.prodAppId return this.prodAppId
} }
// SETUP / TEARDOWN
// use a new id as the name to avoid name collisions
async init(appName = newid()) {
await this.globalUser()
return this.createApp(appName)
}
end() {
if (!this) {
return
}
if (this.server) {
this.server.close()
}
cleanup(this.allApps.map(app => app.appId))
}
// UTILS
async _req(config, params, controlFunc) { async _req(config, params, controlFunc) {
const request = {} const request = {}
// fake cookies, we don't need them // fake cookies, we don't need them
@ -88,19 +108,7 @@ class TestConfiguration {
} }
} }
async generateApiKey(userId = GLOBAL_USER_ID) { // USER / AUTH
const db = getGlobalDB(TENANT_ID)
const id = generateDevInfoID(userId)
let devInfo
try {
devInfo = await db.get(id)
} catch (err) {
devInfo = { _id: id, userId }
}
devInfo.apiKey = encrypt(`${TENANT_ID}${SEPARATOR}${newid()}`)
await db.put(devInfo)
return devInfo.apiKey
}
async globalUser({ async globalUser({
id = GLOBAL_USER_ID, id = GLOBAL_USER_ID,
@ -138,314 +146,6 @@ class TestConfiguration {
} }
} }
// use a new id as the name to avoid name collisions
async init(appName = newid()) {
await this.globalUser()
return this.createApp(appName)
}
end() {
if (!this) {
return
}
if (this.server) {
this.server.close()
}
cleanup(this.allApps.map(app => app.appId))
}
defaultHeaders(extras = {}) {
const auth = {
userId: GLOBAL_USER_ID,
sessionId: "sessionid",
tenantId: TENANT_ID,
}
const app = {
roleId: BUILTIN_ROLE_IDS.ADMIN,
appId: this.appId,
}
const authToken = jwt.sign(auth, env.JWT_SECRET)
const appToken = jwt.sign(app, env.JWT_SECRET)
const headers = {
Accept: "application/json",
Cookie: [
`${Cookies.Auth}=${authToken}`,
`${Cookies.CurrentApp}=${appToken}`,
],
[Headers.CSRF_TOKEN]: CSRF_TOKEN,
...extras,
}
if (this.appId) {
headers[Headers.APP_ID] = this.appId
}
return headers
}
publicHeaders({ prodApp = true } = {}) {
const appId = prodApp ? this.prodAppId : this.appId
const headers = {
Accept: "application/json",
}
if (appId) {
headers[Headers.APP_ID] = appId
}
return headers
}
async roleHeaders({
email = EMAIL,
roleId = BUILTIN_ROLE_IDS.ADMIN,
builder = false,
prodApp = true,
} = {}) {
return this.login({ email, roleId, builder, prodApp })
}
async createApp(appName) {
// create dev app
this.app = await this._req({ name: appName }, null, controllers.app.create)
this.appId = this.app.appId
context.updateAppId(this.appId)
// create production app
this.prodApp = await this.deploy()
this.prodAppId = this.prodApp.appId
this.allApps.push(this.prodApp)
this.allApps.push(this.app)
return this.app
}
async deploy() {
await this._req(null, null, controllers.deploy.deployApp)
const prodAppId = this.getAppId().replace("_dev", "")
return context.doInAppContext(prodAppId, async () => {
const appPackage = await this._req(
null,
{ appId: prodAppId },
controllers.app.fetchAppPackage
)
return appPackage.application
})
}
async updateTable(config = null) {
config = config || basicTable()
this.table = await this._req(config, null, controllers.table.save)
return this.table
}
async createTable(config = null) {
if (config != null && config._id) {
delete config._id
}
return this.updateTable(config)
}
async getTable(tableId = null) {
tableId = tableId || this.table._id
return this._req(null, { tableId }, controllers.table.find)
}
async createLinkedTable(relationshipType = null, links = ["link"]) {
if (!this.table) {
throw "Must have created a table first."
}
const tableConfig = basicTable()
tableConfig.primaryDisplay = "name"
for (let link of links) {
tableConfig.schema[link] = {
type: "link",
fieldName: link,
tableId: this.table._id,
name: link,
}
if (relationshipType) {
tableConfig.schema[link].relationshipType = relationshipType
}
}
const linkedTable = await this.createTable(tableConfig)
this.linkedTable = linkedTable
return linkedTable
}
async createAttachmentTable() {
const table = basicTable()
table.schema.attachment = {
type: "attachment",
}
return this.createTable(table)
}
async createRow(config = null) {
if (!this.table) {
throw "Test requires table to be configured."
}
const tableId = (config && config.tableId) || this.table._id
config = config || basicRow(tableId)
return this._req(config, { tableId }, controllers.row.save)
}
async getRow(tableId, rowId) {
return this._req(null, { tableId, rowId }, controllers.row.find)
}
async getRows(tableId) {
if (!tableId && this.table) {
tableId = this.table._id
}
return this._req(null, { tableId }, controllers.row.fetch)
}
async createRole(config = null) {
config = config || basicRole()
return this._req(config, null, controllers.role.save)
}
async addPermission(roleId, resourceId, level = "read") {
return this._req(
null,
{
roleId,
resourceId,
level,
},
controllers.perms.addPermission
)
}
async createView(config) {
if (!this.table) {
throw "Test requires table to be configured."
}
const view = config || {
map: "function(doc) { emit(doc[doc.key], doc._id); } ",
tableId: this.table._id,
name: "ViewTest",
}
return this._req(view, null, controllers.view.save)
}
async createAutomation(config) {
config = config || basicAutomation()
if (config._rev) {
delete config._rev
}
this.automation = (
await this._req(config, null, controllers.automation.create)
).automation
return this.automation
}
async getAllAutomations() {
return this._req(null, null, controllers.automation.fetch)
}
async deleteAutomation(automation = null) {
automation = automation || this.automation
if (!automation) {
return
}
return this._req(
null,
{ id: automation._id, rev: automation._rev },
controllers.automation.destroy
)
}
async createDatasource(config = null) {
config = config || basicDatasource()
const response = await this._req(config, null, controllers.datasource.save)
this.datasource = response.datasource
return this.datasource
}
async updateDatasource(datasource) {
const response = await this._req(
datasource,
{ datasourceId: datasource._id },
controllers.datasource.update
)
this.datasource = response.datasource
return this.datasource
}
async restDatasource(cfg) {
return this.createDatasource({
datasource: {
...basicDatasource().datasource,
source: "REST",
config: cfg || {},
},
})
}
async dynamicVariableDatasource() {
let datasource = await this.restDatasource()
const basedOnQuery = await this.createQuery({
...basicQuery(datasource._id),
fields: {
path: "www.google.com",
},
})
datasource = await this.updateDatasource({
...datasource,
config: {
dynamicVariables: [
{
queryId: basedOnQuery._id,
name: "variable3",
value: "{{ data.0.[value] }}",
},
],
},
})
return { datasource, query: basedOnQuery }
}
async previewQuery(request, config, datasource, fields) {
return request
.post(`/api/queries/preview`)
.send({
datasourceId: datasource._id,
parameters: {},
fields,
queryVerb: "read",
name: datasource.name,
})
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
}
async createQuery(config = null) {
if (!this.datasource && !config) {
throw "No data source created for query."
}
config = config || basicQuery(this.datasource._id)
return this._req(config, null, controllers.query.save)
}
async createScreen(config = null) {
config = config || basicScreen()
return this._req(config, null, controllers.screen.save)
}
async createWebhook(config = null) {
if (!this.automation) {
throw "Must create an automation before creating webhook."
}
config = config || basicWebhook(this.automation._id)
return (await this._req(config, null, controllers.webhook.save)).webhook
}
async createLayout(config = null) {
config = config || basicLayout()
return await this._req(config, null, controllers.layout.save)
}
async createUser(id = null, email = EMAIL) { async createUser(id = null, email = EMAIL) {
const globalId = !id ? `us_${Math.random()}` : `us_${id}` const globalId = !id ? `us_${Math.random()}` : `us_${id}`
const resp = await this.globalUser({ id: globalId, email }) const resp = await this.globalUser({ id: globalId, email })
@ -500,6 +200,334 @@ class TestConfiguration {
} }
}) })
} }
defaultHeaders(extras = {}) {
const auth = {
userId: GLOBAL_USER_ID,
sessionId: "sessionid",
tenantId: TENANT_ID,
}
const app = {
roleId: BUILTIN_ROLE_IDS.ADMIN,
appId: this.appId,
}
const authToken = jwt.sign(auth, env.JWT_SECRET)
const appToken = jwt.sign(app, env.JWT_SECRET)
const headers = {
Accept: "application/json",
Cookie: [
`${Cookies.Auth}=${authToken}`,
`${Cookies.CurrentApp}=${appToken}`,
],
[Headers.CSRF_TOKEN]: CSRF_TOKEN,
...extras,
}
if (this.appId) {
headers[Headers.APP_ID] = this.appId
}
return headers
}
publicHeaders({ prodApp = true } = {}) {
const appId = prodApp ? this.prodAppId : this.appId
const headers = {
Accept: "application/json",
}
if (appId) {
headers[Headers.APP_ID] = appId
}
return headers
}
async roleHeaders({
email = EMAIL,
roleId = BUILTIN_ROLE_IDS.ADMIN,
builder = false,
prodApp = true,
} = {}) {
return this.login({ email, roleId, builder, prodApp })
}
// API
async generateApiKey(userId = GLOBAL_USER_ID) {
const db = getGlobalDB(TENANT_ID)
const id = generateDevInfoID(userId)
let devInfo
try {
devInfo = await db.get(id)
} catch (err) {
devInfo = { _id: id, userId }
}
devInfo.apiKey = encrypt(`${TENANT_ID}${SEPARATOR}${newid()}`)
await db.put(devInfo)
return devInfo.apiKey
}
// APP
async createApp(appName) {
// create dev app
this.app = await this._req({ name: appName }, null, controllers.app.create)
this.appId = this.app.appId
context.updateAppId(this.appId)
// create production app
this.prodApp = await this.deploy()
this.prodAppId = this.prodApp.appId
this.allApps.push(this.prodApp)
this.allApps.push(this.app)
return this.app
}
async deploy() {
await this._req(null, null, controllers.deploy.deployApp)
const prodAppId = this.getAppId().replace("_dev", "")
return context.doInAppContext(prodAppId, async () => {
const appPackage = await this._req(
null,
{ appId: prodAppId },
controllers.app.fetchAppPackage
)
return appPackage.application
})
}
// TABLE
async updateTable(config = null) {
config = config || basicTable()
this.table = await this._req(config, null, controllers.table.save)
return this.table
}
async createTable(config = null) {
if (config != null && config._id) {
delete config._id
}
return this.updateTable(config)
}
async getTable(tableId = null) {
tableId = tableId || this.table._id
return this._req(null, { tableId }, controllers.table.find)
}
async createLinkedTable(relationshipType = null, links = ["link"]) {
if (!this.table) {
throw "Must have created a table first."
}
const tableConfig = basicTable()
tableConfig.primaryDisplay = "name"
for (let link of links) {
tableConfig.schema[link] = {
type: "link",
fieldName: link,
tableId: this.table._id,
name: link,
}
if (relationshipType) {
tableConfig.schema[link].relationshipType = relationshipType
}
}
const linkedTable = await this.createTable(tableConfig)
this.linkedTable = linkedTable
return linkedTable
}
async createAttachmentTable() {
const table = basicTable()
table.schema.attachment = {
type: "attachment",
}
return this.createTable(table)
}
// ROW
async createRow(config = null) {
if (!this.table) {
throw "Test requires table to be configured."
}
const tableId = (config && config.tableId) || this.table._id
config = config || basicRow(tableId)
return this._req(config, { tableId }, controllers.row.save)
}
async getRow(tableId, rowId) {
return this._req(null, { tableId, rowId }, controllers.row.find)
}
async getRows(tableId) {
if (!tableId && this.table) {
tableId = this.table._id
}
return this._req(null, { tableId }, controllers.row.fetch)
}
// ROLE
async createRole(config = null) {
config = config || basicRole()
return this._req(config, null, controllers.role.save)
}
async addPermission(roleId, resourceId, level = "read") {
return this._req(
null,
{
roleId,
resourceId,
level,
},
controllers.perms.addPermission
)
}
// VIEW
async createView(config) {
if (!this.table) {
throw "Test requires table to be configured."
}
const view = config || {
map: "function(doc) { emit(doc[doc.key], doc._id); } ",
tableId: this.table._id,
name: "ViewTest",
}
return this._req(view, null, controllers.view.save)
}
// AUTOMATION
async createAutomation(config) {
config = config || basicAutomation()
if (config._rev) {
delete config._rev
}
this.automation = (
await this._req(config, null, controllers.automation.create)
).automation
return this.automation
}
async getAllAutomations() {
return this._req(null, null, controllers.automation.fetch)
}
async deleteAutomation(automation = null) {
automation = automation || this.automation
if (!automation) {
return
}
return this._req(
null,
{ id: automation._id, rev: automation._rev },
controllers.automation.destroy
)
}
async createWebhook(config = null) {
if (!this.automation) {
throw "Must create an automation before creating webhook."
}
config = config || basicWebhook(this.automation._id)
return (await this._req(config, null, controllers.webhook.save)).webhook
}
// DATASOURCE
async createDatasource(config = null) {
config = config || basicDatasource()
const response = await this._req(config, null, controllers.datasource.save)
this.datasource = response.datasource
return this.datasource
}
async updateDatasource(datasource) {
const response = await this._req(
datasource,
{ datasourceId: datasource._id },
controllers.datasource.update
)
this.datasource = response.datasource
return this.datasource
}
async restDatasource(cfg) {
return this.createDatasource({
datasource: {
...basicDatasource().datasource,
source: "REST",
config: cfg || {},
},
})
}
async dynamicVariableDatasource() {
let datasource = await this.restDatasource()
const basedOnQuery = await this.createQuery({
...basicQuery(datasource._id),
fields: {
path: "www.google.com",
},
})
datasource = await this.updateDatasource({
...datasource,
config: {
dynamicVariables: [
{
queryId: basedOnQuery._id,
name: "variable3",
value: "{{ data.0.[value] }}",
},
],
},
})
return { datasource, query: basedOnQuery }
}
// QUERY
async previewQuery(request, config, datasource, fields) {
return request
.post(`/api/queries/preview`)
.send({
datasourceId: datasource._id,
parameters: {},
fields,
queryVerb: "read",
name: datasource.name,
})
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
}
async createQuery(config = null) {
if (!this.datasource && !config) {
throw "No data source created for query."
}
config = config || basicQuery(this.datasource._id)
return this._req(config, null, controllers.query.save)
}
// SCREEN
async createScreen(config = null) {
config = config || basicScreen()
return this._req(config, null, controllers.screen.save)
}
// LAYOUT
async createLayout(config = null) {
config = config || basicLayout()
return await this._req(config, null, controllers.layout.save)
}
} }
module.exports = TestConfiguration module.exports = TestConfiguration

View File

@ -1,20 +1,20 @@
jest.mock("nodemailer") jest.mock("nodemailer")
const setup = require("./utilities") const { config, request, mocks, structures } = require("../../../tests")
const sendMailMock = setup.emailMock() const sendMailMock = mocks.email.mock()
const { events } = require("@budibase/backend-core") const { events } = require("@budibase/backend-core")
const TENANT_ID = "default" const TENANT_ID = structures.TENANT_ID
describe("/api/global/auth", () => { describe("/api/global/auth", () => {
let request = setup.getRequest()
let config = setup.getConfig()
let code let code
beforeAll(async () => { beforeAll(async () => {
await config.init() await config.beforeAll()
}) })
afterAll(setup.afterAll) afterAll(async () => {
await config.afterAll()
})
afterEach(() => { afterEach(() => {
jest.clearAllMocks() jest.clearAllMocks()

View File

@ -1,16 +1,14 @@
// mock the email system // mock the email system
jest.mock("nodemailer") jest.mock("nodemailer")
const setup = require("./utilities") const { config, structures, mocks, request } = require("../../../tests")
setup.emailMock() mocks.email.mock()
const { Configs } = require("@budibase/backend-core/constants") const { Configs } = require("@budibase/backend-core/constants")
const { events } = require("@budibase/backend-core") const { events } = require("@budibase/backend-core")
describe("configs", () => { describe("configs", () => {
let request = setup.getRequest()
let config = setup.getConfig()
beforeAll(async () => { beforeAll(async () => {
await config.init() await config.beforeAll()
}) })
beforeEach(() => { beforeEach(() => {
@ -18,15 +16,14 @@ describe("configs", () => {
}) })
afterAll(async () => { afterAll(async () => {
await setup.afterAll() await config.afterAll()
}) })
describe("post /api/global/configs", () => { describe("post /api/global/configs", () => {
const saveConfig = async (conf, type, _id, _rev) => { const saveConfig = async (conf, _id, _rev) => {
const data = { const data = {
type, ...conf,
config: conf,
_id, _id,
_rev _rev
} }
@ -46,14 +43,8 @@ describe("configs", () => {
describe("google", () => { describe("google", () => {
const saveGoogleConfig = async (conf, _id, _rev) => { const saveGoogleConfig = async (conf, _id, _rev) => {
const googleConfig = { const googleConfig = structures.configs.google(conf)
clientID: "clientID", return saveConfig(googleConfig, _id, _rev)
clientSecret: "clientSecret",
activated: true,
...conf
}
return saveConfig(googleConfig, Configs.GOOGLE, _id, _rev)
} }
describe("create", () => { describe("create", () => {
@ -106,19 +97,8 @@ describe("configs", () => {
describe("oidc", () => { describe("oidc", () => {
const saveOIDCConfig = async (conf, _id, _rev) => { const saveOIDCConfig = async (conf, _id, _rev) => {
const oidcConfig = { const oidcConfig = structures.configs.oidc(conf)
configs: [{ return saveConfig(oidcConfig, _id, _rev)
clientID: "clientID",
clientSecret: "clientSecret",
configUrl: "http://example.com",
logo: "logo",
name: "oidc",
uuid: "uuid",
activated: true,
...conf
}]
}
return saveConfig(oidcConfig, Configs.OIDC, _id, _rev)
} }
describe("create", () => { describe("create", () => {
@ -169,6 +149,34 @@ describe("configs", () => {
}) })
}) })
describe("smtp", () => {
const saveSMTPConfig = async (conf, _id, _rev) => {
const smtpConfig = structures.configs.smtp(conf)
return saveConfig(smtpConfig, _id, _rev)
}
describe("create", () => {
it ("should create SMTP config", async () => {
await config.deleteConfig(Configs.SMTP)
await saveSMTPConfig()
expect(events.email.SMTPUpdated).not.toBeCalled()
expect(events.email.SMTPCreated).toBeCalledTimes(1)
await config.deleteConfig(Configs.SMTP)
})
})
describe("update", () => {
it ("should update SMTP config", async () => {
const smtpConf = await saveSMTPConfig()
jest.clearAllMocks()
await saveSMTPConfig(smtpConf.config, smtpConf._id, smtpConf._rev)
expect(events.email.SMTPCreated).not.toBeCalled()
expect(events.email.SMTPUpdated).toBeCalledTimes(1)
await config.deleteConfig(Configs.SMTP)
})
})
})
}) })
it("should return the correct checklist status based on the state of the budibase installation", async () => { it("should return the correct checklist status based on the state of the budibase installation", async () => {

View File

@ -1,19 +1,20 @@
jest.mock("nodemailer") jest.mock("nodemailer")
const setup = require("./utilities") const { config, mocks, structures, request } = require("../../../tests")
const sendMailMock = setup.emailMock() const sendMailMock = mocks.email.mock()
const { EmailTemplatePurpose } = require("../../../constants") const { EmailTemplatePurpose } = require("../../../constants")
const { TENANT_ID } = require("./utilities/structures")
const TENANT_ID = structures.TENANT_ID
describe("/api/global/email", () => { describe("/api/global/email", () => {
let request = setup.getRequest()
let config = setup.getConfig()
beforeAll(async () => { beforeAll(async () => {
await config.init() await config.beforeAll()
}) })
afterAll(setup.afterAll) afterAll(async () => {
await config.afterAll()
})
it("should be able to send an email (with mocking)", async () => { it("should be able to send an email (with mocking)", async () => {
// initially configure settings // initially configure settings

View File

@ -1,17 +1,17 @@
const setup = require("./utilities") const { config, request } = require("../../../tests")
const { EmailTemplatePurpose } = require("../../../constants") const { EmailTemplatePurpose } = require("../../../constants")
const nodemailer = require("nodemailer") const nodemailer = require("nodemailer")
const fetch = require("node-fetch") const fetch = require("node-fetch")
describe("/api/global/email", () => { describe("/api/global/email", () => {
let request = setup.getRequest()
let config = setup.getConfig()
beforeAll(async () => { beforeAll(async () => {
await config.init() await config.beforeAll()
}) })
afterAll(setup.afterAll) afterAll(async () => {
await config.afterAll()
})
async function sendRealEmail(purpose) { async function sendRealEmail(purpose) {
let response, text let response, text

View File

@ -1,17 +1,17 @@
jest.mock("nodemailer") jest.mock("nodemailer")
const setup = require("./utilities") const { config, request, mocks } = require("../../../tests")
const sendMailMock = setup.emailMock() const sendMailMock = mocks.email.mock()
describe("/api/global/users", () => { describe("/api/global/users", () => {
let request = setup.getRequest()
let config = setup.getConfig()
let code let code
beforeAll(async () => { beforeAll(async () => {
await config.init() await config.beforeAll()
}) })
afterAll(setup.afterAll) afterAll(async () => {
await config.afterAll()
})
it("should be able to generate an invitation", async () => { it("should be able to generate an invitation", async () => {
// initially configure settings // initially configure settings

View File

@ -1,7 +0,0 @@
module.exports = {
email: require("../../../controllers/global/email"),
workspaces: require("../../../controllers/global/workspaces"),
config: require("../../../controllers/global/configs"),
templates: require("../../../controllers/global/templates"),
users: require("../../../controllers/global/users"),
}

View File

@ -1,41 +0,0 @@
const TestConfig = require("./TestConfiguration")
let request, config
exports.beforeAll = () => {
config = new TestConfig()
request = config.getRequest()
}
exports.afterAll = async () => {
if (config) {
await config.end()
}
request = null
config = null
}
exports.getRequest = () => {
if (!request) {
exports.beforeAll()
}
return request
}
exports.getConfig = () => {
if (!config) {
exports.beforeAll()
}
return config
}
exports.emailMock = () => {
// mock the email system
const sendMailMock = jest.fn()
const nodemailer = require("nodemailer")
nodemailer.createTransport.mockReturnValue({
sendMail: sendMailMock,
verify: jest.fn(),
})
return sendMailMock
}

View File

@ -1 +0,0 @@
require("./core")

View File

@ -1,2 +0,0 @@
exports.TENANT_ID = "default"
exports.CSRF_TOKEN = "e3727778-7af0-4226-b5eb-f43cbe60a306"

View File

@ -1,22 +1,22 @@
require("./mocks") require("./mocks")
require("../../../../db").init() require("../db").init()
const env = require("../../../../environment") const env = require("../environment")
const controllers = require("./controllers") const controllers = require("./controllers")
const supertest = require("supertest") const supertest = require("supertest")
const { jwt } = require("@budibase/backend-core/auth") const { jwt } = require("@budibase/backend-core/auth")
const { Cookies, Headers } = require("@budibase/backend-core/constants") const { Cookies, Headers } = require("@budibase/backend-core/constants")
const { Configs, LOGO_URL } = require("../../../../constants") const { Configs } = require("../constants")
const { getGlobalUserByEmail } = require("@budibase/backend-core/utils") const { getGlobalUserByEmail } = require("@budibase/backend-core/utils")
const { createASession } = require("@budibase/backend-core/sessions") const { createASession } = require("@budibase/backend-core/sessions")
const { newid } = require("@budibase/backend-core/src/hashing")
const { TENANT_ID, CSRF_TOKEN } = require("./structures") const { TENANT_ID, CSRF_TOKEN } = require("./structures")
const structures = require("./structures")
const { doInTenant } = require("@budibase/backend-core/tenancy") const { doInTenant } = require("@budibase/backend-core/tenancy")
class TestConfiguration { class TestConfiguration {
constructor(openServer = true) { constructor(openServer = true) {
if (openServer) { if (openServer) {
env.PORT = 4012 env.PORT = "0" // random port
this.server = require("../../../../index") this.server = require("../index")
// we need the request for logging in, involves cookies, hard to fake // we need the request for logging in, involves cookies, hard to fake
this.request = supertest(this.server) this.request = supertest(this.server)
} }
@ -26,6 +26,8 @@ class TestConfiguration {
return this.request return this.request
} }
// UTILS
async _req(config, params, controlFunc) { async _req(config, params, controlFunc) {
const request = {} const request = {}
// fake cookies, we don't need them // fake cookies, we don't need them
@ -49,25 +51,37 @@ class TestConfiguration {
return request.body return request.body
} }
async init(createUser = true) { // SETUP / TEARDOWN
if (createUser) {
// create a test user async beforeAll() {
await this._req( await this.login()
{ }
email: "test@test.com",
password: "test", async afterAll() {
_id: "us_uuid1", if (this.server) {
builder: { await this.server.close()
global: true,
},
admin: {
global: true,
},
},
null,
controllers.users.save
)
} }
}
// USER / AUTH
async login() {
// create a test user
await this._req(
{
email: "test@test.com",
password: "test",
_id: "us_uuid1",
builder: {
global: true,
},
admin: {
global: true,
},
},
null,
controllers.users.save
)
await createASession("us_uuid1", { await createASession("us_uuid1", {
sessionId: "sessionid", sessionId: "sessionid",
tenantId: TENANT_ID, tenantId: TENANT_ID,
@ -75,12 +89,6 @@ class TestConfiguration {
}) })
} }
async end() {
if (this.server) {
await this.server.close()
}
}
cookieHeader(cookies) { cookieHeader(cookies) {
return { return {
Cookie: [cookies], Cookie: [cookies],
@ -123,6 +131,20 @@ class TestConfiguration {
) )
} }
async saveAdminUser() {
await this._req(
{
email: "testuser@test.com",
password: "test@test.com",
tenantId: TENANT_ID,
},
null,
controllers.users.adminUser
)
}
// CONFIGS
async deleteConfig(type) { async deleteConfig(type) {
try { try {
const cfg = await this._req( const cfg = await this._req(
@ -147,37 +169,26 @@ class TestConfiguration {
} }
} }
// CONFIGS - SETTINGS
async saveSettingsConfig() { async saveSettingsConfig() {
await this.deleteConfig(Configs.SETTINGS) await this.deleteConfig(Configs.SETTINGS)
await this._req( await this._req(
{ structures.configs.settings(),
type: Configs.SETTINGS,
config: {
platformUrl: "http://localhost:10000",
logoUrl: LOGO_URL,
company: "Budibase",
},
},
null, null,
controllers.config.save controllers.config.save
) )
} }
async saveOAuthConfig() { // CONFIGS - GOOGLE
async saveGoogleConfig() {
await this.deleteConfig(Configs.GOOGLE) await this.deleteConfig(Configs.GOOGLE)
await this._req( await this._req(structures.configs.google(), null, controllers.config.save)
{
type: Configs.GOOGLE,
config: {
clientID: "clientId",
clientSecret: "clientSecret",
},
},
null,
controllers.config.save
)
} }
// CONFIGS - OIDC
getOIDConfigCookie(configId) { getOIDConfigCookie(configId) {
const token = jwt.sign(configId, env.JWT_SECRET) const token = jwt.sign(configId, env.JWT_SECRET)
return this.cookieHeader([[`${Cookies.OIDC_CONFIG}=${token}`]]) return this.cookieHeader([[`${Cookies.OIDC_CONFIG}=${token}`]])
@ -185,75 +196,27 @@ class TestConfiguration {
async saveOIDCConfig() { async saveOIDCConfig() {
await this.deleteConfig(Configs.OIDC) await this.deleteConfig(Configs.OIDC)
const config = { const config = structures.configs.oidc()
type: Configs.OIDC,
config: {
configs: [
{
configUrl: "http://someconfigurl",
clientID: "clientId",
clientSecret: "clientSecret",
logo: "Microsoft",
name: "Active Directory",
uuid: newid(),
},
],
},
}
await this._req(config, null, controllers.config.save) await this._req(config, null, controllers.config.save)
return config return config
} }
// CONFIGS - SMTP
async saveSmtpConfig() { async saveSmtpConfig() {
await this.deleteConfig(Configs.SMTP) await this.deleteConfig(Configs.SMTP)
await this._req( await this._req(structures.configs.smtp(), null, controllers.config.save)
{
type: Configs.SMTP,
config: {
port: 12345,
host: "smtptesthost.com",
from: "testfrom@test.com",
subject: "Hello!",
},
},
null,
controllers.config.save
)
} }
async saveEtherealSmtpConfig() { async saveEtherealSmtpConfig() {
await this.deleteConfig(Configs.SMTP) await this.deleteConfig(Configs.SMTP)
await this._req( await this._req(
{ structures.configs.smtpEthereal(),
type: Configs.SMTP,
config: {
port: 587,
host: "smtp.ethereal.email",
secure: false,
auth: {
user: "don.bahringer@ethereal.email",
pass: "yCKSH8rWyUPbnhGYk9",
},
connectionTimeout: 1000, // must be less than the jest default of 5000
},
},
null, null,
controllers.config.save controllers.config.save
) )
} }
async saveAdminUser() {
await this._req(
{
email: "testuser@test.com",
password: "test@test.com",
tenantId: TENANT_ID,
},
null,
controllers.users.adminUser
)
}
} }
module.exports = TestConfiguration module.exports = TestConfiguration

View File

@ -0,0 +1,7 @@
module.exports = {
email: require("../api/controllers/global/email"),
workspaces: require("../api/controllers/global/workspaces"),
config: require("../api/controllers/global/configs"),
templates: require("../api/controllers/global/templates"),
users: require("../api/controllers/global/users"),
}

View File

@ -0,0 +1,12 @@
const TestConfiguration = require("./TestConfiguration")
const structures = require("./structures")
const mocks = require("./mocks")
const config = new TestConfiguration()
const request = config.getRequest()
module.exports = {
structures,
mocks,
config,
request,
}

View File

@ -0,0 +1,10 @@
exports.mock = () => {
// mock the email system
const sendMailMock = jest.fn()
const nodemailer = require("nodemailer")
nodemailer.createTransport.mockReturnValue({
sendMail: sendMailMock,
verify: jest.fn(),
})
return sendMailMock
}

View File

@ -0,0 +1,6 @@
require("./core")
const email = require("./email")
module.exports = {
email,
}

View File

@ -0,0 +1,76 @@
const { Configs, LOGO_URL } = require("../../constants")
const { utils } = require("@budibase/backend-core")
exports.oidc = conf => {
return {
type: Configs.OIDC,
config: {
configs: [
{
configUrl: "http://someconfigurl",
clientID: "clientId",
clientSecret: "clientSecret",
logo: "Microsoft",
name: "Active Directory",
uuid: utils.newid(),
activated: true,
...conf,
},
],
},
}
}
exports.google = conf => {
return {
type: Configs.GOOGLE,
config: {
clientID: "clientId",
clientSecret: "clientSecret",
activated: true,
...conf,
},
}
}
exports.smtp = conf => {
return {
type: Configs.SMTP,
config: {
port: 12345,
host: "smtptesthost.com",
from: "testfrom@test.com",
subject: "Hello!",
secure: false,
...conf,
},
}
}
exports.smtpEthereal = () => {
return {
type: Configs.SMTP,
config: {
port: 587,
host: "smtp.ethereal.email",
secure: false,
auth: {
user: "don.bahringer@ethereal.email",
pass: "yCKSH8rWyUPbnhGYk9",
},
connectionTimeout: 1000, // must be less than the jest default of 5000
},
}
}
exports.settings = conf => {
return {
type: Configs.SETTINGS,
config: {
platformUrl: "http://localhost:10000",
logoUrl: LOGO_URL,
company: "Budibase",
...conf,
},
}
}

View File

@ -0,0 +1,10 @@
const configs = require("./configs")
const TENANT_ID = "default"
const CSRF_TOKEN = "e3727778-7af0-4226-b5eb-f43cbe60a306"
module.exports = {
configs,
TENANT_ID,
CSRF_TOKEN,
}