mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
124 lines
4.8 KiB
TypeScript
124 lines
4.8 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
const testState = vi.hoisted(() => ({
|
|
consoleErrorMock: vi.fn(),
|
|
communities: {} as Record<string, { roles?: Record<string, { role?: string }> }>,
|
|
}));
|
|
|
|
vi.mock('@bitsocial/bitsocial-react-hooks/dist/stores/communities', () => ({
|
|
default: {
|
|
getState: () => ({
|
|
communities: testState.communities,
|
|
}),
|
|
},
|
|
}));
|
|
|
|
import { commentMatchesPattern, displayNameMatchesPattern, matchesPattern, parsePattern, userHasRole, userIdMatchesPattern } from '../pattern-utils';
|
|
|
|
describe('pattern-utils', () => {
|
|
let consoleErrorSpy: ReturnType<typeof vi.spyOn>;
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
testState.communities = {
|
|
'music-posting.eth': {
|
|
roles: {
|
|
'author-1': { role: 'moderator' },
|
|
'author-2': { role: 'owner' },
|
|
},
|
|
},
|
|
};
|
|
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(testState.consoleErrorMock);
|
|
});
|
|
|
|
afterEach(() => {
|
|
consoleErrorSpy.mockRestore();
|
|
});
|
|
|
|
it('matches whole words, exact phrases, regexes, wildcards, and logical operators', () => {
|
|
expect(matchesPattern('That feel when the girlfriend texts back', 'feel')).toBe(true);
|
|
expect(matchesPattern('That feel when the girlfriend texts back', 'feels')).toBe(false);
|
|
expect(matchesPattern('That feel when the girlfriend texts back', 'feel girlfriend')).toBe(true);
|
|
expect(matchesPattern('That feel when the girlfriend texts back', 'girlfriend|boyfriend feel')).toBe(true);
|
|
expect(matchesPattern('That feel when the girlfriend texts back', '"feel when the girlfriend"')).toBe(true);
|
|
expect(matchesPattern('That feeling stays forever', 'feel*')).toBe(true);
|
|
expect(matchesPattern('MIXED Case Example', '/mixed case example/i')).toBe(true);
|
|
});
|
|
|
|
it('falls back to a simple include when pattern parsing throws', () => {
|
|
expect(matchesPattern('the broken marker foo(', 'foo(')).toBe(true);
|
|
expect(consoleErrorSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it('matches user ids through full and short addresses', () => {
|
|
const comment = {
|
|
author: {
|
|
address: '12D3KooWabcdef',
|
|
shortAddress: '12D3KooWabc',
|
|
},
|
|
};
|
|
|
|
expect(userIdMatchesPattern(comment as never, 'abcdef')).toBe(true);
|
|
expect(userIdMatchesPattern(comment as never, '12D3KooWabc')).toBe(true);
|
|
expect(userIdMatchesPattern(comment as never, 'missing')).toBe(false);
|
|
});
|
|
|
|
it('matches display names case-insensitively and treats anonymous as undefined display names', () => {
|
|
expect(displayNameMatchesPattern({ author: { displayName: 'Alice' } } as never, 'alice')).toBe(true);
|
|
expect(displayNameMatchesPattern({ author: {} } as never, 'anonymous')).toBe(true);
|
|
expect(displayNameMatchesPattern({ author: { displayName: 'Bob' } } as never, 'anonymous')).toBe(false);
|
|
});
|
|
|
|
it('matches roles with moderator aliases and rejects missing role metadata', () => {
|
|
const modComment = {
|
|
author: { address: 'author-1' },
|
|
communityAddress: 'music-posting.eth',
|
|
};
|
|
const ownerComment = {
|
|
author: { address: 'author-2' },
|
|
communityAddress: 'music-posting.eth',
|
|
};
|
|
|
|
expect(userHasRole(modComment as never, 'moderator')).toBe(true);
|
|
expect(userHasRole(modComment as never, 'mod')).toBe(true);
|
|
expect(userHasRole(ownerComment as never, 'owner')).toBe(true);
|
|
expect(userHasRole(ownerComment as never, 'admin')).toBe(false);
|
|
expect(userHasRole({ author: { address: 'missing' }, communityAddress: 'unknown.eth' } as never, 'moderator')).toBe(false);
|
|
});
|
|
|
|
it('parses mixed special filters and content filters', () => {
|
|
expect(parsePattern('#abc ##Alice #!#mod exact phrase')).toEqual({
|
|
contentFilter: 'exact phrase',
|
|
specialFilters: [
|
|
{ type: 'userId', value: 'abc' },
|
|
{ type: 'displayName', value: 'Alice' },
|
|
{ type: 'role', value: 'mod' },
|
|
],
|
|
});
|
|
expect(parsePattern('')).toEqual({
|
|
contentFilter: '',
|
|
specialFilters: [],
|
|
});
|
|
});
|
|
|
|
it('matches comments against combined special filters and content filters', () => {
|
|
const comment = {
|
|
author: {
|
|
address: 'author-1',
|
|
displayName: 'Alice',
|
|
shortAddress: 'auth1',
|
|
},
|
|
content: 'That feel when the girlfriend texts back',
|
|
communityAddress: 'music-posting.eth',
|
|
title: 'TFW',
|
|
};
|
|
|
|
expect(commentMatchesPattern(comment as never, '#auth1 ##Alice #!#moderator girlfriend')).toBe(true);
|
|
expect(commentMatchesPattern(comment as never, '#auth1 ##Bob #!#moderator girlfriend')).toBe(false);
|
|
expect(commentMatchesPattern(comment as never, '#auth1')).toBe(true);
|
|
expect(commentMatchesPattern(comment as never, '##Alice')).toBe(true);
|
|
expect(commentMatchesPattern(comment as never, '#!#mod')).toBe(true);
|
|
expect(commentMatchesPattern(comment as never, 'tfw girlfriend')).toBe(true);
|
|
});
|
|
});
|