You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Node.js 14环境下使用AWS SDK v3调用transformToWebStream报错及单元测试问题

Node.js 14环境下使用AWS SDK v3调用transformToWebStream报错及单元测试问题

我完全懂你现在的困扰——在Node.js 14环境下用AWS SDK v3做S3文件下载的单元测试时,调用transformToWebStream()触发了版本兼容报错,提示Readable.toWeb() is not supported。这是因为transformToWebStream()底层依赖Node.js 17+才引入的stream.Readable.toWeb()方法,而Node.js 14原生并没有这个API,直接用原生Readable包装的SDK Stream自然会报错。

下面给你两个实用的解决办法,还有一个测试里的小坑要注意:

解决方案一:直接Mock符合要求的SDK Stream对象

最直接的方式是不用原生Node Stream,而是自己创建一个Mock对象,直接实现transformToWebStream()方法,完全绕开版本兼容问题。修改你的测试代码如下:

it('should be able to downloadFromS3()', async () => {
  // 创建一个Mock的SDK Stream,直接实现transformToWebStream方法
  const mockSdkStream = {
    transformToWebStream: () => {
      // 返回一个模拟的Web ReadableStream,对应你要测试的内容
      return new ReadableStream({
        start(controller) {
          // 把测试用的字符串转成Uint8Array,模拟文件内容
          controller.enqueue(new TextEncoder().encode('hello world'));
          controller.close();
        }
      });
    }
  };

  const mockS3Client = mockClient(S3Client);
  // 只需要Mock GetObjectCommand,你的生产代码里没调用HeadObject
  mockS3Client.on(GetObjectCommand).resolves({ Body: mockSdkStream });

  const result = await downloadFromS3({
    name: 'name',
    s3Key: 's3Key',
  } as Document);

  // 只断言GetObjectCommand被调用即可
  expect(mockS3Client).toHaveReceivedCommand(GetObjectCommand);
});

解决方案二:给Node.js 14添加toWeb方法的Polyfill

如果希望保留原生Stream的使用方式,可以给Node.js 14的Readable原型添加toWeb()的polyfill,让SDK的transformToWebStream()能正常调用。在测试文件顶部添加这段代码:

import { Readable } from 'stream';

// 给Node.js 14的Readable添加toWeb方法的polyfill
if (!Readable.prototype.toWeb) {
  Readable.prototype.toWeb = function() {
    return new ReadableStream({
      async start(controller) {
        try {
          // 遍历Node流的内容,转发到Web流
          for await (const chunk of this) {
            controller.enqueue(chunk);
          }
          controller.close();
        } catch (err) {
          controller.error(err);
        }
      }
    });
  };
}

之后你原来的测试代码就可以正常运行了,sdkStreamMixin包装的原生Readable现在能调用toWeb()方法,不会再报错。

额外注意:移除不必要的HeadObjectCommand断言

看你的测试代码里Mock了HeadObjectCommand还加了断言,但你的生产代码downloadFromS3()里并没有调用这个命令,这会导致测试失败哦。记得把这两行删掉:

mockS3Client.on(HeadObjectCommand).resolves({ /* 模拟响应 */ });
expect(mockS3Client).toHaveReceivedCommand(HeadObjectCommand);

备注:内容来源于stack exchange,提问作者LP13

火山引擎 最新活动