node.jsamazon-web-servicesamazon-s3aws-lambdaaws-sdk-nodejs

Mock AWS S3 Select Response with Jest and AWS SDK V3


I am using S3 Select to query the CSV file and extract the rows out of it in my nodejs application. How to write a unit test to mock the response of the SelectObjectContentCommand. The response is of type SelectObjectContentCommandOutput

import { SelectObjectContentCommand, S3Client, ExpressionType, FileHeaderInfo } from '@aws-sdk/client-s3';

const s3Client = new S3Client({});

export const getDataUsingS3Select = async (bucketName: string, fileName: string, query: string, params: any) => {
  
  const command = new SelectObjectContentCommand(params);
  const response = await s3Client.send(command);

  if (response.$metadata.httpStatusCode === 200) {
    if (response.Payload) {
      const data = convertDataToJson(response.Payload);
      return data;
    } else {
      console.log(`S3Select did not have payload for ${bucketName}/${fileName}`);
      return [];
    }
  } else {
    console.log(`S3Select did not receive 200 for ${bucketName}/${fileName}. 
    Metadata is ${response.$metadata}`);
    return [];
  }
}

Solution

  • I got this working by using the Symbol.asyncIterator property:

    class MockAsyncIterator {
      constructor(readonly chunks: string[]) {
      }
    
      async* [Symbol.asyncIterator]() {
        for (const c of this.chunks) {
          yield { Records: { Payload: Buffer.from(c, "utf8") } }
        }
      }
    }
    

    then, using aws-sdk-client-mock we can test your function like so:

    import { mockClient } from "aws-sdk-client-mock";
    const s3Mock = mockClient(S3Client);
    
    test("s3 query", async () => {
      s3Mock.on(SelectObjectContentCommand).resolves({
        Payload: new MockAsyncIterator(["column1,column2", "value1,value2"]),
        "$metadata": {
          httpStatusCode: 200
        }
      })
    
      const query = {
        // query params
      };
    
      const result = await getDataUsingS3Select("my-bucket", "my.csv", "SELECT * FROM S3Object", query);
      expect(result).toBeDefined();
      // additional checks
    });