vchikalkin 9118a2d9ab refactor(orders): streamline order creation logic and enhance test setup
- Removed redundant variable assignments in the createOrder method for cleaner code.
- Updated test setup in orders.test.js to use global mocks for user and service retrieval, improving test clarity and maintainability.
- Added checks for required fields in order creation to ensure data integrity.
2025-08-11 16:05:55 +03:00

1408 lines
38 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
});
});
});