Skip to content

Commit

Permalink
feat!: change structure
Browse files Browse the repository at this point in the history
  • Loading branch information
tednaaa committed Jul 9, 2023
1 parent 51f49f3 commit 685b3d2
Show file tree
Hide file tree
Showing 52 changed files with 532 additions and 408 deletions.
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nodejs 18.15.0
nodejs 18.16.1
4 changes: 2 additions & 2 deletions src/app/testing/setup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import '@testing-library/jest-dom';

import { server } from '@/shared/api/mocks';
import { server } from '@/shared/api/mock-instance';

beforeAll(() => server.listen());
beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
55 changes: 52 additions & 3 deletions src/app/typings/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,53 @@
declare module '*.scss' {
const content: { readonly [className: string]: string };
export default content;
/// <reference types="react" />
/// <reference types="react-dom" />

declare module '*.module.scss' {
const classes: { readonly [key: string]: string };
export default classes;
}

declare module '*.svg' {
import * as React from 'react';

export const ReactComponent: React.FunctionComponent<
React.SVGProps<SVGSVGElement> & { title?: string }
>;

const src: string;
export default src;
}

declare module '*.bmp' {
const src: string;
export default src;
}

declare module '*.gif' {
const src: string;
export default src;
}

declare module '*.jpg' {
const src: string;
export default src;
}

declare module '*.jpeg' {
const src: string;
export default src;
}

declare module '*.png' {
const src: string;
export default src;
}

declare module '*.avif' {
const src: string;
export default src;
}

declare module '*.webp' {
const src: string;
export default src;
}
1 change: 1 addition & 0 deletions src/layouts/main/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { MainLayout } from './main';
22 changes: 22 additions & 0 deletions src/layouts/main/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { FC, ReactNode } from 'react';

import { Container } from '@/shared/ui/container';

import styles from './styles.module.scss';

interface Props {
title: string;
children: ReactNode;
}

export const MainLayout: FC<Props> = ({ title, children }) => {
return (
<div className={styles.wrapper}>
<Container>
<h1 className={styles.title}>{title}</h1>
</Container>

<div className={styles.content}>{children}</div>
</div>
);
};
12 changes: 12 additions & 0 deletions src/layouts/main/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.wrapper {
padding: 20px 0;
min-height: 100vh;
background: #312e2e;
color: #fff;
}

.title {
font-size: 30px;
line-height: 36px;
margin-bottom: 20px;
}
10 changes: 10 additions & 0 deletions src/modules/users/api/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { jsonApiInstance } from '@/shared/api/instances';
import { User } from './types';

export const routes = {
users: '/users',
};

export const fetchUsers = () => {
return jsonApiInstance.get<User[]>(routes.users);
};
100 changes: 100 additions & 0 deletions src/modules/users/api/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { User } from './types';

export const usersOkFixture: User[] = [
{
id: 1,
name: 'Leanne Graham',
username: 'Bret',
email: '[email protected]',
address: {
street: 'Kulas Light',
suite: 'Apt. 556',
city: 'Gwenborough',
zipcode: '92998-3874',
geo: {
lat: '-37.3159',
lng: '81.1496',
},
},
phone: '1-770-736-8031 x56442',
website: 'hildegard.org',
company: {
name: 'Romaguera-Crona',
catchPhrase: 'Multi-layered client-server neural-net',
bs: 'harness real-time e-markets',
},
},
{
id: 2,
name: 'Ervin Howell',
username: 'Antonette',
email: '[email protected]',
address: {
street: 'Victor Plains',
suite: 'Suite 879',
city: 'Wisokyburgh',
zipcode: '90566-7771',
geo: {
lat: '-43.9509',
lng: '-34.4618',
},
},
phone: '010-692-6593 x09125',
website: 'anastasia.net',
company: {
name: 'Deckow-Crist',
catchPhrase: 'Proactive didactic contingency',
bs: 'synergize scalable supply-chains',
},
},
{
id: 3,
name: 'Clementine Bauch',
username: 'Samantha',
email: '[email protected]',
address: {
street: 'Douglas Extension',
suite: 'Suite 847',
city: 'McKenziehaven',
zipcode: '59590-4157',
geo: {
lat: '-68.6102',
lng: '-47.0653',
},
},
phone: '1-463-123-4447',
website: 'ramiro.info',
company: {
name: 'Romaguera-Jacobson',
catchPhrase: 'Face to face bifurcated interface',
bs: 'e-enable strategic applications',
},
},
{
id: 4,
name: 'Patricia Lebsack',
username: 'Karianne',
email: '[email protected]',
address: {
street: 'Hoeger Mall',
suite: 'Apt. 692',
city: 'South Elvis',
zipcode: '53919-4257',
geo: {
lat: '29.4572',
lng: '-164.2990',
},
},
phone: '493-170-9623 x156',
website: 'kale.biz',
company: {
name: 'Robel-Corkery',
catchPhrase: 'Multi-tiered zero tolerance productivity',
bs: 'transition cutting-edge web services',
},
},
];

export const usersFailureFixture = {
error: 'Error message',
};
32 changes: 32 additions & 0 deletions src/modules/users/api/mocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { rest } from 'msw';

import { server } from '@/shared/api/mock-instance';
import { routes } from './api';

import { usersOkFixture, usersFailureFixture } from './fixtures';
import { JSONPLACEHOLDER_API_URL } from '@/shared/config';

const route = JSONPLACEHOLDER_API_URL + routes.users;

export const fetchUsersMockOk = () => {
server.use(
rest.get(route, (request, response, context) => {
return response(context.status(200), context.json(usersOkFixture));
})
);

return { usersOkFixture };
};

export const fetchUsersMockFailure = () => {
server.use(
rest.get(
'https://jsonplaceholder.typicode.com/users',
(request, response, context) => {
return response(context.status(500));
}
)
);

return { usersFailureFixture };
};
29 changes: 29 additions & 0 deletions src/modules/users/api/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export interface User {
id: number;
name: string;
username: string;
email: string;
address: Address;
phone: string;
website: string;
company: Company;
}

interface Address {
street: string;
suite: string;
city: string;
zipcode: string;
geo: Geo;
}

interface Geo {
lat: string;
lng: string;
}

interface Company {
name: string;
catchPhrase: string;
bs: string;
}
3 changes: 3 additions & 0 deletions src/modules/users/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { useUsers } from './lib/use-users';

export { Users } from './ui/users';
37 changes: 37 additions & 0 deletions src/modules/users/lib/use-users.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { act, renderHook } from '@testing-library/react';

import { fetchUsersMockFailure, fetchUsersMockOk } from '../api/mocks';
import { useUsers } from './use-users';
import { nextTick } from 'process';

describe('useUsers', () => {
it('should be empty users array on init', () => {
const { result } = renderHook(useUsers);

expect(result.current.users).toStrictEqual([]);
});

it('should set users on ok response (200)', async () => {
const { usersOkFixture } = fetchUsersMockOk();

const { result } = renderHook(useUsers);

await act(async () => {
console.log('I dont know why its working');
});

expect(result.current.users).toStrictEqual(usersOkFixture);
});

it('should set error on failure response (500)', async () => {
fetchUsersMockFailure();

const { result } = renderHook(useUsers);

await act(async () => {
console.log('I dont know why its working');
});

expect(result.current.error).toBe('Error fetching users');
});
});
17 changes: 17 additions & 0 deletions src/modules/users/lib/use-users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useEffect, useState } from 'react';

