React Native Cannot call a class as a function - firebase

I have a simple function that register users in firebase and save data in cloud firestore
But I am getting this error:
[TypeError: Cannot call a class as a function]
Can anyone help my find where is located the error?
function below:
const handleSignUp = useCallback(
async data => {
try {
setLoading(true);
const auth = await authFB().createUserWithEmailAndPassword(
data.email,
data.password,
);
const db = firestore();
const firstName = data.name.split(' ').slice(0, -1).join(' ');
const lastName = data.name.split(' ').slice(-1).join(' ');
await db
.collection('Providers')
.doc(auth.user.uid)
.set({
id: auth.user.uid,
name: {
first: firstName,
last: lastName,
},
email: data.email,
createdAt: firestore.Timestamp.fromDate(new Date()),
address: {
position: firestore.GeoPoint(
coordinates.latitude,
coordinates.longitude,
),
},
})
.then(() => {
navigation.reset({
routes: [{ name: 'SignIn' }],
index: 0,
});
});
setLoading(false);
Alert.alert(
'Cadastro realizado com sucesso!',
'Você já pode fazer login na aplicação.',
);
} catch (err) {
setLoading(false);
}
},
[coordinates],
);

I'm not terribly familiar with the Firestore API, but most likely you just need the new keyword where you're creating a GeoPoint:
position: new firestore.GeoPoint(
coordinates.latitude,
coordinates.longitude,
),

Related

Adding update property to mutation function breaks mocked result in MockProvider

I've got the following function that gets triggered on a form submission
const [register, { loading }] = useMutation(RegisterDocument);
const router = useRouter();
const onSubmit = async (values: FormValues) => {
const v = { ...values };
delete v.confirmPassword;
const res = await register({
variables: { options: v },
update: (cache, { data }) => {
cache.writeQuery<MeQuery>({
query: MeDocument,
data: {
__typename: 'Query',
me: data?.register.user,
},
});
},
});
if (res.data?.register.user) {
router.push('/');
}
};
I then have the following test to submit the form
test('it should submit form without error', async () => {
const firstName = faker.name.firstName();
const surname = faker.name.lastName();
const username = faker.internet.userName().replace('#', '');
const email = faker.internet.email();
const password = faker.internet.password(6, false, /^[a-zA-Z0-9_.-]*$/);
const cache = new InMemoryCache().restore({});
const variables = {
options: { email, firstName, password, surname, username },
};
const user = { email, firstName, surname, username, id: 1, activated: false, photo: null };
const mocks = [
{
request: { query: RegisterDocument, variables },
result: { data: { register: { errors: null, user } } },
},
];
const { queryByTestId, container } = renderWithTheme(
<MockedProvider mocks={mocks} cache={cache}>
<Register />
</MockedProvider>,
);
await updateRegisterInputs(container); // util function that updates input values for submission
await submitForm({ queryByTestId, testId: 'register-submit', loadingTestId: 'register-loading' }); // util function that submits form
await waitFor(() => expect(onPush).toBeCalledWith('/'));
});
When I run this test res returns the following
{ data: { register: {} } }
However, once I remove the update property inside the register mutation function, res returns the following.
{ data: { register: { errors: null, user: [Object] } } }
Any ideas why the mocked return value returns an empty object for the register property only when the update property function is added?
Even just instantiating the update property like so;
update: () => {}
still breaks the response from the mutation.
I realised that the graphql doc required the __typename property in the relevant places in my mocks
So I have to update the mock to include the typenames.
const user = { email, firstName, surname, username, id: 1, activated: false, photo: null, __typename: 'User' };
const mocks = [
{
request: { query: RegisterDocument, variables },
result: { data: { register: { errors: null, user, __typename: 'UserResponse' } } },
},
];

can not send tax amount in stripe from next js app

