feat(automations): form-driven branching rules, round-robin assignment, lead-linked activities
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
matchFormFieldCondition,
|
||||
planAutomationActions,
|
||||
splitFormAnswer,
|
||||
type AutomationStep,
|
||||
} from '@mento/shared';
|
||||
import {
|
||||
formatFormAnswers,
|
||||
pickRoundRobin,
|
||||
renderAutomationTemplate,
|
||||
} from '../src/automations/automation-engine.util';
|
||||
|
||||
const KEY = 'coop_type';
|
||||
const answers = (raw: string): Record<string, string> => ({ [KEY]: raw });
|
||||
|
||||
function cond(id: string, value: string): AutomationStep {
|
||||
return {
|
||||
id,
|
||||
kind: 'condition',
|
||||
conditionField: 'form_field',
|
||||
conditionKey: KEY,
|
||||
conditionOp: 'contains',
|
||||
conditionValue: value,
|
||||
};
|
||||
}
|
||||
|
||||
function act(id: string): AutomationStep {
|
||||
return { id, kind: 'action', action: 'create_activity' };
|
||||
}
|
||||
|
||||
const BSJ: AutomationStep[] = [
|
||||
cond('c1', 'بنکداری'),
|
||||
act('a1'),
|
||||
cond('c2', 'آنلاین شاپ'),
|
||||
act('a2'),
|
||||
cond('c3', 'ویترین نقره'),
|
||||
act('a3'),
|
||||
];
|
||||
|
||||
function run(steps: AutomationStep[], raw: string, mode: 'branches' | 'stop' = 'branches') {
|
||||
const values = answers(raw);
|
||||
return planAutomationActions(steps, mode, (s) =>
|
||||
matchFormFieldCondition(s.conditionOp, values[s.conditionKey ?? ''], s.conditionValue),
|
||||
).map((s) => s.id);
|
||||
}
|
||||
|
||||
describe('اتوماسیون شاخهای فرم', () => {
|
||||
it('چندانتخابی را میشکند', () => {
|
||||
assert.deepEqual(splitFormAnswer('بنکداری, آنلاین شاپ'), ['بنکداری', 'آنلاین شاپ']);
|
||||
assert.deepEqual(splitFormAnswer('الف، ب'), ['الف', 'ب']);
|
||||
assert.deepEqual(splitFormAnswer(''), []);
|
||||
assert.deepEqual(splitFormAnswer(undefined), []);
|
||||
});
|
||||
|
||||
it('عملگرهای فیلد فرم', () => {
|
||||
assert.equal(matchFormFieldCondition('contains', 'بنکداری, ویترین نقره', 'ویترین نقره'), true);
|
||||
assert.equal(matchFormFieldCondition('contains', 'بنکداری', 'آنلاین شاپ'), false);
|
||||
assert.equal(matchFormFieldCondition('not_contains', 'بنکداری', 'آنلاین شاپ'), true);
|
||||
assert.equal(matchFormFieldCondition('eq', 'بنکداری', 'بنکداری'), true);
|
||||
assert.equal(matchFormFieldCondition('eq', 'بنکداری, آنلاین شاپ', 'بنکداری'), false);
|
||||
assert.equal(matchFormFieldCondition('is_set', 'x', ''), true);
|
||||
assert.equal(matchFormFieldCondition('is_empty', '', ''), true);
|
||||
});
|
||||
|
||||
it('هر گزینه فقط شاخهٔ خودش را اجرا میکند', () => {
|
||||
assert.deepEqual(run(BSJ, 'بنکداری'), ['a1']);
|
||||
assert.deepEqual(run(BSJ, 'آنلاین شاپ'), ['a2']);
|
||||
assert.deepEqual(run(BSJ, 'ویترین نقره'), ['a3']);
|
||||
});
|
||||
|
||||
it('چند تیک = چند فعالیت', () => {
|
||||
assert.deepEqual(run(BSJ, 'بنکداری, ویترین نقره'), ['a1', 'a3']);
|
||||
assert.deepEqual(run(BSJ, 'بنکداری, آنلاین شاپ, ویترین نقره'), ['a1', 'a2', 'a3']);
|
||||
assert.deepEqual(run(BSJ, ''), []);
|
||||
});
|
||||
|
||||
it('شرطهای پشتسرهم با «و» ترکیب میشوند', () => {
|
||||
const steps = [cond('c1', 'بنکداری'), cond('c2', 'آنلاین شاپ'), act('a1'), act('a2')];
|
||||
assert.deepEqual(run(steps, 'بنکداری'), []);
|
||||
assert.deepEqual(run(steps, 'بنکداری, آنلاین شاپ'), ['a1', 'a2']);
|
||||
});
|
||||
|
||||
it('حالت stop رفتار قدیمی را حفظ میکند', () => {
|
||||
assert.deepEqual(run(BSJ, 'آنلاین شاپ', 'stop'), []);
|
||||
assert.deepEqual(run(BSJ, 'بنکداری, آنلاین شاپ, ویترین نقره', 'stop'), ['a1', 'a2', 'a3']);
|
||||
assert.deepEqual(
|
||||
planAutomationActions([act('a0')], undefined, () => false).map((s) => s.id),
|
||||
['a0'],
|
||||
);
|
||||
});
|
||||
|
||||
it('تقسیم نوبتی مساوی و پایدار', () => {
|
||||
const team = ['u3', 'u1', 'u2'];
|
||||
const picks = [1, 2, 3, 4, 5, 6].map((n) => pickRoundRobin(team, n));
|
||||
assert.deepEqual(picks, ['u1', 'u2', 'u3', 'u1', 'u2', 'u3']);
|
||||
assert.equal(pickRoundRobin([], 1), null);
|
||||
assert.equal(pickRoundRobin(['u1', 'u1'], 2), 'u1');
|
||||
});
|
||||
|
||||
it('جایگذاری متغیرها و خلاصهٔ پاسخها', () => {
|
||||
const text = renderAutomationTemplate('تماس با {{title}} ({{mobile}}) — {{field.coop_type}} از {{form}}', {
|
||||
title: 'علی',
|
||||
mobile: '0912',
|
||||
formName: 'BSJ',
|
||||
formValues: answers('بنکداری'),
|
||||
});
|
||||
assert.equal(text, 'تماس با علی (0912) — بنکداری از BSJ');
|
||||
assert.equal(
|
||||
formatFormAnswers([{ key: KEY, label: 'نوع همکاری' }], { [KEY]: 'بنکداری', extra: 'x' }),
|
||||
'نوع همکاری: بنکداری\nextra: x',
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user