11import { NodeBuilder , s } from 'json-joy/lib/json-crdt' ;
22import { setup as setup0 } from './setup' ;
33import { until } from 'thingies/lib/until' ;
4+ import { EditSession } from '../EditSession' ;
5+ import { EditSessionFactory } from '../EditSessionFactory' ;
6+ import { BehaviorSubject } from 'rxjs' ;
47
5- const setupTwoSessions = async ( schema ?: undefined | NodeBuilder ) => {
8+ type TwoSessionsSetup = ( schema ?: undefined | NodeBuilder ) => Promise < [ EditSession , EditSession , ( ) => Promise < void > ] > ;
9+
10+ const setupTwoRemoteSessions : TwoSessionsSetup = async ( schema ?: undefined | NodeBuilder ) => {
611 const kit = await setup0 ( ) ;
712 const id = kit . blockId ;
8- const session1 = kit . sessions . make ( { id, schema} ) ;
13+ const session1 = kit . sessions . make ( { id, schema, session : 1 } ) ;
914 await until ( async ( ) => {
1015 try {
1116 await kit . getModelFromRemote ( id . join ( '/' ) ) ;
@@ -14,32 +19,80 @@ const setupTwoSessions = async (schema?: undefined | NodeBuilder) => {
1419 return false ;
1520 }
1621 } ) ;
17- const session2 = await kit . sessions . load ( { id, remote : { } } ) ;
22+ const session2 = await kit . sessions . load ( { id, session : 2 , remote : { } } ) ;
23+ const stop = async ( ) => {
24+ await session1 . dispose ( ) ;
25+ await session2 . dispose ( ) ;
26+ await kit . stop ( ) ;
27+ } ;
28+ return [ session1 , session2 , stop ] ;
29+ } ;
30+
31+ const setupTwoLocalSessions : TwoSessionsSetup = async ( schema ?: undefined | NodeBuilder ) => {
32+ const kit = await setup0 ( { local : { connected$ : new BehaviorSubject ( false ) } } ) ;
33+ const id = kit . blockId ;
34+ const session1 = kit . sessions . make ( { id, schema, session : 1 } ) ;
35+ await until ( async ( ) => {
36+ try {
37+ await kit . local . get ( { id} ) ;
38+ return true ;
39+ } catch {
40+ return false ;
41+ }
42+ } ) ;
43+ const local2 = await kit . createLocal ( ) ;
44+ const sessions2 = new EditSessionFactory ( {
45+ sid : local2 . sid ,
46+ repo : local2 . local ,
47+ } ) ;
48+ const session2 = await sessions2 . load ( { id, session : 2 } ) ;
49+ const stop = async ( ) => {
50+ await session1 . dispose ( ) ;
51+ await session2 . dispose ( ) ;
52+ await local2 . stop ( ) ;
53+ await kit . stop ( ) ;
54+ } ;
55+ return [ session1 , session2 , stop ] ;
56+ } ;
57+
58+ const setupTwoSameTabSessions : TwoSessionsSetup = async ( schema ?: undefined | NodeBuilder ) => {
59+ const kit = await setup0 ( { local : { connected$ : new BehaviorSubject ( false ) } } ) ;
60+ const id = kit . blockId ;
61+ const session1 = kit . sessions . make ( { id, schema, session : 1 } ) ;
62+ await until ( async ( ) => {
63+ try {
64+ await kit . local . get ( { id} ) ;
65+ return true ;
66+ } catch {
67+ return false ;
68+ }
69+ } ) ;
70+ const session2 = await kit . sessions . load ( { id, session : 2 } ) ;
1871 const stop = async ( ) => {
1972 await session1 . dispose ( ) ;
2073 await session2 . dispose ( ) ;
2174 await kit . stop ( ) ;
2275 } ;
23- return [ session1 , session2 , stop ] as const ;
76+ return [ session1 , session2 , stop ] ;
2477} ;
2578
26- describe ( 'sync through remote server' , ( ) => {
27- test ( 'can load block which exists remotely (no schema)' , async ( ) => {
79+ const runTwoSessionsTests = ( setupTwoSessions : TwoSessionsSetup ) => {
80+ test ( 'can load block created by another session (no schema)' , async ( ) => {
2881 const [ session1 , session2 , stop ] = await setupTwoSessions ( ) ;
2982 expect ( session1 . model . view ( ) ) . toBe ( undefined ) ;
3083 expect ( session2 . model . view ( ) ) . toBe ( undefined ) ;
3184 await stop ( ) ;
3285 } ) ;
3386
34- test ( 'can load block which exists remotely (with schema)' , async ( ) => {
87+ test ( 'can load block created by another session (with schema)' , async ( ) => {
3588 const schema = s . obj ( { foo : s . str ( 'bar' ) } ) ;
3689 const [ session1 , session2 , stop ] = await setupTwoSessions ( schema ) ;
3790 expect ( session1 . model . view ( ) ) . toEqual ( { foo : 'bar' } ) ;
3891 expect ( session2 . model . view ( ) ) . toEqual ( { foo : 'bar' } ) ;
3992 await stop ( ) ;
4093 } ) ;
4194
42- test ( 'receives a changes done remotely ' , async ( ) => {
95+ test ( 'receives changes done in another session ' , async ( ) => {
4396 const schema = undefined ;
4497 const [ session1 , session2 , stop ] = await setupTwoSessions ( schema ) ;
4598 expect ( session1 . model . view ( ) ) . toBe ( undefined ) ;
@@ -51,7 +104,7 @@ describe('sync through remote server', () => {
51104 await stop ( ) ;
52105 } ) ;
53106
54- test ( 'receives a changes done remotely (reverse)' , async ( ) => {
107+ test ( 'receives changes done in another session (reverse)' , async ( ) => {
55108 const schema = undefined ;
56109 const [ session1 , session2 , stop ] = await setupTwoSessions ( schema ) ;
57110 expect ( session1 . model . view ( ) ) . toBe ( undefined ) ;
@@ -62,4 +115,72 @@ describe('sync through remote server', () => {
62115 expect ( session2 . model . view ( ) ) . toEqual ( { foo : 'bar' } ) ;
63116 await stop ( ) ;
64117 } ) ;
118+
119+ test ( 'two sessions can do edits simultaneously (with schema)' , async ( ) => {
120+ const schema = s . obj ( { } ) ;
121+ const [ session1 , session2 , stop ] = await setupTwoSessions ( schema ) ;
122+ session1 . model . api . obj ( [ ] ) . set ( { foo : 'bar' } ) ;
123+ session2 . model . api . obj ( [ ] ) . set ( { baz : 'qux' } ) ;
124+ await until ( ( ) => session2 . model . view ( ) ?. foo === 'bar' ) ;
125+ await until ( ( ) => session1 . model . view ( ) ?. baz === 'qux' ) ;
126+ expect ( session1 . model . view ( ) ) . toEqual ( { foo : 'bar' , baz : 'qux' } ) ;
127+ expect ( session2 . model . view ( ) ) . toEqual ( { foo : 'bar' , baz : 'qux' } ) ;
128+ await stop ( ) ;
129+ } ) ;
130+
131+ test ( 'two sessions can do edits simultaneously' , async ( ) => {
132+ const schema = undefined ;
133+ const [ session1 , session2 , stop ] = await setupTwoSessions ( schema ) ;
134+ session1 . model . api . root ( { } ) ;
135+ await until ( ( ) => ! ! session2 . model . view ( ) ) ;
136+ await until ( ( ) => ! ! session1 . model . view ( ) ) ;
137+ session1 . model . api . obj ( [ ] ) . set ( { foo : 'bar' } ) ;
138+ session2 . model . api . obj ( [ ] ) . set ( { baz : 'qux' } ) ;
139+ await until ( ( ) => session2 . model . view ( ) ?. foo === 'bar' ) ;
140+ await until ( ( ) => session1 . model . view ( ) ?. baz === 'qux' ) ;
141+ expect ( session1 . model . view ( ) ) . toEqual ( { foo : 'bar' , baz : 'qux' } ) ;
142+ expect ( session2 . model . view ( ) ) . toEqual ( { foo : 'bar' , baz : 'qux' } ) ;
143+ await stop ( ) ;
144+ } ) ;
145+
146+ test ( 'can synchronize two session doing multiple edits' , async ( ) => {
147+ const schema = undefined ;
148+ const [ session1 , session2 , stop ] = await setupTwoSessions ( schema ) ;
149+ expect ( session1 . model . view ( ) ) . toBe ( undefined ) ;
150+ expect ( session2 . model . view ( ) ) . toBe ( undefined ) ;
151+ session1 . model . api . root ( { foo : 'bar' } ) ;
152+ await until ( ( ) => session2 . model . view ( ) ?. foo === 'bar' ) ;
153+
154+ session1 . model . api . obj ( [ ] ) . set ( { x : 'x' } ) ;
155+ session1 . model . api . obj ( [ ] ) . set ( { y : 'y' } ) ;
156+ await until ( ( ) => session2 . model . view ( ) ?. y === 'y' ) ;
157+ expect ( session1 . model . view ( ) ) . toEqual ( { foo : 'bar' , x : 'x' , y : 'y' } ) ;
158+ expect ( session2 . model . view ( ) ) . toEqual ( { foo : 'bar' , x : 'x' , y : 'y' } ) ;
159+
160+ session1 . model . api . obj ( [ ] ) . set ( { x : '1' } ) ;
161+ session2 . model . api . obj ( [ ] ) . set ( { y : '2' } ) ;
162+ await until ( ( ) => session2 . model . view ( ) ?. x === '1' ) ;
163+ await until ( ( ) => session1 . model . view ( ) ?. y === '2' ) ;
164+ expect ( session1 . model . view ( ) ) . toEqual ( { foo : 'bar' , x : '1' , y : '2' } ) ;
165+ expect ( session2 . model . view ( ) ) . toEqual ( { foo : 'bar' , x : '1' , y : '2' } ) ;
166+
167+ session2 . model . api . obj ( [ ] ) . set ( { z : 'z' } ) ;
168+ await until ( ( ) => session1 . model . view ( ) ?. z === 'z' ) ;
169+ expect ( session1 . model . view ( ) ) . toEqual ( { foo : 'bar' , x : '1' , y : '2' , z : 'z' } ) ;
170+ expect ( session2 . model . view ( ) ) . toEqual ( { foo : 'bar' , x : '1' , y : '2' , z : 'z' } ) ;
171+
172+ await stop ( ) ;
173+ } ) ;
174+ } ;
175+
176+ describe ( 'two remote sessions' , ( ) => {
177+ runTwoSessionsTests ( setupTwoRemoteSessions ) ;
178+ } ) ;
179+
180+ describe ( 'two local sessions' , ( ) => {
181+ runTwoSessionsTests ( setupTwoLocalSessions ) ;
182+ } ) ;
183+
184+ describe ( 'two same-tab sessions' , ( ) => {
185+ runTwoSessionsTests ( setupTwoSameTabSessions ) ;
65186} ) ;
0 commit comments