In my project, I am using WordPress woo-commerce as backend and next js as frontend. I am trying to implement stripe payment. I can send line items in stripe sessionData and they show perfectly on the stripe page, how ever when I am trying to send the tax amounts with line items I am getting errors.
import { createCheckoutSession } from "next-stripe/client"; // #see https://github.com/ynnoj/next-stripe
import { loadStripe } from "#stripe/stripe-js";
.....
.....
const createCheckoutSessionAndRedirect = async (orderData) => {
const sessionData = {
success_url:
window.location.origin +
`/thank-you?session_id={CHECKOUT_SESSION_ID}&order_id=${orderData.orderId}`,
cancel_url: window.location.href,
customer_email: orderData.customer_email,
line_items: getStripeLineItems(orderData.products),
metadata: getMetaData(
orderData.billing,
orderData.shipping,
orderData.orderId
),
payment_method_types: ["card"],
mode: "payment",
total_details:{
amount_discount: 0,
amount_shipping: Math.round(10 * 100),
amount_tax: Math.round(10 * 100),
},
};
console.log("Session from another1:", sessionData);
const session = await createCheckoutSession(sessionData);
console.log("Session from another2:", sessionData);
console.log("from another2:", orderData);
try {
console.log("session data", session);
const stripe = await loadStripe(
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
);
if (stripe) {
stripe.redirectToCheckout({ sessionId: session.id });
}
} catch (error) {
console.log(error);
}
};
After many attempts, I could solve the problem.
This is the controller.
const stripe = require("stripe")(process.env.STRIPE_PRIVATE_KEY);
const stripePaymentService = require('../service/stripePaymentService');
module.exports.checkoutSessionCreate = async (req, res) => {
const responseFromService = await stripePaymentService.checkoutSessionCreate(req.body);
console.log("this is session data", responseFromService);
try{
const session = await stripe.checkout.sessions.create(responseFromService);
res.json({ url: session.url });
console.log("success session:", session.url);
}
catch(e){
res.status(500).json({ error: e.message })
console.log("success session:", e.message);
}
}
This is the service...
const stripe = require("stripe")(process.env.STRIPE_PRIVATE_KEY);
const lodash = require('lodash');
module.exports.checkoutSessionCreate = async (serviceData) => {
// console.log(serviceData.products);
const sessionData = {
success_url:`${process.env.CLIENT_URL}/thank-you?session_id={CHECKOUT_SESSION_ID}&order_id=${serviceData.orderId}`,
cancel_url: `${process.env.CLIENT_URL}`,
customer_email: serviceData.customer_email,
line_items: await getStripeLineItems(serviceData.products),
metadata: getMetaData(
serviceData.billing,
serviceData.shipping,
serviceData.orderId
),
payment_method_types: ["card"],
mode: "payment",
};
return sessionData;
}
const getMetaData = (billing, shipping, orderId) => {
return {
billing: JSON.stringify(billing),
shipping: JSON.stringify(shipping),
orderId,
};
};
let getStripeLineItems =async (products) => {
if (lodash.isEmpty(products) && !isArray(products)) {
return [];
}
const productData = await Promise.all(
products.map(async (product) => {
const taxArr = await getTaxID(product.tax_data);
return {
quantity: product?.quantity ?? 0,
name: product?.name ?? "",
images: [product?.images ?? ""],
amount: Math.round(product?.amount * 100),
currency: product?.currency ?? "",
tax_rates: taxArr,
};
})
);
return productData;
};
let getTaxID = async (taxData) => {
let idArr = await Promise.all(
taxData.map(async (item)=>{
const taxRate = await stripe.taxRates.create({
display_name: item.display_name,
inclusive: item.inclusive,
percentage: item.percentage,
});
return taxRate?.id;
})
);
return idArr;
}
I hope this will help somebody....
You cannot set total_details directly as you are trying to do. That is a calculated property of the object (ref), not part of the create endpoint (ref).
To add tax to a Checkout session, you should either use automatic taxes with Stripe Tax, or provide explicit tax rates.

Firebase react native loading issue

