@friggframework/api-module-hubspot 1.2.0-canary.293.5731c31.0 → 2.0.0-next.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.
package/tests/api.test.js CHANGED
@@ -1,17 +1,49 @@
1
- const { Authenticator } = require('@friggframework/devtools');
1
+ const {Authenticator} = require('@friggframework/test');
2
2
  const {Api} = require('../api');
3
3
  const config = require('../defaultConfig.json');
4
+ const {promises: fs} = require("fs");
5
+
6
+ const mockDir = `./mocks${Date.now()}`
7
+ const parsedBody = async function async(resp) {
8
+ const contentType = resp.headers.get('Content-Type') || '';
9
+ let body;
10
+ if (
11
+ contentType.match(/^application\/json/) ||
12
+ contentType.match(/^application\/vnd.api\+json/) ||
13
+ contentType.match(/^application\/hal\+json/)
14
+ ) {
15
+ body = await resp.json();
16
+ } else {
17
+ body = await resp.text();
18
+ }
19
+ await fs.writeFile(`./${mockDir}/${this.lastCalled}.json`, JSON.stringify(body));
20
+ return body;
21
+ }
4
22
 
5
23
  describe(`${config.label} API tests`, () => {
6
-
7
-
8
24
  const apiParams = {
9
25
  client_id: process.env.HUBSPOT_CLIENT_ID,
10
26
  client_secret: process.env.HUBSPOT_CLIENT_SECRET,
11
27
  redirect_uri: `${process.env.REDIRECT_URI}/hubspot`,
12
28
  scope: process.env.HUBSPOT_SCOPE
13
29
  };
30
+ Object.getOwnPropertyNames(Api.prototype).forEach(f => {
31
+ if (f !== 'constructor' &&
32
+ typeof Api.prototype[f] === 'function' &&
33
+ f !== 'addJsonHeaders' &&
34
+ !f.startsWith('_')) {
35
+ const old = Api.prototype[f];
36
+ Api.prototype[f] = function (...args) {
37
+ this.lastCalled = f;
38
+ return old.apply(this, args);
39
+ }
40
+ }
41
+ })
14
42
  const api = new Api(apiParams);
43
+ api.parsedBody = parsedBody;
44
+ beforeAll(async () => {
45
+ await fs.mkdir(mockDir, {recursive: true});
46
+ });
15
47
 
16
48
  beforeAll(async () => {
17
49
  const url = await api.getAuthUri();
@@ -23,6 +55,8 @@ describe(`${config.label} API tests`, () => {
23
55
  await api.getTokenFromCode(response.data.code);
24
56
  });
25
57
 
58
+ const testObjType = 'tests';
59
+
26
60
  describe('HS User Info', () => {
27
61
  it('should return the user details', async () => {
28
62
  const response = await api.getUserDetails();
@@ -327,34 +361,34 @@ describe(`${config.label} API tests`, () => {
327
361
  expect(allLandingPages.total).toBe(primaryLandingPages.total + variationLandingPages.total)
328
362
  });
329
363
 
330
- it('get Landing Page by Id' , async () => {
364
+ it('get Landing Page by Id', async () => {
331
365
  const response = await api.getLandingPage(sampleLandingPage.id);
332
366
  expect(response).toBeDefined();
333
367
  });
334
- it('update a Landing page (maximal patch)' , async () => {
368
+ it('update a Landing page (maximal patch)', async () => {
335
369
  delete sampleLandingPage['archivedAt'];
336
370
  const response = await api.updateLandingPage(
337
371
  sampleLandingPage.id,
338
372
  sampleLandingPage,
339
- true );
373
+ true);
340
374
  expect(response).toBeDefined();
341
375
  });
342
- it('update a Landing page (minimal patch)' , async () => {
376
+ it('update a Landing page (minimal patch)', async () => {
343
377
  const response = await api.updateLandingPage(
344
378
  sampleLandingPage.id,
345
379
  {htmlTitle: `test Landing page ${Date.now()}`},
346
- true );
380
+ true);
347
381
  expect(response).toBeDefined();
348
382
  });
349
- it('publish a Landing Page' , async () => {
350
- const now = new Date(Date.now()+5000);
383
+ it('publish a Landing Page', async () => {
384
+ const now = new Date(Date.now() + 5000);
351
385
  const response = await api.publishLandingPage(
352
386
  sampleLandingPage.id,
353
387
  now.toISOString(),
354
388
  );
355
389
  expect(response).toBeDefined();
356
390
  });
357
- it('push a Landing page draft to live' , async () => {
391
+ it('push a Landing page draft to live', async () => {
358
392
 
359
393
  const response = await api.pushLandingPageDraftToLive(sampleLandingPage.id);
360
394
  expect(response).toBeDefined();
@@ -380,17 +414,17 @@ describe(`${config.label} API tests`, () => {
380
414
  it('confirm total Site pages', async () => {
381
415
  expect(allSitePages.total).toBe(primarySitePages.total + variationSitePages.total)
382
416
  });
383
- it('get Site Page by Id' , async () => {
417
+ it('get Site Page by Id', async () => {
384
418
  const pageToGet = primarySitePages.results.slice(-1)[0];
385
419
  const response = await api.getSitePage(pageToGet.id);
386
420
  expect(response).toBeDefined();
387
421
  });
388
- it('update a Site page' , async () => {
422
+ it('update a Site page', async () => {
389
423
  const pageToUpdate = variationSitePages.results.slice(-1)[0];
390
424
  const response = await api.updateSitePage(
391
425
  pageToUpdate.id,
392
426
  {htmlTitle: `test site page ${Date.now()}`},
393
- true );
427
+ true);
394
428
  expect(response).toBeDefined();
395
429
  });
396
430
  });
@@ -414,17 +448,17 @@ describe(`${config.label} API tests`, () => {
414
448
  it('confirm total Blog Posts', async () => {
415
449
  expect(allBlogPosts.total).toBe(primaryBlogPosts.total + variationBlogPosts.total)
416
450
  });
417
- it('get Blog Post by Id' , async () => {
451
+ it('get Blog Post by Id', async () => {
418
452
  const postToGet = primaryBlogPosts.results.slice(-1)[0];
419
453
  const response = await api.getBlogPost(postToGet.id);
420
454
  expect(response).toBeDefined();
421
455
  });
422
- it('update a Blog Post' , async () => {
456
+ it('update a Blog Post', async () => {
423
457
  const postToUpdate = primaryBlogPosts.results[0];
424
458
  const response = await api.updateBlogPost(
425
459
  postToUpdate.id,
426
460
  {htmlTitle: `test blog post ${Date.now()}`},
427
- true );
461
+ true);
428
462
  expect(response).toBeDefined();
429
463
  });
430
464
  });
@@ -436,36 +470,84 @@ describe(`${config.label} API tests`, () => {
436
470
  expect(allEmailTemplates).toBeDefined();
437
471
  expect(allEmailTemplates).toHaveProperty('objects')
438
472
  });
439
- it('get Email Template by Id' , async () => {
473
+ it('get Email Template by Id', async () => {
440
474
  const templateToGet = allEmailTemplates.objects.slice(-1)[0];
441
475
  const response = await api.getEmailTemplate(templateToGet.id);
442
476
  expect(response).toBeDefined();
443
477
  });
444
- it('update a Email Template' , async () => {
478
+ it('update a Email Template', async () => {
445
479
  const postToUpdate = allEmailTemplates.objects.slice(-1)[0];
446
480
  const response = await api.updateEmailTemplate(
447
481
  postToUpdate.id,
448
482
  {label: `test email template ${Date.now()}`},
449
- );
483
+ );
450
484
  expect(response).toBeDefined();
451
485
  });
452
486
  let createdId;
453
- it('create an Email Template' , async () => {
487
+ it('create an Email Template', async () => {
454
488
  const response = await api.createEmailTemplate(
455
489
  allEmailTemplates.objects.slice(-1)[0]
456
490
  );
457
491
  expect(response).toBeDefined();
458
492
  createdId = response.id;
459
493
  });
460
- it('Delete an Email Template' , async () => {
494
+ it('Delete an Email Template', async () => {
461
495
  const response = await api.deleteEmailTemplate(createdId)
462
496
  expect(response.status).toBe(204);
463
497
  });
464
498
  });
465
499
 
466
- describe.only('HS Custom Objects', () => {
500
+ describe('Custom Object Schemas', () => {
501
+ const testSchema = {
502
+ "labels": {"singular": "Test Object", "plural": "Test Objects"},
503
+ "requiredProperties": ["word"],
504
+ "searchableProperties": ["word"],
505
+ "primaryDisplayProperty": "word",
506
+ "secondaryDisplayProperties": [],
507
+ "description": null,
508
+ "properties": [{
509
+ "name": "word",
510
+ "label": "Word",
511
+ "type": "string",
512
+ "fieldType": "text",
513
+ "description": "",
514
+ "hasUniqueValue": false
515
+ }],
516
+ "associatedObjects": [
517
+ "COMPANY"
518
+ ],
519
+ "name": "test_object"
520
+ }
521
+
522
+ it('should return the Custom Object Schemas', async () => {
523
+ const response = await api.listCustomObjectSchemas();
524
+ expect(response).toBeDefined();
525
+ expect(response).toHaveProperty('results');
526
+ expect(response.results.length).toBeGreaterThan(0);
527
+ expect(response.results.filter(s => s.name === testSchema.name).length).toBe(0);
528
+ });
529
+
530
+ it('should create a Custom Object Schema', async () => {
531
+ const response = await api.createCustomObjectSchema(testSchema);
532
+ expect(response).toBeDefined();
533
+ expect(response).toHaveProperty('id');
534
+ });
535
+
536
+ it('Should get association labels', async () => {
537
+ const labels = await api.getAssociationLabels('COMPANY', testSchema.name);
538
+ expect(labels).toBeDefined();
539
+ expect(labels.results).toHaveProperty('length');
540
+ expect(labels.results.find(label => label.label === 'Primary')).toBeTruthy();
541
+ })
542
+
543
+ it('should delete a Custom Object Schema', async () => {
544
+ const response = await api.deleteCustomObjectSchema(testSchema.name);
545
+ expect(response.status).toBe(204);
546
+ })
547
+ })
548
+
549
+ describe('HS Custom Objects', () => {
467
550
  let allCustomObjects;
468
- const testObjType = 'tests';
469
551
  let oneWord;
470
552
  const createWord = 'Test Custom Object Create';
471
553
  const updateWord = 'Test Custom Object Update';
@@ -478,13 +560,13 @@ describe(`${config.label} API tests`, () => {
478
560
  expect(allCustomObjects).toHaveProperty('results')
479
561
  oneWord = allCustomObjects.results.find(o => o.properties.word === 'One');
480
562
  });
481
- it('get Custom Object by Id' , async () => {
563
+ it('get Custom Object by Id', async () => {
482
564
  const objectToGet = allCustomObjects.results.slice(-1)[0];
483
565
  const response = await api.getCustomObject(testObjType, objectToGet.id);
484
566
  expect(response).toBeDefined();
485
567
  });
486
568
  let createdObject;
487
- it('create a Custom Object' , async () => {
569
+ it('create a Custom Object', async () => {
488
570
  createdObject = await api.createCustomObject(
489
571
  testObjType,
490
572
  {
@@ -492,10 +574,10 @@ describe(`${config.label} API tests`, () => {
492
574
  word: createWord
493
575
  }
494
576
  },
495
- );
577
+ );
496
578
  expect(createdObject).toBeDefined();
497
579
  })
498
- it('update a Custom Object' , async () => {
580
+ it('update a Custom Object', async () => {
499
581
  const response = await api.updateCustomObject(
500
582
  testObjType,
501
583
  createdObject.id,
@@ -504,10 +586,10 @@ describe(`${config.label} API tests`, () => {
504
586
  word: updateWord
505
587
  }
506
588
  },
507
- );
589
+ );
508
590
  expect(response).toBeDefined();
509
591
  });
510
- it('Search for custom object' , async () => {
592
+ it('Search for custom object', async () => {
511
593
  // Search doesn't work on objects that were very recently created
512
594
  const response = await api.searchCustomObjects(
513
595
  testObjType,
@@ -525,12 +607,12 @@ describe(`${config.label} API tests`, () => {
525
607
  }
526
608
  ]
527
609
  }
528
- );
610
+ );
529
611
  expect(response).toBeDefined();
530
612
  expect(response.results).toHaveProperty('length');
531
613
  expect(response.results[0].id).toBe(oneWord.id);
532
614
  });
533
- it('delete a Custom Object' , async () => {
615
+ it('delete a Custom Object', async () => {
534
616
  const response = await api.deleteCustomObject(testObjType, createdObject.id);
535
617
  expect(response.status).toBe(204);
536
618
  })
@@ -539,7 +621,7 @@ describe(`${config.label} API tests`, () => {
539
621
  const batchSize = 100;
540
622
  let createdBatch;
541
623
  it('Should bulk create a batch of objects', async () => {
542
- const range = Array.from({ length: batchSize }, (_, i) => i);
624
+ const range = Array.from({length: batchSize}, (_, i) => i);
543
625
  const objectsToCreate = range.map(i => ({
544
626
  properties: {
545
627
  word: `Test Bulk Create ${i}`
@@ -554,7 +636,9 @@ describe(`${config.label} API tests`, () => {
554
636
  createdBatch = response.results;
555
637
  })
556
638
  it('Should read a batch of objects', async () => {
557
- const inputs = createdBatch.map(o => {return {id: o.id}});
639
+ const inputs = createdBatch.map(o => {
640
+ return {id: o.id}
641
+ });
558
642
  const response = await api.bulkReadCustomObjects(
559
643
  testObjType,
560
644
  {
@@ -585,7 +669,9 @@ describe(`${config.label} API tests`, () => {
585
669
  expect(response.results.length).toBe(batchSize);
586
670
  });
587
671
  it('Should delete a batch of objects', async () => {
588
- const inputs = createdBatch.map(o => {return {id: o.id}});
672
+ const inputs = createdBatch.map(o => {
673
+ return {id: o.id}
674
+ });
589
675
  const response = await api.bulkArchiveCustomObjects(
590
676
  testObjType,
591
677
  {
@@ -615,8 +701,251 @@ describe(`${config.label} API tests`, () => {
615
701
  ]
616
702
  }
617
703
  );
618
- const inputs = response.results.map(o => {return {id: o.id}});
704
+ const inputs = response.results.map(o => {
705
+ return {id: o.id}
706
+ });
619
707
  await api.bulkArchiveCustomObjects(testObjType, {inputs});
620
708
  })
621
709
  })
710
+
711
+ describe('HS List Requests', () => {
712
+ it('Should get a list of lists', async () => {
713
+ const response = await api.searchLists();
714
+ expect(response).toBeDefined();
715
+ expect(response.lists).toHaveProperty('length');
716
+ });
717
+ let createdListId;
718
+ it('Should create a list', async () => {
719
+ const {list} = await api.createList('Test List', '0-2');
720
+ createdListId = list.listId;
721
+ });
722
+ it('Should get a list', async () => {
723
+ const response = await api.getListById(createdListId);
724
+ expect(response).toBeDefined();
725
+ expect(response.list.listId).toBe(createdListId);
726
+ })
727
+ it('Should add a record to list', async () => {
728
+ const companyResponse = await api.listCompanies();
729
+ const someCompanyId = companyResponse.results[0].id;
730
+ const response = await api.addToList(createdListId, [someCompanyId]);
731
+ expect(response).toBeDefined();
732
+ // HS has a typo in the response "recordsIds" instead of "recordIds"
733
+ expect(response.recordsIdsAdded).toHaveLength(1);
734
+ })
735
+ it('Should remove all records from list', async () => {
736
+ const response = await api.removeAllListMembers(createdListId);
737
+ expect(response.status).toBe(204);
738
+ })
739
+ it('Should delete a list', async () => {
740
+ const response = await api.deleteList(createdListId);
741
+ expect(response).toBeDefined();
742
+ expect(response.status).toBe(204);
743
+ })
744
+ });
745
+
746
+ describe('Association Labels', () => {
747
+ it('Should get association labels', async () => {
748
+ const labels = await api.getAssociationLabels('COMPANY', 'CONTACT');
749
+ expect(labels).toBeDefined();
750
+ expect(labels.results).toHaveProperty('length');
751
+ expect(labels.results.find(label => label.label && label.label.includes('Primary'))).toBeTruthy();
752
+ })
753
+
754
+ let createdBatch;
755
+ let toCompany;
756
+ beforeAll(async () => {
757
+ const batchSize = 20;
758
+ const range = Array.from({length: batchSize}, (_, i) => i);
759
+ const objectsToCreate = range.map(i => ({
760
+ properties: {
761
+ word: `Test Bulk Create ${Date.now()}${i}`
762
+ },
763
+ }))
764
+ const response = await api.bulkCreateCustomObjects(
765
+ testObjType,
766
+ {inputs: objectsToCreate}
767
+ );
768
+ expect(response.results).toHaveProperty('length');
769
+ expect(response.results.length).toBe(batchSize);
770
+ createdBatch = response.results;
771
+
772
+ const companyResponse = await api.listCompanies();
773
+ toCompany = companyResponse.results[0].id;
774
+ })
775
+
776
+ it('Should create batch default associations', async () => {
777
+ const inputs = createdBatch.map(o => {
778
+ return {
779
+ from: {id: o.id},
780
+ to: {id: toCompany}
781
+ }
782
+ });
783
+ const response = await api.createBatchAssociationsDefault(
784
+ testObjType,
785
+ 'COMPANY',
786
+ inputs
787
+ );
788
+ expect(response).toBeDefined();
789
+ expect(response).toHaveProperty('length');
790
+ expect(response.length).toBe(createdBatch.length * 2);
791
+ })
792
+
793
+ let createdLabel;
794
+ it('Should create a test association label', async () => {
795
+ const response = await api.createAssociationLabel(testObjType, 'COMPANY', {
796
+ inverseLabel: 'ooF',
797
+ name: 'Foo',
798
+ label: 'Foo',
799
+ });
800
+ expect(response).toBeDefined();
801
+ const {results} = response;
802
+ expect(results).toHaveProperty('length');
803
+ expect(results.length).toBe(2);
804
+ expect(results.find(label => label.label && label.label === 'Foo')).toBeTruthy();
805
+ createdLabel = results.find(label => label.label && label.label === 'Foo');
806
+ })
807
+
808
+ it('Should get association labels', async () => {
809
+ const labels = await api.getAssociationLabels(testObjType, 'COMPANY');
810
+ expect(labels).toBeDefined();
811
+ expect(labels.results).toHaveProperty('length');
812
+ expect(labels.results.find(label => label.label && label.label === 'Foo')).toBeTruthy();
813
+ const created = labels.results.find(label => label.label && label.label === 'Foo');
814
+ expect(created).toEqual(createdLabel);
815
+ })
816
+
817
+ it('Should associate a batch of objects', async () => {
818
+ const inputs = createdBatch.map(o => {
819
+ return {
820
+ types: [{
821
+ associationCategory: createdLabel.category,
822
+ associationTypeId: createdLabel.typeId
823
+ }],
824
+ from: {id: o.id},
825
+ to: {id: toCompany}
826
+ }
827
+ });
828
+ const response = await api.createBatchAssociations(
829
+ testObjType,
830
+ 'COMPANY',
831
+ inputs
832
+ );
833
+ expect(response).toBeDefined();
834
+ expect(response).toHaveProperty('length');
835
+ expect(response.length).toBe(createdBatch.length);
836
+ });
837
+
838
+ it('Should read the associations of a batch of objects', async () => {
839
+ const inputs = createdBatch.map(o => ({id: o.id}));
840
+ const response = await api.getBatchAssociations(
841
+ testObjType,
842
+ 'COMPANY',
843
+ inputs
844
+ )
845
+ expect(response).toBeDefined();
846
+ expect(response).toHaveProperty('length');
847
+ expect(response.length).toBe(createdBatch.length);
848
+ for (const a of response) {
849
+ expect(a).toHaveProperty('to');
850
+ expect(a.to[0].associationTypes).toHaveProperty('length');
851
+ expect(a.to[0].associationTypes.some(t => t.typeId === createdLabel.typeId)).toBe(true);
852
+ }
853
+ })
854
+
855
+ it('Should remove the specific labelled associations of a batch of objects', async () => {
856
+ const inputs = createdBatch.map(o => {
857
+ return {
858
+ types: [{
859
+ associationCategory: createdLabel.category,
860
+ associationTypeId: createdLabel.typeId
861
+ }],
862
+ from: {id: o.id},
863
+ to: {id: toCompany}
864
+ }
865
+ });
866
+ const response = await api.deleteBatchAssociationLabels(
867
+ testObjType,
868
+ 'COMPANY',
869
+ inputs
870
+ );
871
+ expect(response).toBeDefined();
872
+ expect(response.status).toBe(204);
873
+ })
874
+
875
+ it('Should delete an association label', async () => {
876
+ const response = await api.deleteAssociationLabel(testObjType, 'COMPANY', createdLabel.typeId);
877
+ expect(response).toBeDefined();
878
+ expect(response.status).toBe(204);
879
+ })
880
+
881
+ afterAll(async () => {
882
+ const inputs = createdBatch.map(o => {
883
+ return {id: o.id}
884
+ });
885
+ const response = await api.bulkArchiveCustomObjects(
886
+ testObjType,
887
+ {
888
+ inputs
889
+ }
890
+ );
891
+ expect(response).toBeDefined();
892
+ expect(response).toBe("");
893
+ });
894
+ });
895
+
896
+ describe('Properties requests', () => {
897
+ let groupeName;
898
+ it('Should retrieve a property', async () => {
899
+ const response = await api.getPropertyByName('tests', 'word');
900
+ expect(response).toBeDefined();
901
+ expect(response).toHaveProperty('label');
902
+ expect(response.label).toBe('Word');
903
+ groupeName = response.groupName;
904
+ });
905
+
906
+ it('Should create a property', async () => {
907
+ const response = await api.createProperty('tests', {
908
+ "name": "test_field",
909
+ "label": "Test Field",
910
+ "type": "enumeration",
911
+ "fieldType": "select",
912
+ "groupName": groupeName,
913
+ "description": "A test of enumerated fields",
914
+ "options": [
915
+ {
916
+ "label": "Item One",
917
+ "value": "item_one"
918
+ },
919
+ {
920
+ "label": "Item Two",
921
+ "value": "item_two"
922
+ }
923
+ ]
924
+ });
925
+ expect(response).toBeDefined();
926
+ expect(response).toHaveProperty('label');
927
+ expect(response.name).toBe('test_field');
928
+ });
929
+
930
+ it('Should update a property', async () => {
931
+ const existing = await api.getPropertyByName('tests', 'test_field');
932
+ existing.options.push(
933
+ {
934
+ "label": "Item Three",
935
+ "value": "item_three",
936
+ }
937
+ )
938
+ const response = await api.updateProperty('tests', 'test_field', existing);
939
+ expect(response).toBeDefined();
940
+ expect(response).toHaveProperty('options');
941
+ expect(response.options.some(o => o.label === 'Item Three')).toBeTruthy();
942
+ });
943
+
944
+ it('Should delete a property', async () => {
945
+ const response = await api.deleteProperty('tests', 'test_field');
946
+ expect(response).toBeDefined();
947
+ expect(response.status).toBe(204);
948
+ })
949
+
950
+ })
622
951
  });
@@ -1,6 +1,6 @@
1
- const { connectToDatabase, disconnectFromDatabase, createObjectId, Auther} = require('@friggframework/core');
2
- const { Authenticator, testAutherDefinition } = require('@friggframework/devtools');
3
- const { Definition} = require('../definition');
1
+ const {connectToDatabase, disconnectFromDatabase, createObjectId, Auther} = require('@friggframework/core');
2
+ const {Authenticator, testAutherDefinition} = require('@friggframework/devtools');
3
+ const {Definition} = require('../definition');
4
4
 
5
5
  const authorizeResponse = {
6
6
  "base": "/redirect/hubspot",
@@ -100,7 +100,7 @@ describe.skip('HubSpot Module Live Tests', () => {
100
100
  expect(firstRes.entity_id).toBeDefined();
101
101
  expect(firstRes.credential_id).toBeDefined();
102
102
  });
103
- it.skip('retrieves existing entity on subsequent calls', async () =>{
103
+ it.skip('retrieves existing entity on subsequent calls', async () => {
104
104
  const response = await Authenticator.oauth2(authUrl);
105
105
  const res = await module.processAuthorizationCallback({
106
106
  data: {