mirror of
https://github.com/lowdefy/lowdefy.git
synced 2025-04-06 15:30:30 +08:00
fix(engine): Fix required validation broken by dynamic operators.
This commit is contained in:
parent
10a017fd08
commit
6d38dbbe57
@ -30,6 +30,7 @@ const blockData = ({
|
||||
id,
|
||||
layout,
|
||||
meta,
|
||||
operators,
|
||||
pageId,
|
||||
properties,
|
||||
requests,
|
||||
@ -47,6 +48,7 @@ const blockData = ({
|
||||
id,
|
||||
layout,
|
||||
meta,
|
||||
operators,
|
||||
pageId,
|
||||
properties,
|
||||
requests,
|
||||
@ -69,12 +71,13 @@ const getContext = async ({ block, contextId, lowdefy }) => {
|
||||
if (!lowdefy.inputs[contextId]) {
|
||||
lowdefy.inputs[contextId] = {};
|
||||
}
|
||||
const operatorsSet = new Set([...block.operators, '_not', '_type']);
|
||||
lowdefy.contexts[contextId] = {
|
||||
id: contextId,
|
||||
blockId: block.blockId,
|
||||
eventLog: [],
|
||||
requests: {},
|
||||
operators: block.operators || [],
|
||||
operators: [...operatorsSet],
|
||||
lowdefy,
|
||||
pageId: lowdefy.pageId,
|
||||
rootBlock: blockData(block), // filter block to prevent circular structure
|
||||
|
@ -46,6 +46,116 @@ afterAll(() => {
|
||||
global.Date = RealDate;
|
||||
});
|
||||
|
||||
test('Validate required field', async () => {
|
||||
const rootBlock = {
|
||||
blockId: 'root',
|
||||
meta: {
|
||||
category: 'context',
|
||||
},
|
||||
areas: {
|
||||
content: {
|
||||
blocks: [
|
||||
{
|
||||
blockId: 'text1',
|
||||
type: 'TextInput',
|
||||
meta: {
|
||||
category: 'input',
|
||||
valueType: 'string',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
blockId: 'button',
|
||||
type: 'Button',
|
||||
meta: {
|
||||
category: 'display',
|
||||
},
|
||||
events: {
|
||||
onClick: [
|
||||
{
|
||||
id: 'validate',
|
||||
type: 'Validate',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
const context = await testContext({
|
||||
lowdefy,
|
||||
rootBlock,
|
||||
});
|
||||
const { button, text1 } = context.RootBlocks.map;
|
||||
expect(text1.validationEval.output).toEqual({
|
||||
errors: ['This field is required'],
|
||||
status: null,
|
||||
warnings: [],
|
||||
});
|
||||
await button.triggerEvent({ name: 'onClick' });
|
||||
expect(button.Events.events.onClick.history[0]).toEqual({
|
||||
blockId: 'button',
|
||||
event: undefined,
|
||||
eventName: 'onClick',
|
||||
responses: [
|
||||
{
|
||||
actionId: 'validate',
|
||||
actionType: 'Validate',
|
||||
error: new Error('Your input has 1 validation error.'),
|
||||
},
|
||||
],
|
||||
success: false,
|
||||
timestamp: {
|
||||
date: 0,
|
||||
},
|
||||
});
|
||||
expect(text1.validationEval.output).toEqual({
|
||||
errors: ['This field is required'],
|
||||
status: 'error',
|
||||
warnings: [],
|
||||
});
|
||||
expect(displayMessage.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
Object {
|
||||
"content": "Your input has 1 validation error.",
|
||||
"duration": 6,
|
||||
"status": "error",
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
displayMessage.mockReset();
|
||||
displayMessage.mockImplementation(() => closeLoader);
|
||||
text1.setValue('text1');
|
||||
await button.triggerEvent({ name: 'onClick' });
|
||||
expect(button.Events.events.onClick.history[0]).toEqual({
|
||||
blockId: 'button',
|
||||
event: undefined,
|
||||
eventName: 'onClick',
|
||||
responses: [
|
||||
{
|
||||
actionId: 'validate',
|
||||
actionType: 'Validate',
|
||||
response: undefined,
|
||||
},
|
||||
],
|
||||
success: true,
|
||||
timestamp: {
|
||||
date: 0,
|
||||
},
|
||||
});
|
||||
expect(text1.validationEval.output).toEqual({
|
||||
errors: [],
|
||||
status: 'success',
|
||||
warnings: [],
|
||||
});
|
||||
expect(displayMessage.mock.calls).toEqual([]);
|
||||
displayMessage.mockReset();
|
||||
displayMessage.mockImplementation(() => closeLoader);
|
||||
});
|
||||
|
||||
test('Validate all fields', async () => {
|
||||
const rootBlock = {
|
||||
blockId: 'root',
|
||||
|
@ -46,6 +46,7 @@ test('memoize context', async () => {
|
||||
meta: {
|
||||
type: 'context',
|
||||
},
|
||||
operators: [],
|
||||
};
|
||||
const c1 = await getContext({ block, contextId: 'c1', lowdefy });
|
||||
const c2 = await getContext({ block, contextId: 'c1', lowdefy });
|
||||
@ -71,6 +72,7 @@ test('create context', async () => {
|
||||
meta: {
|
||||
type: 'context',
|
||||
},
|
||||
operators: [],
|
||||
};
|
||||
const context = await getContext({ block, contextId: 'contextId', lowdefy });
|
||||
expect(context.Actions).toBeDefined();
|
||||
@ -81,6 +83,7 @@ test('create context', async () => {
|
||||
expect(context.lowdefy).toEqual(lowdefy);
|
||||
expect(context.eventLog).toEqual([]);
|
||||
expect(context.id).toEqual('contextId');
|
||||
expect(context.operators).toBeInstanceOf(Array);
|
||||
expect(context.lowdefy.pageId).toEqual('pageId');
|
||||
expect(context.parser).toBeDefined();
|
||||
expect(context.requests).toEqual({});
|
||||
@ -111,6 +114,7 @@ test('create context, initialize input', async () => {
|
||||
meta: {
|
||||
type: 'context',
|
||||
},
|
||||
operators: [],
|
||||
};
|
||||
const context = await getContext({ block, contextId: 'contextId', lowdefy });
|
||||
expect(context.lowdefy.inputs.contextId).toEqual({});
|
||||
@ -129,12 +133,14 @@ test('call update for listening contexts', async () => {
|
||||
meta: {
|
||||
type: 'context',
|
||||
},
|
||||
operators: [],
|
||||
};
|
||||
const block2 = {
|
||||
blockId: 'block2',
|
||||
meta: {
|
||||
type: 'context',
|
||||
},
|
||||
operators: [],
|
||||
};
|
||||
const mockUpdate = jest.fn();
|
||||
const c1 = await getContext({ block: block1, contextId: 'c1', lowdefy });
|
||||
@ -158,6 +164,7 @@ test('remove contextId from updateListeners if not found', async () => {
|
||||
meta: {
|
||||
type: 'context',
|
||||
},
|
||||
operators: [],
|
||||
};
|
||||
const c1 = await getContext({ block, contextId: 'c1', lowdefy });
|
||||
|
||||
@ -180,6 +187,7 @@ test('remove contextId from updateListeners if equal to own contextId', async ()
|
||||
meta: {
|
||||
type: 'context',
|
||||
},
|
||||
operators: [],
|
||||
};
|
||||
const c1 = await getContext({ block, contextId: 'c1', lowdefy });
|
||||
|
||||
@ -202,6 +210,7 @@ test('update memoized context', async () => {
|
||||
meta: {
|
||||
type: 'context',
|
||||
},
|
||||
operators: [],
|
||||
};
|
||||
const mockUpdate = jest.fn();
|
||||
const c1 = await getContext({ block, contextId: 'c1', lowdefy });
|
||||
@ -223,6 +232,7 @@ test('call update for nested contexts and prevent circular loop structure', asyn
|
||||
meta: {
|
||||
type: 'context',
|
||||
},
|
||||
operators: [],
|
||||
};
|
||||
const block1 = {
|
||||
blockId: 'block1',
|
||||
@ -234,6 +244,7 @@ test('call update for nested contexts and prevent circular loop structure', asyn
|
||||
blocks: block2,
|
||||
},
|
||||
},
|
||||
operators: [],
|
||||
};
|
||||
const c1 = await getContext({ block: block1, contextId: 'c1', lowdefy });
|
||||
const getC2 = () =>
|
||||
@ -244,3 +255,22 @@ test('call update for nested contexts and prevent circular loop structure', asyn
|
||||
});
|
||||
await expect(getC2()).resolves.not.toThrow();
|
||||
});
|
||||
|
||||
test('Add operators for required validation', async () => {
|
||||
const lowdefy = {
|
||||
client,
|
||||
contexts: {},
|
||||
inputs: {},
|
||||
pageId,
|
||||
updateBlock,
|
||||
};
|
||||
const block = {
|
||||
blockId: 'blockId',
|
||||
meta: {
|
||||
type: 'context',
|
||||
},
|
||||
operators: [],
|
||||
};
|
||||
const context = await getContext({ block, contextId: 'contextId', lowdefy });
|
||||
expect(context.operators).toEqual(expect.arrayContaining(['_not', '_type']));
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user