import { getClientWithToken } from '../apollo/client'; import * as GQL from '../types'; import { CustomersService } from './customers'; import { ERRORS, OrdersService } from './orders'; import { ServicesService } from './services'; import { SlotsService } from './slots'; import dayjs from 'dayjs'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; vi.mock('../apollo/client'); vi.mock('./customers'); vi.mock('./services'); vi.mock('./slots'); vi.mock('../config/env', () => { return { env: { BOT_TOKEN: 'test', LOGIN_GRAPHQL: 'test', PASSWORD_GRAPHQL: 'test', URL_GRAPHQL: 'test', }, }; }); const mockGetClientWithToken = vi.mocked(getClientWithToken); const mockCustomersService = vi.mocked(CustomersService); const mockServicesService = vi.mocked(ServicesService); const mockSlotsService = vi.mocked(SlotsService); describe('OrdersService', () => { /** * @type {OrdersService} */ let ordersService; const mockUser = { telegramId: 123_456_789 }; const mockCustomer = { active: true, documentId: 'customer-123', firstName: 'John', lastName: 'Doe', role: GQL.Enum_Customer_Role.Customer, telegramId: 123_456_789, }; const mockMaster = { active: true, documentId: 'master-123', firstName: 'Jane', lastName: 'Master', role: GQL.Enum_Customer_Role.Master, telegramId: 987_654_321, }; const now = dayjs().minute(0).second(0).millisecond(0); vi.setSystemTime(now.toDate()); const mockSlot = { datetime_end: now.add(6, 'hour').toISOString(), datetime_start: now.toISOString(), documentId: 'slot-123', master: mockMaster, orders: [], state: GQL.Enum_Slot_State.Open, }; const mockService = { active: true, documentId: 'service-123', duration: '01:00:00', // 1 час master: mockMaster, name: 'Test Service', }; const mockOrder = { client: mockCustomer, datetime_end: now.add(1, 'hour').toISOString(), datetime_start: now.toISOString(), documentId: 'order-123', services: [mockService], slot: mockSlot, state: GQL.Enum_Order_State.Created, }; const mockGetCustomerResult = { data: { customers: [mockCustomer], }, }; beforeEach(() => { ordersService = new OrdersService(mockUser); vi.clearAllMocks(); // Глобальный мок для _getUser vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockCustomer, }); // Глобальные моки для сервисов mockServicesService.mockImplementation(() => ({ getService: vi.fn().mockResolvedValue({ service: mockService, }), })); mockSlotsService.mockImplementation(() => ({ getSlot: vi.fn().mockResolvedValue({ slot: mockSlot, }), })); mockCustomersService.mockImplementation(() => ({ getCustomer: vi.fn().mockResolvedValue({ customer: mockCustomer, }), getMasters: vi.fn().mockResolvedValue({ masters: [mockMaster], }), })); }); afterEach(() => { vi.restoreAllMocks(); }); describe('createOrder', () => { const mockVariables = { input: { client: 'customer-123', datetime_start: now.toISOString(), services: ['service-123'], slot: 'slot-123', }, }; const mockMutationResult = { data: { createOrder: mockOrder, }, errors: undefined, }; it('should successfully create order for customer', async () => { const mockMutate = vi.fn().mockResolvedValue(mockMutationResult); const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve(mockGetCustomerResult); } if (query === GQL.GetOrdersDocument) { return Promise.resolve({ data: { orders: [] } }); // нет пересекающихся заказов } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: mockMutate, query: mockQuery, }); const result = ordersService.createOrder(mockVariables); await expect(result).resolves.toBe(mockMutationResult.data); }); it('should successfully create approved order for master', async () => { const masterCustomer = { ...mockCustomer, role: GQL.Enum_Customer_Role.Master, }; // Переопределяем мок для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: masterCustomer, }); const masterSlot = { ...mockSlot, master: masterCustomer, }; const mockMutate = vi.fn().mockResolvedValue(mockMutationResult); const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve({ data: { customers: [masterCustomer] }, }); } if (query === GQL.GetOrdersDocument) { return Promise.resolve({ data: { orders: [] } }); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: mockMutate, query: mockQuery, }); // Переопределяем моки для мастера mockSlotsService.mockImplementation(() => ({ getSlot: vi.fn().mockResolvedValue({ slot: masterSlot, }), })); mockCustomersService.mockImplementation(() => ({ getCustomer: vi.fn().mockResolvedValue({ customer: masterCustomer, }), getMasters: vi.fn().mockResolvedValue({ masters: [masterCustomer], }), })); const result = ordersService.createOrder({ ...mockVariables, input: { ...mockVariables.input, client: masterCustomer.documentId, }, }); await expect(result).resolves.toBe(mockMutationResult.data); }); it('should throw error when slot is missing', async () => { const variablesWithoutSlot = { input: { client: 'customer-123', datetime_start: now.toISOString(), services: ['service-123'], }, }; const result = ordersService.createOrder(variablesWithoutSlot); await expect(result).rejects.toThrow(ERRORS.MISSING_SLOT); }); it('should throw error when services are missing', async () => { const variablesWithoutServices = { input: { client: 'customer-123', datetime_start: now.toISOString(), slot: 'slot-123', }, }; const result = ordersService.createOrder(variablesWithoutServices); await expect(result).rejects.toThrow(ERRORS.MISSING_SERVICES); }); it('should throw error when datetime_start is missing', async () => { const variablesWithoutStart = { input: { client: 'customer-123', services: ['service-123'], slot: 'slot-123', }, }; const result = ordersService.createOrder(variablesWithoutStart); await expect(result).rejects.toThrow(ERRORS.MISSING_START_TIME); }); it('should throw error when client is missing', async () => { const variablesWithoutClient = { input: { datetime_start: now.toISOString(), services: ['service-123'], slot: 'slot-123', }, }; const result = ordersService.createOrder(variablesWithoutClient); await expect(result).rejects.toThrow(ERRORS.MISSING_CLIENT); }); it('should throw error when order time is in the past', async () => { const pastTime = now.subtract(1, 'hour'); const variablesWithPastTime = { input: { client: 'customer-123', datetime_end: pastTime.add(1, 'hour').toISOString(), datetime_start: pastTime.toISOString(), services: ['service-123'], slot: 'slot-123', }, }; const result = ordersService.createOrder(variablesWithPastTime); await expect(result).rejects.toThrow(ERRORS.NO_ORDER_IN_PAST); }); it('should throw error when slot is not found', async () => { const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve(mockGetCustomerResult); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); const mockGetSlot = vi.fn().mockResolvedValue({ slot: null, // слот не найден }); mockSlotsService.mockImplementation(() => ({ getSlot: mockGetSlot, })); const result = ordersService.createOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.MISSING_SLOT); }); it('should throw error when order is out of slot time', async () => { const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve(mockGetCustomerResult); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); const mockGetSlot = vi.fn().mockResolvedValue({ slot: mockSlot, }); mockSlotsService.mockImplementation(() => ({ getSlot: mockGetSlot, })); const mockGetCustomer = vi.fn().mockResolvedValue({ customer: mockCustomer, }); mockCustomersService.mockImplementation(() => ({ getCustomer: mockGetCustomer, getMasters: vi.fn().mockResolvedValue({ masters: [mockMaster], }), })); const variablesWithOutOfSlotTime = { input: { client: 'customer-123', datetime_end: now.add(8, 'hour').toISOString(), datetime_start: now.add(7, 'hour').toISOString(), // после окончания слота services: ['service-123'], slot: 'slot-123', }, }; const result = ordersService.createOrder(variablesWithOutOfSlotTime); await expect(result).rejects.toThrow(ERRORS.NO_ORDER_OUT_OF_SLOT); }); it('should throw error when slot is closed', async () => { const closedSlot = { ...mockSlot, state: GQL.Enum_Slot_State.Closed, }; const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve(mockGetCustomerResult); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); const mockGetSlot = vi.fn().mockResolvedValue({ slot: closedSlot, }); mockSlotsService.mockImplementation(() => ({ getSlot: mockGetSlot, })); const mockGetCustomer = vi.fn().mockResolvedValue({ customer: mockCustomer, }); mockCustomersService.mockImplementation(() => ({ getCustomer: mockGetCustomer, getMasters: vi.fn().mockResolvedValue({ masters: [mockMaster], }), })); const result = ordersService.createOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.SLOT_CLOSED); }); it('should throw error when client is not found', async () => { const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve(mockGetCustomerResult); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); const mockGetSlot = vi.fn().mockResolvedValue({ slot: mockSlot, }); mockSlotsService.mockImplementation(() => ({ getSlot: mockGetSlot, })); const mockGetCustomer = vi.fn().mockResolvedValue({ customer: null, // клиент не найден }); mockCustomersService.mockImplementation(() => ({ getCustomer: mockGetCustomer, getMasters: vi.fn().mockResolvedValue({ masters: [mockMaster], }), })); const result = ordersService.createOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.NOT_FOUND_CLIENT); }); it('should throw error when client is inactive', async () => { const inactiveCustomer = { ...mockCustomer, active: false, }; const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve(mockGetCustomerResult); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); const mockGetSlot = vi.fn().mockResolvedValue({ slot: mockSlot, }); mockSlotsService.mockImplementation(() => ({ getSlot: mockGetSlot, })); const mockGetCustomer = vi.fn().mockResolvedValue({ customer: inactiveCustomer, }); mockCustomersService.mockImplementation(() => ({ getCustomer: mockGetCustomer, getMasters: vi.fn().mockResolvedValue({ masters: [mockMaster], }), })); const result = ordersService.createOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.INACTIVE_CLIENT); }); it('should throw error when master is inactive', async () => { const inactiveMaster = { ...mockMaster, active: false, }; const slotWithInactiveMaster = { ...mockSlot, master: inactiveMaster, }; const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve(mockGetCustomerResult); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); const mockGetSlot = vi.fn().mockResolvedValue({ slot: slotWithInactiveMaster, }); mockSlotsService.mockImplementation(() => ({ getSlot: mockGetSlot, })); const mockGetCustomer = vi.fn().mockResolvedValue({ customer: mockCustomer, }); mockCustomersService.mockImplementation(() => ({ getCustomer: mockGetCustomer, getMasters: vi.fn().mockResolvedValue({ masters: [inactiveMaster], }), })); const result = ordersService.createOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.INACTIVE_MASTER); }); it('should throw error when customer tries to book themselves as master', async () => { const activeCustomerAsMaster = { ...mockCustomer, active: true, role: GQL.Enum_Customer_Role.Master, }; const slotWithCustomerAsMaster = { ...mockSlot, master: activeCustomerAsMaster, }; const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve(mockGetCustomerResult); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); const mockGetSlot = vi.fn().mockResolvedValue({ slot: slotWithCustomerAsMaster, }); mockSlotsService.mockImplementation(() => ({ getSlot: mockGetSlot, })); const mockGetCustomer = vi.fn().mockResolvedValue({ customer: mockCustomer, }); mockCustomersService.mockImplementation(() => ({ getCustomer: mockGetCustomer, getMasters: vi.fn().mockResolvedValue({ masters: [activeCustomerAsMaster], }), })); const result = ordersService.createOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.NO_MASTER_SELF_BOOK); }); it('should throw error when customer is not linked to master', async () => { const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve(mockGetCustomerResult); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); const mockGetSlot = vi.fn().mockResolvedValue({ slot: mockSlot, }); mockSlotsService.mockImplementation(() => ({ getSlot: mockGetSlot, })); const mockGetCustomer = vi.fn().mockResolvedValue({ customer: mockCustomer, }); mockCustomersService.mockImplementation(() => ({ getCustomer: mockGetCustomer, getMasters: vi.fn().mockResolvedValue({ masters: [], // клиент не связан с мастером }), })); const result = ordersService.createOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.INVALID_MASTER); }); it('should throw error when time overlaps with other orders', async () => { const overlappingOrder = { ...mockOrder, documentId: 'order-456', }; const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve(mockGetCustomerResult); } if (query === GQL.GetOrdersDocument) { return Promise.resolve({ data: { orders: [overlappingOrder] }, }); // есть пересекающиеся заказы } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); const mockGetSlot = vi.fn().mockResolvedValue({ slot: mockSlot, }); mockSlotsService.mockImplementation(() => ({ getSlot: mockGetSlot, })); const mockGetCustomer = vi.fn().mockResolvedValue({ customer: mockCustomer, }); mockCustomersService.mockImplementation(() => ({ getCustomer: mockGetCustomer, getMasters: vi.fn().mockResolvedValue({ masters: [mockMaster], }), })); const result = ordersService.createOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.OVERLAPPING_TIME); }); it('should throw error when service duration is invalid', async () => { const serviceWithoutDuration = { ...mockService, duration: null, }; const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve(mockGetCustomerResult); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); const mockGetSlot = vi.fn().mockResolvedValue({ slot: mockSlot, }); mockSlotsService.mockImplementation(() => ({ getSlot: mockGetSlot, })); const mockGetCustomer = vi.fn().mockResolvedValue({ customer: mockCustomer, }); mockCustomersService.mockImplementation(() => ({ getCustomer: mockGetCustomer, getMasters: vi.fn().mockResolvedValue({ masters: [mockMaster], }), })); const mockGetService = vi.fn().mockResolvedValue({ service: serviceWithoutDuration, }); mockServicesService.mockImplementation(() => ({ getService: mockGetService, })); const result = ordersService.createOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.INVALID_SERVICE_DURATION); }); it('should calculate datetime_end based on service duration', async () => { const mockMutate = vi.fn().mockResolvedValue(mockMutationResult); const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetCustomerDocument) { return Promise.resolve(mockGetCustomerResult); } if (query === GQL.GetOrdersDocument) { return Promise.resolve({ data: { orders: [] } }); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: mockMutate, query: mockQuery, }); await ordersService.createOrder(mockVariables); expect(mockMutate).toHaveBeenCalledWith({ mutation: GQL.CreateOrderDocument, variables: { ...mockVariables, input: { ...mockVariables.input, datetime_end: now.add(1, 'hour').toISOString(), // 1 час от начала state: GQL.Enum_Order_State.Created, }, }, }); }); }); describe('updateOrder', () => { const mockVariables = { data: { datetime_end: now.add(2, 'hour').toISOString(), datetime_start: now.add(1, 'hour').toISOString(), state: GQL.Enum_Order_State.Approved, }, documentId: 'order-123', }; const mockMutationResult = { data: { updateOrder: { ...mockOrder, ...mockVariables.data, }, }, errors: undefined, }; it('should successfully update order by master', async () => { const mockMutate = vi.fn().mockResolvedValue(mockMutationResult); const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetOrderDocument) { return Promise.resolve({ data: { order: { ...mockOrder, slot: { ...mockSlot, master: mockMaster }, }, }, }); } if (query === GQL.GetOrdersDocument) { return Promise.resolve({ data: { orders: [] } }); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: mockMutate, query: mockQuery, }); // Мокаем _getUser для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockMaster, }); const result = await ordersService.updateOrder(mockVariables); expect(result).toBe(mockMutationResult.data); expect(mockMutate).toHaveBeenCalledWith({ mutation: GQL.UpdateOrderDocument, variables: { ...mockVariables, data: { ...mockVariables.data, order_number: undefined, }, }, }); }); it('should successfully update order by client (cancelling)', async () => { const mockMutate = vi.fn().mockResolvedValue(mockMutationResult); const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetOrderDocument) { return Promise.resolve({ data: { order: { ...mockOrder, client: mockCustomer, slot: { ...mockSlot, master: mockMaster }, }, }, }); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: mockMutate, query: mockQuery, }); // Мокаем _getUser для клиента vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockCustomer, }); const clientVariables = { ...mockVariables, data: { state: GQL.Enum_Order_State.Cancelling, }, }; const result = await ordersService.updateOrder(clientVariables); expect(result).toBe(mockMutationResult.data); }); it('should throw error when order is not found', async () => { const mockQuery = vi.fn().mockResolvedValue({ data: { order: null }, }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); // Мокаем _getUser для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockMaster, }); const result = ordersService.updateOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.MISSING_ORDER); }); it('should throw error when user has no permission', async () => { const unauthorizedUser = { ...mockCustomer, documentId: 'unauthorized-user', }; const mockQuery = vi.fn().mockResolvedValue({ data: { order: { ...mockOrder, client: mockCustomer, slot: { ...mockSlot, master: mockMaster }, }, }, }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); // Мокаем _getUser для неавторизованного пользователя vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: unauthorizedUser, }); const result = ordersService.updateOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.NO_PERMISSION); }); it('should throw error when client tries to change more than one field', async () => { const mockQuery = vi.fn().mockResolvedValue({ data: { order: { ...mockOrder, client: mockCustomer, slot: { ...mockSlot, master: mockMaster }, }, }, }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); // Мокаем _getUser для клиента vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockCustomer, }); const clientVariables = { ...mockVariables, data: { datetime_start: now.add(1, 'hour').toISOString(), state: GQL.Enum_Order_State.Cancelling, }, }; const result = ordersService.updateOrder(clientVariables); await expect(result).rejects.toThrow(ERRORS.NO_PERMISSION); }); it('should throw error when client tries to change state to non-cancelling', async () => { const mockQuery = vi.fn().mockResolvedValue({ data: { order: { ...mockOrder, client: mockCustomer, slot: { ...mockSlot, master: mockMaster }, }, }, }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); // Мокаем _getUser для клиента vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockCustomer, }); const clientVariables = { ...mockVariables, data: { state: GQL.Enum_Order_State.Approved, }, }; const result = ordersService.updateOrder(clientVariables); await expect(result).rejects.toThrow(ERRORS.NO_PERMISSION); }); it('should throw error when trying to change client', async () => { const mockQuery = vi.fn().mockResolvedValue({ data: { order: { ...mockOrder, slot: { ...mockSlot, master: mockMaster }, }, }, }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); // Мокаем _getUser для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockMaster, }); const variablesWithClient = { ...mockVariables, data: { ...mockVariables.data, client: 'new-client-id', }, }; const result = ordersService.updateOrder(variablesWithClient); await expect(result).rejects.toThrow(ERRORS.NO_PERMISSION); }); it('should throw error when trying to change services', async () => { const mockQuery = vi.fn().mockResolvedValue({ data: { order: { ...mockOrder, slot: { ...mockSlot, master: mockMaster }, }, }, }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); // Мокаем _getUser для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockMaster, }); const variablesWithServices = { ...mockVariables, data: { ...mockVariables.data, services: ['new-service-id'], }, }; const result = ordersService.updateOrder(variablesWithServices); await expect(result).rejects.toThrow(ERRORS.NO_PERMISSION); }); it('should throw error when trying to change slot', async () => { const mockQuery = vi.fn().mockResolvedValue({ data: { order: { ...mockOrder, slot: { ...mockSlot, master: mockMaster }, }, }, }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); // Мокаем _getUser для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockMaster, }); const variablesWithSlot = { ...mockVariables, data: { ...mockVariables.data, slot: 'new-slot-id', }, }; const result = ordersService.updateOrder(variablesWithSlot); await expect(result).rejects.toThrow(ERRORS.NO_PERMISSION); }); it('should throw error when order slot is not found', async () => { const mockQuery = vi.fn().mockResolvedValue({ data: { order: { ...mockOrder, client: mockCustomer, slot: null, }, }, }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); // Мокаем _getUser для клиента заказа vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockCustomer, }); const variablesWithSingleField = { ...mockVariables, data: { state: GQL.Enum_Order_State.Cancelling, }, }; const result = ordersService.updateOrder(variablesWithSingleField); await expect(result).rejects.toThrow(ERRORS.NOT_FOUND_ORDER_SLOT); }); it('should throw error when trying to change completed order state', async () => { const completedOrder = { ...mockOrder, state: GQL.Enum_Order_State.Completed, }; const mockQuery = vi.fn().mockResolvedValue({ data: { order: completedOrder, }, }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); // Мокаем _getUser для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockMaster, }); const result = ordersService.updateOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.NO_CHANGE_STATE_COMPLETED); }); it('should throw error when time is invalid', async () => { const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetOrderDocument) { return Promise.resolve({ data: { order: { ...mockOrder, slot: { ...mockSlot, master: mockMaster }, }, }, }); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); // Мокаем _getUser для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockMaster, }); const variablesWithInvalidTime = { ...mockVariables, data: { datetime_end: now.add(1, 'hour').toISOString(), datetime_start: now.add(2, 'hour').toISOString(), // конец раньше начала }, }; const result = ordersService.updateOrder(variablesWithInvalidTime); await expect(result).rejects.toThrow(ERRORS.INVALID_TIME); }); it('should throw error when time overlaps with other orders', async () => { const overlappingOrder = { ...mockOrder, documentId: 'order-456', }; const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetOrderDocument) { return Promise.resolve({ data: { order: { ...mockOrder, slot: { ...mockSlot, master: mockMaster }, }, }, }); } if (query === GQL.GetOrdersDocument) { return Promise.resolve({ data: { orders: [overlappingOrder] }, }); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); // Мокаем _getUser для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockMaster, }); const result = ordersService.updateOrder(mockVariables); await expect(result).rejects.toThrow(ERRORS.OVERLAPPING_TIME); }); it('should successfully complete order and set order number', async () => { const mockMutate = vi.fn().mockResolvedValue(mockMutationResult); const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetOrderDocument) { return Promise.resolve({ data: { order: { ...mockOrder, client: mockCustomer, datetime_start: now.subtract(1, 'hour').toISOString(), // заказ в прошлом slot: { ...mockSlot, master: mockMaster }, }, }, }); } if (query === GQL.GetOrdersDocument) { return Promise.resolve({ data: { orders: [ { ...mockOrder, order_number: 5, }, ], }, }); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: mockMutate, query: mockQuery, }); // Мокаем _getUser для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockMaster, }); const completeVariables = { ...mockVariables, data: { state: GQL.Enum_Order_State.Completed, }, }; const result = await ordersService.updateOrder(completeVariables); expect(result).toBe(mockMutationResult.data); expect(mockMutate).toHaveBeenCalledWith({ mutation: GQL.UpdateOrderDocument, variables: { ...completeVariables, data: { ...completeVariables.data, order_number: 6, // 5 + 1 }, }, }); }); it('should successfully complete order and set order number to 1 when no previous completed orders', async () => { const mockMutate = vi.fn().mockResolvedValue(mockMutationResult); const mockQuery = vi.fn().mockImplementation(({ query }) => { if (query === GQL.GetOrderDocument) { return Promise.resolve({ data: { order: { ...mockOrder, client: mockCustomer, datetime_start: now.subtract(1, 'hour').toISOString(), // заказ в прошлом slot: { ...mockSlot, master: mockMaster }, }, }, }); } if (query === GQL.GetOrdersDocument) { return Promise.resolve({ data: { orders: [], // нет других завершенных заказов }, }); } return Promise.resolve({ data: {} }); }); mockGetClientWithToken.mockResolvedValue({ mutate: mockMutate, query: mockQuery, }); // Мокаем _getUser для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockMaster, }); const completeVariables = { ...mockVariables, data: { state: GQL.Enum_Order_State.Completed, }, }; const result = await ordersService.updateOrder(completeVariables); expect(result).toBe(mockMutationResult.data); expect(mockMutate).toHaveBeenCalledWith({ mutation: GQL.UpdateOrderDocument, variables: { ...completeVariables, data: { ...completeVariables.data, order_number: undefined, }, }, }); }); it('should throw error when trying to complete order before start time', async () => { const futureOrder = { ...mockOrder, datetime_start: now.add(1, 'hour').toISOString(), }; const mockQuery = vi.fn().mockResolvedValue({ data: { order: futureOrder, }, }); mockGetClientWithToken.mockResolvedValue({ mutate: vi.fn(), query: mockQuery, }); // Мокаем _getUser для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockMaster, }); const completeVariables = { ...mockVariables, data: { state: GQL.Enum_Order_State.Completed, }, }; const result = ordersService.updateOrder(completeVariables); await expect(result).rejects.toThrow(ERRORS.CANNOT_COMPLETE_BEFORE_START); }); it('should return early when no datetime changes are provided', async () => { const mockMutate = vi.fn().mockResolvedValue(mockMutationResult); const mockQuery = vi.fn().mockResolvedValue({ data: { order: { ...mockOrder, slot: { ...mockSlot, master: mockMaster }, }, }, }); mockGetClientWithToken.mockResolvedValue({ mutate: mockMutate, query: mockQuery, }); // Мокаем _getUser для мастера vi.spyOn(ordersService, '_getUser').mockResolvedValue({ customer: mockMaster, }); const variablesWithoutTime = { ...mockVariables, data: { state: GQL.Enum_Order_State.Approved, }, }; const result = await ordersService.updateOrder(variablesWithoutTime); expect(result).toBe(mockMutationResult.data); }); }); });