Add and fix table tests
This commit is contained in:
parent
a7c8009e09
commit
616b1bf012
|
@ -17,8 +17,10 @@ import {
|
||||||
TableSchema,
|
TableSchema,
|
||||||
TableSourceType,
|
TableSourceType,
|
||||||
User,
|
User,
|
||||||
|
ValidateTableImportResponse,
|
||||||
ViewCalculation,
|
ViewCalculation,
|
||||||
ViewV2Enriched,
|
ViewV2Enriched,
|
||||||
|
RowExportFormat,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { checkBuilderEndpoint } from "./utilities/TestFunctions"
|
import { checkBuilderEndpoint } from "./utilities/TestFunctions"
|
||||||
import * as setup from "./utilities"
|
import * as setup from "./utilities"
|
||||||
|
@ -1086,7 +1088,10 @@ describe.each([
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("import validation", () => {
|
describe.each([
|
||||||
|
[RowExportFormat.CSV, (val: any) => JSON.stringify(val).replace(/"/g, "'")],
|
||||||
|
[RowExportFormat.JSON, (val: any) => val],
|
||||||
|
])("import validation (%s)", (_, userParser) => {
|
||||||
const basicSchema: TableSchema = {
|
const basicSchema: TableSchema = {
|
||||||
id: {
|
id: {
|
||||||
type: FieldType.NUMBER,
|
type: FieldType.NUMBER,
|
||||||
|
@ -1098,9 +1103,41 @@ describe.each([
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("validateNewTableImport", () => {
|
const importCases: [
|
||||||
it("can validate basic imports", async () => {
|
string,
|
||||||
const result = await config.api.table.validateNewTableImport(
|
(rows: Row[], schema: TableSchema) => Promise<ValidateTableImportResponse>
|
||||||
|
][] = [
|
||||||
|
[
|
||||||
|
"validateNewTableImport",
|
||||||
|
async (rows: Row[], schema: TableSchema) => {
|
||||||
|
const result = await config.api.table.validateNewTableImport({
|
||||||
|
rows,
|
||||||
|
schema,
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"validateExistingTableImport",
|
||||||
|
async (rows: Row[], schema: TableSchema) => {
|
||||||
|
const table = await config.api.table.save(
|
||||||
|
tableForDatasource(datasource, {
|
||||||
|
primary: ["id"],
|
||||||
|
schema,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
const result = await config.api.table.validateExistingTableImport({
|
||||||
|
tableId: table._id,
|
||||||
|
rows,
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
describe.each(importCases)("%s", (_, testDelegate) => {
|
||||||
|
it("validates basic imports", async () => {
|
||||||
|
const result = await testDelegate(
|
||||||
[{ id: generator.natural(), name: generator.first() }],
|
[{ id: generator.natural(), name: generator.first() }],
|
||||||
basicSchema
|
basicSchema
|
||||||
)
|
)
|
||||||
|
@ -1119,18 +1156,18 @@ describe.each([
|
||||||
it.each(
|
it.each(
|
||||||
isInternal ? PROTECTED_INTERNAL_COLUMNS : PROTECTED_EXTERNAL_COLUMNS
|
isInternal ? PROTECTED_INTERNAL_COLUMNS : PROTECTED_EXTERNAL_COLUMNS
|
||||||
)("don't allow protected names in schema (%s)", async columnName => {
|
)("don't allow protected names in schema (%s)", async columnName => {
|
||||||
const result = await config.api.table.validateNewTableImport(
|
const result = await config.api.table.validateNewTableImport({
|
||||||
[
|
rows: [
|
||||||
{
|
{
|
||||||
id: generator.natural(),
|
id: generator.natural(),
|
||||||
name: generator.first(),
|
name: generator.first(),
|
||||||
[columnName]: generator.word(),
|
[columnName]: generator.word(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
{
|
schema: {
|
||||||
...basicSchema,
|
...basicSchema,
|
||||||
}
|
},
|
||||||
)
|
})
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
allValid: false,
|
allValid: false,
|
||||||
|
@ -1146,25 +1183,53 @@ describe.each([
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("does not allow imports without rows", async () => {
|
||||||
|
const result = await testDelegate([], basicSchema)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
allValid: false,
|
||||||
|
errors: {},
|
||||||
|
invalidColumns: [],
|
||||||
|
schemaValidation: {},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("validates imports with some empty rows", async () => {
|
||||||
|
const result = await testDelegate(
|
||||||
|
[{}, { id: generator.natural(), name: generator.first() }, {}],
|
||||||
|
basicSchema
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
allValid: true,
|
||||||
|
errors: {},
|
||||||
|
invalidColumns: [],
|
||||||
|
schemaValidation: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
isInternal &&
|
isInternal &&
|
||||||
it.each(
|
it.each(
|
||||||
isInternal ? PROTECTED_INTERNAL_COLUMNS : PROTECTED_EXTERNAL_COLUMNS
|
isInternal ? PROTECTED_INTERNAL_COLUMNS : PROTECTED_EXTERNAL_COLUMNS
|
||||||
)("don't allow protected names in the rows (%s)", async columnName => {
|
)("don't allow protected names in the rows (%s)", async columnName => {
|
||||||
const result = await config.api.table.validateNewTableImport(
|
const result = await config.api.table.validateNewTableImport({
|
||||||
[
|
rows: [
|
||||||
{
|
{
|
||||||
id: generator.natural(),
|
id: generator.natural(),
|
||||||
name: generator.first(),
|
name: generator.first(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
{
|
schema: {
|
||||||
...basicSchema,
|
...basicSchema,
|
||||||
[columnName]: {
|
[columnName]: {
|
||||||
name: columnName,
|
name: columnName,
|
||||||
type: FieldType.STRING,
|
type: FieldType.STRING,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
)
|
})
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
allValid: false,
|
allValid: false,
|
||||||
|
@ -1179,20 +1244,24 @@ describe.each([
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
describe("validateExistingTableImport", () => {
|
it("validates required fields and valid rows", async () => {
|
||||||
it("can validate basic imports", async () => {
|
const schema: TableSchema = {
|
||||||
const table = await config.api.table.save(
|
...basicSchema,
|
||||||
tableForDatasource(datasource, {
|
name: {
|
||||||
primary: ["id"],
|
type: FieldType.STRING,
|
||||||
schema: basicSchema,
|
name: "name",
|
||||||
})
|
constraints: { presence: true },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await testDelegate(
|
||||||
|
[
|
||||||
|
{ id: generator.natural(), name: generator.first() },
|
||||||
|
{ id: generator.natural(), name: generator.first() },
|
||||||
|
],
|
||||||
|
schema
|
||||||
)
|
)
|
||||||
const result = await config.api.table.validateExistingTableImport({
|
|
||||||
tableId: table._id,
|
|
||||||
rows: [{ id: generator.natural(), name: generator.first() }],
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
allValid: true,
|
allValid: true,
|
||||||
|
@ -1205,6 +1274,154 @@ describe.each([
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("validates required fields and non-valid rows", async () => {
|
||||||
|
const schema: TableSchema = {
|
||||||
|
...basicSchema,
|
||||||
|
name: {
|
||||||
|
type: FieldType.STRING,
|
||||||
|
name: "name",
|
||||||
|
constraints: { presence: true },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await testDelegate(
|
||||||
|
[
|
||||||
|
{ id: generator.natural(), name: generator.first() },
|
||||||
|
{ id: generator.natural(), name: "" },
|
||||||
|
],
|
||||||
|
schema
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
allValid: false,
|
||||||
|
errors: {},
|
||||||
|
invalidColumns: [],
|
||||||
|
schemaValidation: {
|
||||||
|
id: true,
|
||||||
|
name: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("bb references", () => {
|
||||||
|
const getUserValues = () => ({
|
||||||
|
_id: docIds.generateGlobalUserID(),
|
||||||
|
primaryDisplay: generator.first(),
|
||||||
|
email: generator.email({}),
|
||||||
|
})
|
||||||
|
|
||||||
|
it("can validate user column imports", async () => {
|
||||||
|
const schema: TableSchema = {
|
||||||
|
...basicSchema,
|
||||||
|
user: {
|
||||||
|
type: FieldType.BB_REFERENCE_SINGLE,
|
||||||
|
subtype: BBReferenceFieldSubType.USER,
|
||||||
|
name: "user",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await testDelegate(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: generator.natural(),
|
||||||
|
name: generator.first(),
|
||||||
|
user: userParser(getUserValues()),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
schema
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
allValid: true,
|
||||||
|
errors: {},
|
||||||
|
invalidColumns: [],
|
||||||
|
schemaValidation: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
user: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("can validate user column imports with invalid data", async () => {
|
||||||
|
const schema: TableSchema = {
|
||||||
|
...basicSchema,
|
||||||
|
user: {
|
||||||
|
type: FieldType.BB_REFERENCE_SINGLE,
|
||||||
|
subtype: BBReferenceFieldSubType.USER,
|
||||||
|
name: "user",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await testDelegate(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: generator.natural(),
|
||||||
|
name: generator.first(),
|
||||||
|
user: userParser(getUserValues()),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: generator.natural(),
|
||||||
|
name: generator.first(),
|
||||||
|
user: "no valid user data",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
schema
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
allValid: false,
|
||||||
|
errors: {},
|
||||||
|
invalidColumns: [],
|
||||||
|
schemaValidation: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
user: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("can validate users column imports", async () => {
|
||||||
|
const schema: TableSchema = {
|
||||||
|
...basicSchema,
|
||||||
|
user: {
|
||||||
|
type: FieldType.BB_REFERENCE,
|
||||||
|
subtype: BBReferenceFieldSubType.USER,
|
||||||
|
name: "user",
|
||||||
|
externalType: "array",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await testDelegate(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: generator.natural(),
|
||||||
|
name: generator.first(),
|
||||||
|
user: userParser([
|
||||||
|
getUserValues(),
|
||||||
|
getUserValues(),
|
||||||
|
getUserValues(),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
schema
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
allValid: true,
|
||||||
|
errors: {},
|
||||||
|
invalidColumns: [],
|
||||||
|
schemaValidation: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
user: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("validateExistingTableImport", () => {
|
||||||
isInternal &&
|
isInternal &&
|
||||||
it("can reimport _id fields for internal tables", async () => {
|
it("can reimport _id fields for internal tables", async () => {
|
||||||
const table = await config.api.table.save(
|
const table = await config.api.table.save(
|
||||||
|
|
|
@ -5,11 +5,10 @@ import {
|
||||||
CsvToJsonResponse,
|
CsvToJsonResponse,
|
||||||
MigrateRequest,
|
MigrateRequest,
|
||||||
MigrateResponse,
|
MigrateResponse,
|
||||||
Row,
|
|
||||||
SaveTableRequest,
|
SaveTableRequest,
|
||||||
SaveTableResponse,
|
SaveTableResponse,
|
||||||
Table,
|
Table,
|
||||||
TableSchema,
|
ValidateNewTableImportRequest,
|
||||||
ValidateTableImportRequest,
|
ValidateTableImportRequest,
|
||||||
ValidateTableImportResponse,
|
ValidateTableImportResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
@ -73,17 +72,13 @@ export class TableAPI extends TestAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
validateNewTableImport = async (
|
validateNewTableImport = async (
|
||||||
rows: Row[],
|
body: ValidateNewTableImportRequest,
|
||||||
schema: TableSchema,
|
|
||||||
expectations?: Expectations
|
expectations?: Expectations
|
||||||
): Promise<ValidateTableImportResponse> => {
|
): Promise<ValidateTableImportResponse> => {
|
||||||
return await this._post<ValidateTableImportResponse>(
|
return await this._post<ValidateTableImportResponse>(
|
||||||
`/api/tables/validateNewTableImport`,
|
`/api/tables/validateNewTableImport`,
|
||||||
{
|
{
|
||||||
body: {
|
body,
|
||||||
rows,
|
|
||||||
schema,
|
|
||||||
},
|
|
||||||
expectations,
|
expectations,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -210,10 +210,6 @@ function isValidBBReference(
|
||||||
subtype: BBReferenceFieldSubType,
|
subtype: BBReferenceFieldSubType,
|
||||||
isRequired: boolean
|
isRequired: boolean
|
||||||
): boolean {
|
): boolean {
|
||||||
if (typeof data !== "string") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type === FieldType.BB_REFERENCE_SINGLE) {
|
if (type === FieldType.BB_REFERENCE_SINGLE) {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return !isRequired
|
return !isRequired
|
||||||
|
@ -240,7 +236,10 @@ function isValidBBReference(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseJsonExport<T>(value: string) {
|
function parseJsonExport<T>(value: any) {
|
||||||
|
if (typeof value !== "string") {
|
||||||
|
return value
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(value)
|
const parsed = JSON.parse(value)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue