Global Loading Flag for Apollo Client - apollo

Is there a global loading flag available anywhere for react-apollo client? I have a “page wrapper” component that i’d like to apply ui effects to after all the child components have received their data.
I have set up apollo with redux so have ready access to the store (http://dev.apollodata.com/react/redux.html)
I could quite easily dispatch state changes from each component that receives data from apollo but I'd like this page wrapper component to not have any knowledge of its children nor their queries.
I have investigated using withApollo - http://dev.apollodata.com/react/higher-order-components.html#withApollo -
but don't see an api for a global is loading.

I've just released a library that solves this for Apollo 2: react-apollo-network-status.
The gist is:
import React, {Fragment} from 'react';
import ReactDOM from 'react-dom';
import {ApolloClient} from 'apollo-client';
import {createNetworkStatusNotifier} from 'react-apollo-network-status';
import {createHttpLink} from 'apollo-link-http';
const {
NetworkStatusNotifier,
link: networkStatusNotifierLink
} = createNetworkStatusNotifier();
const client = new ApolloClient({
link: networkStatusNotifierLink.concat(createHttpLink())
});
// Render the notifier along with the app. The
// `NetworkStatusNotifier` can be placed anywhere.
const element = (
<Fragment>
<NetworkStatusNotifier render={({loading, error}) => (
<div>
{loading && <p>Loading …</p>}
{error && <p>Error: {JSON.stringify(error)}</p>}
</div>
)} />
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</Fragment>
);
const node = document.getElementById('root');
ReactDOM.render(element, node);

You can achieve this in two ways:
One way is to use the middleware/afterware of Apollo's network interface.
The other way is to wrap Apollo's network interface to include your custom logic. Specifically you would wrap the query method.

Related

Add dynamic components to predefined aws-amplify react code

I have some figma designs which I have converted to react code with the help of aws-amplify. Now, the problem is, they are predifined components built with #aws-amplify/ui-react.
For Example:
/***************************************************************************
* The contents of this file were generated with Amplify Studio. *
* Please refrain from making any modifications to this file. *
* Any changes to this file will be overwritten when running amplify pull. *
**************************************************************************/
/* eslint-disable */
import React from "react";
import { getOverrideProps } from "#aws-amplify/ui-react/internal";
import { Button, Text, View } from "#aws-amplify/ui-react";
export default function DataAbc(props) {
const { overrides, ...rest } = props;
return (
<View
width="868px"
height="220px"
display="block"
gap="unset"
alignItems="unset"
justifyContent="unset"
{...rest}
{...getOverrideProps(overrides, "DataAbc")}
>
<Text
direction="column"
justifyContent="unset"
width="unset"
height="unset"
gap="unset"
alignItems="unset"
position="absolute"
top="72px"
left="34px"
children="Upload files"
{...getOverrideProps(overrides, "Upload files")}
></Text>
<Text
width="unset"
height="unset"
gap="unset"
alignItems="unset"
position="absolute"
top="98px"
left="34px"
padding="0px 0px 0px 0px"
whiteSpace="pre-wrap"
children="pqr"
{...getOverrideProps(
overrides,
"pqr"
)}
></Text>
<Button
display="flex"
gap="0"
direction="row"
width="180px"
height="unset"
justifyContent="center"
variation="primary"
children="Choose files"
{...getOverrideProps(overrides, "Button")}
></Button>
</View>
);
}
Inside the "DataAbc" component after the "Button", I want to populate some components like <p>,<h1>,etc dynamically from data fetched from the server.
Is there any way of doing it ?
I tried doing this:
<DataAbc>`<p>Hello</p>`<DataAbc/>
and I have also tried something like this:
<DataAbc>`{React.createElement('p',{},'Hello'}`</DataAbc>
I also tried to change DataAbc with overrides property.
But nothing seems to work.

UI Kitten & React Native Web no custom mapping

I am having an issue trying to load the most basic custom mapping in React Native Web. The custom styles are loading just fine in the App, but not Web. Using the latest version with the babel loader hack as proposed here. I am using the default mapping as proposed in the UI Kitten docs for v5.x
My code looks like this:
import * as eva from '#eva-design/eva'
import * as mapping from '../styles/mapping.json'
import { myTheme } from '../styles/light-theme'
export default function App(): React.ReactElement {
return <>
<ApplicationProvider {...eva} theme={myTheme} customMapping={mapping}>
...
</ApplicationProvider>
</>
}
I tried replicating with a blank repo and it was working fine, so one line at a time I figured out that my import was not correct (not readable by babel?).
Instead of:
import * as mapping from '../styles/mapping.json'
Should be:
import {default as mapping} from '../styles/mapping.json'
The correct way is suggested in the UIKitten docs, so I don't think it will happen to many, but may help others as it's not an obvious thing if someone is working with the App emulator for the most time and not checking the Web until later.
This is the way I use the custom mapping with ts file: custom-mapping.ts
export const customMapping: any = {
components: {
CircleButton: {
meta:{...},
appearances: {...}
}
}
}
and import it like this:
...
import {customMapping} from '../custom-mapping';
<ApplicationProvider
...
customMapping={{...eva.mapping, ...customMapping}}
>
{children}
</ApplicationProvider>

How can I spy on TouchableNativeFeedback onPress in React Native with #testing-library/react-native?

Help me please...
I have a React Native custom Button component that receives an onPress prop and passes that onPress to a TouchableNativeFeedback. I make a unit testing with #testing-library/react-native. I try to spy on onPress, to check if it is triggered when the TouchableNativeFeedback is touched. Somehow the spy function is not called when I simulate press event on the Button. Is there any mistake in my implementation?
FI: This behavior only occurs in TouchableNativeFeedback, but working perfectly with Button
Here is my implementation:
Button.js
const Button = ({onPress, label}) => (
<TouchableNativeFeedback onPress={onPress} testID="button">
<View style={someStyling}>
<Text>{label}</Text>
</View>
</TouchableNativeFeedback>
)
export default Button
Button.test.js
it("Fire onPress props when button pressed", () => {
const mockFn = jest.fn();
const { getByTestId } = render(<Button onPress={mockFn} />);
const button = getByTestId("button");
fireEvent.press(button);
expect(mockFn).toHaveBeenCalled();
});
I had the same issue in a component using <TouchableNativeFeedback/>. My test case failed with a message saying No instances found on the getByText call.
After few attempts, I used following snippet for debugging:
const { debug } = render(<Tag onPress={handler}>Press me</Tag>);
debug();
Along with some other details, following message popped up in console:
TouchableNativeFeedback is not supported on this platform!
At this moment, there is a related thread regarding Touchable* components on react-native-testing-library GH issues where they explain details and provide some workarounds.
I ended up using platform detection in my component, as that's what I wanted to do anyway:
const TouchComponent =
Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity;
return (
<TouchComponent onPress={onPress}>
...
</TouchComponent>
);
I had the same issue.
What solved it for me was that fact that my TouchableXXX component was imported fromreact-native-gesture-handler. This library probably was imported as dependency by one of my dependecies. I guess when I wrote TouchableXXX it was imported automatically from there by my IDE.
After changing the import statement to import from react-native - everything worked for me in tests.
So eventually my change was from this:
import { TouchableHighlight } from 'react-native-gesture-handler'
to this
import { TouchableOpacity } from 'react-native'

Can't Figure out the Syntax Error in App.js

I am using this tutorial to install React for the front with an API built in Django.
https://sweetcode.io/how-use-djang-react-ap/
My repository for this projects so far is here:
https://github.com/AlexMercedCoder/DjangoReactCRM
When I npm run dev I get a syntax error in App.js, I've played with it and can't seem to figure it out. The error I get is.
ERROR in ./frontend/src/components/App.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError:
C:\Users\alexm\projects\DjangoReactCRM\drcrm\frontend\src
\components\App.js: Unexpected token, expected "," (29:6)
27 |
28 | wrapper ? ReactDOM.render(<app>, wrapper) : null;
> 29 | </app>
App.js
import React, { Component } from "react";
import ReactDOM from "react-dom";
class App extends Component {
state = {
data: ''
};
componentDidMount() {
fetch("/api")
.then(response => {
return response.json();
})
.then(data => this.setState({ data: JSON.stringify(data)}));
}
render(){
return (
<p>Jason data = {this.state.data}</p>
)
}
}
wrapper ? ReactDOM.render(<app>, wrapper) : null;
</app>
First, the <app> component is closed outside the ternary operator, so you'd have to use <app></ app> or even simpler <app />.
wrapper ? ReactDOM.render(<app></app>, wrapper) : null;
or
wrapper ? ReactDOM.render(<app/>, wrapper) : null;
Then, all React components must start with a capital letter
to differentiate default DOM component from those created with React, so you have to use this notation.
wrapper ? ReactDOM.render(<App />, wrapper) : null;
Finally, I do not see the utility of the ternary operator at the end of your code. Normally, the second argument when we call reactDOM.render(X, Y) must represent the DOM element in which we will render our main React component (in this case, <App />).
By default, when we create a React project with create-react-app, we don't have to deal with these settings and the DOM element is automatically defined as <div id='root'></div> (check inside the <body> in public/index.html inside your project root).
So call document.getElementById('root') to get the DOM element and simply put the result as second argument.
ReactDOM.render(<App />, document.getElementById('root'));
If it persist, I suggest you to simply create another React project with create-react-app and copy/paste only the code you need.
To get more informations: Click here
I hope it can help you.
** I apologize if my explanations are not clear or if I made some mistakes.
There are three problems in your component.
I'm guessing wrapper was supposed to be document.getElementById("root") ? Even then the ternary condition doesn't make sense. It should be something like:
ReactDOM.render(
<App />,
document.getElementById("root")
)
You defined the component as App, yet in ReactDOM.render you are using app
You have </app> at the end of the file. It doesn't do anything in this case.

How to mock global Vue.js variable in JEST test

I have a global property/variable with my app urls:
Vue.prototype.$apiUrls = {
root: 'http://localhost:8080/',
api: 'api/v1/'
// etc.
}
I use it inside my components as axios request:
axios.get(`${this.$apiUrls.root}${this.$apiUrls.api}/users/`)
Now I want to test my component's code, I've mocked axios already, but still I receive an error:
TypeError: Cannot read property '$apiUrls' of undefined
I've tried to define/mock this property inside each test and/or in JEST's setup file, like e.g.
global.$apiUrls = {...}
// or
Vue.prototype.$apiUrls = {...}
// or
Object.defineProperties(Vue.prototype, {$apiUrls: {...}})
I've also tried mocking it to window or this (yeah, thats silly), but with no success - I still receive that error - please help.
There is two ways to achieve this. One is using the Config option, as mentioned by #Aldarund. You can read about it here.
If you are using Jest, I recommend doing this in the jest.init.js file:
import { config } from '#vue/test-utils'
config.mocks['$apiUrls'] = {
'some/endpoint'
}
Then add this to the jest section of your package.json:
"setupFiles": [
"<rootDir>/jest.init.js"
]
Now it is globally mocked. If you want to do this on a per test basis, you can use the mocks mounting option:
const wrapper = shallowMount(Foo, {
mocks: {
$apiUrls: 'some/endpoint'
}
})
Hopefully this helps!
If you are interested I am compiling a collection of simple guides on how to test Vue components here. It's under development, but feel free to ask make an issue if you need help with other related things to testing Vue components.
I don't think the answers above work anymore (in 2020).
Here's what worked for me:
For vue-test-utils 1.x.x (Vue 2)
Create a new file, name it eg. jest.init.js
Give it the following content:
import { config } from "#vue/test-utils";
config.mocks["yourGlobalProperty"] = label => label; //you can replace it with your own mock
Add this to your jest.config.js (actually write "rootDir", don't replace anything with a real path)
module.exports = {
setupFiles: ["<rootDir>/jest.init.js"]
}
These files will be only ran before jest runs unit tests.
Note that I'm importing {config}, not the default export. I don't know why the default didn't work for me. Even the documentation for vue test utils doesn't import the default export anymore
Also make sure you're not trying to import from the old vue-test-utils package. (The new one is #vue/test-utils)
For #vue/test-utils 2.x.x (vue-test-utils-next) (Vue 3)
Follow steps like for 1.x.x above, but in step two, do this instead:
import { config } from "#vue/test-utils"; //2.0.0-beta.5
config.global.mocks = {
yourGlobalProperty: label => label
};
You can do it with vue-test-utils beta 15 and later.
Here docs
And some example would be:
import VueTestUtils from '#vue/test-utils'
VueTestUtils.config.mocks['$apiUrls'] = {
...
}