Trying to properly use ReactHook's useState - state

I want to establish some simple validation for my functional React component. To that end, I'm using ReactHook's useState to instantiate a validationErrors object that is intended to grow like this:
{}
{'fieldName1': 'Some error message'}
{'fieldName1': 'Some error message', 'fieldName2': 'Another error message'}
{'fieldName1': 'Different error message', 'fieldName2': 'Another error message'}
const [validationErrors, setValidationErrors] = useState(null);
// If this function is working correctly then it will either add a
// new key-value pair if the key doesn't exist yet or will update
// the value if the key already exists.
const updateValidationErrors = (name, error) => {
if ([name] in validationErrors) {
setValidationErrors({...validationErrors, [name]: error});
} else {
setValidationErrors({[name]: error, ...validationErrors});
}
};
const checkValidation = (target) => {
updateValidationErrors('companyName', 'Test Company 1');
console.log(validationErrors);
updateValidationErrors('companyName', 'Test Company 2');
console.log(validationErrors);
updateValidationErrors('notes', 'Notes error message 1');
console.log(validationErrors);
updateValidationErrors('notes', 'Notes error message 2');
console.log(validationErrors);
updateValidationErrors('companyName', 'Test Company 3');
console.log(validationErrors);
};
I'm getting strange results with the console.log and am wondering if that's because there is a short async delay with ReactHook's useState?
Or is there something wrong with my updateValidationErrors code?
Note: I tested the function here: https://repl.it/repls/WeeklyMustyMiddleware

I guess it won't work like this because in
const [validationErrors, setValidationErrors] = useState(null);
setValidationErrors is nothing but the short hand of setState({ validationErrors: <new value> }) which you have mentioned as well.
setState in react is an async call and doesn't guarantee that the value will be updated after the setState line is executed.
Try this to see the updated result
const [validationErrors, setValidationErrors] = useState();
const updateValidationErrors = (name, error) => {
setValidationErrors({...validationErrors, [name]: error});
};
const checkValidation = (target) => {
updateValidationErrors('companyName', 'Test Company 1');
updateValidationErrors('companyName', 'Test Company 2');
updateValidationErrors('notes', 'Notes error message 1');
updateValidationErrors('notes', 'Notes error message 2');
updateValidationErrors('companyName', 'Test Company 3');
};

react useState is not rective to console
react useState is not rective, then you can do useEffect to console.
And then you will see when validationErrorsupdate.
Add this line to your code
useEffect(() => console.log(validationErrors))
And of course
import React, { useEffect } from 'react';

Related

Next js with django api rendering data

