¿Cómo stubbing S3 upload en Node.js?
Estoy usando Mocha y Sinon. Y tengo un archivo que exporta una instancia de clase que incluye el método de carga. Se parece a esto:
// 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();Intento bloquear este método de carga en mi prueba unitaria, se ve así:
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(); }); });Y tengo un error:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.Quiero probar el método de carga, pero en realidad no cargue el archivo a s3.
Cómo debería hacer ?
Gracias a todos.
Habilite esModuleInterop: true config en su archivo tsconfig.json y cambie import * as AWS from 'aws-sdk' to import AWS from 'aws-sdk' .
Dado que la new Storage() se ejecutará instantáneamente cuando importe este módulo, debe importar el módulo ./storage.ts después de agregar la clase AWS.S3 .
PD : eliminé el código que no está relacionado con el problema.
P.ej
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); }); });resultado de la prueba:
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 | ------------|---------|----------|---------|---------|-------------------