+
{id}
diff --git a/src/components/protected-route/ProtectedRoute.tsx b/src/components/protected-route/ProtectedRoute.tsx
index 6b3cfc5..6bbd7e3 100644
--- a/src/components/protected-route/ProtectedRoute.tsx
+++ b/src/components/protected-route/ProtectedRoute.tsx
@@ -1,12 +1,14 @@
import React, {FC} from 'react'
-import { Navigate, } from 'react-router-dom'
+import {Navigate, useLocation,} from 'react-router-dom'
import {useAppSelector} from "../../hooks/useAppSelector";
export const ProtectedRoute: FC<{children: any}> = ({ children }) => {
+ const location = useLocation();
+
const { isLoggedIn } = useAppSelector((state) => state.user);
if (!isLoggedIn) {
- return ;
+ return ;
}
return children;
diff --git a/src/constants.js b/src/constants.ts
similarity index 80%
rename from src/constants.js
rename to src/constants.ts
index bb70550..3939cce 100644
--- a/src/constants.js
+++ b/src/constants.ts
@@ -1,4 +1,4 @@
-export const API_BASE = 'https://norma.nomoreparties.space';
+export const API_BASE: string = 'https://norma.nomoreparties.space';
export const API = {
AUTH: {
@@ -16,13 +16,13 @@ export const API = {
},
};
-export const INGREDIENT = {
+export const INGREDIENT: { [key: string]: string; } = {
BUN: 'bun',
MAIN: 'main',
SAUCE: 'sauce',
};
-export const ROUTE = {
+export const ROUTE: { [key: string]: string; } = {
FORGOT_PASSWORD: '/forgot-password',
INDEX: '/',
INGREDIENT: '/ingredients/:id',
@@ -36,7 +36,7 @@ export const ROUTE = {
RESET_PASSWORD: '/reset-password',
};
-export const WEB_SOCKET_BASE = {
+export const WEB_SOCKET_BASE: { [key: string]: string; } = {
ORDERS: 'wss://norma.nomoreparties.space/orders/all',
USER_ORDERS: 'wss://norma.nomoreparties.space/orders',
-}
+};
diff --git a/src/services/actions/ingredients.js b/src/services/actions/ingredients.ts
similarity index 79%
rename from src/services/actions/ingredients.js
rename to src/services/actions/ingredients.ts
index 8d9940b..bbdbed9 100644
--- a/src/services/actions/ingredients.js
+++ b/src/services/actions/ingredients.ts
@@ -1,4 +1,4 @@
-import { createAsyncThunk } from '@reduxjs/toolkit';
+import {createAsyncThunk} from '@reduxjs/toolkit';
import { getIngredients as getIngredientsApi } from '../../utils/api';
export const getIngredients = createAsyncThunk(
diff --git a/src/services/actions/order.js b/src/services/actions/order.ts
similarity index 88%
rename from src/services/actions/order.js
rename to src/services/actions/order.ts
index 7728c8e..517d76b 100644
--- a/src/services/actions/order.js
+++ b/src/services/actions/order.ts
@@ -2,6 +2,6 @@ import { createAsyncThunk } from '@reduxjs/toolkit';
import { createOrder as createOrderApi } from '../../utils/api';
export const createOrder = createAsyncThunk(
- 'order/fetchOrderNum',
+ 'order/createOrder',
createOrderApi,
);
diff --git a/src/services/actions/orderDetail.ts b/src/services/actions/orderDetail.ts
index 60e0375..9609424 100644
--- a/src/services/actions/orderDetail.ts
+++ b/src/services/actions/orderDetail.ts
@@ -1,5 +1,5 @@
-import {createAsyncThunk} from "@reduxjs/toolkit";
-import {getOrderDetails as getOrderDetailsApi} from "../../utils/api";
+import {createAsyncThunk} from '@reduxjs/toolkit';
+import {getOrderDetails as getOrderDetailsApi} from '../../utils/api';
export const getOrderDetails = createAsyncThunk(
'order/getOrderDetail',
diff --git a/src/services/reducers/burgerConstructor.test.js b/src/services/reducers/burgerConstructor.test.js
new file mode 100644
index 0000000..363dcb0
--- /dev/null
+++ b/src/services/reducers/burgerConstructor.test.js
@@ -0,0 +1,198 @@
+import reducer, { addIngredient, deleteIngredient, moveIngredient, setBun } from './burgerConstructor'
+import { initialState } from './burgerConstructor';
+
+describe('burger constructor test', () => {
+ it('should set bun', () => {
+ const action = {
+ type: setBun,
+ payload: {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093c',
+ calories: 420,
+ carbohydrates: 53,
+ count: 0,
+ fat: 24,
+ image: 'https://code.s3.yandex.net/react/code/bun-02.png',
+ image_large: 'https://code.s3.yandex.net/react/code/bun-02-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/bun-02-mobile.png',
+ name: 'Краторная булка N-200i',
+ price: 1255,
+ proteins: 80,
+ type: 'bun',
+ },
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ bun: action.payload,
+ ingredients: []
+ });
+ });
+
+ it('should add ingredient', () => {
+ const initialState = {
+ bun: null,
+ ingredients: [],
+ };
+
+ const action = {
+ type: addIngredient,
+ payload: {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093e',
+ calories: 643,
+ carbohydrates: 85,
+ count: 0,
+ fat: 26,
+ image: 'https://code.s3.yandex.net/react/code/meat-03.png',
+ image_large: 'https://code.s3.yandex.net/react/code/meat-03-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/meat-03-mobile.png',
+ name: 'Филе Люминесцентного тетраодонтимформа',
+ price: 988,
+ proteins: 44,
+ type: 'main',
+ },
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ bun: null,
+ ingredients: [action.payload],
+ });
+ });
+
+ it('should delete ingredient', () => {
+ const initialState = {
+ bun: null,
+ ingredients: [{
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093e',
+ calories: 643,
+ carbohydrates: 85,
+ count: 0,
+ fat: 26,
+ image: 'https://code.s3.yandex.net/react/code/meat-03.png',
+ image_large: 'https://code.s3.yandex.net/react/code/meat-03-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/meat-03-mobile.png',
+ name: 'Филе Люминесцентного тетраодонтимформа',
+ price: 988,
+ proteins: 44,
+ type: 'main',
+ }],
+ };
+
+ const action = {
+ type: deleteIngredient,
+ payload: 0,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ bun: null,
+ ingredients: [],
+ });
+ });
+
+ it('should move ingredient', () => {
+ const initialState = {
+ bun: null,
+ ingredients: [
+ {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa0941',
+ calories: 4242,
+ carbohydrates: 242,
+ count: 0,
+ fat: 142,
+ image: 'https://code.s3.yandex.net/react/code/meat-01.png',
+ image_large: 'https://code.s3.yandex.net/react/code/meat-01-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/meat-01-mobile.png',
+ name: 'Биокотлета из марсианской Магнолии',
+ price: 424,
+ proteins: 420,
+ type: 'main',
+ },
+ {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093e',
+ calories: 643,
+ carbohydrates: 85,
+ count: 0,
+ fat: 26,
+ image: 'https://code.s3.yandex.net/react/code/meat-03.png',
+ image_large: 'https://code.s3.yandex.net/react/code/meat-03-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/meat-03-mobile.png',
+ name: 'Филе Люминесцентного тетраодонтимформа',
+ price: 988,
+ proteins: 44,
+ type: 'main',
+ },
+ ],
+ };
+
+ const action = {
+ type: moveIngredient,
+ payload: {
+ newIndex: 0,
+ oldIndex: 1,
+ },
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ bun: null,
+ ingredients: [
+ {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093e',
+ calories: 643,
+ carbohydrates: 85,
+ count: 0,
+ fat: 26,
+ image: 'https://code.s3.yandex.net/react/code/meat-03.png',
+ image_large: 'https://code.s3.yandex.net/react/code/meat-03-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/meat-03-mobile.png',
+ name: 'Филе Люминесцентного тетраодонтимформа',
+ price: 988,
+ proteins: 44,
+ type: 'main',
+ },
+ {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa0941',
+ calories: 4242,
+ carbohydrates: 242,
+ count: 0,
+ fat: 142,
+ image: 'https://code.s3.yandex.net/react/code/meat-01.png',
+ image_large: 'https://code.s3.yandex.net/react/code/meat-01-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/meat-01-mobile.png',
+ name: 'Биокотлета из марсианской Магнолии',
+ price: 424,
+ proteins: 420,
+ type: 'main',
+ },
+ ],
+ });
+ });
+});
diff --git a/src/services/reducers/burgerConstructor.ts b/src/services/reducers/burgerConstructor.ts
index 9b723e0..27f95c8 100644
--- a/src/services/reducers/burgerConstructor.ts
+++ b/src/services/reducers/burgerConstructor.ts
@@ -6,7 +6,7 @@ interface IBurgerConstructorState {
ingredients: IConstructorIngredient[];
}
-const initialState: IBurgerConstructorState = {
+export const initialState: IBurgerConstructorState = {
bun: null,
ingredients: [],
};
@@ -41,25 +41,14 @@ const reducers = {
state
.ingredients
.splice(
- action
- .payload
- .oldIndex,
- 1,
- )
- .shift();
-
- state
- .ingredients
- .splice(
- action
- .payload
- .newIndex,
+ action.payload.newIndex,
0,
+ state.ingredients.splice(
+ action.payload.oldIndex,
+ 1,
+ )[0],
);
},
- resetIngredients(state: IBurgerConstructorState) {
- state.ingredients = [];
- },
setBun(
state: IBurgerConstructorState,
action: PayloadAction,
diff --git a/src/services/reducers/ingredient.test.js b/src/services/reducers/ingredient.test.js
new file mode 100644
index 0000000..b97caa8
--- /dev/null
+++ b/src/services/reducers/ingredient.test.js
@@ -0,0 +1,91 @@
+import { closeModal, openModal } from './ingredient'
+import reducer from './ingredient';
+
+describe('ingredient test', () => {
+ it('should close modal', () => {
+ const initialState = {
+ item: {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093c',
+ calories: 420,
+ carbohydrates: 53,
+ count: 0,
+ fat: 24,
+ image: 'https://code.s3.yandex.net/react/code/bun-02.png',
+ image_large: 'https://code.s3.yandex.net/react/code/bun-02-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/bun-02-mobile.png',
+ name: 'Краторная булка N-200i',
+ price: 1255,
+ proteins: 80,
+ type: 'bun',
+ },
+ modalOpen: true,
+ };
+
+ const action = {
+ type: closeModal,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ item: null,
+ modalOpen: false,
+ });
+ });
+
+ it('should open modal', () => {
+ const initialState = {
+ item: null,
+ modalOpen: false,
+ };
+
+ const action = {
+ type: openModal,
+ payload: {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093c',
+ calories: 420,
+ carbohydrates: 53,
+ count: 0,
+ fat: 24,
+ image: 'https://code.s3.yandex.net/react/code/bun-02.png',
+ image_large: 'https://code.s3.yandex.net/react/code/bun-02-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/bun-02-mobile.png',
+ name: 'Краторная булка N-200i',
+ price: 1255,
+ proteins: 80,
+ type: 'bun',
+ },
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ item: {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093c',
+ calories: 420,
+ carbohydrates: 53,
+ count: 0,
+ fat: 24,
+ image: 'https://code.s3.yandex.net/react/code/bun-02.png',
+ image_large: 'https://code.s3.yandex.net/react/code/bun-02-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/bun-02-mobile.png',
+ name: 'Краторная булка N-200i',
+ price: 1255,
+ proteins: 80,
+ type: 'bun',
+ },
+ modalOpen: true,
+ });
+ });
+});
diff --git a/src/services/reducers/ingredient.ts b/src/services/reducers/ingredient.ts
index dbce38e..b216766 100644
--- a/src/services/reducers/ingredient.ts
+++ b/src/services/reducers/ingredient.ts
@@ -9,7 +9,7 @@ interface IIngredientState {
modalOpen: boolean,
}
-const initialState: IIngredientState = {
+export const initialState: IIngredientState = {
item: null,
modalOpen: false,
};
diff --git a/src/services/reducers/ingredients.test.js b/src/services/reducers/ingredients.test.js
new file mode 100644
index 0000000..1606eb8
--- /dev/null
+++ b/src/services/reducers/ingredients.test.js
@@ -0,0 +1,262 @@
+import { getIngredients } from '../actions/ingredients';
+import reducer, { decreaseCount, increaseCount, resetCount } from './ingredients'
+
+describe('ingredients test', () => {
+ let initialState = {
+ items: [],
+ request: false,
+ requestFailed: false,
+ requestSuccess: false,
+ };
+
+ it('should handle pending', () => {
+ const action = {
+ type: getIngredients
+ .pending
+ .type
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ request: true,
+ });
+ });
+
+ it('should handle fulfilled', () => {
+ const ingredients = [
+ {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093c',
+ calories: 420,
+ carbohydrates: 53,
+ fat: 24,
+ image: 'https://code.s3.yandex.net/react/code/bun-02.png',
+ image_large: 'https://code.s3.yandex.net/react/code/bun-02-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/bun-02-mobile.png',
+ name: 'Краторная булка N-200i',
+ price: 1255,
+ proteins: 80,
+ type: 'bun',
+ },
+ ];
+
+ const action = {
+ type: getIngredients
+ .fulfilled
+ .type,
+ payload: ingredients,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ request: false,
+ requestSuccess: true,
+ items: [
+ {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093c',
+ calories: 420,
+ carbohydrates: 53,
+ count: 0,
+ fat: 24,
+ image: 'https://code.s3.yandex.net/react/code/bun-02.png',
+ image_large: 'https://code.s3.yandex.net/react/code/bun-02-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/bun-02-mobile.png',
+ name: 'Краторная булка N-200i',
+ price: 1255,
+ proteins: 80,
+ type: 'bun',
+ }
+ ],
+ });
+ });
+
+ it('should handle rejected', () => {
+ const action = {
+ type: getIngredients
+ .rejected
+ .type,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ requestFailed: true,
+ });
+ });
+
+ it('should increase count', () => {
+ initialState = {
+ ...initialState,
+ items: [
+ {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093c',
+ calories: 420,
+ carbohydrates: 53,
+ count: 0,
+ fat: 24,
+ image: 'https://code.s3.yandex.net/react/code/bun-02.png',
+ image_large: 'https://code.s3.yandex.net/react/code/bun-02-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/bun-02-mobile.png',
+ name: 'Краторная булка N-200i',
+ price: 1255,
+ proteins: 80,
+ type: 'bun',
+ }
+ ],
+ };
+
+ const action = {
+ type: increaseCount,
+ payload: '643d69a5c3f7b9001cfa093c',
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ items: [
+ {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093c',
+ calories: 420,
+ carbohydrates: 53,
+ count: 1,
+ fat: 24,
+ image: 'https://code.s3.yandex.net/react/code/bun-02.png',
+ image_large: 'https://code.s3.yandex.net/react/code/bun-02-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/bun-02-mobile.png',
+ name: 'Краторная булка N-200i',
+ price: 1255,
+ proteins: 80,
+ type: 'bun',
+ },
+ ],
+ });
+ });
+
+ it('should decrease count', () => {
+ initialState = {
+ ...initialState,
+ items: [
+ {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093c',
+ calories: 420,
+ carbohydrates: 53,
+ count: 1,
+ fat: 24,
+ image: 'https://code.s3.yandex.net/react/code/bun-02.png',
+ image_large: 'https://code.s3.yandex.net/react/code/bun-02-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/bun-02-mobile.png',
+ name: 'Краторная булка N-200i',
+ price: 1255,
+ proteins: 80,
+ type: 'bun',
+ }
+ ],
+ };
+
+ const action = {
+ type: decreaseCount,
+ payload: '643d69a5c3f7b9001cfa093c',
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ items: [
+ {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093c',
+ calories: 420,
+ carbohydrates: 53,
+ count: 0,
+ fat: 24,
+ image: 'https://code.s3.yandex.net/react/code/bun-02.png',
+ image_large: 'https://code.s3.yandex.net/react/code/bun-02-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/bun-02-mobile.png',
+ name: 'Краторная булка N-200i',
+ price: 1255,
+ proteins: 80,
+ type: 'bun',
+ },
+ ],
+ });
+ });
+
+ it('should reset count', () => {
+ initialState = {
+ ...initialState,
+ items: [
+ {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093c',
+ calories: 420,
+ carbohydrates: 53,
+ count: 2,
+ fat: 24,
+ image: 'https://code.s3.yandex.net/react/code/bun-02.png',
+ image_large: 'https://code.s3.yandex.net/react/code/bun-02-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/bun-02-mobile.png',
+ name: 'Краторная булка N-200i',
+ price: 1255,
+ proteins: 80,
+ type: 'bun',
+ }
+ ],
+ };
+
+ const action = {
+ type: resetCount,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ items: [
+ {
+ __v: 0,
+ _id: '643d69a5c3f7b9001cfa093c',
+ calories: 420,
+ carbohydrates: 53,
+ count: 0,
+ fat: 24,
+ image: 'https://code.s3.yandex.net/react/code/bun-02.png',
+ image_large: 'https://code.s3.yandex.net/react/code/bun-02-large.png',
+ image_mobile: 'https://code.s3.yandex.net/react/code/bun-02-mobile.png',
+ name: 'Краторная булка N-200i',
+ price: 1255,
+ proteins: 80,
+ type: 'bun',
+ },
+ ],
+ });
+ });
+});
diff --git a/src/services/reducers/ingredients.ts b/src/services/reducers/ingredients.ts
index 590ad81..2d1ab9f 100644
--- a/src/services/reducers/ingredients.ts
+++ b/src/services/reducers/ingredients.ts
@@ -10,7 +10,7 @@ interface IIngredientsState {
requestSuccess: boolean,
}
-const initialState: IIngredientsState = {
+export const initialState: IIngredientsState = {
items: [],
request: false,
requestFailed: false,
@@ -65,7 +65,7 @@ const slice = createSlice({
state => {
state.request = true;
state.requestFailed = false;
- state.requestSuccess = true;
+ state.requestSuccess = false;
},
)
.addCase(
@@ -80,6 +80,7 @@ const slice = createSlice({
}));
state.request = false;
state.requestFailed = false;
+ state.requestSuccess = true;
},
)
.addCase(
@@ -87,6 +88,7 @@ const slice = createSlice({
state => {
state.request = false;
state.requestFailed = true;
+ state.requestSuccess = false;
},
)
},
diff --git a/src/services/reducers/order-detail.test.js b/src/services/reducers/order-detail.test.js
new file mode 100644
index 0000000..8865be9
--- /dev/null
+++ b/src/services/reducers/order-detail.test.js
@@ -0,0 +1,115 @@
+import reducer from './order-detail';
+import { getOrderDetails } from '../actions/orderDetail';
+import { initialState as baseInitialState } from './order-detail';
+
+describe('order detail test', () => {
+ let initialState = baseInitialState;
+
+ it('should handle pending', () => {
+ const action = {
+ type: getOrderDetails
+ .pending
+ .type
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ loading: true,
+ });
+ });
+
+ it('should handle fulfilled', () => {
+ const action = {
+ type: getOrderDetails
+ .fulfilled
+ .type,
+ payload: {
+ success: true,
+ name: "Люминесцентный флюоресцентный бургер",
+ order: {
+ ingredients: [
+ {
+ _id: "643d69a5c3f7b9001cfa093d",
+ name: "Флюоресцентная булка R2-D3",
+ type: "bun",
+ proteins: 44,
+ fat: 26,
+ carbohydrates: 85,
+ calories: 643,
+ price: 988,
+ image: "https://code.s3.yandex.net/react/code/bun-01.png",
+ image_mobile: "https://code.s3.yandex.net/react/code/bun-01-mobile.png",
+ image_large: "https://code.s3.yandex.net/react/code/bun-01-large.png",
+ __v: 0
+ },
+ {
+ '_id': "643d69a5c3f7b9001cfa093e",
+ 'name': "Филе Люминесцентного тетраодонтимформа",
+ 'type': "main",
+ 'proteins': 44,
+ 'fat': 26,
+ 'carbohydrates': 85,
+ 'calories': 643,
+ 'price': 988,
+ 'image': "https://code.s3.yandex.net/react/code/meat-03.png",
+ 'image_mobile': "https://code.s3.yandex.net/react/code/meat-03-mobile.png",
+ 'image_large': "https://code.s3.yandex.net/react/code/meat-03-large.png",
+ '__v': 0
+ }
+ ],
+ '_id': "6491845b8a4b62001c85f465",
+ 'owner': {
+ 'name': "Denis",
+ 'email': "denis.lityagin@gmail.com",
+ 'createdAt': "2023-06-04T12:31:20.801Z",
+ 'updatedAt': "2023-06-07T14:34:43.349Z"
+ },
+ 'status': "done",
+ 'name': "Люминесцентный флюоресцентный бургер",
+ 'createdAt': "2023-06-20T10:50:03.452Z",
+ 'updatedAt': "2023-06-20T10:50:03.605Z",
+ 'number': 9421,
+ 'price': 1976
+ },
+ },
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ loading: false,
+ order: action.payload,
+ });
+ });
+
+ it('should handle rejected', () => {
+ const action = {
+ type: getOrderDetails
+ .rejected
+ .type,
+ error: {
+ message: 'Oops... Something wrong...'
+ }
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ error: action.error.message,
+ loading: false,
+ });
+ });
+});
\ No newline at end of file
diff --git a/src/services/reducers/order-detail.ts b/src/services/reducers/order-detail.ts
index 5e27f6f..8ec7315 100644
--- a/src/services/reducers/order-detail.ts
+++ b/src/services/reducers/order-detail.ts
@@ -8,7 +8,7 @@ interface IOrderDetailDataState {
error: string | null | undefined,
}
-const initialState: IOrderDetailDataState = {
+export const initialState: IOrderDetailDataState = {
order: null,
loading: false,
error: null,
diff --git a/src/services/reducers/order.test.js b/src/services/reducers/order.test.js
new file mode 100644
index 0000000..e14bab7
--- /dev/null
+++ b/src/services/reducers/order.test.js
@@ -0,0 +1,103 @@
+import { createOrder } from '../actions/order';
+import reducer from './order';
+import { openModal } from './order'
+import { closeModal } from './order'
+import { initialState as baseInitialState } from './order';
+
+describe('order test', () => {
+ let initialState = baseInitialState;
+
+ it('should handle pending', () => {
+ const action = {
+ type: createOrder
+ .pending
+ .type
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ request: true,
+ });
+ });
+
+ it('should handle fulfilled', () => {
+ const action = {
+ type: createOrder
+ .fulfilled
+ .type,
+ payload: {
+ order: {
+ number: 123,
+ }
+ },
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ request: false,
+ requestSuccess: true,
+ number: action.payload.order.number,
+ modalOpen: true,
+ });
+ });
+
+ it('should handle rejected', () => {
+ const action = {
+ type: createOrder
+ .rejected
+ .type,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ requestFailed: true,
+ });
+ });
+
+ it('should open modal', () => {
+ const action = {
+ type: openModal,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ modalOpen: true,
+ });
+ });
+
+ it('should close modal', () => {
+ const action = {
+ type: closeModal,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ modalOpen: false,
+ });
+ });
+});
\ No newline at end of file
diff --git a/src/services/reducers/order.ts b/src/services/reducers/order.ts
index 8ea2871..bb13448 100644
--- a/src/services/reducers/order.ts
+++ b/src/services/reducers/order.ts
@@ -10,7 +10,7 @@ interface IOrderState {
requestSuccess: boolean;
}
-const initialState: IOrderState = {
+export const initialState: IOrderState = {
modalOpen: false,
number: null,
request: false,
diff --git a/src/services/reducers/orders.test.js b/src/services/reducers/orders.test.js
new file mode 100644
index 0000000..0fff886
--- /dev/null
+++ b/src/services/reducers/orders.test.js
@@ -0,0 +1,124 @@
+import { createReducer } from '@reduxjs/toolkit';
+import {WebSocketStatus} from '../../enum/web-socket-status';
+import {TWebSocketOrdersResponse} from '../../types/TWebSocketOrdersResponse';
+import {
+ ordersWebSocketClose,
+ ordersWebSocketConnecting,
+ ordersWebSocketError,
+ ordersWebSocketMessage,
+ ordersWebSocketOpen,
+} from '../actions/orders';
+import reducer from './orders';
+
+describe('orders test', () => {
+ const initialState = {
+ connectingError: '',
+ orders: null,
+ status: WebSocketStatus.OFFLINE,
+ };
+
+ it('should handle web socket close', () => {
+ const action = {
+ type: ordersWebSocketClose,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ status: WebSocketStatus.OFFLINE
+ });
+ });
+
+ it('should handle web socket connecting', () => {
+ const action = {
+ type: ordersWebSocketConnecting,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ status: WebSocketStatus.CONNECTING
+ });
+ });
+
+ it('should handle web socket error', () => {
+ const action = {
+ type: ordersWebSocketError,
+ payload: 'Oops... Something wrong...'
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ connectingError: action.payload
+ });
+ });
+
+ it('should handle web socket message', () => {
+ const action = {
+ type: ordersWebSocketMessage,
+ payload: {
+ orders: [
+ {
+ _id: '64918ba18a4b62001c85f47b',
+ ingredients: [
+ '643d69a5c3f7b9001cfa093c',
+ '643d69a5c3f7b9001cfa0945',
+ '643d69a5c3f7b9001cfa093f',
+ '643d69a5c3f7b9001cfa0943',
+ '643d69a5c3f7b9001cfa093c',
+ ],
+ status: 'done',
+ name: 'Антарианский бессмертный space краторный бургер',
+ createdAt: '2023-06-20T11:21:05.626Z',
+ updatedAt: '2023-06-20T11:21:05.721Z',
+ number: 9423
+ }
+ ],
+ success: true,
+ total: 777,
+ totalToday: 77
+ }
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ orders: action.payload
+ });
+ });
+
+ it('should handle web socket open', () => {
+
+ const action = {
+ type: ordersWebSocketOpen
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ status: WebSocketStatus.ONLINE
+ });
+ });
+});
+
diff --git a/src/services/reducers/orders.ts b/src/services/reducers/orders.ts
index 70103d6..f7c0a0f 100644
--- a/src/services/reducers/orders.ts
+++ b/src/services/reducers/orders.ts
@@ -15,7 +15,7 @@ interface IOrdersState {
status: WebSocketStatus;
}
-const initialState: IOrdersState = {
+export const initialState: IOrdersState = {
connectingError: '',
orders: null,
status: WebSocketStatus.OFFLINE,
diff --git a/src/services/reducers/user.test.js b/src/services/reducers/user.test.js
new file mode 100644
index 0000000..f10125e
--- /dev/null
+++ b/src/services/reducers/user.test.js
@@ -0,0 +1,392 @@
+import reducer from './user';
+import { getUser, loginUser, logoutUser, resetPasswordRequest, resetPasswordReset, updateUser } from '../actions/user'
+import { initialState } from './user';
+
+describe('user test', () => {
+ // getUser
+
+ it('should handle get user pending', () => {
+ const action = {
+ type: getUser
+ .pending
+ .type
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ request: true,
+ });
+ });
+
+ it('should handle get user fulfilled', () => {
+ const action = {
+ type: getUser
+ .fulfilled
+ .type,
+ payload: {
+ user: {
+ name: 'test',
+ email: 'test',
+ },
+ },
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ request: false,
+ requestSuccess: true,
+ isLoggedIn: true,
+ user: {
+ name: action.payload.user.name,
+ email: action.payload.user.email,
+ password: '',
+ }
+ });
+ });
+
+ it('should handle get user rejected', () => {
+ const action = {
+ type: getUser
+ .rejected
+ .type,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ requestFailed: true,
+ });
+ });
+
+ // updateUser
+
+ it('should handle update user pending', () => {
+ const action = {
+ type: updateUser
+ .pending
+ .type
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ updateRequest: true,
+ });
+ });
+
+ it('should handle update user fulfilled', () => {
+ const action = {
+ type: updateUser
+ .fulfilled
+ .type,
+ payload: {
+ user: {
+ name: 'test',
+ email: 'test',
+ },
+ },
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ updateRequest: false,
+ updateRequestSuccess: true,
+ user: {
+ name: action.payload.user.name,
+ email: action.payload.user.email,
+ password: '',
+ }
+ });
+ });
+
+ it('should handle update user rejected', () => {
+ const action = {
+ type: updateUser
+ .rejected
+ .type,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ updateRequestFailed: true,
+ });
+ });
+
+ // resetPasswordRequest
+
+ it('should handle reset password request pending', () => {
+ const action = {
+ type: resetPasswordRequest
+ .pending
+ .type
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ resetPasswordRequest: true,
+ });
+ });
+
+ it('should handle reset password request fulfilled', () => {
+ const action = {
+ type: resetPasswordRequest
+ .fulfilled
+ .type,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ resetPasswordRequest: false,
+ resetPasswordRequestSuccess: true,
+ });
+ });
+
+ it('should handle reset password request rejected', () => {
+ const action = {
+ type: resetPasswordRequest
+ .rejected
+ .type,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ resetPasswordRequest: false,
+ resetPasswordRequestFailed: true,
+ });
+ });
+
+ // resetPasswordReset
+
+ it('should handle reset password reset pending', () => {
+ const action = {
+ type: resetPasswordReset
+ .pending
+ .type
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ resetPasswordResetRequest: true,
+ });
+ });
+
+ it('should handle reset password reset fulfilled', () => {
+ const action = {
+ type: resetPasswordReset
+ .fulfilled
+ .type,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ resetPasswordResetRequest: false,
+ resetPasswordResetRequestSuccess: true,
+ });
+ });
+
+ it('should handle reset password reset rejected', () => {
+ const action = {
+ type: resetPasswordReset
+ .rejected
+ .type,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ resetPasswordResetRequest: false,
+ resetPasswordResetRequestFailed: true,
+ });
+ });
+
+ // logoutUser
+
+ it('should handle logout user pending', () => {
+ const action = {
+ type: logoutUser
+ .pending
+ .type
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ logoutRequest: true,
+ });
+ });
+
+ it('should handle logout user fulfilled', () => {
+ const action = {
+ type: logoutUser
+ .fulfilled
+ .type,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ logoutRequest: false,
+ logoutRequestSuccess: true,
+ isLoggedIn: false,
+ user: {
+ name: '',
+ email: '',
+ password: '',
+ },
+ });
+ });
+
+ it('should handle logout user rejected', () => {
+ const action = {
+ type: logoutUser
+ .rejected
+ .type,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ logoutRequest: false,
+ logoutRequestFailed: true,
+ });
+ });
+
+ // loginUser
+
+ it('should handle login user pending', () => {
+ const action = {
+ type: loginUser
+ .pending
+ .type
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ loginRequest: true,
+ });
+ });
+
+ it('should handle login user fulfilled', () => {
+ const action = {
+ type: loginUser
+ .fulfilled
+ .type,
+ payload: {
+ user: {
+ name: 'test',
+ email: 'test',
+ },
+ },
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ loginRequest: false,
+ loginRequestSuccess: true,
+ isLoggedIn: true,
+ user: {
+ name: action.payload.user.name,
+ email: action.payload.user.email,
+ password: '',
+ },
+ });
+ });
+
+ it('should handle login user rejected', () => {
+ const action = {
+ type: loginUser
+ .rejected
+ .type,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ loginRequest: false,
+ loginRequestFailed: true,
+ });
+ });
+});
diff --git a/src/services/reducers/user.ts b/src/services/reducers/user.ts
index 1e090f3..a9c9ebb 100644
--- a/src/services/reducers/user.ts
+++ b/src/services/reducers/user.ts
@@ -31,7 +31,7 @@ interface IUserState {
user: TProfileUser | null;
}
-const initialState: IUserState = {
+export const initialState: IUserState = {
isLoggedIn: false,
loginRequest: false,
loginRequestFailed: false,
@@ -106,7 +106,7 @@ const user = createSlice({
state => {
state.updateRequest = true;
state.updateRequestFailed = false;
- state.updateRequestSuccess = true;
+ state.updateRequestSuccess = false;
},
)
.addCase(
diff --git a/src/services/reducers/userOrders.test.js b/src/services/reducers/userOrders.test.js
new file mode 100644
index 0000000..7a21663
--- /dev/null
+++ b/src/services/reducers/userOrders.test.js
@@ -0,0 +1,117 @@
+import {WebSocketStatus} from '../../enum/web-socket-status';
+import {
+ userOrdersWebSocketClose,
+ userOrdersWebSocketConnecting,
+ userOrdersWebSocketError,
+ userOrdersWebSocketMessage,
+ userOrdersWebSocketOpen,
+} from '../actions/userOrders';
+import reducer from './userOrders';
+import { initialState } from './userOrders';
+
+describe('user orders test', () => {
+ it('should handle web socket close', () => {
+ const action = {
+ type: userOrdersWebSocketClose,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ status: WebSocketStatus.OFFLINE
+ });
+ });
+
+ it('should handle web socket connecting', () => {
+ const action = {
+ type: userOrdersWebSocketConnecting,
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ status: WebSocketStatus.CONNECTING
+ });
+ });
+
+ it('should handle web socket error', () => {
+ const action = {
+ type: userOrdersWebSocketError,
+ payload: 'Oops... Something wrong...'
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ connectingError: action.payload
+ });
+ });
+
+ it('should handle web socket message', () => {
+ const action = {
+ type: userOrdersWebSocketMessage,
+ payload: {
+ orders: [
+ {
+ _id: '64918ba18a4b62001c85f47b',
+ ingredients: [
+ '643d69a5c3f7b9001cfa093c',
+ '643d69a5c3f7b9001cfa0945',
+ '643d69a5c3f7b9001cfa093f',
+ '643d69a5c3f7b9001cfa0943',
+ '643d69a5c3f7b9001cfa093c',
+ ],
+ status: 'done',
+ name: 'Антарианский бессмертный space краторный бургер',
+ createdAt: '2023-06-20T11:21:05.626Z',
+ updatedAt: '2023-06-20T11:21:05.721Z',
+ number: 9423
+ }
+ ],
+ success: true,
+ total: 777,
+ totalToday: 77
+ }
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ orders: action.payload
+ });
+ });
+
+ it('should handle web socket open', () => {
+
+ const action = {
+ type: userOrdersWebSocketOpen
+ };
+
+ const result = reducer(
+ initialState,
+ action,
+ );
+
+ expect(result).toEqual({
+ ...initialState,
+ status: WebSocketStatus.ONLINE
+ });
+ });
+});
+
diff --git a/src/services/reducers/userOrders.ts b/src/services/reducers/userOrders.ts
index 3640674..f87370c 100644
--- a/src/services/reducers/userOrders.ts
+++ b/src/services/reducers/userOrders.ts
@@ -15,7 +15,7 @@ interface IUserOrdersState {
status: WebSocketStatus;
}
-const initialState: IUserOrdersState = {
+export const initialState: IUserOrdersState = {
connectingError: '',
orders: null,
status: WebSocketStatus.OFFLINE,