Using `createMockClient` for testing non react code? - apollo-client

I have mixed application that uses Apollo for both React and non-react code.
However, I can’t find documentation or code examples around testing non-react code with the apollo client,not using MockedProvider. I did, however, notice that apollo exports a mock client from the testing directory.
import { createMockClient } from '#apollo/client/testing';
I haven’t found any documentation about this API and am wondering if it’s intended to be used publicly and, if not, what the supported approach is for this.
The reason I need this is simple: When using Next.js’ SSR and/or SSG features data fetching and actual data rendering are split into separate functions.
So the fetching code is not using React, but Node.js to fetch data.
Therefore I use apolloClient.query to fetch the data I need.
When trying to wrap a react component around that fetching code in a test an wrap MockedProvider around that the apolloClient’s query method always returns undefined for mocked queries - so it seems this only works for the useQuery hook?
Do you have any idea how to mock the client in non-react code?
Thank you for your support in advance. If you need any further information from me feel free to ask.
Regards,
Horstcredible

I was in a similar position where I wanted to use a MockedProvider and mock the client class, rather than use useQuery as documented here: https://www.apollographql.com/docs/react/development-testing/testing/
Though it doesn't seem to be documented, createMockClient from '#apollo/client/testing' can be passed the same mocks as MockedProvider to mock without useQuery. These examples assume you have a MockedProvider:
export const mockGetAssetById = async (id: Number): Promise<any> => {
const client = createMockClient(mocks, GetAsset)
const data = await client.query({
query: GetAsset,
variables: id,
})
return data
}
Accomplishes the same as:
const { data } = useQuery(
GetAsset,
{ variables: { id } }
)

Related

Top Level Await for AsyncStorage in React Native

