Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save juliomerisio/b886d69ca7cc768abcc6ea04792104d1 to your computer and use it in GitHub Desktop.
Save juliomerisio/b886d69ca7cc768abcc6ea04792104d1 to your computer and use it in GitHub Desktop.
test using relay hooks, relay-test-utils and react-testing-library
jest.mock('path/to/Environment', () => {
const { createMockEnvironment } = require('relay-test-utils');
return createMockEnvironment();
});
import React from 'react';
import { render, cleanup } from '@testing-library/react';
import { MockPayloadGenerator } from 'relay-test-utils';
import { useRelayEnvironment } from 'react-relay/hooks';
import TransactionList from '../TransactionList';
afterEach(cleanup);
describe('<TransactionList />', () => {
it('should reject query', () => {
const Environment = useRelayEnvironment();
const { getByText } = render(<TransactionList />);
Environment.mock.rejectMostRecentOperation(new Error('A very bad error'));
expect(getByText('Error: A very bad error')).toBeTruthy();
});
it('should reject query with function and render error with name of the operation', () => {
const Environment = useRelayEnvironment();
const { getByText } = render(<TransactionList />);
Environment.mock.rejectMostRecentOperation((operation) =>
new Error(`A error occurred on operation: ${operation.fragment.node.name}`)
);
expect(getByText('Error: A error occurred on operation: TransactionListQuery')).toBeTruthy();
});
it('should render success TransactionList', async () => {
const Environment = useRelayEnvironment();
const { getByText } = render(<TransactionList />);
expect(getByText('loading transactions...')).toBeTruthy();
Environment.mock.resolveMostRecentOperation(operation =>
MockPayloadGenerator.generate(operation, {
PageInfo() {
return {
hasNextPage: false,
hasPreviousPage: false,
startCursor: "YXJyYXljb25uZWN0aW9uOjA=",
endCursor: "YXJyYXljb25uZWN0aW9uOjE="
}
},
TransactionEdge() {
return [
{
cursor: "YXJyYXljb25uZWN0aW9uOjA=",
node: {
id: "Q2xpZW50OjE=",
fromUser {
user: "George Lima",
username: "georgelima",
},
toUser {
user: "Augusto Calaca",
username: "augustocalaca",
},
value: 1000,
cashback: 50,
message: 'A gift on your birthday'
}
},
{
cursor: "YXJyYXljb25uZWN0aW9uOjE=",
node: {
id: "Q2xpZW50OjI=",
fromUser {
user: "Bori Silva",
username: "bori",
},
toUser {
user: "Augusto Calaca",
username: "augustocalaca",
},
value: 500,
cashback: 25,
message: 'This transaction yielded cashback'
}
}
]
}
})
);
expect(getByText('FromUser')).toBeTruthy();
expect(getByText('Name: George Lima')).toBeTruthy();
expect(getByText('Username: georgelima')).toBeTruthy();
expect(getByText('ToUser')).toBeTruthy();
expect(getByText('Name: Augusto Calaca')).toBeTruthy();
expect(getByText('Username: augustocalaca')).toBeTruthy();
expect(getByText('Value: 1000')).toBeTruthy();
expect(getByText('Cashback: 50')).toBeTruthy();
expect(getByText('Message: A gift on your birthday')).toBeTruthy();
expect(getByText('FromUser')).toBeTruthy();
expect(getByText('Name: Bori Silva')).toBeTruthy();
expect(getByText('Username: bori')).toBeTruthy();
expect(getByText('ToUser')).toBeTruthy();
expect(getByText('Name: Augusto Calaca')).toBeTruthy();
expect(getByText('Username: augustocalaca')).toBeTruthy();
expect(getByText(/Value: 500/)).toBeTruthy();
expect(getByText(/Cashback: 25/)).toBeTruthy();
expect(getByText(/Message: This transaction yielded cashback/)).toBeTruthy(); // this is a default message
});
});
import React, { Suspense, useCallback, useState } from 'react';
import { graphql, useLazyLoadQuery, usePaginationFragment } from 'react-relay/hooks';
const TransactionsListPagination = (props) => {
const {
data,
loadNext,
isLoadingNext,
hasNext,
refetch,
} = usePaginationFragment(
graphql`
fragment TransactionsList_query on Query
@argumentDefinitions(count: { type: "Int", defaultValue: 5 }, cursor: { type: "String" })
@refetchable(queryName: "TransactionsListPaginationQuery") {
transactions(first: $count, after: $cursor, fromUser: $fromUser)
@connection(key: "TransactionsList_transactions") {
totalCount
edges {
node {
id
fromUser {
id
name
username
}
toUser {
id
name
username
}
value
cashback
message
}
}
}
}
`,
props.query
);
const [isFetchingTop, setIsFetchingTop] = useState<boolean>(false);
const onRefresh = useCallback(() => {
if(isLoadingNext) {
return ;
}
setIsFetchingTop(true);
const onComplete = () => {
setIsFetchingTop(false);
};
const fetchPolicy = 'network-only';
refetch({}, { onComplete, fetchPolicy });
}, [isLoadingNext, isFetchingTop]);
const onEndReached = useCallback(() => {
if(isLoadingNext || !hasNext) {
return ;
}
loadNext(5);
}, [loadNext, isLoadingNext, hasNext]);
return (
<div>
{data.transactions!.edges.map((edge) => (
<div key={edge!.node.id}>
<div>
<strong>From User</strong>
<span>Name: {edge!.node.fromUser.name}</span>
<span>Username: {edge!.node.fromUser.username}</span>
</div>
<div>
<strong>To User</strong>
<span>Name: {edge!.node.toUser.name}</span>
<span>Uername: {edge!.node.toUser.username}</span>
</div>
<strong>Value: {edge!.node.value}</>
<strong>Cashback: {edge!.node.cashback}</>
<strong>Message: {edge!.node.message}</>
</div>
))}
<button oClick={onRefresh}>Refresh</button>
<button oClick={onEndReached}>Load More</button>
</div>
);
};
const TransactionsListLazyLoad = (props) => {
const query = useLazyLoadQuery(
graphql`
query TransactionsListQuery($fromUser: ID!) {
...TransactionsList_query
}
`,
{ fromUser: props.fromUser },
{ fetchPolicy: 'store-or-network' }
);
return <TransactionsListPagination query={query} />
};
const TransactionsList = (props) => {
return (
<Suspense fallback={<Text>loading transactions...</Text>}>
<TransactionsListLazyLoad {...props} />
</Suspense>
)
};
export default TransactionsList;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment