Skip to content

Commit

Permalink
feat: add thunk tests \ function for testing thunks
Browse files Browse the repository at this point in the history
  • Loading branch information
TomatoVan committed Nov 22, 2023
1 parent b6bfc8b commit ad90a05
Show file tree
Hide file tree
Showing 13 changed files with 193 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ node_modules
/yarn.lock
.package-lock.json
/package-lock.json
/.package-lock.json
/storybook-static/project.json
/storybook-static/favicon.ico

Expand Down
1 change: 0 additions & 1 deletion config/jest/setupTests.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
// Такой файл вы могли наблюдать при create-react-app
import '@testing-library/jest-dom';
import 'regenerator-runtime/runtime';
14 changes: 7 additions & 7 deletions json-server/db.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
{
"posts": [
{
"id": 1,
"id": "1",
"title": "json-server",
"userId": 1
"userId": "1"
},
{
"id": 2,
"id": "2",
"title": "json-server",
"userId": 2
"userId": "2"
}
],
"comments": [
{
"id": 1,
"id": "1",
"body": "some comment",
"postId": 1
"postId": "1"
}
],
"users": [
{
"id": 1,
"id": "1",
"username": "admin",
"password": "123"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ describe('getCounter', () => {
};
expect(getCounter(state as StateSchema)).toEqual({ value: 10 });
});

test('should work with empty state', () => {
const state:DeepPartial<StateSchema> = {};
expect(getCounter(state as StateSchema)).toEqual(undefined);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { DeepPartial } from '@reduxjs/toolkit';
import { StateSchema } from 'app/providers/StoreProvider';
import { getLoginError } from './getLoginError';

describe('getLoginError.test', () => {
test('should return error', () => {
const state:DeepPartial<StateSchema> = {
loginForm: { error: 'error' },
};
expect(getLoginError(state as StateSchema)).toEqual('error');
});
test('should work with empty state', () => {
const state:DeepPartial<StateSchema> = {};
expect(getLoginError(state as StateSchema)).toEqual(undefined);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { DeepPartial } from '@reduxjs/toolkit';
import { StateSchema } from 'app/providers/StoreProvider';
import { getLoginIsLoading } from './getLoginIsLoading';

describe('getLoginLoading.test', () => {
test('should return loading', () => {
const state: DeepPartial<StateSchema> = {
loginForm: { isLoading: true },
};
expect(getLoginIsLoading(state as StateSchema)).toEqual(true);
});
test('should work with empty state', () => {
const state: DeepPartial<StateSchema> = {};
expect(getLoginIsLoading(state as StateSchema)).toEqual(false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { DeepPartial } from '@reduxjs/toolkit';
import { StateSchema } from 'app/providers/StoreProvider';
import { getLoginPassword } from './getLoginPassword';

describe('getLoginPassword.test', () => {
test('should return loading', () => {
const state: DeepPartial<StateSchema> = {
loginForm: { password: '123' },
};
expect(getLoginPassword(state as StateSchema)).toEqual('123');
});
test('should work with empty state', () => {
const state: DeepPartial<StateSchema> = {};
expect(getLoginPassword(state as StateSchema)).toEqual('');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { DeepPartial } from '@reduxjs/toolkit';
import { StateSchema } from 'app/providers/StoreProvider';
import { getLoginUsername } from './getLoginUsername';

describe('getLoginUsername.test', () => {
test('should return loading', () => {
const state: DeepPartial<StateSchema> = {
loginForm: { username: 'name' },
};
expect(getLoginUsername(state as StateSchema)).toEqual('name');
});
test('should work with empty state', () => {
const state: DeepPartial<StateSchema> = {};
expect(getLoginUsername(state as StateSchema)).toEqual('');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import axios from 'axios';
import { userActions } from 'entities/User';
import { TestAsyncThunk } from 'shared/lib/tests/TestAsyncThunk/TestAsyncThunk';
import { loginByUsername } from './loginByUsername';

jest.mock('axios');

const mockedAxios = jest.mocked(axios, true);

describe('loginByUsername.test', () => {
// let dispatch: Dispatch;
// let getState: () => StateSchema;
//
// beforeEach(() => {
// dispatch = jest.fn();
// getState = jest.fn();
// });
// test('loginByUsername async thunk test', async () => {
// const userValue = { username: '123', id: '1' };
// mockedAxios.post.mockReturnValue(Promise.resolve({ data: userValue }));
// const action = loginByUsername({ username: 'name', password: '123' });
// const result = await action(dispatch, getState, undefined);
//
// expect(dispatch).toHaveBeenCalledWith(userActions.setAuthData(userValue));
// expect(dispatch).toHaveBeenCalledTimes(3);
// expect(mockedAxios.post).toHaveBeenCalled();
// expect(result.meta.requestStatus).toBe('fulfilled');
// expect(result.payload).toEqual(userValue);
// });
//
// test('loginByUsername async error thunk test', async () => {
// mockedAxios.post.mockReturnValue(Promise.resolve({ status: 403 }));
// const action = loginByUsername({ username: 'name', password: '123' });
// const result = await action(dispatch, getState, undefined);
//
// expect(dispatch).toHaveBeenCalledTimes(2);
// expect(mockedAxios.post).toHaveBeenCalled();
// expect(result.meta.requestStatus).toBe('rejected');
// expect(result.payload).toBe('error');
// });

test('loginByUsername async thunk test', async () => {
const userValue = { username: '123', id: '1' };
mockedAxios.post.mockReturnValue(Promise.resolve({ data: userValue }));

const thunk = new TestAsyncThunk(loginByUsername);
const result = await thunk.callThunk({ username: '123', password: '123' });

expect(thunk.dispatch).toHaveBeenCalledWith(userActions.setAuthData(userValue));
expect(thunk.dispatch).toHaveBeenCalledTimes(3);
expect(mockedAxios.post).toHaveBeenCalled();
expect(result.meta.requestStatus).toBe('fulfilled');
expect(result.payload).toEqual(userValue);
});

test('loginByUsername async error thunk test', async () => {
mockedAxios.post.mockReturnValue(Promise.resolve({ status: 403 }));

const thunk = new TestAsyncThunk(loginByUsername);
const result = await thunk.callThunk({ username: '123', password: '123' });

expect(thunk.dispatch).toHaveBeenCalledTimes(2);
expect(mockedAxios.post).toHaveBeenCalled();
expect(result.meta.requestStatus).toBe('rejected');
expect(result.payload).toBe('error');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ interface LoginByUsernameProps {
password: string
}

enum LoginErrors {
INCORRECT_DATA = '',
SERVER_ERROR = ''
}

export const loginByUsername = createAsyncThunk<
User,
LoginByUsernameProps,
Expand All @@ -33,6 +28,6 @@ export const loginByUsername = createAsyncThunk<
return response.data;
} catch (error) {
console.log(error);
return thunkAPI.rejectWithValue('login_error');
return thunkAPI.rejectWithValue('error');
}
});
21 changes: 21 additions & 0 deletions src/features/AuthByUsername/model/slice/loginSlice.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { DeepPartial } from '@reduxjs/toolkit';
import { LoginSchema } from '../types/loginSchema';
import { loginActions, loginReducer } from './loginSlice';

describe('loginSlice.test', () => {
test('test set username', () => {
const state: DeepPartial<LoginSchema> = { username: '123' };
expect(loginReducer(
state as LoginSchema,
loginActions.setUsername('123123'),
)).toEqual({ username: '123123' });
});

test('test set password', () => {
const state: DeepPartial<LoginSchema> = { password: '123' };
expect(loginReducer(
state as LoginSchema,
loginActions.setPassword('123123'),
)).toEqual({ password: '123123' });
});
});
26 changes: 26 additions & 0 deletions src/shared/lib/tests/TestAsyncThunk/TestAsyncThunk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { StateSchema } from 'app/providers/StoreProvider';
import { AsyncThunkAction } from '@reduxjs/toolkit';

type ActionCreatorType<Return, Arg, RejectedValue>
= (arg: Arg) => AsyncThunkAction<Return, Arg, { rejectValue: RejectedValue }>;

export class TestAsyncThunk<Return, Arg, RejectedValue> {
dispatch: jest.MockedFn<any>;

getState: () => StateSchema;

actionCreator: ActionCreatorType<Return, Arg, RejectedValue>;

constructor(actionCreator: ActionCreatorType<Return, Arg, RejectedValue>) {
this.actionCreator = actionCreator;
this.dispatch = jest.fn();
this.getState = jest.fn();
}

async callThunk(arg: Arg) {
const action = this.actionCreator(arg);
const result = await action(this.dispatch, this.getState, undefined);

return result;
}
}
2 changes: 1 addition & 1 deletion src/shared/ui/Button/Button.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ describe('Button', () => {
test('Test clear theme', () => {
render(<Button theme={ButtonTheme.CLEAR}>TEST</Button>);
expect(screen.getByText('TEST')).toHaveClass('clear');
screen.debug();
// screen.debug();
});
});

0 comments on commit ad90a05

Please sign in to comment.