@aerogel/plugin-local-first 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/aerogel-plugin-local-first.d.ts +48 -17
  2. package/dist/aerogel-plugin-local-first.js +1219 -1232
  3. package/dist/aerogel-plugin-local-first.js.map +1 -1
  4. package/package.json +5 -5
  5. package/src/components/Account.vue +9 -0
  6. package/src/components/AccountLoggedIn.vue +85 -0
  7. package/src/components/AccountLoggedOut.vue +26 -0
  8. package/src/components/AccountLoginModal.vue +36 -0
  9. package/src/components/AccountModal.vue +206 -0
  10. package/src/components/index.ts +5 -3
  11. package/src/components/settings/PurgeData.vue +43 -0
  12. package/src/components/settings/index.ts +10 -0
  13. package/src/index.css +1 -0
  14. package/src/index.ts +5 -1
  15. package/src/jobs/Migrate.test.ts +1 -1
  16. package/src/jobs/Migrate.ts +8 -1
  17. package/src/jobs/Sync.test.ts +313 -35
  18. package/src/jobs/Sync.ts +183 -77
  19. package/src/jobs/mixins/LoadsChildren.ts +48 -31
  20. package/src/jobs/mixins/LoadsTypeIndex.ts +7 -5
  21. package/src/jobs/mixins/TracksLocalModels.ts +4 -4
  22. package/src/lib/mirroring.ts +45 -21
  23. package/src/services/Cloud.ts +84 -25
  24. package/src/services/DocumentsCache.ts +6 -2
  25. package/src/testing/cloud.ts +1 -1
  26. package/src/testing/setup.ts +3 -2
  27. package/src/testing/stubs/Person.schema.ts +9 -0
  28. package/src/testing/stubs/Person.ts +18 -0
  29. package/src/testing/stubs/Post.schema.ts +17 -0
  30. package/src/testing/stubs/Post.ts +18 -0
  31. package/dist/InruptAuthenticator.lazy-BvpQLGoj-BvpQLGoj.js +0 -9
  32. package/dist/InruptAuthenticator.lazy-BvpQLGoj-BvpQLGoj.js.map +0 -1
  33. package/dist/LegacyAuthenticator.lazy-ChFFqP14-ChFFqP14.js +0 -5
  34. package/dist/LegacyAuthenticator.lazy-ChFFqP14-ChFFqP14.js.map +0 -1
  35. package/src/components/AGCloudStatus.vue +0 -31
@@ -18,8 +18,11 @@ import {
18
18
  } from '@aerogel/plugin-local-first/testing/cloud';
19
19
  import Movie from '@aerogel/plugin-local-first/testing/stubs/Movie';
20
20
  import MoviesContainer from '@aerogel/plugin-local-first/testing/stubs/MoviesContainer';
21
+ import Post from '@aerogel/plugin-local-first/testing/stubs/Post';
21
22
  import SolidMock from '@aerogel/plugin-local-first/testing/mocks/Solid.mock';
22
23
  import Workspace from '@aerogel/plugin-local-first/testing/stubs/Workspace';
24
+ import Person from '@aerogel/plugin-local-first/testing/stubs/Person';
25
+ import DocumentsCache from '@aerogel/plugin-local-first/services/DocumentsCache';
23
26
 