I am trying to implement top level await in my react native & expo environment so I can pull data from AsyncStorage and store it in a variable to use globally in my app.
I'm running the app on an android emulator. All I want to do is get the data and use it in my application, but the the variable always returns an empty object when called outside the async function. It seems to apply a value to the variable before the data from AsyncStorage is done loading.
async function getData(){
try {
const value = await AsyncStorage.getItem('redditInsights')
console.log('----------- getStore insights ---------')
const insights = JSON.parse(value)
console.log(insights) // -------------> returns desired data
return insights
}
catch (error) {
console.log(error)
}
}
const outsights = getData()
console.log("-------------------- outsights---------------------")
console.log(outsights) // ----------------------> returns empty object
I know I can pull the data inside an async function, but I can't use that data anywhere except inside the async function. I can't call a variable declared inside async outside of the function without it trying to apply a value to the variable before the data is even pulled.
Ideally I would simply store the data into a variable to use wherever I want without an async function like so, but this requires top level await support:
const value = await AsyncStorage.getItem('redditInsights')
const insights = JSON.parse(value)
I tried implementing top level await through numerous flags (--harmony-top-level-await, --experimental-repl-await, --experimental-top-level-await) at npm start like so: npm start --flag to no avail. I also upgraded to node v14.15.1 which is suppose to support top level await, but I still get an error.
How do I implement top level await in my react native & expo environment so I can use the data in my AsyncStorage
Or if anyone knows a better way to get my data from AsynStorage, I'm more than willing to try it out!!
The simple answer is this is not possible.
There's a more detailed answer about top level await in react-native here which says that React Native doesn't meet the requirements for top level await (uses node modules not ECMAScript native modules).
But your code sample has a mistake, you could declare a top level variable insights and assign the result of your async data to it. Your mistake is using the return value of getData you would need to declare a top level variable with let and then assign the result to it (so instead of return insights) you would do something like topScopeInsights = insights after a let topScopeInsights.
But, this doesn't make any sense, because you won't know if the data has arrived yet. The app will boot with your variable undefined and then you'll need to check if it has arrived or not. That's what promises are for.
So, back to my original answer, this is not possible. :-(

How to find Docs for Jest, Enzyme, Create-React-App, Shallow()?

Im using Create React App and have set up my test files like this:
import React from 'react';
import { shallow, configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Then I set up wrapper using shallow() like this:
let wrapper;
beforeEach(() => {
const defaultProps = {
color: 'orange',
value: 17,
title: 'live services',
link: 'htttp://google.com'
};
wrapper = shallow(<Callout {...defaultProps} />);
});
Im using assertions that I have been using for a while such as
expect(wrapper.find('h5').html()).toContain('some title');
expect(wrapper.containsMatchingElement(<Foo />)).toBe(true);
These assertions work but i want to find more.
I have no idea where to find the docs for the assertions that are available to me.
The assertions I have working so far look a bit like Jasmine assertions in that they are using camel case but the methods are still named differently.
https://jasmine.github.io/
I thought I was using jest and enzyme but the assertions are completely different to those in the Enzyme docs
https://airbnb.io/enzyme/
For example
expect(wrapper.find(Foo)).to.have.lengthOf(3);
Does not work. These methods of find() are not available to my current set up.
In the Jest Docs I can only find assertions for testing javaScript functions and can't find any methods for traversing and testing Virtual DOM or shadow DOM elements like the ones I have been using( see above)
https://jestjs.io/docs/en/jest-object
How do I see what assertions are available to shallow() and shallow.find() with my current setup?
You can find the Jest assertion methods here Jest assertion methods
You could also look at this library package https://www.npmjs.com/package/jest-enzyme

How do I add axios to react-redux-universal-hot-example starter kit?

So I picked react-redux-universal-hot-example as a starter kit.
I want to make ajax calls to 3rd party API.
(I want to use OpenWeatherMap API)
I want to use axios and react-promise middleware.
The first part installation is easy:
npm install --save redux-promise
npm install --save axios
Then I need to apply redux-promise middleware ... I think it goes into create.js somehow.
So I have several questions (all specific to react-redux-universal-hot-example) :
Is it the right way to do 3rd party calls using axios with redux-promise or the kit already have another way to do ajax requests?
Is create.js the right place to add redux-promise middleware?
Also, is there a concise syntax to apply multiple middlewares at the same time?
I am not 100% sure if you want to use react-promise or redux-promise. I am assuming the redux version. Which yea that create.js file is the right place to add it. You import a middleware from redux-promise and then add it to the lost of middlewares on line 9
import promiseMiddleware from 'redux-promise';
const middleware = [createMiddleware(client), reduxRouterMiddleware, promiseMiddleware];
So to answer your questions:
1. I am not 100% sure if the starter kit has a what to fetch 3rd party data. However using axios with redux-promise is exactly what I do.
2. Yes, see above on how.
3. Yep and that starter kit is showing one way which is creating an array of middlewares and then using the new spread operator it feed them into the applyMiddleware function. Which is a curried function that will then accept the createStore function. This is shown in the create.js file on line 21. Which is what the finalCreateStore will be during production.
4. The way I have been using this is with redux-actions which create Flux Standard Actions So..
// actionCreator
import { createAction } from 'redux-actions';
import { FETCH_DATA } from '../constants; // a file that exports constants
const fetchData = createAction(FETCH_DATA);
// reducer
const reducer = (state, action) => {
switch(action.type) {
case FETCH_DATA:
return {
...state,
fetchedData: action.payload.data
};
default:
return state;
}
}
// then dispatch the promise and not an action
store.dispatch(fetchData(axios.get('some_route')));
Then redux-promise 'intercepts' the promise and will resolve it. Once the promise resolves the action is then re-dispatched with the results in the payload. With axios you will get back an object that had the data you want as a property of that object. Which is shown is in the reducer with action.payload.data
A project I am working on that has this as an example.
Please not the actions have been wrapped with the dispatch call so all I have to do is call the actionCreators directly to get the same result as dispatching. This is explained in redux docs on bindActionCreators.
actionCreator
reducer
Component is where I dispatch the action
Where I hook up the middleware <-- similar to your create.js file
Again by dispatching the promise redux-promise intercepts(my way of understanding) the promise, resolves it and then dispatches the same action again but with the results of the promise on the payload property of the action object.

How can you mix Parse.Promise with other forms of Promise, e.g. Bluebird / ES6 native Promises?

I want to run some of my Parse Cloud Code on Heroku (Node) to kick start the migration process out of Parse's hosted Cloud Code.
One of the differences between the two environments is the fact that Parse SDK you use is different too. On node, I found that if you do a
var Parse require('parse/node').Parse;
... then Parse.Cloud.httpRequest is actually missing.
I was looking for Node alternatives for performing http requests and found request. But... it doesn't really fit in well with Parse Promises:
parsePromise1()
.then(parsePromise2) // okay
.then(requestPromise) // CUSTOM HTTP REQUEST!
.done(parsePromise3) // this Parse promise always succeeds, and occurs even before the request is fully completed.
I was wondering if anybody had found better ways of converting out of Parse Promises? Thanks.
You can use the request-promise package that wraps request with promises support or a library like bluebird that exposes a method that converts callback APIs to promises.
I recommend that you migrate from Parse promises which are suboptimal to ES2015 native promises (or, more powerful alternatives like bluebird). With those you could:
Promise.resolve(someParsePromise).then(() => // convert
return someParsePromiseFn()// return some Parse promise, that works
}).then(res => {
// more async work ...
});
And avoid .done altogether.
Its not ideal at all, but you can use this kind of wrapper from native Bluebird to native promises:
const Promise = require('bluebird')
function handle () {
return new Promise((resolve, reject) => {
handleWithNativePromise(...arguments)
.then(resolve)
.catch(reject)
})
}

Adding a method to Bluebird promise

I have promisified Mongoose. I have some methods that extent Mongoose Query that now would need to be added to Bluebird. I don't mind extending Mongoose but do not want to take the same approach for this more gobal library. Looking through the docs I see some potentials but I am not sure.
I would like to come as close/clean as the following:
Model.findAsync().toCustom();
toCustom is basically a form of toJSON which 1) execs the query and 2) custom outputs the results/create custom errors etc... pretty straighforward.
What is the cleanest way to achieve something like the above? I would like to avoid doing this each time:
Model.findAsync().then(function(docs) {
return toCustom(docs);
}, function(err) {
return toCustom(err);
});
You get the idea...
Bluebird actually supports your use case directly. If you need to publish a library that extends bluebird in your own custom way you can get a fresh copy of bluebird by doing:
var Promise = require("bluebird/js/main/promise")();
Promise.promisifyAll(require("mongoose")); // promisify with a local copy
Promise.prototype.toCustom = function(){
return this.then(toCustom, toCustom); // assuming this isn't just `.finally`
};
You might also want to export it somehow. This feature is designed for library authors and for getting an isolated copy of bluebird. See the for library authors section in the wiki.

Resources