I'm integrating recaptcha to my react app and I'm having this error: "Missing required parameters: sitekey" when I use the render method of grecaptch even though I have properly included the sitekey in to the parameters.
Here is my code for reference:
class ReCaptcha extends React.Component {
componentDidMount() {
this.callbackName = 'g-lf-callback';
window[this.callbackName] = this.props.callback;
if(window.grecaptcha) {
this.renderRecaptcha();
} else {
this.loadRecaptchaScript();
}
}
componentWillUnmount() {
delete window['rconload'];
delete window[this.callbackName];
}
loadRecaptchaScript() {
window['rconload'] = () => {
this.renderRecaptcha();
};
let url = 'https://www.google.com/recaptcha/api.js?onload=rconload&render=explicit';
loadScript(url, '', 'recaptcha', true, true)
.then( () => {})
.catch( () => {});
}
renderRecaptcha = () => {
if(this.container) {
let parameters = {
sitekey: process.env.MY_SITEKEY,
size: 'invisible',
badge: null,
callback: 'g-lf-callback'
};
const recaptchaId = window.grecaptcha.render(this.container, parameters);
this.execute = () => window.grecaptcha.execute(recaptchaId);
this.reset = () => window.grecaptcha.reset(recaptchaId);
this.getResponse = () => window.grecaptcha.getResponse(recaptchaId);
}
}
onClick = () => {
this.execute();
}
render() {
let { callback, label, className, ...btnProps } = this.props;
return (
<Button
{ ...btnProps }
className={ className }
onClick={ this.onClick }
ref = { ref => this.container = ref }
>
{ label }
</Button>
)
}
}
I have also set the render parameter of recaptcha url to explicit
https://www.google.com/recaptcha/api.js?onload=rconload&render=explicit
Onload callback:
window['rconload'] = () => {
this.renderRecaptcha();
};
Related
// App.js - WEB
/* eslint-disable no-undef */
import { hot } from 'react-hot-loader/root';
import React, { Component } from "react";
import { View, Platform, Dimensions, Linking, Text } from "react-native";
import { Routes } from "react-router-dom";
import { ModalContainer } from "react-router-modal";
import IdleTimer from "react-idle-timer";
import {
BroadcastChannel
} from 'broadcast-channel';
import { withRouter } from './utils/withRouterComponent';
const routeMap = {
...CommonRouteMap,
};
class App extends Component {
constructor(props) {
super(props);
this.state = {
backgroundColor: "#F36414",
openmodel: false,
bootboxtext: "",
modalopenhide: false,
measure: getMeasure(this.getWidth()),
workingtime: true,
userIdle: false,
maintainanceText: APP.MAINTAINANCE_TIME,
linearColors: linearColors(),
isDuplicate: false
};
this.handleWindowPerformanceEvents();
// Store the previous pathname and search strings
this.currentPathname = null;
this.currentSearch = null;
this.workingTime = dayjs(new Date()).format("HH");
}
changeBackground = (color) => {
this.setState({ backgroundColor: color });
};
handleLayout = ({ nativeEvent }) => {
const { width } = nativeEvent.layout;
const measure = getMeasure(width);
this.setState(() => ({ measure }));
};
getWidth = () => {
const { width } = Dimensions.get("window");
return width;
};
handleWindowPerformanceEvents = async () => {
let ExternalFlag;
if (Platform.OS === "web") {
ExternalFlag = sessionStorage.getItem("ExternalFlag");
} else {
ExternalFlag = await AsyncStorage.getItem("ExternalFlag");
}
let parts = window.location.pathname.split("/");
let path = parts[parts.length - 1];
if (window.performance) {
if (
performance.navigation.type === 0 &&
!window.location.pathname != "404Page"
) {
localStorage.clear();
} else if (!window.location.pathname != "404Page") {
localStorage.clear();
const pathName = window.location.pathname;
const domainName = window.location.origin;
let updatedPath = pathName.substr(0, pathName.lastIndexOf("/"));
if (paths.includes(updatedPath)) {
if (ExternalFlag == 'false') {
window.location.href = `${domainName}${updatedPath}`;
}
return;
} else {
if (ExternalFlag == 'false') {
window.location.href = `${window.location.origin}/servicing/index.html`;
}
}
}
}
};
async componentDidMount() {
const bc = new BroadcastChannel("MY-Project");
bc.onmessage = (event) => {
if (event === "newTab") {
bc.postMessage(`duplicateTab`);
this.setState({ isDuplicate: false })
}
if (event === `duplicateTab`) {
bc.close()
}
};
bc.postMessage('newTab');
this.myContext = {
...this.myContext,
isSupported: await this.isSupportedForVKYC(),
};
const windowValues = window.location;
this.navigateOptions();
if (
windowValues.pathname.includes("product") &&
windowValues.search != ""
) {
fetchUrl(windowValues, this.props);
}
this.setState({
workingtime: true,
});
this.interval = setInterval(() => this.timer(windowValues), 5000);
let machine = null;
if (Platform.OS === 'web') {
machine = sessionStorage.getItem('machine');
}
if (machine) {
this.setState({ machine: true })
}
}
componentWillUnmount() {
clearInterval(this.interval);
}
timer = (windowValues) => {
if (
windowValues.hostname != "localhost" &&
this.state.workingtime &&
!(this.workingTime >= 6 && this.workingTime < 23)
) {
this.setState({
workingtime: true,
});
this.interval = setInterval(() => this.timer(windowValues), 5000);
}
};
navigateOptions() {
const { history } = this.props;
if (
window.location.pathname ===
`${"/" + injectUrlPaths(window.location).path + "/"}`
) {
history.push(`${"/" + injectUrlPaths(window.location).path + ""}`);
}
}
refresh() {
let clear = [
"time",
"product_name",
"payment_gateway",
"stopwatch",
"credit_opted",
"flow",
"easyPay",
"token",
];
clear.forEach((item) => {
sessionStorage.removeItem(item);
});
}
handleKeyPress = (event) => {
if (this.state.userIdle && event.keyCode === 9) {
event.preventDefault();
}
};
closebootbox = () => {
if (this.state.userIdle) {
this.refresh();
window.removeEventListener("keydown", this.handleKeyPress);
Linking.openURL(window.location.origin);
} else {
this.setState({
openmodel: false,
modalopenhide: false,
});
}
};
onIdle = async () => {
const pathName = window.location.pathname;
window.addEventListener('keydown', this.handleKeyPress);
let ExternalFlag = (Platform.OS === "web") ? sessionStorage.getItem("ExternalFlag") : await AsyncStorage.getItem("ExternalFlag");
const { history } = this.props;
let newProps = this.props.location.state;
newProps = { ...newProps, idle: true };
let redirectPath = "/servicing/index.html";
let parts = window.location.pathname.split("/");
let path = parts[parts.length - 1];
if (ExternalFlag) {
history.push({
pathname: '/servicing/redirectHome',
state: newProps
});
} else {
let machine = null;
if (Platform.OS === 'web') {
machine = sessionStorage.getItem('machine');
}
if (machine) {
window.location.href = `http://localhost:9309/SendStatus?CurrentStatus=Timeout`;
} else {
history.push({
pathname: redirectPath,
state: newProps
});
}
}
};
setTimeout = data => {
if (data.otptimer) {
this.idleTimer.pause();
} else {
this.idleTimer.resume();
}
};
clearStorage = (data) => {
data.map((item) => {
sessionStorage.removeItem(item);
});
};
render() {
const ua = window.navigator.userAgent;
return (
!this.state.isDuplicate ?
<CacheBuster enableCaching>
{({ loading, isLatestVersion, refreshCacheAndReload }) => {
if (loading) return null;
if (!loading && !isLatestVersion) {
refreshCacheAndReload();
}
return (
browserSupport(ua) && (
<LinearGradient {...this.state.linearColors}>
<IdleTimer
ref={(ref) => {
this.idleTimer = ref;
}}
element={document}
onIdle={this.onIdle}
debounce={APP.DEBOUNCE}
timeout={APP.IDLE_TIMEOUT}
/>
<View onLayout={this.handleLayout} style={styles.container}>
<script>
window.onpopstate = function() {this.props.history.go(1)};
</script>
{this.state.workingtime ? (
<AppProvider value={{ ...this.myContext, ...this.state }}>
<View style={styles.rootStyle}>
<CustomBootbox
{...this.props}
measure={this.state.measure}
bootboxtext={this.state.bootboxtext}
bootboxmodal={this.state.openmodel}
closebootbox={this.closebootbox}
hideBlackout
/>
<Routes>
{WebRoutesGenerator(
{ routeMap },
this.changeBackground
)}
</Routes>
<ModalContainer />
</View>
</AppProvider>
) : (
<AvailableTimeError
maintainanceText={this.state.maintainanceText}
/>
)}
</View>
</LinearGradient>
)
);
}}
</CacheBuster> : <View style={{ height: Dimensions.get("window").height, }}>
<View >
<Text>Previous session is already open...!</Text>
<Text><br></br> Please close the window and try again </Text>
</View>
</View>
);
}
}
export default hot((withRouter((App))))
I have a react native project and it was running in the older version of React, React Dom and rest. After updating the application to match the latest version, I am getting the above error and I couldn't find a proper solution for it.
Initially I searched withRouter imports and uses, and then created a custom hook of withRouter. Still the error persists.
import {
useLocation,
useNavigate,
useParams
} from "react-router-dom";
export function withRouter(Component) {
function ComponentWithRouterProp(props) {
let location = useLocation();
let navigate = useNavigate();
let params = useParams();
return (
<Component
{...props}
router={{ location, navigate, params }}
/>
);
}
return ComponentWithRouterProp;
}
This issue is likely surfacing as you might be using --legacy-peer-deps flag when installing node_modules. Now Remove node_modules, and just try to fix code after doing npm install. have a nice day.
I have an OIDC client service
export class AuthService {
public userManager: UserManager;
private user: any = null;
constructor() {
const settings = this.getClientSettings();
this.userManager = new UserManager(settings);
}
public isLoggedIn(): boolean {
return this.user != null && this.user.access_token && !this.user.expired;
}
loadUser() {
this.userManager.getUser().then((user) => this.user = user);
}
public getUser(): Promise<User | null> {
return this.userManager.getUser().then((user) => this.user = user);
}
public login(): Promise<void> {
return this.userManager.signinRedirect();
}
}
Functional component
export default function NavMenu() {
useSelector((state: ApplicationState) => state.oidcUser);
const dispatch = useDispatch();
const [state, setState] = useState({
menu: {
open: true,
coordinates: undefined
}
});
const onClose = () => {
setState({
...state, menu: {
open: false,
coordinates: undefined
}
})
}
authService: AuthService;
const login = () => {
authService.startAuthentication(window.location.pathname);
};
const menuOptions = [
'Save',
'Edit',
'Cut',
'Copy',
'Paste',
];
return (<div>
<TopAppBar>
<TopAppBarRow>
<TopAppBarSection align='start'>
<TopAppBarTitle>Falcon</TopAppBarTitle>
</TopAppBarSection>
<TopAppBarSection align='end' role='toolbar'>
<div>
{(() => {
if (true) {
return (
<Button raised type="button" onClick={() => { login }}>Portal</Button>
)
} else {
return (
<Menu
open={state.menu.open}
onClose={onClose}
coordinates={state.menu.coordinates}
onSelected={(index, item) => console.log(index, item)}>
<MenuList>
{menuOptions.map((option : any, index : any) => (
<MenuListItem key={index}>
<MenuListItemText primaryText={option} />
{/* You can also use other components from list, which are documented below */}
</MenuListItem>
))}
</MenuList>
</Menu>
)
}
})()}
</div>
</TopAppBarSection>
</TopAppBarRow>
</TopAppBar>
</div>);
}
Trying to call
authService: AuthService;
const login = () => {
authService.startAuthentication(window.location.pathname);
};
Getting an error Cann't find the name authService
How to call service class method from react functional component.
Here, you could do something like this in your functional component:
import * as React from "react";
import { AuthService } from "./AuthService";
export default function NavMenu() {
const authService = new AuthService();
const login = () => {
authService.startAuthentication(window.location.pathname);
}
return (
<div className="App">
<h1>Hello NavMenu</h1>
</div>
);
}
If you have any more questions, would be happy to help!
I want to test addEventListener/RemoveEventListener for an Element.
class Image extends PureComponent {
state = {
isLoaded: false,
};
componentDidMount() {
if (!this.props.src) return;
this.imageToLoad = document.createElement('img');
this.imageToLoad.addEventListener('load', this.loadImage);
this.imageToLoad.src = this.props.src;
}
componentWillUnmount() {
if (!this.imageToLoad) return;
this.imageToLoad.removeEventListener('load', this.loadImage);
}
loadImage = () => {
this.setState({ isLoaded: true }, () => {
this.myimg.src = this.imageToLoad.src;
});
}
render() {
const { className, src, alt } = this.props;
const { isLoaded } = this.state;
if (isLoaded === false || !src) return '';
return (
<img
className={className}
ref={img => (this.myimg = img)}
src={src}
alt={alt}
/>
);
}
}
Test code:-
it('should add event listener on mount', () => {
const elementMock = { addEventListener: jest.fn() };
jest.spyOn(Image.prototype, 'myimg').mockImplementation(() => elementMock);
expect(elementMock.addEventListener).toBeCalledWith('load', expect.any(Function), false);
});
But it is not working as expected.
I'm using React-Native-Navigation with the Context api.
I'm wrapping my screens with a HOC component below.
const ProviderWrap = Comp => props => (
<Provider>
<Comp {...props} />
</Provider>
);
Navigation.registerComponent('app.AuthScreen', () => ProviderWrap(AuthScreen));
Navigation.registerComponent('app.FindPlaceScreen', () => ProviderWrap(FindPlaceScreen));
Navigation.registerComponent('app.SharePlaceScreen', () => ProviderWrap(SharePlaceScreen));
And this is my Provider Component
class Provider extends Component {
state = {
placeName: 'hello',
image: 'https://images.unsplash.com/photo-1534075786808-9b819c51f0b7?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=4dec0c0b139fb398b714a5c8264b4a9a&auto=format&fit=crop&w=934&q=80',
places: [],
}
textInputHandler = (text) => {
this.setState({
placeName: text,
})
}
searchInputHandler = (text) => {
const SearchedPlace = this.state.places.filter(place => {
return place.name.includes(text)
})
this.setState(prevState => {
return {
places: SearchedPlace,
}
})
}
placeSubmitHandler = () => {
if (this.state.placeName) {
this.setState(prevState => {
return {
places: [...prevState.places, {
name: prevState.placeName,
image: prevState.image,
}],
placeName: '',
}
})
} else {
return;
}
}
placeDeleteHandler = (id, deleteModal) => {
const newPlaces = this.state.places.filter((place, index) => {
return index !== id
})
this.setState({
places: newPlaces,
})
deleteModal();
}
render() {
return (
<GlobalContext.Provider value={{
state: this.state,
textInputHandler: this.textInputHandler,
placeSubmitHandler: this.placeSubmitHandler,
placeDeleteHandler: this.placeDeleteHandler,
searchInputHandler: this.searchInputHandler,
}}>
{this.props.children}
</GlobalContext.Provider>
)
}
}
My issue is that The Context state isnt shared between screens. in my context state i have a places array which i add to in the SharePlaceScreen which works fine but when i go over to FindPlaceScreen that context state places is empty. As if i had two separate context for each screen.
Here is an example of singleton Object there are many implementation you cas use es6 class also ... es6 examples
var SingletonState = (function () {
var state;
function createState() {
return {someKey:'what ever'};
}
return {
getState: function () {
if (!state) {
state = createState();
}
return state;
}
};
})();
// usage
var state1 = SingletonState.getState();
var state2 = SingletonState.getState();
console.log("Same state? " + (state1 === state2));
I am trying to test an event handler with Enzyme / Jest for a react component, however my spy function is never called...
My component has a div with an id and I am using that to find the dom elem
render() {
return (
<div>
<Top
{...this.props}
/>
<div
id = 'keyboard_clickable'
onClick = {this._handleClick}
style= {styles.main}>
{this._showKeyBoard()}
</div>
<input onChange = {() => {}}/>
</div>
);
}
}
My test
describe('onclick function is called ...', () => {
it.only('spyOn', () => {
const spy = jest.fn()
const wrapper = shallow(
<Keyboard
_getData = { () => {} }
_erase = { () => {} }
_get_letters = { () => {} }
_createWord = { () => {} }
_modeSwitch = { () => {} }
onClick = { spy }
/>
)
wrapper.find('#keyboard_clickable').simulate('click', {
target:{
parentElement:{ id: 5 },
id:6
}
})
expect(spy).toHaveBeenCalled();
})
})
my HandleClick
_handleClick = e => {
let parent = e.target.parentElement;
if(e.target.id || (!isNaN(parent.id) && parent.id > 0) ) {
this.props._getData(e.target.id || e.target.parentElement.id)
this.setState({status:'ok'})
}else{
this.setState({status:'Use numbers between 2 and 9'},()=>{
return alert(this.state.status)
})
}
}
Test output
Expected mock function to have been called, but it was not called.
To test that your event handler is called, you'll have to replace the event handler with a mock function. One way to do that is to extend your component class:
class TestKeyboard extends Keyboard {
constructor(props) {
super(props)
this._handleClick = this.props._handleClick
}
}
describe('onclick function is called ...', () => {
it.only('spyOn', () => {
const spy = jest.fn()
const wrapper = shallow(
<TestKeyboard
_getData = { () => {} }
_erase = { () => {} }
_get_letters = { () => {} }
_createWord = { () => {} }
_modeSwitch = { () => {} }
_handleClick = { spy }
/>
)
wrapper.find('#keyboard_clickable').simulate('click', {
target:{
parentElement:{ id: 5 },
id:6
}
})
expect(spy).toHaveBeenCalled();
})
})
The prop _handleClick replaces Keyboard._handleClick and is therefore called when onClick fires in the clicked element.
Alternatively, jest.spyOn
In case you need to let the event handler execute and test what it was called with, you can use jest.spyOn. I find this method more complex, but it is more flexible.
import { mount } from 'enzyme'
describe('onclick function is called ...', () => {
it.only('spyOn', () => {
const wrapper = mount(
<Keyboard
_getData = { () => {} }
_erase = { () => {} }
_get_letters = { () => {} }
_createWord = { () => {} }
_modeSwitch = { () => {} }
/>
)
const spy = jest.spyOn(wrapper.instance(), '_handleClick')
wrapper.instance().forceUpdate()
wrapper.find('#keyboard_clickable').simulate('click', {
target:{
parentElement:{ id: 5 },
id:6
}
})
expect(spy).toHaveBeenCalled();
})
})
Note that this will fail when using shallow rendering so you'll have to use enzyme.mount instead.
It seems that simulating a click with enzyme in shallow render does work, but only if I forceUpdate(), like in Jemi's solution.
example:
beforeEach(() => {
wrapper = shallow(<VehicleDamage handleSubmit={mockFunction} onPrevClick={mockFunction} />);
});
it('handlePrevClick is called on click', function() {
const spyHandlePrevClick = jest.spyOn(wrapper.instance(), 'handlePrevClick');
wrapper.instance().forceUpdate(); // I assume required to assign mocked function
let buttonContainer = wrapper.find('ButtonContainer').dive();
let button = buttonContainer.find('Button').at(0);
button.simulate('click', {
preventDefault: () => jest.fn()
});
expect(spyHandlePrevClick).toHaveBeenCalled();
});