1
0
Fork 0
mirror of synced 2024-07-02 04:50:44 +12:00

Merge branch 'master' into chore/remove-pro-test-specific-pipeline

This commit is contained in:
Adria Navarro 2024-03-15 15:44:34 +01:00 committed by GitHub
commit 7a77bda734
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 308 additions and 248 deletions

View file

@ -16,7 +16,7 @@ import {
ViewV2,
} from "@budibase/types"
import * as setup from "./utilities"
import { mocks } from "@budibase/backend-core/tests"
import { generator, mocks } from "@budibase/backend-core/tests"
const { basicRow } = setup.structures
const { BUILTIN_ROLE_IDS } = roles
@ -44,7 +44,10 @@ describe("/permission", () => {
table = (await config.createTable()) as typeof table
row = await config.createRow()
view = await config.api.viewV2.create({ tableId: table._id })
view = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
})
perms = await config.api.permission.add({
roleId: STD_ROLE_ID,
resourceId: table._id,

View file

@ -42,6 +42,7 @@ tk.freeze(timestamp)
jest.unmock("mysql2")
jest.unmock("mysql2/promise")
jest.unmock("mssql")
jest.unmock("pg")
describe.each([
["internal", undefined],
@ -152,8 +153,8 @@ describe.each([
table = await config.api.table.save(defaultTable())
})
describe("save, load, update", () => {
it("returns a success message when the row is created", async () => {
describe("create", () => {
it("creates a new row successfully", async () => {
const rowUsage = await getRowUsage()
const row = await config.api.row.save(table._id!, {
name: "Test Contact",
@ -163,7 +164,44 @@ describe.each([
await assertRowUsage(rowUsage + 1)
})
it("Increment row autoId per create row request", async () => {
it("fails to create a row for a table that does not exist", async () => {
const rowUsage = await getRowUsage()
await config.api.row.save("1234567", {}, { status: 404 })
await assertRowUsage(rowUsage)
})
it("fails to create a row if required fields are missing", async () => {
const rowUsage = await getRowUsage()
const table = await config.api.table.save(
saveTableRequest({
schema: {
required: {
type: FieldType.STRING,
name: "required",
constraints: {
type: "string",
presence: true,
},
},
},
})
)
await config.api.row.save(
table._id!,
{},
{
status: 500,
body: {
validationErrors: {
required: ["can't be blank"],
},
},
}
)
await assertRowUsage(rowUsage)
})
it("increment row autoId per create row request", async () => {
const rowUsage = await getRowUsage()
const newTable = await config.api.table.save(
@ -198,52 +236,6 @@ describe.each([
await assertRowUsage(rowUsage + 10)
})
it("updates a row successfully", async () => {
const existing = await config.api.row.save(table._id!, {})
const rowUsage = await getRowUsage()
const res = await config.api.row.save(table._id!, {
_id: existing._id,
_rev: existing._rev,
name: "Updated Name",
})
expect(res.name).toEqual("Updated Name")
await assertRowUsage(rowUsage)
})
it("should load a row", async () => {
const existing = await config.api.row.save(table._id!, {})
const res = await config.api.row.get(table._id!, existing._id!)
expect(res).toEqual({
...existing,
...defaultRowFields,
})
})
it("should list all rows for given tableId", async () => {
const table = await config.api.table.save(defaultTable())
const rows = await Promise.all([
config.api.row.save(table._id!, {}),
config.api.row.save(table._id!, {}),
])
const res = await config.api.row.fetch(table._id!)
expect(res.map(r => r._id)).toEqual(
expect.arrayContaining(rows.map(r => r._id))
)
})
it("load should return 404 when row does not exist", async () => {
const table = await config.api.table.save(defaultTable())
await config.api.row.save(table._id!, {})
await config.api.row.get(table._id!, "1234567", {
status: 404,
})
})
isInternal &&
it("row values are coerced", async () => {
const str: FieldSchema = {
@ -296,8 +288,6 @@ describe.each([
}
const table = await config.api.table.save(
saveTableRequest({
name: "TestTable2",
type: "table",
schema: {
name: str,
stringUndefined: str,
@ -404,53 +394,60 @@ describe.each([
})
})
describe("view save", () => {
it("views have extra data trimmed", async () => {
const table = await config.api.table.save(
saveTableRequest({
name: "orders",
schema: {
Country: {
type: FieldType.STRING,
name: "Country",
},
Story: {
type: FieldType.STRING,
name: "Story",
},
},
})
)
describe("get", () => {
it("reads an existing row successfully", async () => {
const existing = await config.api.row.save(table._id!, {})
const createViewResponse = await config.api.viewV2.create({
tableId: table._id!,
name: uuid.v4(),
schema: {
Country: {
visible: true,
},
},
})
const res = await config.api.row.get(table._id!, existing._id!)
const createRowResponse = await config.api.row.save(
createViewResponse.id,
{
Country: "Aussy",
Story: "aaaaa",
}
)
const row = await config.api.row.get(table._id!, createRowResponse._id!)
expect(row.Story).toBeUndefined()
expect(row).toEqual({
expect(res).toEqual({
...existing,
...defaultRowFields,
Country: "Aussy",
id: createRowResponse.id,
_id: createRowResponse._id,
_rev: createRowResponse._rev,
tableId: table._id,
})
})
it("returns 404 when row does not exist", async () => {
const table = await config.api.table.save(defaultTable())
await config.api.row.save(table._id!, {})
await config.api.row.get(table._id!, "1234567", {
status: 404,
})
})
})
describe("fetch", () => {
it("fetches all rows for given tableId", async () => {
const table = await config.api.table.save(defaultTable())
const rows = await Promise.all([
config.api.row.save(table._id!, {}),
config.api.row.save(table._id!, {}),
])
const res = await config.api.row.fetch(table._id!)
expect(res.map(r => r._id)).toEqual(
expect.arrayContaining(rows.map(r => r._id))
)
})
it("returns 404 when table does not exist", async () => {
await config.api.row.fetch("1234567", { status: 404 })
})
})
describe("update", () => {
it("updates an existing row successfully", async () => {
const existing = await config.api.row.save(table._id!, {})
const rowUsage = await getRowUsage()
const res = await config.api.row.save(table._id!, {
_id: existing._id,
_rev: existing._rev,
name: "Updated Name",
})
expect(res.name).toEqual("Updated Name")
await assertRowUsage(rowUsage)
})
})
describe("patch", () => {
@ -722,50 +719,7 @@ describe.each([
})
})
// Legacy views are not available for external
isInternal &&
describe("fetchView", () => {
beforeEach(async () => {
table = await config.api.table.save(defaultTable())
})
it("should be able to fetch tables contents via 'view'", async () => {
const row = await config.api.row.save(table._id!, {})
const rowUsage = await getRowUsage()
const rows = await config.api.legacyView.get(table._id!)
expect(rows.length).toEqual(1)
expect(rows[0]._id).toEqual(row._id)
await assertRowUsage(rowUsage)
})
it("should throw an error if view doesn't exist", async () => {
const rowUsage = await getRowUsage()
await config.api.legacyView.get("derp", undefined, { status: 404 })
await assertRowUsage(rowUsage)
})
it("should be able to run on a view", async () => {
const view = await config.createLegacyView({
tableId: table._id!,
name: "ViewTest",
filters: [],
schema: {},
})
const row = await config.api.row.save(table._id!, {})
const rowUsage = await getRowUsage()
const rows = await config.api.legacyView.get(view.name)
expect(rows.length).toEqual(1)
expect(rows[0]._id).toEqual(row._id)
await assertRowUsage(rowUsage)
})
})
describe("fetchEnrichedRows", () => {
describe("enrich", () => {
beforeAll(async () => {
table = await config.api.table.save(defaultTable())
})
@ -827,10 +781,6 @@ describe.each([
isInternal &&
describe("attachments", () => {
beforeAll(async () => {
table = await config.api.table.save(defaultTable())
})
it("should allow enriching attachment rows", async () => {
const table = await config.api.table.save(
defaultTable({
@ -865,7 +815,7 @@ describe.each([
})
})
describe("exportData", () => {
describe("exportRows", () => {
beforeAll(async () => {
table = await config.api.table.save(defaultTable())
})
@ -947,6 +897,7 @@ describe.each([
const table = await config.api.table.save(await userTable())
const view = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
schema: {
name: { visible: true },
surname: { visible: true },
@ -984,6 +935,7 @@ describe.each([
const tableId = table._id!
const view = await config.api.viewV2.create({
tableId: tableId,
name: generator.guid(),
schema: {
name: { visible: true },
address: { visible: true },
@ -1026,6 +978,7 @@ describe.each([
const tableId = table._id!
const view = await config.api.viewV2.create({
tableId: tableId,
name: generator.guid(),
schema: {
name: { visible: true },
address: { visible: true },
@ -1049,6 +1002,7 @@ describe.each([
const tableId = table._id!
const view = await config.api.viewV2.create({
tableId: tableId,
name: generator.guid(),
schema: {
name: { visible: true },
address: { visible: true },
@ -1109,6 +1063,7 @@ describe.each([
const createViewResponse = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
})
const response = await config.api.viewV2.search(createViewResponse.id)
@ -1155,6 +1110,7 @@ describe.each([
const createViewResponse = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
query: [
{ operator: SearchQueryOperators.EQUAL, field: "age", value: 40 },
],
@ -1279,6 +1235,7 @@ describe.each([
async (sortParams, expected) => {
const createViewResponse = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
sort: sortParams,
schema: viewSchema,
})
@ -1299,6 +1256,7 @@ describe.each([
async (sortParams, expected) => {
const createViewResponse = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
sort: {
field: "name",
order: SortOrder.ASCENDING,
@ -1339,6 +1297,7 @@ describe.each([
const view = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
schema: { name: { visible: true } },
})
const response = await config.api.viewV2.search(view.id)
@ -1361,6 +1320,7 @@ describe.each([
const table = await config.api.table.save(await userTable())
const createViewResponse = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
})
const response = await config.api.viewV2.search(createViewResponse.id)
expect(response.rows).toHaveLength(0)
@ -1376,6 +1336,7 @@ describe.each([
const createViewResponse = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
})
const response = await config.api.viewV2.search(createViewResponse.id, {
limit,
@ -1392,6 +1353,7 @@ describe.each([
)
const view = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
})
const rows = (await config.api.viewV2.search(view.id)).rows
@ -1466,6 +1428,7 @@ describe.each([
view = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
})
})

View file

@ -20,7 +20,7 @@ import sdk from "../../../sdk"
import * as uuid from "uuid"
import tk from "timekeeper"
import { mocks } from "@budibase/backend-core/tests"
import { generator, mocks } from "@budibase/backend-core/tests"
import { TableToBuild } from "../../../tests/utilities/TestConfiguration"
tk.freeze(mocks.date.MOCK_DATE)
@ -417,8 +417,8 @@ describe("/tables", () => {
it("should fetch views", async () => {
const tableId = config.table!._id!
const views = [
await config.api.viewV2.create({ tableId }),
await config.api.viewV2.create({ tableId }),
await config.api.viewV2.create({ tableId, name: generator.guid() }),
await config.api.viewV2.create({ tableId, name: generator.guid() }),
]
const res = await request
@ -455,7 +455,7 @@ describe("/tables", () => {
},
}))
await config.api.viewV2.create({ tableId })
await config.api.viewV2.create({ tableId, name: generator.guid() })
await config.createLegacyView()
const res = await config.api.table.fetch()

View file

@ -3,12 +3,15 @@ import * as setup from "./utilities"
import {
FieldType,
INTERNAL_TABLE_SOURCE_ID,
QuotaUsageType,
SaveTableRequest,
StaticQuotaName,
Table,
TableSourceType,
View,
ViewCalculation,
} from "@budibase/types"
import { quotas } from "@budibase/pro"
const priceTable: SaveTableRequest = {
name: "table",
@ -57,6 +60,18 @@ describe("/views", () => {
return config.api.legacyView.save(viewToSave)
}
const getRowUsage = async () => {
const { total } = await config.doInContext(undefined, () =>
quotas.getCurrentUsageValues(QuotaUsageType.STATIC, StaticQuotaName.ROWS)
)
return total
}
const assertRowUsage = async (expected: number) => {
const usage = await getRowUsage()
expect(usage).toBe(expected)
}
describe("create", () => {
it("returns a success message when the view is successfully created", async () => {
const res = await saveView()
@ -265,6 +280,41 @@ describe("/views", () => {
expect(views.length).toBe(1)
expect(views.find(({ name }) => name === "TestView")).toBeDefined()
})
it("should be able to fetch tables contents via 'view'", async () => {
const row = await config.api.row.save(table._id!, {})
const rowUsage = await getRowUsage()
const rows = await config.api.legacyView.get(table._id!)
expect(rows.length).toEqual(1)
expect(rows[0]._id).toEqual(row._id)
await assertRowUsage(rowUsage)
})
it("should throw an error if view doesn't exist", async () => {
const rowUsage = await getRowUsage()
await config.api.legacyView.get("derp", undefined, { status: 404 })
await assertRowUsage(rowUsage)
})
it("should be able to run on a view", async () => {
const view = await config.api.legacyView.save({
tableId: table._id!,
name: "ViewTest",
filters: [],
schema: {},
})
const row = await config.api.row.save(table._id!, {})
const rowUsage = await getRowUsage()
const rows = await config.api.legacyView.get(view.name!)
expect(rows.length).toEqual(1)
expect(rows[0]._id).toEqual(row._id)
await assertRowUsage(rowUsage)
})
})
describe("query", () => {

View file

@ -1,9 +1,11 @@
import * as setup from "./utilities"
import {
CreateViewRequest,
Datasource,
FieldSchema,
FieldType,
INTERNAL_TABLE_SOURCE_ID,
SaveTableRequest,
SearchQueryOperators,
SortOrder,
SortType,
@ -14,65 +16,88 @@ import {
ViewV2,
} from "@budibase/types"
import { generator } from "@budibase/backend-core/tests"
import { generateDatasourceID } from "../../../db/utils"
import * as uuid from "uuid"
import { databaseTestProviders } from "../../../integrations/tests/utils"
import merge from "lodash/merge"
function priceTable(): Table {
return {
name: "table",
type: "table",
sourceId: INTERNAL_TABLE_SOURCE_ID,
sourceType: TableSourceType.INTERNAL,
schema: {
Price: {
type: FieldType.NUMBER,
name: "Price",
constraints: {},
},
Category: {
type: FieldType.STRING,
name: "Category",
constraints: {
type: "string",
},
},
},
}
}
const config = setup.getConfig()
beforeAll(async () => {
await config.init()
})
jest.unmock("mysql2")
jest.unmock("mysql2/promise")
jest.unmock("mssql")
jest.unmock("pg")
describe.each([
["internal ds", () => config.createTable(priceTable())],
[
"external ds",
async () => {
const datasource = await config.createDatasource({
datasource: {
...setup.structures.basicDatasource().datasource,
plus: true,
_id: generateDatasourceID({ plus: true }),
},
})
["internal", undefined],
["postgres", databaseTestProviders.postgres],
["mysql", databaseTestProviders.mysql],
["mssql", databaseTestProviders.mssql],
["mariadb", databaseTestProviders.mariadb],
])("/v2/views (%s)", (_, dsProvider) => {
const config = setup.getConfig()
return config.createExternalTable({
...priceTable(),
sourceId: datasource._id,
sourceType: TableSourceType.EXTERNAL,
})
},
],
])("/v2/views (%s)", (_, tableBuilder) => {
let table: Table
let datasource: Datasource
function saveTableRequest(
...overrides: Partial<SaveTableRequest>[]
): SaveTableRequest {
const req: SaveTableRequest = {
name: uuid.v4().substring(0, 16),
type: "table",
sourceType: datasource
? TableSourceType.EXTERNAL
: TableSourceType.INTERNAL,
sourceId: datasource ? datasource._id! : INTERNAL_TABLE_SOURCE_ID,
primary: ["id"],
schema: {
id: {
type: FieldType.AUTO,
name: "id",
autocolumn: true,
constraints: {
presence: true,
},
},
},
}
return merge(req, ...overrides)
}
function priceTable(): SaveTableRequest {
return saveTableRequest({
schema: {
Price: {
type: FieldType.NUMBER,
name: "Price",
constraints: {},
},
Category: {
type: FieldType.STRING,
name: "Category",
constraints: {
type: "string",
},
},
},
})
}
beforeAll(async () => {
table = await tableBuilder()
await config.init()
if (dsProvider) {
datasource = await config.createDatasource({
datasource: await dsProvider.datasource(),
})
}
table = await config.api.table.save(priceTable())
})
afterAll(setup.afterAll)
afterAll(async () => {
if (dsProvider) {
await dsProvider.stop()
}
setup.afterAll()
})
describe("create", () => {
it("persist the view when the view is successfully created", async () => {
@ -186,9 +211,12 @@ describe.each([
let view: ViewV2
beforeEach(async () => {
table = await tableBuilder()
table = await config.api.table.save(priceTable())
view = await config.api.viewV2.create({ name: "View A" })
view = await config.api.viewV2.create({
tableId: table._id!,
name: "View A",
})
})
it("can update an existing view data", async () => {
@ -247,6 +275,9 @@ describe.each([
...updatedData,
schema: {
...table.schema,
id: expect.objectContaining({
visible: false,
}),
Category: expect.objectContaining({
visible: false,
}),
@ -320,23 +351,27 @@ describe.each([
})
it("cannot update views v1", async () => {
const viewV1 = await config.createLegacyView()
await config.api.viewV2.update(
{
...viewV1,
},
{
const viewV1 = await config.api.legacyView.save({
tableId: table._id!,
name: generator.guid(),
filters: [],
schema: {},
})
await config.api.viewV2.update(viewV1 as unknown as ViewV2, {
status: 400,
body: {
message: "Only views V2 can be updated",
status: 400,
body: {
message: "Only views V2 can be updated",
status: 400,
},
}
)
},
})
})
it("cannot update the a view with unmatching ids between url and body", async () => {
const anotherView = await config.api.viewV2.create()
const anotherView = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
})
const result = await config
.request!.put(`/api/v2/views/${anotherView.id}`)
.send(view)
@ -411,7 +446,10 @@ describe.each([
let view: ViewV2
beforeAll(async () => {
view = await config.api.viewV2.create()
view = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
})
})
it("can delete an existing view", async () => {
@ -448,4 +486,43 @@ describe.each([
expect(viewSchema.Price?.visible).toEqual(false)
})
})
describe("read", () => {
it("views have extra data trimmed", async () => {
const table = await config.api.table.save(
saveTableRequest({
name: "orders",
schema: {
Country: {
type: FieldType.STRING,
name: "Country",
},
Story: {
type: FieldType.STRING,
name: "Story",
},
},
})
)
const view = await config.api.viewV2.create({
tableId: table._id!,
name: uuid.v4(),
schema: {
Country: {
visible: true,
},
},
})
let row = await config.api.row.save(view.id, {
Country: "Aussy",
Story: "aaaaa",
})
row = await config.api.row.get(table._id!, row._id!)
expect(row.Story).toBeUndefined()
expect(row.Country).toEqual("Aussy")
})
})
})

View file

@ -1,21 +0,0 @@
import * as search from "../../app/rows/search"
describe("removeEmptyFilters", () => {
it("0 should not be removed", () => {
const filters = search.removeEmptyFilters({
equal: {
column: 0,
},
})
expect((filters.equal as any).column).toBe(0)
})
it("empty string should be removed", () => {
const filters = search.removeEmptyFilters({
equal: {
column: "",
},
})
expect(Object.values(filters.equal as any).length).toBe(0)
})
})

View file

@ -11,21 +11,9 @@ import sdk from "../../../sdk"
export class ViewV2API extends TestAPI {
create = async (
viewData?: Partial<CreateViewRequest>,
view: CreateViewRequest,
expectations?: Expectations
): Promise<ViewV2> => {
let tableId = viewData?.tableId
if (!tableId && !this.config.table) {
throw "Test requires table to be configured."
}
tableId = tableId || this.config.table!._id!
const view = {
tableId,
name: generator.guid(),
...viewData,
}
const exp: Expectations = {
status: 201,
...expectations,