Repository: algorand/js-algorand-sdk
Pull request #502 (2022-01-20 09:31:50)

Fix JSON decoding
Hey team,

I think I found a bug in how we decode json responses; essentially, we always pick the wrong parser.

Look at the following code snippet:

```typescript
  const assetDetails = await client
    .getAssetByID(ASAIdx)
    .setIntDecoding(algosdk.IntDecoding.BIGINT)
    .do();
  console.log(typeof assetDetails.params.total);
```

Before: `number`
Now: `bigint`

I also think that we should add a unit test for this. My JS skills are somehow limited, but I'd be happy to give it a shot if you point me in the right direction :)

jasonpaulos: @aldur thank you for catching this! I agree we should also have a unit test for this before merging.

Perhaps you could make the `HTTPClient.parseJSON` function public (in order to test it) and add a unit test in `tests/9.Client.ts`?
aldur: Added unit tests :)

Patch:
diff --git a/src/client/client.ts b/src/client/client.ts
index 170b487..8be88c1 100644
--- a/src/client/client.ts
+++ b/src/client/client.ts
@@ -140,15 +140,14 @@ export default class HTTPClient {
    * @param status Status of the response (used in case parseJSON fails)
    * @param jsonOptions Options object to use to decode JSON responses. See
    *   utils.parseJSON for the options available.
-   * @private
    */
-  private static parseJSON(
+  public static parseJSON(
     text: string,
     status: number,
     jsonOptions: utils.JSONOptions = {}
   ) {
     try {
-      if (Object.keys(jsonOptions).length !== 0) {
+      if (Object.keys(jsonOptions).length === 0) {
         return text && JSON.parse(text);
       }
       return text && utils.parseJSON(text, jsonOptions);


Test patch:
diff --git a/tests/9.Client.ts b/tests/9.Client.ts
index 67b1141..9c87600 100644
--- a/tests/9.Client.ts
+++ b/tests/9.Client.ts
@@ -1,6 +1,8 @@
 import assert from 'assert';
 import HTTPClient from '../src/client/client';
 import { URLTokenBaseHTTPClient } from '../src/client/urlTokenBaseHTTPClient';
+import IntDecoding from '../src/types/intDecoding';
+import * as utils from '../src/utils/utils';
 
 describe('client', () => {
   describe('url construction', () => {
@@ -33,6 +35,40 @@ describe('client', () => {
       assert.strictEqual(actual, expected);
     });
 
+    it('should encode and decode values correctly', () => {
+      const j = '{"total":18446744073709551615, "base":42}';
+
+      let options = {
+        // intDecoding: IntDecoding.DEFAULT,
+      };
+      let actual = HTTPClient.parseJSON(j, 200, options);
+      let expected = JSON.parse(j);
+      assert.strictEqual(actual.total, expected.total);
+      assert.strictEqual(typeof actual.total, 'number');
+
+      options = {
+        intDecoding: IntDecoding.BIGINT,
+      };
+      actual = HTTPClient.parseJSON(j, 200, options);
+      expected = utils.parseJSON(j, options);
+      assert.strictEqual(actual.total, expected.total);
+      assert.strictEqual(typeof actual.total, 'bigint');
+
+      options = {
+        intDecoding: IntDecoding.MIXED,
+      };
+      actual = HTTPClient.parseJSON(j, 200, options);
+      expected = utils.parseJSON(j, options);
+      assert.strictEqual(actual.total, expected.total);
+      assert.strictEqual(typeof actual.total, 'bigint');
+      assert.strictEqual(typeof actual.base, 'number');
+
+      options = {
+        intDecoding: IntDecoding.SAFE,
+      };
+      assert.throws(() => HTTPClient.parseJSON(j, 200, options), Error);
+    });
+
     it('should handle slash variations on complex paths', () => {
       const regularBase = 'https://localhost/absolute';
       const regularBaseWithFinalSlash = `${regularBase}/`;