QA Core repo, and Jest API tests running end to end
This commit is contained in:
parent
30bbb5e0d8
commit
2a6c9cd6c5
|
@ -54,8 +54,10 @@ jobs:
|
||||||
verbose: true
|
verbose: true
|
||||||
|
|
||||||
# TODO: parallelise this
|
# TODO: parallelise this
|
||||||
- name: Cypress run
|
# - name: Cypress run
|
||||||
uses: cypress-io/github-action@v2
|
# uses: cypress-io/github-action@v2
|
||||||
with:
|
# with:
|
||||||
install: false
|
# install: false
|
||||||
command: yarn test:e2e:ci
|
# command: yarn test:e2e:ci
|
||||||
|
|
||||||
|
- run: yarn test:api:ci
|
|
@ -8,4 +8,4 @@ packages/server/client
|
||||||
packages/server/src/definitions/openapi.ts
|
packages/server/src/definitions/openapi.ts
|
||||||
packages/builder/.routify
|
packages/builder/.routify
|
||||||
packages/builder/cypress/support/queryLevelTransformerFunction.js
|
packages/builder/cypress/support/queryLevelTransformerFunction.js
|
||||||
packages/builder/cypress/support/queryLevelTransformerFunctionWithData.js
|
packages/builder/cypress/support/queryLevelTransformerFunctionWithData.js
|
|
@ -52,6 +52,8 @@
|
||||||
"test:e2e:ci": "lerna run cy:ci --stream",
|
"test:e2e:ci": "lerna run cy:ci --stream",
|
||||||
"test:e2e:ci:record": "lerna run cy:ci:record --stream",
|
"test:e2e:ci:record": "lerna run cy:ci:record --stream",
|
||||||
"test:e2e:ci:notify": "lerna run cy:ci:notify",
|
"test:e2e:ci:notify": "lerna run cy:ci:notify",
|
||||||
|
"test:api:ci": "npm --prefix ./qa-core run api:test:ci",
|
||||||
|
"test:api": "npm --prefix ./qa-core run api:test",
|
||||||
"build:specs": "lerna run specs",
|
"build:specs": "lerna run specs",
|
||||||
"build:docker": "lerna run build:docker && npm run build:docker:proxy:compose && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh $BUDIBASE_RELEASE_VERSION && cd -",
|
"build:docker": "lerna run build:docker && npm run build:docker:proxy:compose && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh $BUDIBASE_RELEASE_VERSION && cd -",
|
||||||
"build:docker:pre": "lerna run build && lerna run predocker",
|
"build:docker:pre": "lerna run build && lerna run predocker",
|
||||||
|
|
|
@ -22,6 +22,12 @@ process.env.COUCH_DB_PASSWORD = "budibase"
|
||||||
process.env.INTERNAL_API_KEY = "budibase"
|
process.env.INTERNAL_API_KEY = "budibase"
|
||||||
process.env.ALLOW_DEV_AUTOMATIONS = 1
|
process.env.ALLOW_DEV_AUTOMATIONS = 1
|
||||||
|
|
||||||
|
// TODO: inject at the qa-core level
|
||||||
|
process.env.BB_ADMIN_USER_EMAIL = "qa@budibase.com"
|
||||||
|
process.env.BB_ADMIN_USER_PASSWORD = "budibase"
|
||||||
|
process.env.ENCRYPTED_TEST_PUBLIC_API_KEY =
|
||||||
|
"a65722f06bee5caeadc5d7ca2f543a43-d610e627344210c643bb726f"
|
||||||
|
|
||||||
// Stop info logs polluting test outputs
|
// Stop info logs polluting test outputs
|
||||||
process.env.LOG_LEVEL = "error"
|
process.env.LOG_LEVEL = "error"
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ describe("/users", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("fetch", () => {
|
describe("fetch", () => {
|
||||||
|
|
||||||
it("returns a list of users from an instance db", async () => {
|
it("returns a list of users from an instance db", async () => {
|
||||||
await config.createUser("uuidx")
|
await config.createUser("uuidx")
|
||||||
await config.createUser("uuidy")
|
await config.createUser("uuidy")
|
||||||
|
|
|
@ -29,7 +29,11 @@ const { Thread } = require("./threads")
|
||||||
import redis from "./utilities/redis"
|
import redis from "./utilities/redis"
|
||||||
import * as migrations from "./migrations"
|
import * as migrations from "./migrations"
|
||||||
import { events, installation, tenancy } from "@budibase/backend-core"
|
import { events, installation, tenancy } from "@budibase/backend-core"
|
||||||
import { createAdminUser, getChecklist } from "./utilities/workerRequests"
|
import {
|
||||||
|
createAdminUser,
|
||||||
|
generateApiKey,
|
||||||
|
getChecklist,
|
||||||
|
} from "./utilities/workerRequests"
|
||||||
|
|
||||||
const app = new Koa()
|
const app = new Koa()
|
||||||
|
|
||||||
|
@ -123,11 +127,16 @@ module.exports = server.listen(env.PORT || 0, async () => {
|
||||||
if (!checklist?.adminUser?.checked) {
|
if (!checklist?.adminUser?.checked) {
|
||||||
try {
|
try {
|
||||||
const tenantId = tenancy.getTenantId()
|
const tenantId = tenancy.getTenantId()
|
||||||
await createAdminUser(
|
const user = await createAdminUser(
|
||||||
env.BB_ADMIN_USER_EMAIL,
|
env.BB_ADMIN_USER_EMAIL,
|
||||||
env.BB_ADMIN_USER_PASSWORD,
|
env.BB_ADMIN_USER_PASSWORD,
|
||||||
tenantId
|
tenantId
|
||||||
)
|
)
|
||||||
|
// Need to set up an API key for automated integration tests
|
||||||
|
if (env.isTest()) {
|
||||||
|
await generateApiKey(user._id)
|
||||||
|
}
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
"Admin account automatically created for",
|
"Admin account automatically created for",
|
||||||
env.BB_ADMIN_USER_EMAIL
|
env.BB_ADMIN_USER_EMAIL
|
||||||
|
|
|
@ -153,3 +153,11 @@ exports.getChecklist = async () => {
|
||||||
)
|
)
|
||||||
return checkResponse(response, "get checklist")
|
return checkResponse(response, "get checklist")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.generateApiKey = async userId => {
|
||||||
|
const response = await fetch(
|
||||||
|
checkSlashesInUrl(env.WORKER_URL + "/api/global/self/api_key"),
|
||||||
|
request(null, { method: "POST", body: { userId } })
|
||||||
|
)
|
||||||
|
return checkResponse(response, "generate API key")
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,11 @@ const { newid } = require("@budibase/backend-core/utils")
|
||||||
const { users } = require("../../../sdk")
|
const { users } = require("../../../sdk")
|
||||||
const { Cookies } = require("@budibase/backend-core/constants")
|
const { Cookies } = require("@budibase/backend-core/constants")
|
||||||
const { events, featureFlags } = require("@budibase/backend-core")
|
const { events, featureFlags } = require("@budibase/backend-core")
|
||||||
|
const env = require("../../../environment")
|
||||||
|
|
||||||
|
function newTestApiKey() {
|
||||||
|
return env.ENCRYPTED_TEST_PUBLIC_API_KEY
|
||||||
|
}
|
||||||
|
|
||||||
function newApiKey() {
|
function newApiKey() {
|
||||||
return encrypt(`${getTenantId()}${SEPARATOR}${newid()}`)
|
return encrypt(`${getTenantId()}${SEPARATOR}${newid()}`)
|
||||||
|
@ -29,15 +34,25 @@ function cleanupDevInfo(info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.generateAPIKey = async ctx => {
|
exports.generateAPIKey = async ctx => {
|
||||||
|
let userId
|
||||||
|
let apiKey
|
||||||
|
if (env.isTest() && ctx.request.body.userId) {
|
||||||
|
userId = ctx.request.body.userId
|
||||||
|
apiKey = newTestApiKey()
|
||||||
|
} else {
|
||||||
|
userId = ctx.user._id
|
||||||
|
apiKey = newApiKey()
|
||||||
|
}
|
||||||
|
|
||||||
const db = getGlobalDB()
|
const db = getGlobalDB()
|
||||||
const id = generateDevInfoID(ctx.user._id)
|
const id = generateDevInfoID(userId)
|
||||||
let devInfo
|
let devInfo
|
||||||
try {
|
try {
|
||||||
devInfo = await db.get(id)
|
devInfo = await db.get(id)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
devInfo = { _id: id, userId: ctx.user._id }
|
devInfo = { _id: id, userId }
|
||||||
}
|
}
|
||||||
devInfo.apiKey = await newApiKey()
|
devInfo.apiKey = await apiKey
|
||||||
await db.put(devInfo)
|
await db.put(devInfo)
|
||||||
ctx.body = cleanupDevInfo(devInfo)
|
ctx.body = cleanupDevInfo(devInfo)
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ const env = {
|
||||||
// other
|
// other
|
||||||
CHECKLIST_CACHE_TTL: parseIntSafe(process.env.CHECKLIST_CACHE_TTL) || 3600,
|
CHECKLIST_CACHE_TTL: parseIntSafe(process.env.CHECKLIST_CACHE_TTL) || 3600,
|
||||||
SESSION_UPDATE_PERIOD: process.env.SESSION_UPDATE_PERIOD,
|
SESSION_UPDATE_PERIOD: process.env.SESSION_UPDATE_PERIOD,
|
||||||
|
ENCRYPTED_TEST_PUBLIC_API_KEY: process.env.ENCRYPTED_TEST_PUBLIC_API_KEY,
|
||||||
_set(key: any, value: any) {
|
_set(key: any, value: any) {
|
||||||
process.env[key] = value
|
process.env[key] = value
|
||||||
module.exports[key] = value
|
module.exports[key] = value
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
node_modules/
|
||||||
|
.env
|
||||||
|
watchtower-hook.json
|
||||||
|
dist/
|
|
@ -0,0 +1,52 @@
|
||||||
|
{
|
||||||
|
"name": "@budibase/qa-core",
|
||||||
|
"email": "hi@budibase.com",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"main": "index.js",
|
||||||
|
"description": "Budibase Integration Test Suite",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Budibase/budibase.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "jest --runInBand",
|
||||||
|
"test:watch": "jest --watch",
|
||||||
|
"test:debug": "DEBUG=1 jest",
|
||||||
|
"api:server:setup": "ts-node ../packages/builder/cypress/ts/setup.ts",
|
||||||
|
"api:server:setup:ci": "node ../packages/builder/cypress/setup.js",
|
||||||
|
"api:test:ci": "start-server-and-test api:server:setup:ci http://localhost:4100/builder test",
|
||||||
|
"api:test": "start-server-and-test api:server:setup http://localhost:4100/builder test"
|
||||||
|
},
|
||||||
|
"jest": {
|
||||||
|
"preset": "ts-jest",
|
||||||
|
"testEnvironment": "node",
|
||||||
|
"moduleNameMapper": {
|
||||||
|
"@budibase/backend-core/(.*)": "<rootDir>/../packages/backend-core/$1",
|
||||||
|
"@budibase/backend-core": "<rootDir>/../packages/backend-core/src",
|
||||||
|
"@budibase/types": "<rootDir>/../packages/types/src"
|
||||||
|
},
|
||||||
|
"setupFiles": [
|
||||||
|
"./scripts/jestSetup.js"
|
||||||
|
],
|
||||||
|
"setupFilesAfterEnv": [
|
||||||
|
"./src/jest.extends.ts"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@budibase/types": "^1.3.4",
|
||||||
|
"@types/jest": "^29.0.0",
|
||||||
|
"@types/node-fetch": "^2.6.2",
|
||||||
|
"chance": "^1.1.8",
|
||||||
|
"jest": "^28.0.2",
|
||||||
|
"prettier": "^2.7.1",
|
||||||
|
"start-server-and-test": "^1.14.0",
|
||||||
|
"timekeeper": "^2.2.0",
|
||||||
|
"ts-jest": "28.0.8",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
|
"tsconfig-paths": "^4.1.0",
|
||||||
|
"typescript": "^4.8.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"node-fetch": "2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
const env = require("../src/environment")
|
||||||
|
|
||||||
|
env._set("BUDIBASE_SERVER_URL", "http://localhost:4100")
|
||||||
|
env._set("BUDIBASE_PUBLIC_API_KEY", "a65722f06bee5caeadc5d7ca2f543a43-d610e627344210c643bb726f")
|
||||||
|
|
||||||
|
// mock all dates to 2020-01-01T00:00:00.000Z
|
||||||
|
// use tk.reset() to use real dates in individual tests
|
||||||
|
const MOCK_DATE = new Date("2020-01-01T00:00:00.000Z")
|
||||||
|
const MOCK_DATE_TIMESTAMP = 1577836800000
|
||||||
|
const tk = require("timekeeper")
|
||||||
|
tk.freeze(MOCK_DATE)
|
||||||
|
|
||||||
|
if (!process.env.DEBUG) {
|
||||||
|
global.console.log = jest.fn() // console.log are ignored in tests
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
export = {
|
||||||
|
BUDIBASE_SERVER_URL: process.env.BUDIBASE_SERVER_URL,
|
||||||
|
BUDIBASE_PUBLIC_API_KEY: process.env.BUDIBASE_PUBLIC_API_KEY,
|
||||||
|
_set(key: any, value: any) {
|
||||||
|
process.env[key] = value
|
||||||
|
module.exports[key] = value
|
||||||
|
},
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
// boilerplate to allow TS updates to the global scope
|
||||||
|
export {};
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace jest {
|
||||||
|
interface Matchers<R> {
|
||||||
|
toHaveStatusCode(code: number): R;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expect extensions
|
||||||
|
expect.extend({
|
||||||
|
toHaveStatusCode(received, code) {
|
||||||
|
const pass = received.status === code
|
||||||
|
return {
|
||||||
|
message: () =>
|
||||||
|
`expected ${received.status} to match status code ${code}`,
|
||||||
|
pass,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
|
@ -0,0 +1,58 @@
|
||||||
|
import env from "../../environment"
|
||||||
|
import fetch from "node-fetch"
|
||||||
|
|
||||||
|
interface HeaderOptions {
|
||||||
|
headers?: object;
|
||||||
|
body?: object;
|
||||||
|
json?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type APIMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE"
|
||||||
|
|
||||||
|
class PublicAPIClient {
|
||||||
|
host: string
|
||||||
|
apiKey: string
|
||||||
|
appId?: string
|
||||||
|
|
||||||
|
constructor(appId?: string) {
|
||||||
|
if (!env.BUDIBASE_PUBLIC_API_KEY || !env.BUDIBASE_SERVER_URL) {
|
||||||
|
throw new Error("Must set BUDIBASE_PUBLIC_API_KEY and BUDIBASE_SERVER_URL env vars")
|
||||||
|
}
|
||||||
|
this.host = `${env.BUDIBASE_SERVER_URL}/api/public/v1`
|
||||||
|
this.apiKey = env.BUDIBASE_PUBLIC_API_KEY
|
||||||
|
this.appId = appId
|
||||||
|
}
|
||||||
|
|
||||||
|
apiCall =
|
||||||
|
(method: APIMethod) =>
|
||||||
|
async (url = "", options: HeaderOptions = {}) => {
|
||||||
|
const requestOptions = {
|
||||||
|
method: method,
|
||||||
|
body: JSON.stringify(options.body),
|
||||||
|
headers: {
|
||||||
|
"x-budibase-api-key": this.apiKey,
|
||||||
|
"x-budibase-app-id": this.appId,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
...options.headers,
|
||||||
|
},
|
||||||
|
// TODO: See if this is necessary
|
||||||
|
credentials: "include",
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const response = await fetch(`${this.host}${url}`, requestOptions)
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.error(response)
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
post = this.apiCall("POST")
|
||||||
|
get = this.apiCall("GET")
|
||||||
|
patch = this.apiCall("PATCH")
|
||||||
|
del = this.apiCall("DELETE")
|
||||||
|
put = this.apiCall("PUT")
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PublicAPIClient
|
|
@ -0,0 +1,39 @@
|
||||||
|
import PublicAPIClient from "./PublicAPIClient";
|
||||||
|
import generateApp from "./applications/fixtures/generate"
|
||||||
|
|
||||||
|
class TestConfiguration {
|
||||||
|
testContext: Record<string, any>;
|
||||||
|
apiClient: PublicAPIClient;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.testContext = {}
|
||||||
|
this.apiClient = new PublicAPIClient()
|
||||||
|
}
|
||||||
|
|
||||||
|
async beforeAll() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async afterAll() {
|
||||||
|
}
|
||||||
|
|
||||||
|
async seedTable(appId: string) {
|
||||||
|
const response = await this.apiClient.post("/tables", {
|
||||||
|
body: require("./tables/fixtures/seed.json"),
|
||||||
|
headers: {
|
||||||
|
"x-budibase-app-id": appId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const json = await response.json()
|
||||||
|
return json.data
|
||||||
|
}
|
||||||
|
|
||||||
|
async seedApp() {
|
||||||
|
const response = await this.apiClient.post("/applications", {
|
||||||
|
body: generateApp()
|
||||||
|
})
|
||||||
|
return response.json()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TestConfiguration
|
|
@ -0,0 +1,47 @@
|
||||||
|
import TestConfiguration from "../TestConfiguration"
|
||||||
|
import PublicAPIClient from "../PublicAPIClient"
|
||||||
|
import generateApp from "./fixtures/generate"
|
||||||
|
|
||||||
|
describe("Public API - /applications endpoints", () => {
|
||||||
|
const api = new PublicAPIClient()
|
||||||
|
const config = new TestConfiguration()
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await config.beforeAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await config.afterAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("POST - Create a application", async () => {
|
||||||
|
const response = await api.post(`/applications`, {
|
||||||
|
body: generateApp()
|
||||||
|
})
|
||||||
|
const json = await response.json()
|
||||||
|
config.testContext.application = json.data
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("POST - Search applications", async () => {
|
||||||
|
const response = await api.post(`/applications/search`, {
|
||||||
|
body: {
|
||||||
|
name: config.testContext.application.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("GET - Retrieve a application", async () => {
|
||||||
|
const response = await api.get(`/applications/${config.testContext.application._id}`)
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it("PUT - update a application", async () => {
|
||||||
|
const response = await api.put(`/applications/${config.testContext.application._id}`, {
|
||||||
|
body: require("./fixtures/update_application.json")
|
||||||
|
})
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "TestApp",
|
||||||
|
"url": "/testapp"
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import generator from "../../generator"
|
||||||
|
|
||||||
|
const generate = (overrides = {}) => ({
|
||||||
|
name: generator.word(),
|
||||||
|
url: `/${generator.word()}`,
|
||||||
|
...overrides
|
||||||
|
})
|
||||||
|
|
||||||
|
export default generate
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "SeedApp",
|
||||||
|
"url": "/seedapp"
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "UpdatedTestApp",
|
||||||
|
"url": "/updatedtestapp"
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
const Chance = require("chance")
|
||||||
|
|
||||||
|
export default new Chance()
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"type": "row",
|
||||||
|
"tableId": "seed_table",
|
||||||
|
"sasa": "Mike",
|
||||||
|
"relationship": [
|
||||||
|
"ro_ta_"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"name": "test",
|
||||||
|
"primaryDisplay": "sasa",
|
||||||
|
"schema": {
|
||||||
|
"Auto ID": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"numericality": {
|
||||||
|
"greaterThanOrEqualTo": "",
|
||||||
|
"lessThanOrEqualTo": ""
|
||||||
|
},
|
||||||
|
"presence": false,
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Auto ID",
|
||||||
|
"subtype": "autoID",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"Created At": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"datetime": {
|
||||||
|
"earliest": "",
|
||||||
|
"latest": ""
|
||||||
|
},
|
||||||
|
"length": {},
|
||||||
|
"presence": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Created At",
|
||||||
|
"subtype": "createdAt",
|
||||||
|
"type": "datetime"
|
||||||
|
},
|
||||||
|
"Created By": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"presence": false,
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"fieldName": "test12-Created By",
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Created By",
|
||||||
|
"relationshipType": "many-to-many",
|
||||||
|
"subtype": "createdBy",
|
||||||
|
"tableId": "ta_users",
|
||||||
|
"type": "link"
|
||||||
|
},
|
||||||
|
"sasa": {
|
||||||
|
"constraints": {
|
||||||
|
"length": {
|
||||||
|
"maximum": null
|
||||||
|
},
|
||||||
|
"presence": {
|
||||||
|
"allowEmpty": false
|
||||||
|
},
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": "sasa",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Updated At": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"datetime": {
|
||||||
|
"earliest": "",
|
||||||
|
"latest": ""
|
||||||
|
},
|
||||||
|
"length": {},
|
||||||
|
"presence": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Updated At",
|
||||||
|
"subtype": "updatedAt",
|
||||||
|
"type": "datetime"
|
||||||
|
},
|
||||||
|
"Updated By": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"presence": false,
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"fieldName": "test12-Updated By",
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Updated By",
|
||||||
|
"relationshipType": "many-to-many",
|
||||||
|
"subtype": "updatedBy",
|
||||||
|
"tableId": "ta_users",
|
||||||
|
"type": "link"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"name": "test",
|
||||||
|
"primaryDisplay": "sasa",
|
||||||
|
"schema": {
|
||||||
|
"Auto ID": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"numericality": {
|
||||||
|
"greaterThanOrEqualTo": "",
|
||||||
|
"lessThanOrEqualTo": ""
|
||||||
|
},
|
||||||
|
"presence": false,
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Auto ID",
|
||||||
|
"subtype": "autoID",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"Created At": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"datetime": {
|
||||||
|
"earliest": "",
|
||||||
|
"latest": ""
|
||||||
|
},
|
||||||
|
"length": {},
|
||||||
|
"presence": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Created At",
|
||||||
|
"subtype": "createdAt",
|
||||||
|
"type": "datetime"
|
||||||
|
},
|
||||||
|
"Created By": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"presence": false,
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"fieldName": "test12-Created By",
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Created By",
|
||||||
|
"relationshipType": "many-to-many",
|
||||||
|
"subtype": "createdBy",
|
||||||
|
"tableId": "ta_users",
|
||||||
|
"type": "link"
|
||||||
|
},
|
||||||
|
"sasa": {
|
||||||
|
"constraints": {
|
||||||
|
"length": {
|
||||||
|
"maximum": null
|
||||||
|
},
|
||||||
|
"presence": {
|
||||||
|
"allowEmpty": false
|
||||||
|
},
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": "sasa",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Updated At": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"datetime": {
|
||||||
|
"earliest": "",
|
||||||
|
"latest": ""
|
||||||
|
},
|
||||||
|
"length": {},
|
||||||
|
"presence": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Updated At",
|
||||||
|
"subtype": "updatedAt",
|
||||||
|
"type": "datetime"
|
||||||
|
},
|
||||||
|
"Updated By": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"presence": false,
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"fieldName": "test12-Updated By",
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Updated By",
|
||||||
|
"relationshipType": "many-to-many",
|
||||||
|
"subtype": "updatedBy",
|
||||||
|
"tableId": "ta_users",
|
||||||
|
"type": "link"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"type": "row",
|
||||||
|
"tableId": "seed_table",
|
||||||
|
"sasa": "MikeIsTheBest",
|
||||||
|
"relationship": [
|
||||||
|
"ro_ta_..."
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"name": "test123",
|
||||||
|
"primaryDisplay": "sasa",
|
||||||
|
"schema": {
|
||||||
|
"Auto ID": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"numericality": {
|
||||||
|
"greaterThanOrEqualTo": "",
|
||||||
|
"lessThanOrEqualTo": ""
|
||||||
|
},
|
||||||
|
"presence": false,
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Auto ID",
|
||||||
|
"subtype": "autoID",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"Created At": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"datetime": {
|
||||||
|
"earliest": "",
|
||||||
|
"latest": ""
|
||||||
|
},
|
||||||
|
"length": {},
|
||||||
|
"presence": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Created At",
|
||||||
|
"subtype": "createdAt",
|
||||||
|
"type": "datetime"
|
||||||
|
},
|
||||||
|
"Created By": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"presence": false,
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"fieldName": "test12-Created By",
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Created By",
|
||||||
|
"relationshipType": "many-to-many",
|
||||||
|
"subtype": "createdBy",
|
||||||
|
"tableId": "ta_users",
|
||||||
|
"type": "link"
|
||||||
|
},
|
||||||
|
"sasa": {
|
||||||
|
"constraints": {
|
||||||
|
"length": {
|
||||||
|
"maximum": null
|
||||||
|
},
|
||||||
|
"presence": {
|
||||||
|
"allowEmpty": false
|
||||||
|
},
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": "sasa",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Updated At": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"datetime": {
|
||||||
|
"earliest": "",
|
||||||
|
"latest": ""
|
||||||
|
},
|
||||||
|
"length": {},
|
||||||
|
"presence": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Updated At",
|
||||||
|
"subtype": "updatedAt",
|
||||||
|
"type": "datetime"
|
||||||
|
},
|
||||||
|
"Updated By": {
|
||||||
|
"autocolumn": true,
|
||||||
|
"constraints": {
|
||||||
|
"presence": false,
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"fieldName": "test12-Updated By",
|
||||||
|
"icon": "ri-magic-line",
|
||||||
|
"name": "Updated By",
|
||||||
|
"relationshipType": "many-to-many",
|
||||||
|
"subtype": "updatedBy",
|
||||||
|
"tableId": "ta_users",
|
||||||
|
"type": "link"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
import TestConfiguration from "../TestConfiguration"
|
||||||
|
import PublicAPIClient from "../PublicAPIClient"
|
||||||
|
|
||||||
|
describe("Public API - /rows endpoints", () => {
|
||||||
|
let api: PublicAPIClient
|
||||||
|
|
||||||
|
const config = new TestConfiguration()
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await config.beforeAll()
|
||||||
|
const app = await config.seedApp()
|
||||||
|
|
||||||
|
config.testContext.table = await config.seedTable(app.data._id)
|
||||||
|
api = new PublicAPIClient(app.data._id)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await config.afterAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("POST - Create a row", async () => {
|
||||||
|
const response = await api.post(`/tables/${config.testContext.table._id}/rows`, {
|
||||||
|
body: require("./fixtures/row.json")
|
||||||
|
})
|
||||||
|
const json = await response.json()
|
||||||
|
config.testContext.row = json.data
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("POST - Search rows", async () => {
|
||||||
|
const response = await api.post(`/tables/${config.testContext.table._id}/rows/search`, {
|
||||||
|
body: {
|
||||||
|
name: config.testContext.row.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("GET - Retrieve a row", async () => {
|
||||||
|
const response = await api.get(`/tables/${config.testContext.table._id}/rows/${config.testContext.row._id}`)
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it("PUT - update a row", async () => {
|
||||||
|
const response = await api.put(`/tables/${config.testContext.table._id}/rows/${config.testContext.row._id}`, {
|
||||||
|
body: require("./fixtures/update_row.json")
|
||||||
|
})
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,48 @@
|
||||||
|
import TestConfiguration from "../TestConfiguration"
|
||||||
|
import PublicAPIClient from "../PublicAPIClient"
|
||||||
|
|
||||||
|
describe("Public API - /tables endpoints", () => {
|
||||||
|
let api: PublicAPIClient
|
||||||
|
const config = new TestConfiguration()
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await config.beforeAll()
|
||||||
|
const app = await config.seedApp()
|
||||||
|
api = new PublicAPIClient(app.data._id)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await config.afterAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("POST - Create a table", async () => {
|
||||||
|
const response = await api.post(`/tables`, {
|
||||||
|
body: require("./fixtures/table.json")
|
||||||
|
})
|
||||||
|
const json = await response.json()
|
||||||
|
config.testContext.table = json.data
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("POST - Search tables", async () => {
|
||||||
|
const response = await api.post(`/tables/search`, {
|
||||||
|
body: {
|
||||||
|
name: config.testContext.table.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("GET - Retrieve a table", async () => {
|
||||||
|
const response = await api.get(`/tables/${config.testContext.table._id}`)
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it("PUT - update a table", async () => {
|
||||||
|
const response = await api.put(`/tables/${config.testContext.table._id}`, {
|
||||||
|
body: require("./fixtures/update_table.json")
|
||||||
|
})
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,22 @@
|
||||||
|
import generator from "../../generator"
|
||||||
|
import { User } from "@budibase/types"
|
||||||
|
|
||||||
|
const generate = (overrides = {}): User => ({
|
||||||
|
tenantId: generator.word(),
|
||||||
|
email: generator.email(),
|
||||||
|
roles: {
|
||||||
|
[generator.string({ length: 32, alpha: true, numeric: true })]: generator.word(),
|
||||||
|
},
|
||||||
|
password: generator.word(),
|
||||||
|
status: "active",
|
||||||
|
forceResetPassword: generator.bool(),
|
||||||
|
builder: {
|
||||||
|
global: generator.bool()
|
||||||
|
},
|
||||||
|
admin: {
|
||||||
|
global: generator.bool()
|
||||||
|
},
|
||||||
|
...overrides
|
||||||
|
})
|
||||||
|
|
||||||
|
export default generate
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"email": "test@budibase.com",
|
||||||
|
"roles": {
|
||||||
|
"sed_6d7": "sit ea amet",
|
||||||
|
"cupidatat_e16": "fugiat proident sed"
|
||||||
|
},
|
||||||
|
"password": "cupidatat Lorem ad",
|
||||||
|
"status": "active",
|
||||||
|
"firstName": "QA",
|
||||||
|
"lastName": "Updated",
|
||||||
|
"forceResetPassword": true,
|
||||||
|
"builder": {
|
||||||
|
"global": true
|
||||||
|
},
|
||||||
|
"admin": {
|
||||||
|
"global": false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"email": "test@budibase.com",
|
||||||
|
"roles": {
|
||||||
|
"sed_6d7": "sit ea amet",
|
||||||
|
"cupidatat_e16": "fugiat proident sed"
|
||||||
|
},
|
||||||
|
"password": "cupidatat Lorem ad",
|
||||||
|
"status": "active",
|
||||||
|
"firstName": "QA",
|
||||||
|
"lastName": "Test",
|
||||||
|
"forceResetPassword": true,
|
||||||
|
"builder": {
|
||||||
|
"global": true
|
||||||
|
},
|
||||||
|
"admin": {
|
||||||
|
"global": false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
import TestConfiguration from "../TestConfiguration"
|
||||||
|
import PublicAPIClient from "../PublicAPIClient"
|
||||||
|
|
||||||
|
describe("Public API - /users endpoints", () => {
|
||||||
|
const api = new PublicAPIClient()
|
||||||
|
const config = new TestConfiguration()
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await config.beforeAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await config.afterAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("POST - Create a user", async () => {
|
||||||
|
const response = await api.post(`/users`, {
|
||||||
|
body: require("./fixtures/user.json")
|
||||||
|
})
|
||||||
|
const json = await response.json()
|
||||||
|
config.testContext.user = json.data
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("POST - Search users", async () => {
|
||||||
|
const response = await api.post(`/users/search`, {
|
||||||
|
body: {
|
||||||
|
name: config.testContext.user.email
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("GET - Retrieve a user", async () => {
|
||||||
|
const response = await api.get(`/users/${config.testContext.user._id}`)
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it("PUT - update a user", async () => {
|
||||||
|
const response = await api.put(`/users/${config.testContext.user._id}`, {
|
||||||
|
body: require("./fixtures/update_user.json")
|
||||||
|
})
|
||||||
|
expect(response).toHaveStatusCode(200)
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"module": "commonjs",
|
||||||
|
"lib": ["es2020"],
|
||||||
|
"allowJs": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"incremental": true,
|
||||||
|
"types": ["node", "jest"],
|
||||||
|
"outDir": "dist",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"paths": {
|
||||||
|
"@budibase/types": ["../packages/types/src"],
|
||||||
|
"@budibase/backend-core": ["../packages/backend-core/src"],
|
||||||
|
"@budibase/backend-core/*": ["../packages/backend-core/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ts-node": {
|
||||||
|
"require": ["tsconfig-paths/register"]
|
||||||
|
},
|
||||||
|
"references": [
|
||||||
|
{ "path": "../packages/types" },
|
||||||
|
{ "path": "../packages/backend-core" },
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*",
|
||||||
|
"package.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue