Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

462
Views
how to stub aws s3 upload with sinon

How to stubbing S3 upload in Node.js?

I'm using Mocha and Sinon. And I have a file that exports a class instance that including the upload method. It looks like this:

// storage.ts
import * as AWS from 'aws-sdk';
import archiver from 'archiver';
import retry from 'bluebird-retry';


export class Storage {
  private readonly s3: AWS.S3 = new AWS.S3({
    endpoint: MINIO_ENDPOINT,
    accessKeyId: AWS_ACCESS_KEY_ID,
    secretAccessKey: AWS_SECRET_ACCESS_KEY,
    s3ForcePathStyle: true,
    signatureVersion: 'v4',
  });
  private readonly uploadBucket: string = UPLOAD_BUCKET;
  private readonly downloadBucket: string = DOWNLOAD_BUCKET;

  public async upload(localPath: string, s3Key: string, onProgress: (progress: number) => void): Promise<void> {
    await retry(async () => { // Be careful, it will influence stub.
      const stat = fse.statSync(localPath);
      let readable: stream.Readable;
      let archive: archiver.Archiver | undefined;
      if (stat.isFile()) {
        readable = fse.createReadStream(localPath);
      } else {
        archive = archiver('zip', { zlib: { level: 0 } }).directory(localPath, false);
        readable = archive;
      }
      const request = this.s3.upload({ Bucket: this.uploadBucket, Key: s3Key, Body: readable });
      request.on('httpUploadProgress', ({ loaded }) => {
        onProgress(loaded);
      });
      if (archive) {
        archive.finalize().catch(console.error);
      }

      await request.promise().catch((err) => {
        fse.removeSync(localPath);
        throw err;
      });
    }, { max_tries: UPLOAD_RETRY_TIMES, throw_original: true });
  }

}

export const storage = new Storage();

I try to stub this upload method in my unit test, it looks like:

import { storage } from './storage';
import * as AWS from 'aws-sdk';
import sinon from 'sinon';

describe('Storage', () => {
  let sandbox: sinon.SinonSandbox;

  before(() => {
    sandbox = sinon.createSandbox();
  });

  afterEach(() => {
    sandbox.restore();
  });

  it('upload', async () => {

    const s3Stub = sandbox.stub(AWS.S3.prototype, 'upload'); // something wrong

    await storage.upload(
      './package.json',
      's3Key',
      uploadBytes => { return uploadBytes; });

    expect(s3Stub).to.have.callCount(1);
    s3Stub.restore();

  });
});

And I got an error:

Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

I want to test the upload method , but do not upload file to s3 really.

How should I do ?

Thank you everyone.

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Enable esModuleInterop: true config in your tsconfig.json file and change the import * as AWS from 'aws-sdk' to import AWS from 'aws-sdk'.

Since the new Storage() statement will execute instantly when you import the this module, you should import the ./storage.ts module after you stub AWS.S3 class.

P.S. I deleted the code not related to the problem

E.g.

storage.ts:

import AWS from 'aws-sdk';

const UPLOAD_BUCKET = 'UPLOAD_BUCKET';
const MINIO_ENDPOINT = 'MINIO_ENDPOINT';
const AWS_ACCESS_KEY_ID = 'AWS_ACCESS_KEY_ID';
const AWS_SECRET_ACCESS_KEY = 'AWS_SECRET_ACCESS_KEY';

export class Storage {
  private readonly s3: AWS.S3 = new AWS.S3({
    endpoint: MINIO_ENDPOINT,
    accessKeyId: AWS_ACCESS_KEY_ID,
    secretAccessKey: AWS_SECRET_ACCESS_KEY,
    s3ForcePathStyle: true,
    signatureVersion: 'v4',
  });
  private readonly uploadBucket: string = UPLOAD_BUCKET;

  public async upload(localPath: string, s3Key: string, onProgress: (progress: number) => void): Promise<void> {
    const request = this.s3.upload({ Bucket: this.uploadBucket, Key: s3Key, Body: '123' });
  }
}

export const storage = new Storage();

storage.test.ts:

import AWS from 'aws-sdk';
import sinon from 'sinon';

describe('68431461', () => {
  let sandbox: sinon.SinonSandbox;

  before(() => {
    sandbox = sinon.createSandbox();
  });

  afterEach(() => {
    sandbox.restore();
  });

  it('should pass', async () => {
    const s3InstanceStub = { upload: sandbox.stub() };
    const s3Stub = sandbox.stub(AWS, 'S3').callsFake(() => s3InstanceStub);
    const { storage } = await import('./storage');
    const onProgressStub = sandbox.stub();
    await storage.upload('./package.json', 's3Key', onProgressStub);
    sinon.assert.calledOnce(s3Stub);
    sinon.assert.calledOnce(s3InstanceStub.upload);
  });
});

test result:

  68431461
    ✓ should pass (796ms)


  1 passing (810ms)

------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------|---------|----------|---------|---------|-------------------
All files   |     100 |      100 |     100 |     100 |                   
 storage.ts |     100 |      100 |     100 |     100 |                   
------------|---------|----------|---------|---------|-------------------
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!