Is your feature request related to a problem? Please describe.
I am attempting to write unit tests in Jest for React Native components that interact with Amplify DataStore.
Typically I would mock out external dependencies such as DataStore, but as it doesn't make network calls (if not wired to AppSync) and is hard to mock in a way that avoids false positives from making incorrect assumptions because it's such a black box, I would prefer to not mock DataStore out and validate that the correct data is added/updated/deleted from the React Native components.
Describe the solution you'd like
Using DataStore in our unit tests do not work since there is no AsyncStorage to back the DataStore with when running outside the App environment. Therefore I'm looking for good suggestions here.
One possibility would be for a new Storage Adapter to be created to support a unit test environment in Jest. I don't know enough detail about DataStore, but it seems like that may be a viable option.
Describe alternatives you've considered
For now we've reverted to just mocking out DataStore but concerned we'll miss errors that will only show up in Production. Our automated end-to-end testing has hit a roadblock due to Detox flakiness, and so we were hoping to create unit/integration tests in Jest with react-native-testing-library that integrated with DataStore to at least test our data integration.
Additional context
I did look for documentation on creating a custom Storage Adapter but didn't see any and I'm concerned it may be beyond what can be reasonably achieved without detailed knowledge of how DataStore is implemented.
/cc @undefobj as discussed
Hi @danrivett , have you considered using a mock of Async Storage itself. You can use something like: https://www.npmjs.com/package/mock-async-storage
Also you could create your own Mock of it since the API surface is quite small, and just use a in memory Map to store the key value pairs.
We are adding some unit tests to DataStore React Native soon, and can share that with you once the PR is out.
Interesting @Ashish-Nanda. I did consider that package actually, but I have no experience with it so was a bit unsure whether it would be suitable.
I will check it out, but I would also appreciate if you could share any findings you have with your unit tests as that definitely would be helpful for me. Thanks.
For other's benefit, I looked further into this after @Ashish-Nanda's suggestion and it appears tha the DataStore AsyncStorage interaction is limited to just the AsyncStorageDatabase class, and so that should make it easier to mock out AsyncStorage as suggested since it's easy to see all the interactions with it.
We will give it a go and report back on how successful we are, looks promising 馃憤
@danrivett
Hope the above suggestion was helpful in enabling you to unit test DataStore in React Native.
As promised here is a link to our unit tests which we merged recently: https://github.com/aws-amplify/amplify-js/blob/master/packages/datastore/__tests__/AsyncStorage.ts
Closing the issue as you should be able to use either mock-async-storage or the above file as a reference for your unit tests.
Thanks @Ashish-Nanda that example is really helpful, I'll pass it onto my team.
@Ashish-Nanda I know this ticket has been closed but we only just attempted to mock out AsyncStorage as we had a number of existing tests which mocked out DataStore itself and didn't have the time to refactor them until now.
We've run into 2 problems so far that I was hoping you would be able to comment on. I'm quoting from one of the developers on my team who worked on this story:
@aws-amplify/datastorestill uses AsyncStorage from the 'react-native' package. It started to be deprecated more than 1 year ago, and it鈥檚 impossible to set the custom AsyncStorage while Datastore is initializing.In this case 2 options are available: writing a custom mock for AsyncStorage or using mock-async-storage package 1.x.x version. Unfortunately,
mock-async-storageproduces an error, so I had to write the custom mock for theAsyncStorage.
- Thanks to the
AsyncStoragemock we are able to observe its methods, and then check keys and values. Datastore keeps all the keys as@AmplifyDatastore::${storeName}::Data::${ulid}::${id}and the values as JSON.
storeName =${namespaceName}_${modelName}, for example 'user_MyModel';
ULID= the value which is generated in the runtime;
id= the id of the model, we can get it from newDataStoreModel().id;
The problem here is next: it鈥檚 not possible to retrieve the correct ULID from the datastore package. It鈥檚 only possible inside this package.
I haven't been able to verify this myself, but looking at the getKeyForAsyncStorage() function in AsyncStorage test file here it doesn't appear this can be implemented outside this package.
I'd really appreciate your thoughts on this, and if it is possible to improve the DataStore package in order to effectively unit test code that uses DataStore since currently by mocking out DataStore itself we cannot effectively test that we are querying DataStore correctly for example.
This would be a _huge_ help in us creating effective unit tests that integrate with DataStore (we have many such files in our app).
I'd also like to see switching to @react-native-community/async-storage finally implemented as you mentioned in #6031 back in June it would be implemented in the near future, and I understand it's a question of priorities, but this would be really helpful.
Thanks @Ashish-Nanda.
Most helpful comment
For other's benefit, I looked further into this after @Ashish-Nanda's suggestion and it appears tha the DataStore
AsyncStorageinteraction is limited to just theAsyncStorageDatabaseclass, and so that should make it easier to mock outAsyncStorageas suggested since it's easy to see all the interactions with it.We will give it a go and report back on how successful we are, looks promising 馃憤