|
|
@@ -16,23 +16,35 @@
|
|
|
|
|
|
import { renderHook, act, waitFor } from '@testing-library/react';
|
|
|
import useSaveData from './useSaveData';
|
|
|
-import { post } from '../../../api/utils';
|
|
|
-
|
|
|
-jest.mock('../../../api/utils', () => ({
|
|
|
- post: jest.fn()
|
|
|
-}));
|
|
|
+import { HttpMethod, sendApiRequest } from '../../../api/utils';
|
|
|
+
|
|
|
+jest.mock('../../../api/utils', () => {
|
|
|
+ const original = jest.requireActual('../../../api/utils');
|
|
|
+ return {
|
|
|
+ ...original,
|
|
|
+ post: jest.fn(),
|
|
|
+ put: jest.fn(),
|
|
|
+ patch: jest.fn(),
|
|
|
+ sendApiRequest: jest.fn()
|
|
|
+ };
|
|
|
+});
|
|
|
|
|
|
-const mockPost = post as jest.MockedFunction<typeof post>;
|
|
|
+const mockSendApiRequest = sendApiRequest as jest.MockedFunction<typeof sendApiRequest>;
|
|
|
const mockUrlPrefix = 'https://api.example.com';
|
|
|
const mockEndpoint = '/save-endpoint';
|
|
|
const mockUrl = `${mockUrlPrefix}${mockEndpoint}`;
|
|
|
const mockData = { id: 1, product: 'Hue' };
|
|
|
const mockBody = { id: 1 };
|
|
|
+const mockRequestOptions = {
|
|
|
+ ignoreSuccessErrors: true,
|
|
|
+ qsEncodeData: false,
|
|
|
+ silenceErrors: true
|
|
|
+};
|
|
|
|
|
|
describe('useSaveData', () => {
|
|
|
beforeEach(() => {
|
|
|
jest.clearAllMocks();
|
|
|
- mockPost.mockResolvedValue(mockData);
|
|
|
+ mockSendApiRequest.mockResolvedValue(mockData);
|
|
|
});
|
|
|
|
|
|
it('should save data successfully and update state', async () => {
|
|
|
@@ -49,8 +61,13 @@ describe('useSaveData', () => {
|
|
|
expect(result.current.loading).toBe(true);
|
|
|
|
|
|
await waitFor(() => {
|
|
|
- expect(mockPost).toHaveBeenCalledTimes(1);
|
|
|
- expect(mockPost).toHaveBeenCalledWith(mockUrl, mockBody, expect.any(Object));
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledTimes(1);
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.POST,
|
|
|
+ mockUrl,
|
|
|
+ mockBody,
|
|
|
+ mockRequestOptions
|
|
|
+ );
|
|
|
expect(result.current.data).toEqual(mockData);
|
|
|
expect(result.current.error).toBeUndefined();
|
|
|
expect(result.current.loading).toBe(false);
|
|
|
@@ -59,7 +76,7 @@ describe('useSaveData', () => {
|
|
|
|
|
|
it('should handle errors and update error state', async () => {
|
|
|
const mockError = new Error('Save error');
|
|
|
- mockPost.mockRejectedValue(mockError);
|
|
|
+ mockSendApiRequest.mockRejectedValue(mockError);
|
|
|
|
|
|
const { result } = renderHook(() => useSaveData(mockUrl));
|
|
|
|
|
|
@@ -74,7 +91,12 @@ describe('useSaveData', () => {
|
|
|
expect(result.current.loading).toBe(true);
|
|
|
|
|
|
await waitFor(() => {
|
|
|
- expect(mockPost).toHaveBeenCalledWith(mockUrl, mockBody, expect.any(Object));
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.POST,
|
|
|
+ mockUrl,
|
|
|
+ mockBody,
|
|
|
+ mockRequestOptions
|
|
|
+ );
|
|
|
expect(result.current.data).toBeUndefined();
|
|
|
expect(result.current.error).toEqual(mockError);
|
|
|
expect(result.current.loading).toBe(false);
|
|
|
@@ -91,7 +113,7 @@ describe('useSaveData', () => {
|
|
|
expect(result.current.data).toBeUndefined();
|
|
|
expect(result.current.error).toBeUndefined();
|
|
|
expect(result.current.loading).toBe(false);
|
|
|
- expect(mockPost).not.toHaveBeenCalled();
|
|
|
+ expect(mockSendApiRequest).not.toHaveBeenCalled();
|
|
|
});
|
|
|
|
|
|
it('should update options when props change', async () => {
|
|
|
@@ -110,7 +132,12 @@ describe('useSaveData', () => {
|
|
|
expect(result.current.loading).toBe(true);
|
|
|
|
|
|
await waitFor(() => {
|
|
|
- expect(mockPost).toHaveBeenCalledWith(mockUrl, mockBody, expect.any(Object));
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.POST,
|
|
|
+ mockUrl,
|
|
|
+ mockBody,
|
|
|
+ mockRequestOptions
|
|
|
+ );
|
|
|
expect(result.current.data).toEqual(mockData);
|
|
|
expect(result.current.error).toBeUndefined();
|
|
|
expect(result.current.loading).toBe(false);
|
|
|
@@ -118,7 +145,7 @@ describe('useSaveData', () => {
|
|
|
|
|
|
const newBody = { id: 2 };
|
|
|
const newMockData = { ...mockData, id: 2 };
|
|
|
- mockPost.mockResolvedValueOnce(newMockData);
|
|
|
+ mockSendApiRequest.mockResolvedValueOnce(newMockData);
|
|
|
|
|
|
rerender({ url: mockUrl });
|
|
|
|
|
|
@@ -129,7 +156,12 @@ describe('useSaveData', () => {
|
|
|
expect(result.current.loading).toBe(true);
|
|
|
|
|
|
await waitFor(() => {
|
|
|
- expect(mockPost).toHaveBeenCalledWith(mockUrl, newBody, expect.any(Object));
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.POST,
|
|
|
+ mockUrl,
|
|
|
+ newBody,
|
|
|
+ mockRequestOptions
|
|
|
+ );
|
|
|
expect(result.current.data).toEqual(newMockData);
|
|
|
expect(result.current.error).toBeUndefined();
|
|
|
expect(result.current.loading).toBe(false);
|
|
|
@@ -157,7 +189,12 @@ describe('useSaveData', () => {
|
|
|
expect(result.current.loading).toBe(true);
|
|
|
|
|
|
await waitFor(() => {
|
|
|
- expect(mockPost).toHaveBeenCalledWith(mockUrl, mockBody, expect.any(Object));
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.POST,
|
|
|
+ mockUrl,
|
|
|
+ mockBody,
|
|
|
+ mockRequestOptions
|
|
|
+ );
|
|
|
expect(result.current.data).toEqual(mockData);
|
|
|
expect(result.current.error).toBeUndefined();
|
|
|
expect(result.current.loading).toBe(false);
|
|
|
@@ -168,7 +205,7 @@ describe('useSaveData', () => {
|
|
|
|
|
|
it('should call onError callback when provided', async () => {
|
|
|
const mockError = new Error('Save error');
|
|
|
- mockPost.mockRejectedValue(mockError);
|
|
|
+ mockSendApiRequest.mockRejectedValue(mockError);
|
|
|
|
|
|
const mockOnSuccess = jest.fn();
|
|
|
const mockOnError = jest.fn();
|
|
|
@@ -190,7 +227,12 @@ describe('useSaveData', () => {
|
|
|
expect(result.current.loading).toBe(true);
|
|
|
|
|
|
await waitFor(() => {
|
|
|
- expect(mockPost).toHaveBeenCalledWith(mockUrl, mockBody, expect.any(Object));
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.POST,
|
|
|
+ mockUrl,
|
|
|
+ mockBody,
|
|
|
+ mockRequestOptions
|
|
|
+ );
|
|
|
expect(result.current.data).toBeUndefined();
|
|
|
expect(result.current.error).toEqual(mockError);
|
|
|
expect(result.current.loading).toBe(false);
|
|
|
@@ -207,7 +249,8 @@ describe('useSaveData', () => {
|
|
|
});
|
|
|
|
|
|
await waitFor(() => {
|
|
|
- expect(mockPost).toHaveBeenCalledWith(
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.POST,
|
|
|
mockUrl,
|
|
|
'hue data',
|
|
|
expect.objectContaining({ qsEncodeData: true })
|
|
|
@@ -228,7 +271,8 @@ describe('useSaveData', () => {
|
|
|
});
|
|
|
|
|
|
await waitFor(() => {
|
|
|
- expect(mockPost).toHaveBeenCalledWith(
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.POST,
|
|
|
mockUrl,
|
|
|
payload,
|
|
|
expect.objectContaining({ qsEncodeData: false })
|
|
|
@@ -249,7 +293,8 @@ describe('useSaveData', () => {
|
|
|
});
|
|
|
|
|
|
await waitFor(() => {
|
|
|
- expect(mockPost).toHaveBeenCalledWith(
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.POST,
|
|
|
mockUrl,
|
|
|
payload,
|
|
|
expect.objectContaining({ qsEncodeData: false })
|
|
|
@@ -274,7 +319,8 @@ describe('useSaveData', () => {
|
|
|
});
|
|
|
|
|
|
await waitFor(() => {
|
|
|
- expect(mockPost).toHaveBeenCalledWith(
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.POST,
|
|
|
mockUrl,
|
|
|
payload,
|
|
|
expect.objectContaining({ qsEncodeData: true })
|
|
|
@@ -284,4 +330,90 @@ describe('useSaveData', () => {
|
|
|
expect(result.current.loading).toBe(false);
|
|
|
});
|
|
|
});
|
|
|
+
|
|
|
+ it('should use PUT method when specified in options', async () => {
|
|
|
+ mockSendApiRequest.mockResolvedValue(mockData);
|
|
|
+
|
|
|
+ const { result } = renderHook(() => useSaveData(mockUrl, { method: HttpMethod.PUT }));
|
|
|
+
|
|
|
+ act(() => {
|
|
|
+ result.current.save(mockBody);
|
|
|
+ });
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledTimes(1);
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.PUT,
|
|
|
+ mockUrl,
|
|
|
+ mockBody,
|
|
|
+ mockRequestOptions
|
|
|
+ );
|
|
|
+ expect(result.current.data).toEqual(mockData);
|
|
|
+ expect(result.current.loading).toBe(false);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should use PATCH method when specified in saveOptions', async () => {
|
|
|
+ mockSendApiRequest.mockResolvedValue(mockData);
|
|
|
+
|
|
|
+ const { result } = renderHook(() => useSaveData(mockUrl));
|
|
|
+
|
|
|
+ act(() => {
|
|
|
+ result.current.save(mockBody, { method: HttpMethod.PATCH });
|
|
|
+ });
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledTimes(1);
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.PATCH,
|
|
|
+ mockUrl,
|
|
|
+ mockBody,
|
|
|
+ mockRequestOptions
|
|
|
+ );
|
|
|
+ expect(result.current.data).toEqual(mockData);
|
|
|
+ expect(result.current.loading).toBe(false);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should prioritize saveOptions method over options method', async () => {
|
|
|
+ mockSendApiRequest.mockResolvedValue(mockData);
|
|
|
+
|
|
|
+ const { result } = renderHook(() => useSaveData(mockUrl, { method: HttpMethod.PUT }));
|
|
|
+
|
|
|
+ act(() => {
|
|
|
+ result.current.save(mockBody, { method: HttpMethod.PATCH });
|
|
|
+ });
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledTimes(1);
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.PATCH,
|
|
|
+ mockUrl,
|
|
|
+ mockBody,
|
|
|
+ mockRequestOptions
|
|
|
+ );
|
|
|
+ expect(result.current.data).toEqual(mockData);
|
|
|
+ expect(result.current.loading).toBe(false);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should default to POST when no method is specified', async () => {
|
|
|
+ const { result } = renderHook(() => useSaveData(mockUrl));
|
|
|
+
|
|
|
+ act(() => {
|
|
|
+ result.current.save(mockBody);
|
|
|
+ });
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledTimes(1);
|
|
|
+ expect(mockSendApiRequest).toHaveBeenCalledWith(
|
|
|
+ HttpMethod.POST,
|
|
|
+ mockUrl,
|
|
|
+ mockBody,
|
|
|
+ mockRequestOptions
|
|
|
+ );
|
|
|
+ expect(result.current.data).toEqual(mockData);
|
|
|
+ expect(result.current.loading).toBe(false);
|
|
|
+ });
|
|
|
+ });
|
|
|
});
|