Relay mutation is not resolving synchronously in test
I have the following code essentially.
// MyComponent.js
const myMutation = graphql`
mutation myMutation($input: MyInput!) {
doMyMutation(input: $input) {
ok
}
}
`
const MyComponent = () => {
const [mutate] = useMutation(myMutation)
const handleClick = async () => {
const variables = {
input: {
stuff: true
}
}
await mutate({ variables })
myfunction('Hello World')
}
return <button onClick={handleClick}>Click Me</button>
}
export default MyComponent
// test.js
import myfunction from './myfunction'
it('should finish mutation', async () => {
environment.mock.queueOperationResolver(operation =>
MockPayloadGenerator.generate(operation)
)
const { getByText } = render(<MyComponent />)
fireEvent.click(getByText('Click Me'))
expect(myfunction).toHaveBeenCalledWith('Hello World')
// expect(AsyncRequestStore.clickToCall).toHaveBeenCalledTimes(2)
})
// myfunction.js
const myfunction = (message) => {
console.log(message)
}
export default myfunction
However, when I run the test, the mutation finishes after the test runs, saying there is something async going on. There are non timers I can see directly in my code. What could be causing this to not resolve the mutation until several frames/milliseconds later?
I would expect myfunction
(which is mocked with jest.mock('./myfunction')
to be called with Hello World
, but it is not being called by the time at this point in the test, it only gets called after the test is done.
See also questions close to this topic
-
Unable to catch and log the error from axios request
I'm validating user input and result in express and am returning 422 if the input is invalid and a 400 if result is empty. The problem is that I can't log the response object when an error occurs.
Nodejs:
if (q === '' || q.length < 3 || q.length > 150) { console.log('invalid query'); return res.sendStatus(422).send('Search not found'); } else { try { // Fetch redis data const data = await GET_ASYNC('data'); // stuff here // Result Validation if (!Array.isArray(data) || !data.length) { res.status(400).send('Search not found'); } else { // do stuff res.status(200).send(data); } } catch (err) { console.error(err); res.sendStatus(500); // Server error }
Now my react code:
const searchDb = useCallback(async() => { const CancelToken = axios.CancelToken; const source = CancelToken.source(); try { axios.get(`/api/bestProduct?q=${searchValue}`, { cancelToken: source.token }) .then(res => { console.log(res) // nothing shows up const data = res.data; setData(data) }); } catch (err) { if (axios.isCancel(err)) { console.log(err.response); // nothing shows up } else { console.log('hello??') // nothing return setError(`There's been a problem on our end.`) } } }, [])
I've looked at other solution and tried to log the res and res.status but nothing shows up. This is what my console looks like during the error:
-
Dynamic object keys... Cannot create property on string
I'm trying to make an input automatically store its value in an object. The key should be the input's id. Ex: {screen1_input1: 'whatever'}. The first character does that. The second character crashes with "TypeError: Cannot create property on string". I think I see what's happening but I don't know how to fix it.
import { useState } from 'react' function Demo() { const [contentData, setContentData] = useState({}) const onChange = (e) => { let oldData = contentData setContentData(oldData[e.target.id] = e.target.value) console.log('*') } const Screen1 = () => { return ( <> <input type="text" id="screen1_input1" onChange={onChange} /> </> ) } return ( <> <h2 className="Demo"> {Screen1()} </h2> </> ) } export default Demo
-
How can I extract a nested array of objects and put them in the core array?
I am working on a functionality where I need to group some items and also ungroup them.
Some days ago I asked this question: How can I group specific items within an object in the same array and delete them from the core array? where a couple of people helped me solving the grouping part. But it is very related to this question.
What I need to do now, is to ungroup the items with the exact same requirement: ungroup the
checked === true
group and put the items back from where they came from and remove all duplicates.Here is a reproducible demo with both functionalities: https://codesandbox.io/s/ts-react-grouping-forked-rmwhr?file=/src/App.tsx
And here the relevante piece of code:
const handleUngroupingQuestions = (): void => { const questionAddedCopy: VariableConfig[] = [...questionAdded] const filteredByChecked: VariableConfig[] = questionAddedCopy.filter((q: VariableConfig) => isCheck.includes(q.id)) if (isCheck.length) { setCheck([]) const extractGroup = (i: number): VariableConfig[] => filteredByChecked[i].questionGroup const addChecked = (q: VariableConfig): VariableConfig => ({ ...q, questionGroup: [] }) // @TODO // Remove this when we have a proper data structure clearVariable() const nestChecked = (qs: VariableConfig[], found = false) => qs.flatMap((q: VariableConfig, i: number) => { if (filteredByChecked.includes(q)) { if (found) { return [] } else { found = true return [...[addChecked(q)], ...extractGroup(i)] } } else { return [q] } }) const getNew = [...nestChecked(questionAdded)] console.log({ getNew: JSON.stringify(getNew, null, 2) }) addQuestion(getNew.filter((g, i, a) => a.indexOf(g) === i)) } }
For some reason right now I am getting an error:
Cannot read property 'questionGroup' of undefined
Something is happening with an index.
So what I need is to group all of the items with the checked property being true. Then click on
ungroup
and bring the items back to its original position and deleting the current group. I must be able to do that even when there are multiple groups of questions.What am I missing?
-
Jest mock middleware response
I am trying to mock a middleware response, and i am trying to use
jest.spyOn()
but can't seem to get it workingMy controller.ts has the following
import someMiddleware from '../someMiddleware; .... .... this.route.post('/getData', someMiddleware, setValue)
In someMiddlware.ts
//making a fetch call based on data in req.body ..... const data = await fetchData(url, data) next() .....
In my test file controller.test.ts
describe('Test Data', () => { beforeEach(() => { someMiddlewareSpyOn = jest.spyOn(meddelware, "someMiddleware"); }); afterEach(() => { jest.resetModules(); jest.resetAllMocks(); }); it('response status should be a 200', async () => { someMiddlewareSpyOn.mockResolvedValue({data:[].....}); const res = await request(app.getServer()) .post('/getData'); expect(res.status).toBe(200); }) });
The above does not work, looking for assistance on how to do this.
-
Testing Controller and Service in Jest
I'm fairly new to Jest and have been trying (with no luck) to figure out how to write tests for my controller. I'm not sure how to write the test as it calls another function. It would be great if I could get pointed in the right direction at least. Thanks in advance.
controller.ts
import * as Services from './services'; export async function GetCountriesList(req: Request, res: Response): Promise<void> { const response = await Services.GetCountriesList(); res.status(response.code).json({ status: response.status, message: response.message, count: response.count, data: response.data }); }
service.ts
import db from '../../modules/db'; import { DBGenericDataResponse } from '../../types/models'; export async function GetCountriesList(): Promise<DBGenericDataResponse> { const lQuery = 'somquery'; const responseMessage: DBGenericDataResponse = { code: 200, status: 'ok', message: '', count: 0, data: [], error: '' }; try { const dbResult = await db.query<any>(lQuery); responseMessage.message = 'Countries returned'; responseMessage.count = dbResult.rows.length; responseMessage.data = dbResult.rows; } catch (err) { responseMessage.code = 400; responseMessage.status = 'error'; responseMessage.message = 'Error retrieving Countries List'; responseMessage.error = err; } return responseMessage; }
-
Warning: <TEXT /> is using incorrect casing
console.error node_modules/react-dom/cjs/react-dom.development.js
Warning:
<TEXT />
is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.I have the issue with Jest and react-pdf
In the component where I'm using the react-pdf components this is written as:
<Text>
, but when performing the test it's appearing as<TEXT>
My component:
const HeaderPDF: React.FC<Props> = (props: Props) => { return ( <View style={styles.headerContainer} fixed> <View style={styles.headerTop}> <Text style={styles.textBoldTopHeader}> "Some text" </Text> <View style={styles.headerTopInputContainer}> <View style={styles.headerTopInputTextContainer}> <Text style={styles.textInputTopHeader}>Route</Text> </View> <View style={styles.inputSmall} /> </View> </View> </View> ); };
The test:
import React from 'react'; import { render } from 'tests/support/customRender'; import HeaderPDF from ../../HeaderPDF'; describe('HeaderPDF', () => { it('Renders a HeaderPDF component successfully', () => { const { container } = render( <HeaderPDF someProps /> ); expect(container).toMatchSnapshot(); }); });
-
Apollo GraphQL React refresh token(with AWS amplify) fromPromise --> flatMap() is not being triggered at all
So I followed the documentation from this post to implement the refresh token logic How to refresh JWT token using Apollo and GraphQL
Here's my code:
import Auth from '@aws-amplify/auth'; const getNewToken = () => { return Auth.currentSession() .then(data => { return { accessToken: data.getAccessToken().getJwtToken(), refreshToken: data.getRefreshToken().getToken() }; }) .catch(error => { console.log('error', error); }); };
const link = ApolloLink.from([ stateLink, authLink, onError(({ graphQLErrors, networkError, operation, forward }) => { if (graphQLErrors) { graphQLErrors.map(({ message, locations, path, extensions }) => { if (message.includes('Access Token has expired')) { console.log('access token has expired'); return fromPromise( getNewToken().catch(error => { console.log('error', error) // Handle token refresh errors e.g clear stored tokens, redirect to login }) ) .filter(value => Boolean(value)) .flatMap(accessToken => { console.log('access token!!!', accessToken) const oldHeaders = operation.getContext().headers; // modify the operation context with a new token operation.setContext({ headers: { ...oldHeaders, authorization: `Bearer ${accessToken}` } }); // retry the request, returning the new observable return forward(operation); }); } console.log( `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}` ); }); } if (networkError) console.log(`[Network error]: ${networkError}`); }), linkHttp ]);
But it does not work, the request is not made again and even the
console.log('access token!!!', accessToken)
is not being called.I don't know why the code inside flatMap() is not being executed. I can't figure out what am I doing wrong, please advise what should I do -
GraphQL Express server with Typescript resolve() typecheck on a mutation
As the title mentions, I'm in the process of building the backend with graphql, express, and typescript. I am getting an issue with typescript type-checking in the resolve() function inside of my mutation function. The mutation function simply updates a subfield of the user object (previous language to updated language). But typescript is telling me "Property 'language' does not exist on type 'Document'.ts(2339)" when I attempt to access the language key after finding my user. I'm not sure what the issue is when I'm just trying to access the key value of user..
Thanks for your time.
export const mutation = new GraphQLObjectType({ name: "Mutation", fields: { editUserLanguage: { type: UserType, args: { userId: { type: GraphQLString }, language: { type: GraphQLString } }, async resolve (_, { userId, language }): Promise<void | any> { const user = await User.findById(userId); user!.language = language; //error on user!.language user!.save(); } } }, });
-
Best practice around GraphQL nesting depth
I’ve read through the GraphQL and Apollo docs and hunted around to find guidelines for the best practice around GraphQL schema design and can’t find authorative answers to these questions
- Is there an optimum maximum depth to nesting?
We are often presented with the option to either try to represent complex heirarchical data models with the nesting they demonstrate in real life. In my work this is genetics and modelling protein / transcript / homology relationships where it is possible to have very deep nesting up to maybe 7/8 levels .. we use dataloader to make nested batching more efficient and resolver level caching with directives, but is it good practice to model a schema on a real life data model or should you focus on making your resolvers reasonable to query and keep nesting to a maximum ideal depth of say 4 levels.. or is this fine?
- When designing a schema is it better to create a different parent resolver for a type or use arguments that to direct a conditional response
If I have two sets of for example ‘cars’ let’s say I have cars produced by Volvo and cars produced by tesla and the underlying data while having similarities is originally pulled from different apis with different characteristics. Is it best practice to have a tesla_cars and volvo_cars resolver or one cars resolver which uses for example a manufacturer argument to act differently on the data it returns and homogenise the response especially where there may then be a sub resolver that expects certain fields which may not be similar in the original data.
Or is it better to say.. these two things are both cars but the shape of the data we have for them is significantly different so its better to create seperate resolvers with totally or notably different fields
- Should my resolvers and graphQL apis try to model the data they describe or should I allow duplication in order to create efficient application focused queries and responses?
We often find ourselves wondering do we have a seperate api for application x and y that maybe use underlying data and possibly even multiple sources (different databases or even api calls) inside resolvers very differently or should we try to make a resolver work with any application even if that means using type like arguments to allow custom filtering and conditional behaviour.
It would be great to get some answers to these from people with deep production experience of GraphQL. It’s very hard to get answers to these questions and yet they seem like such fundamental ones to designing a scaleable and extendable schema / api or set of apis
Thanks
Dan
-
resetting a pagination to refetch on default variables on pull to refresh throw cursor warning?
i have this props on my flatlist:
onRefresh={() => { setIsRefreshing(true); refetch( { categoriesCount: 4, categoriesCursor: '' }, { fetchPolicy: 'network-only', onComplete: () => { setIsRefreshing(false); }, } ); }}
this is how i initialize pagination:
const { data, loadNext, isLoadingNext, hasNext, refetch } = usePaginationFragment< CategoriesPaginationQuery, Categories_viewer$key >( graphql` fragment Categories_viewer on Viewer @argumentDefinitions( categoriesCount: { type: "Int", defaultValue: 4 } categoriesCursor: { type: "String", defaultValue: "" } ) @refetchable(queryName: "CategoriesPaginationQuery") { categories(first: $categoriesCount, after: $categoriesCursor) @connection(key: "Categories_viewer_categories", filters: []) { pageInfo { startCursor endCursor hasNextPage hasPreviousPage } edges { cursor node { id pk name } } } } `, viewer );
this is the warning:
Warning: Relay: Unexpected after cursor ``, edges must be fetched from the end of the list (YXJyYXljb25uZWN0aW9uOjc=).
you see on the argumentDefinitions the default value of categoriesCount is 4 and categoriesCursor is "" and i think relay thinks i am reusing variables that's already fetched but what i want to do is make the pagination "forget it's current edges" and go back like the beginning on pull to refresh?
-
Why is QueryRenderer passing null to render?
This must be a classic beginner's mistake but I can't see the problem. Why is the
props
in the belownull
? In the very last part of the question I have included the server response. This tells me there is nothing wrong with the graphql aspect; indeed I get the same response through the Browser API.// index.js ReactDOM.render( <QueryRenderer environment={environment} query={graphql` query assetsQuery { viewer { ...PeopleList_people id } } `} render={({ error, props }) => { console.log(props); // is null for some reason console.log(error); return <PeopleList people={props.viewer.people} /> }} />, document.getElementById('root') );
// PeopleList.js const PeopleList = (props) => { return ( <table> <thead> <tr> <th>Unique Identifier</th> <th>First Name</th> <th>Last Name</th> </tr> </thead> <tbody> { props.viewer.people.edges.map(edge => <tr key={edge.node.id}> <Person person={edge.node} /> </tr> ) } </tbody> </table> ) }; export default createFragmentContainer(PeopleList, { people: graphql` fragment PeopleList_people on ViewerNode { people( first: 100 ) @connection(key: "PeopleList_people"){ edges { node { id, ...Person_person } cursor } } } ` })
// Person.js const Person = (props) => { return ( <> <td>{props.person.uniqueIdentifier}</td> <td>{props.person.firstName}</td> <td>{props.person.lastName}</td> <td>Edit button</td> <td>Delete button</td> </> ) }; export default createFragmentContainer(Person, { person: graphql` fragment Person_person on PersonNode { uniqueIdentifier firstName lastName } ` });
When the page loads I can see the response to the graphql response is
{"data":{"viewer":{"people":{"edges":[{"node":{"id":"UGVyc29uTm9kZTox","uniqueIdentifier":"1","firstName":"Ross","lastName":"Meredith","__typename":"PersonNode"},"cursor":"YXJyYXljb25uZWN0aW9uOjA="},{"node":{"id":"UGVyc29uTm9kZToy","uniqueIdentifier":"2","firstName":"Nicole","lastName":"Meredith","__typename":"PersonNode"},"cursor":"YXJyYXljb25uZWN0aW9uOjE="},{"node":{"id":"UGVyc29uTm9kZToz","uniqueIdentifier":"3","firstName":"Ross","lastName":"Meredith","__typename":"PersonNode"},"cursor":"YXJyYXljb25uZWN0aW9uOjI="}],"pageInfo":{"endCursor":"YXJyYXljb25uZWN0aW9uOjI=","hasNextPage":false}},"id":"Vmlld2VyTm9kZTpOb25l"}}}
And this is the request payload -
query assetsQuery { viewer { ...PeopleList_people id } } fragment PeopleList_people on ViewerNode { people(first: 100) { edges { node { id ...Person_person __typename } cursor } pageInfo { endCursor hasNextPage } } } fragment Person_person on PersonNode { uniqueIdentifier firstName lastName }
-
Cannot read property 'createKeywordTypeNode' of undefined
I have a react typescript application which uses GraphQl. Everything was working fine till yesterday But now I am receiving a weird bug while executing the command
"yarn run relay && react-scripts start"
"relay": "relay-compiler --src ./src --schema ./src/modules/open-cti/schema.graphql --language=typescript --extensions=ts --extensions=tsx",
Can anyone help how to troubleshoot this one I am using
nodejs 12.16.1
and Typescript version^3.8.3
-
Export babel-plugin-relay/macro erroring with create-react-app
I am trying to export the
babel-plugin-relay/macro
module in a file (to make my relay functions easier to import), however it is throwing an error. I am using create-react-app without ejecting or changing any config.Module parse failed: Export 'graphql' is not defined (7:9) File was processed with these loaders: * ./node_modules/@pmmmwh/react-refresh-webpack-plugin/loader/index.js * ./node_modules/babel-loader/lib/index.js You may need an additional loader to handle the result of these loaders. | export { preloadQuery } from "./preloadQuery"; | export { RelayEnvironment } from "./RelayEnvironment"; > export { graphql }; | | const currentExports = __react_refresh_utils__.getModuleExports(module.id);
import graphql from "babel-plugin-relay/macro" export { usePreloadedQuery } from "react-relay/hooks" export { preloadQuery } from "./preloadQuery" export { RelayEnvironment } from "./RelayEnvironment" export { graphql }
The only way I can make this work is by importing
babel-plugin-relay/macro
into the files I want to use it. -
GraphQL relay - file upload mutation with multipart request
Having a problem uploading file to server and executing my mutation in Graphql.
Mutation:
mutation($file: Upload!) { singleUpload(file: $file) { id } }
Client side:
commitMutation( environment, { mutation: mutationScript, variables: { file: selectedFile }, onCompleted: (response) => { .... }, onError: error => { ... }, }, );
<input type="file" name="file" onChange={(event) => { if (event.target.files && event.target.files.length > 0) { setSelectedFile(event.target.files[0]) }} }/>
The problem Im having is when I try to execute my mutation, the server returns
{"0": { "message": "Cannot convert 'System.Collections.Generic.Dictionary`2[System.String,System.Object]' value to AST for type 'Upload'." } }
Server setup guide that I used: https://github.com/JannikLassahn/graphql-dotnet-upload
And strangely enough when I execude command line, it works like a charm:
curl localhost:1345/graphql ^ -F operations="{ \"query\": \"mutation ($file: Upload!) { singleUpload(file: $file) }\", \"variables\": { \"file\": null } }" ^ -F map="{ \"0\": [\"variables.file\"] }" ^ -F 0=@nice.txt
Any ideas whats wrong with it?