import type { BaseFieldConfig, Field, TActionContext } from "data/fields"; import type { ColumnDataType } from "kysely"; import { omit } from "lodash-es"; import type { TestRunner } from "core/test"; type ConstructableField = new (name: string, config?: Partial) => Field; type FieldTestConfig = { defaultValue: any; sampleValues?: any[]; schemaType: ColumnDataType; }; export function transformPersist(field: Field, value: any, context?: TActionContext) { return field.transformPersist(value, undefined as any, context as any); } export function fieldTestSuite( testRunner: TestRunner, fieldClass: ConstructableField, config: FieldTestConfig, _requiredConfig: any = {}, ) { const { test, expect } = testRunner; const noConfigField = new fieldClass("no_config", _requiredConfig); const fillable = new fieldClass("fillable", { ..._requiredConfig, fillable: true }); const required = new fieldClass("required", { ..._requiredConfig, required: true }); const hidden = new fieldClass("hidden", { ..._requiredConfig, hidden: true }); const dflt = new fieldClass("dflt", { ..._requiredConfig, default_value: config.defaultValue }); const requiredAndDefault = new fieldClass("full", { ..._requiredConfig, fillable: true, required: true, default_value: config.defaultValue, }); test("schema", () => { expect(noConfigField.name).toBe("no_config"); const { type, name, nullable, dflt } = noConfigField.schema()!; expect({ type, name, nullable, dflt }).toEqual({ type: config.schemaType as any, name: "no_config", nullable: true, // always true dflt: undefined, // never using default value }); }); test("hasDefault", async () => { expect(noConfigField.hasDefault()).toBe(false); expect(noConfigField.getDefault()).toBeUndefined(); expect(dflt.hasDefault()).toBe(true); expect(dflt.getDefault()).toEqual(config.defaultValue); }); test("isFillable", async () => { expect(noConfigField.isFillable()).toBe(true); expect(fillable.isFillable()).toBe(true); expect(hidden.isFillable()).toBe(true); expect(required.isFillable()).toBe(true); }); test("isHidden", async () => { expect(noConfigField.isHidden()).toBe(false); expect(hidden.isHidden()).toBe(true); expect(fillable.isHidden()).toBe(false); expect(required.isHidden()).toBe(false); }); test("isRequired", async () => { expect(noConfigField.isRequired()).toBe(false); expect(required.isRequired()).toBe(true); expect(hidden.isRequired()).toBe(false); expect(fillable.isRequired()).toBe(false); }); test.if(Array.isArray(config.sampleValues))("getValue (RenderContext)", async () => { const isPrimitive = (v) => ["string", "number"].includes(typeof v); for (const value of config.sampleValues!) { // "form" expect(isPrimitive(noConfigField.getValue(value, "form"))).toBe(true); // "table" expect(isPrimitive(noConfigField.getValue(value, "table"))).toBe(true); // "read" // "submit" } }); test("transformPersist", async () => { const persist = await transformPersist(noConfigField, config.defaultValue); expect(config.defaultValue).toEqual(noConfigField.transformRetrieve(config.defaultValue)); expect(transformPersist(noConfigField, null)).resolves.toBeUndefined(); expect(transformPersist(noConfigField, undefined)).resolves.toBeUndefined(); expect(transformPersist(requiredAndDefault, null)).resolves.toBe(persist); expect(transformPersist(dflt, null)).resolves.toBe(persist); }); test("toJSON", async () => { const _config = { ..._requiredConfig, required: false, }; function fieldJson(field: Field) { const json = field.toJSON(); return { ...json, config: omit(json.config, ["html"]), }; } expect(fieldJson(noConfigField)).toEqual({ type: noConfigField.type, config: _config, }); expect(fieldJson(fillable)).toEqual({ type: noConfigField.type, config: { ..._config, fillable: true, }, }); expect(fieldJson(required)).toEqual({ type: required.type, config: { ..._config, required: true, }, }); expect(fieldJson(hidden)).toEqual({ type: required.type, config: { ..._config, hidden: true, }, }); expect(fieldJson(dflt)).toEqual({ type: dflt.type, config: { ..._config, default_value: config.defaultValue, }, }); expect(fieldJson(requiredAndDefault)).toEqual({ type: requiredAndDefault.type, config: { ..._config, fillable: true, required: true, default_value: config.defaultValue, }, }); }); }