@budibase/server
Version:
Budibase Web Server
273 lines (238 loc) • 7.9 kB
text/typescript
import { setEnv } from "@budibase/backend-core"
import { mocks } from "@budibase/backend-core/tests"
import { environmentVariables } from "@budibase/pro"
import { encodeJSBinding } from "@budibase/string-templates"
import { AutomationStatus } from "@budibase/types"
import { v4 as uuidv4 } from "uuid"
import TestConfiguration from "../../../../src/tests/utilities/TestConfiguration"
import { createAutomationBuilder } from "../utilities/AutomationTestBuilder"
describe("Extract state Automations", () => {
const config = new TestConfiguration()
let envCleanup: () => void
beforeAll(async () => {
envCleanup = setEnv({
ENCRYPTION_KEY: "some-key",
})
await config.init()
config.devWorkspace = await config.api.workspace.update(
config.getDevWorkspaceId(),
{
snippets: [
{
name: "tester",
code: `return function (test) {
return "snippet_" + (test || "no_value")
}
`,
},
],
}
)
// Init env var
await config.doInTenant(async () => {
mocks.licenses.useEnvironmentVariables()
await environmentVariables.update("env-1", {
production: "a",
development: "b",
})
const envKeys = await environmentVariables.fetch()
expect(envKeys).toStrictEqual(["env-1"])
})
})
afterAll(() => {
envCleanup()
config.end()
})
it("should execute a basic script and set the state value", async () => {
const builder = createAutomationBuilder(config)
const results = await builder
.onAppAction()
.extractState({
key: "sample",
value: encodeJSBinding("return 2 + 2"),
})
.test({ fields: {} })
const step = results.steps[0]
expect(step.outputs.value).toEqual(4)
// There should be a matching entry in the state
expect(results.state?.["sample"]).toBe(4)
})
it("should process a failed js script leaving valid state intact", async () => {
const builder = createAutomationBuilder(config)
const results = await builder
.onAppAction()
.extractState({
key: "invalid",
value: encodeJSBinding("return 2 +"),
})
.extractState({
key: "valid",
value: encodeJSBinding("return 2 + 3"),
})
.test({ fields: {} })
const failureStep = results.steps[0]
expect(failureStep.outputs.success).toBe(false)
expect(results.status).toEqual(AutomationStatus.ERROR)
const successStep = results.steps[1]
expect(successStep.outputs.success).toBe(true)
expect(successStep.outputs.value).toBe(5)
// The failure should not cause a total automation failure
// Successful elements should be present
expect(results.state?.["valid"]).toEqual(5)
expect(results.state?.["invalid"]).toBeUndefined()
})
it("should be able to reference state and modify the value", async () => {
const builder = createAutomationBuilder(config)
const firstStepId = uuidv4()
const results = await builder
.onAppAction()
.extractState(
{
key: "first",
value: encodeJSBinding("return 2 + 5"),
},
{
stepId: firstStepId,
}
)
.extractState({
key: "first",
value: encodeJSBinding(`return $('state.[first]') + 3`),
})
.test({ fields: {} })
expect(results.state?.["first"]).toBe(10)
})
it("should be able to build complex state vars and bind them", async () => {
const builder = createAutomationBuilder(config)
const firstStepId = uuidv4()
const results = await builder
.onAppAction()
.extractState(
{
key: "first",
value: encodeJSBinding("return ['hello']"),
},
{
stepId: firstStepId,
}
)
// take the initial array and add more values.
.extractState({
key: "first",
value: encodeJSBinding(`return [...$('state.[first]'),'there']`),
})
.extractState({
key: "second",
value: encodeJSBinding(
`return {firstCount: $('state.[first]').length, test: { complete: true }}`
),
})
.serverLog({
text: "{{ state.[second].[test].[complete] }}",
})
.test({ fields: {} })
// You can work with the values via state
expect(results.state?.["first"]).toStrictEqual(["hello", "there"])
expect(results.state?.["second"]).toStrictEqual({
firstCount: 2,
test: { complete: true },
})
// You can navigate the elements you build in state in regular steps.
expect(results.steps[3].outputs.message).toBe(
`App ${config.devWorkspace?.appId} - true`
)
})
it("should process plain text handlebars expression", async () => {
const builder = createAutomationBuilder(config)
const results = await builder
.onAppAction()
.extractState({
key: "sample",
value: "some handlebars text {{ [user].[email] }}",
})
.test({ fields: {} })
const processed = `some handlebars text ${config.user?.email}`
const step = results.steps[0]
expect(step.outputs.value).toEqual(processed)
expect(results.state?.["sample"]).toBe(processed)
})
it("should process env variables correctly", async () => {
const builder = createAutomationBuilder(config)
const results = await builder
.onAppAction()
.extractState({
key: "samplehb",
value: "{{ env.env-1 }}",
})
.extractState({
key: "samplejs",
value: encodeJSBinding("return $('env.env-1')"),
})
.test({ fields: {} })
expect(results.state?.["samplehb"]).toBe("b")
expect(results.state?.["samplejs"]).toBe("b")
expect(results.steps[0].outputs.value).toBe("b")
expect(results.steps[1].outputs.value).toBe("b")
})
it("should process snippets correctly", async () => {
const builder = createAutomationBuilder(config)
const results = await builder
.onAppAction()
.extractState({
key: "sampleSnippets",
value: encodeJSBinding("return snippets.tester('sampleSnippets')"),
})
.test({ fields: {} })
expect(results.state?.["sampleSnippets"]).toBe("snippet_sampleSnippets")
expect(results.steps[0].outputs.value).toBe("snippet_sampleSnippets")
})
it("should process state values in a branched path", async () => {
const builder = createAutomationBuilder(config)
//someVal
const results = await builder
.onAppAction()
.extractState({
key: "testValue",
value: encodeJSBinding("return 5"),
})
.branch({
activeBranch: {
steps: stepBuilder =>
stepBuilder
.extractState({
key: "testValue", // alter and replace in the branch
value: encodeJSBinding("return $('state.testValue') + 10"),
})
.extractState({
key: "someOtherValue",
value: "hi",
}),
condition: {
equal: { [encodeJSBinding("return $('state.testValue')")]: 5 },
},
},
inactiveBranch: {
steps: stepBuilder =>
stepBuilder
.extractState({
key: "testValue",
value: encodeJSBinding("return $('state.testValue') + 20"),
})
.extractState({
key: "someOtherValue",
value: "bye",
}),
condition: {
equal: { [encodeJSBinding("return $('state.testValue')")]: 6 },
},
},
})
.test({
fields: {},
})
// Should alter an existing value
expect(results?.state?.testValue).toBe(15)
// Should initialise a new value.
expect(results?.state?.someOtherValue).toBe("hi")
})
})