I am working on a front end of a project and I am stuck for a while.
I have created an api with django rest framework and I am trying to connect to a Nextjs front end. The data is to show on the front page that is why I call getInitialProps. Following is the code
import styles from '../styles/Home.module.css';
import axios from 'axios';
const Home = ({ listings, error }) => {
if (error) {
return <div>An error occured: {error.message}</div>;
}
return (
<ul>
{listings.map((listing) => (
<li key={listing.address}>{listing.title}</li>
))}
</ul>
);
};
Home.getInitialProps = async (ctx) => {
try {
const res = await axios.get('http://127.0.0.1:8000/api/listings/?page=4');
const rep = await res.data;
console.log(rep.results);
listings = rep.results;
return { listings };
} catch (error) {
return { error };
}
};
export default Home;
In the console log I get the data, which is in the bellow format:
[
{
index: 1734112,
user: 11233,
title: 'Classical style',
address: 'address 23, city , country',
bedrooms: '2',
bethrooms: '1',
price: '5803',
list_type: 'rent'
},
{
index: 1722303,
user: 32119,
title: 'Pangrati On the Lake',
address: 'address 28, city , country',
bedrooms: '1',
bethrooms: '1',
price: '4800',
list_type: 'rent'
}
]
But I get an error occured in the browser without specifying the error.
And in the console I get the bellow.
next-dev.js?3515:32 Warning: Did not expect server HTML to contain the text node "listings is not defined" in <div>.
at div
at Home (webpack-internal:///./pages/index.js:50:26)
at MyApp (webpack-internal:///./pages/_app.js:38:27)
at ErrorBoundary (webpack-internal:///./node_modules/next/dist/compiled/#next/react-dev-overlay/client.js:8:20584)
at ReactDevOverlay (webpack-internal:///./node_modules/next/dist/compiled/#next/react-dev-overlay/client.js:8:23125)
at Container (webpack-internal:///./node_modules/next/dist/client/index.js:359:9)
at AppContainer (webpack-internal:///./node_modules/next/dist/client/index.js:793:26)
at Root (webpack-internal:///./node_modules/next/dist/client/index.js:915:27)
I am not sure what the issue is so any help much appreciated. Thank you!
You are assigning value to some variable listings = rep.results;, but this variable was not declared, you can't do that in strict mode (which I believe is default in that case)
So just declare it as const and the error should go away:
const listings = rep.results

Apollo client & Absinthe - difficulty parsing errors

I'm working with the #apollo/client and #absinthe/socket-apollo-link NPM packages in my React app, but I'm having some trouble parsing query and mutation errors received by onError in my implementation of the useQuery and useMutation hooks.
For example, here is the way I've set up a query in my component:
useQuery(OperationLib.agendaQuery, {
fetchPolicy: "network-only",
onCompleted: ({ myData }) => {
setData(myData)
setLoading(false)
},
onError: (error) => {
console.log(error)
}
})
When that onError handler is called, the error object that is returned is logged as:
Error: request: [object Object]
at new ApolloError (app.js:36358)
at app.js:146876
at app.js:145790
at new Promise (<anonymous>)
at Object.error (app.js:145790)
at notifySubscription (app.js:145130)
at onNotify (app.js:145169)
at SubscriptionObserver.error (app.js:145230)
at app.js:58209
at Array.forEach (<anonymous>)
I can break this response into its parts "graphQLErrors", "networkError", "message", "extraInfo", but I'm finding it difficult to get any useful info there. In particular, I'd like to be able to get something out of the message - but in this case, error.message is the string,
request: [object Object]
typeof error.message logs string so yeah I can't really do anything with this.
Maybe I could find something useful under one of the other attributes? Nope, graphQLErrors is an empty array, networkError yields the same output as I got when I logged the initial error above, and extraInfo is undefined.
I dug into the source code and found the method createRequestError - when I added a debug log here to see what the message was, I good some good data - I could see the message that I would think would be available somewhere in the error response:
var createRequestError = function createRequestError(message) {
return new Error("request: ".concat(message));
}.bind(undefined);
What could be causing this issue? Is there something I need to configure in my Apollo/Absinthe initialization? I've set those up like so:
apollo-client.js
import { ApolloClient, InMemoryCache } from "#apollo/client"
import absintheSocketLink from "./absinthe-socket-apollo-link"
export default new ApolloClient({
link: absintheSocketLink,
cache: new InMemoryCache()
})
absinthe-socket-apollo-link.js
import * as AbsintheSocket from "#absinthe/socket"
import { createAbsintheSocketLink } from "#absinthe/socket-apollo-link"
import { Socket as PhoenixSocket } from "phoenix"
const protocol = window.location.protocol === "https:" ? "wss" : "ws";
const getToken = () => JSON.parse(window.localStorage.getItem("token"))
let token = getToken();
const params = {
get jwt() {
if (!token) {
token = getToken();
}
return token;
},
};
export default createAbsintheSocketLink(
AbsintheSocket.create(
new PhoenixSocket(`${protocol}://${WS_API_URL}/graphql`, {
reconnect: true,
params: params
})
)
);
Thanks much for any insight!

Cannot log after tests are done in jestjs

I have written test cases for signin API using jest. After completing all five test of a test suit jest give me following error in log.
Can any body tell Why it is So and how to fix it?
CODE:(signup.test.ts)
import request from 'supertest';
import { TYPES } from '../src/inversify.types'
import { Application } from '../src/app/Application'
import { container } from '../src/inversify.config'
import dotenv from 'dotenv'
import { RESPONSE_CODE } from '../src/utils/enums/ResponseCode'
import { RESPONSE_MESSAGES } from '../src/utils/enums/ResponseMessages'
import { UserSchema } from '../src/components/user/User';
// import jwt from 'jsonwebtoken';
var application: Application
describe("POST / - SIGNUP endpoint", () => {
// var testusers: any;
//This hook is executed before running all test cases, It will make application instance, make it to listen
// on it on port 3000 and add test document in DB
beforeAll(async () => {
// Make enviroment variables available throughout the application
dotenv.config();
// Getting application instance using iversify container
application = container.get<Application>(TYPES.Application);
// Initialize frontside of application
await application.bootstrap();
// Starting Application server on given port
await application.listen(3000);
});
afterAll(
//This hook is executed after running all test cases and delete test document in database
async () =>{
const res = await UserSchema.deleteMany({ Name: { $in: [ "Test User", "Test" ] } });
// `0` if no docs matched the filter, number of docs deleted otherwise
console.log('---------------------->>>>>>>>>>>>>>>>>>>', (res as any).deletedCount);
}
)
it("Signup for user that don\'t exists", async () => {
const response = await request(application.getServer()).post('/user/signup')
.send({
"Email": JSON.parse(process.env.TEST_USER).Email,
"Name": "Test User",
"Password": process.env.TEST_ACCOUNTS_PASSWORD
})
expect(response.status).toBe(RESPONSE_CODE.CREATED);
expect(JSON.parse(response.text)).toEqual(expect.objectContaining({
Message: RESPONSE_MESSAGES.ADDED_SUCESSFULLY,
Data: expect.objectContaining({
Name: 'Test User',
Country: '',
PhoneNumber: '',
// Password: '$2b$10$nIHLW/SA73XLHoIcND27iuODFAArOvpch6FL/eikKT78qbShAl6ry',
Dob: '',
Role: 'MEMBER',
IsEmailVerified: false,
IsBlocked: 'ACTIVE',
IsTokenSent: false,
twoFAStatus: false,
// _id: '5c812e2715e0711b98260fee',
Email: JSON.parse(process.env.TEST_USER).Email
})
})
);
console.log('*** Signup for user that don\'t exists *** response', response.text, 'response status', response.status);
});
it("Signup for user that exists", async () => {
const response = await request(application.getServer()).post('/user/signup')
.send({
"Email": JSON.parse(process.env.TEST_USER).Email,
"Name": "Test User",
"Password": process.env.TEST_ACCOUNTS_PASSWORD
})
expect(response.status).toBe(RESPONSE_CODE.CONFLICT);
expect(JSON.parse(response.text)).toEqual({
Message: RESPONSE_MESSAGES.ALREADY_EXISTS
})
console.log('*** Signup for user that don\'t exists *** response', response.text, 'response status', response.status);
});
});
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't
stopped in your tests. Consider running Jest with
--detectOpenHandles to troubleshoot this issue.
Cannot log after tests are done. Did you forget to wait for something
async in your test?
Attempted to log "{ accepted: [ 'unverifiedtestuser#abc.com' ],
rejected: [],
envelopeTime: 621,
messageTime: 867,
messageSize: 906,
response: '250 2.0.0 OK 1551945300 f6sm5442066wrt.87 - gsmtp',
envelope:
{ from: 'abc#gmail.com',
to: [ 'unverifiedtestuser#abc.com' ] },
messageId: '<45468449-b5c8-0d86-9404-d55bb5f4g6a3#gmail.com>' }".
at CustomConsole.log (node_modules/jest-util/build/CustomConsole.js:156:10)
at src/email/MailHandler.ts:2599:17
at transporter.send.args (node_modules/nodemailer/lib/mailer/index.js:226:21)
at connection.send (node_modules/nodemailer/lib/smtp-transport/index.js:247:32)
at callback (node_modules/nodemailer/lib/smtp-connection/index.js:435:13)
at stream._createSendStream (node_modules/nodemailer/lib/smtp-connection/index.js:458:24)
at SMTPConnection._actionSMTPStream (node_modules/nodemailer/lib/smtp-connection/index.js:1481:20)
at SMTPConnection._responseActions.push.str (node_modules/nodemailer/lib/smtp-connection/index.js:968:22)
at SMTPConnection._processResponse (node_modules/nodemailer/lib/smtp-connection/index.js:764:20)
at SMTPConnection._onData (node_modules/nodemailer/lib/smtp-connection/index.js:570:14)
I was using the react-native default test case (see below) when Cannot log after tests are done happened.
it('renders correctly', () => {
renderer.create(<App />);
});
Apparently, the problem was that the test ended but logging was still needed. So I tried to make the callback in the test case async, hoping that the test won't terminate immediately:
it('renders correctly', async () => {
renderer.create(<App />);
});
And it worked. However, I have very little clue what the inner working is.
If you are using async/await type in your code, then this error can occur when you are calling async function without await keyword.
In my case, I have defined a function like this below,
async getStatistics(headers) {
....
....
return response;
}
But I have called this method like getStatistics(headers) instead of await getStatistics(headers).
When I included await, it worked fine and the issue resolved.
In my case while using nodejs + jest + supertest the problem was that when I import app from "./app" to my test file to do some stuff with supertest (request(app)), I actually import with app.listen() , because when I'm exporting app, export takes in account app.listen() too, but we don't need app.listen() in tests and it throws an error
"Cannot log after tests are done.Did you forget to wait for something async in your test?"
Here is all in one file(that's the problem!)
const app = express();
app.use(express.json());
// ROUTES
app.get("/api", (req, res) => {
res.json({ message: "Welcome to Blog API!" });
});
app.use("/api/users", usersRoutes);
app.use("/api/blogs", blogsRouter);
// The server will start only if the connection to database is established
mongoose
.connect(process.env.MONGO_URI!)
.then(() => {
console.log("MongoDB est connecté");
const port = process.env.PORT || 4000;
app.listen(port, () => console.log(`The server is running on port: ${port}`));
})
.catch(err => {
console.log(err);
});
export default app;
To solve this issue I created 2 separate folders:
// 1) app.ts
Where I put all stuff for my const app = express(), routes etc and export app
dotenv.config();
const app = express();
app.use(express.json());
// ROUTES
app.get("/api", (req, res) => {
res.json({ message: "Welcome to Blog API!" });
});
app.use("/api/users", usersRoutes);
app.use("/api/blogs", blogsRouter);
export default app;
// 2) index.ts
Where I put app.listen() and mongoose.connection() and import app
*import mongoose from "mongoose";
import app from "./app";
// The server will start only if the connection to database is established
mongoose
.connect(process.env.MONGO_URI!)
.then(() => {
console.log("MongoDB est connecté");
const port = process.env.PORT || 4000;
app.listen(port, () => console.log(`The server is running on port: ${port}`));
})
.catch(err => {
console.log(err);
});*
For me I needed to add an await before the expect() call also to stop this error (and an async before the test() callback function).
Also caused and fixed Jest not detecting coverage on the lines in the code throwing the error!
test("expect error to be thrown for incorrect request", async () => {
await expect(
// ^ added this
async () => await getData("i-made-this-up")
).rejects.toThrow(
"[API] Not recognised: i-made-this-up"
);
});
getData() returns an Axios call and in this case an error is caught by catch and re-thrown.
const getData = async (id) => {
return await axios
.get(`https://api.com/some/path?id=${id}`)
.then((response) => response.data)
.catch((error) => {
if (error?.response?.data?.message) {
console.error(error) // Triggered the error
throw new Error("[API] " + error.response.data.message);
}
throw error;
});
};
This happened to me because I had an infinite loop while (true). In my case, I was able to add a method for setting the value of the loop based on user input, rather than defaulting to true.
In my case, the error was caused by asynchronous Redis connection still online. Just added afterall method to quit Redis and could see the log again.
Working on Typescript 4.4.2:
test("My Test", done => {
let redisUtil: RedisUtil = new RedisUtil();
let redisClient: Redis = redisUtil.redis_client();
done();
});
afterAll(() => {
redisClient.quit();
});
I solved it with the env variables:
if (process.env.NODE_ENV !== 'test') {
db.init().then(() => {
app.listen(PORT, () => {
console.log('API lista por el puerto ', PORT)
})
}).catch((err) => {
console.error(err)
process.exit(1)
})
} else {
module.export = app
}
I faced same warnings. However the fix is bit weird:
The jest unit test script import a function (which is not export from src/). After I added the export to the function to be tested. The error disappears.
I had a similar issue:
Cannot log after tests are done. Did you forget to wait for something async in your test?
Attempted to log "Warning: You seem to have overlapping act() calls, this is not supported. Be sure to await previous act() calls before making a new one. ".
It was due to a missing static keyword. This code caused the issue:
class MyComponent extends React.Component<Props, State> {
propTypes = {
onDestroy: PropTypes.func,
}
}
It should have been:
class MyComponent extends React.Component<Props, State> {
static propTypes = {
onDestroy: PropTypes.func,
}
}

Vue + Vuetify - test:unit cannot see the v-alert message value

In my component template I have a v-alert vuetify sub-component
<v-alert dismissible #input="closeAlert()" #type="msgTypeContactForm" v-model="msgStatusContactForm">{{ msgValueContactForm }}</v-alert>
using the following data
data() {
return {
...
msgStatusContactForm: false,
msgTypeContactForm: "",
msgValueContactForm: ""
};
},
on submitting the form, when an error is raised , I set these data
catch (err) {
this.msgTypeContactForm = "error";
this.msgValueContactForm = this.$i18n.t("lang.views.home.contactForm.post_error");
this.msgStatusContactForm = true;
This is running fine, the alert is correctly displayed with the correct type and value ..
However in the component unit test , the alert properties and value are not updated in the template
it("should not sendMessage - invalid form", async () => {
...
wrapper = mount(ContactForm, options);
const contactForm = wrapper.find("form");
...
const btnSubmit = wrapper.find("#btnSubmit");
btnSubmit.trigger("click");
await wrapper.vm.$nextTick();
// then
setTimeout(() => {
expect(wrapper.vm.validForm).toEqual(false);
expect(wrapper.vm.msgStatusContactForm).toEqual(true);
expect(wrapper.vm.msgTypeContactForm).toEqual("error");
}, 2000);
await wrapper.vm.$nextTick();
const alert = wrapper.find(".v-alert");
console.log("INVALID FORM ALERT: ", alert.html());
})
console.log tests/unit/ContactForm.spec.js:383
INVALID FORM ALERT: cancel
the alert should be displayed and the type set and message value present in the html output ....
I don't know where I am wrong in my test ? any help appreciated
SOLVED..
It's a matter of handling async/await function... in my component
submitForm: async function() {
....
So I use flush-promises in my test
yarn add -D flush-promises
then
import flushPromises from "flush-promises";
...
it("should not sendMessage - invalid form", async () => {
...
wrapper = mount(ContactForm, options);
...
// then
const btnSubmit = wrapper.find("#btnSubmit");
btnSubmit.trigger("click");
await flushPromises();
...
const alert = wrapper.find(".v-alert");
console.log("INVALID FORM ALERT: ", alert.html());
Then I can see the DOM updated
<div class="v-alert error" style=""><div>One or more fields are invalid. Please, review your input and submit</div><a class="v-alert__dismissible"><i aria-hidden="true" class="v-icon v-icon--right material-icons theme--light">cancel</i></a></div>

Querying with apollo-link-state gives the error "Field <name> doesn't exist on type 'Query'"

I'm totally new to both Apollo and GraphQL. I'm following along with this apollo-link-state-tutorial, and am hitting a stumbling block.
I have set up my link with a currentGame property default.
const stateLink = withClientState({
cache: stateCache,
defaults: {
currentGame: {
__typename: 'currentGame',
teamAScore: 0
}
}
})
I'm using it in my client.
const client = new ApolloClient({
stateCache,
link: stateLink,
...
})
I'm defining a GraphQL query like this:
const getCurrentGame = gql`
query {
currentGame #client {
teamAScore
}
}
`
I am connecting it to my component's props.
export default compose(
graphql(getCurrentGame, {
props: ({ data: { currentGame }}) => ({
currentGame
})
})
)
This generates an error in the console.
[GraphQL error]: Message: Field 'currentGame' doesn't exist on type 'Query', Location: [object Object], Path: undefined
I've gone over my code and haven't been able to spot what is surely a typo or simple mistake. How can I debug this error message, or what does it suggest the problem is?
Update: I have tried adding a resolver as suggested by Tal Z, but am still receiving the same error message.
const stateCache = new InMemoryCache()
const stateLink = withClientState({
cache: stateCache,
resolvers: {
Query: {
currentGame: () => {
return {}
}
}
},
defaults: defaultState
})
For what it's worth, most of the few example repositories I've found have queries for fields that do not have resolvers defined. For example, this queries for todo list items, but the only resolver defined is for a mutation.
Well, I figured it out... this breaks:
import ApolloClient from 'apollo-boost'
This works:
import ApolloClient from 'apollo-client'
I have no idea what the difference is.