Closed mogarick closed 4 years ago
@ajredniwja is there a place where I can check how does the AWS SDK determines which of the runtimeConfig
files are used? I can see there are :
@aws-sdk/xxxxxxx/runtimeConfig.ts
@aws-sdk/xxxxxxx/runtimeConfig.browser.ts
@aws-sdk/xxxxxxx/runtimeConfig.native.ts
@aws-sdk/xxxxxxx/runtimeConfig.shared.ts
But I can't find out how o where is decided which one to use.
The thing is even though my Jest customenv.js
file extends from jest-environment-node
, when debugging I can see that in the end CognitoIdentityClient
imports a runtimeConfig
file that is really runtimeConfig.native
. and then everything breaks because of the problems already documented above.
I found this article New AWS SDK for JavaScript – Developer Preview where it states
Separate packages for browser and Node.js
... By publishing separate packages for Node.js and browser environments, we’ve removed the guesswork around which version your builds will use. This also allows us to use environment-specific typings. For example, streams are implemented with different interfaces in Node.js and browsers. Depending on which package you are using, the typings will reflect the streams for the environment you’ve chosen.
Where can I find the way to control which one is used?
That's my problem currently. That I'm running Jest like with node
mode but somehow inside amplify & aws-sdk they don't see this and try to use react-native
which causes the problem derived from the differences in streams management and so on. And even if I change to extend from jest-environment-jsdom
the fetch part continues being the problem because node-fetch
is not completely a mirror from Fetch API for web in the streams management and that gets me again in the same problem.
Thank you in advance for the help/hints you can give me.
Hey @mogarick thanks for reaching out. I believe this might be related to V3 but I can try to help you out.
Few things I would want you to do before we proceed further:
Thank you @ajredniwja. I'm gonna try out your suggestions. I'll let you know the outcome.
Hi @ajredniwja. I bumped the aws SDK. The blob problem was indeed solved but the other ones remain. I'm making other changes and tweaks to try to avoid the error. I'll keep the issue updated. I'll also try to implement an isolated code snippet and will share it here when done. Thank you
I have this exact issue. No matter how I set up the environment (even with latest aws-sdk) I cannot get past this error when calling Auth.SignIn() in integration tests:
console.log
[DEBUG] 02:26.792 AuthClass - cannot get cognito credentials TypeError: stream.getReader is not a function
at /Users/jimbo/Projects/xxxx/node_modules/@aws-sdk/fetch-http-handler/src/stream-collector.ts:23:17
at step (/Users/jimbo/Projects/xxxx/node_modules/tslib/tslib.js:141:27)
at Object.next (/Users/jimbo/Projects/xxxx/node_modules/tslib/tslib.js:122:57)
at /Users/jimbo/Projects/xxxx/node_modules/tslib/tslib.js:115:75
at new Promise (/Users/jimbo/Projects/xxxx/node_modules/core-js/modules/es.promise.js:233:7)
at Object.__awaiter (/Users/jimbo/Projects/xxxx/node_modules/tslib/tslib.js:111:16)
at collectStream (/Users/jimbo/Projects/xxxx/node_modules/@aws-sdk/fetch-http-handler/dist/cjs/stream-collector.js:32:20)
at Object.exports.streamCollector (/Users/jimbo/Projects/xxxx/node_modules/@aws-sdk/fetch-http-handler/dist/cjs/stream-collector.js:15:12)
at collectBody (/Users/jimbo/Projects/xxxx/node_modules/@aws-amplify/core/node_modules/@aws-sdk/client-cognito-identity/protocols/Aws_json1_1.ts:3388:18)
at collectBodyString (/Users/jimbo/Projects/xxxx/node_modules/@aws-amplify/core/node_modules/@aws-sdk/client-cognito-identity/protocols/Aws_json1_1.ts:3393:3) {
'$metadata': { attempts: 1, totalRetryDelay: 0 }
}
at ConsoleLogger._log (node_modules/@aws-amplify/core/src/Logger/ConsoleLogger.ts:99:4)
@mogarick I found a temporary work around for my tests. I have a typescript setup file (jest.setup.ts) and I added the following code to set up a "monkeypatch" for @aws-sdk/fetch-http-handler library. All my tests now pass. I basically changed the collectStream function to work on a node readable stream instead of a whatwg readablestream
import { StreamCollector } from '@aws-sdk/types';
import 'cross-fetch/polyfill';
jest.mock('@aws-sdk/fetch-http-handler', () => {
const { BrowserHttpOptions, FetchHttpHandler } = jest.requireActual(
'@aws-sdk/fetch-http-handler',
);
const newStreamCollector: StreamCollector = (
stream: any,
): Promise<Uint8Array> => {
return collectStream(stream);
};
async function collectStream(
stream: NodeJS.ReadableStream,
): Promise<Uint8Array> {
return new Promise((resolve, reject) => {
let res = new Uint8Array(0);
stream.on('data', (chunk) => {
const prior = res;
res = new Uint8Array(prior.length + chunk.length);
res.set(prior);
res.set(chunk, prior.length);
});
stream.on('end', function () {
resolve(res);
});
stream.on('error', function (err) {
reject(err);
});
});
}
return {
streamCollector: newStreamCollector,
BrowserHttpOptions,
FetchHttpHandler,
};
});
@jcbdev thanks for providing a workaround, @mogarickI would close this issue for now, please reach out if there are additional questions.
We have rolled up all our packages to latest versions and this problem persists for S3. In our case we are using Cypress for automated testing and the only area that is impacted is S3.
The below screenshot happens after automation has already authenticated, navigated to an area, and then we are using cypress to attach a file upload for testing. The result is it attempts to load these credentials again and fails on the streamReader.
This is exposed via window.LOG_LEVEL = 'DEBUG';
We are using version v2.829.0
of the aws-sdk within the project.
You can see it here:
@SourceCode Did you ever find a solution to this? This too affects our Cypress testing and we cannot get past it.
Problem still exists. IMO this shouldn't have been closed.
SDK version number 1.0.0-gamma.3(?)
I'm not sure. It's the
@aws-sdk
package that gets added when installingaws-amplify
. It's only a dir with many subdirectories, every one of them having its ownpackage.json
file. there ones I checked have"version": "1.0.0-gamma.3"
Is the issue in the browser/Node.js/ReactNative? A mix of Browser/Node.js/ReactNative
Details of the browser/Node.js/ReactNative version Browsers (I'm testing using chrome for the Expo web version of my app): Brave Browser: 80.1.5.123 Chrome: 85.0.4183.83 Firefox: 72.0.2 Safari: 13.1.2 Node: v12.18.3 React Native The one from Expo 37
TL&DR I have a React Active Expo + Amplify app. It has a graphql schema that includes
@auth
directives, withowner
andgroups
support and some with privateiam
provider permissions. Testing it manually via UI everything works ok. But using Jest I’m getting errors. Such errors are related with authentication but they can be traced to components responsible for cyphering (lib-typed-arrays
) and request and response processing (Blob
,Headers
,streamCollector
stream.getReader
) that I could see varies depending if the mode AWS SDK runs isnode
,react-native
, etc..I haven’t been able to find how I could control this running mode in order to being able to run my Jest tests without errors. So I’m not sure if this is a bug or something environment related that can be configured/tweaked somewhere.
Please help me to find a way to solve the problem or a hint about where else to look at.
Troubleshooting story
Problem 1.
Running a test with Jest, where I call
Auth.signIn
, I got this error:After setting
Logger.LOG_LEVEL=“DEBUG”
and troubleshooting I narrowed the problem to this fragment fromcrypto-js/lib-typed-arrays
used byamazon-cognito-identity-js
:the condition fails even though the value of
typedArray
is an instance ofUint8Array
. This only occurs when executing using Jest but not when using my App directly (UI). I could find the issue aws/aws-encryption-sdk-javascript#126 and with help from a comment on facebook/jest#7780 (comment) I addedtestEnvironment: “.path/to/my/customenv.js”
to thejest.config.js
file. This is thecustomenv.js
file.With this tweak the call to
Auth.signIn
was successful and the test could ran some queries withowners
restrictions.Problem 2
After solving Problem 1, I got a new one. This time when executing a test that requieres an operation with
authMode:AWS_IAM
. This is where I fell in a rabbit hole. It failed with this error first:Again with the logger activated I found this error as possible cause:
Troubleshooting the problem I traced the error to this fragment from
@aws-sdk/util-body-length-browser
So it appears the Jest test some how is triggering a browser mode for the AWS SDK, but Jest is running with
node
mode and Blob is not implemented in node or something like that. Troubleshooting the problem I followed some ideas from different GitHub issues and SO answers installedblob-polyfill
and added it as global to mycustomenv.js
file. So this is how it looked at this point:With this tweak the blob problem was gone but the
403
from the query persisted.Problem 2.1
After solving Problem 2 the new root error was this:
This time I traced the error presumably to this code fragment from
@aws-sdk/fetch-http-handler/dist/cjs/fetch-http-handler.js
:This again is presumably due the fact Jest is running with a
node
test environment and there is noHeaders
object there. So I tried to solve it usingnode-fetch
Headers
object and adding it to the globals in mycustomers.js
.This solved the
Headers
but as the code fragment shows, there’s also aRequest
object creating, so the new error now wasCredentials - Error loading credentials ReferenceError: Request is not defined
. I also addedRequest
fromnode-fetch
tocustomenv.js
This is the resultant file after the update.This tweaks solved the
Headers
andRequest
errors but the403
from the query persisted.Problem 2.2
After solving Problem 2.1 the new root error was:
The code fragment where the error occurs is this code from
amazon-cognito-identity-js/node_modules/isomorphic-unfetch/index.js
The error occurs when there is no global fetch present and then the last function is executed (
(function(url, opts)…)
) becauseprocess
is notundefined
. This means again AWS SDK is executing presumably innode
mode I noticed wile debugging, that theurl
param is theRequest
object so that’s why the error throws. Request doesn’t have a methodreplace
because its not a string. I hacked a little bit and modified the code to testif(typeof url !== “string” )
and if that’s the case I addedurl=url.url
. Doing that just got me to this other error:The same error also appear if I update my
customenv.js
file to addnode-fetch
asglobal.fecth
.The code fragment from
@aws-sdk/fetch-http-handler/dist/cjs/stream-collector.js
where the error it occurs is this:Debugging to get here the
stream
param has aZlib
prototype, sostream instanceof Blob
isfalse
andcollectStream
is called. The thing here is that this method expectsstream
to have agetReader
method and that’s where the dead ends appears because thestream
param doesn’t have such method. I assume this occurs due to AWS SDK is running innode
when I execute my Jest tests and the response object returned is not the same that the one forreact-native
mode. Innode
mode the object returned at the point of error is aZlib
stream. So this is the dead end for me because I think there no easy way to keep tweaking things anymore to work in Jest because it’s not definitively the right path.The right way to solve the root cause(?)
I think the right way is to make the Jest tests behave in such a way that AWS SDK runs in react-native mode or something like that but I don’t know how to achieve that. I hope some one can help me out on this or give a hint.