forked from mystiq/hydrogen-web
Add tests
This commit is contained in:
parent
640a3fb9fa
commit
6f8001bd82
1 changed files with 142 additions and 7 deletions
|
@ -252,20 +252,20 @@ export class Timeline {
|
||||||
this._addLocalRelationsToNewRemoteEntries(newEntries);
|
this._addLocalRelationsToNewRemoteEntries(newEntries);
|
||||||
this._updateFetchedEntries(newEntries);
|
this._updateFetchedEntries(newEntries);
|
||||||
this._moveFetchedEntryToRemoteEntries(newEntries);
|
this._moveFetchedEntryToRemoteEntries(newEntries);
|
||||||
this._loadRelatedEvents(newEntries);
|
|
||||||
this._remoteEntries.setManySorted(newEntries);
|
this._remoteEntries.setManySorted(newEntries);
|
||||||
|
this._loadRelatedEvents(newEntries);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update entries in contextEntriesNotInTimeline based on newly received events.
|
* Update entries based on newly received events.
|
||||||
* eg: a newly received redacted event may mark an existing event in contextEntriesNotInTimeline as being redacted
|
* eg: a newly received redacted event may mark an existing event in contextEntriesNotInTimeline as being redacted
|
||||||
*/
|
*/
|
||||||
_updateFetchedEntries(entries) {
|
_updateFetchedEntries(entries) {
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
const relatedEntry = this._contextEntriesNotInTimeline.get(entry.relatedEventId);
|
const relatedEntry = this._getTrackedEntry(entry.relatedEventId);
|
||||||
// todo: can this be called .addRelation instead?
|
// todo: can this be called .addRelation instead?
|
||||||
if (relatedEntry?.addLocalRelation(entry)) {
|
if (relatedEntry?.addLocalRelation(entry)) {
|
||||||
relatedEntry.contextForEntries.forEach(e => this._updateEntry(e));
|
relatedEntry.contextForEntries?.forEach(e => this._updateEntry(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,7 +294,7 @@ export class Timeline {
|
||||||
const entriesNeedingContext = entries.filter(e => !!e.contextEventId);
|
const entriesNeedingContext = entries.filter(e => !!e.contextEventId);
|
||||||
for (const entry of entriesNeedingContext) {
|
for (const entry of entriesNeedingContext) {
|
||||||
const id = entry.contextEventId;
|
const id = entry.contextEventId;
|
||||||
let contextEvent = this._getTrackedEvent(id);
|
let contextEvent = this._getTrackedEntry(id);
|
||||||
if (!contextEvent) {
|
if (!contextEvent) {
|
||||||
contextEvent = await this._getEventFromStorage(id) ?? await this._getEventFromHomeserver(id);
|
contextEvent = await this._getEventFromStorage(id) ?? await this._getEventFromHomeserver(id);
|
||||||
if (contextEvent) {
|
if (contextEvent) {
|
||||||
|
@ -311,7 +311,7 @@ export class Timeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_getTrackedEvent(id) {
|
_getTrackedEntry(id) {
|
||||||
return this.getByEventId(id) ?? this._contextEntriesNotInTimeline.get(id);
|
return this.getByEventId(id) ?? this._contextEntriesNotInTimeline.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +433,7 @@ import {poll} from "../../../mocks/poll.js";
|
||||||
import {Clock as MockClock} from "../../../mocks/Clock.js";
|
import {Clock as MockClock} from "../../../mocks/Clock.js";
|
||||||
import {createMockStorage} from "../../../mocks/Storage";
|
import {createMockStorage} from "../../../mocks/Storage";
|
||||||
import {ListObserver} from "../../../mocks/ListObserver.js";
|
import {ListObserver} from "../../../mocks/ListObserver.js";
|
||||||
import {createEvent, withTextBody, withContent, withSender} from "../../../mocks/event.js";
|
import {createEvent, withTextBody, withContent, withSender, withRedacts} from "../../../mocks/event.js";
|
||||||
import {NullLogItem} from "../../../logging/NullLogger";
|
import {NullLogItem} from "../../../logging/NullLogger";
|
||||||
import {EventEntry} from "./entries/EventEntry.js";
|
import {EventEntry} from "./entries/EventEntry.js";
|
||||||
import {User} from "../../User.js";
|
import {User} from "../../User.js";
|
||||||
|
@ -689,6 +689,141 @@ export function tests() {
|
||||||
assert.equal(type, "update");
|
assert.equal(type, "update");
|
||||||
assert.equal(value.eventType, "m.room.message");
|
assert.equal(value.eventType, "m.room.message");
|
||||||
assert.equal(value.content.body, "hi bob!");
|
assert.equal(value.content.body, "hi bob!");
|
||||||
|
},
|
||||||
|
|
||||||
|
"context entry is fetched from remoteEntries": async assert => {
|
||||||
|
const timeline = new Timeline({roomId, storage: await createMockStorage(), closeCallback: () => {},
|
||||||
|
fragmentIdComparer, pendingEvents: new ObservableArray(), clock: new MockClock()});
|
||||||
|
const entryA = new EventEntry({ event: withTextBody("foo", createEvent("m.room.message", "event_id_1", alice)) });
|
||||||
|
let event = withContent({
|
||||||
|
body: "bar",
|
||||||
|
msgtype: "m.text",
|
||||||
|
"m.relates_to": {
|
||||||
|
"m.in_reply_to": {
|
||||||
|
"event_id": "event_id_1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, createEvent("m.room.message", "event_id_2", bob));
|
||||||
|
const entryB = new EventEntry({ event });
|
||||||
|
await timeline.load(new User(alice), "join", new NullLogItem());
|
||||||
|
timeline._remoteEntries.setManyUnsorted([entryA, entryB]);
|
||||||
|
await timeline._loadRelatedEvents([entryA, entryB]);
|
||||||
|
assert.deepEqual(entryB.contextEntry, entryA);
|
||||||
|
},
|
||||||
|
|
||||||
|
"context entry is fetched from storage": async assert => {
|
||||||
|
const timeline = new Timeline({roomId, storage: await createMockStorage(), closeCallback: () => {},
|
||||||
|
fragmentIdComparer, pendingEvents: new ObservableArray(), clock: new MockClock()});
|
||||||
|
const entryA = new EventEntry({ event: withTextBody("foo", createEvent("m.room.message", "event_id_1", alice)) });
|
||||||
|
let event = withContent({
|
||||||
|
body: "bar",
|
||||||
|
msgtype: "m.text",
|
||||||
|
"m.relates_to": {
|
||||||
|
"m.in_reply_to": {
|
||||||
|
"event_id": "event_id_1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, createEvent("m.room.message", "event_id_2", bob));
|
||||||
|
const entryB = new EventEntry({ event });
|
||||||
|
timeline._getEventFromStorage = () => entryA
|
||||||
|
await timeline.load(new User(alice), "join", new NullLogItem());
|
||||||
|
await timeline._loadRelatedEvents([entryB]);
|
||||||
|
assert.deepEqual(entryB.contextEntry, entryA);
|
||||||
|
},
|
||||||
|
|
||||||
|
"context entry is fetched from hs": async assert => {
|
||||||
|
const timeline = new Timeline({roomId, storage: await createMockStorage(), closeCallback: () => {},
|
||||||
|
fragmentIdComparer, pendingEvents: new ObservableArray(), clock: new MockClock()});
|
||||||
|
const entryA = new EventEntry({ event: withTextBody("foo", createEvent("m.room.message", "event_id_1", alice)) });
|
||||||
|
let event = withContent({
|
||||||
|
body: "bar",
|
||||||
|
msgtype: "m.text",
|
||||||
|
"m.relates_to": {
|
||||||
|
"m.in_reply_to": {
|
||||||
|
"event_id": "event_id_1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, createEvent("m.room.message", "event_id_2", bob));
|
||||||
|
const entryB = new EventEntry({ event });
|
||||||
|
timeline._getEventFromHomeserver = () => entryA
|
||||||
|
await timeline.load(new User(alice), "join", new NullLogItem());
|
||||||
|
await timeline._loadRelatedEvents([entryB]);
|
||||||
|
assert.deepEqual(entryB.contextEntry, entryA);
|
||||||
|
},
|
||||||
|
|
||||||
|
"context entry has a list of entries to which it forms the context": async assert => {
|
||||||
|
const timeline = new Timeline({roomId, storage: await createMockStorage(), closeCallback: () => {},
|
||||||
|
fragmentIdComparer, pendingEvents: new ObservableArray(), clock: new MockClock()});
|
||||||
|
const entryA = new EventEntry({ event: withTextBody("foo", createEvent("m.room.message", "event_id_1", alice)) });
|
||||||
|
const content = {
|
||||||
|
body: "bar",
|
||||||
|
msgtype: "m.text",
|
||||||
|
"m.relates_to": {
|
||||||
|
"m.in_reply_to": {
|
||||||
|
"event_id": "event_id_1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const entryB = new EventEntry({ event: withContent(content, createEvent("m.room.message", "event_id_2", bob)) });
|
||||||
|
const entryC = new EventEntry({ event: withContent(content, createEvent("m.room.message", "event_id_3", bob)) });
|
||||||
|
await timeline.load(new User(alice), "join", new NullLogItem());
|
||||||
|
timeline._remoteEntries.setManyUnsorted([entryA, entryB, entryC]);
|
||||||
|
await timeline._loadRelatedEvents([entryA, entryB, entryC]);
|
||||||
|
assert.deepEqual(entryA.contextForEntries, [entryB, entryC]);
|
||||||
|
},
|
||||||
|
|
||||||
|
"context entry in contextEntryNotInTimeline gets updated based on incoming redaction": async assert => {
|
||||||
|
const timeline = new Timeline({roomId, storage: await createMockStorage(), closeCallback: () => {},
|
||||||
|
fragmentIdComparer, pendingEvents: new ObservableArray(), clock: new MockClock()});
|
||||||
|
const entryA = new EventEntry({ event: withTextBody("foo", createEvent("m.room.message", "event_id_1", alice)) });
|
||||||
|
let event = withContent({
|
||||||
|
body: "bar",
|
||||||
|
msgtype: "m.text",
|
||||||
|
"m.relates_to": {
|
||||||
|
"m.in_reply_to": {
|
||||||
|
"event_id": "event_id_1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, createEvent("m.room.message", "event_id_2", bob));
|
||||||
|
const entryB = new EventEntry({ event });
|
||||||
|
timeline._getEventFromStorage = () => entryA
|
||||||
|
await timeline.load(new User(alice), "join", new NullLogItem());
|
||||||
|
await timeline._loadRelatedEvents([entryB]);
|
||||||
|
const redactingEntry = new EventEntry({ event: withRedacts(entryA.id, "foo", createEvent("m.room.redaction", "event_id_3", alice)) });
|
||||||
|
await timeline.addEntries([redactingEntry]);
|
||||||
|
const contextEntry = timeline._contextEntriesNotInTimeline.get(entryA.id);
|
||||||
|
assert.strictEqual(contextEntry.isRedacted, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
"redaction of context entry triggers updates in other entries": async assert => {
|
||||||
|
const timeline = new Timeline({roomId, storage: await createMockStorage(), closeCallback: () => {},
|
||||||
|
fragmentIdComparer, pendingEvents: new ObservableArray(), clock: new MockClock()});
|
||||||
|
const entryA = new EventEntry({ event: withTextBody("foo", createEvent("m.room.message", "event_id_1", alice)) });
|
||||||
|
const content = {
|
||||||
|
body: "bar",
|
||||||
|
msgtype: "m.text",
|
||||||
|
"m.relates_to": {
|
||||||
|
"m.in_reply_to": {
|
||||||
|
"event_id": "event_id_1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const entryB = new EventEntry({ event: withContent(content, createEvent("m.room.message", "event_id_2", bob)) });
|
||||||
|
const entryC = new EventEntry({ event: withContent(content, createEvent("m.room.message", "event_id_3", bob)) });
|
||||||
|
await timeline.load(new User(alice), "join", new NullLogItem());
|
||||||
|
// timeline._getEventFromStorage = () => entryA;
|
||||||
|
await timeline.addEntries([entryA, entryB, entryC]);
|
||||||
|
const bin = [entryB, entryC];
|
||||||
|
timeline.entries.subscribe({
|
||||||
|
onUpdate: (index) => {
|
||||||
|
const i = bin.findIndex(e => e.id === index);
|
||||||
|
bin.splice(i, 1);
|
||||||
|
},
|
||||||
|
onAdd: () => { }
|
||||||
|
});
|
||||||
|
const redactingEntry = new EventEntry({ event: withRedacts(entryA.id, "foo", createEvent("m.room.redaction", "event_id_3", alice)) });
|
||||||
|
await timeline.addEntries([redactingEntry]);
|
||||||
|
assert.strictEqual(bin.length, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue