import { FieldType, INTERNAL_TABLE_SOURCE_ID, Table, TableSourceType, } from "@budibase/types" import { generateTableID } from "../../../../db/utils" import { validate } from "../utils" import { generator } from "@budibase/backend-core/tests" describe("validate", () => { const hour = () => generator.hour().toString().padStart(2, "0") const minute = () => generator.minute().toString().padStart(2, "0") const second = minute describe("time only", () => { const getTable = (): Table => ({ type: "table", _id: generateTableID(), name: "table", sourceId: INTERNAL_TABLE_SOURCE_ID, sourceType: TableSourceType.INTERNAL, schema: { time: { name: "time", type: FieldType.DATETIME, timeOnly: true, }, }, }) it("should accept empty values", async () => { const row = {} const table = getTable() const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(true) expect(output.errors).toEqual({}) }) it("should accept valid times with HH:mm format", async () => { const row = { time: `${hour()}:${minute()}`, } const table = getTable() const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(true) }) it("should accept valid times with HH:mm:ss format", async () => { const row = { time: `${hour()}:${minute()}:${second()}`, } const table = getTable() const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(true) }) it.each([ ["ISO datetimes", generator.date().toISOString()], ["random values", generator.word()], ])("should reject %s", async (_, time) => { const row = { time, } const table = getTable() table.schema.time.constraints = { presence: true, } const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(false) expect(output.errors).toEqual({ time: ['"time" is not a valid time'] }) }) describe("time constraints", () => { describe("earliest only", () => { const table = getTable() table.schema.time.constraints = { presence: true, datetime: { earliest: "10:00", latest: "", }, } it.each([ "10:00", "15:00", `10:${minute()}`, "12:34", `${generator.integer({ min: 11, max: 23 })}:${minute()}`, ])("should accept values after config value (%s)", async time => { const row = { time } const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(true) }) it.each([ "09:59:59", `${generator.integer({ min: 0, max: 9 })}:${minute()}`, ])("should reject values before config value (%s)", async time => { const row = { time } const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(false) expect(output.errors).toEqual({ time: ["must be no earlier than 10:00"], }) }) }) describe("latest only", () => { const table = getTable() table.schema.time.constraints = { presence: true, datetime: { earliest: "", latest: "15:16:17", }, } it.each([ "15:16:17", "15:16", "15:00", `${generator.integer({ min: 0, max: 12 })}:${minute()}`, ])("should accept values before config value (%s)", async time => { const row = { time } const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(true) }) it.each([ "15:16:18", `${generator.integer({ min: 16, max: 23 })}:${minute()}`, ])("should reject values after config value (%s)", async time => { const row = { time } const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(false) expect(output.errors).toEqual({ time: ["must be no later than 15:16:17"], }) }) }) describe("range", () => { const table = getTable() table.schema.time.constraints = { presence: true, datetime: { earliest: "10:00", latest: "15:00", }, } it.each(["10:00", "15:00", `10:${minute()}`, "12:34"])( "should accept values in range (%s)", async time => { const row = { time } const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(true) } ) it.each([ "9:59:50", `${generator.integer({ min: 0, max: 9 })}:${minute()}`, ])("should reject values before range (%s)", async time => { const row = { time } const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(false) expect(output.errors).toEqual({ time: ["must be no earlier than 10:00"], }) }) it.each([ "15:00:01", `${generator.integer({ min: 16, max: 23 })}:${minute()}`, ])("should reject values after range (%s)", async time => { const row = { time } const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(false) expect(output.errors).toEqual({ time: ["must be no later than 15:00"], }) }) describe("range crossing midnight", () => { const table = getTable() table.schema.time.constraints = { presence: true, datetime: { earliest: "15:00", latest: "10:00", }, } it.each(["10:00", "15:00", `9:${minute()}`, "16:34", "00:00"])( "should accept values in range (%s)", async time => { const row = { time } const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(true) } ) it.each(["10:01", "14:59:59", `12:${minute()}`])( "should reject values out range (%s)", async time => { const row = { time } const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(false) expect(output.errors).toEqual({ time: ["must be no later than 10:00"], }) } ) }) }) }) describe("required", () => { it("should reject empty values", async () => { const row = {} const table = getTable() table.schema.time.constraints = { presence: true, } const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(false) expect(output.errors).toEqual({ time: ["can't be blank"] }) }) it.each([undefined, null])("should reject %s values", async time => { const row = { time } const table = getTable() table.schema.time.constraints = { presence: true, } const output = await validate({ table, tableId: table._id!, row }) expect(output.valid).toBe(false) expect(output.errors).toEqual({ time: ["can't be blank"] }) }) }) }) })