1- import { Node } from "prosemirror-model" ;
2- import { schema } from "prosemirror-schema-basic" ;
3- import { EditorState } from "prosemirror-state" ;
1+ import { TextSelection } from "prosemirror-state" ;
42// Todo: should the test files be named differently?
53import { assert , expect , test } from "vitest" ;
64
75import {
8- NodeJSON ,
9- collab ,
10- } from "@pitter-patter/collab-client" ;
11- import {
12- PresenceClient ,
13- PresenceClientConfig ,
14- LongPollListener as PresenceLongPollListener ,
15- receivePresenceTransaction ,
6+ presenceKey ,
167} from "@pitter-patter/presence-client" ;
178
189import { getDoc } from "../database/docs" ;
1910import { randomRef } from "../editor/Editor" ;
2011import { createDeployment , startServer } from "../server-base" ;
2112
22- import { createCollabClient , generateTestDeploymentConfig , sleep , StateBox } from "./utils" ;
23-
24- const TEST_PORT = 10001 ;
13+ import { createCollabClient , createPresenceClient , generateTestDeploymentConfig , sleep } from "./utils" ;
2514
26- interface Doc {
27- content : NodeJSON ;
28- createdAt : string ;
29- id : string ;
30- updatedAt : string ;
31- version : number ;
32- }
15+ const TEST_PORT = 10002 ;
3316
3417test ( "Test collab" , async ( ) => {
3518 const config = generateTestDeploymentConfig ( 1 ) ;
@@ -51,72 +34,53 @@ test("Test collab", async () => {
5134
5235 const userId1 = randomRef ( ) ;
5336 const doc1 = await getDoc ( await deployment . db . getDb ( ) , docId ) ;
54- const { client : _presenceClient1 , stateBox : presenceStateBox1 } = await createPresenceClient (
37+ const { client : collabClient1 , stateBox : stateBox1 } = await createCollabClient (
5538 serverUrl ,
56- userId1 ,
39+ docId ,
5740 doc1 ,
5841 ) ;
59- const { client : collabClient1 , stateBox : collabStateBox1 } = await createCollabClient (
42+ const { client : presenceClient1 } = await createPresenceClient (
6043 serverUrl ,
61- docId ,
44+ userId1 ,
6245 doc1 ,
63- "client1" ,
46+ stateBox1 ,
6447 ) ;
6548
6649 const userId2 = randomRef ( ) ;
6750 const doc2 = await getDoc ( await deployment . db . getDb ( ) , docId ) ;
68- const { client : _presenceClient2 , stateBox : presenceStateBox2 } = await createPresenceClient (
51+ const { client : _collabClient2 , stateBox : stateBox2 } = await createCollabClient (
52+ serverUrl ,
53+ docId ,
54+ doc2 ,
55+ ) ;
56+ const { client : _presenceClient2 } = await createPresenceClient (
6957 serverUrl ,
7058 userId2 ,
7159 doc2 ,
60+ stateBox2 ,
7261 ) ;
7362
74- const tr = collabStateBox1 . state . tr . . insertText ( "hello" ) ;
75- collabStateBox1 . state = collabStateBox1 . state . apply ( tr ) ;
76- await collabClient1 . send ( collabStateBox1 . state ) ;
63+ const collabTr = stateBox1 . state . tr . insertText ( "hello" ) ;
64+ stateBox1 . state = stateBox1 . state . apply ( collabTr ) ;
65+ await collabClient1 . send ( stateBox1 . state ) ;
7766
7867 // We could pass a channel into the client's receive function and await that instead
7968 // of using an arbitrary delay
8069 await sleep ( 500 ) ;
8170
82- expect ( presenceStateBox1 . state . doc . content ) . toStrictEqual ( presenceStateBox2 . state . doc . content ) ;
83- } ) ;
71+ const presenceTr = stateBox1 . state . tr . setSelection ( TextSelection . create ( stateBox1 . state . doc , 2 ) ) ;
72+ stateBox1 . state = stateBox1 . state . apply ( presenceTr ) ;
73+ await presenceClient1 . send ( stateBox1 . state ) ;
8474
85- async function createPresenceClient (
86- serverUrl : string ,
87- userId : string ,
88- doc : Doc ,
89- ) : Promise < { client : PresenceClient ; stateBox : StateBox } > {
90- const presenceListener = new PresenceLongPollListener (
91- new URL ( `${ serverUrl } /api/docs/${ doc . id } /presence` ) ,
92- ) ;
75+ await sleep ( 500 ) ;
76+
77+ const presenceState = presenceKey . getState ( stateBox2 . state ) ;
78+ let indicatorArr = presenceState ?. indicators [ presenceClient1 . getClientId ( ) ] ;
79+ if ( ! indicatorArr || ! indicatorArr [ 0 ] ) {
80+ throw "Indicators not found" ;
81+ }
82+ const indicator = indicatorArr [ 0 ] ;
83+ expect ( indicator . anchor ) . toBe ( 2 ) ;
84+ expect ( indicator . head ) . toBe ( 2 ) ;
85+ } ) ;
9386
94- const stateBox = {
95- state : EditorState . create ( {
96- doc : Node . fromJSON ( schema , doc . content ) ,
97- plugins : [ collab ( { version : doc . version } ) ] ,
98- } ) ,
99- } ;
100-
101- const presenceConfig : PresenceClientConfig = {
102- userId,
103- sendIndicator : async ( clientId , indicator ) => {
104- await fetch ( `${ serverUrl } /api/docs/${ doc . id } /presence/${ clientId } ` , {
105- method : "POST" ,
106- headers : { "Content-Type" : "application/json" } ,
107- body : JSON . stringify ( indicator ) ,
108- } ) ;
109- } ,
110- receiveIndicators : ( indicators ) => {
111- // Todo: Something seems redundant about this line in presence and collab. Why
112- // do we have to call apply on state and pass it to the receive transaction function?
113- stateBox . state = stateBox . state . apply ( receivePresenceTransaction ( stateBox . state , indicators ) ) ;
114- } ,
115- listener : presenceListener ,
116- } ;
117-
118- const client = new PresenceClient ( presenceConfig ) ;
119- client . listen ( ) ;
120-
121- return { client, stateBox } ;
122- }
0 commit comments