197 lines
5.5 KiB
TypeScript
197 lines
5.5 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
||
import { applyFilterRules } from '../src/core/filtering/filter-engine';
|
||
import { RawParticipant } from '../src/core/types/participant';
|
||
import { FilterRules } from '../src/core/types/giveaway';
|
||
|
||
describe('Filter Engine', () => {
|
||
const sampleParticipants: RawParticipant[] = [
|
||
{
|
||
platformUserId: '1',
|
||
firstName: 'Иван',
|
||
lastName: 'Иванов',
|
||
source: 'LIKES',
|
||
liked: true,
|
||
commented: true,
|
||
commentsCount: 1,
|
||
reposted: true,
|
||
subscribed: true,
|
||
isAdmin: false,
|
||
},
|
||
{
|
||
platformUserId: '2',
|
||
firstName: 'Петр',
|
||
lastName: 'Петров',
|
||
source: 'LIKES',
|
||
liked: false,
|
||
commented: true,
|
||
commentsCount: 1,
|
||
reposted: true,
|
||
subscribed: true,
|
||
isAdmin: false,
|
||
},
|
||
{
|
||
platformUserId: '3',
|
||
firstName: 'Анна',
|
||
lastName: 'Сидорова',
|
||
source: 'COMMENTS',
|
||
liked: true,
|
||
commented: false,
|
||
commentsCount: 0,
|
||
reposted: true,
|
||
subscribed: true,
|
||
isAdmin: false,
|
||
},
|
||
{
|
||
platformUserId: '4',
|
||
firstName: 'Админ',
|
||
lastName: 'Группы',
|
||
source: 'LIKES',
|
||
liked: true,
|
||
commented: true,
|
||
commentsCount: 1,
|
||
reposted: true,
|
||
subscribed: true,
|
||
isAdmin: true,
|
||
},
|
||
{
|
||
platformUserId: '5',
|
||
firstName: 'Не',
|
||
lastName: 'Подписан',
|
||
source: 'LIKES',
|
||
liked: true,
|
||
commented: true,
|
||
commentsCount: 1,
|
||
reposted: true,
|
||
subscribed: false,
|
||
isAdmin: false,
|
||
},
|
||
];
|
||
|
||
it('should filter by like requirement correctly', () => {
|
||
const rules: FilterRules = {
|
||
requireLike: true,
|
||
requireComment: false,
|
||
requireRepost: false,
|
||
requireSubscription: false,
|
||
excludeAdmins: false,
|
||
excludeBlacklistedIds: [],
|
||
excludeDuplicateComments: true,
|
||
};
|
||
|
||
const result = applyFilterRules(sampleParticipants, rules);
|
||
expect(result.stats.eligibleCount).toBe(4);
|
||
expect(result.stats.excludedCount).toBe(1);
|
||
expect(result.excludedParticipants[0].platformUserId).toBe('2');
|
||
expect(result.excludedParticipants[0].exclusionReason).toBe('MISSING_LIKE');
|
||
});
|
||
|
||
it('should filter by comment and subscription requirements', () => {
|
||
const rules: FilterRules = {
|
||
requireLike: true,
|
||
requireComment: true,
|
||
requireRepost: false,
|
||
requireSubscription: true,
|
||
excludeAdmins: false,
|
||
excludeBlacklistedIds: [],
|
||
excludeDuplicateComments: true,
|
||
};
|
||
|
||
const result = applyFilterRules(sampleParticipants, rules);
|
||
// 1: passed
|
||
// 2: missing like
|
||
// 3: missing comment
|
||
// 4: passed (admin allowed here)
|
||
// 5: not subscribed
|
||
expect(result.stats.eligibleCount).toBe(2);
|
||
const eligibleIds = result.eligibleParticipants.map(p => p.platformUserId);
|
||
expect(eligibleIds).toEqual(['1', '4']);
|
||
});
|
||
|
||
it('should exclude administrators when excludeAdmins is true', () => {
|
||
const rules: FilterRules = {
|
||
requireLike: true,
|
||
requireComment: false,
|
||
requireRepost: false,
|
||
requireSubscription: false,
|
||
excludeAdmins: true,
|
||
excludeBlacklistedIds: [],
|
||
excludeDuplicateComments: true,
|
||
};
|
||
|
||
const result = applyFilterRules(sampleParticipants, rules);
|
||
const adminParticipant = result.allParticipants.find(p => p.platformUserId === '4');
|
||
expect(adminParticipant?.eligible).toBe(false);
|
||
expect(adminParticipant?.exclusionReason).toContain('IS_ADMIN');
|
||
});
|
||
|
||
it('should exclude blacklisted user IDs and usernames', () => {
|
||
const rules: FilterRules = {
|
||
requireLike: false,
|
||
requireComment: false,
|
||
requireRepost: false,
|
||
requireSubscription: false,
|
||
excludeAdmins: false,
|
||
excludeBlacklistedIds: ['1', '5'],
|
||
excludeDuplicateComments: true,
|
||
};
|
||
|
||
const result = applyFilterRules(sampleParticipants, rules);
|
||
const blacklisted = result.excludedParticipants.map(p => p.platformUserId);
|
||
expect(blacklisted).toContain('1');
|
||
expect(blacklisted).toContain('5');
|
||
expect(result.stats.reasonsBreakdown['BLACKLISTED']).toBe(2);
|
||
});
|
||
|
||
it('should deduplicate multiple raw comments from the same user into single participant', () => {
|
||
const multiComments: RawParticipant[] = [
|
||
{
|
||
platformUserId: '100',
|
||
firstName: 'Спамер',
|
||
lastName: 'Обыкновенный',
|
||
source: 'COMMENTS',
|
||
liked: true,
|
||
commented: true,
|
||
commentsCount: 1,
|
||
reposted: false,
|
||
subscribed: true,
|
||
},
|
||
{
|
||
platformUserId: '100',
|
||
firstName: 'Спамер',
|
||
lastName: 'Обыкновенный',
|
||
source: 'COMMENTS',
|
||
liked: true,
|
||
commented: true,
|
||
commentsCount: 1,
|
||
reposted: false,
|
||
subscribed: true,
|
||
},
|
||
{
|
||
platformUserId: '100',
|
||
firstName: 'Спамер',
|
||
lastName: 'Обыкновенный',
|
||
source: 'COMMENTS',
|
||
liked: true,
|
||
commented: true,
|
||
commentsCount: 1,
|
||
reposted: false,
|
||
subscribed: true,
|
||
},
|
||
];
|
||
|
||
const rules: FilterRules = {
|
||
requireLike: true,
|
||
requireComment: true,
|
||
requireRepost: false,
|
||
requireSubscription: true,
|
||
excludeAdmins: false,
|
||
excludeBlacklistedIds: [],
|
||
excludeDuplicateComments: true,
|
||
};
|
||
|
||
const result = applyFilterRules(multiComments, rules);
|
||
expect(result.stats.total).toBe(1);
|
||
expect(result.stats.eligibleCount).toBe(1);
|
||
expect(result.allParticipants[0].commentsCount).toBe(3);
|
||
});
|
||
});
|