Merge branch 'develop' of github.com:Budibase/budibase into feature/test-image
This commit is contained in:
commit
998b7f4a81
|
@ -106,3 +106,5 @@ stats.html
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
budibase-component
|
budibase-component
|
||||||
budibase-datasource
|
budibase-datasource
|
||||||
|
|
||||||
|
*.iml
|
|
@ -8,7 +8,7 @@
|
||||||
"editor.defaultFormatter": "vscode.json-language-features"
|
"editor.defaultFormatter": "vscode.json-language-features"
|
||||||
},
|
},
|
||||||
"[javascript]": {
|
"[javascript]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||||
},
|
},
|
||||||
"debug.javascript.terminalOptions": {
|
"debug.javascript.terminalOptions": {
|
||||||
"skipFiles": [
|
"skipFiles": [
|
||||||
|
@ -16,4 +16,7 @@
|
||||||
"<node_internals>/**"
|
"<node_internals>/**"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "2.1.46-alpha.3",
|
"version": "2.1.46-alpha.6",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/backend-core",
|
"name": "@budibase/backend-core",
|
||||||
"version": "2.1.46-alpha.3",
|
"version": "2.1.46-alpha.6",
|
||||||
"description": "Budibase backend core libraries used in server and worker",
|
"description": "Budibase backend core libraries used in server and worker",
|
||||||
"main": "dist/src/index.js",
|
"main": "dist/src/index.js",
|
||||||
"types": "dist/src/index.d.ts",
|
"types": "dist/src/index.d.ts",
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
"test:watch": "jest --watchAll"
|
"test:watch": "jest --watchAll"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/types": "2.1.46-alpha.3",
|
"@budibase/types": "2.1.46-alpha.6",
|
||||||
"@shopify/jest-koa-mocks": "5.0.1",
|
"@shopify/jest-koa-mocks": "5.0.1",
|
||||||
"@techpass/passport-openidconnect": "0.3.2",
|
"@techpass/passport-openidconnect": "0.3.2",
|
||||||
"aws-sdk": "2.1030.0",
|
"aws-sdk": "2.1030.0",
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./src/plugin"
|
|
@ -1,9 +1,13 @@
|
||||||
function isTest() {
|
function isTest() {
|
||||||
return (
|
return isCypress() || isJest()
|
||||||
process.env.NODE_ENV === "jest" ||
|
}
|
||||||
process.env.NODE_ENV === "cypress" ||
|
|
||||||
process.env.JEST_WORKER_ID != null
|
function isJest() {
|
||||||
)
|
return !!(process.env.NODE_ENV === "jest" || process.env.JEST_WORKER_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCypress() {
|
||||||
|
return process.env.NODE_ENV === "cypress"
|
||||||
}
|
}
|
||||||
|
|
||||||
function isDev() {
|
function isDev() {
|
||||||
|
@ -27,6 +31,7 @@ const DefaultBucketName = {
|
||||||
|
|
||||||
const environment = {
|
const environment = {
|
||||||
isTest,
|
isTest,
|
||||||
|
isJest,
|
||||||
isDev,
|
isDev,
|
||||||
JS_BCRYPT: process.env.JS_BCRYPT,
|
JS_BCRYPT: process.env.JS_BCRYPT,
|
||||||
JWT_SECRET: process.env.JWT_SECRET,
|
JWT_SECRET: process.env.JWT_SECRET,
|
||||||
|
|
|
@ -117,3 +117,7 @@ jest.spyOn(events.view, "filterDeleted")
|
||||||
jest.spyOn(events.view, "calculationCreated")
|
jest.spyOn(events.view, "calculationCreated")
|
||||||
jest.spyOn(events.view, "calculationUpdated")
|
jest.spyOn(events.view, "calculationUpdated")
|
||||||
jest.spyOn(events.view, "calculationDeleted")
|
jest.spyOn(events.view, "calculationDeleted")
|
||||||
|
|
||||||
|
jest.spyOn(events.plugin, "init")
|
||||||
|
jest.spyOn(events.plugin, "imported")
|
||||||
|
jest.spyOn(events.plugin, "deleted")
|
||||||
|
|
|
@ -2,4 +2,5 @@ import "./posthog"
|
||||||
import "./events"
|
import "./events"
|
||||||
export * as accounts from "./accounts"
|
export * as accounts from "./accounts"
|
||||||
export * as date from "./date"
|
export * as date from "./date"
|
||||||
|
export * as licenses from "./licenses"
|
||||||
export { default as fetch } from "./fetch"
|
export { default as fetch } from "./fetch"
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
import { Feature, License, Quotas } from "@budibase/types"
|
||||||
|
import _ from "lodash"
|
||||||
|
|
||||||
|
let CLOUD_FREE_LICENSE: License
|
||||||
|
let TEST_LICENSE: License
|
||||||
|
let getCachedLicense: any
|
||||||
|
|
||||||
|
// init for the packages other than pro
|
||||||
|
export function init(proPkg: any) {
|
||||||
|
initInternal({
|
||||||
|
CLOUD_FREE_LICENSE: proPkg.constants.licenses.CLOUD_FREE_LICENSE,
|
||||||
|
TEST_LICENSE: proPkg.constants.licenses.DEVELOPER_FREE_LICENSE,
|
||||||
|
getCachedLicense: proPkg.licensing.cache.getCachedLicense,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// init for the pro package
|
||||||
|
export function initInternal(opts: {
|
||||||
|
CLOUD_FREE_LICENSE: License
|
||||||
|
TEST_LICENSE: License
|
||||||
|
getCachedLicense: any
|
||||||
|
}) {
|
||||||
|
CLOUD_FREE_LICENSE = opts.CLOUD_FREE_LICENSE
|
||||||
|
TEST_LICENSE = opts.TEST_LICENSE
|
||||||
|
getCachedLicense = opts.getCachedLicense
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UseLicenseOpts {
|
||||||
|
features?: Feature[]
|
||||||
|
quotas?: Quotas
|
||||||
|
}
|
||||||
|
|
||||||
|
// LICENSES
|
||||||
|
|
||||||
|
export const useLicense = (license: License, opts?: UseLicenseOpts) => {
|
||||||
|
if (opts) {
|
||||||
|
if (opts.features) {
|
||||||
|
license.features.push(...opts.features)
|
||||||
|
}
|
||||||
|
if (opts.quotas) {
|
||||||
|
license.quotas = opts.quotas
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getCachedLicense.mockReturnValue(license)
|
||||||
|
|
||||||
|
return license
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useUnlimited = (opts?: UseLicenseOpts) => {
|
||||||
|
return useLicense(TEST_LICENSE, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useCloudFree = () => {
|
||||||
|
return useLicense(CLOUD_FREE_LICENSE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FEATURES
|
||||||
|
|
||||||
|
const useFeature = (feature: Feature) => {
|
||||||
|
const license = _.cloneDeep(TEST_LICENSE)
|
||||||
|
const opts: UseLicenseOpts = {
|
||||||
|
features: [feature],
|
||||||
|
}
|
||||||
|
|
||||||
|
return useLicense(license, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useBackups = () => {
|
||||||
|
return useFeature(Feature.APP_BACKUPS)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGroups = () => {
|
||||||
|
return useFeature(Feature.USER_GROUPS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QUOTAS
|
||||||
|
|
||||||
|
export const setAutomationLogsQuota = (value: number) => {
|
||||||
|
const license = _.cloneDeep(TEST_LICENSE)
|
||||||
|
license.quotas.constant.automationLogRetentionDays.value = value
|
||||||
|
return useLicense(license)
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/bbui",
|
"name": "@budibase/bbui",
|
||||||
"description": "A UI solution used in the different Budibase projects.",
|
"description": "A UI solution used in the different Budibase projects.",
|
||||||
"version": "2.1.46-alpha.3",
|
"version": "2.1.46-alpha.6",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"svelte": "src/index.js",
|
"svelte": "src/index.js",
|
||||||
"module": "dist/bbui.es.js",
|
"module": "dist/bbui.es.js",
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@adobe/spectrum-css-workflow-icons": "1.2.1",
|
"@adobe/spectrum-css-workflow-icons": "1.2.1",
|
||||||
"@budibase/string-templates": "2.1.46-alpha.3",
|
"@budibase/string-templates": "2.1.46-alpha.6",
|
||||||
"@spectrum-css/actionbutton": "1.0.1",
|
"@spectrum-css/actionbutton": "1.0.1",
|
||||||
"@spectrum-css/actiongroup": "1.0.1",
|
"@spectrum-css/actiongroup": "1.0.1",
|
||||||
"@spectrum-css/avatar": "3.0.2",
|
"@spectrum-css/avatar": "3.0.2",
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"@adobe/spectrum-css-workflow-icons@^1.2.1":
|
"@adobe/spectrum-css-workflow-icons@1.2.1":
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.2.1.tgz#7e2cb3fcfb5c8b12d7275afafbb6ec44913551b4"
|
resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.2.1.tgz#7e2cb3fcfb5c8b12d7275afafbb6ec44913551b4"
|
||||||
integrity sha512-uVgekyBXnOVkxp+CUssjN/gefARtudZC8duEn1vm0lBQFwGRZFlDEzU1QC+aIRWCrD1Z8OgRpmBYlSZ7QS003w==
|
integrity sha512-uVgekyBXnOVkxp+CUssjN/gefARtudZC8duEn1vm0lBQFwGRZFlDEzU1QC+aIRWCrD1Z8OgRpmBYlSZ7QS003w==
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/builder",
|
"name": "@budibase/builder",
|
||||||
"version": "2.1.46-alpha.3",
|
"version": "2.1.46-alpha.6",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -71,10 +71,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "2.1.46-alpha.3",
|
"@budibase/bbui": "2.1.46-alpha.6",
|
||||||
"@budibase/client": "2.1.46-alpha.3",
|
"@budibase/client": "2.1.46-alpha.6",
|
||||||
"@budibase/frontend-core": "2.1.46-alpha.3",
|
"@budibase/frontend-core": "2.1.46-alpha.6",
|
||||||
"@budibase/string-templates": "2.1.46-alpha.3",
|
"@budibase/string-templates": "2.1.46-alpha.6",
|
||||||
"@sentry/browser": "5.19.1",
|
"@sentry/browser": "5.19.1",
|
||||||
"@spectrum-css/page": "^3.0.1",
|
"@spectrum-css/page": "^3.0.1",
|
||||||
"@spectrum-css/vars": "^3.0.1",
|
"@spectrum-css/vars": "^3.0.1",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/cli",
|
"name": "@budibase/cli",
|
||||||
"version": "2.1.46-alpha.3",
|
"version": "2.1.46-alpha.6",
|
||||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -26,9 +26,9 @@
|
||||||
"outputPath": "build"
|
"outputPath": "build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/backend-core": "2.1.46-alpha.3",
|
"@budibase/backend-core": "2.1.46-alpha.6",
|
||||||
"@budibase/string-templates": "2.1.46-alpha.3",
|
"@budibase/string-templates": "2.1.46-alpha.6",
|
||||||
"@budibase/types": "2.1.46-alpha.3",
|
"@budibase/types": "2.1.46-alpha.6",
|
||||||
"axios": "0.21.2",
|
"axios": "0.21.2",
|
||||||
"chalk": "4.1.0",
|
"chalk": "4.1.0",
|
||||||
"cli-progress": "3.11.2",
|
"cli-progress": "3.11.2",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/client",
|
"name": "@budibase/client",
|
||||||
"version": "2.1.46-alpha.3",
|
"version": "2.1.46-alpha.6",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"module": "dist/budibase-client.js",
|
"module": "dist/budibase-client.js",
|
||||||
"main": "dist/budibase-client.js",
|
"main": "dist/budibase-client.js",
|
||||||
|
@ -19,9 +19,9 @@
|
||||||
"dev:builder": "rollup -cw"
|
"dev:builder": "rollup -cw"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "2.1.46-alpha.3",
|
"@budibase/bbui": "2.1.46-alpha.6",
|
||||||
"@budibase/frontend-core": "2.1.46-alpha.3",
|
"@budibase/frontend-core": "2.1.46-alpha.6",
|
||||||
"@budibase/string-templates": "2.1.46-alpha.3",
|
"@budibase/string-templates": "2.1.46-alpha.6",
|
||||||
"@spectrum-css/button": "^3.0.3",
|
"@spectrum-css/button": "^3.0.3",
|
||||||
"@spectrum-css/card": "^3.0.3",
|
"@spectrum-css/card": "^3.0.3",
|
||||||
"@spectrum-css/divider": "^1.0.3",
|
"@spectrum-css/divider": "^1.0.3",
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/frontend-core",
|
"name": "@budibase/frontend-core",
|
||||||
"version": "2.1.46-alpha.3",
|
"version": "2.1.46-alpha.6",
|
||||||
"description": "Budibase frontend core libraries used in builder and client",
|
"description": "Budibase frontend core libraries used in builder and client",
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"svelte": "src/index.js",
|
"svelte": "src/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "2.1.46-alpha.3",
|
"@budibase/bbui": "2.1.46-alpha.6",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"svelte": "^3.46.2"
|
"svelte": "^3.46.2"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/sdk",
|
"name": "@budibase/sdk",
|
||||||
"version": "2.1.46-alpha.3",
|
"version": "2.1.46-alpha.6",
|
||||||
"description": "Budibase Public API SDK",
|
"description": "Budibase Public API SDK",
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import fs from "fs"
|
||||||
module FetchMock {
|
module FetchMock {
|
||||||
const fetch = jest.requireActual("node-fetch")
|
const fetch = jest.requireActual("node-fetch")
|
||||||
let failCount = 0
|
let failCount = 0
|
||||||
|
@ -92,6 +93,83 @@ module FetchMock {
|
||||||
value:
|
value:
|
||||||
'<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-GB"></html>',
|
'<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-GB"></html>',
|
||||||
})
|
})
|
||||||
|
} else if (
|
||||||
|
url === "https://api.github.com/repos/my-repo/budibase-comment-box"
|
||||||
|
) {
|
||||||
|
return Promise.resolve({
|
||||||
|
json: () => {
|
||||||
|
return {
|
||||||
|
name: "budibase-comment-box",
|
||||||
|
releases_url:
|
||||||
|
"https://api.github.com/repos/my-repo/budibase-comment-box{/id}",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else if (
|
||||||
|
url === "https://api.github.com/repos/my-repo/budibase-comment-box/latest"
|
||||||
|
) {
|
||||||
|
return Promise.resolve({
|
||||||
|
json: () => {
|
||||||
|
return {
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
content_type: "application/gzip",
|
||||||
|
browser_download_url:
|
||||||
|
"https://github.com/my-repo/budibase-comment-box/releases/download/v1.0.2/comment-box-1.0.2.tar.gz",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else if (
|
||||||
|
url ===
|
||||||
|
"https://github.com/my-repo/budibase-comment-box/releases/download/v1.0.2/comment-box-1.0.2.tar.gz"
|
||||||
|
) {
|
||||||
|
return Promise.resolve({
|
||||||
|
body: fs.createReadStream(
|
||||||
|
"src/api/routes/tests/data/comment-box-1.0.2.tar.gz"
|
||||||
|
),
|
||||||
|
ok: true,
|
||||||
|
})
|
||||||
|
} else if (url === "https://www.npmjs.com/package/budibase-component") {
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 200,
|
||||||
|
json: () => {
|
||||||
|
return {
|
||||||
|
name: "budibase-component",
|
||||||
|
"dist-tags": {
|
||||||
|
latest: "1.0.0",
|
||||||
|
},
|
||||||
|
versions: {
|
||||||
|
"1.0.0": {
|
||||||
|
dist: {
|
||||||
|
tarball:
|
||||||
|
"https://registry.npmjs.org/budibase-component/-/budibase-component-1.0.2.tgz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else if (
|
||||||
|
url ===
|
||||||
|
"https://registry.npmjs.org/budibase-component/-/budibase-component-1.0.2.tgz"
|
||||||
|
) {
|
||||||
|
return Promise.resolve({
|
||||||
|
body: fs.createReadStream(
|
||||||
|
"src/api/routes/tests/data/budibase-component-1.0.2.tgz"
|
||||||
|
),
|
||||||
|
ok: true,
|
||||||
|
})
|
||||||
|
} else if (
|
||||||
|
url === "https://www.someurl.com/comment-box/comment-box-1.0.2.tar.gz"
|
||||||
|
) {
|
||||||
|
return Promise.resolve({
|
||||||
|
body: fs.createReadStream(
|
||||||
|
"src/api/routes/tests/data/comment-box-1.0.2.tar.gz"
|
||||||
|
),
|
||||||
|
ok: true,
|
||||||
|
})
|
||||||
} else if (url.includes("failonce.com")) {
|
} else if (url.includes("failonce.com")) {
|
||||||
failCount++
|
failCount++
|
||||||
if (failCount === 1) {
|
if (failCount === 1) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/server",
|
"name": "@budibase/server",
|
||||||
"email": "hi@budibase.com",
|
"email": "hi@budibase.com",
|
||||||
"version": "2.1.46-alpha.3",
|
"version": "2.1.46-alpha.6",
|
||||||
"description": "Budibase Web Server",
|
"description": "Budibase Web Server",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -43,11 +43,11 @@
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apidevtools/swagger-parser": "10.0.3",
|
"@apidevtools/swagger-parser": "10.0.3",
|
||||||
"@budibase/backend-core": "2.1.46-alpha.3",
|
"@budibase/backend-core": "2.1.46-alpha.6",
|
||||||
"@budibase/client": "2.1.46-alpha.3",
|
"@budibase/client": "2.1.46-alpha.6",
|
||||||
"@budibase/pro": "2.1.46-alpha.3",
|
"@budibase/pro": "2.1.46-alpha.6",
|
||||||
"@budibase/string-templates": "2.1.46-alpha.3",
|
"@budibase/string-templates": "2.1.46-alpha.6",
|
||||||
"@budibase/types": "2.1.46-alpha.3",
|
"@budibase/types": "2.1.46-alpha.6",
|
||||||
"@bull-board/api": "3.7.0",
|
"@bull-board/api": "3.7.0",
|
||||||
"@bull-board/koa": "3.9.4",
|
"@bull-board/koa": "3.9.4",
|
||||||
"@elastic/elasticsearch": "7.10.0",
|
"@elastic/elasticsearch": "7.10.0",
|
||||||
|
|
|
@ -12,13 +12,11 @@ jest.mock("../../../utilities/redis", () => ({
|
||||||
shutdown: jest.fn(),
|
shutdown: jest.fn(),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const {
|
import { clearAllApps, checkBuilderEndpoint } from "./utilities/TestFunctions"
|
||||||
clearAllApps,
|
import * as setup from "./utilities"
|
||||||
checkBuilderEndpoint,
|
import { AppStatus } from "../../../db/utils"
|
||||||
} = require("./utilities/TestFunctions")
|
import { events } from "@budibase/backend-core"
|
||||||
const setup = require("./utilities")
|
import env from "../../../environment"
|
||||||
const { AppStatus } = require("../../../db/utils")
|
|
||||||
const { events } = require("@budibase/backend-core")
|
|
||||||
|
|
||||||
describe("/applications", () => {
|
describe("/applications", () => {
|
||||||
let request = setup.getRequest()
|
let request = setup.getRequest()
|
||||||
|
@ -234,4 +232,39 @@ describe("/applications", () => {
|
||||||
expect(getRes.body.application.updatedAt).toBeDefined()
|
expect(getRes.body.application.updatedAt).toBeDefined()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("sync", () => {
|
||||||
|
it("app should sync correctly", async () => {
|
||||||
|
const res = await request
|
||||||
|
.post(`/api/applications/${config.getAppId()}/sync`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
expect(res.body.message).toEqual("App sync completed successfully.")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("app should not sync if production", async () => {
|
||||||
|
const res = await request
|
||||||
|
.post(`/api/applications/app_123456/sync`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(400)
|
||||||
|
expect(res.body.message).toEqual(
|
||||||
|
"This action cannot be performed for production apps"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("app should not sync if sync is disabled", async () => {
|
||||||
|
env._set("DISABLE_AUTO_PROD_APP_SYNC", true)
|
||||||
|
const res = await request
|
||||||
|
.post(`/api/applications/${config.getAppId()}/sync`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
expect(res.body.message).toEqual(
|
||||||
|
"App sync disabled. You can reenable with the DISABLE_AUTO_PROD_APP_SYNC environment variable."
|
||||||
|
)
|
||||||
|
env._set("DISABLE_AUTO_PROD_APP_SYNC", false)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
|
@ -8,10 +8,10 @@ jest.mock("@budibase/backend-core", () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
|
import * as setup from "./utilities"
|
||||||
const setup = require("./utilities")
|
import { events } from "@budibase/backend-core"
|
||||||
const { events } = require("@budibase/backend-core")
|
import sdk from "../../../sdk"
|
||||||
|
import { checkBuilderEndpoint } from "./utilities/TestFunctions"
|
||||||
describe("/backups", () => {
|
describe("/backups", () => {
|
||||||
let request = setup.getRequest()
|
let request = setup.getRequest()
|
||||||
let config = setup.getConfig()
|
let config = setup.getConfig()
|
||||||
|
@ -30,7 +30,7 @@ describe("/backups", () => {
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.text).toBeDefined()
|
expect(res.text).toBeDefined()
|
||||||
expect(res.headers["content-type"]).toEqual("application/gzip")
|
expect(res.headers["content-type"]).toEqual("application/gzip")
|
||||||
expect(events.app.exported.mock.calls.length).toBe(1)
|
expect(events.app.exported).toBeCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
|
@ -41,4 +41,15 @@ describe("/backups", () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("calculateBackupStats", () => {
|
||||||
|
it("should be able to calculate the backup statistics", async () => {
|
||||||
|
config.createAutomation()
|
||||||
|
config.createScreen()
|
||||||
|
let res = await sdk.backups.calculateBackupStats(config.getAppId())
|
||||||
|
expect(res.automations).toEqual(1)
|
||||||
|
expect(res.datasources).toEqual(1)
|
||||||
|
expect(res.screens).toEqual(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { db as dbCore } from "@budibase/backend-core"
|
||||||
|
import { AppStatus } from "../../../db/utils"
|
||||||
|
|
||||||
|
import * as setup from "./utilities"
|
||||||
|
|
||||||
|
describe("/cloud", () => {
|
||||||
|
let request = setup.getRequest()
|
||||||
|
let config = setup.getConfig()
|
||||||
|
|
||||||
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await config.init()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
// clear all mocks
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("import", () => {
|
||||||
|
it("should be able to import apps", async () => {
|
||||||
|
// first we need to delete any existing apps on the system so it looks clean otherwise the
|
||||||
|
// import will not run
|
||||||
|
await request
|
||||||
|
.delete(
|
||||||
|
`/api/applications/${dbCore.getProdAppID(
|
||||||
|
config.getAppId()
|
||||||
|
)}?unpublish=true`
|
||||||
|
)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
await request
|
||||||
|
.delete(`/api/applications/${config.getAppId()}`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
// get a count of apps before the import
|
||||||
|
const preImportApps = await request
|
||||||
|
.get(`/api/applications?status=${AppStatus.ALL}`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
// Perform the import
|
||||||
|
const res = await request
|
||||||
|
.post(`/api/cloud/import`)
|
||||||
|
.attach("importFile", "src/api/routes/tests/data/export-test.tar.gz")
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect(200)
|
||||||
|
expect(res.body.message).toEqual("Apps successfully imported.")
|
||||||
|
|
||||||
|
// get a count of apps after the import
|
||||||
|
const postImportApps = await request
|
||||||
|
.get(`/api/applications?status=${AppStatus.ALL}`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
// There are two apps in the file that was imported so check for this
|
||||||
|
expect(postImportApps.body.length).toEqual(2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,16 +1,16 @@
|
||||||
jest.mock("pg")
|
jest.mock("pg")
|
||||||
|
import * as setup from "./utilities"
|
||||||
|
import { checkBuilderEndpoint } from "./utilities/TestFunctions"
|
||||||
|
import { checkCacheForDynamicVariable } from "../../../threads/utils"
|
||||||
|
import { events } from "@budibase/backend-core"
|
||||||
|
|
||||||
let setup = require("./utilities")
|
|
||||||
let { basicDatasource } = setup.structures
|
let { basicDatasource } = setup.structures
|
||||||
let { checkBuilderEndpoint } = require("./utilities/TestFunctions")
|
|
||||||
const pg = require("pg")
|
const pg = require("pg")
|
||||||
const { checkCacheForDynamicVariable } = require("../../../threads/utils")
|
|
||||||
const { events } = require("@budibase/backend-core")
|
|
||||||
|
|
||||||
describe("/datasources", () => {
|
describe("/datasources", () => {
|
||||||
let request = setup.getRequest()
|
let request = setup.getRequest()
|
||||||
let config = setup.getConfig()
|
let config = setup.getConfig()
|
||||||
let datasource
|
let datasource: any
|
||||||
|
|
||||||
afterAll(setup.afterAll)
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ describe("/datasources", () => {
|
||||||
.post(`/api/datasources`)
|
.post(`/api/datasources`)
|
||||||
.send(basicDatasource())
|
.send(basicDatasource())
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.datasource.name).toEqual("Test")
|
expect(res.body.datasource.name).toEqual("Test")
|
||||||
|
@ -42,7 +42,7 @@ describe("/datasources", () => {
|
||||||
.put(`/api/datasources/${datasource._id}`)
|
.put(`/api/datasources/${datasource._id}`)
|
||||||
.send(datasource)
|
.send(datasource)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.datasource.name).toEqual("Updated Test")
|
expect(res.body.datasource.name).toEqual("Updated Test")
|
||||||
|
@ -51,16 +51,25 @@ describe("/datasources", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("dynamic variables", () => {
|
describe("dynamic variables", () => {
|
||||||
async function preview(datasource, fields) {
|
async function preview(
|
||||||
|
datasource: any,
|
||||||
|
fields: { path: string; queryString: string }
|
||||||
|
) {
|
||||||
return config.previewQuery(request, config, datasource, fields)
|
return config.previewQuery(request, config, datasource, fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
it("should invalidate changed or removed variables", async () => {
|
it("should invalidate changed or removed variables", async () => {
|
||||||
const { datasource, query } = await config.dynamicVariableDatasource()
|
const { datasource, query } = await config.dynamicVariableDatasource()
|
||||||
// preview once to cache variables
|
// preview once to cache variables
|
||||||
await preview(datasource, { path: "www.test.com", queryString: "test={{ variable3 }}" })
|
await preview(datasource, {
|
||||||
|
path: "www.test.com",
|
||||||
|
queryString: "test={{ variable3 }}",
|
||||||
|
})
|
||||||
// check variables in cache
|
// check variables in cache
|
||||||
let contents = await checkCacheForDynamicVariable(query._id, "variable3")
|
let contents = await checkCacheForDynamicVariable(
|
||||||
|
query._id,
|
||||||
|
"variable3"
|
||||||
|
)
|
||||||
expect(contents.rows.length).toEqual(1)
|
expect(contents.rows.length).toEqual(1)
|
||||||
|
|
||||||
// update the datasource to remove the variables
|
// update the datasource to remove the variables
|
||||||
|
@ -69,7 +78,7 @@ describe("/datasources", () => {
|
||||||
.put(`/api/datasources/${datasource._id}`)
|
.put(`/api/datasources/${datasource._id}`)
|
||||||
.send(datasource)
|
.send(datasource)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.body.errors).toBeUndefined()
|
expect(res.body.errors).toBeUndefined()
|
||||||
|
|
||||||
|
@ -85,7 +94,7 @@ describe("/datasources", () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/datasources`)
|
.get(`/api/datasources`)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
const datasources = res.body
|
const datasources = res.body
|
||||||
|
@ -160,7 +169,7 @@ describe("/datasources", () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/datasources`)
|
.get(`/api/datasources`)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.length).toEqual(1)
|
expect(res.body.length).toEqual(1)
|
||||||
|
@ -174,6 +183,5 @@ describe("/datasources", () => {
|
||||||
url: `/api/datasources/${datasource._id}/${datasource._rev}`,
|
url: `/api/datasources/${datasource._id}/${datasource._rev}`,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
|
@ -0,0 +1,179 @@
|
||||||
|
let mockObjectStore = jest.fn().mockImplementation(() => {
|
||||||
|
return [{ name: "test.js" }]
|
||||||
|
})
|
||||||
|
|
||||||
|
let deleteFolder = jest.fn().mockImplementation()
|
||||||
|
jest.mock("@budibase/backend-core", () => {
|
||||||
|
const core = jest.requireActual("@budibase/backend-core")
|
||||||
|
return {
|
||||||
|
...core,
|
||||||
|
objectStore: {
|
||||||
|
...core.objectStore,
|
||||||
|
upload: jest.fn(),
|
||||||
|
uploadDirectory: mockObjectStore,
|
||||||
|
deleteFolder: deleteFolder,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
import { events } from "@budibase/backend-core"
|
||||||
|
import * as setup from "./utilities"
|
||||||
|
|
||||||
|
describe("/plugins", () => {
|
||||||
|
let request = setup.getRequest()
|
||||||
|
let config = setup.getConfig()
|
||||||
|
|
||||||
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await config.init()
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
const createPlugin = async (status?: number) => {
|
||||||
|
return request
|
||||||
|
.post(`/api/plugin/upload`)
|
||||||
|
.attach("file", "src/api/routes/tests/data/comment-box-1.0.2.tar.gz")
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(status ? status : 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPlugins = async (status?: number) => {
|
||||||
|
return request
|
||||||
|
.get(`/api/plugin`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(status ? status : 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("upload", () => {
|
||||||
|
it("should be able to upload a plugin", async () => {
|
||||||
|
let res = await createPlugin()
|
||||||
|
expect(res.body).toBeDefined()
|
||||||
|
expect(res.body.plugins).toBeDefined()
|
||||||
|
expect(res.body.plugins[0]._id).toEqual("plg_comment-box")
|
||||||
|
expect(events.plugin.imported).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should not be able to create a plugin if there is an error", async () => {
|
||||||
|
mockObjectStore.mockImplementationOnce(() => {
|
||||||
|
throw new Error()
|
||||||
|
})
|
||||||
|
let res = await createPlugin(400)
|
||||||
|
expect(res.body.message).toEqual("Failed to import plugin: Error")
|
||||||
|
expect(events.plugin.imported).toHaveBeenCalledTimes(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("fetch", () => {
|
||||||
|
it("should be able to fetch plugins", async () => {
|
||||||
|
await createPlugin()
|
||||||
|
const res = await getPlugins()
|
||||||
|
expect(res.body).toBeDefined()
|
||||||
|
expect(res.body[0]._id).toEqual("plg_comment-box")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("destroy", () => {
|
||||||
|
it("should be able to delete a plugin", async () => {
|
||||||
|
await createPlugin()
|
||||||
|
const res = await request
|
||||||
|
.delete(`/api/plugin/plg_comment-box`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
expect(res.body).toBeDefined()
|
||||||
|
expect(res.body.message).toEqual("Plugin plg_comment-box deleted.")
|
||||||
|
|
||||||
|
const plugins = await getPlugins()
|
||||||
|
expect(plugins.body).toBeDefined()
|
||||||
|
expect(plugins.body.length).toEqual(0)
|
||||||
|
expect(events.plugin.deleted).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
it("should handle an error deleting a plugin", async () => {
|
||||||
|
deleteFolder.mockImplementationOnce(() => {
|
||||||
|
throw new Error()
|
||||||
|
})
|
||||||
|
|
||||||
|
await createPlugin()
|
||||||
|
const res = await request
|
||||||
|
.delete(`/api/plugin/plg_comment-box`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(400)
|
||||||
|
|
||||||
|
expect(res.body.message).toEqual("Failed to delete plugin: Error")
|
||||||
|
expect(events.plugin.deleted).toHaveBeenCalledTimes(0)
|
||||||
|
const plugins = await getPlugins()
|
||||||
|
expect(plugins.body).toBeDefined()
|
||||||
|
expect(plugins.body.length).toEqual(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("github", () => {
|
||||||
|
const createGithubPlugin = async (status?: number, url?: string) => {
|
||||||
|
return await request
|
||||||
|
.post(`/api/plugin`)
|
||||||
|
.send({
|
||||||
|
source: "Github",
|
||||||
|
url,
|
||||||
|
githubToken: "token",
|
||||||
|
})
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(status ? status : 200)
|
||||||
|
}
|
||||||
|
it("should be able to create a plugin from github", async () => {
|
||||||
|
const res = await createGithubPlugin(
|
||||||
|
200,
|
||||||
|
"https://github.com/my-repo/budibase-comment-box.git"
|
||||||
|
)
|
||||||
|
expect(res.body).toBeDefined()
|
||||||
|
expect(res.body.plugin).toBeDefined()
|
||||||
|
expect(res.body.plugin._id).toEqual("plg_comment-box")
|
||||||
|
})
|
||||||
|
it("should fail if the url is not from github", async () => {
|
||||||
|
const res = await createGithubPlugin(
|
||||||
|
400,
|
||||||
|
"https://notgithub.com/my-repo/budibase-comment-box"
|
||||||
|
)
|
||||||
|
expect(res.body.message).toEqual(
|
||||||
|
"Failed to import plugin: The plugin origin must be from Github"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe("npm", () => {
|
||||||
|
it("should be able to create a plugin from npm", async () => {
|
||||||
|
const res = await request
|
||||||
|
.post(`/api/plugin`)
|
||||||
|
.send({
|
||||||
|
source: "NPM",
|
||||||
|
url: "https://www.npmjs.com/package/budibase-component",
|
||||||
|
})
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
expect(res.body).toBeDefined()
|
||||||
|
expect(res.body.plugin._id).toEqual("plg_budibase-component")
|
||||||
|
expect(events.plugin.imported).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("url", () => {
|
||||||
|
it("should be able to create a plugin from a URL", async () => {
|
||||||
|
const res = await request
|
||||||
|
.post(`/api/plugin`)
|
||||||
|
.send({
|
||||||
|
source: "URL",
|
||||||
|
url: "https://www.someurl.com/comment-box/comment-box-1.0.2.tar.gz",
|
||||||
|
})
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
expect(res.body).toBeDefined()
|
||||||
|
expect(res.body.plugin._id).toEqual("plg_comment-box")
|
||||||
|
expect(events.plugin.imported).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -9,7 +9,6 @@ const route = "/test"
|
||||||
// there are checks which are disabled in test env,
|
// there are checks which are disabled in test env,
|
||||||
// these checks need to be enabled for this test
|
// these checks need to be enabled for this test
|
||||||
|
|
||||||
|
|
||||||
describe("/routing", () => {
|
describe("/routing", () => {
|
||||||
let request = setup.getRequest()
|
let request = setup.getRequest()
|
||||||
let config = setup.getConfig()
|
let config = setup.getConfig()
|
||||||
|
|
|
@ -87,6 +87,12 @@ describe("/tables", () => {
|
||||||
|
|
||||||
it("updates all the row fields for a table when a schema key is renamed", async () => {
|
it("updates all the row fields for a table when a schema key is renamed", async () => {
|
||||||
const testTable = await config.createTable()
|
const testTable = await config.createTable()
|
||||||
|
await config.createView({
|
||||||
|
name: "TestView",
|
||||||
|
field: "Price",
|
||||||
|
calculation: "stats",
|
||||||
|
tableId: testTable._id,
|
||||||
|
})
|
||||||
|
|
||||||
const testRow = await request
|
const testRow = await request
|
||||||
.post(`/api/${testTable._id}/rows`)
|
.post(`/api/${testTable._id}/rows`)
|
||||||
|
|
|
@ -90,4 +90,90 @@ describe("/users", () => {
|
||||||
expect(res.body.tableId).toBeDefined()
|
expect(res.body.tableId).toBeDefined()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
describe("setFlag", () => {
|
||||||
|
it("should throw an error if a flag is not provided", async () => {
|
||||||
|
await config.createUser()
|
||||||
|
const res = await request
|
||||||
|
.post(`/api/users/flags`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.send({ value: "test" })
|
||||||
|
.expect(400)
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
expect(res.body.message).toEqual("Must supply a 'flag' field in request body.")
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to set a flag on the user", async () => {
|
||||||
|
await config.createUser()
|
||||||
|
const res = await request
|
||||||
|
.post(`/api/users/flags`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.send({ value: "test", flag: "test" })
|
||||||
|
.expect(200)
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
expect(res.body.message).toEqual("Flag set successfully")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("getFlags", () => {
|
||||||
|
it("should get flags for a specific user", async () => {
|
||||||
|
let flagData = { value: "test", flag: "test" }
|
||||||
|
await config.createUser()
|
||||||
|
await request
|
||||||
|
.post(`/api/users/flags`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.send(flagData)
|
||||||
|
.expect(200)
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
|
||||||
|
const res = await request
|
||||||
|
.get(`/api/users/flags`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect(200)
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
expect(res.body[flagData.value]).toEqual(flagData.flag)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("setFlag", () => {
|
||||||
|
it("should throw an error if a flag is not provided", async () => {
|
||||||
|
await config.createUser()
|
||||||
|
const res = await request
|
||||||
|
.post(`/api/users/flags`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.send({ value: "test" })
|
||||||
|
.expect(400)
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
expect(res.body.message).toEqual("Must supply a 'flag' field in request body.")
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to set a flag on the user", async () => {
|
||||||
|
await config.createUser()
|
||||||
|
const res = await request
|
||||||
|
.post(`/api/users/flags`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.send({ value: "test", flag: "test" })
|
||||||
|
.expect(200)
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
expect(res.body.message).toEqual("Flag set successfully")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("syncUser", () => {
|
||||||
|
it("should sync the user", async () => {
|
||||||
|
let user = await config.createUser()
|
||||||
|
await config.createApp('New App')
|
||||||
|
let res = await request
|
||||||
|
.post(`/api/users/metadata/sync/${user._id}`)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect(200)
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
expect(res.body.message).toEqual('User synced.')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -63,14 +63,14 @@ export function afterAll() {
|
||||||
|
|
||||||
export function getRequest() {
|
export function getRequest() {
|
||||||
if (!request) {
|
if (!request) {
|
||||||
exports.beforeAll()
|
beforeAll()
|
||||||
}
|
}
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConfig() {
|
export function getConfig() {
|
||||||
if (!config) {
|
if (!config) {
|
||||||
exports.beforeAll()
|
beforeAll()
|
||||||
}
|
}
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
} from "@budibase/string-templates"
|
} from "@budibase/string-templates"
|
||||||
import sdk from "../sdk"
|
import sdk from "../sdk"
|
||||||
import { Row } from "@budibase/types"
|
import { Row } from "@budibase/types"
|
||||||
|
import { LoopStep, LoopStepType, LoopInput } from "../definitions/automations"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When values are input to the system generally they will be of type string as this is required for template strings.
|
* When values are input to the system generally they will be of type string as this is required for template strings.
|
||||||
|
@ -123,3 +124,26 @@ export function stringSplit(value: string | string[]) {
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function typecastForLooping(loopStep: LoopStep, input: LoopInput) {
|
||||||
|
if (!input || !input.binding) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
switch (loopStep.inputs.option) {
|
||||||
|
case LoopStepType.ARRAY:
|
||||||
|
if (typeof input.binding === "string") {
|
||||||
|
return JSON.parse(input.binding)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case LoopStepType.STRING:
|
||||||
|
if (Array.isArray(input.binding)) {
|
||||||
|
return input.binding.join(",")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error("Unable to cast to correct type")
|
||||||
|
}
|
||||||
|
return input.binding
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
const setup = require("./utilities")
|
||||||
|
|
||||||
|
describe("test the bash action", () => {
|
||||||
|
let config = setup.getConfig()
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await config.init()
|
||||||
|
})
|
||||||
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
|
it("should be able to execute a script", async () => {
|
||||||
|
|
||||||
|
let res = await setup.runStep("EXECUTE_BASH",
|
||||||
|
inputs = {
|
||||||
|
code: "echo 'test'"
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
expect(res.stdout).toEqual("test\n")
|
||||||
|
expect(res.success).toEqual(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should handle a null value", async () => {
|
||||||
|
|
||||||
|
let res = await setup.runStep("EXECUTE_BASH",
|
||||||
|
inputs = {
|
||||||
|
code: null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
)
|
||||||
|
expect(res.stdout).toEqual("Budibase bash automation failed: Invalid inputs")
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,27 @@
|
||||||
|
const setup = require("./utilities")
|
||||||
|
const fetch = require("node-fetch")
|
||||||
|
|
||||||
|
jest.mock("node-fetch")
|
||||||
|
|
||||||
|
describe("test the outgoing webhook action", () => {
|
||||||
|
let inputs
|
||||||
|
let config = setup.getConfig()
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await config.init()
|
||||||
|
inputs = {
|
||||||
|
username: "joe_bloggs",
|
||||||
|
url: "http://www.test.com",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
|
it("should be able to run the action", async () => {
|
||||||
|
const res = await setup.runStep(setup.actions.discord.stepId, inputs)
|
||||||
|
expect(res.response.url).toEqual("http://www.test.com")
|
||||||
|
expect(res.response.method).toEqual("post")
|
||||||
|
expect(res.success).toEqual(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
|
@ -0,0 +1,49 @@
|
||||||
|
const setup = require("./utilities")
|
||||||
|
|
||||||
|
describe("test the execute query action", () => {
|
||||||
|
let datasource
|
||||||
|
let config = setup.getConfig()
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await config.init()
|
||||||
|
|
||||||
|
await config.createDatasource()
|
||||||
|
query = await config.createQuery()
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
|
it("should be able to execute a query", async () => {
|
||||||
|
let res = await setup.runStep(setup.actions.EXECUTE_QUERY.stepId,
|
||||||
|
inputs = {
|
||||||
|
query: { queryId: query._id }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expect(res.response).toEqual([{ a: 'string', b: 1 }])
|
||||||
|
expect(res.success).toEqual(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should handle a null query value", async () => {
|
||||||
|
let res = await setup.runStep(setup.actions.EXECUTE_QUERY.stepId,
|
||||||
|
inputs = {
|
||||||
|
query: null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expect(res.response.message).toEqual("Invalid inputs")
|
||||||
|
expect(res.success).toEqual(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it("should handle an error executing a query", async () => {
|
||||||
|
let res = await setup.runStep(setup.actions.EXECUTE_QUERY.stepId,
|
||||||
|
inputs = {
|
||||||
|
query: { queryId: "wrong_id" }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expect(res.response).toEqual('{"status":404,"name":"not_found","message":"missing","reason":"missing"}')
|
||||||
|
expect(res.success).toEqual(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
})
|
|
@ -0,0 +1,48 @@
|
||||||
|
const setup = require("./utilities")
|
||||||
|
|
||||||
|
describe("test the execute script action", () => {
|
||||||
|
let config = setup.getConfig()
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await config.init()
|
||||||
|
})
|
||||||
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
|
it("should be able to execute a script", async () => {
|
||||||
|
|
||||||
|
let res = await setup.runStep(setup.actions.EXECUTE_SCRIPT.stepId,
|
||||||
|
inputs = {
|
||||||
|
code: "return 1 + 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
expect(res.value).toEqual(2)
|
||||||
|
expect(res.success).toEqual(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should handle a null value", async () => {
|
||||||
|
|
||||||
|
let res = await setup.runStep(setup.actions.EXECUTE_SCRIPT.stepId,
|
||||||
|
inputs = {
|
||||||
|
code: null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
)
|
||||||
|
expect(res.response.message).toEqual("Invalid inputs")
|
||||||
|
expect(res.success).toEqual(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to handle an error gracefully", async () => {
|
||||||
|
|
||||||
|
let res = await setup.runStep(setup.actions.EXECUTE_SCRIPT.stepId,
|
||||||
|
inputs = {
|
||||||
|
code: "return something.map(x => x.name)"
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
expect(res.response).toEqual("ReferenceError: something is not defined")
|
||||||
|
expect(res.success).toEqual(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
|
@ -0,0 +1,71 @@
|
||||||
|
|
||||||
|
function generateResponse(to, from) {
|
||||||
|
return {
|
||||||
|
"success": true,
|
||||||
|
"response": {
|
||||||
|
"accepted": [
|
||||||
|
to
|
||||||
|
],
|
||||||
|
"envelope": {
|
||||||
|
"from": from,
|
||||||
|
"to": [
|
||||||
|
to
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"message": `Email sent to ${to}.`
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockFetch = jest.fn(() => ({
|
||||||
|
headers: {
|
||||||
|
raw: () => {
|
||||||
|
return { "content-type": ["application/json"] }
|
||||||
|
},
|
||||||
|
get: () => ["application/json"],
|
||||||
|
},
|
||||||
|
json: jest.fn(() => response),
|
||||||
|
status: 200,
|
||||||
|
text: jest.fn(),
|
||||||
|
}))
|
||||||
|
jest.mock("node-fetch", () => mockFetch)
|
||||||
|
const setup = require("./utilities")
|
||||||
|
|
||||||
|
|
||||||
|
describe("test the outgoing webhook action", () => {
|
||||||
|
let inputs
|
||||||
|
let config = setup.getConfig()
|
||||||
|
beforeEach(async () => {
|
||||||
|
await config.init()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
|
it("should be able to run the action", async () => {
|
||||||
|
inputs = {
|
||||||
|
to: "user1@test.com",
|
||||||
|
from: "admin@test.com",
|
||||||
|
subject: "hello",
|
||||||
|
contents: "testing",
|
||||||
|
}
|
||||||
|
let resp = generateResponse(inputs.to, inputs.from)
|
||||||
|
mockFetch.mockImplementationOnce(() => ({
|
||||||
|
headers: {
|
||||||
|
raw: () => {
|
||||||
|
return { "content-type": ["application/json"] }
|
||||||
|
},
|
||||||
|
get: () => ["application/json"],
|
||||||
|
},
|
||||||
|
json: jest.fn(() => resp),
|
||||||
|
status: 200,
|
||||||
|
text: jest.fn(),
|
||||||
|
}))
|
||||||
|
const res = await setup.runStep(setup.actions.SEND_EMAIL_SMTP.stepId, inputs)
|
||||||
|
expect(res.response).toEqual(resp)
|
||||||
|
expect(res.success).toEqual(true)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
})
|
|
@ -0,0 +1,22 @@
|
||||||
|
const setup = require("./utilities")
|
||||||
|
|
||||||
|
describe("test the server log action", () => {
|
||||||
|
let config = setup.getConfig()
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await config.init()
|
||||||
|
inputs = {
|
||||||
|
text: "log message",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
|
it("should be able to log the text", async () => {
|
||||||
|
|
||||||
|
let res = await setup.runStep(setup.actions.SERVER_LOG.stepId,
|
||||||
|
inputs
|
||||||
|
)
|
||||||
|
expect(res.message).toEqual(`App ${config.getAppId()} - ${inputs.text}`)
|
||||||
|
expect(res.success).toEqual(true)
|
||||||
|
})
|
||||||
|
})
|
|
@ -31,7 +31,7 @@ export async function runInProd(fn: any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runStep(stepId: string, inputs: any) {
|
export async function runStep(stepId: string, inputs: any, stepContext?: any) {
|
||||||
async function run() {
|
async function run() {
|
||||||
let step = await getAction(stepId)
|
let step = await getAction(stepId)
|
||||||
expect(step).toBeDefined()
|
expect(step).toBeDefined()
|
||||||
|
@ -39,7 +39,7 @@ export async function runStep(stepId: string, inputs: any) {
|
||||||
throw new Error("No step found")
|
throw new Error("No step found")
|
||||||
}
|
}
|
||||||
return step({
|
return step({
|
||||||
context: {},
|
context: stepContext || {},
|
||||||
inputs,
|
inputs,
|
||||||
appId: config ? config.getAppId() : null,
|
appId: config ? config.getAppId() : null,
|
||||||
// don't really need an API key, mocked out usage quota, not being tested here
|
// don't really need an API key, mocked out usage quota, not being tested here
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
const setup = require("./utilities")
|
||||||
|
const fetch = require("node-fetch")
|
||||||
|
|
||||||
|
jest.mock("node-fetch")
|
||||||
|
|
||||||
|
describe("test the outgoing webhook action", () => {
|
||||||
|
let inputs
|
||||||
|
let config = setup.getConfig()
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await config.init()
|
||||||
|
inputs = {
|
||||||
|
value1: "test",
|
||||||
|
url: "http://www.test.com",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
|
it("should be able to run the action", async () => {
|
||||||
|
const res = await setup.runStep(setup.actions.zapier.stepId, inputs)
|
||||||
|
expect(res.response.url).toEqual("http://www.test.com")
|
||||||
|
expect(res.response.method).toEqual("post")
|
||||||
|
expect(res.success).toEqual(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
|
@ -1,17 +0,0 @@
|
||||||
const automationUtils = require("../automationUtils")
|
|
||||||
|
|
||||||
describe("automationUtils", () => {
|
|
||||||
test("substituteLoopStep should allow multiple loop binding substitutes", () => {
|
|
||||||
expect(automationUtils.substituteLoopStep(
|
|
||||||
`{{ loop.currentItem._id }} {{ loop.currentItem._id }} {{ loop.currentItem._id }}`,
|
|
||||||
"step.2"))
|
|
||||||
.toBe(`{{ step.2.currentItem._id }} {{ step.2.currentItem._id }} {{ step.2.currentItem._id }}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("substituteLoopStep should handle not subsituting outside of curly braces", () => {
|
|
||||||
expect(automationUtils.substituteLoopStep(
|
|
||||||
`loop {{ loop.currentItem._id }}loop loop{{ loop.currentItem._id }}loop`,
|
|
||||||
"step.2"))
|
|
||||||
.toBe(`loop {{ step.2.currentItem._id }}loop loop{{ step.2.currentItem._id }}loop`)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
const automationUtils = require("../automationUtils")
|
||||||
|
|
||||||
|
describe("automationUtils", () => {
|
||||||
|
describe("substituteLoopStep", () => {
|
||||||
|
it("should allow multiple loop binding substitutes", () => {
|
||||||
|
expect(
|
||||||
|
automationUtils.substituteLoopStep(
|
||||||
|
`{{ loop.currentItem._id }} {{ loop.currentItem._id }} {{ loop.currentItem._id }}`,
|
||||||
|
"step.2"
|
||||||
|
)
|
||||||
|
).toBe(
|
||||||
|
`{{ step.2.currentItem._id }} {{ step.2.currentItem._id }} {{ step.2.currentItem._id }}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should handle not subsituting outside of curly braces", () => {
|
||||||
|
expect(
|
||||||
|
automationUtils.substituteLoopStep(
|
||||||
|
`loop {{ loop.currentItem._id }}loop loop{{ loop.currentItem._id }}loop`,
|
||||||
|
"step.2"
|
||||||
|
)
|
||||||
|
).toBe(
|
||||||
|
`loop {{ step.2.currentItem._id }}loop loop{{ step.2.currentItem._id }}loop`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("typeCastForLooping", () => {
|
||||||
|
it("should parse to correct type", () => {
|
||||||
|
expect(
|
||||||
|
automationUtils.typecastForLooping(
|
||||||
|
{ inputs: { option: "Array" } },
|
||||||
|
{ binding: [1, 2, 3] }
|
||||||
|
)
|
||||||
|
).toEqual([1, 2, 3])
|
||||||
|
expect(
|
||||||
|
automationUtils.typecastForLooping(
|
||||||
|
{ inputs: { option: "Array" } },
|
||||||
|
{ binding: "[1, 2, 3]" }
|
||||||
|
)
|
||||||
|
).toEqual([1, 2, 3])
|
||||||
|
expect(
|
||||||
|
automationUtils.typecastForLooping(
|
||||||
|
{ inputs: { option: "String" } },
|
||||||
|
{ binding: [1, 2, 3] }
|
||||||
|
)
|
||||||
|
).toEqual("1,2,3")
|
||||||
|
})
|
||||||
|
it("should handle null values", () => {
|
||||||
|
// expect it to handle where the binding is null
|
||||||
|
expect(
|
||||||
|
automationUtils.typecastForLooping(
|
||||||
|
{ inputs: { option: "Array" } },
|
||||||
|
{ binding: null }
|
||||||
|
)
|
||||||
|
).toEqual(null)
|
||||||
|
expect(() =>
|
||||||
|
automationUtils.typecastForLooping(
|
||||||
|
{ inputs: { option: "Array" } },
|
||||||
|
{ binding: "test" }
|
||||||
|
)
|
||||||
|
).toThrow()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,3 +1,12 @@
|
||||||
|
import { mocks } from "@budibase/backend-core/tests"
|
||||||
|
|
||||||
|
// init the licensing mock
|
||||||
|
import * as pro from "@budibase/pro"
|
||||||
|
mocks.licenses.init(pro)
|
||||||
|
|
||||||
|
// use unlimited license by default
|
||||||
|
mocks.licenses.useUnlimited()
|
||||||
|
|
||||||
import { init as dbInit } from "../../db"
|
import { init as dbInit } from "../../db"
|
||||||
dbInit()
|
dbInit()
|
||||||
import env from "../../environment"
|
import env from "../../environment"
|
||||||
|
|
|
@ -32,31 +32,8 @@ const LOOP_STEP_ID = actions.ACTION_DEFINITIONS.LOOP.stepId
|
||||||
const CRON_STEP_ID = triggerDefs.CRON.stepId
|
const CRON_STEP_ID = triggerDefs.CRON.stepId
|
||||||
const STOPPED_STATUS = { success: true, status: AutomationStatus.STOPPED }
|
const STOPPED_STATUS = { success: true, status: AutomationStatus.STOPPED }
|
||||||
|
|
||||||
function typecastForLooping(loopStep: LoopStep, input: LoopInput) {
|
|
||||||
if (!input || !input.binding) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
switch (loopStep.inputs.option) {
|
|
||||||
case LoopStepType.ARRAY:
|
|
||||||
if (typeof input.binding === "string") {
|
|
||||||
return JSON.parse(input.binding)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case LoopStepType.STRING:
|
|
||||||
if (Array.isArray(input.binding)) {
|
|
||||||
return input.binding.join(",")
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error("Unable to cast to correct type")
|
|
||||||
}
|
|
||||||
return input.binding
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLoopIterations(loopStep: LoopStep, input: LoopInput) {
|
function getLoopIterations(loopStep: LoopStep, input: LoopInput) {
|
||||||
const binding = typecastForLooping(loopStep, input)
|
const binding = automationUtils.typecastForLooping(loopStep, input)
|
||||||
if (!loopStep || !binding) {
|
if (!loopStep || !binding) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
@ -289,7 +266,7 @@ class Orchestrator {
|
||||||
|
|
||||||
let tempOutput = { items: loopSteps, iterations: iterationCount }
|
let tempOutput = { items: loopSteps, iterations: iterationCount }
|
||||||
try {
|
try {
|
||||||
newInput.binding = typecastForLooping(
|
newInput.binding = automationUtils.typecastForLooping(
|
||||||
loopStep as LoopStep,
|
loopStep as LoopStep,
|
||||||
newInput
|
newInput
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { fixAutoColumnSubType } from "../utils"
|
||||||
|
import { AutoFieldDefaultNames, AutoFieldSubTypes } from "../../../constants"
|
||||||
|
|
||||||
|
describe("rowProcessor utility", () => {
|
||||||
|
describe("fixAutoColumnSubType", () => {
|
||||||
|
let schema = {
|
||||||
|
name: "",
|
||||||
|
type: "link",
|
||||||
|
subtype: "", // missing subtype
|
||||||
|
icon: "ri-magic-line",
|
||||||
|
autocolumn: true,
|
||||||
|
constraints: { type: "array", presence: false },
|
||||||
|
tableId: "ta_users",
|
||||||
|
fieldName: "test-Updated By",
|
||||||
|
relationshipType: "many-to-many",
|
||||||
|
sortable: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
it("updates the schema with the correct subtype", async () => {
|
||||||
|
schema.name = AutoFieldDefaultNames.CREATED_BY
|
||||||
|
expect(fixAutoColumnSubType(schema).subtype).toEqual(
|
||||||
|
AutoFieldSubTypes.CREATED_BY
|
||||||
|
)
|
||||||
|
schema.subtype = ""
|
||||||
|
|
||||||
|
schema.name = AutoFieldDefaultNames.UPDATED_BY
|
||||||
|
expect(fixAutoColumnSubType(schema).subtype).toEqual(
|
||||||
|
AutoFieldSubTypes.UPDATED_BY
|
||||||
|
)
|
||||||
|
schema.subtype = ""
|
||||||
|
|
||||||
|
schema.name = AutoFieldDefaultNames.CREATED_AT
|
||||||
|
expect(fixAutoColumnSubType(schema).subtype).toEqual(
|
||||||
|
AutoFieldSubTypes.CREATED_AT
|
||||||
|
)
|
||||||
|
schema.subtype = ""
|
||||||
|
|
||||||
|
schema.name = AutoFieldDefaultNames.UPDATED_AT
|
||||||
|
expect(fixAutoColumnSubType(schema).subtype).toEqual(
|
||||||
|
AutoFieldSubTypes.UPDATED_AT
|
||||||
|
)
|
||||||
|
schema.subtype = ""
|
||||||
|
|
||||||
|
schema.name = AutoFieldDefaultNames.AUTO_ID
|
||||||
|
expect(fixAutoColumnSubType(schema).subtype).toEqual(
|
||||||
|
AutoFieldSubTypes.AUTO_ID
|
||||||
|
)
|
||||||
|
schema.subtype = ""
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns the column if subtype exists", async () => {
|
||||||
|
schema.subtype = AutoFieldSubTypes.CREATED_BY
|
||||||
|
schema.name = AutoFieldDefaultNames.CREATED_AT
|
||||||
|
expect(fixAutoColumnSubType(schema)).toEqual(schema)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { enrichPluginURLs } from "../plugins"
|
||||||
|
const env = require("../../environment")
|
||||||
|
jest.mock("../../environment")
|
||||||
|
|
||||||
|
describe("plugins utility", () => {
|
||||||
|
let pluginsArray: any = [
|
||||||
|
{
|
||||||
|
name: "test-plugin",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
it("enriches the plugins url self-hosted", async () => {
|
||||||
|
let result = enrichPluginURLs(pluginsArray)
|
||||||
|
expect(result[0].jsUrl).toEqual("/plugins/test-plugin/plugin.min.js")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("enriches the plugins url cloud", async () => {
|
||||||
|
env.SELF_HOSTED = 0
|
||||||
|
let result = enrichPluginURLs(pluginsArray)
|
||||||
|
expect(result[0].jsUrl).toEqual(
|
||||||
|
"https://cdn.budi.live/test-plugin/plugin.min.js"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
|
@ -19,6 +19,8 @@
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"dist",
|
"dist",
|
||||||
"src/tests",
|
"src/tests",
|
||||||
|
"src/api/routes/tests/utilities",
|
||||||
|
"src/automations/tests/utilities",
|
||||||
"**/*.spec.ts",
|
"**/*.spec.ts",
|
||||||
"**/*.spec.js"
|
"**/*.spec.js"
|
||||||
]
|
]
|
||||||
|
|
|
@ -1273,12 +1273,12 @@
|
||||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||||
|
|
||||||
"@budibase/backend-core@2.1.46-alpha.3":
|
"@budibase/backend-core@2.1.46-alpha.6":
|
||||||
version "2.1.46-alpha.3"
|
version "2.1.46-alpha.6"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.1.46-alpha.3.tgz#f8caf2af9a8d3a16d4c4280f365567581f9b55a2"
|
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.1.46-alpha.6.tgz#eb24abae6e3f6435a01b97978d25a466b672caff"
|
||||||
integrity sha512-osyuJq9db0DeUkaj4uANzo1mMt7SuKO5vSBITemLua0K8T8Z4r2ypE4muktEsfBdPxAH4cclMg/JaYl4RM8bwQ==
|
integrity sha512-oDPhUE1nPoBu74lWQFj+9p8Fxh42CbNiE+PqaIBrcjpgSmg88Ftcr82UHg3YPQSXGBa/7hVvIkyXqVYzhIfG/Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@budibase/types" "2.1.46-alpha.3"
|
"@budibase/types" "2.1.46-alpha.6"
|
||||||
"@shopify/jest-koa-mocks" "5.0.1"
|
"@shopify/jest-koa-mocks" "5.0.1"
|
||||||
"@techpass/passport-openidconnect" "0.3.2"
|
"@techpass/passport-openidconnect" "0.3.2"
|
||||||
aws-sdk "2.1030.0"
|
aws-sdk "2.1030.0"
|
||||||
|
@ -1360,13 +1360,13 @@
|
||||||
svelte-flatpickr "^3.2.3"
|
svelte-flatpickr "^3.2.3"
|
||||||
svelte-portal "^1.0.0"
|
svelte-portal "^1.0.0"
|
||||||
|
|
||||||
"@budibase/pro@2.1.46-alpha.3":
|
"@budibase/pro@2.1.46-alpha.6":
|
||||||
version "2.1.46-alpha.3"
|
version "2.1.46-alpha.6"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.1.46-alpha.3.tgz#88e13775402561f1bd8d20483493a34082a6d8ab"
|
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.1.46-alpha.6.tgz#c81465fe03c1a2dac69308ce5304e423bfbcabf4"
|
||||||
integrity sha512-B3z/Jk4g1ig8Wx62KmjAeYeITePxwrLHnSoy/Ugz6APNfNiXe7Y/ilQ5BFHWB0z/z3/8Vs1sOdP5c3/R5LpqDQ==
|
integrity sha512-76/29biUDsGfOE4nzMHuVyzTpXPXsNOSe1dkbhGvxBVn42CQGIaR17a+0do9XX5I9qn7zhFJmz2B3UYYb9rZ4g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@budibase/backend-core" "2.1.46-alpha.3"
|
"@budibase/backend-core" "2.1.46-alpha.6"
|
||||||
"@budibase/types" "2.1.46-alpha.3"
|
"@budibase/types" "2.1.46-alpha.6"
|
||||||
"@koa/router" "8.0.8"
|
"@koa/router" "8.0.8"
|
||||||
bull "4.10.1"
|
bull "4.10.1"
|
||||||
joi "17.6.0"
|
joi "17.6.0"
|
||||||
|
@ -1390,10 +1390,10 @@
|
||||||
svelte-apexcharts "^1.0.2"
|
svelte-apexcharts "^1.0.2"
|
||||||
svelte-flatpickr "^3.1.0"
|
svelte-flatpickr "^3.1.0"
|
||||||
|
|
||||||
"@budibase/types@2.1.46-alpha.3":
|
"@budibase/types@2.1.46-alpha.6":
|
||||||
version "2.1.46-alpha.3"
|
version "2.1.46-alpha.6"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.46-alpha.3.tgz#ffd96e1f3b006af5f0c0900e927d0454a2e61c53"
|
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.46-alpha.6.tgz#d80f47aa57ffa0685f03f5aaf5477d1e985fc9cf"
|
||||||
integrity sha512-JIO5qH/UYbIays/3dDovltiUEL3a4npXZIMlGgARzPQ5DW7ZB8hfJ5fXPt+BsbMXeaJAEsRbDkx82MDQs4y5Lg==
|
integrity sha512-ol0/j0h5A6ZCQrc+qGkigFcuQ8EsyTLhHEhBynh/TWyTbjbUWPJBGTeY5lYzWD2bqQWnRDXsDP4iNdpbuviZNA==
|
||||||
|
|
||||||
"@bull-board/api@3.7.0":
|
"@bull-board/api@3.7.0":
|
||||||
version "3.7.0"
|
version "3.7.0"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/string-templates",
|
"name": "@budibase/string-templates",
|
||||||
"version": "2.1.46-alpha.3",
|
"version": "2.1.46-alpha.6",
|
||||||
"description": "Handlebars wrapper for Budibase templating.",
|
"description": "Handlebars wrapper for Budibase templating.",
|
||||||
"main": "src/index.cjs",
|
"main": "src/index.cjs",
|
||||||
"module": "dist/bundle.mjs",
|
"module": "dist/bundle.mjs",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/types",
|
"name": "@budibase/types",
|
||||||
"version": "2.1.46-alpha.3",
|
"version": "2.1.46-alpha.6",
|
||||||
"description": "Budibase types",
|
"description": "Budibase types",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
|
|
@ -19,6 +19,8 @@ if (!process.env.CI) {
|
||||||
}
|
}
|
||||||
// add pro sources if they exist
|
// add pro sources if they exist
|
||||||
if (fs.existsSync("../../../budibase-pro")) {
|
if (fs.existsSync("../../../budibase-pro")) {
|
||||||
|
config.moduleNameMapper["@budibase/pro/(.*)"] =
|
||||||
|
"<rootDir>/../../../budibase-pro/packages/pro/$1"
|
||||||
config.moduleNameMapper["@budibase/pro"] =
|
config.moduleNameMapper["@budibase/pro"] =
|
||||||
"<rootDir>/../../../budibase-pro/packages/pro/src"
|
"<rootDir>/../../../budibase-pro/packages/pro/src"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/worker",
|
"name": "@budibase/worker",
|
||||||
"email": "hi@budibase.com",
|
"email": "hi@budibase.com",
|
||||||
"version": "2.1.46-alpha.3",
|
"version": "2.1.46-alpha.6",
|
||||||
"description": "Budibase background service",
|
"description": "Budibase background service",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -36,10 +36,10 @@
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/backend-core": "2.1.46-alpha.3",
|
"@budibase/backend-core": "2.1.46-alpha.6",
|
||||||
"@budibase/pro": "2.1.46-alpha.3",
|
"@budibase/pro": "2.1.46-alpha.6",
|
||||||
"@budibase/string-templates": "2.1.46-alpha.3",
|
"@budibase/string-templates": "2.1.46-alpha.6",
|
||||||
"@budibase/types": "2.1.46-alpha.3",
|
"@budibase/types": "2.1.46-alpha.6",
|
||||||
"@koa/router": "8.0.8",
|
"@koa/router": "8.0.8",
|
||||||
"@sentry/node": "6.17.7",
|
"@sentry/node": "6.17.7",
|
||||||
"@techpass/passport-openidconnect": "0.3.2",
|
"@techpass/passport-openidconnect": "0.3.2",
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { events } from "@budibase/backend-core"
|
||||||
|
import { structures, TestConfiguration, mocks } from "../../../../tests"
|
||||||
|
|
||||||
|
describe("/api/global/groups", () => {
|
||||||
|
const config = new TestConfiguration()
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await config.beforeAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await config.afterAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
mocks.licenses.useGroups()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("create", () => {
|
||||||
|
it("should be able to create a new group", async () => {
|
||||||
|
const group = structures.groups.UserGroup()
|
||||||
|
await config.api.groups.saveGroup(group)
|
||||||
|
expect(events.group.created).toBeCalledTimes(1)
|
||||||
|
expect(events.group.updated).not.toBeCalled()
|
||||||
|
expect(events.group.permissionsEdited).not.toBeCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("update", () => {
|
||||||
|
it("should be able to update a basic group", async () => {
|
||||||
|
const group = structures.groups.UserGroup()
|
||||||
|
let oldGroup = await config.api.groups.saveGroup(group)
|
||||||
|
|
||||||
|
let updatedGroup = {
|
||||||
|
...oldGroup.body,
|
||||||
|
...group,
|
||||||
|
name: "New Name",
|
||||||
|
}
|
||||||
|
await config.api.groups.saveGroup(updatedGroup)
|
||||||
|
|
||||||
|
expect(events.group.updated).toBeCalledTimes(1)
|
||||||
|
expect(events.group.permissionsEdited).not.toBeCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("destroy", () => {
|
||||||
|
it("should be able to delete a basic group", async () => {
|
||||||
|
const group = structures.groups.UserGroup()
|
||||||
|
let oldGroup = await config.api.groups.saveGroup(group)
|
||||||
|
await config.api.groups.deleteGroup(
|
||||||
|
oldGroup.body._id,
|
||||||
|
oldGroup.body._rev
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(events.group.deleted).toBeCalledTimes(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,7 +1,5 @@
|
||||||
import { TestConfiguration } from "../../../../tests"
|
import { TestConfiguration } from "../../../../tests"
|
||||||
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
describe("/api/global/license", () => {
|
describe("/api/global/license", () => {
|
||||||
const config = new TestConfiguration()
|
const config = new TestConfiguration()
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,47 @@
|
||||||
import { TestConfiguration } from "../../../../tests"
|
import { structures, TestConfiguration } from "../../../../tests"
|
||||||
|
import { context, db, permissions, roles } from "@budibase/backend-core"
|
||||||
|
import { Mock } from "jest-mock"
|
||||||
|
|
||||||
// TODO
|
jest.mock("@budibase/backend-core", () => {
|
||||||
|
const core = jest.requireActual("@budibase/backend-core")
|
||||||
|
return {
|
||||||
|
...core,
|
||||||
|
db: {
|
||||||
|
...core.db,
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
...core.context,
|
||||||
|
getAppDB: jest.fn(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const appDb = db.getDB("app_test")
|
||||||
|
const mockAppDB = context.getAppDB as Mock
|
||||||
|
mockAppDB.mockReturnValue(appDb)
|
||||||
|
|
||||||
|
async function addAppMetadata() {
|
||||||
|
await appDb.put({
|
||||||
|
_id: "app_metadata",
|
||||||
|
appId: "app_test",
|
||||||
|
name: "New App",
|
||||||
|
version: "version",
|
||||||
|
url: "url",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
describe("/api/global/roles", () => {
|
describe("/api/global/roles", () => {
|
||||||
const config = new TestConfiguration()
|
const config = new TestConfiguration()
|
||||||
|
const role = new roles.Role(
|
||||||
|
db.generateRoleID("newRole"),
|
||||||
|
roles.BUILTIN_ROLE_IDS.BASIC,
|
||||||
|
permissions.BuiltinPermissionID.READ_ONLY
|
||||||
|
)
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
console.debug(role)
|
||||||
|
appDb.put(role)
|
||||||
|
await addAppMetadata()
|
||||||
await config.beforeAll()
|
await config.beforeAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -18,10 +54,35 @@ describe("/api/global/roles", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("GET /api/global/roles", () => {
|
describe("GET /api/global/roles", () => {
|
||||||
it("retrieves roles", () => {})
|
it("retrieves roles", async () => {
|
||||||
|
const res = await config.api.roles.get()
|
||||||
|
expect(res.body).toBeDefined()
|
||||||
|
expect(res.body["app_test"].roles.length).toEqual(5)
|
||||||
|
expect(res.body["app_test"].roles.map((r: any) => r._id)).toContain(
|
||||||
|
role._id
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("GET /api/global/roles/:appId", () => {})
|
describe("GET api/global/roles/:appId", () => {
|
||||||
|
it("finds a role by appId", async () => {
|
||||||
describe("DELETE /api/global/roles/:appId", () => {})
|
const res = await config.api.roles.find("app_test")
|
||||||
|
expect(res.body).toBeDefined()
|
||||||
|
expect(res.body.name).toEqual("New App")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("DELETE /api/global/roles/:appId", () => {
|
||||||
|
it("removes an app role", async () => {
|
||||||
|
let user = structures.users.user()
|
||||||
|
user.roles = {
|
||||||
|
app_test: "role1",
|
||||||
|
}
|
||||||
|
const userResponse = await config.createUser(user)
|
||||||
|
const res = await config.api.roles.remove("app_test")
|
||||||
|
const updatedUser = await config.api.users.getUser(userResponse._id!)
|
||||||
|
expect(updatedUser.body.roles).not.toHaveProperty("app_test")
|
||||||
|
expect(res.body.message).toEqual("App role removed from all users")
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,17 @@
|
||||||
|
import {
|
||||||
|
addBaseTemplates,
|
||||||
|
EmailTemplates,
|
||||||
|
getTemplates,
|
||||||
|
} from "../../../../constants/templates"
|
||||||
|
import {
|
||||||
|
EmailTemplatePurpose,
|
||||||
|
TemplateMetadata,
|
||||||
|
TemplateMetadataNames,
|
||||||
|
TemplateType,
|
||||||
|
} from "../../../../constants"
|
||||||
import { TestConfiguration } from "../../../../tests"
|
import { TestConfiguration } from "../../../../tests"
|
||||||
|
import { join } from "path"
|
||||||
|
import { readStaticFile } from "../../../../../src/utilities/fileSystem"
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
|
@ -18,18 +31,85 @@ describe("/api/global/template", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("GET /api/global/template/definitions", () => {
|
describe("GET /api/global/template/definitions", () => {
|
||||||
it("retrieves definitions", () => {})
|
describe("retrieves definitions", () => {
|
||||||
|
it("checks description definitions", async () => {
|
||||||
|
let result = await config.api.templates.definitions()
|
||||||
|
|
||||||
|
expect(result.body.info[EmailTemplatePurpose.BASE].description).toEqual(
|
||||||
|
TemplateMetadata[TemplateType.EMAIL][0].description
|
||||||
|
)
|
||||||
|
expect(
|
||||||
|
result.body.info[EmailTemplatePurpose.PASSWORD_RECOVERY].description
|
||||||
|
).toEqual(TemplateMetadata[TemplateType.EMAIL][1].description)
|
||||||
|
expect(
|
||||||
|
result.body.info[EmailTemplatePurpose.WELCOME].description
|
||||||
|
).toEqual(TemplateMetadata[TemplateType.EMAIL][2].description)
|
||||||
|
expect(
|
||||||
|
result.body.info[EmailTemplatePurpose.INVITATION].description
|
||||||
|
).toEqual(TemplateMetadata[TemplateType.EMAIL][3].description)
|
||||||
|
expect(
|
||||||
|
result.body.info[EmailTemplatePurpose.CUSTOM].description
|
||||||
|
).toEqual(TemplateMetadata[TemplateType.EMAIL][4].description)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("POST /api/global/template", () => {})
|
it("checks description bindings", async () => {
|
||||||
|
let result = await config.api.templates.definitions()
|
||||||
|
|
||||||
describe("GET /api/global/template", () => {})
|
expect(result.body.bindings[EmailTemplatePurpose.BASE]).toEqual(
|
||||||
|
TemplateMetadata[TemplateType.EMAIL][0].bindings
|
||||||
describe("GET /api/global/template/:type", () => {})
|
)
|
||||||
|
expect(
|
||||||
describe("GET /api/global/template/:ownerId", () => {})
|
result.body.bindings[EmailTemplatePurpose.PASSWORD_RECOVERY]
|
||||||
|
).toEqual(TemplateMetadata[TemplateType.EMAIL][1].bindings)
|
||||||
describe("GET /api/global/template/:id", () => {})
|
expect(result.body.bindings[EmailTemplatePurpose.WELCOME]).toEqual(
|
||||||
|
TemplateMetadata[TemplateType.EMAIL][2].bindings
|
||||||
describe("DELETE /api/global/template/:id/:rev", () => {})
|
)
|
||||||
|
expect(result.body.bindings[EmailTemplatePurpose.INVITATION]).toEqual(
|
||||||
|
TemplateMetadata[TemplateType.EMAIL][3].bindings
|
||||||
|
)
|
||||||
|
expect(result.body.bindings[EmailTemplatePurpose.CUSTOM]).toEqual(
|
||||||
|
TemplateMetadata[TemplateType.EMAIL][4].bindings
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("POST /api/global/template", () => {
|
||||||
|
it("adds a new template", async () => {
|
||||||
|
let purpose = "base"
|
||||||
|
let contents = "Test contents"
|
||||||
|
let updatedTemplate = {
|
||||||
|
contents: contents,
|
||||||
|
purpose: purpose,
|
||||||
|
type: "email",
|
||||||
|
}
|
||||||
|
await config.api.templates.saveTemplate(updatedTemplate)
|
||||||
|
let res = await config.api.templates.getTemplate()
|
||||||
|
let newTemplate = res.body.find((t: any) => (t.purpose = purpose))
|
||||||
|
expect(newTemplate.contents).toEqual(contents)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("GET /api/global/template", () => {
|
||||||
|
it("fetches templates", async () => {
|
||||||
|
let res = await config.api.templates.getTemplate()
|
||||||
|
expect(
|
||||||
|
res.body.find((t: any) => t.purpose === EmailTemplatePurpose.BASE)
|
||||||
|
).toBeDefined()
|
||||||
|
expect(
|
||||||
|
res.body.find((t: any) => t.purpose === EmailTemplatePurpose.CUSTOM)
|
||||||
|
).toBeDefined()
|
||||||
|
expect(
|
||||||
|
res.body.find((t: any) => t.purpose === EmailTemplatePurpose.INVITATION)
|
||||||
|
).toBeDefined()
|
||||||
|
expect(
|
||||||
|
res.body.find(
|
||||||
|
(t: any) => t.purpose === EmailTemplatePurpose.PASSWORD_RECOVERY
|
||||||
|
)
|
||||||
|
).toBeDefined()
|
||||||
|
expect(
|
||||||
|
res.body.find((t: any) => t.purpose === EmailTemplatePurpose.WELCOME)
|
||||||
|
).toBeDefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -116,7 +116,7 @@ describe("/api/global/users", () => {
|
||||||
|
|
||||||
it("should ignore users existing in other tenants", async () => {
|
it("should ignore users existing in other tenants", async () => {
|
||||||
const user = await config.createUser()
|
const user = await config.createUser()
|
||||||
jest.resetAllMocks()
|
jest.clearAllMocks()
|
||||||
|
|
||||||
await tenancy.doInTenant(TENANT_1, async () => {
|
await tenancy.doInTenant(TENANT_1, async () => {
|
||||||
const response = await config.api.users.bulkCreateUsers([user])
|
const response = await config.api.users.bulkCreateUsers([user])
|
||||||
|
@ -229,7 +229,7 @@ describe("/api/global/users", () => {
|
||||||
|
|
||||||
it("should not be able to create user that exists in other tenant", async () => {
|
it("should not be able to create user that exists in other tenant", async () => {
|
||||||
const user = await config.createUser()
|
const user = await config.createUser()
|
||||||
jest.resetAllMocks()
|
jest.clearAllMocks()
|
||||||
|
|
||||||
await tenancy.doInTenant(TENANT_1, async () => {
|
await tenancy.doInTenant(TENANT_1, async () => {
|
||||||
delete user._id
|
delete user._id
|
||||||
|
|
|
@ -27,6 +27,14 @@ export enum EmailTemplatePurpose {
|
||||||
CUSTOM = "custom",
|
CUSTOM = "custom",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum TemplateMetadataNames {
|
||||||
|
BASE = "Base format",
|
||||||
|
PASSWORD_RECOVERY = "Password recovery",
|
||||||
|
WELCOME = "User welcome",
|
||||||
|
INVITATION = "User invitation",
|
||||||
|
CUSTOM = "Custom",
|
||||||
|
}
|
||||||
|
|
||||||
export enum InternalTemplateBinding {
|
export enum InternalTemplateBinding {
|
||||||
PLATFORM_URL = "platformUrl",
|
PLATFORM_URL = "platformUrl",
|
||||||
COMPANY = "company",
|
COMPANY = "company",
|
||||||
|
@ -93,7 +101,7 @@ export const TemplateBindings = {
|
||||||
export const TemplateMetadata = {
|
export const TemplateMetadata = {
|
||||||
[TemplateType.EMAIL]: [
|
[TemplateType.EMAIL]: [
|
||||||
{
|
{
|
||||||
name: "Base format",
|
name: TemplateMetadataNames.BASE,
|
||||||
description:
|
description:
|
||||||
"This is the base template, all others are based on it. The {{ body }} will be replaced with another email template.",
|
"This is the base template, all others are based on it. The {{ body }} will be replaced with another email template.",
|
||||||
category: "miscellaneous",
|
category: "miscellaneous",
|
||||||
|
@ -110,7 +118,7 @@ export const TemplateMetadata = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Password recovery",
|
name: TemplateMetadataNames.PASSWORD_RECOVERY,
|
||||||
description:
|
description:
|
||||||
"When a user requests a password reset they will receive an email built with this template.",
|
"When a user requests a password reset they will receive an email built with this template.",
|
||||||
category: "user management",
|
category: "user management",
|
||||||
|
@ -129,7 +137,7 @@ export const TemplateMetadata = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "User welcome",
|
name: TemplateMetadataNames.WELCOME,
|
||||||
description:
|
description:
|
||||||
"When a new user is added they will be sent a welcome email using this template.",
|
"When a new user is added they will be sent a welcome email using this template.",
|
||||||
category: "user management",
|
category: "user management",
|
||||||
|
@ -137,7 +145,7 @@ export const TemplateMetadata = {
|
||||||
bindings: [],
|
bindings: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "User invitation",
|
name: TemplateMetadataNames.INVITATION,
|
||||||
description:
|
description:
|
||||||
"When inviting a user via the email on-boarding this template will be used.",
|
"When inviting a user via the email on-boarding this template will be used.",
|
||||||
category: "user management",
|
category: "user management",
|
||||||
|
@ -156,7 +164,7 @@ export const TemplateMetadata = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Custom",
|
name: TemplateMetadataNames.CUSTOM,
|
||||||
description:
|
description:
|
||||||
"A custom template, this is currently used for SMTP email actions in automations.",
|
"A custom template, this is currently used for SMTP email actions in automations.",
|
||||||
category: "automations",
|
category: "automations",
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
import "./mocks"
|
import mocks from "./mocks"
|
||||||
|
|
||||||
|
// init the licensing mock
|
||||||
|
import * as pro from "@budibase/pro"
|
||||||
|
mocks.licenses.init(pro)
|
||||||
|
|
||||||
|
// use unlimited license by default
|
||||||
|
mocks.licenses.useUnlimited()
|
||||||
|
|
||||||
import * as dbConfig from "../db"
|
import * as dbConfig from "../db"
|
||||||
dbConfig.init()
|
dbConfig.init()
|
||||||
import env from "../environment"
|
import env from "../environment"
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { UserGroup } from "@budibase/types"
|
||||||
|
import TestConfiguration from "../TestConfiguration"
|
||||||
|
import { TestAPI } from "./base"
|
||||||
|
|
||||||
|
export class GroupsAPI extends TestAPI {
|
||||||
|
constructor(config: TestConfiguration) {
|
||||||
|
super(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
saveGroup = (group: UserGroup) => {
|
||||||
|
return this.request
|
||||||
|
.post(`/api/global/groups`)
|
||||||
|
.send(group)
|
||||||
|
.set(this.config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteGroup = (id: string, rev: string) => {
|
||||||
|
return this.request
|
||||||
|
.delete(`/api/global/groups/${id}/${rev}`)
|
||||||
|
.set(this.config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,10 @@ import { MigrationAPI } from "./migrations"
|
||||||
import { StatusAPI } from "./status"
|
import { StatusAPI } from "./status"
|
||||||
import { RestoreAPI } from "./restore"
|
import { RestoreAPI } from "./restore"
|
||||||
import { TenantAPI } from "./tenants"
|
import { TenantAPI } from "./tenants"
|
||||||
|
import { GroupsAPI } from "./groups"
|
||||||
|
import { RolesAPI } from "./roles"
|
||||||
|
import { TemplatesAPI } from "./templates"
|
||||||
|
import { LicenseAPI } from "./license"
|
||||||
export default class API {
|
export default class API {
|
||||||
accounts: AccountAPI
|
accounts: AccountAPI
|
||||||
auth: AuthAPI
|
auth: AuthAPI
|
||||||
|
@ -23,6 +26,10 @@ export default class API {
|
||||||
status: StatusAPI
|
status: StatusAPI
|
||||||
restore: RestoreAPI
|
restore: RestoreAPI
|
||||||
tenants: TenantAPI
|
tenants: TenantAPI
|
||||||
|
groups: GroupsAPI
|
||||||
|
roles: RolesAPI
|
||||||
|
templates: TemplatesAPI
|
||||||
|
license: LicenseAPI
|
||||||
|
|
||||||
constructor(config: TestConfiguration) {
|
constructor(config: TestConfiguration) {
|
||||||
this.accounts = new AccountAPI(config)
|
this.accounts = new AccountAPI(config)
|
||||||
|
@ -36,5 +43,9 @@ export default class API {
|
||||||
this.status = new StatusAPI(config)
|
this.status = new StatusAPI(config)
|
||||||
this.restore = new RestoreAPI(config)
|
this.restore = new RestoreAPI(config)
|
||||||
this.tenants = new TenantAPI(config)
|
this.tenants = new TenantAPI(config)
|
||||||
|
this.groups = new GroupsAPI(config)
|
||||||
|
this.roles = new RolesAPI(config)
|
||||||
|
this.templates = new TemplatesAPI(config)
|
||||||
|
this.license = new LicenseAPI(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import TestConfiguration from "../TestConfiguration"
|
||||||
|
import { TestAPI } from "./base"
|
||||||
|
|
||||||
|
export class LicenseAPI extends TestAPI {
|
||||||
|
constructor(config: TestConfiguration) {
|
||||||
|
super(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
activate = async (licenseKey: string) => {
|
||||||
|
return this.request
|
||||||
|
.post("/api/global/license/activate")
|
||||||
|
.send({ licenseKey: licenseKey })
|
||||||
|
.set(this.config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import TestConfiguration from "../TestConfiguration"
|
||||||
|
import { TestAPI, TestAPIOpts } from "./base"
|
||||||
|
|
||||||
|
export class RolesAPI extends TestAPI {
|
||||||
|
constructor(config: TestConfiguration) {
|
||||||
|
super(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
get = (opts?: TestAPIOpts) => {
|
||||||
|
return this.request
|
||||||
|
.get(`/api/global/roles`)
|
||||||
|
.set(this.config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(opts?.status ? opts.status : 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
find = (appId: string, opts?: TestAPIOpts) => {
|
||||||
|
return this.request
|
||||||
|
.get(`/api/global/roles/${appId}`)
|
||||||
|
.set(this.config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(opts?.status ? opts.status : 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
remove = (appId: string, opts?: TestAPIOpts) => {
|
||||||
|
return this.request
|
||||||
|
.delete(`/api/global/roles/${appId}`)
|
||||||
|
.set(this.config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(opts?.status ? opts.status : 200)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
import TestConfiguration from "../TestConfiguration"
|
||||||
|
import { TestAPI, TestAPIOpts } from "./base"
|
||||||
|
|
||||||
|
export class TemplatesAPI extends TestAPI {
|
||||||
|
constructor(config: TestConfiguration) {
|
||||||
|
super(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
definitions = (opts?: TestAPIOpts) => {
|
||||||
|
return this.request
|
||||||
|
.get(`/api/global/template/definitions`)
|
||||||
|
.set(opts?.headers ? opts.headers : this.config.defaultHeaders())
|
||||||
|
.expect(opts?.status ? opts.status : 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
getTemplate = (opts?: TestAPIOpts) => {
|
||||||
|
return this.request
|
||||||
|
.get(`/api/global/template`)
|
||||||
|
.set(opts?.headers ? opts.headers : this.config.defaultHeaders())
|
||||||
|
.expect(opts?.status ? opts.status : 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
saveTemplate = (data: any, opts?: TestAPIOpts) => {
|
||||||
|
return this.request
|
||||||
|
.post(`/api/global/template`)
|
||||||
|
.send(data)
|
||||||
|
.set(opts?.headers ? opts.headers : this.config.defaultHeaders())
|
||||||
|
.expect(opts?.status ? opts.status : 200)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
const email = require("./email")
|
const email = require("./email")
|
||||||
import { mocks as coreMocks } from "@budibase/backend-core/tests"
|
import { mocks } from "@budibase/backend-core/tests"
|
||||||
|
|
||||||
export = {
|
export = {
|
||||||
email,
|
email,
|
||||||
...coreMocks,
|
...mocks,
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ export const UserGroup = () => {
|
||||||
color: "var(--spectrum-global-color-blue-600)",
|
color: "var(--spectrum-global-color-blue-600)",
|
||||||
icon: "UserGroup",
|
icon: "UserGroup",
|
||||||
name: "New group",
|
name: "New group",
|
||||||
roles: {},
|
roles: { app_uuid1: "ADMIN", app_uuid2: "POWER" },
|
||||||
users: [],
|
users: [],
|
||||||
}
|
}
|
||||||
return group
|
return group
|
||||||
|
|
|
@ -10,7 +10,7 @@ export const user = (userProps?: any): User => {
|
||||||
return {
|
return {
|
||||||
email: newEmail(),
|
email: newEmail(),
|
||||||
password: "test",
|
password: "test",
|
||||||
roles: {},
|
roles: { app_test: "admin" },
|
||||||
...userProps,
|
...userProps,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
"package.json"
|
"package.json"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
|
||||||
"dist"
|
"dist"
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -470,12 +470,12 @@
|
||||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||||
|
|
||||||
"@budibase/backend-core@2.1.46-alpha.3":
|
"@budibase/backend-core@2.1.46-alpha.6":
|
||||||
version "2.1.46-alpha.3"
|
version "2.1.46-alpha.6"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.1.46-alpha.3.tgz#f8caf2af9a8d3a16d4c4280f365567581f9b55a2"
|
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.1.46-alpha.6.tgz#eb24abae6e3f6435a01b97978d25a466b672caff"
|
||||||
integrity sha512-osyuJq9db0DeUkaj4uANzo1mMt7SuKO5vSBITemLua0K8T8Z4r2ypE4muktEsfBdPxAH4cclMg/JaYl4RM8bwQ==
|
integrity sha512-oDPhUE1nPoBu74lWQFj+9p8Fxh42CbNiE+PqaIBrcjpgSmg88Ftcr82UHg3YPQSXGBa/7hVvIkyXqVYzhIfG/Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@budibase/types" "2.1.46-alpha.3"
|
"@budibase/types" "2.1.46-alpha.6"
|
||||||
"@shopify/jest-koa-mocks" "5.0.1"
|
"@shopify/jest-koa-mocks" "5.0.1"
|
||||||
"@techpass/passport-openidconnect" "0.3.2"
|
"@techpass/passport-openidconnect" "0.3.2"
|
||||||
aws-sdk "2.1030.0"
|
aws-sdk "2.1030.0"
|
||||||
|
@ -507,22 +507,22 @@
|
||||||
uuid "8.3.2"
|
uuid "8.3.2"
|
||||||
zlib "1.0.5"
|
zlib "1.0.5"
|
||||||
|
|
||||||
"@budibase/pro@2.1.46-alpha.3":
|
"@budibase/pro@2.1.46-alpha.6":
|
||||||
version "2.1.46-alpha.3"
|
version "2.1.46-alpha.6"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.1.46-alpha.3.tgz#88e13775402561f1bd8d20483493a34082a6d8ab"
|
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.1.46-alpha.6.tgz#c81465fe03c1a2dac69308ce5304e423bfbcabf4"
|
||||||
integrity sha512-B3z/Jk4g1ig8Wx62KmjAeYeITePxwrLHnSoy/Ugz6APNfNiXe7Y/ilQ5BFHWB0z/z3/8Vs1sOdP5c3/R5LpqDQ==
|
integrity sha512-76/29biUDsGfOE4nzMHuVyzTpXPXsNOSe1dkbhGvxBVn42CQGIaR17a+0do9XX5I9qn7zhFJmz2B3UYYb9rZ4g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@budibase/backend-core" "2.1.46-alpha.3"
|
"@budibase/backend-core" "2.1.46-alpha.6"
|
||||||
"@budibase/types" "2.1.46-alpha.3"
|
"@budibase/types" "2.1.46-alpha.6"
|
||||||
"@koa/router" "8.0.8"
|
"@koa/router" "8.0.8"
|
||||||
bull "4.10.1"
|
bull "4.10.1"
|
||||||
joi "17.6.0"
|
joi "17.6.0"
|
||||||
node-fetch "^2.6.1"
|
node-fetch "^2.6.1"
|
||||||
|
|
||||||
"@budibase/types@2.1.46-alpha.3":
|
"@budibase/types@2.1.46-alpha.6":
|
||||||
version "2.1.46-alpha.3"
|
version "2.1.46-alpha.6"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.46-alpha.3.tgz#ffd96e1f3b006af5f0c0900e927d0454a2e61c53"
|
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.46-alpha.6.tgz#d80f47aa57ffa0685f03f5aaf5477d1e985fc9cf"
|
||||||
integrity sha512-JIO5qH/UYbIays/3dDovltiUEL3a4npXZIMlGgARzPQ5DW7ZB8hfJ5fXPt+BsbMXeaJAEsRbDkx82MDQs4y5Lg==
|
integrity sha512-ol0/j0h5A6ZCQrc+qGkigFcuQ8EsyTLhHEhBynh/TWyTbjbUWPJBGTeY5lYzWD2bqQWnRDXsDP4iNdpbuviZNA==
|
||||||
|
|
||||||
"@cspotcode/source-map-support@^0.8.0":
|
"@cspotcode/source-map-support@^0.8.0":
|
||||||
version "0.8.1"
|
version "0.8.1"
|
||||||
|
|
|
@ -1,25 +1,30 @@
|
||||||
echo "Linking backend-core"
|
echo "Linking backend-core"
|
||||||
cd packages/backend-core
|
cd packages/backend-core
|
||||||
|
yarn unlink
|
||||||
yarn link
|
yarn link
|
||||||
cd -
|
cd -
|
||||||
|
|
||||||
echo "Linking string-templates"
|
echo "Linking string-templates"
|
||||||
cd packages/string-templates
|
cd packages/string-templates
|
||||||
|
yarn unlink
|
||||||
yarn link
|
yarn link
|
||||||
cd -
|
cd -
|
||||||
|
|
||||||
echo "Linking types"
|
echo "Linking types"
|
||||||
cd packages/types
|
cd packages/types
|
||||||
|
yarn unlink
|
||||||
yarn link
|
yarn link
|
||||||
cd -
|
cd -
|
||||||
|
|
||||||
echo "Linking bbui"
|
echo "Linking bbui"
|
||||||
cd packages/bbui
|
cd packages/bbui
|
||||||
|
yarn unlink
|
||||||
yarn link
|
yarn link
|
||||||
cd -
|
cd -
|
||||||
|
|
||||||
echo "Linking frontend-core"
|
echo "Linking frontend-core"
|
||||||
cd packages/frontend-core
|
cd packages/frontend-core
|
||||||
|
yarn unlink
|
||||||
yarn link
|
yarn link
|
||||||
cd -
|
cd -
|
||||||
|
|
||||||
|
@ -30,6 +35,7 @@ if [ -d "../budibase-pro" ]; then
|
||||||
|
|
||||||
cd packages/pro
|
cd packages/pro
|
||||||
echo "Linking pro"
|
echo "Linking pro"
|
||||||
|
yarn unlink
|
||||||
yarn link
|
yarn link
|
||||||
|
|
||||||
echo "Linking backend-core to pro"
|
echo "Linking backend-core to pro"
|
||||||
|
|
Loading…
Reference in New Issue