import { fetchUsers } from '../api/api';
import { User } from '../api/types';

export const useUsers = () => {
const [users, setUsers] = useState<User[]>([]);
const [error, setError] = useState('');

useEffect(() => {
fetchUsers()
.then(({ data }) => setUsers(data))
.catch(() => setError('Error fetching users'));
}, []);

return { users, error };
};
5 changes: 5 additions & 0 deletions src/modules/users/ui/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.title {
font-size: 24px;
line-height: 28px;
margin-bottom: 15px;
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { render, screen } from '@testing-library/react';

import { fetchUsersMockFailure, fetchUsersMockOk } from '../api/mocks';

import { Users } from './users';
import { server } from '@/shared/api/mocks';
import { rest } from 'msw';

describe('Users', () => {
it('should render correctly', async () => {
it('should render headline correctly', async () => {
render(<Users />);

const heading = await screen.findByRole('heading', { name: 'Users' });
Expand All @@ -13,22 +14,17 @@ describe('Users', () => {
});

it('should render list of users', async () => {
const { usersOkFixture } = fetchUsersMockOk();

render(<Users />);

const users = await screen.findAllByRole('listitem');

expect(users).toHaveLength(3);
expect(users).toHaveLength(usersOkFixture.length);
});

it('should handle the error', async () => {
server.use(
rest.get(
'https://jsonplaceholder.typicode.com/users',
(request, response, context) => {
return response(context.status(500));
}
)
);
fetchUsersMockFailure();

render(<Users />);

Expand Down
Loading

0 comments on commit 685b3d2

Please sign in to comment.