Skip to content

Commit c2a1a2d

Browse files
committed
test: more accurately simulate a remote note change
1 parent 1c26d26 commit c2a1a2d

File tree

3 files changed

+33
-5
lines changed

3 files changed

+33
-5
lines changed

src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor.component.spec.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import Quill, { Delta, EmitterSource, Range } from 'quill';
3131
import { User } from 'realtime-server/lib/esm/common/models/user';
3232
import { createTestUser } from 'realtime-server/lib/esm/common/models/user-test-data';
3333
import { WritingSystem } from 'realtime-server/lib/esm/common/models/writing-system';
34+
import { Json0OpBuilder } from 'realtime-server/lib/esm/common/utils/json0-op-builder';
3435
import { obj } from 'realtime-server/lib/esm/common/utils/obj-path';
3536
import { RecursivePartial } from 'realtime-server/lib/esm/common/utils/type-utils';
3637
import { BiblicalTerm } from 'realtime-server/lib/esm/scriptureforge/models/biblical-term';
@@ -70,6 +71,7 @@ import { CONSOLE } from 'xforge-common/browser-globals';
7071
import { BugsnagService } from 'xforge-common/bugsnag.service';
7172
import { createTestFeatureFlag, FeatureFlagService } from 'xforge-common/feature-flags/feature-flag.service';
7273
import { GenericDialogComponent, GenericDialogOptions } from 'xforge-common/generic-dialog/generic-dialog.component';
74+
import { MemoryRealtimeDocAdapter } from 'xforge-common/memory-realtime-remote-store';
7375
import { UserDoc } from 'xforge-common/models/user-doc';
7476
import { NoticeService } from 'xforge-common/notice.service';
7577
import { OnlineStatusService } from 'xforge-common/online-status.service';
@@ -3373,7 +3375,7 @@ describe('EditorComponent', () => {
33733375
env.dispose();
33743376
}));
33753377

3376-
it('should remove resolved notes after a remote update', fakeAsync(() => {
3378+
it('should remove resolved notes after a remote update', fakeAsync(async () => {
33773379
const env = new TestEnvironment();
33783380
env.setProjectUserConfig();
33793381
env.wait();
@@ -3382,7 +3384,7 @@ describe('EditorComponent', () => {
33823384
let noteThreadEmbedCount = env.countNoteThreadEmbeds(contents.ops!);
33833385
expect(noteThreadEmbedCount).toEqual(5);
33843386

3385-
env.resolveNote('project01', 'dataid01');
3387+
await env.resolveNote('project01', 'dataid01', 'remote');
33863388
contents = env.targetEditor.getContents();
33873389
noteThreadEmbedCount = env.countNoteThreadEmbeds(contents.ops!);
33883390
expect(noteThreadEmbedCount).toEqual(4);
@@ -5594,10 +5596,31 @@ class TestEnvironment {
55945596
return noteEmbedCount;
55955597
}
55965598

5597-
resolveNote(projectId: string, threadId: string): void {
5599+
async resolveNote(projectId: string, threadId: string, origin: 'local' | 'remote'): Promise<void> {
55985600
const noteDoc: NoteThreadDoc = this.getNoteThreadDoc(projectId, threadId);
5599-
noteDoc.submitJson0Op(op => op.set(n => n.status, NoteStatus.Resolved));
5600-
this.realtimeService.updateQueryAdaptersRemote();
5601+
const builder = new Json0OpBuilder(noteDoc.data);
5602+
const ops = op => op.set(n => n.status, NoteStatus.Resolved);
5603+
5604+
if (origin === 'remote') {
5605+
const docAdapter: MemoryRealtimeDocAdapter = noteDoc.adapter as MemoryRealtimeDocAdapter;
5606+
ops(builder);
5607+
const operations = builder.op;
5608+
// Don't let the doc adapter emit about changes before the query updates its result list. Otherwise code might
5609+
// hear about the change and examine the query before it is updated.
5610+
const quietAdapter = Object.assign(Object.create(Object.getPrototypeOf(docAdapter)), docAdapter, {
5611+
changes$: new Subject<any>(),
5612+
remoteChanges$: new Subject<any>()
5613+
});
5614+
// Using submitOp to simulate writing data on a remote server may seem backwards but is getting the job done.
5615+
await quietAdapter.submitOp(operations, false);
5616+
// Update the query results and emit changes. The order of emits, and presence or absence of
5617+
// RealtimeQuery.remoteDocChanges$, may be different than when running the app.
5618+
this.realtimeService.updateQueryAdaptersRemote();
5619+
docAdapter.emitChange(operations);
5620+
docAdapter.emitRemoteChange(operations);
5621+
} else {
5622+
await noteDoc.submitJson0Op(ops);
5623+
}
56015624
this.wait();
56025625
}
56035626

src/SIL.XForge.Scripture/ClientApp/src/xforge-common/memory-realtime-remote-store.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export class MemoryRealtimeRemoteStore extends RealtimeRemoteStore {
1717
// getAccessToken is not used in this memory implementation
1818
}
1919

20+
/** Write a realtime doc into the store, for a given collection. An existing realtime doc with the same id is
21+
* overwritten. */
2022
addSnapshot<T>(collection: string, snapshot: Snapshot<T>): void {
2123
let collectionSnapshots = this.snapshots.get(collection);
2224
if (collectionSnapshots == null) {
@@ -132,6 +134,7 @@ export class MemoryRealtimeDocAdapter implements RealtimeDocAdapter {
132134
return Promise.resolve();
133135
}
134136

137+
/** Multiple operations are received for the `op` argument. */
135138
submitOp(op: any, source?: any): Promise<void> {
136139
if (this.type == null) {
137140
throw new Error('The doc has not been loaded.');

src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-realtime.service.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ export class TestRealtimeService extends RealtimeService {
3333
}
3434
}
3535

36+
/** Write a realtime doc into the store, for a given collection. An existing realtime doc with the same id is
37+
* overwritten. */
3638
addSnapshot<T>(collection: string, snapshot: Partial<Snapshot<T>>, addToOfflineStore: boolean = false): void {
3739
const completeSnapshot = addSnapshotDefaults(snapshot);
3840
(this.remoteStore as MemoryRealtimeRemoteStore).addSnapshot(collection, completeSnapshot);

0 commit comments

Comments
 (0)