24
27
  describe('Sync', () => {
25
28
 
@@ -28,10 +31,8 @@ describe('Sync', () => {
28
31
  it('Syncs containers', async () => {
29
32
  // Arrange - Mint urls
30
33
  const parentContainerUrl = SolidMock.requireUser().storageUrls[0];
31
- // fakeContainerUrl({ baseUrl: parentContainerUrl });
32
- const remoteContainerUrl = parentContainerUrl + 'remote/';
33
- // fakeContainerUrl({ baseUrl: parentContainerUrl });
34
- const localContainerUrl = parentContainerUrl + 'local/';
34
+ const remoteContainerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
35
+ const localContainerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
35
36
 
36
37
  // Arrange - Prepare models
37
38
  await MoviesContainer.at(parentContainerUrl).create({
@@ -92,11 +93,13 @@ describe('Sync', () => {
92
93
  expect(containers).toHaveLength(2);
93
94
  expect(arrayFind(containers, 'name', 'Local Movies')).toBeInstanceOf(MoviesContainer);
94
95
  expect(arrayFind(containers, 'name', 'Remote Movies')).toBeInstanceOf(MoviesContainer);
96
+
97
+ expect(Cloud.localModelUpdates).toEqual({});
95
98
  });
96
99
 
97
100
  it('Syncs container documents', async () => {
98
101
  // Arrange - Mint urls
99
- const parentContainerUrl = Solid.requireUser().storageUrls[0];
102
+ const parentContainerUrl = Solid.requireUser().storageUrls[0] + 'movies/';
100
103
  const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
101
104
  const localDocumentUrl = fakeDocumentUrl({ containerUrl });
102
105
  const remoteDocumentUrl = fakeDocumentUrl({ containerUrl });
@@ -148,6 +151,113 @@ describe('Sync', () => {
148
151
  expect(movies).toHaveLength(2);
149
152
  expect(arrayFind(movies, 'name', 'The Tale of Princess Kaguya')).toBeInstanceOf(Movie);
150
153
  expect(arrayFind(movies, 'name', 'Spirited Away')).toBeInstanceOf(Movie);
154
+
155
+ expect(Cloud.localModelUpdates).toEqual({});
156
+ });
157
+
158
+ it('Pushes container documents', async () => {
159
+ // Arrange - Mint urls
160
+ const parentContainerUrl = Solid.requireUser().storageUrls[0] + 'movies/';
161
+ const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
162
+ const localDocumentUrl = fakeDocumentUrl({ containerUrl });
163
+
164
+ // Arrange - Prepare models
165
+ const container = await MoviesContainer.at(parentContainerUrl).create({
166
+ url: containerUrl,
167
+ name: 'Remote Movies',
168
+ });
169
+
170
+ await container.relatedMovies.create({ url: `${localDocumentUrl}#it`, name: 'The Tale of Princess Kaguya' });
171
+
172
+ // Arrange - Prepare responses
173
+ const typeIndexUrl = SolidMock.requireUser().privateTypeIndexUrl ?? '';
174
+
175
+ FakeServer.respond(typeIndexUrl, typeIndexResponse({ [containerUrl]: '<https://schema.org/Movie>' }));
176
+ FakeServer.respond(
177
+ containerUrl,
178
+ containerResponse({
179
+ name: 'Remote Movies',
180
+ documentUrls: [],
181
+ createdAt: container.createdAt,
182
+ updatedAt: container.updatedAt,
183
+ }),
184
+ );
185
+ FakeServer.respondOnce(localDocumentUrl, FakeResponse.notFound()); // Check before create
186
+ FakeServer.respondOnce(localDocumentUrl, FakeResponse.created()); // Create
187
+
188
+ // Arrange - Prepare service
189
+ await Cloud.launch();
190
+ await Cloud.register(MoviesContainer);
191
+ await Events.emit('application-ready');
192
+
193
+ // Act
194
+ const updates: number[] = [];
195
+
196
+ await Cloud.sync({ onUpdated: (progress) => updates.push(progress) });
197
+
198
+ // Assert
199
+ expect(updates).toEqual([0, 0.9, 1]);
200
+ expect(FakeServer.getRequests(typeIndexUrl)).toHaveLength(1);
201
+ expect(FakeServer.getRequests(containerUrl)).toHaveLength(1);
202
+ expect(FakeServer.getRequests(localDocumentUrl)).toHaveLength(2);
203
+ expect(FakeServer.getRequests()).toHaveLength(4);
204
+
205
+ const movies = await Movie.from(containerUrl).all();
206
+ expect(movies).toHaveLength(1);
207
+ expect(arrayFind(movies, 'name', 'The Tale of Princess Kaguya')).toBeInstanceOf(Movie);
208
+
209
+ expect(Cloud.localModelUpdates).toEqual({});
210
+ });
211
+
212
+ it('Pulls container documents', async () => {
213
+ // Arrange - Mint urls
214
+ const parentContainerUrl = Solid.requireUser().storageUrls[0] + 'movies/';
215
+ const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
216
+ const remoteDocumentUrl = fakeDocumentUrl({ containerUrl });
217
+
218
+ // Arrange - Prepare models
219
+ const container = await MoviesContainer.at(parentContainerUrl).create({
220
+ url: containerUrl,
221
+ name: 'Remote Movies',
222
+ });
223
+
224
+ // Arrange - Prepare responses
225
+ const typeIndexUrl = SolidMock.requireUser().privateTypeIndexUrl ?? '';
226
+
227
+ FakeServer.respond(typeIndexUrl, typeIndexResponse({ [containerUrl]: '<https://schema.org/Movie>' }));
228
+ FakeServer.respond(
229
+ containerUrl,
230
+ containerResponse({
231
+ name: 'Remote Movies',
232
+ documentUrls: [remoteDocumentUrl],
233
+ createdAt: container.createdAt,
234
+ updatedAt: container.updatedAt,
235
+ }),
236
+ );
237
+ FakeServer.respond(remoteDocumentUrl, movieResponse('Spirited Away'));
238
+
239
+ // Arrange - Prepare service
240
+ await Cloud.launch();
241
+ await Cloud.register(MoviesContainer);
242
+ await Events.emit('application-ready');
243
+
244
+ // Act
245
+ const updates: number[] = [];
246
+
247
+ await Cloud.sync({ onUpdated: (progress) => updates.push(progress) });
248
+
249
+ // Assert
250
+ expect(updates).toEqual([0, 0.9, 1]);
251
+ expect(FakeServer.getRequests(typeIndexUrl)).toHaveLength(1);
252
+ expect(FakeServer.getRequests(containerUrl)).toHaveLength(1);
253
+ expect(FakeServer.getRequests(remoteDocumentUrl)).toHaveLength(1);
254
+ expect(FakeServer.getRequests()).toHaveLength(3);
255
+
256
+ const movies = await Movie.from(containerUrl).all();
257
+ expect(movies).toHaveLength(1);
258
+ expect(arrayFind(movies, 'name', 'Spirited Away')).toBeInstanceOf(Movie);
259
+
260
+ expect(Cloud.localModelUpdates).toEqual({});
151
261
  });
152
262
 
153
263
  it('Syncs documents', async () => {
@@ -195,11 +305,13 @@ describe('Sync', () => {
195
305
  expect(movies).toHaveLength(2);
196
306
  expect(arrayFind(movies, 'name', 'The Tale of Princess Kaguya')).toBeInstanceOf(Movie);
197
307
  expect(arrayFind(movies, 'name', 'Spirited Away')).toBeInstanceOf(Movie);
308
+
309
+ expect(Cloud.localModelUpdates).toEqual({});
198
310
  });
199
311
 
200
312
  it('Syncs individual container updates', async () => {
201
313
  // Arrange - Mint urls
202
- const parentContainerUrl = Solid.requireUser().storageUrls[0];
314
+ const parentContainerUrl = Solid.requireUser().storageUrls[0] + 'movies/';
203
315
  const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
204
316
  const movieDocumentUrl = fakeDocumentUrl({ containerUrl });
205
317
 
@@ -311,6 +423,8 @@ describe('Sync', () => {
311
423
  crdt:value "Great Movies" .
312
424
  } .
313
425
  `);
426
+
427
+ expect(Cloud.localModelUpdates).toEqual({});
314
428
  });
315
429
 
316
430
  it('Syncs individual container documents', async () => {
@@ -347,11 +461,13 @@ describe('Sync', () => {
347
461
 
348
462
  expect(FakeServer.getRequests(documentUrl)).toHaveLength(4);
349
463
  expect(FakeServer.getRequests()).toHaveLength(4);
464
+
465
+ expect(Cloud.localModelUpdates).toEqual({});
350
466
  });
351
467
 
352
468
  it('Creates containers with documents', async () => {
353
469
  // Arrange - Mint urls
354
- const parentContainerUrl = Solid.requireUser().storageUrls[0];
470
+ const parentContainerUrl = Solid.requireUser().storageUrls[0] + 'movies/';
355
471
  const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
356
472
  const documentUrl = fakeDocumentUrl({ containerUrl });
357
473
 
@@ -401,11 +517,13 @@ describe('Sync', () => {
401
517
  expect(FakeServer.getRequests(`${containerUrl}.meta`)).toHaveLength(1);
402
518
  expect(FakeServer.getRequests(documentUrl)).toHaveLength(2);
403
519
  expect(FakeServer.getRequests()).toHaveLength(10);
520
+
521
+ expect(Cloud.localModelUpdates).toEqual({});
404
522
  });
405
523
 
406
524
  it('Skips pulling fresh documents', async () => {
407
525
  // Arrange - Mint urls
408
- const parentContainerUrl = Solid.requireUser().storageUrls[0];
526
+ const parentContainerUrl = Solid.requireUser().storageUrls[0] + 'tasks/';
409
527
  const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
410
528
  const childContainerUrl = fakeContainerUrl({ baseUrl: containerUrl });
411
529
  const freshDocumentUrl = fakeDocumentUrl({ containerUrl });
@@ -447,16 +565,18 @@ describe('Sync', () => {
447
565
  // Arrange - Prepare responses
448
566
  const now = Date.now();
449
567
  const typeIndexUrl = SolidMock.requireUser().privateTypeIndexUrl ?? '';
450
- const typeIndexTurtle = `
568
+
569
+ FakeServer.respond(
570
+ typeIndexUrl,
571
+ `
451
572
  <${typeIndexUrl}> a <http://www.w3.org/ns/solid/terms#TypeIndex> .
452
573
 
453
574
  <#tasks>
454
575
  a <http://www.w3.org/ns/solid/terms#TypeRegistration> ;
455
576
  <http://www.w3.org/ns/solid/terms#forClass> <https://schema.org/Action> ;
456
577
  <http://www.w3.org/ns/solid/terms#instanceContainer> <${containerUrl}> .
457
- `;
458
-
459
- FakeServer.respondOnce(typeIndexUrl, FakeResponse.success(typeIndexTurtle)); // Initial fetch
578
+ `,
579
+ );
460
580
  FakeServer.respondOnce(
461
581
  containerUrl,
462
582
  containerResponse({
@@ -559,19 +679,19 @@ describe('Sync', () => {
559
679
  await Cloud.sync();
560
680
 
561
681
  // Assert
562
- expect(FakeServer.getRequests(typeIndexUrl)).toHaveLength(1);
682
+ expect(FakeServer.getRequests(typeIndexUrl)).toHaveLength(2);
563
683
  expect(FakeServer.getRequests(containerUrl)).toHaveLength(2);
564
684
  expect(FakeServer.getRequests(childContainerUrl)).toHaveLength(2);
565
685
  expect(FakeServer.getRequests(freshDocumentUrl)).toHaveLength(1);
566
686
  expect(FakeServer.getRequests(staleDocumentUrl)).toHaveLength(2);
567
687
  expect(FakeServer.getRequests(freshChildDocumentUrl)).toHaveLength(1);
568
688
  expect(FakeServer.getRequests(staleChildDocumentUrl)).toHaveLength(2);
569
- expect(FakeServer.getRequests()).toHaveLength(11);
689
+ expect(FakeServer.getRequests()).toHaveLength(12);
570
690
  });
571
691
 
572
692
  it('Ignores missing children', async () => {
573
693
  // Arrange - Mint urls
574
- const parentContainerUrl = Solid.requireUser().storageUrls[0];
694
+ const parentContainerUrl = Solid.requireUser().storageUrls[0] + 'tasks/';
575
695
  const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
576
696
  const existingChildDocumentUrl = fakeContainerUrl({ baseUrl: containerUrl });
577
697
  const notFoundChildDocumentUrl = fakeDocumentUrl({ containerUrl });
@@ -629,7 +749,7 @@ describe('Sync', () => {
629
749
 
630
750
  it('Ignores malformed documents', async () => {
631
751
  // Arrange - Mint urls
632
- const parentContainerUrl = Solid.requireUser().storageUrls[0];
752
+ const parentContainerUrl = Solid.requireUser().storageUrls[0] + 'movies/';
633
753
  const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
634
754
  const firstDocumentUrl = fakeDocumentUrl({ containerUrl: containerUrl });
635
755
  const secondDocumentUrl = fakeDocumentUrl({ containerUrl: containerUrl });
@@ -692,7 +812,7 @@ describe('Sync', () => {
692
812
 
693
813
  it('Ignores malformed documents in individual syncs', async () => {
694
814
  // Arrange - Mint urls
695
- const parentContainerUrl = Solid.requireUser().storageUrls[0];
815
+ const parentContainerUrl = Solid.requireUser().storageUrls[0] + 'movies/';
696
816
  const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
697
817
  const documentUrl = fakeDocumentUrl({ containerUrl: containerUrl });
698
818
 
@@ -725,9 +845,155 @@ describe('Sync', () => {
725
845
  expect(Cloud.localModelUpdates).toEqual({ [movie.url]: 1 });
726
846
  });
727
847
 
848
+ it('Syncs nested fresh containers', async () => {
849
+ // Arrange - Mint urls
850
+ const rootContainerUrl = Solid.requireUser().storageUrls[0];
851
+ const parentContainerUrl = fakeContainerUrl({ baseUrl: rootContainerUrl });
852
+ const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
853
+ const documentUrl = fakeDocumentUrl({ containerUrl });
854
+
855
+ // Arrange - Prepare models
856
+ const parentContainer = await Workspace.at(rootContainerUrl).create({
857
+ url: parentContainerUrl,
858
+ name: 'Tasks',
859
+ });
860
+ const container = await parentContainer.relatedLists.create({
861
+ url: containerUrl,
862
+ name: 'More Tasks',
863
+ });
864
+ const task = await container.relatedTasks.create({ url: `${documentUrl}#it`, name: 'Sync' });
865
+
866
+ // Arrange - Prepare responses
867
+ const typeIndexUrl = SolidMock.requireUser().privateTypeIndexUrl ?? '';
868
+ const now = Date.now();
869
+
870
+ FakeServer.respond(typeIndexUrl, typeIndexResponse({ [parentContainerUrl]: '<https://schema.org/Action>' }));
871
+ FakeServer.respond(parentContainerUrl, containerResponse({ name: 'Tasks', documentUrls: [containerUrl] }));
872
+ FakeServer.respond(
873
+ containerUrl,
874
+ containerResponse({
875
+ name: 'More Tasks',
876
+ documentUrls: [documentUrl],
877
+ append: `
878
+ <${documentUrl}>
879
+ a <http://www.w3.org/ns/iana/media-types/text/turtle#Resource> ;
880
+ <http://purl.org/dc/terms/modified>
881
+ "${new Date(now).toISOString()}"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
882
+ `,
883
+ }),
884
+ );
885
+ FakeServer.respond(documentUrl, await task.toTurtle());
886
+ FakeServer.respond(`${parentContainerUrl}.meta`);
887
+ FakeServer.respond(`${containerUrl}.meta`);
888
+
889
+ // Arrange - Prepare service
890
+ await DocumentsCache.remember(documentUrl, now);
891
+ await Cloud.launch();
892
+ await Cloud.register(Workspace);
893
+ await Events.emit('application-ready');
894
+
895
+ // Act
896
+ await Cloud.sync();
897
+
898
+ // Assert
899
+ expect(FakeServer.getRequests(typeIndexUrl)).toHaveLength(1);
900
+ expect(FakeServer.getRequests(parentContainerUrl)).toHaveLength(2);
901
+ expect(FakeServer.getRequests(containerUrl)).toHaveLength(2);
902
+ expect(FakeServer.getRequests(`${parentContainerUrl}.meta`)).toHaveLength(1);
903
+ expect(FakeServer.getRequests(`${containerUrl}.meta`)).toHaveLength(1);
904
+ expect(FakeServer.getRequests()).toHaveLength(7);
905
+
906
+ expect(Cloud.localModelUpdates).toEqual({});
907
+ });
908
+
909
+ it('Ignores nested container registrations', async () => {
910
+ // Arrange - Mint urls
911
+ const rootContainerUrl = Solid.requireUser().storageUrls[0];
912
+ const parentContainerUrl = fakeContainerUrl({ baseUrl: rootContainerUrl });
913
+ const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
914
+ const parentDocumentUrl = fakeDocumentUrl({ containerUrl: parentContainerUrl });
915
+ const documentUrl = fakeDocumentUrl({ containerUrl });
916
+
917
+ // Arrange - Prepare responses
918
+ const typeIndexUrl = SolidMock.requireUser().privateTypeIndexUrl ?? '';
919
+
920
+ FakeServer.respond(
921
+ typeIndexUrl,
922
+ typeIndexResponse({
923
+ [parentContainerUrl]: '<https://schema.org/Movie>',
924
+ [containerUrl]: '<https://schema.org/Movie>',
925
+ }),
926
+ );
927
+ FakeServer.respond(parentContainerUrl, containerResponse({ documentUrls: [containerUrl, parentDocumentUrl] }));
928
+ FakeServer.respond(containerUrl, containerResponse({ documentUrls: [documentUrl] }));
929
+ FakeServer.respond(parentDocumentUrl, movieResponse());
930
+
931
+ // Arrange - Prepare service
932
+ await Cloud.launch();
933
+ await Cloud.register(MoviesContainer);
934
+ await Events.emit('application-ready');
935
+
936
+ // Act
937
+ await Cloud.sync();
938
+
939
+ // Assert
940
+ expect(FakeServer.getRequests(typeIndexUrl)).toHaveLength(1);
941
+ expect(FakeServer.getRequests(parentContainerUrl)).toHaveLength(1);
942
+ expect(FakeServer.getRequests(containerUrl)).toHaveLength(1);
943
+ expect(FakeServer.getRequests(parentDocumentUrl)).toHaveLength(1);
944
+ expect(FakeServer.getRequests()).toHaveLength(4);
945
+ });
946
+
947
+ it('Works with circular relationships', async () => {
948
+ // Arrange
949
+ const typeIndexUrl = SolidMock.requireUser().privateTypeIndexUrl ?? '';
950
+ const containerUrl = fakeContainerUrl();
951
+ const documentUrl = fakeDocumentUrl({ containerUrl });
952
+ const typeIndexTurtle = `
953
+ <${typeIndexUrl}> a <http://www.w3.org/ns/solid/terms#TypeIndex> .
954
+
955
+ <#posts>
956
+ a <http://www.w3.org/ns/solid/terms#TypeRegistration> ;
957
+ <http://www.w3.org/ns/solid/terms#forClass> <https://schema.org/Article> ;
958
+ <http://www.w3.org/ns/solid/terms#instanceContainer> <${containerUrl}> .
959
+ `;
960
+
961
+ FakeServer.respondOnce(typeIndexUrl, FakeResponse.success(typeIndexTurtle));
962
+ FakeServer.respondOnce(containerUrl, containerResponse({ documentUrls: [documentUrl] }));
963
+ FakeServer.respondOnce(
964
+ documentUrl,
965
+ `
966
+ <#it>
967
+ a <https://schema.org/Article> ;
968
+ <https://schema.org/name> "Title" ;
969
+ <https://schema.org/author> <#author> .
970
+
971
+ <#author>
972
+ a <https://schema.org/Person> ;
973
+ <https://schema.org/name> "Author" .
974
+ `,
975
+ );
976
+
977
+ Cloud.ready = true;
978
+
979
+ await Cloud.launch();
980
+ await Cloud.register(Post);
981
+ await Events.emit('application-ready');
982
+
983
+ // Act
984
+ await Cloud.sync();
985
+
986
+ // Assert
987
+ const [post] = await Post.all();
988
+
989
+ expect(post).toBeInstanceOf(Post);
990
+ expect(post?.author).toBeInstanceOf(Person);
991
+ expect(post?.author?.posts?.[0]).toBe(post);
992
+ });
993
+
728
994
  testRegisterVariants('Leaves tombstones behind', async (registerModels) => {
729
995
  // Arrange - Mint urls
730
- const parentContainerUrl = Solid.requireUser().storageUrls[0];
996
+ const parentContainerUrl = Solid.requireUser().storageUrls[0] + 'movies/';
731
997
  const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
732
998
  const documentUrl = fakeDocumentUrl({ containerUrl });
733
999
 
@@ -783,14 +1049,16 @@ describe('Sync', () => {
783
1049
  crdt:deletedAt "[[.*]]"^^xsd:dateTime .
784
1050
  } .
785
1051
  `);
1052
+
1053
+ expect(Cloud.localModelUpdates).toEqual({});
786
1054
  });
787
1055
 
788
1056
  testRegisterVariants('Deletes tombstone models', async (registerModels, variant) => {
789
1057
  const usingContainers = variant === 'container registration';
790
1058
 
791
1059
  // Arrange - Mint urls
792
- const parentContainerUrl = Solid.requireUser().storageUrls[0];
793
- const containerUrl = parentContainerUrl + 'delete/'; //fakeContainerUrl({ baseUrl: parentContainerUrl });
1060
+ const parentContainerUrl = Solid.requireUser().storageUrls[0] + 'movies/';
1061
+ const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
794
1062
  const documentUrl = fakeDocumentUrl({ containerUrl });
795
1063
 
796
1064
  // Arrange - Prepare models
@@ -816,12 +1084,17 @@ describe('Sync', () => {
816
1084
  FakeResponse.success('<> a <http://www.w3.org/ns/ldp#Container> .'),
817
1085
  );
818
1086
  FakeServer.respondOnce(`${containerUrl}.meta`, FakeResponse.success()); // Update meta
819
- FakeServer.respondOnce(typeIndexUrl, typeIndexResponse()); // Check before update
820
- FakeServer.respondOnce(typeIndexUrl, FakeResponse.success()); // Update
821
1087
  } else {
822
1088
  FakeServer.respondOnce(documentUrl, FakeResponse.notFound()); // Tombstone check
823
1089
  }
824
1090
 
1091
+ FakeServer.respondOnce(typeIndexUrl, typeIndexResponse()); // Check before update
1092
+ FakeServer.respondOnce(typeIndexUrl, FakeResponse.success()); // Update
1093
+ FakeServer.respondOnce(
1094
+ typeIndexUrl,
1095
+ typeIndexResponse({ [containerUrl]: '<https://schema.org/Movie>' }), // Second sync
1096
+ );
1097
+
825
1098
  FakeServer.respondOnce(documentUrl, FakeResponse.notFound()); // Existence check
826
1099
  FakeServer.respondOnce(documentUrl, FakeResponse.success()); // Create
827
1100
 
@@ -854,9 +1127,6 @@ describe('Sync', () => {
854
1127
 
855
1128
  // Assert
856
1129
  const freshMovie = await Movie.at(containerUrl).find(movie.url);
857
- const cloud = Cloud;
858
-
859
- cloud;
860
1130
 
861
1131
  expect(freshMovie).toBeNull();
862
1132
 
@@ -868,23 +1138,26 @@ describe('Sync', () => {
868
1138
  expect(freshContainer.movies).toHaveLength(0);
869
1139
  expect(freshContainer.resourceUrls).toHaveLength(1);
870
1140
 
871
- expect(FakeServer.getRequests(typeIndexUrl)).toHaveLength(3);
1141
+ expect(FakeServer.getRequests(typeIndexUrl)).toHaveLength(4);
872
1142
  expect(FakeServer.getRequests(containerUrl)).toHaveLength(5);
873
1143
  expect(FakeServer.getRequests(documentUrl)).toHaveLength(3);
874
1144
  expect(FakeServer.getRequests(`${containerUrl}.meta`)).toHaveLength(1);
875
- expect(FakeServer.getRequests()).toHaveLength(12);
1145
+ expect(FakeServer.getRequests()).toHaveLength(13);
876
1146
  } else {
877
- expect(FakeServer.getRequests(typeIndexUrl)).toHaveLength(1);
878
- expect(FakeServer.getRequests(documentUrl)).toHaveLength(4);
879
- expect(FakeServer.getRequests()).toHaveLength(5);
1147
+ expect(FakeServer.getRequests(typeIndexUrl)).toHaveLength(4);
1148
+ expect(FakeServer.getRequests(containerUrl)).toHaveLength(1);
1149
+ expect(FakeServer.getRequests(documentUrl)).toHaveLength(5);
1150
+ expect(FakeServer.getRequests()).toHaveLength(10);
880
1151
  }
1152
+
1153
+ expect(Cloud.localModelUpdates).toEqual({});
881
1154
  });
882
1155
 
883
1156
  testRegisterVariants('Deletes updated tombstone models', async (registerModels, variant) => {
884
1157
  const usingContainers = variant === 'container registration';
885
1158
 
886
1159
  // Arrange - Mint urls
887
- const parentContainerUrl = Solid.requireUser().storageUrls[0];
1160
+ const parentContainerUrl = Solid.requireUser().storageUrls[0] + 'movies/';
888
1161
  const containerUrl = fakeContainerUrl({ baseUrl: parentContainerUrl });
889
1162
  const documentUrl = fakeDocumentUrl({ containerUrl });
890
1163
 
@@ -911,12 +1184,13 @@ describe('Sync', () => {
911
1184
  FakeResponse.success('<> a <http://www.w3.org/ns/ldp#Container> .'),
912
1185
  );
913
1186
  FakeServer.respondOnce(`${containerUrl}.meta`, FakeResponse.success()); // Update meta
914
- FakeServer.respondOnce(typeIndexUrl, typeIndexResponse()); // Check before update
915
- FakeServer.respondOnce(typeIndexUrl, FakeResponse.success()); // Update
916
1187
  } else {
917
1188
  FakeServer.respondOnce(documentUrl, FakeResponse.notFound()); // Tombstone check
918
1189
  }
919
1190
 
1191
+ FakeServer.respondOnce(typeIndexUrl, typeIndexResponse()); // Check before update
1192
+ FakeServer.respondOnce(typeIndexUrl, FakeResponse.success()); // Update
1193
+
920
1194
  FakeServer.respondOnce(documentUrl, FakeResponse.notFound()); // Existence check
921
1195
  FakeServer.respondOnce(documentUrl, FakeResponse.success()); // Create
922
1196
 
@@ -958,10 +1232,12 @@ describe('Sync', () => {
958
1232
  expect(FakeServer.getRequests(`${containerUrl}.meta`)).toHaveLength(1);
959
1233
  expect(FakeServer.getRequests()).toHaveLength(12);
960
1234
  } else {
961
- expect(FakeServer.getRequests(typeIndexUrl)).toHaveLength(1);
1235
+ expect(FakeServer.getRequests(typeIndexUrl)).toHaveLength(3);
962
1236
  expect(FakeServer.getRequests(documentUrl)).toHaveLength(5);
963
- expect(FakeServer.getRequests()).toHaveLength(6);
1237
+ expect(FakeServer.getRequests()).toHaveLength(8);
964
1238
  }
1239
+
1240
+ expect(Cloud.localModelUpdates).toEqual({});
965
1241
  });
966
1242
 
967
1243
  testRegisterVariants('Tracks model updates', async (registerModels) => {
@@ -971,6 +1247,8 @@ describe('Sync', () => {
971
1247
 
972
1248
  await registerModels();
973
1249
 
1250
+ Cloud.ready = true;
1251
+
974
1252
  // Act
975
1253
  await movie.update({ releaseDate: new Date('2023-07-14') });
976
1254
  await container.relatedMovies.create({ name: 'The Tale of Princess Kaguya' });