Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add React Query command #26

Merged
merged 3 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 0 additions & 76 deletions src/commands/__tests__/reactQuery.test.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/commands/createApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ async function printIntro(appName: string) {
- ESLint
- Jest, React Native Testing Library
- React Navigation
- Intuitive directory structure
- TanStack Query (formerly known as React Query)
`);

if (!globals.interactive) {
Expand Down
10 changes: 3 additions & 7 deletions src/util/addToGitignore.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import fs from 'fs-extra';
import path from 'path';
import getProjectDir from './getProjectDir';
import appendToFile from './appendToFile';

/**
* lines should be separated by newlines
*/
export default async function addToGitignore(lines: string) {
return fs.appendFile(
path.join(await getProjectDir(), '.gitignore'),
`\n${lines}`,
);
return appendToFile('.gitignore', lines);
}
12 changes: 12 additions & 0 deletions src/util/appendToFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import fs from 'fs-extra';
import path from 'path';
import getProjectDir from './getProjectDir';
/**
* lines should be separated by newlines
*/
export default async function appendToFile(filename: string, lines: string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of having both the addToGitignore and the appendToFile to the same fileUtils file? This would keep the src/util leaner and keep related utilities together instead of having 1 file per function.

return fs.appendFile(
path.join(await getProjectDir(), filename),
`\n${lines}`,
);
}
9 changes: 7 additions & 2 deletions templates/boilerplate/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { NavigationContainer } from '@react-navigation/native';

import { QueryClientProvider } from '@tanstack/react-query';
import Providers, { Provider } from 'src/components/Providers';
import RootNavigator from 'src/navigators/RootNavigator';
import queryClient from 'src/util/api/queryClient';

// Add providers to this array
// Add providers to this array. They will be wrapped around the app, with the
// first items in the array wrapping the last items in the array.
const providers: Provider[] = [
(children) => <NavigationContainer>{children}</NavigationContainer>,
(children) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
),
// CODEGEN:BELT:PROVIDERS - do not remove
];

Expand Down
14 changes: 14 additions & 0 deletions templates/boilerplate/jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import '@testing-library/jest-native/extend-expect';
import { configure } from '@testing-library/react-native';
import mockSafeAreaContext from 'react-native-safe-area-context/jest/mock';
import mockBackHandler from 'react-native/Libraries/Utilities/__mocks__/BackHandler.js';
import server from 'src/test/server';
import queryClient from 'src/util/api/queryClient';

beforeEach(() => {
jest.clearAllMocks();
Expand Down Expand Up @@ -35,6 +37,18 @@ jest.mock('@react-native-async-storage/async-storage', () =>

jest.mock('react-native-keyboard-aware-scroll-view');

// listen with MSW server. Individual tests can pass mocks to 'render' function
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
afterAll(() => server.close());

beforeEach(() => {
server.resetHandlers();
});

afterEach(() => {
queryClient.clear();
});

// configure debug output for RN Testing Library
// is way too verbose by default. Only include common
// props that might affect test failure.
Expand Down
4 changes: 4 additions & 0 deletions templates/boilerplate/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@
"@react-navigation/bottom-tabs": "^6.5.20",
"@react-navigation/native": "^6.1.10",
"@react-navigation/native-stack": "^6.9.18",
"@tanstack/react-query": "^5.32.1",
"axios": "^1.6.8",
"expo": "^50.0.17",
"expo-status-bar": "~1.11.1",
"jest": "^29.3.1",
"jest-expo": "~50.0.2",
"msw": "^2.2.14",
"react": "18.2.0",
"react-native": "0.73.6",
"react-native-keyboard-aware-scrollview": "^2.1.0",
Expand All @@ -40,6 +43,7 @@
"@thoughtbot/eslint-config": "^1.0.2",
"@types/jest": "^29.5.12",
"@types/react": "~18.2.73",
"@types/react-test-renderer": "^18.0.7",
"babel-jest": "^29.7.0",
"create-belt-app": "^0.4.0",
"eslint": "^8.56.0",
Expand Down
29 changes: 25 additions & 4 deletions templates/boilerplate/src/__tests__/App.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
import { screen } from '@testing-library/react-native';

import RootNavigator from 'src/navigators/RootNavigator';
import render from 'src/test/render';
import mock from 'src/test/mock';
import { renderApplication } from 'src/test/render';

test('renders', async () => {
// We would not normally recommend fake timers, but the tests are currently
// throwing a "not wrapped in act" warning after this test finishes. One
// option is to put a `await waitForUpdates()` at the end of the test, but
// fake timers also work here until we find a better solution. The stack trace
// seems to point to React Navigation bottom tabs.
jest.useFakeTimers();
render(<RootNavigator />);
expect(await screen.findByText(/Open up App.tsx/)).toBeDefined();

const mocks = [mockCoffees()];

renderApplication({ mocks });

expect(await screen.findByRole('header', { name: 'Mocha' })).toBeDefined();
});

function mockCoffees() {
return mock.get('coffee/hot', {
response: [
{
id: 1,
title: 'Mocha',
image: 'htps://placehold.it/200x200',
},
],
});
}
49 changes: 49 additions & 0 deletions templates/boilerplate/src/components/ExampleCoffees.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { useQuery } from '@tanstack/react-query';
import { FlatList, Image, Text, View } from 'react-native';
import api, { Coffee as CoffeeType } from 'src/util/api/api';

// TODO: sample data, remove
export default function ExampleCoffees() {
const { data } = useQuery({ queryKey: ['coffee'], queryFn: api.coffee });

return (
<>
<Text style={{ fontWeight: '600', fontSize: 24 }}>Coffees</Text>
<FlatList
data={data?.slice(0, 4)}
numColumns={2}
scrollEnabled={false}
renderItem={({ item }) => <Coffee coffee={item} />}
keyExtractor={(item) => item.id.toString()}
style={{ flexGrow: 0 }}
/>
</>
);
}

function Coffee({ coffee }: { coffee: CoffeeType }) {
const { title, image } = coffee;

return (
<View
style={{
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'salmon',
borderRadius: 10,
padding: 16,
margin: 10,
}}
>
<Text accessibilityRole="header" style={{ fontWeight: '600' }}>
{title}
</Text>
<Image
width={100}
height={100}
source={{ uri: image }}
accessibilityIgnoresInvertColors
/>
</View>
);
}
2 changes: 2 additions & 0 deletions templates/boilerplate/src/screens/HomeScreen/HomeScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useNavigation } from '@react-navigation/native';
import { StatusBar } from 'expo-status-bar';
import { Button, StyleSheet, Text, View } from 'react-native';
import ExampleCoffees from 'src/components/ExampleCoffees';
import { HomeScreenProp } from 'src/navigators/navigatorTypes';

export default function HomeScreen() {
Expand All @@ -14,6 +15,7 @@ export default function HomeScreen() {
onPress={() => navigation.navigate('Information', { owner: 'Will' })}
/>
<StatusBar style="auto" />
<ExampleCoffees />
</View>
);
}
Expand Down
Loading
Loading