Merge branch 'master' into demock-application-tests
This commit is contained in:
commit
85e0b2f478
|
@ -9,6 +9,7 @@ import {
|
||||||
const DISABLED_EXTERNAL_INTEGRATIONS = [
|
const DISABLED_EXTERNAL_INTEGRATIONS = [
|
||||||
SourceName.AIRTABLE,
|
SourceName.AIRTABLE,
|
||||||
SourceName.BUDIBASE,
|
SourceName.BUDIBASE,
|
||||||
|
SourceName.ARANGODB,
|
||||||
]
|
]
|
||||||
|
|
||||||
export async function fetch(ctx: UserCtx<void, FetchIntegrationsResponse>) {
|
export async function fetch(ctx: UserCtx<void, FetchIntegrationsResponse>) {
|
||||||
|
|
|
@ -1,153 +1,106 @@
|
||||||
const pg = require("pg")
|
import { structures } from "./utilities"
|
||||||
|
|
||||||
jest.mock("pg", () => {
|
|
||||||
return {
|
|
||||||
Client: jest.fn().mockImplementation(() => ({
|
|
||||||
connect: jest.fn(),
|
|
||||||
query: jest.fn().mockImplementation(() => ({ rows: [] })),
|
|
||||||
end: jest.fn().mockImplementation((fn: any) => fn()),
|
|
||||||
})),
|
|
||||||
queryMock: jest.fn().mockImplementation(() => {}),
|
|
||||||
on: jest.fn(),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
import * as setup from "./utilities"
|
|
||||||
import { mocks } from "@budibase/backend-core/tests"
|
import { mocks } from "@budibase/backend-core/tests"
|
||||||
import { env, events } from "@budibase/backend-core"
|
import { setEnv } from "@budibase/backend-core"
|
||||||
import { QueryPreview } from "@budibase/types"
|
import { Datasource } from "@budibase/types"
|
||||||
|
import TestConfiguration from "../../../tests/utilities/TestConfiguration"
|
||||||
|
import {
|
||||||
|
DatabaseName,
|
||||||
|
datasourceDescribe,
|
||||||
|
} from "../../../integrations/tests/utils"
|
||||||
|
|
||||||
const structures = setup.structures
|
const describes = datasourceDescribe({ only: [DatabaseName.POSTGRES] })
|
||||||
|
|
||||||
env._set("ENCRYPTION_KEY", "budibase")
|
if (describes.length > 0) {
|
||||||
mocks.licenses.useEnvironmentVariables()
|
describe.each(describes)("/api/env/variables", ({ dsProvider }) => {
|
||||||
|
const config = new TestConfiguration()
|
||||||
|
|
||||||
describe("/api/env/variables", () => {
|
let rawDatasource: Datasource
|
||||||
let request = setup.getRequest()
|
let restoreEnv: () => void
|
||||||
let config = setup.getConfig()
|
|
||||||
|
|
||||||
afterAll(setup.afterAll)
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
restoreEnv = setEnv({ ENCRYPTION_KEY: "budibase" })
|
||||||
|
mocks.licenses.useEnvironmentVariables()
|
||||||
|
|
||||||
|
const ds = await dsProvider()
|
||||||
|
rawDatasource = ds.rawDatasource!
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
restoreEnv()
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const { variables } = await config.api.environment.fetch()
|
||||||
|
for (const variable of variables) {
|
||||||
|
await config.api.environment.destroy(variable)
|
||||||
|
}
|
||||||
|
|
||||||
|
await config.api.environment.create({
|
||||||
|
name: "test",
|
||||||
|
production: rawDatasource.config!.password,
|
||||||
|
development: rawDatasource.config!.password,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should be able check the status of env var API", async () => {
|
it("should be able check the status of env var API", async () => {
|
||||||
const res = await request
|
const { encryptionKeyAvailable } = await config.api.environment.status()
|
||||||
.get(`/api/env/variables/status`)
|
expect(encryptionKeyAvailable).toEqual(true)
|
||||||
.set(config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
expect(res.body.encryptionKeyAvailable).toEqual(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should be able to create an environment variable", async () => {
|
|
||||||
await request
|
|
||||||
.post(`/api/env/variables`)
|
|
||||||
.send(structures.basicEnvironmentVariable("test", "test"))
|
|
||||||
.set(config.defaultHeaders())
|
|
||||||
.expect(200)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should be able to fetch the 'test' variable name", async () => {
|
it("should be able to fetch the 'test' variable name", async () => {
|
||||||
const res = await request
|
const { variables } = await config.api.environment.fetch()
|
||||||
.get(`/api/env/variables`)
|
expect(variables.length).toEqual(1)
|
||||||
.set(config.defaultHeaders())
|
expect(variables[0]).toEqual("test")
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
expect(res.body.variables.length).toEqual(1)
|
|
||||||
expect(res.body.variables[0]).toEqual("test")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should be able to update the environment variable 'test'", async () => {
|
it("should be able to update the environment variable 'test'", async () => {
|
||||||
const varName = "test"
|
await config.api.environment.update("test", {
|
||||||
await request
|
production: "test1",
|
||||||
.patch(`/api/env/variables/${varName}`)
|
development: "test1",
|
||||||
.send(structures.basicEnvironmentVariable("test", "test1"))
|
})
|
||||||
.set(config.defaultHeaders())
|
|
||||||
.expect(200)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should be able to delete the environment variable 'test'", async () => {
|
it("should be able to delete the environment variable 'test'", async () => {
|
||||||
const varName = "test"
|
await config.api.environment.destroy("test")
|
||||||
await request
|
|
||||||
.delete(`/api/env/variables/${varName}`)
|
|
||||||
.set(config.defaultHeaders())
|
|
||||||
.expect(200)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should create a datasource (using the environment variable) and query", async () => {
|
it("should create a datasource (using the environment variable) and query", async () => {
|
||||||
const datasourceBase = structures.basicDatasource()
|
const datasource = await config.api.datasource.create({
|
||||||
await request
|
...structures.basicDatasource().datasource,
|
||||||
.post(`/api/env/variables`)
|
config: {
|
||||||
.send(structures.basicEnvironmentVariable("test", "test"))
|
...rawDatasource.config,
|
||||||
.set(config.defaultHeaders())
|
|
||||||
|
|
||||||
datasourceBase.datasource.config = {
|
|
||||||
password: "{{ env.test }}",
|
password: "{{ env.test }}",
|
||||||
}
|
},
|
||||||
const response = await request
|
})
|
||||||
.post(`/api/datasources`)
|
|
||||||
.send(datasourceBase)
|
|
||||||
.set(config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
expect(response.body.datasource._id).toBeDefined()
|
|
||||||
|
|
||||||
const response2 = await request
|
const query = await config.api.query.save({
|
||||||
.post(`/api/queries`)
|
...structures.basicQuery(datasource._id!),
|
||||||
.send(structures.basicQuery(response.body.datasource._id))
|
fields: { sql: "SELECT 1" },
|
||||||
.set(config.defaultHeaders())
|
})
|
||||||
.expect("Content-Type", /json/)
|
expect(query._id).toBeDefined()
|
||||||
.expect(200)
|
|
||||||
expect(response2.body._id).toBeDefined()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should run a query preview and check the mocked results", async () => {
|
it("should run a query preview and check the mocked results", async () => {
|
||||||
const datasourceBase = structures.basicDatasource()
|
const datasource = await config.api.datasource.create({
|
||||||
await request
|
...structures.basicDatasource().datasource,
|
||||||
.post(`/api/env/variables`)
|
config: {
|
||||||
.send(structures.basicEnvironmentVariable("test", "test"))
|
...rawDatasource.config,
|
||||||
.set(config.defaultHeaders())
|
|
||||||
|
|
||||||
datasourceBase.datasource.config = {
|
|
||||||
password: "{{ env.test }}",
|
password: "{{ env.test }}",
|
||||||
}
|
},
|
||||||
const response = await request
|
|
||||||
.post(`/api/datasources`)
|
|
||||||
.send(datasourceBase)
|
|
||||||
.set(config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
expect(response.body.datasource._id).toBeDefined()
|
|
||||||
|
|
||||||
const queryPreview: QueryPreview = {
|
|
||||||
datasourceId: response.body.datasource._id,
|
|
||||||
parameters: [],
|
|
||||||
fields: {},
|
|
||||||
queryVerb: "read",
|
|
||||||
name: response.body.datasource.name,
|
|
||||||
transformer: null,
|
|
||||||
schema: {},
|
|
||||||
readable: true,
|
|
||||||
}
|
|
||||||
const res = await request
|
|
||||||
.post(`/api/queries/preview`)
|
|
||||||
.send(queryPreview)
|
|
||||||
.set(config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
expect(res.body.rows.length).toEqual(0)
|
|
||||||
expect(events.query.previewed).toHaveBeenCalledTimes(1)
|
|
||||||
// API doesn't include config in response
|
|
||||||
delete response.body.datasource.config
|
|
||||||
expect(events.query.previewed).toHaveBeenCalledWith(
|
|
||||||
response.body.datasource,
|
|
||||||
{
|
|
||||||
...queryPreview,
|
|
||||||
nullDefaultSupport: true,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
expect(pg.Client).toHaveBeenCalledWith({ password: "test", ssl: undefined })
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
const query = await config.api.query.save({
|
||||||
|
...structures.basicQuery(datasource._id!),
|
||||||
|
fields: { sql: "SELECT 1 as id" },
|
||||||
|
})
|
||||||
|
|
||||||
|
const { rows } = await config.api.query.preview({
|
||||||
|
...query,
|
||||||
|
queryId: query._id!,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(rows).toEqual([{ id: 1 }])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
docIds,
|
docIds,
|
||||||
MAX_VALID_DATE,
|
MAX_VALID_DATE,
|
||||||
MIN_VALID_DATE,
|
MIN_VALID_DATE,
|
||||||
|
setEnv,
|
||||||
SQLITE_DESIGN_DOC_ID,
|
SQLITE_DESIGN_DOC_ID,
|
||||||
utils,
|
utils,
|
||||||
withEnv as withCoreEnv,
|
withEnv as withCoreEnv,
|
||||||
|
@ -43,19 +44,7 @@ import { generator, structures, mocks } from "@budibase/backend-core/tests"
|
||||||
import { DEFAULT_EMPLOYEE_TABLE_SCHEMA } from "../../../db/defaultData/datasource_bb_default"
|
import { DEFAULT_EMPLOYEE_TABLE_SCHEMA } from "../../../db/defaultData/datasource_bb_default"
|
||||||
import { generateRowIdField } from "../../../integrations/utils"
|
import { generateRowIdField } from "../../../integrations/utils"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
|
import { mockChatGPTResponse } from "../../../tests/utilities/mocks/openai"
|
||||||
jest.mock("@budibase/pro", () => ({
|
|
||||||
...jest.requireActual("@budibase/pro"),
|
|
||||||
ai: {
|
|
||||||
LargeLanguageModel: {
|
|
||||||
forCurrentTenant: async () => ({
|
|
||||||
llm: {},
|
|
||||||
run: jest.fn(() => `Mock LLM Response`),
|
|
||||||
buildPromptFromAIOperation: jest.fn(),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
|
|
||||||
const descriptions = datasourceDescribe({ plus: true })
|
const descriptions = datasourceDescribe({ plus: true })
|
||||||
|
|
||||||
|
@ -1896,11 +1885,15 @@ if (descriptions.length) {
|
||||||
!isInMemory &&
|
!isInMemory &&
|
||||||
describe("AI Column", () => {
|
describe("AI Column", () => {
|
||||||
const UNEXISTING_AI_COLUMN = "Real LLM Response"
|
const UNEXISTING_AI_COLUMN = "Real LLM Response"
|
||||||
|
let envCleanup: () => void
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
mocks.licenses.useBudibaseAI()
|
mocks.licenses.useBudibaseAI()
|
||||||
mocks.licenses.useAICustomConfigs()
|
mocks.licenses.useAICustomConfigs()
|
||||||
|
|
||||||
|
envCleanup = setEnv({ OPENAI_API_KEY: "mock" })
|
||||||
|
mockChatGPTResponse("Mock LLM Response")
|
||||||
|
|
||||||
tableOrViewId = await createTableOrView({
|
tableOrViewId = await createTableOrView({
|
||||||
product: { name: "product", type: FieldType.STRING },
|
product: { name: "product", type: FieldType.STRING },
|
||||||
ai: {
|
ai: {
|
||||||
|
@ -1917,6 +1910,10 @@ if (descriptions.length) {
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
envCleanup()
|
||||||
|
})
|
||||||
|
|
||||||
describe("equal", () => {
|
describe("equal", () => {
|
||||||
it("successfully finds rows based on AI column", async () => {
|
it("successfully finds rows based on AI column", async () => {
|
||||||
await expectQuery({
|
await expectQuery({
|
||||||
|
|
|
@ -16,6 +16,7 @@ describe("Execute Bash Automations", () => {
|
||||||
name: "test row",
|
name: "test row",
|
||||||
description: "test description",
|
description: "test description",
|
||||||
})
|
})
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -33,6 +33,7 @@ describe("test the create row action", () => {
|
||||||
name: "test",
|
name: "test",
|
||||||
description: "test",
|
description: "test",
|
||||||
}
|
}
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -6,6 +6,7 @@ describe("test the delay logic", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -13,6 +13,7 @@ describe("test the delete row action", () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
table = await config.api.table.save(basicTable())
|
table = await config.api.table.save(basicTable())
|
||||||
row = await config.api.row.save(table._id!, {})
|
row = await config.api.row.save(table._id!, {})
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -7,6 +7,7 @@ describe("test the outgoing webhook action", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -26,6 +26,7 @@ if (descriptions.length) {
|
||||||
const ds = await dsProvider()
|
const ds = await dsProvider()
|
||||||
datasource = ds.datasource!
|
datasource = ds.datasource!
|
||||||
client = ds.client!
|
client = ds.client!
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
|
|
@ -13,6 +13,7 @@ describe("Execute Script Automations", () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
table = await config.api.table.save(basicTable())
|
table = await config.api.table.save(basicTable())
|
||||||
await config.api.row.save(table._id!, {})
|
await config.api.row.save(table._id!, {})
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -26,6 +26,7 @@ describe("test the filter logic", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -22,10 +22,7 @@ describe("Attempt to run a basic loop automation", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const { automations } = await config.api.automation.fetch()
|
await config.api.automation.deleteAll()
|
||||||
for (const automation of automations) {
|
|
||||||
await config.api.automation.delete(automation)
|
|
||||||
}
|
|
||||||
|
|
||||||
table = await config.api.table.save(basicTable())
|
table = await config.api.table.save(basicTable())
|
||||||
await config.api.row.save(table._id!, {})
|
await config.api.row.save(table._id!, {})
|
||||||
|
|
|
@ -7,6 +7,7 @@ describe("test the outgoing webhook action", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -8,6 +8,7 @@ describe("test the outgoing webhook action", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -16,6 +16,7 @@ describe("test the openai action", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
|
@ -8,6 +8,7 @@ describe("test the outgoing webhook action", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -21,6 +21,7 @@ describe("Test a query step automation", () => {
|
||||||
}
|
}
|
||||||
await config.api.row.save(table._id!, row)
|
await config.api.row.save(table._id!, row)
|
||||||
await config.api.row.save(table._id!, row)
|
await config.api.row.save(table._id!, row)
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -28,6 +28,7 @@ describe("test the outgoing webhook action", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -6,6 +6,7 @@ describe("test the server log action", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -9,6 +9,7 @@ describe("Test triggering an automation from another automation", () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await automation.init()
|
await automation.init()
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
|
|
@ -23,6 +23,7 @@ describe("test the update row action", () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
table = await config.createTable()
|
table = await config.createTable()
|
||||||
row = await config.createRow()
|
row = await config.createRow()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -7,6 +7,7 @@ describe("test the outgoing webhook action", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -9,6 +9,8 @@ describe("app action trigger", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
|
|
||||||
automation = await createAutomationBuilder(config)
|
automation = await createAutomationBuilder(config)
|
||||||
.onAppAction()
|
.onAppAction()
|
||||||
.serverLog({
|
.serverLog({
|
||||||
|
|
|
@ -16,6 +16,7 @@ describe("cron trigger", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|
|
@ -11,6 +11,7 @@ describe("row deleted trigger", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
table = await config.api.table.save(basicTable())
|
table = await config.api.table.save(basicTable())
|
||||||
automation = await createAutomationBuilder(config)
|
automation = await createAutomationBuilder(config)
|
||||||
.onRowDeleted({ tableId: table._id! })
|
.onRowDeleted({ tableId: table._id! })
|
||||||
|
|
|
@ -11,6 +11,7 @@ describe("row saved trigger", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
table = await config.api.table.save(basicTable())
|
table = await config.api.table.save(basicTable())
|
||||||
automation = await createAutomationBuilder(config)
|
automation = await createAutomationBuilder(config)
|
||||||
.onRowSaved({ tableId: table._id! })
|
.onRowSaved({ tableId: table._id! })
|
||||||
|
|
|
@ -11,6 +11,7 @@ describe("row updated trigger", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
table = await config.api.table.save(basicTable())
|
table = await config.api.table.save(basicTable())
|
||||||
automation = await createAutomationBuilder(config)
|
automation = await createAutomationBuilder(config)
|
||||||
.onRowUpdated({ tableId: table._id! })
|
.onRowUpdated({ tableId: table._id! })
|
||||||
|
|
|
@ -37,6 +37,7 @@ describe("Webhook trigger test", () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
await config.api.automation.deleteAll()
|
||||||
table = await config.createTable()
|
table = await config.createTable()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,11 @@ import {
|
||||||
|
|
||||||
import { Database, aql } from "arangojs"
|
import { Database, aql } from "arangojs"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated 3rd March 2025
|
||||||
|
* datasource disabled - this datasource is marked for deprecation and removal
|
||||||
|
*/
|
||||||
|
|
||||||
interface ArangodbConfig {
|
interface ArangodbConfig {
|
||||||
url: string
|
url: string
|
||||||
username: string
|
username: string
|
||||||
|
|
|
@ -33,15 +33,17 @@ const DEFINITIONS: Record<SourceName, Integration | undefined> = {
|
||||||
[SourceName.COUCHDB]: couchdb.schema,
|
[SourceName.COUCHDB]: couchdb.schema,
|
||||||
[SourceName.SQL_SERVER]: sqlServer.schema,
|
[SourceName.SQL_SERVER]: sqlServer.schema,
|
||||||
[SourceName.S3]: s3.schema,
|
[SourceName.S3]: s3.schema,
|
||||||
[SourceName.AIRTABLE]: airtable.schema,
|
|
||||||
[SourceName.MYSQL]: mysql.schema,
|
[SourceName.MYSQL]: mysql.schema,
|
||||||
[SourceName.ARANGODB]: arangodb.schema,
|
|
||||||
[SourceName.REST]: rest.schema,
|
[SourceName.REST]: rest.schema,
|
||||||
[SourceName.FIRESTORE]: firebase.schema,
|
[SourceName.FIRESTORE]: firebase.schema,
|
||||||
[SourceName.GOOGLE_SHEETS]: googlesheets.schema,
|
[SourceName.GOOGLE_SHEETS]: googlesheets.schema,
|
||||||
[SourceName.REDIS]: redis.schema,
|
[SourceName.REDIS]: redis.schema,
|
||||||
[SourceName.SNOWFLAKE]: snowflake.schema,
|
[SourceName.SNOWFLAKE]: snowflake.schema,
|
||||||
[SourceName.ORACLE]: oracle.schema,
|
[SourceName.ORACLE]: oracle.schema,
|
||||||
|
/* deprecated - not available through UI */
|
||||||
|
[SourceName.ARANGODB]: arangodb.schema,
|
||||||
|
[SourceName.AIRTABLE]: airtable.schema,
|
||||||
|
/* un-used */
|
||||||
[SourceName.BUDIBASE]: undefined,
|
[SourceName.BUDIBASE]: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,15 +58,17 @@ const INTEGRATIONS: Record<SourceName, IntegrationBaseConstructor | undefined> =
|
||||||
[SourceName.COUCHDB]: couchdb.integration,
|
[SourceName.COUCHDB]: couchdb.integration,
|
||||||
[SourceName.SQL_SERVER]: sqlServer.integration,
|
[SourceName.SQL_SERVER]: sqlServer.integration,
|
||||||
[SourceName.S3]: s3.integration,
|
[SourceName.S3]: s3.integration,
|
||||||
[SourceName.AIRTABLE]: airtable.integration,
|
|
||||||
[SourceName.MYSQL]: mysql.integration,
|
[SourceName.MYSQL]: mysql.integration,
|
||||||
[SourceName.ARANGODB]: arangodb.integration,
|
|
||||||
[SourceName.REST]: rest.integration,
|
[SourceName.REST]: rest.integration,
|
||||||
[SourceName.FIRESTORE]: firebase.integration,
|
[SourceName.FIRESTORE]: firebase.integration,
|
||||||
[SourceName.GOOGLE_SHEETS]: googlesheets.integration,
|
[SourceName.GOOGLE_SHEETS]: googlesheets.integration,
|
||||||
[SourceName.REDIS]: redis.integration,
|
[SourceName.REDIS]: redis.integration,
|
||||||
[SourceName.SNOWFLAKE]: snowflake.integration,
|
[SourceName.SNOWFLAKE]: snowflake.integration,
|
||||||
[SourceName.ORACLE]: oracle.integration,
|
[SourceName.ORACLE]: oracle.integration,
|
||||||
|
/* deprecated - not available through UI */
|
||||||
|
[SourceName.ARANGODB]: arangodb.integration,
|
||||||
|
[SourceName.AIRTABLE]: airtable.integration,
|
||||||
|
/* un-used */
|
||||||
[SourceName.BUDIBASE]: undefined,
|
[SourceName.BUDIBASE]: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
import { default as AirtableIntegration } from "../airtable"
|
|
||||||
|
|
||||||
jest.mock("airtable")
|
|
||||||
|
|
||||||
class TestConfiguration {
|
|
||||||
integration: any
|
|
||||||
client: any
|
|
||||||
|
|
||||||
constructor(config: any = {}) {
|
|
||||||
this.integration = new AirtableIntegration.integration(config)
|
|
||||||
this.client = {
|
|
||||||
create: jest.fn(),
|
|
||||||
select: jest.fn(() => ({
|
|
||||||
firstPage: jest.fn(() => []),
|
|
||||||
})),
|
|
||||||
update: jest.fn(),
|
|
||||||
destroy: jest.fn(),
|
|
||||||
}
|
|
||||||
this.integration.client = () => this.client
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("Airtable Integration", () => {
|
|
||||||
let config: any
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
config = new TestConfiguration()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("calls the create method with the correct params", async () => {
|
|
||||||
await config.integration.create({
|
|
||||||
table: "test",
|
|
||||||
json: {},
|
|
||||||
})
|
|
||||||
expect(config.client.create).toHaveBeenCalledWith([
|
|
||||||
{
|
|
||||||
fields: {},
|
|
||||||
},
|
|
||||||
])
|
|
||||||
})
|
|
||||||
|
|
||||||
it("calls the read method with the correct params", async () => {
|
|
||||||
await config.integration.read({
|
|
||||||
table: "test",
|
|
||||||
view: "Grid view",
|
|
||||||
})
|
|
||||||
expect(config.client.select).toHaveBeenCalledWith({
|
|
||||||
maxRecords: 10,
|
|
||||||
view: "Grid view",
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("calls the update method with the correct params", async () => {
|
|
||||||
await config.integration.update({
|
|
||||||
table: "table",
|
|
||||||
id: "123",
|
|
||||||
json: {
|
|
||||||
name: "test",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
expect(config.client.update).toHaveBeenCalledWith([
|
|
||||||
{
|
|
||||||
id: "123",
|
|
||||||
fields: { name: "test" },
|
|
||||||
},
|
|
||||||
])
|
|
||||||
})
|
|
||||||
|
|
||||||
it("calls the delete method with the correct params", async () => {
|
|
||||||
const ids = [1, 2, 3, 4]
|
|
||||||
await config.integration.delete({
|
|
||||||
ids,
|
|
||||||
})
|
|
||||||
expect(config.client.destroy).toHaveBeenCalledWith(ids)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,38 +0,0 @@
|
||||||
import { default as ArangoDBIntegration } from "../arangodb"
|
|
||||||
|
|
||||||
jest.mock("arangojs")
|
|
||||||
|
|
||||||
class TestConfiguration {
|
|
||||||
integration: any
|
|
||||||
|
|
||||||
constructor(config: any = {}) {
|
|
||||||
this.integration = new ArangoDBIntegration.integration(config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("ArangoDB Integration", () => {
|
|
||||||
let config: any
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
config = new TestConfiguration()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("calls the create method with the correct params", async () => {
|
|
||||||
const body = {
|
|
||||||
json: "Hello",
|
|
||||||
}
|
|
||||||
|
|
||||||
await config.integration.create(body)
|
|
||||||
expect(config.integration.client.query).toHaveBeenCalledWith(
|
|
||||||
`INSERT Hello INTO collection RETURN NEW`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("calls the read method with the correct params", async () => {
|
|
||||||
const query = {
|
|
||||||
sql: `test`,
|
|
||||||
}
|
|
||||||
await config.integration.read(query)
|
|
||||||
expect(config.integration.client.query).toHaveBeenCalledWith(query.sql)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -133,4 +133,11 @@ export class AutomationAPI extends TestAPI {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteAll = async (expectations?: Expectations): Promise<void> => {
|
||||||
|
const { automations } = await this.fetch()
|
||||||
|
await Promise.all(
|
||||||
|
automations.map(automation => this.delete(automation, expectations))
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { Expectations, TestAPI } from "./base"
|
||||||
|
import {
|
||||||
|
CreateEnvironmentVariableRequest,
|
||||||
|
CreateEnvironmentVariableResponse,
|
||||||
|
GetEnvironmentVariablesResponse,
|
||||||
|
StatusEnvironmentVariableResponse,
|
||||||
|
UpdateEnvironmentVariableRequest,
|
||||||
|
} from "@budibase/types"
|
||||||
|
|
||||||
|
export class EnvironmentAPI extends TestAPI {
|
||||||
|
create = async (
|
||||||
|
body: CreateEnvironmentVariableRequest,
|
||||||
|
expectations?: Expectations
|
||||||
|
) => {
|
||||||
|
return await this._post<CreateEnvironmentVariableResponse>(
|
||||||
|
`/api/env/variables`,
|
||||||
|
{ body, expectations }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
status = async (expectations?: Expectations) => {
|
||||||
|
return await this._get<StatusEnvironmentVariableResponse>(
|
||||||
|
`/api/env/variables/status`,
|
||||||
|
{ expectations }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch = async (expectations?: Expectations) => {
|
||||||
|
return await this._get<GetEnvironmentVariablesResponse>(
|
||||||
|
`/api/env/variables`,
|
||||||
|
{ expectations }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
update = async (
|
||||||
|
varName: string,
|
||||||
|
body: UpdateEnvironmentVariableRequest,
|
||||||
|
expectations?: Expectations
|
||||||
|
) => {
|
||||||
|
return await this._patch<void>(`/api/env/variables/${varName}`, {
|
||||||
|
body,
|
||||||
|
expectations,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy = async (varName: string, expectations?: Expectations) => {
|
||||||
|
return await this._delete<void>(`/api/env/variables/${varName}`, {
|
||||||
|
expectations,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import { RowActionAPI } from "./rowAction"
|
||||||
import { AutomationAPI } from "./automation"
|
import { AutomationAPI } from "./automation"
|
||||||
import { PluginAPI } from "./plugin"
|
import { PluginAPI } from "./plugin"
|
||||||
import { WebhookAPI } from "./webhook"
|
import { WebhookAPI } from "./webhook"
|
||||||
|
import { EnvironmentAPI } from "./environment"
|
||||||
import { UserPublicAPI } from "./public/user"
|
import { UserPublicAPI } from "./public/user"
|
||||||
|
|
||||||
export default class API {
|
export default class API {
|
||||||
|
@ -25,6 +26,7 @@ export default class API {
|
||||||
automation: AutomationAPI
|
automation: AutomationAPI
|
||||||
backup: BackupAPI
|
backup: BackupAPI
|
||||||
datasource: DatasourceAPI
|
datasource: DatasourceAPI
|
||||||
|
environment: EnvironmentAPI
|
||||||
legacyView: LegacyViewAPI
|
legacyView: LegacyViewAPI
|
||||||
permission: PermissionAPI
|
permission: PermissionAPI
|
||||||
plugin: PluginAPI
|
plugin: PluginAPI
|
||||||
|
@ -49,6 +51,7 @@ export default class API {
|
||||||
this.automation = new AutomationAPI(config)
|
this.automation = new AutomationAPI(config)
|
||||||
this.backup = new BackupAPI(config)
|
this.backup = new BackupAPI(config)
|
||||||
this.datasource = new DatasourceAPI(config)
|
this.datasource = new DatasourceAPI(config)
|
||||||
|
this.environment = new EnvironmentAPI(config)
|
||||||
this.legacyView = new LegacyViewAPI(config)
|
this.legacyView = new LegacyViewAPI(config)
|
||||||
this.permission = new PermissionAPI(config)
|
this.permission = new PermissionAPI(config)
|
||||||
this.plugin = new PluginAPI(config)
|
this.plugin = new PluginAPI(config)
|
||||||
|
|
|
@ -37,6 +37,7 @@ import {
|
||||||
DeepPartial,
|
DeepPartial,
|
||||||
FilterCondition,
|
FilterCondition,
|
||||||
AutomationTriggerResult,
|
AutomationTriggerResult,
|
||||||
|
CreateEnvironmentVariableRequest,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { LoopInput } from "../../definitions/automations"
|
import { LoopInput } from "../../definitions/automations"
|
||||||
import { merge } from "lodash"
|
import { merge } from "lodash"
|
||||||
|
@ -574,7 +575,7 @@ export function basicEnvironmentVariable(
|
||||||
name: string,
|
name: string,
|
||||||
prod: string,
|
prod: string,
|
||||||
dev?: string
|
dev?: string
|
||||||
) {
|
): CreateEnvironmentVariableRequest {
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
production: prod,
|
production: prod,
|
||||||
|
|
Loading…
Reference in New Issue