I'm new at react native and I try to build an mobile app. I'm using Firebase for applications. When I try to login, it stucks on the loading page. And getting this warning:
Setting a timer for a long period of time, i.e. multiple minutes, is a performance and correctness issue on Android as it keeps the timer module awake, and timers can only be called when the app is in the foreground. See https://github.com/facebook/react-native/issues/12981 for more info.
(Saw setTimeout with duration 3600000ms)
What should I do?
Also authentication code is here:
import { AsyncStorage } from 'react-native';
export const SIGNUP = 'SIGNUP';
export const LOGIN = 'LOGIN';
export const AUTHENTICATE = 'AUTHENTICATE';
export const LOGOUT = 'LOGOUT';
let timer;
export const authenticate = (userId, token, expiryTime) => {
return dispatch => {
dispatch(setLogoutTimer(expiryTime));
dispatch({ type: AUTHENTICATE, userId: userId, token: token });
};
};
export const signup = (email, password) => {
return async dispatch => {
const response = await fetch(
'https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=...',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email,
password: password,
returnSecureToken: true
})
}
);
if (!response.ok) {
const errorResData = await response.json();
const errorId = errorResData.error.message;
let message = 'Bir terslik var!';
if (errorId === 'EMAIL_EXISTS') {
message = 'Bu e-posta zaten kayıtlı!';
}
throw new Error(message);
}
const resData = await response.json();
console.log(resData);
dispatch(
authenticate(
resData.localId,
resData.idToken,
parseInt(resData.expiresIn) * 1000
)
);
const expirationDate = new Date(
new Date().getTime() + parseInt(resData.expiresIn) * 1000
);
saveDataToStorage(resData.idToken, resData.localId, expirationDate);
};
};
export const login = (email, password) => {
return async dispatch => {
const response = await fetch(
'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=...',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email,
password: password,
returnSecureToken: true
})
}
);
if (!response.ok) {
const errorResData = await response.json();
const errorId = errorResData.error.message;
let message = 'Bir terslik var!';
if (errorId === 'EMAIL_NOT_FOUND') {
message = 'Böyle bir e-posta yok!';
} else if (errorId === 'INVALID_PASSWORD') {
message = 'Bu şifre geçersiz!';
}
throw new Error(message);
}
const resData = await response.json();
console.log(resData);
dispatch(
authenticate(
resData.localId,
resData.idToken,
parseInt(resData.expiresIn) * 1000
)
);
const expirationDate = new Date(
new Date().getTime() + parseInt(resData.expiresIn) * 1000
);
saveDataToStorage(resData.idToken, resData.localId, expirationDate);
};
};
export const logout = () => {
clearLogoutTimer();
AsyncStorage.removeItem('userData');
return { type: LOGOUT };
};
const clearLogoutTimer = () => {
if (timer) {
clearTimeout(timer);
}
};
const setLogoutTimer = expirationTime => {
return dispatch => {
timer = setTimeout(() => {
dispatch(logout());
}, expirationTime);
};
};
const saveDataToStorage = (token, userId, expirationDate) => {
AsyncStorage.setItem(
'userData',
JSON.stringify({
token: token,
userId: userId,
expiryDate: expirationDate.toISOString()
})
);
};

Is there a way to mock firebase modules in jest?

