Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions __tests__/triggers/greeting-and-acquaintance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const { trigger: greetingAndAcquaintanceTrigger, combinedResponses, containsGreetingAndAcquaintance } = require('../../triggers/greeting-and-acquaintance');
const { enqueueMessage } = require('../../outgoing-messages');
jest.mock('../../outgoing-messages');

const triggerDescription = 'greeting and acquaintance trigger';

describe(triggerDescription, () => {
beforeEach(() => {
enqueueMessage.mockClear();
});

test.each([
['Привет! Мы знакомы?'],
['Привет. Мы знакомы?'],
['Привет, мы знакомы с тобой?'],
['Приветик! Мы знакомы?'],
['Здравствуйте! Мы знакомы?'],
['🖐 Мы знакомы?'],
['👋 Мы знакомы с тобой?'],
['Мы знакомы? Привет!'],
['Знакомы мы? Привет'],
['Привет, знакомы мы?'],
['Салют! Мы знакомы?'],
['Хай! Мы знакомы с тобой?'],
])(`"%s" message matches ${triggerDescription} and gives expected response`, (incomingMessage) => {
const context = { request: { isFromUser: true, isOutbox: false, text: incomingMessage, attachments: [] } };
expect(greetingAndAcquaintanceTrigger.condition(context)).toBe(true);
if (greetingAndAcquaintanceTrigger.condition(context)) {
greetingAndAcquaintanceTrigger.action(context);
}
expect(enqueueMessage).toHaveBeenCalled();
const callArg = enqueueMessage.mock.calls[0][0];
expect(callArg).toEqual(expect.objectContaining(context));
expect(combinedResponses).toContain(callArg.response.message);
});

test.each([
['Привет'],
['Мы знакомы?'],
['Как дела?'],
['Здравствуйте, как у вас дела?'],
])(`"%s" message does not match ${triggerDescription} (missing greeting or acquaintance)`, (incomingMessage) => {
const context = { request: { isFromUser: true, isOutbox: false, text: incomingMessage, attachments: [] } };
expect(greetingAndAcquaintanceTrigger.condition(context)).toBe(false);
});

test('greeting sticker + acquaintance text matches trigger', () => {
const context = {
request: {
isFromUser: true,
isOutbox: false,
text: 'Мы знакомы?',
attachments: [{ id: 72789 }] // greeting sticker
}
};
expect(greetingAndAcquaintanceTrigger.condition(context)).toBe(true);
});

test('containsGreetingAndAcquaintance function works correctly', () => {
expect(containsGreetingAndAcquaintance('Привет! Мы знакомы?', [])).toBe(true);
expect(containsGreetingAndAcquaintance('Привет', [])).toBe(false);
expect(containsGreetingAndAcquaintance('Мы знакомы?', [])).toBe(false);
expect(containsGreetingAndAcquaintance('Мы знакомы?', [{ id: 72789 }])).toBe(true);
});
});
3 changes: 2 additions & 1 deletion triggers/acquaintance.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,6 @@ const trigger = {

module.exports = {
trigger,
acquaintanceSuggestions
acquaintanceSuggestions,
acquaintedRegex
};
63 changes: 63 additions & 0 deletions triggers/greeting-and-acquaintance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const { getRandomElement, hasSticker } = require('../utils');
const { enqueueMessage } = require('../outgoing-messages');
const { DateTime } = require('luxon');
const { incomingGreetingStickersIds } = require('./greeting');

// Combined responses for greeting + acquaintance question
const combinedResponses = [
"Привет! Ещё нет, но давай исправим. Я программист. А ты? (можно на ты?)",
"Привет! Мы не знакомы, но можем познакомиться. Я программист, а ты? (можем на ты?)",
"Привет! Нет, ещё не знакомы. Я программист :)",
"Привет! Нет, мы не знакомы. Я программист, а ты? (не против, что на ты?)",
"Привет! Ещё нет, я программист, предлагаю дружбу :)",
"Привет! Ещё нет, я программист, а ты? (можем перейти на ты?)",
"Привет! Не встречались ранее. Давай познакомимся. Я программист, а ты? (переходим на ты?)",
"Привет! Пока не знакомы, но можно это исправить. Я программист. А ты? (можно на ты?)",
"Привет! Ещё нет, но я всегда рад новым знакомствам. Я программист, а ты? (продолжим на ты?)",
"Привет! Пока что нет. Давай познакомимся? Я программист, а ты чем занимаешься? (мы на ты?)",
"Привет! Пока еще не знакомы. Исправим это? Я программист. А ты? (можно на ты?)",
"Привет! Мы еще не знакомы. Давай это исправим? Я программист. А ты? (перейдем на ты?)",
];

// Partial regex patterns to match within a message (not requiring full message match)
const greetingPartialRegex = /(трям|🖖|👋|🖐|мо[иё] приветстви[ея]|салам|салют|з?д[ао]ров[ао]?|ку|q+|шалом|хай|хэллоу|йоу?|привет(ствую|ики?)?|здрав?с(твуй|ь)?(те)?|дд|((день|вечер)[^\p{L}]+)?добр(ый([^\p{L}]*(день|вечер))?|ое[^\p{L}]*утро|ой[^\p{L}]*ночи|ого[^\p{L}]*времени[^\p{L}]*суток))/ui;
// Match acquaintance question - look for "знакомы" followed by "?" anywhere in the text
const acquaintancePartialRegex = /знакомы[^\?]*\?/ui;

// Check if message contains both greeting and acquaintance question
function containsGreetingAndAcquaintance(text, attachments) {
const hasGreeting = greetingPartialRegex.test(text) || hasSticker({ attachments }, incomingGreetingStickersIds);
const hasAcquaintance = acquaintancePartialRegex.test(text);
return hasGreeting && hasAcquaintance;
}

const trigger = {
name: "GreetingAndAcquaintanceTrigger",
condition: (context) => {
if (!context?.request?.isFromUser) {
return false;
}

const now = DateTime.now();
const lastTriggered = context?.state?.triggers?.[trigger.name]?.lastTriggered;
const lastTriggeredDiff = lastTriggered ? now.diff(lastTriggered, 'days').days : Number.MAX_SAFE_INTEGER;

return lastTriggeredDiff >= 1
&& !context?.request?.isOutbox
&& containsGreetingAndAcquaintance(context.request.text || '', context.request.attachments);
},
action: (context) => {
enqueueMessage({
...context,
response: {
message: getRandomElement(combinedResponses)
}
});
}
};

module.exports = {
trigger,
combinedResponses,
containsGreetingAndAcquaintance
};