signal-desktop/ts/test-node/quill/mentions/matchers_test.ts

202 lines
4.8 KiB
TypeScript
Raw Normal View History

2023-01-03 19:55:46 +00:00
// Copyright 2020 Signal Messenger, LLC
2020-11-03 01:19:52 +00:00
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import type { RefObject } from 'react';
2020-11-03 01:19:52 +00:00
import Delta from 'quill-delta';
2023-08-16 20:54:39 +00:00
import type { AciString } from '../../../types/ServiceId';
import { generateAci } from '../../../types/ServiceId';
2020-11-03 01:19:52 +00:00
import { matchMention } from '../../../quill/mentions/matchers';
2020-11-04 22:04:48 +00:00
import { MemberRepository } from '../../../quill/memberRepository';
import type { ConversationType } from '../../../state/ducks/conversations';
2023-08-16 20:54:39 +00:00
import { getDefaultConversationWithServiceId } from '../../../test-both/helpers/getDefaultConversation';
const ACI_1 = generateAci();
2020-11-03 01:19:52 +00:00
class FakeTokenList<T> extends Array<T> {
constructor(elements: Array<T>) {
super();
elements.forEach(element => this.push(element));
}
contains(searchElement: T) {
return this.includes(searchElement);
}
}
const createMockElement = (
className: string,
dataset: Record<string, string>
): HTMLElement =>
2021-11-11 22:43:05 +00:00
({
2020-11-03 01:19:52 +00:00
classList: new FakeTokenList([className]),
dataset,
2024-07-24 00:31:40 +00:00
}) as unknown as HTMLElement;
2020-11-03 01:19:52 +00:00
const createMockAtMentionElement = (
dataset: Record<string, string>
2021-10-20 20:46:42 +00:00
): HTMLElement => createMockElement('MessageBody__at-mention', dataset);
2020-11-03 01:19:52 +00:00
const createMockMentionBlotElement = (
dataset: Record<string, string>
): HTMLElement => createMockElement('mention-blot', dataset);
2023-08-16 20:54:39 +00:00
const memberMahershala: ConversationType = getDefaultConversationWithServiceId({
2020-11-03 01:19:52 +00:00
id: '555444',
title: 'Mahershala Ali',
firstName: 'Mahershala',
profileName: 'Mahershala A.',
type: 'direct',
lastUpdated: Date.now(),
markedUnread: false,
areWeAdmin: false,
2021-05-07 22:21:10 +00:00
});
2020-11-03 01:19:52 +00:00
2023-08-16 20:54:39 +00:00
const memberShia: ConversationType = getDefaultConversationWithServiceId({
2020-11-03 01:19:52 +00:00
id: '333222',
title: 'Shia LaBeouf',
firstName: 'Shia',
profileName: 'Shia L.',
type: 'direct',
lastUpdated: Date.now(),
markedUnread: false,
areWeAdmin: false,
2021-05-07 22:21:10 +00:00
});
2020-11-03 01:19:52 +00:00
const members: Array<ConversationType> = [memberMahershala, memberShia];
const memberRepositoryRef: RefObject<MemberRepository> = {
current: new MemberRepository(members),
};
const matcher = matchMention(memberRepositoryRef);
type Mention = {
2023-08-16 20:54:39 +00:00
aci: AciString;
2020-11-03 01:19:52 +00:00
title: string;
};
2020-11-03 01:19:52 +00:00
type MentionInsert = {
2020-11-03 01:19:52 +00:00
mention: Mention;
};
2020-11-03 01:19:52 +00:00
const isMention = (insert?: unknown): insert is MentionInsert => {
if (insert) {
2022-09-13 21:48:09 +00:00
if (Object.getOwnPropertyNames(insert).includes('mention')) {
return true;
}
2020-11-03 01:19:52 +00:00
}
return false;
};
const EMPTY_DELTA = new Delta();
describe('matchMention', () => {
it('handles an AtMentionify from clipboard', () => {
const existingAttributes = { italic: true };
2020-11-03 01:19:52 +00:00
const result = matcher(
createMockAtMentionElement({
id: memberMahershala.id,
title: memberMahershala.title,
}),
EMPTY_DELTA,
existingAttributes
2020-11-03 01:19:52 +00:00
);
const { ops } = result;
assert.isNotEmpty(ops);
const [op] = ops;
const { insert, attributes } = op;
2020-11-03 01:19:52 +00:00
if (isMention(insert)) {
2023-08-16 20:54:39 +00:00
const { title, aci } = insert.mention;
2020-11-03 01:19:52 +00:00
assert.equal(title, memberMahershala.title);
2023-08-16 20:54:39 +00:00
assert.equal(aci, memberMahershala.serviceId);
assert.deepEqual(existingAttributes, attributes, 'attributes');
2020-11-03 01:19:52 +00:00
} else {
assert.fail('insert is invalid');
}
});
it('handles an MentionBlot from clipboard', () => {
const result = matcher(
createMockMentionBlotElement({
2023-08-16 20:54:39 +00:00
aci: memberMahershala.serviceId || '',
2020-11-03 01:19:52 +00:00
title: memberMahershala.title,
}),
EMPTY_DELTA,
{}
2020-11-03 01:19:52 +00:00
);
const { ops } = result;
assert.isNotEmpty(ops);
const [op] = ops;
const { insert } = op;
if (isMention(insert)) {
2023-08-16 20:54:39 +00:00
const { title, aci } = insert.mention;
2020-11-03 01:19:52 +00:00
assert.equal(title, memberMahershala.title);
2023-08-16 20:54:39 +00:00
assert.equal(aci, memberMahershala.serviceId);
2020-11-03 01:19:52 +00:00
} else {
assert.fail('insert is invalid');
}
});
it('converts a missing AtMentionify to string', () => {
const result = matcher(
createMockAtMentionElement({
id: 'florp',
title: 'Nonexistent',
}),
EMPTY_DELTA,
{}
2020-11-03 01:19:52 +00:00
);
const { ops } = result;
assert.isNotEmpty(ops);
const [op] = ops;
const { insert } = op;
if (isMention(insert)) {
assert.fail('insert is invalid');
} else {
assert.equal(insert, '@Nonexistent');
}
});
it('converts a missing MentionBlot to string', () => {
const result = matcher(
createMockMentionBlotElement({
2023-08-16 20:54:39 +00:00
aci: ACI_1,
2020-11-03 01:19:52 +00:00
title: 'Nonexistent',
}),
EMPTY_DELTA,
{}
2020-11-03 01:19:52 +00:00
);
const { ops } = result;
assert.isNotEmpty(ops);
const [op] = ops;
const { insert } = op;
if (isMention(insert)) {
assert.fail('insert is invalid');
} else {
assert.equal(insert, '@Nonexistent');
}
});
it('passes other clipboard elements through', () => {
const result = matcher(createMockElement('ignore', {}), EMPTY_DELTA, {});
2020-11-03 01:19:52 +00:00
assert.equal(result, EMPTY_DELTA);
});
});