Code.js
saveToFirebase = () => {
let statusMsg = ""
firebase
.firestore()
.collection("messages")
.doc(this.state.field.email)
.set(this.state.field)
.then((statusMsg = "Your Message have been submitted successfully."))
this.clearFields(statusMsg)
}
Code.test.js
it("should call mock firebase module", () => {
const docData = {
field: {
name: "Rob Bob",
email: "rob#bob.com",
phone: "9999999999",
subject: "Test subject",
message: "Test message",
},
}
const docResult = {
data: () => docData,
}
const get = jest.fn(() => Promise.resolve(docResult))
const set = jest.fn()
const doc = jest.fn(() => {
return {
set,
get,
}
})
const colllection = jest.fn((messages) => {
return { doc }
})
const firestore = () => {
return colllection
}
firebase.firestore = firestore
const mockData = { fake: "data" }
jest.clearAllMocks()
wrapper.instance().saveToFirebase()
})
While running the Code.test.js, it throws an error that firebase.firestore().collection() is not a function. Please suggest proper mocking of the firebase module for the above code and to add a case to check if firebase has successfully returned then, clearFields() is invoked.
You can use jest.spyOn(object, methodName) to mock firebase.firestore() function.
E.g.
index.jsx:
import React, { Component } from 'react';
import firebase from 'firebase';
export default class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
field: { email: 'mock#example.com' },
};
}
clearFields(statusMsg) {
console.log(statusMsg);
}
saveToFirebase = () => {
let statusMsg = '';
return firebase
.firestore()
.collection('messages')
.doc(this.state.field.email)
.set(this.state.field)
.then(() => {
statusMsg = 'Your Message have been submitted successfully.';
this.clearFields(statusMsg);
});
};
render() {
return <div>my component</div>;
}
}
index.test.jsx:
import MyComponent from '.';
import { shallow } from 'enzyme';
import React from 'react';
import firebase from 'firebase';
describe('61358076', () => {
afterEach(() => {
jest.restoreAllMocks();
});
it('should pass', async () => {
const firestoreMock = {
collection: jest.fn().mockReturnThis(),
doc: jest.fn().mockReturnThis(),
set: jest.fn().mockResolvedValueOnce(),
};
const clearFieldsSpy = jest.spyOn(MyComponent.prototype, 'clearFields');
jest.spyOn(firebase, 'firestore').mockImplementationOnce(() => firestoreMock);
const wrapper = shallow(<MyComponent></MyComponent>);
await wrapper.instance().saveToFirebase();
expect(firestoreMock.collection).toBeCalledWith('messages');
expect(firestoreMock.doc).toBeCalledWith('mock#example.com');
expect(firestoreMock.set).toBeCalledWith({ email: 'mock#example.com' });
expect(clearFieldsSpy).toBeCalledWith('Your Message have been submitted successfully.');
});
});
unit test results with 100% coverage:
PASS stackoverflow/61358076/index.test.jsx (17.824s)
61358076
✓ should pass (39ms)
console.log stackoverflow/61358076/index.jsx:1611
Your Message have been submitted successfully.
-----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.jsx | 100 | 100 | 100 | 100 |
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 19.945s
source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/61358076
Hi recently I needed to mock jest module and this is my implementation,
note: I used eventEmitter3 to handle onAuthStateChange
import EventEmitter from 'eventemitter3';
const authEmitter = new EventEmitter();
let isSignIn = true;
const user = {
displayName: 'test name',
email: 'redirectTest#test.com',
emailVerified: true,
uid: 'id123',
providerData: [
{
email: 'redirectTest#test.com',
displayName: 'redirectResultTestDisplayName',
providerId: 'google',
},
],
};
const mockFirebase: any = {
initializeApp: jest.fn().mockReturnValue({
auth: jest.fn().mockReturnValue({
currentUser: isSignIn
? {
displayName: 'redirectResultTestDisplayName',
email: 'redirectTest#test.com',
emailVerified: true,
uid: 'id123',
providerData: [
{
email: 'redirectTest#test.com',
displayName: 'redirectResultTestDisplayName',
providerId: 'google',
},
],
sendEmailVerification: jest.fn(),
}
: null,
signInWithRedirect: jest.fn(),
getRedirectResult: jest.fn().mockReturnValue({
credential: {
providerId: 'Google',
},
user: {
getIdToken: jest.fn().mockResolvedValue('abc1234'),
},
additionalUserInfo: {
profile: {
email: '__tests__#__tests__.com',
name: 'John Doe',
},
},
}),
onAuthStateChanged: jest.fn(fn => {
// sign user on start
fn(user);
// sign-out user on start
authEmitter.on('sign-out', fn, undefined);
authEmitter.on('sign-in', fn, user);
}),
signOut: jest.fn(() => {
isSignIn = false;
authEmitter.emit('sign-out');
}),
signInWithEmailAndPassword: jest.fn(() => {
isSignIn = true;
authEmitter.emit('sign-in', user);
return Promise.resolve(true);
}),
sendPasswordResetEmail: jest.fn(() => Promise.resolve(true)),
sendEmailVerification: jest.fn(() => Promise.resolve(true)),
signInWithPopup: jest.fn(() => {
isSignIn = true;
authEmitter.emit('sign-in', user);
return Promise.resolve(true);
}),
}),
firestore: jest.fn().mockReturnValue({
collection: jest.fn().mockReturnValue({
doc: jest.fn().mockReturnValue({
add: jest.fn().mockResolvedValue({
id: 'abc123',
}),
set: jest.fn().mockResolvedValue({
uid: 'abc123',
}),
}),
}),
}),
}),
auth: {
GoogleAuthProvider: class {
addScope = jest.fn();
},
GithubAuthProvider: class {
addScope = jest.fn();
},
FacebookAuthProvider: class {
addScope = jest.fn();
},
},
};
jest.mock('firebase/app', () => mockFirebase);

