A social knowledge tool for researchers built on ATProto
1import {
2 PostgreSqlContainer,
3 StartedPostgreSqlContainer,
4} from '@testcontainers/postgresql';
5import postgres from 'postgres';
6import { drizzle, PostgresJsDatabase } from 'drizzle-orm/postgres-js';
7import { DrizzleCollectionQueryRepository } from '../../infrastructure/repositories/DrizzleCollectionQueryRepository';
8import { DrizzleCardRepository } from '../../infrastructure/repositories/DrizzleCardRepository';
9import { DrizzleCollectionRepository } from '../../infrastructure/repositories/DrizzleCollectionRepository';
10import { CuratorId } from '../../domain/value-objects/CuratorId';
11import { UniqueEntityID } from '../../../../shared/domain/UniqueEntityID';
12import {
13 collections,
14 collectionCollaborators,
15 collectionCards,
16} from '../../infrastructure/repositories/schema/collection.sql';
17import { cards } from '../../infrastructure/repositories/schema/card.sql';
18import { libraryMemberships } from '../../infrastructure/repositories/schema/libraryMembership.sql';
19import { publishedRecords } from '../../infrastructure/repositories/schema/publishedRecord.sql';
20import { Collection, CollectionAccessType } from '../../domain/Collection';
21import { CardFactory } from '../../domain/CardFactory';
22import { CardTypeEnum } from '../../domain/value-objects/CardType';
23import { PublishedRecordId } from '../../domain/value-objects/PublishedRecordId';
24import { UrlMetadata } from '../../domain/value-objects/UrlMetadata';
25import { createTestSchema } from '../test-utils/createTestSchema';
26
27describe('DrizzleCollectionQueryRepository - getCollectionsContainingCardForUser', () => {
28 let container: StartedPostgreSqlContainer;
29 let db: PostgresJsDatabase;
30 let queryRepository: DrizzleCollectionQueryRepository;
31 let collectionRepository: DrizzleCollectionRepository;
32 let cardRepository: DrizzleCardRepository;
33
34 // Test data
35 let curatorId: CuratorId;
36 let otherCuratorId: CuratorId;
37
38 // Setup before all tests
39 beforeAll(async () => {
40 // Start PostgreSQL container
41 container = await new PostgreSqlContainer('postgres:14').start();
42
43 // Create database connection
44 const connectionString = container.getConnectionUri();
45 process.env.DATABASE_URL = connectionString;
46 const client = postgres(connectionString);
47 db = drizzle(client);
48
49 // Create repositories
50 queryRepository = new DrizzleCollectionQueryRepository(db);
51 collectionRepository = new DrizzleCollectionRepository(db);
52 cardRepository = new DrizzleCardRepository(db);
53
54 // Create schema using helper function
55 await createTestSchema(db);
56
57 // Create test data
58 curatorId = CuratorId.create('did:plc:testcurator').unwrap();
59 otherCuratorId = CuratorId.create('did:plc:othercurator').unwrap();
60 }, 60000); // Increase timeout for container startup
61
62 // Cleanup after all tests
63 afterAll(async () => {
64 // Stop container
65 await container.stop();
66 });
67
68 // Clear data between tests
69 beforeEach(async () => {
70 await db.delete(collectionCards);
71 await db.delete(collectionCollaborators);
72 await db.delete(collections);
73 await db.delete(libraryMemberships);
74 await db.delete(cards);
75 await db.delete(publishedRecords);
76 });
77
78 describe('URL card in collections', () => {
79 it('should return collections when user has URL card in multiple collections', async () => {
80 const testUrl = 'https://example.com/test-article';
81
82 // Create a URL card
83 const urlMetadata = UrlMetadata.create({
84 url: testUrl,
85 title: 'Test Article',
86 description: 'A test article for testing',
87 author: 'Test Author',
88 siteName: 'Example.com',
89 }).unwrap();
90
91 const card = CardFactory.create({
92 curatorId: curatorId.value,
93 cardInput: {
94 type: CardTypeEnum.URL,
95 url: testUrl,
96 metadata: urlMetadata,
97 },
98 }).unwrap();
99
100 // Add card to library
101 const addToLibResult = card.addToLibrary(curatorId);
102 expect(addToLibResult.isOk()).toBe(true);
103
104 await cardRepository.save(card);
105
106 // Create first collection
107 const collection1 = Collection.create(
108 {
109 authorId: curatorId,
110 name: 'Tech Articles',
111 description: 'Collection of technology articles',
112 accessType: CollectionAccessType.OPEN,
113 collaboratorIds: [],
114 createdAt: new Date(),
115 updatedAt: new Date(),
116 },
117 new UniqueEntityID(),
118 ).unwrap();
119
120 // Create second collection
121 const collection2 = Collection.create(
122 {
123 authorId: curatorId,
124 name: 'Reading List',
125 description: 'My personal reading list',
126 accessType: CollectionAccessType.OPEN,
127 collaboratorIds: [],
128 createdAt: new Date(),
129 updatedAt: new Date(),
130 },
131 new UniqueEntityID(),
132 ).unwrap();
133
134 // Add card to both collections
135 const addToCollection1Result = collection1.addCard(
136 card.cardId,
137 curatorId,
138 );
139 expect(addToCollection1Result.isOk()).toBe(true);
140
141 const addToCollection2Result = collection2.addCard(
142 card.cardId,
143 curatorId,
144 );
145 expect(addToCollection2Result.isOk()).toBe(true);
146
147 // Mark collections as published
148 const collection1PublishedRecordId = PublishedRecordId.create({
149 uri: 'at://did:plc:testcurator/network.cosmik.collection/collection1',
150 cid: 'bafyreicollection1cid',
151 });
152
153 const collection2PublishedRecordId = PublishedRecordId.create({
154 uri: 'at://did:plc:testcurator/network.cosmik.collection/collection2',
155 cid: 'bafyreicollection2cid',
156 });
157
158 collection1.markAsPublished(collection1PublishedRecordId);
159 collection2.markAsPublished(collection2PublishedRecordId);
160
161 // Save collections
162 await collectionRepository.save(collection1);
163 await collectionRepository.save(collection2);
164
165 // Execute the query
166 const result = await queryRepository.getCollectionsContainingCardForUser(
167 card.cardId.getStringValue(),
168 curatorId.value,
169 );
170
171 // Verify the result
172 expect(result).toHaveLength(2);
173
174 // Sort by name for consistent testing
175 result.sort((a, b) => a.name.localeCompare(b.name));
176
177 // Verify collection details
178 expect(result[0]?.id).toBe(collection2.collectionId.getStringValue()); // Reading List comes first alphabetically
179 expect(result[0]?.uri).toBe(
180 'at://did:plc:testcurator/network.cosmik.collection/collection2',
181 );
182 expect(result[0]?.name).toBe('Reading List');
183 expect(result[0]?.description).toBe('My personal reading list');
184
185 expect(result[1]?.id).toBe(collection1.collectionId.getStringValue()); // Tech Articles comes second
186 expect(result[1]?.uri).toBe(
187 'at://did:plc:testcurator/network.cosmik.collection/collection1',
188 );
189 expect(result[1]?.name).toBe('Tech Articles');
190 expect(result[1]?.description).toBe('Collection of technology articles');
191 });
192
193 it('should return empty array when user has URL card but not in any collections', async () => {
194 const testUrl = 'https://example.com/standalone-article';
195
196 // Create a URL card
197 const urlMetadata = UrlMetadata.create({
198 url: testUrl,
199 title: 'Standalone Article',
200 description: 'A standalone article for testing',
201 }).unwrap();
202
203 const card = CardFactory.create({
204 curatorId: curatorId.value,
205 cardInput: {
206 type: CardTypeEnum.URL,
207 url: testUrl,
208 metadata: urlMetadata,
209 },
210 }).unwrap();
211
212 // Add card to library
213 const addToLibResult = card.addToLibrary(curatorId);
214 expect(addToLibResult.isOk()).toBe(true);
215
216 await cardRepository.save(card);
217
218 // Execute the query
219 const result = await queryRepository.getCollectionsContainingCardForUser(
220 card.cardId.getStringValue(),
221 curatorId.value,
222 );
223
224 // Verify the result
225 expect(result).toHaveLength(0);
226 });
227
228 it('should return empty array when card does not exist', async () => {
229 const nonExistentCardId = new UniqueEntityID().toString();
230
231 // Execute the query
232 const result = await queryRepository.getCollectionsContainingCardForUser(
233 nonExistentCardId,
234 curatorId.value,
235 );
236
237 // Verify the result
238 expect(result).toHaveLength(0);
239 });
240
241 it('should not return collections from other users even if they have the same card', async () => {
242 const testUrl = 'https://example.com/shared-article';
243
244 // Create URL card for first user
245 const urlMetadata1 = UrlMetadata.create({
246 url: testUrl,
247 title: 'Shared Article',
248 description: 'An article shared between users',
249 }).unwrap();
250
251 const card1 = CardFactory.create({
252 curatorId: curatorId.value,
253 cardInput: {
254 type: CardTypeEnum.URL,
255 url: testUrl,
256 metadata: urlMetadata1,
257 },
258 }).unwrap();
259
260 const addToLibResult1 = card1.addToLibrary(curatorId);
261 expect(addToLibResult1.isOk()).toBe(true);
262
263 await cardRepository.save(card1);
264
265 // Create URL card for second user (different card, same URL)
266 const urlMetadata2 = UrlMetadata.create({
267 url: testUrl,
268 title: 'Shared Article',
269 description: 'An article shared between users',
270 }).unwrap();
271
272 const card2 = CardFactory.create({
273 curatorId: otherCuratorId.value,
274 cardInput: {
275 type: CardTypeEnum.URL,
276 url: testUrl,
277 metadata: urlMetadata2,
278 },
279 }).unwrap();
280
281 const addToLibResult2 = card2.addToLibrary(otherCuratorId);
282 expect(addToLibResult2.isOk()).toBe(true);
283
284 await cardRepository.save(card2);
285
286 // Create collection for second user and add their card
287 const otherUserCollection = Collection.create(
288 {
289 authorId: otherCuratorId,
290 name: 'Other User Collection',
291 accessType: CollectionAccessType.OPEN,
292 collaboratorIds: [],
293 createdAt: new Date(),
294 updatedAt: new Date(),
295 },
296 new UniqueEntityID(),
297 ).unwrap();
298
299 const addToOtherCollectionResult = otherUserCollection.addCard(
300 card2.cardId,
301 otherCuratorId,
302 );
303 expect(addToOtherCollectionResult.isOk()).toBe(true);
304
305 await collectionRepository.save(otherUserCollection);
306
307 // Execute the query for first user's card
308 const result = await queryRepository.getCollectionsContainingCardForUser(
309 card1.cardId.getStringValue(),
310 curatorId.value,
311 );
312
313 // Verify the result - should be empty since first user's card is not in any collections
314 expect(result).toHaveLength(0);
315 });
316
317 it('should only return collections owned by the requesting user', async () => {
318 const testUrl = 'https://example.com/multi-user-article';
319
320 // Create URL card for the user
321 const urlMetadata = UrlMetadata.create({
322 url: testUrl,
323 title: 'Multi User Article',
324 description: 'An article for multi-user testing',
325 }).unwrap();
326
327 const card = CardFactory.create({
328 curatorId: curatorId.value,
329 cardInput: {
330 type: CardTypeEnum.URL,
331 url: testUrl,
332 metadata: urlMetadata,
333 },
334 }).unwrap();
335
336 const addToLibResult = card.addToLibrary(curatorId);
337 expect(addToLibResult.isOk()).toBe(true);
338
339 await cardRepository.save(card);
340
341 // Create user's own collection
342 const userCollection = Collection.create(
343 {
344 authorId: curatorId,
345 name: 'My Collection',
346 accessType: CollectionAccessType.OPEN,
347 collaboratorIds: [],
348 createdAt: new Date(),
349 updatedAt: new Date(),
350 },
351 new UniqueEntityID(),
352 ).unwrap();
353
354 const addToUserCollectionResult = userCollection.addCard(
355 card.cardId,
356 curatorId,
357 );
358 expect(addToUserCollectionResult.isOk()).toBe(true);
359
360 await collectionRepository.save(userCollection);
361
362 // Create another user's collection (this should not appear in results)
363 const otherUserCollection = Collection.create(
364 {
365 authorId: otherCuratorId,
366 name: 'Other User Collection',
367 accessType: CollectionAccessType.OPEN,
368 collaboratorIds: [],
369 createdAt: new Date(),
370 updatedAt: new Date(),
371 },
372 new UniqueEntityID(),
373 ).unwrap();
374
375 // Note: We don't add the card to the other user's collection since they can't add
376 // another user's card to their collection in this domain model
377
378 await collectionRepository.save(otherUserCollection);
379
380 // Execute the query
381 const result = await queryRepository.getCollectionsContainingCardForUser(
382 card.cardId.getStringValue(),
383 curatorId.value,
384 );
385
386 // Verify the result - should only see user's own collection
387 expect(result).toHaveLength(1);
388 expect(result[0]?.name).toBe('My Collection');
389 expect(result[0]?.id).toBe(userCollection.collectionId.getStringValue());
390 });
391 });
392
393 describe('Note cards in collections', () => {
394 it('should return collections containing note cards', async () => {
395 // Create a note card
396 const card = CardFactory.create({
397 curatorId: curatorId.value,
398 cardInput: {
399 type: CardTypeEnum.NOTE,
400 text: 'This is a test note',
401 },
402 }).unwrap();
403
404 // Add card to library
405 const addToLibResult = card.addToLibrary(curatorId);
406 expect(addToLibResult.isOk()).toBe(true);
407
408 await cardRepository.save(card);
409
410 // Create collection
411 const collection = Collection.create(
412 {
413 authorId: curatorId,
414 name: 'My Notes',
415 description: 'Collection of my personal notes',
416 accessType: CollectionAccessType.OPEN,
417 collaboratorIds: [],
418 createdAt: new Date(),
419 updatedAt: new Date(),
420 },
421 new UniqueEntityID(),
422 ).unwrap();
423
424 // Add card to collection
425 const addToCollectionResult = collection.addCard(card.cardId, curatorId);
426 expect(addToCollectionResult.isOk()).toBe(true);
427
428 await collectionRepository.save(collection);
429
430 // Execute the query
431 const result = await queryRepository.getCollectionsContainingCardForUser(
432 card.cardId.getStringValue(),
433 curatorId.value,
434 );
435
436 // Verify the result
437 expect(result).toHaveLength(1);
438 expect(result[0]?.id).toBe(collection.collectionId.getStringValue());
439 expect(result[0]?.name).toBe('My Notes');
440 expect(result[0]?.description).toBe('Collection of my personal notes');
441 expect(result[0]?.uri).toBeUndefined(); // Not published
442 });
443
444 it('should handle collections with and without descriptions', async () => {
445 // Create a note card
446 const card = CardFactory.create({
447 curatorId: curatorId.value,
448 cardInput: {
449 type: CardTypeEnum.NOTE,
450 text: 'Test note for collections',
451 },
452 }).unwrap();
453
454 await cardRepository.save(card);
455
456 // Create collection with description
457 const collectionWithDesc = Collection.create(
458 {
459 authorId: curatorId,
460 name: 'Collection With Description',
461 description: 'This collection has a description',
462 accessType: CollectionAccessType.OPEN,
463 collaboratorIds: [],
464 createdAt: new Date(),
465 updatedAt: new Date(),
466 },
467 new UniqueEntityID(),
468 ).unwrap();
469
470 // Create collection without description
471 const collectionWithoutDesc = Collection.create(
472 {
473 authorId: curatorId,
474 name: 'Collection Without Description',
475 // No description provided
476 accessType: CollectionAccessType.OPEN,
477 collaboratorIds: [],
478 createdAt: new Date(),
479 updatedAt: new Date(),
480 },
481 new UniqueEntityID(),
482 ).unwrap();
483
484 // Add card to both collections
485 collectionWithDesc.addCard(card.cardId, curatorId);
486 collectionWithoutDesc.addCard(card.cardId, curatorId);
487
488 await collectionRepository.save(collectionWithDesc);
489 await collectionRepository.save(collectionWithoutDesc);
490
491 // Execute the query
492 const result = await queryRepository.getCollectionsContainingCardForUser(
493 card.cardId.getStringValue(),
494 curatorId.value,
495 );
496
497 // Verify the result
498 expect(result).toHaveLength(2);
499
500 // Sort by name for consistent testing
501 result.sort((a, b) => a.name.localeCompare(b.name));
502
503 expect(result[0]?.name).toBe('Collection With Description');
504 expect(result[0]?.description).toBe('This collection has a description');
505
506 expect(result[1]?.name).toBe('Collection Without Description');
507 expect(result[1]?.description).toBeUndefined();
508 });
509 });
510
511 describe('Published and unpublished collections', () => {
512 it('should return URI for published collections and undefined for unpublished', async () => {
513 // Create a card
514 const card = CardFactory.create({
515 curatorId: curatorId.value,
516 cardInput: {
517 type: CardTypeEnum.NOTE,
518 text: 'Card for published/unpublished test',
519 },
520 }).unwrap();
521
522 await cardRepository.save(card);
523
524 // Create published collection
525 const publishedCollection = Collection.create(
526 {
527 authorId: curatorId,
528 name: 'Published Collection',
529 description: 'This collection is published',
530 accessType: CollectionAccessType.OPEN,
531 collaboratorIds: [],
532 createdAt: new Date(),
533 updatedAt: new Date(),
534 },
535 new UniqueEntityID(),
536 ).unwrap();
537
538 // Create unpublished collection
539 const unpublishedCollection = Collection.create(
540 {
541 authorId: curatorId,
542 name: 'Unpublished Collection',
543 description: 'This collection is not published',
544 accessType: CollectionAccessType.OPEN,
545 collaboratorIds: [],
546 createdAt: new Date(),
547 updatedAt: new Date(),
548 },
549 new UniqueEntityID(),
550 ).unwrap();
551
552 // Mark published collection as published
553 const publishedRecordId = PublishedRecordId.create({
554 uri: 'at://did:plc:testcurator/network.cosmik.collection/published123',
555 cid: 'bafyreipublishedcid',
556 });
557
558 publishedCollection.markAsPublished(publishedRecordId);
559
560 // Add card to both collections
561 publishedCollection.addCard(card.cardId, curatorId);
562 unpublishedCollection.addCard(card.cardId, curatorId);
563
564 await collectionRepository.save(publishedCollection);
565 await collectionRepository.save(unpublishedCollection);
566
567 // Execute the query
568 const result = await queryRepository.getCollectionsContainingCardForUser(
569 card.cardId.getStringValue(),
570 curatorId.value,
571 );
572
573 // Verify the result
574 expect(result).toHaveLength(2);
575
576 // Find collections by name
577 const publishedResult = result.find(
578 (c) => c.name === 'Published Collection',
579 );
580 const unpublishedResult = result.find(
581 (c) => c.name === 'Unpublished Collection',
582 );
583
584 expect(publishedResult?.uri).toBe(
585 'at://did:plc:testcurator/network.cosmik.collection/published123',
586 );
587 expect(unpublishedResult?.uri).toBeUndefined();
588 });
589 });
590
591 describe('Sorting and ordering', () => {
592 it('should return collections sorted by name in ascending order', async () => {
593 // Create a card
594 const card = CardFactory.create({
595 curatorId: curatorId.value,
596 cardInput: {
597 type: CardTypeEnum.NOTE,
598 text: 'Card for sorting test',
599 },
600 }).unwrap();
601
602 await cardRepository.save(card);
603
604 // Create collections with names that will test alphabetical sorting
605 const collectionNames = [
606 'Zebra Collection',
607 'Alpha Collection',
608 'Beta Collection',
609 ];
610
611 for (const name of collectionNames) {
612 const collection = Collection.create(
613 {
614 authorId: curatorId,
615 name,
616 accessType: CollectionAccessType.OPEN,
617 collaboratorIds: [],
618 createdAt: new Date(),
619 updatedAt: new Date(),
620 },
621 new UniqueEntityID(),
622 ).unwrap();
623
624 collection.addCard(card.cardId, curatorId);
625 await collectionRepository.save(collection);
626 }
627
628 // Execute the query
629 const result = await queryRepository.getCollectionsContainingCardForUser(
630 card.cardId.getStringValue(),
631 curatorId.value,
632 );
633
634 // Verify the result is sorted by name
635 expect(result).toHaveLength(3);
636 expect(result[0]?.name).toBe('Alpha Collection');
637 expect(result[1]?.name).toBe('Beta Collection');
638 expect(result[2]?.name).toBe('Zebra Collection');
639 });
640 });
641
642 describe('Edge cases', () => {
643 it('should handle non-existent curator gracefully', async () => {
644 const card = CardFactory.create({
645 curatorId: curatorId.value,
646 cardInput: {
647 type: CardTypeEnum.NOTE,
648 text: 'Test card',
649 },
650 }).unwrap();
651
652 await cardRepository.save(card);
653
654 // Execute the query with non-existent curator
655 const result = await queryRepository.getCollectionsContainingCardForUser(
656 card.cardId.getStringValue(),
657 'did:plc:nonexistent',
658 );
659
660 // Verify the result
661 expect(result).toHaveLength(0);
662 });
663
664 it('should handle empty curator ID gracefully', async () => {
665 const card = CardFactory.create({
666 curatorId: curatorId.value,
667 cardInput: {
668 type: CardTypeEnum.NOTE,
669 text: 'Test card',
670 },
671 }).unwrap();
672
673 await cardRepository.save(card);
674
675 // Execute the query with empty curator ID
676 const result = await queryRepository.getCollectionsContainingCardForUser(
677 card.cardId.getStringValue(),
678 '',
679 );
680
681 // Verify the result
682 expect(result).toHaveLength(0);
683 });
684
685 it('should handle collections with null published records', async () => {
686 // Create a card
687 const card = CardFactory.create({
688 curatorId: curatorId.value,
689 cardInput: {
690 type: CardTypeEnum.NOTE,
691 text: 'Card for null published record test',
692 },
693 }).unwrap();
694
695 await cardRepository.save(card);
696
697 // Create collection without published record
698 const collection = Collection.create(
699 {
700 authorId: curatorId,
701 name: 'Collection Without Published Record',
702 accessType: CollectionAccessType.OPEN,
703 collaboratorIds: [],
704 createdAt: new Date(),
705 updatedAt: new Date(),
706 },
707 new UniqueEntityID(),
708 ).unwrap();
709
710 collection.addCard(card.cardId, curatorId);
711 await collectionRepository.save(collection);
712
713 // Execute the query
714 const result = await queryRepository.getCollectionsContainingCardForUser(
715 card.cardId.getStringValue(),
716 curatorId.value,
717 );
718
719 // Verify the result
720 expect(result).toHaveLength(1);
721 expect(result[0]?.uri).toBeUndefined();
722 expect(result[0]?.name).toBe('Collection Without Published Record');
723 });
724 });
725
726 describe('Multiple card types', () => {
727 it('should work with different card types in the same collection', async () => {
728 // Create different types of cards
729 const urlMetadata = UrlMetadata.create({
730 url: 'https://example.com/test',
731 title: 'Test URL',
732 description: 'A test URL for mixed content',
733 }).unwrap();
734
735 const urlCard = CardFactory.create({
736 curatorId: curatorId.value,
737 cardInput: {
738 type: CardTypeEnum.URL,
739 url: 'https://example.com/test',
740 metadata: urlMetadata,
741 },
742 }).unwrap();
743
744 const noteCard = CardFactory.create({
745 curatorId: curatorId.value,
746 cardInput: {
747 type: CardTypeEnum.NOTE,
748 text: 'Test note',
749 },
750 }).unwrap();
751
752 await cardRepository.save(urlCard);
753 await cardRepository.save(noteCard);
754
755 // Create collection and add all cards
756 const collection = Collection.create(
757 {
758 authorId: curatorId,
759 name: 'Mixed Content Collection',
760 description: 'Collection with different card types',
761 accessType: CollectionAccessType.OPEN,
762 collaboratorIds: [],
763 createdAt: new Date(),
764 updatedAt: new Date(),
765 },
766 new UniqueEntityID(),
767 ).unwrap();
768
769 collection.addCard(urlCard.cardId, curatorId);
770 collection.addCard(noteCard.cardId, curatorId);
771
772 await collectionRepository.save(collection);
773
774 // Test each card type
775 const urlResult =
776 await queryRepository.getCollectionsContainingCardForUser(
777 urlCard.cardId.getStringValue(),
778 curatorId.value,
779 );
780
781 const noteResult =
782 await queryRepository.getCollectionsContainingCardForUser(
783 noteCard.cardId.getStringValue(),
784 curatorId.value,
785 );
786
787 // Verify all return the same collection
788 expect(urlResult).toHaveLength(1);
789 expect(noteResult).toHaveLength(1);
790
791 expect(urlResult[0]?.name).toBe('Mixed Content Collection');
792 expect(noteResult[0]?.name).toBe('Mixed Content Collection');
793
794 expect(urlResult[0]?.id).toBe(collection.collectionId.getStringValue());
795 expect(noteResult[0]?.id).toBe(collection.collectionId.getStringValue());
796 });
797 });
798});