2022-08-09 21:39:00 +00:00
|
|
|
// Copyright 2022 Signal Messenger, LLC
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
|
|
|
import { assert } from 'chai';
|
|
|
|
|
|
|
|
import { strictAssert } from '../util/assert';
|
|
|
|
|
|
|
|
import type { ConversationModel } from '../models/conversations';
|
2023-08-10 16:43:33 +00:00
|
|
|
import type { AciString, PniString, ServiceIdString } from '../types/ServiceId';
|
|
|
|
import { generateAci, generatePni } from '../types/ServiceId';
|
2022-12-05 22:46:54 +00:00
|
|
|
import type { SafeCombineConversationsParams } from '../ConversationController';
|
2022-08-09 21:39:00 +00:00
|
|
|
|
2023-08-10 16:43:33 +00:00
|
|
|
const ACI_1 = generateAci();
|
|
|
|
const ACI_2 = generateAci();
|
2022-08-09 21:39:00 +00:00
|
|
|
const E164_1 = '+14155550111';
|
|
|
|
const E164_2 = '+14155550112';
|
2023-08-10 16:43:33 +00:00
|
|
|
const PNI_1 = generatePni();
|
|
|
|
const PNI_2 = generatePni();
|
2022-08-09 21:39:00 +00:00
|
|
|
const reason = 'test';
|
|
|
|
|
|
|
|
type ParamsType = {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId?: ServiceIdString;
|
2023-08-10 16:43:33 +00:00
|
|
|
aci?: AciString;
|
2022-08-09 21:39:00 +00:00
|
|
|
e164?: string;
|
2023-08-10 16:43:33 +00:00
|
|
|
pni?: PniString;
|
2022-08-09 21:39:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
describe('ConversationController', () => {
|
|
|
|
describe('maybeMergeContacts', () => {
|
2022-12-05 22:46:54 +00:00
|
|
|
let mergeOldAndNew: (
|
|
|
|
options: SafeCombineConversationsParams
|
|
|
|
) => Promise<void>;
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
await window.Signal.Data._removeAllConversations();
|
|
|
|
|
|
|
|
window.ConversationController.reset();
|
|
|
|
await window.ConversationController.load();
|
2022-12-05 22:46:54 +00:00
|
|
|
await window.textsecure.storage.protocol.hydrateCaches();
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
mergeOldAndNew = () => {
|
|
|
|
throw new Error('mergeOldAndNew: Should not be called!');
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
2022-08-09 23:46:01 +00:00
|
|
|
it('throws when provided no data', () => {
|
|
|
|
assert.throws(() => {
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
reason,
|
|
|
|
});
|
|
|
|
}, 'Need to provide at least one');
|
2022-08-09 21:39:00 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
function create(
|
|
|
|
name: string,
|
2023-08-16 20:54:39 +00:00
|
|
|
{ serviceId: maybeServiceId, aci, e164, pni }: ParamsType
|
2022-08-09 21:39:00 +00:00
|
|
|
): ConversationModel {
|
2023-08-16 20:54:39 +00:00
|
|
|
const identifier = aci || maybeServiceId || e164 || pni;
|
|
|
|
const serviceId = aci || maybeServiceId || pni;
|
2022-08-09 21:39:00 +00:00
|
|
|
|
2023-08-16 20:54:39 +00:00
|
|
|
strictAssert(identifier, 'create needs aci, e164, pni, or serviceId');
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
const conversation = window.ConversationController.getOrCreate(
|
|
|
|
identifier,
|
|
|
|
'private',
|
2023-08-16 20:54:39 +00:00
|
|
|
{ serviceId, e164, pni }
|
2022-08-09 21:39:00 +00:00
|
|
|
);
|
2023-08-16 20:54:39 +00:00
|
|
|
expectLookups(conversation, name, { serviceId, aci, e164, pni });
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
return conversation;
|
|
|
|
}
|
|
|
|
|
|
|
|
function expectLookups(
|
|
|
|
conversation: ConversationModel | undefined,
|
|
|
|
name: string,
|
2023-08-16 20:54:39 +00:00
|
|
|
{ serviceId, aci, e164, pni }: ParamsType
|
2022-08-09 21:39:00 +00:00
|
|
|
) {
|
|
|
|
assert.exists(conversation, `${name} conversation exists`);
|
|
|
|
|
|
|
|
// Verify that this conversation hasn't been deleted
|
|
|
|
assert.strictEqual(
|
|
|
|
window.ConversationController.get(conversation?.id)?.id,
|
|
|
|
conversation?.id,
|
|
|
|
`${name} vs. lookup by id`
|
|
|
|
);
|
|
|
|
|
2023-08-16 20:54:39 +00:00
|
|
|
if (serviceId) {
|
2022-08-09 21:39:00 +00:00
|
|
|
assert.strictEqual(
|
2023-08-16 20:54:39 +00:00
|
|
|
window.ConversationController.get(serviceId)?.id,
|
2022-08-09 21:39:00 +00:00
|
|
|
conversation?.id,
|
2023-08-16 20:54:39 +00:00
|
|
|
`${name} vs. lookup by serviceId`
|
2022-08-09 21:39:00 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
if (aci) {
|
|
|
|
assert.strictEqual(
|
|
|
|
window.ConversationController.get(aci)?.id,
|
|
|
|
conversation?.id,
|
|
|
|
`${name} vs. lookup by aci`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (e164) {
|
|
|
|
assert.strictEqual(
|
|
|
|
window.ConversationController.get(e164)?.id,
|
|
|
|
conversation?.id,
|
|
|
|
`${name} vs. lookup by e164`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (pni) {
|
|
|
|
assert.strictEqual(
|
|
|
|
window.ConversationController.get(pni)?.id,
|
|
|
|
conversation?.id,
|
|
|
|
`${name} vs. lookup by pni`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function expectPropsAndLookups(
|
|
|
|
conversation: ConversationModel | undefined,
|
|
|
|
name: string,
|
2023-08-16 20:54:39 +00:00
|
|
|
{ serviceId, aci, e164, pni }: ParamsType
|
2022-08-09 21:39:00 +00:00
|
|
|
) {
|
|
|
|
assert.exists(conversation, `${name} conversation exists`);
|
|
|
|
assert.strictEqual(
|
2023-08-16 20:54:39 +00:00
|
|
|
conversation?.getServiceId(),
|
|
|
|
aci || serviceId,
|
|
|
|
`${name} serviceId matches`
|
2022-08-09 21:39:00 +00:00
|
|
|
);
|
|
|
|
assert.strictEqual(
|
|
|
|
conversation?.get('e164'),
|
|
|
|
e164,
|
|
|
|
`${name} e164 matches`
|
|
|
|
);
|
2023-08-16 20:54:39 +00:00
|
|
|
assert.strictEqual(conversation?.getPni(), pni, `${name} pni matches`);
|
2022-08-09 21:39:00 +00:00
|
|
|
|
2023-08-16 20:54:39 +00:00
|
|
|
expectLookups(conversation, name, { serviceId, e164, pni });
|
2022-08-09 21:39:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function expectDeleted(conversation: ConversationModel, name: string) {
|
|
|
|
assert.isUndefined(
|
|
|
|
window.ConversationController.get(conversation.id),
|
|
|
|
`${name} has been deleted`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
describe('non-destructive updates', () => {
|
|
|
|
it('creates a new conversation with just ACI if no matches', () => {
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: second } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
expectPropsAndLookups(second, 'second', {
|
|
|
|
aci: ACI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, second?.id, 'result and second match');
|
|
|
|
});
|
|
|
|
it('creates a new conversation with just e164 if no matches', () => {
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
e164: E164_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
expectPropsAndLookups(result, 'result', {
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: second } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
e164: E164_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
expectPropsAndLookups(second, 'second', {
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, second?.id, 'result and second match');
|
|
|
|
});
|
2022-08-17 23:12:38 +00:00
|
|
|
it('creates a new conversation with e164+PNI if no matches', () => {
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-17 23:12:38 +00:00
|
|
|
|
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-17 23:12:38 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: second } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-17 23:12:38 +00:00
|
|
|
|
|
|
|
expectPropsAndLookups(second, 'second', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-17 23:12:38 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, second?.id, 'result and second match');
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
it('creates a new conversation with all data if no matches', () => {
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: second } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
expectPropsAndLookups(second, 'second', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, second?.id, 'result and second match');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('fetches all-data conversation with ACI-only query', () => {
|
|
|
|
const initial = create('initial', {
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, initial?.id, 'result and initial match');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('fetches all-data conversation with e164+PNI query', () => {
|
|
|
|
const initial = create('initial', {
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, initial?.id, 'result and initial match');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('adds ACI to conversation with e164+PNI', () => {
|
|
|
|
const initial = create('initial', {
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(initial?.id, result?.id, 'result and initial match');
|
|
|
|
});
|
2022-08-09 23:46:01 +00:00
|
|
|
it('adds ACI (via ACI+PNI) to conversation with e164+PNI', () => {
|
|
|
|
const initial = create('initial', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-09 23:46:01 +00:00
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
expectPropsAndLookups(initial, 'initial', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-09 23:46:01 +00:00
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 23:46:01 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 23:46:01 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(initial?.id, result?.id, 'result and initial match');
|
|
|
|
});
|
|
|
|
|
2022-08-09 21:39:00 +00:00
|
|
|
it('adds e164+PNI to conversation with just ACI', () => {
|
|
|
|
const initial = create('initial', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, initial?.id, 'result and initial match');
|
|
|
|
});
|
|
|
|
it('adds e164 to conversation with ACI+PNI', () => {
|
|
|
|
const initial = create('initial', {
|
|
|
|
aci: ACI_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, initial?.id, 'result and initial match');
|
|
|
|
});
|
|
|
|
it('adds PNI to conversation with ACI+e164', () => {
|
|
|
|
const initial = create('initial', {
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(initial?.id, result?.id, 'result and initial match');
|
|
|
|
});
|
|
|
|
it('adds PNI to conversation with just e164', () => {
|
|
|
|
const initial = create('initial', {
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(initial?.id, result?.id, 'result and initial match');
|
|
|
|
});
|
|
|
|
it('adds PNI+ACI to conversation with just e164', () => {
|
|
|
|
const initial = create('initial', {
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(initial?.id, result?.id, 'result and initial match');
|
|
|
|
});
|
|
|
|
it('adds ACI+e164 to conversation with just PNI', () => {
|
|
|
|
const initial = create('initial', {
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(initial?.id, result?.id, 'result and initial match');
|
|
|
|
});
|
|
|
|
|
2023-08-16 20:54:39 +00:00
|
|
|
it('promotes PNI used as generic serviceId to be in the PNI field as well', () => {
|
2022-08-09 21:39:00 +00:00
|
|
|
const initial = create('initial', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
expectPropsAndLookups(initial, 'initial', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(initial?.id, result?.id, 'result and initial match');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with destructive updates', () => {
|
|
|
|
it('replaces e164+PNI in conversation with matching ACI', () => {
|
|
|
|
const initial = create('initial', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_2,
|
|
|
|
pni: PNI_2,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_2,
|
|
|
|
pni: PNI_2,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.isUndefined(
|
|
|
|
window.ConversationController.get(E164_1),
|
|
|
|
'old e164 no longer found'
|
|
|
|
);
|
|
|
|
assert.isUndefined(
|
|
|
|
window.ConversationController.get(PNI_1),
|
|
|
|
'old pni no longer found'
|
|
|
|
);
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, initial?.id, 'result and initial match');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('replaces PNI in conversation with e164+PNI', () => {
|
|
|
|
const initial = create('initial', {
|
|
|
|
pni: PNI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
pni: PNI_2,
|
|
|
|
e164: E164_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_2,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_2,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.isUndefined(
|
|
|
|
window.ConversationController.get(PNI_1),
|
|
|
|
'old pni no longer found'
|
|
|
|
);
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, initial?.id, 'result and initial match');
|
|
|
|
});
|
2023-03-24 00:52:46 +00:00
|
|
|
it('adds PNI to conversation with e164+ACI', () => {
|
|
|
|
const initial = create('initial', {
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
pni: PNI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
reason,
|
|
|
|
});
|
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2023-03-24 00:52:46 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, initial?.id, 'result and initial match');
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
it('replaces PNI in conversation with all data', () => {
|
|
|
|
const initial = create('initial', {
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_2,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_2,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert.isUndefined(
|
|
|
|
window.ConversationController.get(PNI_1),
|
|
|
|
'old pni no longer found'
|
|
|
|
);
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, initial?.id, 'result and initial match');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('removes e164+PNI from previous conversation with an ACI, adds all data to new conversation', () => {
|
|
|
|
const initial = create('initial', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_2,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_2,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2023-08-16 20:54:39 +00:00
|
|
|
expectPropsAndLookups(initial, 'initial', { serviceId: ACI_1 });
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
assert.notStrictEqual(
|
|
|
|
initial?.id,
|
|
|
|
result?.id,
|
|
|
|
'result and initial should not match'
|
|
|
|
);
|
|
|
|
});
|
|
|
|
it('removes e164+PNI from previous conversation with an ACI, adds to ACI match', () => {
|
|
|
|
const initial = create('initial', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
const aciOnly = create('aciOnly', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_2,
|
2022-08-09 21:39:00 +00:00
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_2,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(aciOnly, 'aciOnly', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_2,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2023-08-16 20:54:39 +00:00
|
|
|
expectPropsAndLookups(initial, 'initial', { serviceId: ACI_1 });
|
2022-08-09 21:39:00 +00:00
|
|
|
|
|
|
|
assert.strictEqual(
|
|
|
|
aciOnly?.id,
|
|
|
|
result?.id,
|
|
|
|
'result and aciOnly should match'
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('removes PNI from previous conversation, adds it to e164-only match', () => {
|
|
|
|
const withE164 = create('withE164', {
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
const withPNI = create('withPNI', {
|
|
|
|
e164: E164_2,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
expectPropsAndLookups(withPNI, 'withPNI', { e164: E164_2 });
|
|
|
|
|
|
|
|
assert.strictEqual(
|
|
|
|
withE164?.id,
|
|
|
|
result?.id,
|
|
|
|
'result and initial should match'
|
|
|
|
);
|
|
|
|
});
|
|
|
|
it('removes PNI from previous conversation, adds it new e164+PNI conversation', () => {
|
|
|
|
const initial = create('initial', {
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
e164: E164_2,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_2,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
expectPropsAndLookups(initial, 'initial', { e164: E164_1 });
|
|
|
|
|
|
|
|
assert.notStrictEqual(
|
|
|
|
initial?.id,
|
|
|
|
result?.id,
|
|
|
|
'result and initial should not match'
|
|
|
|
);
|
|
|
|
});
|
|
|
|
it('deletes PNI-only previous conversation, adds it to e164 match', () => {
|
2022-12-05 22:46:54 +00:00
|
|
|
mergeOldAndNew = ({ obsolete }) => {
|
|
|
|
window.ConversationController.dangerouslyRemoveById(obsolete.id);
|
2022-08-09 21:39:00 +00:00
|
|
|
return Promise.resolve();
|
|
|
|
};
|
|
|
|
|
|
|
|
const withE164 = create('withE164', {
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
const withPNI = create('withPNI', {
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
expectDeleted(withPNI, 'withPNI');
|
|
|
|
|
|
|
|
assert.strictEqual(
|
|
|
|
withE164?.id,
|
|
|
|
result?.id,
|
|
|
|
'result and initial should match'
|
|
|
|
);
|
|
|
|
});
|
2023-08-16 20:54:39 +00:00
|
|
|
it('deletes previous conversation with PNI as serviceId only, adds it to e164 match', () => {
|
2022-12-05 22:46:54 +00:00
|
|
|
mergeOldAndNew = ({ obsolete }) => {
|
|
|
|
window.ConversationController.dangerouslyRemoveById(obsolete.id);
|
2022-08-09 21:39:00 +00:00
|
|
|
return Promise.resolve();
|
|
|
|
};
|
|
|
|
|
|
|
|
const withE164 = create('withE164', {
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
const withPNI = create('withPNI', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: PNI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
expectDeleted(withPNI, 'withPNI');
|
|
|
|
|
|
|
|
assert.strictEqual(
|
|
|
|
withE164?.id,
|
|
|
|
result?.id,
|
|
|
|
'result and initial should match'
|
|
|
|
);
|
|
|
|
});
|
|
|
|
it('deletes e164+PNI previous conversation, adds data to ACI match', () => {
|
2022-12-05 22:46:54 +00:00
|
|
|
mergeOldAndNew = ({ obsolete }) => {
|
|
|
|
window.ConversationController.dangerouslyRemoveById(obsolete.id);
|
2022-08-09 21:39:00 +00:00
|
|
|
return Promise.resolve();
|
|
|
|
};
|
|
|
|
|
|
|
|
const withE164 = create('withE164', {
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
const withACI = create('withPNI', {
|
|
|
|
aci: ACI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
expectDeleted(withE164, 'withE164');
|
|
|
|
|
|
|
|
assert.strictEqual(
|
|
|
|
withACI?.id,
|
|
|
|
result?.id,
|
|
|
|
'result and initial should match'
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('handles three matching conversations: ACI-only, with E164, and with PNI', () => {
|
|
|
|
const withACI = create('withACI', {
|
|
|
|
aci: ACI_1,
|
|
|
|
});
|
|
|
|
const withE164 = create('withE164', {
|
|
|
|
aci: ACI_2,
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
const withPNI = create('withPNI', {
|
|
|
|
pni: PNI_1,
|
|
|
|
e164: E164_2,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
expectPropsAndLookups(withE164, 'withE164', { aci: ACI_2 });
|
|
|
|
expectPropsAndLookups(withPNI, 'withPNI', { e164: E164_2 });
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, withACI?.id, 'result and withACI match');
|
|
|
|
});
|
|
|
|
it('handles three matching conversations: ACI-only, E164-only (deleted), and with PNI', () => {
|
2022-12-05 22:46:54 +00:00
|
|
|
mergeOldAndNew = ({ obsolete }) => {
|
|
|
|
window.ConversationController.dangerouslyRemoveById(obsolete.id);
|
2022-08-09 21:39:00 +00:00
|
|
|
return Promise.resolve();
|
|
|
|
};
|
|
|
|
|
|
|
|
const withACI = create('withACI', {
|
|
|
|
aci: ACI_1,
|
|
|
|
});
|
|
|
|
const withE164 = create('withE164', {
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
const withPNI = create('withPNI', {
|
|
|
|
pni: PNI_1,
|
|
|
|
e164: E164_2,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
expectPropsAndLookups(withPNI, 'withPNI', { e164: E164_2 });
|
|
|
|
|
|
|
|
expectDeleted(withE164, 'withE164');
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, withACI?.id, 'result and withACI match');
|
|
|
|
});
|
|
|
|
it('merges three matching conversations: ACI-only, E164-only (deleted), PNI-only (deleted)', () => {
|
2022-12-05 22:46:54 +00:00
|
|
|
mergeOldAndNew = ({ obsolete }) => {
|
|
|
|
window.ConversationController.dangerouslyRemoveById(obsolete.id);
|
2022-08-09 21:39:00 +00:00
|
|
|
return Promise.resolve();
|
|
|
|
};
|
|
|
|
|
|
|
|
const withACI = create('withACI', {
|
|
|
|
aci: ACI_1,
|
|
|
|
});
|
|
|
|
const withE164 = create('withE164', {
|
|
|
|
e164: E164_1,
|
|
|
|
});
|
|
|
|
const withPNI = create('withPNI', {
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
2022-12-05 22:46:54 +00:00
|
|
|
const { conversation: result } =
|
|
|
|
window.ConversationController.maybeMergeContacts({
|
|
|
|
mergeOldAndNew,
|
|
|
|
aci: ACI_1,
|
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
reason,
|
|
|
|
});
|
2022-08-09 21:39:00 +00:00
|
|
|
expectPropsAndLookups(result, 'result', {
|
2023-08-16 20:54:39 +00:00
|
|
|
serviceId: ACI_1,
|
2022-08-09 21:39:00 +00:00
|
|
|
e164: E164_1,
|
|
|
|
pni: PNI_1,
|
|
|
|
});
|
|
|
|
|
|
|
|
expectDeleted(withPNI, 'withPNI');
|
|
|
|
expectDeleted(withE164, 'withE164');
|
|
|
|
|
|
|
|
assert.strictEqual(result?.id, withACI?.id, 'result and withACI match');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|