testing redux async action creators with jest

I started to write tests for my application. I'm trying to create test for redux async creators.
The problem is when I run test I get following error :
Fetch all users › dispatch action loadUsersSuccess
Actions may not have an undefined "type" property. Have you misspelled a constant? Action: undefined
All actions have defined type constant so I dont understand what should be the problem.
const LOAD_ALL_USERS_SUCCESS = "src/containers/User/LOAD_ALL_USERS_SUCCESS";
const LOAD_ALL_USERS_FAILURE = "src/containers/User/LOAD_ALL_USERS_FAILURE";
//action creators
export function loadUsersSuccess(users) {
return {
type: LOAD_ALL_USERS_SUCCESS,
payload: users
};
}
export function loadUsersFailure(error) {
return {
type: LOAD_ALL_USERS_FAILURE,
payload: error
};
}
import nock from "nock";
import { loadUsersSuccess, loadUsersFailure } from "./ducks";
import configureStore from "redux-mock-store";
const middlewares = [];
const mockStore = configureStore(middlewares);
const LOAD_ALL_USERS_SUCCESS = "src/containers/User/LOAD_ALL_USERS_SUCCESS";
const LOAD_ALL_USERS_FAILURE = "src/containers/User/LOAD_ALL_USERS_FAILURE";
const users = [
{
first_name: "Emlynne",
last_name: "Spellacy",
email: "espellacy0#lycos.com",
gender: "Female",
age: 1965,
country: "Indonesia"
},
{
first_name: "Alie",
last_name: "Dalrymple",
email: "adalrymple1#telegraph.co.uk",
gender: "Female",
age: 1976,
country: "Pakistan"
}
];
function fetchData() {
return async (dispatch) => {
try {
const { data } = await axios.get("/users");
dispatch(loadUsersSuccess(data));
} catch (error) {
dispatch(loadUsersFailure(error));
}
};
}
describe("Fetch all users", () => {
afterEach(() => {
nock.cleanAll()
})
test("Should load all Users", () => {
nock("http://localhost:8000")
.get("api/users")
.reply(200, users);
const expectedAction = [
{
type: LOAD_ALL_USERS_SUCCESS,
payload: users
},
{
type: LOAD_ALL_USERS_FAILURE,
payload: "error"
}
];
const store = mockStore({});
return store.dispatch(fetchData()).then(() => {
expect(store.getActions()).toEqual(expectedAction);
});
});
});
The problem was that dispatch function didn't exist. So, I needed to add following lines.
import thunk from "redux-thunk";
const middlewares = [thunk];

Resources