Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20a6a1c954 | ||
|
|
2c84587387 |
@@ -353,6 +353,8 @@
|
|||||||
"autoUnzipFileLimitTooltip": "Only unzip if the ZIP contains this many files or fewer. Set higher to extract larger ZIPs.",
|
"autoUnzipFileLimitTooltip": "Only unzip if the ZIP contains this many files or fewer. Set higher to extract larger ZIPs.",
|
||||||
"defaultToolPickerMode": "Default tool picker mode",
|
"defaultToolPickerMode": "Default tool picker mode",
|
||||||
"defaultToolPickerModeDescription": "Choose whether the tool picker opens in fullscreen or sidebar by default",
|
"defaultToolPickerModeDescription": "Choose whether the tool picker opens in fullscreen or sidebar by default",
|
||||||
|
"rememberInputs": "Remember tool inputs",
|
||||||
|
"rememberInputsDescription": "Store the last settings you used for each tool on this device",
|
||||||
"mode": {
|
"mode": {
|
||||||
"fullscreen": "Fullscreen",
|
"fullscreen": "Fullscreen",
|
||||||
"sidebar": "Sidebar"
|
"sidebar": "Sidebar"
|
||||||
|
|||||||
@@ -323,6 +323,8 @@
|
|||||||
"autoUnzipFileLimitTooltip": "Only unzip if the ZIP contains this many files or fewer. Set higher to extract larger ZIPs.",
|
"autoUnzipFileLimitTooltip": "Only unzip if the ZIP contains this many files or fewer. Set higher to extract larger ZIPs.",
|
||||||
"defaultToolPickerMode": "Default tool picker mode",
|
"defaultToolPickerMode": "Default tool picker mode",
|
||||||
"defaultToolPickerModeDescription": "Choose whether the tool picker opens in fullscreen or sidebar by default",
|
"defaultToolPickerModeDescription": "Choose whether the tool picker opens in fullscreen or sidebar by default",
|
||||||
|
"rememberInputs": "Remember tool inputs",
|
||||||
|
"rememberInputsDescription": "Store the last settings you used for each tool on this device",
|
||||||
"mode": {
|
"mode": {
|
||||||
"fullscreen": "Fullscreen",
|
"fullscreen": "Fullscreen",
|
||||||
"sidebar": "Sidebar"
|
"sidebar": "Sidebar"
|
||||||
|
|||||||
@@ -114,6 +114,23 @@ const GeneralSection: React.FC<GeneralSectionProps> = ({ hideTitle = false }) =>
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||||
|
<div>
|
||||||
|
<Text fw={500} size="sm">
|
||||||
|
{t('settings.general.rememberInputs', 'Remember tool inputs')}
|
||||||
|
</Text>
|
||||||
|
<Text size="xs" c="dimmed" mt={4}>
|
||||||
|
{t(
|
||||||
|
'settings.general.rememberInputsDescription',
|
||||||
|
'Store the last settings you used for each tool on this device'
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
checked={preferences.rememberFormInputs}
|
||||||
|
onChange={(event) => updatePreference('rememberFormInputs', event.currentTarget.checked)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
label={t('settings.general.autoUnzipTooltip', 'Automatically extract ZIP files returned from API operations. Disable to keep ZIP files intact. This does not affect automation workflows.')}
|
label={t('settings.general.autoUnzipTooltip', 'Automatically extract ZIP files returned from API operations. Disable to keep ZIP files intact. This does not affect automation workflows.')}
|
||||||
multiline
|
multiline
|
||||||
|
|||||||
@@ -2,10 +2,13 @@ import { describe, expect, test } from 'vitest';
|
|||||||
import { renderHook, act } from '@testing-library/react';
|
import { renderHook, act } from '@testing-library/react';
|
||||||
import { useAddPasswordParameters, defaultParameters, AddPasswordParametersHook } from '@app/hooks/tools/addPassword/useAddPasswordParameters';
|
import { useAddPasswordParameters, defaultParameters, AddPasswordParametersHook } from '@app/hooks/tools/addPassword/useAddPasswordParameters';
|
||||||
import { defaultParameters as defaultChangePermissionsParameters, ChangePermissionsParameters } from '@app/hooks/tools/changePermissions/useChangePermissionsParameters';
|
import { defaultParameters as defaultChangePermissionsParameters, ChangePermissionsParameters } from '@app/hooks/tools/changePermissions/useChangePermissionsParameters';
|
||||||
|
import { PreferencesTestWrapper } from '@testing/preferencesTestWrapper';
|
||||||
|
|
||||||
|
const renderAddPasswordHook = () => renderHook(() => useAddPasswordParameters(), { wrapper: PreferencesTestWrapper });
|
||||||
|
|
||||||
describe('useAddPasswordParameters', () => {
|
describe('useAddPasswordParameters', () => {
|
||||||
test('should initialize with default parameters', () => {
|
test('should initialize with default parameters', () => {
|
||||||
const { result } = renderHook(() => useAddPasswordParameters());
|
const { result } = renderAddPasswordHook();
|
||||||
|
|
||||||
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
||||||
});
|
});
|
||||||
@@ -15,7 +18,7 @@ describe('useAddPasswordParameters', () => {
|
|||||||
{ paramName: 'ownerPassword' as const, value: 'owner-password' },
|
{ paramName: 'ownerPassword' as const, value: 'owner-password' },
|
||||||
{ paramName: 'keyLength' as const, value: 256 }
|
{ paramName: 'keyLength' as const, value: 256 }
|
||||||
])('should update parameter $paramName', ({ paramName, value }) => {
|
])('should update parameter $paramName', ({ paramName, value }) => {
|
||||||
const { result } = renderHook(() => useAddPasswordParameters());
|
const { result } = renderAddPasswordHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter(paramName, value);
|
result.current.updateParameter(paramName, value);
|
||||||
@@ -28,7 +31,7 @@ describe('useAddPasswordParameters', () => {
|
|||||||
{ paramName: 'preventAssembly' as const },
|
{ paramName: 'preventAssembly' as const },
|
||||||
{ paramName: 'preventPrinting' as const }
|
{ paramName: 'preventPrinting' as const }
|
||||||
])('should update boolean permission parameter $paramName', ({ paramName }) => {
|
])('should update boolean permission parameter $paramName', ({ paramName }) => {
|
||||||
const { result } = renderHook(() => useAddPasswordParameters());
|
const { result } = renderAddPasswordHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.permissions.updateParameter(paramName, true);
|
result.current.permissions.updateParameter(paramName, true);
|
||||||
@@ -38,7 +41,7 @@ describe('useAddPasswordParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should reset parameters to defaults', () => {
|
test('should reset parameters to defaults', () => {
|
||||||
const { result } = renderHook(() => useAddPasswordParameters());
|
const { result } = renderAddPasswordHook();
|
||||||
|
|
||||||
// First, change some parameters
|
// First, change some parameters
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -60,7 +63,7 @@ describe('useAddPasswordParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return correct endpoint name', () => {
|
test('should return correct endpoint name', () => {
|
||||||
const { result } = renderHook(() => useAddPasswordParameters());
|
const { result } = renderAddPasswordHook();
|
||||||
|
|
||||||
expect(result.current.getEndpointName()).toBe('add-password');
|
expect(result.current.getEndpointName()).toBe('add-password');
|
||||||
});
|
});
|
||||||
@@ -112,7 +115,7 @@ describe('useAddPasswordParameters', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
])('should validate parameters correctly $description', ({ setup }) => {
|
])('should validate parameters correctly $description', ({ setup }) => {
|
||||||
const { result } = renderHook(() => useAddPasswordParameters());
|
const { result } = renderAddPasswordHook();
|
||||||
|
|
||||||
// Default state should be valid
|
// Default state should be valid
|
||||||
expect(result.current.validateParameters()).toBe(true);
|
expect(result.current.validateParameters()).toBe(true);
|
||||||
@@ -126,7 +129,7 @@ describe('useAddPasswordParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test.each(Object.keys(defaultChangePermissionsParameters) as Array<keyof ChangePermissionsParameters>)('should handle boolean restriction parameter %s', (param) => {
|
test.each(Object.keys(defaultChangePermissionsParameters) as Array<keyof ChangePermissionsParameters>)('should handle boolean restriction parameter %s', (param) => {
|
||||||
const { result } = renderHook(() => useAddPasswordParameters());
|
const { result } = renderAddPasswordHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.resetParameters();
|
result.current.resetParameters();
|
||||||
@@ -137,7 +140,7 @@ describe('useAddPasswordParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle mixed parameter types in updateParameter', () => {
|
test('should handle mixed parameter types in updateParameter', () => {
|
||||||
const { result } = renderHook(() => useAddPasswordParameters());
|
const { result } = renderAddPasswordHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('password', 'test-string');
|
result.current.updateParameter('password', 'test-string');
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { describe, expect, test } from 'vitest';
|
import { describe, expect, test } from 'vitest';
|
||||||
import { renderHook, act } from '@testing-library/react';
|
import { renderHook, act } from '@testing-library/react';
|
||||||
import { useAdjustPageScaleParameters, defaultParameters, PageSize, AdjustPageScaleParametersHook } from '@app/hooks/tools/adjustPageScale/useAdjustPageScaleParameters';
|
import { useAdjustPageScaleParameters, defaultParameters, PageSize, AdjustPageScaleParametersHook } from '@app/hooks/tools/adjustPageScale/useAdjustPageScaleParameters';
|
||||||
|
import { PreferencesTestWrapper } from '@testing/preferencesTestWrapper';
|
||||||
|
|
||||||
|
const renderAdjustPageScaleHook = () => renderHook(() => useAdjustPageScaleParameters(), { wrapper: PreferencesTestWrapper });
|
||||||
|
|
||||||
describe('useAdjustPageScaleParameters', () => {
|
describe('useAdjustPageScaleParameters', () => {
|
||||||
test('should initialize with default parameters', () => {
|
test('should initialize with default parameters', () => {
|
||||||
const { result } = renderHook(() => useAdjustPageScaleParameters());
|
const { result } = renderAdjustPageScaleHook();
|
||||||
|
|
||||||
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
||||||
expect(result.current.parameters.scaleFactor).toBe(1.0);
|
expect(result.current.parameters.scaleFactor).toBe(1.0);
|
||||||
@@ -19,7 +22,7 @@ describe('useAdjustPageScaleParameters', () => {
|
|||||||
{ paramName: 'pageSize' as const, value: PageSize.LETTER },
|
{ paramName: 'pageSize' as const, value: PageSize.LETTER },
|
||||||
{ paramName: 'pageSize' as const, value: PageSize.LEGAL },
|
{ paramName: 'pageSize' as const, value: PageSize.LEGAL },
|
||||||
])('should update parameter $paramName to $value', ({ paramName, value }) => {
|
])('should update parameter $paramName to $value', ({ paramName, value }) => {
|
||||||
const { result } = renderHook(() => useAdjustPageScaleParameters());
|
const { result } = renderAdjustPageScaleHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter(paramName, value);
|
result.current.updateParameter(paramName, value);
|
||||||
@@ -29,7 +32,7 @@ describe('useAdjustPageScaleParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should reset parameters to defaults', () => {
|
test('should reset parameters to defaults', () => {
|
||||||
const { result } = renderHook(() => useAdjustPageScaleParameters());
|
const { result } = renderAdjustPageScaleHook();
|
||||||
|
|
||||||
// First, change some parameters
|
// First, change some parameters
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -49,7 +52,7 @@ describe('useAdjustPageScaleParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return correct endpoint name', () => {
|
test('should return correct endpoint name', () => {
|
||||||
const { result } = renderHook(() => useAdjustPageScaleParameters());
|
const { result } = renderAdjustPageScaleHook();
|
||||||
|
|
||||||
expect(result.current.getEndpointName()).toBe('scale-pages');
|
expect(result.current.getEndpointName()).toBe('scale-pages');
|
||||||
});
|
});
|
||||||
@@ -96,7 +99,7 @@ describe('useAdjustPageScaleParameters', () => {
|
|||||||
expected: false
|
expected: false
|
||||||
}
|
}
|
||||||
])('should validate parameters correctly $description', ({ setup, expected }) => {
|
])('should validate parameters correctly $description', ({ setup, expected }) => {
|
||||||
const { result } = renderHook(() => useAdjustPageScaleParameters());
|
const { result } = renderAdjustPageScaleHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
setup(result.current);
|
setup(result.current);
|
||||||
@@ -106,7 +109,7 @@ describe('useAdjustPageScaleParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle all PageSize enum values', () => {
|
test('should handle all PageSize enum values', () => {
|
||||||
const { result } = renderHook(() => useAdjustPageScaleParameters());
|
const { result } = renderAdjustPageScaleHook();
|
||||||
|
|
||||||
Object.values(PageSize).forEach(pageSize => {
|
Object.values(PageSize).forEach(pageSize => {
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -119,7 +122,7 @@ describe('useAdjustPageScaleParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle scale factor edge cases', () => {
|
test('should handle scale factor edge cases', () => {
|
||||||
const { result } = renderHook(() => useAdjustPageScaleParameters());
|
const { result } = renderAdjustPageScaleHook();
|
||||||
|
|
||||||
// Test very small valid scale factor
|
// Test very small valid scale factor
|
||||||
act(() => {
|
act(() => {
|
||||||
|
|||||||
@@ -2,10 +2,13 @@ import { renderHook, act } from '@testing-library/react';
|
|||||||
import { defaultParameters, useChangeMetadataParameters } from '@app/hooks/tools/changeMetadata/useChangeMetadataParameters';
|
import { defaultParameters, useChangeMetadataParameters } from '@app/hooks/tools/changeMetadata/useChangeMetadataParameters';
|
||||||
import { TrappedStatus } from '@app/types/metadata';
|
import { TrappedStatus } from '@app/types/metadata';
|
||||||
import { describe, expect, test } from 'vitest';
|
import { describe, expect, test } from 'vitest';
|
||||||
|
import { PreferencesTestWrapper } from '@testing/preferencesTestWrapper';
|
||||||
|
|
||||||
|
const renderChangeMetadataHook = () => renderHook(() => useChangeMetadataParameters(), { wrapper: PreferencesTestWrapper });
|
||||||
|
|
||||||
describe('useChangeMetadataParameters', () => {
|
describe('useChangeMetadataParameters', () => {
|
||||||
test('should initialize with default parameters', () => {
|
test('should initialize with default parameters', () => {
|
||||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
const { result } = renderChangeMetadataHook();
|
||||||
|
|
||||||
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
||||||
});
|
});
|
||||||
@@ -23,7 +26,7 @@ describe('useChangeMetadataParameters', () => {
|
|||||||
{ paramName: 'trapped', value: TrappedStatus.TRUE },
|
{ paramName: 'trapped', value: TrappedStatus.TRUE },
|
||||||
{ paramName: 'deleteAll', value: true },
|
{ paramName: 'deleteAll', value: true },
|
||||||
] as const)('should update $paramName parameter', ({ paramName, value }) => {
|
] as const)('should update $paramName parameter', ({ paramName, value }) => {
|
||||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
const { result } = renderChangeMetadataHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter(paramName, value);
|
result.current.updateParameter(paramName, value);
|
||||||
@@ -48,7 +51,7 @@ describe('useChangeMetadataParameters', () => {
|
|||||||
{ description: 'no meaningful content', updates: {}, expected: false },
|
{ description: 'no meaningful content', updates: {}, expected: false },
|
||||||
{ description: 'whitespace only', updates: { title: ' ', author: ' ' }, expected: false },
|
{ description: 'whitespace only', updates: { title: ' ', author: ' ' }, expected: false },
|
||||||
])('should validate correctly when $description', ({ updates, expected }) => {
|
])('should validate correctly when $description', ({ updates, expected }) => {
|
||||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
const { result } = renderChangeMetadataHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
Object.entries(updates).forEach(([key, value]) => {
|
Object.entries(updates).forEach(([key, value]) => {
|
||||||
@@ -64,7 +67,7 @@ describe('useChangeMetadataParameters', () => {
|
|||||||
{ description: 'valid modification date', updates: { title: 'Test', modificationDate: new Date('2025/01/17 14:30:00') }, expected: true },
|
{ description: 'valid modification date', updates: { title: 'Test', modificationDate: new Date('2025/01/17 14:30:00') }, expected: true },
|
||||||
{ description: 'empty dates are valid', updates: { title: 'Test', creationDate: null, modificationDate: null }, expected: true },
|
{ description: 'empty dates are valid', updates: { title: 'Test', creationDate: null, modificationDate: null }, expected: true },
|
||||||
])('should validate dates correctly with $description', ({ updates, expected }) => {
|
])('should validate dates correctly with $description', ({ updates, expected }) => {
|
||||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
const { result } = renderChangeMetadataHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
Object.entries(updates).forEach(([key, value]) => {
|
Object.entries(updates).forEach(([key, value]) => {
|
||||||
@@ -78,7 +81,7 @@ describe('useChangeMetadataParameters', () => {
|
|||||||
|
|
||||||
describe('custom metadata', () => {
|
describe('custom metadata', () => {
|
||||||
test('should add custom metadata with sequential IDs', () => {
|
test('should add custom metadata with sequential IDs', () => {
|
||||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
const { result } = renderChangeMetadataHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.addCustomMetadata();
|
result.current.addCustomMetadata();
|
||||||
@@ -93,7 +96,7 @@ describe('useChangeMetadataParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should remove custom metadata by ID', () => {
|
test('should remove custom metadata by ID', () => {
|
||||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
const { result } = renderChangeMetadataHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.addCustomMetadata();
|
result.current.addCustomMetadata();
|
||||||
@@ -109,7 +112,7 @@ describe('useChangeMetadataParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should update custom metadata by ID', () => {
|
test('should update custom metadata by ID', () => {
|
||||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
const { result } = renderChangeMetadataHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.addCustomMetadata();
|
result.current.addCustomMetadata();
|
||||||
@@ -129,7 +132,7 @@ describe('useChangeMetadataParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should validate with custom metadata', () => {
|
test('should validate with custom metadata', () => {
|
||||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
const { result } = renderChangeMetadataHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.addCustomMetadata();
|
result.current.addCustomMetadata();
|
||||||
@@ -145,7 +148,7 @@ describe('useChangeMetadataParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should generate unique IDs for multiple custom entries', () => {
|
test('should generate unique IDs for multiple custom entries', () => {
|
||||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
const { result } = renderChangeMetadataHook();
|
||||||
|
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -161,7 +164,7 @@ describe('useChangeMetadataParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return correct endpoint name', () => {
|
test('should return correct endpoint name', () => {
|
||||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
const { result } = renderChangeMetadataHook();
|
||||||
|
|
||||||
expect(result.current.getEndpointName()).toBe('update-metadata');
|
expect(result.current.getEndpointName()).toBe('update-metadata');
|
||||||
});
|
});
|
||||||
|
|||||||
+9
-6
@@ -1,16 +1,19 @@
|
|||||||
import { describe, expect, test } from 'vitest';
|
import { describe, expect, test } from 'vitest';
|
||||||
import { renderHook, act } from '@testing-library/react';
|
import { renderHook, act } from '@testing-library/react';
|
||||||
import { useChangePermissionsParameters, defaultParameters, ChangePermissionsParameters } from '@app/hooks/tools/changePermissions/useChangePermissionsParameters';
|
import { useChangePermissionsParameters, defaultParameters, ChangePermissionsParameters } from '@app/hooks/tools/changePermissions/useChangePermissionsParameters';
|
||||||
|
import { PreferencesTestWrapper } from '@testing/preferencesTestWrapper';
|
||||||
|
|
||||||
|
const renderChangePermissionsHook = () => renderHook(() => useChangePermissionsParameters(), { wrapper: PreferencesTestWrapper });
|
||||||
|
|
||||||
describe('useChangePermissionsParameters', () => {
|
describe('useChangePermissionsParameters', () => {
|
||||||
test('should initialize with default parameters', () => {
|
test('should initialize with default parameters', () => {
|
||||||
const { result } = renderHook(() => useChangePermissionsParameters());
|
const { result } = renderChangePermissionsHook();
|
||||||
|
|
||||||
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should update individual boolean parameters', () => {
|
test('should update individual boolean parameters', () => {
|
||||||
const { result } = renderHook(() => useChangePermissionsParameters());
|
const { result } = renderChangePermissionsHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('preventAssembly', true);
|
result.current.updateParameter('preventAssembly', true);
|
||||||
@@ -28,7 +31,7 @@ describe('useChangePermissionsParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should update all permission parameters', () => {
|
test('should update all permission parameters', () => {
|
||||||
const { result } = renderHook(() => useChangePermissionsParameters());
|
const { result } = renderChangePermissionsHook();
|
||||||
|
|
||||||
const permissionKeys = Object.keys(defaultParameters) as Array<keyof ChangePermissionsParameters>;
|
const permissionKeys = Object.keys(defaultParameters) as Array<keyof ChangePermissionsParameters>;
|
||||||
|
|
||||||
@@ -56,7 +59,7 @@ describe('useChangePermissionsParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should reset parameters to defaults', () => {
|
test('should reset parameters to defaults', () => {
|
||||||
const { result } = renderHook(() => useChangePermissionsParameters());
|
const { result } = renderChangePermissionsHook();
|
||||||
|
|
||||||
// First, change some parameters
|
// First, change some parameters
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -78,13 +81,13 @@ describe('useChangePermissionsParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return correct endpoint name', () => {
|
test('should return correct endpoint name', () => {
|
||||||
const { result } = renderHook(() => useChangePermissionsParameters());
|
const { result } = renderChangePermissionsHook();
|
||||||
|
|
||||||
expect(result.current.getEndpointName()).toBe('add-password');
|
expect(result.current.getEndpointName()).toBe('add-password');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should always validate as true', () => {
|
test('should always validate as true', () => {
|
||||||
const { result } = renderHook(() => useChangePermissionsParameters());
|
const { result } = renderChangePermissionsHook();
|
||||||
|
|
||||||
// Default state should be valid
|
// Default state should be valid
|
||||||
expect(result.current.validateParameters()).toBe(true);
|
expect(result.current.validateParameters()).toBe(true);
|
||||||
|
|||||||
@@ -6,13 +6,16 @@ import { describe, test, expect } from 'vitest';
|
|||||||
import { renderHook, act } from '@testing-library/react';
|
import { renderHook, act } from '@testing-library/react';
|
||||||
import { useConvertParameters } from '@app/hooks/tools/convert/useConvertParameters';
|
import { useConvertParameters } from '@app/hooks/tools/convert/useConvertParameters';
|
||||||
import { FIT_OPTIONS } from '@app/constants/convertConstants';
|
import { FIT_OPTIONS } from '@app/constants/convertConstants';
|
||||||
|
import { PreferencesTestWrapper } from '@testing/preferencesTestWrapper';
|
||||||
|
|
||||||
|
const renderConvertHook = () => renderHook(() => useConvertParameters(), { wrapper: PreferencesTestWrapper });
|
||||||
|
|
||||||
describe('useConvertParameters', () => {
|
describe('useConvertParameters', () => {
|
||||||
|
|
||||||
describe('Parameter Management', () => {
|
describe('Parameter Management', () => {
|
||||||
|
|
||||||
test('should initialize with default parameters', () => {
|
test('should initialize with default parameters', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
expect(result.current.parameters.fromExtension).toBe('');
|
expect(result.current.parameters.fromExtension).toBe('');
|
||||||
expect(result.current.parameters.toExtension).toBe('');
|
expect(result.current.parameters.toExtension).toBe('');
|
||||||
@@ -28,7 +31,7 @@ describe('useConvertParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should update individual parameters', () => {
|
test('should update individual parameters', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('fromExtension', 'pdf');
|
result.current.updateParameter('fromExtension', 'pdf');
|
||||||
@@ -39,7 +42,7 @@ describe('useConvertParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should update nested image options', () => {
|
test('should update nested image options', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('imageOptions', {
|
result.current.updateParameter('imageOptions', {
|
||||||
@@ -61,7 +64,7 @@ describe('useConvertParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should update nested HTML options', () => {
|
test('should update nested HTML options', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('htmlOptions', {
|
result.current.updateParameter('htmlOptions', {
|
||||||
@@ -73,7 +76,7 @@ describe('useConvertParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should update nested email options', () => {
|
test('should update nested email options', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('emailOptions', {
|
result.current.updateParameter('emailOptions', {
|
||||||
@@ -91,7 +94,7 @@ describe('useConvertParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should update nested PDF/A options', () => {
|
test('should update nested PDF/A options', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('pdfaOptions', {
|
result.current.updateParameter('pdfaOptions', {
|
||||||
@@ -103,7 +106,7 @@ describe('useConvertParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should reset parameters to defaults', () => {
|
test('should reset parameters to defaults', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('fromExtension', 'pdf');
|
result.current.updateParameter('fromExtension', 'pdf');
|
||||||
@@ -124,7 +127,7 @@ describe('useConvertParameters', () => {
|
|||||||
describe('Parameter Validation', () => {
|
describe('Parameter Validation', () => {
|
||||||
|
|
||||||
test('should validate parameters correctly', () => {
|
test('should validate parameters correctly', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
// No parameters - should be invalid
|
// No parameters - should be invalid
|
||||||
expect(result.current.validateParameters()).toBe(false);
|
expect(result.current.validateParameters()).toBe(false);
|
||||||
@@ -143,7 +146,7 @@ describe('useConvertParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should validate unsupported conversions', () => {
|
test('should validate unsupported conversions', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('fromExtension', 'pdf');
|
result.current.updateParameter('fromExtension', 'pdf');
|
||||||
@@ -158,7 +161,7 @@ describe('useConvertParameters', () => {
|
|||||||
describe('Endpoint Generation', () => {
|
describe('Endpoint Generation', () => {
|
||||||
|
|
||||||
test('should generate correct endpoint names', () => {
|
test('should generate correct endpoint names', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('fromExtension', 'pdf');
|
result.current.updateParameter('fromExtension', 'pdf');
|
||||||
@@ -170,7 +173,7 @@ describe('useConvertParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should generate correct endpoint URLs', () => {
|
test('should generate correct endpoint URLs', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('fromExtension', 'pdf');
|
result.current.updateParameter('fromExtension', 'pdf');
|
||||||
@@ -182,7 +185,7 @@ describe('useConvertParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return empty strings for invalid conversions', () => {
|
test('should return empty strings for invalid conversions', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('fromExtension', 'invalid');
|
result.current.updateParameter('fromExtension', 'invalid');
|
||||||
@@ -197,7 +200,7 @@ describe('useConvertParameters', () => {
|
|||||||
describe('Available Extensions', () => {
|
describe('Available Extensions', () => {
|
||||||
|
|
||||||
test('should return available extensions for valid source format', () => {
|
test('should return available extensions for valid source format', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const availableExtensions = result.current.getAvailableToExtensions('pdf');
|
const availableExtensions = result.current.getAvailableToExtensions('pdf');
|
||||||
|
|
||||||
@@ -207,7 +210,7 @@ describe('useConvertParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return empty array for invalid source format', () => {
|
test('should return empty array for invalid source format', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const availableExtensions = result.current.getAvailableToExtensions('invalid');
|
const availableExtensions = result.current.getAvailableToExtensions('invalid');
|
||||||
|
|
||||||
@@ -219,7 +222,7 @@ describe('useConvertParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return empty array for empty source format', () => {
|
test('should return empty array for empty source format', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const availableExtensions = result.current.getAvailableToExtensions('');
|
const availableExtensions = result.current.getAvailableToExtensions('');
|
||||||
|
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ export const useConvertParameters = (): ConvertParametersHook => {
|
|||||||
defaultParameters,
|
defaultParameters,
|
||||||
endpointName: getEndpointName,
|
endpointName: getEndpointName,
|
||||||
validateFn: validateParameters,
|
validateFn: validateParameters,
|
||||||
|
storageKey: 'convert',
|
||||||
}), []);
|
}), []);
|
||||||
|
|
||||||
const baseHook = useBaseParameters(config);
|
const baseHook = useBaseParameters(config);
|
||||||
|
|||||||
@@ -6,13 +6,16 @@
|
|||||||
import { describe, test, expect } from 'vitest';
|
import { describe, test, expect } from 'vitest';
|
||||||
import { renderHook, act } from '@testing-library/react';
|
import { renderHook, act } from '@testing-library/react';
|
||||||
import { useConvertParameters } from '@app/hooks/tools/convert/useConvertParameters';
|
import { useConvertParameters } from '@app/hooks/tools/convert/useConvertParameters';
|
||||||
|
import { PreferencesTestWrapper } from '@testing/preferencesTestWrapper';
|
||||||
|
|
||||||
|
const renderConvertHook = () => renderHook(() => useConvertParameters(), { wrapper: PreferencesTestWrapper });
|
||||||
|
|
||||||
describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
||||||
|
|
||||||
describe('Single File Detection', () => {
|
describe('Single File Detection', () => {
|
||||||
|
|
||||||
test('should detect single file extension and set auto-target', () => {
|
test('should detect single file extension and set auto-target', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const pdfFile = [{ name: 'document.pdf' }];
|
const pdfFile = [{ name: 'document.pdf' }];
|
||||||
|
|
||||||
@@ -27,7 +30,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle unknown file types with file-to-pdf fallback', () => {
|
test('should handle unknown file types with file-to-pdf fallback', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const unknownFile = [{ name: 'document.xyz' }, { name: 'image.jpggg' }];
|
const unknownFile = [{ name: 'document.xyz' }, { name: 'image.jpggg' }];
|
||||||
|
|
||||||
@@ -41,7 +44,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle files without extensions', () => {
|
test('should handle files without extensions', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const noExtFile = [{ name: 'document' }];
|
const noExtFile = [{ name: 'document' }];
|
||||||
|
|
||||||
@@ -59,7 +62,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
describe('Multiple Identical Files', () => {
|
describe('Multiple Identical Files', () => {
|
||||||
|
|
||||||
test('should detect multiple PDF files and set auto-target', () => {
|
test('should detect multiple PDF files and set auto-target', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const pdfFiles = [
|
const pdfFiles = [
|
||||||
{ name: 'doc1.pdf' },
|
{ name: 'doc1.pdf' },
|
||||||
@@ -78,7 +81,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle multiple unknown file types with fallback', () => {
|
test('should handle multiple unknown file types with fallback', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const unknownFiles = [
|
const unknownFiles = [
|
||||||
{ name: 'file1.xyz' },
|
{ name: 'file1.xyz' },
|
||||||
@@ -98,7 +101,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
describe('Smart Detection - All Images', () => {
|
describe('Smart Detection - All Images', () => {
|
||||||
|
|
||||||
test('should detect all image files and enable smart detection', () => {
|
test('should detect all image files and enable smart detection', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const imageFiles = [
|
const imageFiles = [
|
||||||
{ name: 'photo1.jpg' },
|
{ name: 'photo1.jpg' },
|
||||||
@@ -117,7 +120,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle mixed case image extensions', () => {
|
test('should handle mixed case image extensions', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const imageFiles = [
|
const imageFiles = [
|
||||||
{ name: 'photo1.JPG' },
|
{ name: 'photo1.JPG' },
|
||||||
@@ -136,7 +139,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
describe('Smart Detection - All Web Files', () => {
|
describe('Smart Detection - All Web Files', () => {
|
||||||
|
|
||||||
test('should detect all web files and enable web smart detection', () => {
|
test('should detect all web files and enable web smart detection', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const webFiles = [
|
const webFiles = [
|
||||||
{ name: 'page1.html' },
|
{ name: 'page1.html' },
|
||||||
@@ -154,7 +157,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle mixed case web extensions', () => {
|
test('should handle mixed case web extensions', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const webFiles = [
|
const webFiles = [
|
||||||
{ name: 'page1.HTML' },
|
{ name: 'page1.HTML' },
|
||||||
@@ -170,7 +173,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should detect multiple web files and enable web smart detection', () => {
|
test('should detect multiple web files and enable web smart detection', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const zipFiles = [
|
const zipFiles = [
|
||||||
{ name: 'site1.zip' },
|
{ name: 'site1.zip' },
|
||||||
@@ -191,7 +194,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
describe('Smart Detection - Mixed File Types', () => {
|
describe('Smart Detection - Mixed File Types', () => {
|
||||||
|
|
||||||
test('should detect mixed file types and enable smart detection', () => {
|
test('should detect mixed file types and enable smart detection', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const mixedFiles = [
|
const mixedFiles = [
|
||||||
{ name: 'document.pdf' },
|
{ name: 'document.pdf' },
|
||||||
@@ -210,7 +213,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should detect mixed images and documents as mixed type', () => {
|
test('should detect mixed images and documents as mixed type', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const mixedFiles = [
|
const mixedFiles = [
|
||||||
{ name: 'photo.jpg' },
|
{ name: 'photo.jpg' },
|
||||||
@@ -227,7 +230,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle mixed with unknown file types', () => {
|
test('should handle mixed with unknown file types', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const mixedFiles = [
|
const mixedFiles = [
|
||||||
{ name: 'document.pdf' },
|
{ name: 'document.pdf' },
|
||||||
@@ -247,7 +250,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
describe('Smart Detection Endpoint Resolution', () => {
|
describe('Smart Detection Endpoint Resolution', () => {
|
||||||
|
|
||||||
test('should return correct endpoint for image smart detection', () => {
|
test('should return correct endpoint for image smart detection', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const imageFiles = [
|
const imageFiles = [
|
||||||
{ name: 'photo1.jpg' },
|
{ name: 'photo1.jpg' },
|
||||||
@@ -263,7 +266,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return correct endpoint for web smart detection', () => {
|
test('should return correct endpoint for web smart detection', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const webFiles = [
|
const webFiles = [
|
||||||
{ name: 'page1.html' },
|
{ name: 'page1.html' },
|
||||||
@@ -279,7 +282,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return correct endpoint for mixed smart detection', () => {
|
test('should return correct endpoint for mixed smart detection', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const mixedFiles = [
|
const mixedFiles = [
|
||||||
{ name: 'document.pdf' },
|
{ name: 'document.pdf' },
|
||||||
@@ -298,7 +301,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
describe('Auto-Target Selection Logic', () => {
|
describe('Auto-Target Selection Logic', () => {
|
||||||
|
|
||||||
test('should select single available target automatically', () => {
|
test('should select single available target automatically', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
// Markdown has only one conversion target (PDF)
|
// Markdown has only one conversion target (PDF)
|
||||||
const mdFile = [{ name: 'readme.md' }];
|
const mdFile = [{ name: 'readme.md' }];
|
||||||
@@ -312,7 +315,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should not auto-select when multiple targets available', () => {
|
test('should not auto-select when multiple targets available', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
// PDF has multiple conversion targets, so no auto-selection
|
// PDF has multiple conversion targets, so no auto-selection
|
||||||
const pdfFile = [{ name: 'document.pdf' }];
|
const pdfFile = [{ name: 'document.pdf' }];
|
||||||
@@ -330,7 +333,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
describe('Edge Cases', () => {
|
describe('Edge Cases', () => {
|
||||||
|
|
||||||
test('should handle empty file names', () => {
|
test('should handle empty file names', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const emptyFiles = [{ name: '' }];
|
const emptyFiles = [{ name: '' }];
|
||||||
|
|
||||||
@@ -343,7 +346,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle malformed file objects', () => {
|
test('should handle malformed file objects', () => {
|
||||||
const { result } = renderHook(() => useConvertParameters());
|
const { result } = renderConvertHook();
|
||||||
|
|
||||||
const malformedFiles: Array<{name: string}> = [
|
const malformedFiles: Array<{name: string}> = [
|
||||||
{ name: 'valid.pdf' },
|
{ name: 'valid.pdf' },
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { describe, expect, test } from 'vitest';
|
import { describe, expect, test } from 'vitest';
|
||||||
import { renderHook, act } from '@testing-library/react';
|
import { renderHook, act } from '@testing-library/react';
|
||||||
import { useMergeParameters, defaultParameters } from '@app/hooks/tools/merge/useMergeParameters';
|
import { useMergeParameters, defaultParameters } from '@app/hooks/tools/merge/useMergeParameters';
|
||||||
|
import { PreferencesTestWrapper } from '@testing/preferencesTestWrapper';
|
||||||
|
|
||||||
|
const renderMergeHook = () => renderHook(() => useMergeParameters(), { wrapper: PreferencesTestWrapper });
|
||||||
|
|
||||||
describe('useMergeParameters', () => {
|
describe('useMergeParameters', () => {
|
||||||
test('should initialize with default parameters', () => {
|
test('should initialize with default parameters', () => {
|
||||||
const { result } = renderHook(() => useMergeParameters());
|
const { result } = renderMergeHook();
|
||||||
|
|
||||||
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
||||||
});
|
});
|
||||||
@@ -15,7 +18,7 @@ describe('useMergeParameters', () => {
|
|||||||
{ paramName: 'generateTableOfContents' as const, value: true },
|
{ paramName: 'generateTableOfContents' as const, value: true },
|
||||||
{ paramName: 'generateTableOfContents' as const, value: false }
|
{ paramName: 'generateTableOfContents' as const, value: false }
|
||||||
])('should update parameter $paramName to $value', ({ paramName, value }) => {
|
])('should update parameter $paramName to $value', ({ paramName, value }) => {
|
||||||
const { result } = renderHook(() => useMergeParameters());
|
const { result } = renderMergeHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter(paramName, value);
|
result.current.updateParameter(paramName, value);
|
||||||
@@ -25,7 +28,7 @@ describe('useMergeParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should reset parameters to defaults', () => {
|
test('should reset parameters to defaults', () => {
|
||||||
const { result } = renderHook(() => useMergeParameters());
|
const { result } = renderMergeHook();
|
||||||
|
|
||||||
// First, change some parameters
|
// First, change some parameters
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -45,7 +48,7 @@ describe('useMergeParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should validate parameters correctly - always returns true', () => {
|
test('should validate parameters correctly - always returns true', () => {
|
||||||
const { result } = renderHook(() => useMergeParameters());
|
const { result } = renderMergeHook();
|
||||||
|
|
||||||
// Default state should be valid
|
// Default state should be valid
|
||||||
expect(result.current.validateParameters()).toBe(true);
|
expect(result.current.validateParameters()).toBe(true);
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { describe, expect, test } from 'vitest';
|
import { describe, expect, test } from 'vitest';
|
||||||
import { renderHook, act } from '@testing-library/react';
|
import { renderHook, act } from '@testing-library/react';
|
||||||
import { useRedactParameters, defaultParameters } from '@app/hooks/tools/redact/useRedactParameters';
|
import { useRedactParameters, defaultParameters } from '@app/hooks/tools/redact/useRedactParameters';
|
||||||
|
import { PreferencesTestWrapper } from '@testing/preferencesTestWrapper';
|
||||||
|
|
||||||
|
const renderRedactHook = () => renderHook(() => useRedactParameters(), { wrapper: PreferencesTestWrapper });
|
||||||
|
|
||||||
describe('useRedactParameters', () => {
|
describe('useRedactParameters', () => {
|
||||||
test('should initialize with default parameters', () => {
|
test('should initialize with default parameters', () => {
|
||||||
const { result } = renderHook(() => useRedactParameters());
|
const { result } = renderRedactHook();
|
||||||
|
|
||||||
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
||||||
});
|
});
|
||||||
@@ -18,7 +21,7 @@ describe('useRedactParameters', () => {
|
|||||||
{ paramName: 'customPadding' as const, value: 0.5 },
|
{ paramName: 'customPadding' as const, value: 0.5 },
|
||||||
{ paramName: 'convertPDFToImage' as const, value: false }
|
{ paramName: 'convertPDFToImage' as const, value: false }
|
||||||
])('should update parameter $paramName', ({ paramName, value }) => {
|
])('should update parameter $paramName', ({ paramName, value }) => {
|
||||||
const { result } = renderHook(() => useRedactParameters());
|
const { result } = renderRedactHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter(paramName, value);
|
result.current.updateParameter(paramName, value);
|
||||||
@@ -28,7 +31,7 @@ describe('useRedactParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should reset parameters to defaults', () => {
|
test('should reset parameters to defaults', () => {
|
||||||
const { result } = renderHook(() => useRedactParameters());
|
const { result } = renderRedactHook();
|
||||||
|
|
||||||
// Modify some parameters
|
// Modify some parameters
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -52,7 +55,7 @@ describe('useRedactParameters', () => {
|
|||||||
{ description: 'not validate when wordsToRedact contains only empty strings in automatic mode', wordsToRedact: ['', ' ', ''], expected: false },
|
{ description: 'not validate when wordsToRedact contains only empty strings in automatic mode', wordsToRedact: ['', ' ', ''], expected: false },
|
||||||
{ description: 'validate when wordsToRedact contains at least one non-empty word in automatic mode', wordsToRedact: ['', 'valid', ' '], expected: true },
|
{ description: 'validate when wordsToRedact contains at least one non-empty word in automatic mode', wordsToRedact: ['', 'valid', ' '], expected: true },
|
||||||
])('should $description', ({ wordsToRedact, expected }) => {
|
])('should $description', ({ wordsToRedact, expected }) => {
|
||||||
const { result } = renderHook(() => useRedactParameters());
|
const { result } = renderRedactHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('mode', 'automatic');
|
result.current.updateParameter('mode', 'automatic');
|
||||||
@@ -63,7 +66,7 @@ describe('useRedactParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should not validate in manual mode (not implemented)', () => {
|
test('should not validate in manual mode (not implemented)', () => {
|
||||||
const { result } = renderHook(() => useRedactParameters());
|
const { result } = renderRedactHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('mode', 'manual');
|
result.current.updateParameter('mode', 'manual');
|
||||||
@@ -75,7 +78,7 @@ describe('useRedactParameters', () => {
|
|||||||
|
|
||||||
describe('endpoint handling', () => {
|
describe('endpoint handling', () => {
|
||||||
test('should return correct endpoint for automatic mode', () => {
|
test('should return correct endpoint for automatic mode', () => {
|
||||||
const { result } = renderHook(() => useRedactParameters());
|
const { result } = renderRedactHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('mode', 'automatic');
|
result.current.updateParameter('mode', 'automatic');
|
||||||
@@ -85,7 +88,7 @@ describe('useRedactParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should throw error for manual mode (not implemented)', () => {
|
test('should throw error for manual mode (not implemented)', () => {
|
||||||
const { result } = renderHook(() => useRedactParameters());
|
const { result } = renderRedactHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('mode', 'manual');
|
result.current.updateParameter('mode', 'manual');
|
||||||
@@ -96,7 +99,7 @@ describe('useRedactParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should maintain parameter state across updates', () => {
|
test('should maintain parameter state across updates', () => {
|
||||||
const { result } = renderHook(() => useRedactParameters());
|
const { result } = renderRedactHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('redactColor', '#FF0000');
|
result.current.updateParameter('redactColor', '#FF0000');
|
||||||
@@ -117,7 +120,7 @@ describe('useRedactParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle array parameter updates correctly', () => {
|
test('should handle array parameter updates correctly', () => {
|
||||||
const { result } = renderHook(() => useRedactParameters());
|
const { result } = renderRedactHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('wordsToRedact', ['initial']);
|
result.current.updateParameter('wordsToRedact', ['initial']);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export const useRedactParameters = (): RedactParametersHook => {
|
|||||||
}
|
}
|
||||||
// Manual mode validation would go here when implemented
|
// Manual mode validation would go here when implemented
|
||||||
return false;
|
return false;
|
||||||
}
|
},
|
||||||
|
storageKey: 'redact'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import { describe, expect, test } from 'vitest';
|
import { describe, expect, test } from 'vitest';
|
||||||
import { renderHook, act } from '@testing-library/react';
|
import { renderHook, act } from '@testing-library/react';
|
||||||
import { useRemovePasswordParameters, defaultParameters } from '@app/hooks/tools/removePassword/useRemovePasswordParameters';
|
import { useRemovePasswordParameters, defaultParameters } from '@app/hooks/tools/removePassword/useRemovePasswordParameters';
|
||||||
|
import { PreferencesTestWrapper } from '@testing/preferencesTestWrapper';
|
||||||
|
|
||||||
|
const renderRemovePasswordHook = () => renderHook(() => useRemovePasswordParameters(), { wrapper: PreferencesTestWrapper });
|
||||||
|
|
||||||
describe('useRemovePasswordParameters', () => {
|
describe('useRemovePasswordParameters', () => {
|
||||||
test('should initialize with default parameters', () => {
|
test('should initialize with default parameters', () => {
|
||||||
const { result } = renderHook(() => useRemovePasswordParameters());
|
const { result } = renderRemovePasswordHook();
|
||||||
|
|
||||||
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should update password parameter', () => {
|
test('should update password parameter', () => {
|
||||||
const { result } = renderHook(() => useRemovePasswordParameters());
|
const { result } = renderRemovePasswordHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('password', 'test-password');
|
result.current.updateParameter('password', 'test-password');
|
||||||
@@ -20,7 +23,7 @@ describe('useRemovePasswordParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should reset parameters to defaults', () => {
|
test('should reset parameters to defaults', () => {
|
||||||
const { result } = renderHook(() => useRemovePasswordParameters());
|
const { result } = renderRemovePasswordHook();
|
||||||
|
|
||||||
// First, change the password
|
// First, change the password
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -38,7 +41,7 @@ describe('useRemovePasswordParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return correct endpoint name', () => {
|
test('should return correct endpoint name', () => {
|
||||||
const { result } = renderHook(() => useRemovePasswordParameters());
|
const { result } = renderRemovePasswordHook();
|
||||||
|
|
||||||
expect(result.current.getEndpointName()).toBe('remove-password');
|
expect(result.current.getEndpointName()).toBe('remove-password');
|
||||||
});
|
});
|
||||||
@@ -70,7 +73,7 @@ describe('useRemovePasswordParameters', () => {
|
|||||||
expectedValid: true
|
expectedValid: true
|
||||||
}
|
}
|
||||||
])('should validate parameters correctly $description', ({ password, expectedValid }) => {
|
])('should validate parameters correctly $description', ({ password, expectedValid }) => {
|
||||||
const { result } = renderHook(() => useRemovePasswordParameters());
|
const { result } = renderRemovePasswordHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('password', password);
|
result.current.updateParameter('password', password);
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { describe, expect, test } from 'vitest';
|
import { describe, expect, test } from 'vitest';
|
||||||
import { renderHook, act } from '@testing-library/react';
|
import { renderHook, act } from '@testing-library/react';
|
||||||
import { useRotateParameters, defaultParameters, normalizeAngle } from '@app/hooks/tools/rotate/useRotateParameters';
|
import { useRotateParameters, defaultParameters, normalizeAngle } from '@app/hooks/tools/rotate/useRotateParameters';
|
||||||
|
import { PreferencesTestWrapper } from '@testing/preferencesTestWrapper';
|
||||||
|
|
||||||
|
const renderRotateHook = () => renderHook(() => useRotateParameters(), { wrapper: PreferencesTestWrapper });
|
||||||
|
|
||||||
describe('useRotateParameters', () => {
|
describe('useRotateParameters', () => {
|
||||||
test('should initialize with default parameters', () => {
|
test('should initialize with default parameters', () => {
|
||||||
const { result } = renderHook(() => useRotateParameters());
|
const { result } = renderRotateHook();
|
||||||
|
|
||||||
expect(result.current.parameters).toEqual(defaultParameters);
|
expect(result.current.parameters).toEqual(defaultParameters);
|
||||||
expect(result.current.parameters.angle).toBe(0);
|
expect(result.current.parameters.angle).toBe(0);
|
||||||
@@ -12,7 +15,7 @@ describe('useRotateParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should validate parameters correctly', () => {
|
test('should validate parameters correctly', () => {
|
||||||
const { result } = renderHook(() => useRotateParameters());
|
const { result } = renderRotateHook();
|
||||||
|
|
||||||
// Default should be valid
|
// Default should be valid
|
||||||
expect(result.current.validateParameters()).toBe(true);
|
expect(result.current.validateParameters()).toBe(true);
|
||||||
@@ -31,7 +34,7 @@ describe('useRotateParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should rotate clockwise correctly', () => {
|
test('should rotate clockwise correctly', () => {
|
||||||
const { result } = renderHook(() => useRotateParameters());
|
const { result } = renderRotateHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.rotateClockwise();
|
result.current.rotateClockwise();
|
||||||
@@ -58,7 +61,7 @@ describe('useRotateParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should rotate anticlockwise correctly', () => {
|
test('should rotate anticlockwise correctly', () => {
|
||||||
const { result } = renderHook(() => useRotateParameters());
|
const { result } = renderRotateHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.rotateAnticlockwise();
|
result.current.rotateAnticlockwise();
|
||||||
@@ -85,7 +88,7 @@ describe('useRotateParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should normalize angles correctly', () => {
|
test('should normalize angles correctly', () => {
|
||||||
const { result } = renderHook(() => useRotateParameters());
|
const { result } = renderRotateHook();
|
||||||
|
|
||||||
expect(result.current.normalizeAngle(360)).toBe(0);
|
expect(result.current.normalizeAngle(360)).toBe(0);
|
||||||
expect(result.current.normalizeAngle(450)).toBe(90);
|
expect(result.current.normalizeAngle(450)).toBe(90);
|
||||||
@@ -94,7 +97,7 @@ describe('useRotateParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should reset parameters correctly', () => {
|
test('should reset parameters correctly', () => {
|
||||||
const { result } = renderHook(() => useRotateParameters());
|
const { result } = renderRotateHook();
|
||||||
|
|
||||||
// Set some rotation
|
// Set some rotation
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -116,7 +119,7 @@ describe('useRotateParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should update parameters', () => {
|
test('should update parameters', () => {
|
||||||
const { result } = renderHook(() => useRotateParameters());
|
const { result } = renderRotateHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('angle', 450);
|
result.current.updateParameter('angle', 450);
|
||||||
@@ -132,13 +135,13 @@ describe('useRotateParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return correct endpoint name', () => {
|
test('should return correct endpoint name', () => {
|
||||||
const { result } = renderHook(() => useRotateParameters());
|
const { result } = renderRotateHook();
|
||||||
|
|
||||||
expect(result.current.getEndpointName()).toBe('rotate-pdf');
|
expect(result.current.getEndpointName()).toBe('rotate-pdf');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should detect rotation state correctly', () => {
|
test('should detect rotation state correctly', () => {
|
||||||
const { result } = renderHook(() => useRotateParameters());
|
const { result } = renderRotateHook();
|
||||||
|
|
||||||
// Initially no rotation
|
// Initially no rotation
|
||||||
expect(result.current.hasRotation).toBe(false);
|
expect(result.current.hasRotation).toBe(false);
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import { describe, expect, test } from 'vitest';
|
import { describe, expect, test } from 'vitest';
|
||||||
import { renderHook, act } from '@testing-library/react';
|
import { renderHook, act } from '@testing-library/react';
|
||||||
import { defaultParameters, useSanitizeParameters } from '@app/hooks/tools/sanitize/useSanitizeParameters';
|
import { defaultParameters, useSanitizeParameters } from '@app/hooks/tools/sanitize/useSanitizeParameters';
|
||||||
|
import { PreferencesTestWrapper } from '@testing/preferencesTestWrapper';
|
||||||
|
|
||||||
|
const renderSanitizeHook = () => renderHook(() => useSanitizeParameters(), { wrapper: PreferencesTestWrapper });
|
||||||
|
|
||||||
describe('useSanitizeParameters', () => {
|
describe('useSanitizeParameters', () => {
|
||||||
test('should initialize with default parameters', () => {
|
test('should initialize with default parameters', () => {
|
||||||
const { result } = renderHook(() => useSanitizeParameters());
|
const { result } = renderSanitizeHook();
|
||||||
|
|
||||||
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should update individual parameters', () => {
|
test('should update individual parameters', () => {
|
||||||
const { result } = renderHook(() => useSanitizeParameters());
|
const { result } = renderSanitizeHook();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.updateParameter('removeXMPMetadata', true);
|
result.current.updateParameter('removeXMPMetadata', true);
|
||||||
@@ -23,7 +26,7 @@ describe('useSanitizeParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should reset parameters to defaults', () => {
|
test('should reset parameters to defaults', () => {
|
||||||
const { result } = renderHook(() => useSanitizeParameters());
|
const { result } = renderSanitizeHook();
|
||||||
|
|
||||||
// First, change some parameters
|
// First, change some parameters
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -43,13 +46,13 @@ describe('useSanitizeParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return correct endpoint name', () => {
|
test('should return correct endpoint name', () => {
|
||||||
const { result } = renderHook(() => useSanitizeParameters());
|
const { result } = renderSanitizeHook();
|
||||||
|
|
||||||
expect(result.current.getEndpointName()).toBe('sanitize-pdf');
|
expect(result.current.getEndpointName()).toBe('sanitize-pdf');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should validate parameters correctly', () => {
|
test('should validate parameters correctly', () => {
|
||||||
const { result } = renderHook(() => useSanitizeParameters());
|
const { result } = renderSanitizeHook();
|
||||||
|
|
||||||
// Default state should be valid (has removeJavaScript and removeEmbeddedFiles enabled)
|
// Default state should be valid (has removeJavaScript and removeEmbeddedFiles enabled)
|
||||||
expect(result.current.validateParameters()).toBe(true);
|
expect(result.current.validateParameters()).toBe(true);
|
||||||
@@ -71,7 +74,7 @@ describe('useSanitizeParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle all parameter types correctly', () => {
|
test('should handle all parameter types correctly', () => {
|
||||||
const { result } = renderHook(() => useSanitizeParameters());
|
const { result } = renderSanitizeHook();
|
||||||
|
|
||||||
const allParameters = Object.keys(defaultParameters) as (keyof typeof defaultParameters)[];
|
const allParameters = Object.keys(defaultParameters) as (keyof typeof defaultParameters)[];
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { useState, useCallback, Dispatch, SetStateAction } from 'react';
|
import { useState, useCallback, Dispatch, SetStateAction, useRef, useEffect } from 'react';
|
||||||
|
import { usePreferences } from '@app/contexts/PreferencesContext';
|
||||||
|
import { loadToolParameters, saveToolParameters } from '@app/services/toolParameterStorage';
|
||||||
|
|
||||||
export interface BaseParametersHook<T> {
|
export interface BaseParametersHook<T> {
|
||||||
parameters: T;
|
parameters: T;
|
||||||
@@ -13,10 +15,31 @@ export interface BaseParametersConfig<T> {
|
|||||||
defaultParameters: T;
|
defaultParameters: T;
|
||||||
endpointName: string | ((params: T) => string);
|
endpointName: string | ((params: T) => string);
|
||||||
validateFn?: (params: T) => boolean;
|
validateFn?: (params: T) => boolean;
|
||||||
|
storageKey?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useBaseParameters<T>(config: BaseParametersConfig<T>): BaseParametersHook<T> {
|
export function useBaseParameters<T>(config: BaseParametersConfig<T>): BaseParametersHook<T> {
|
||||||
const [parameters, setParameters] = useState<T>(config.defaultParameters);
|
const { preferences } = usePreferences();
|
||||||
|
const storageKey = config.storageKey ?? (typeof config.endpointName === 'string' ? config.endpointName : undefined);
|
||||||
|
|
||||||
|
const shouldPersist = Boolean(storageKey && preferences.rememberFormInputs);
|
||||||
|
const hasHydratedFromStorage = useRef(false);
|
||||||
|
|
||||||
|
const mergeWithDefaults = useCallback((values?: Partial<T>): T => ({
|
||||||
|
...(config.defaultParameters as T),
|
||||||
|
...(values ?? {}),
|
||||||
|
}), [config.defaultParameters]);
|
||||||
|
|
||||||
|
const [parameters, setParameters] = useState<T>(() => {
|
||||||
|
if (shouldPersist && storageKey) {
|
||||||
|
const stored = loadToolParameters<T>(storageKey);
|
||||||
|
if (stored) {
|
||||||
|
hasHydratedFromStorage.current = true;
|
||||||
|
return mergeWithDefaults(stored);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mergeWithDefaults();
|
||||||
|
});
|
||||||
|
|
||||||
const updateParameter = useCallback(<K extends keyof T>(parameter: K, value: T[K]) => {
|
const updateParameter = useCallback(<K extends keyof T>(parameter: K, value: T[K]) => {
|
||||||
setParameters(prev => ({
|
setParameters(prev => ({
|
||||||
@@ -33,6 +56,34 @@ export function useBaseParameters<T>(config: BaseParametersConfig<T>): BaseParam
|
|||||||
return config.validateFn ? config.validateFn(parameters) : true;
|
return config.validateFn ? config.validateFn(parameters) : true;
|
||||||
}, [parameters, config.validateFn]);
|
}, [parameters, config.validateFn]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!storageKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preferences.rememberFormInputs) {
|
||||||
|
hasHydratedFromStorage.current = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasHydratedFromStorage.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stored = loadToolParameters<T>(storageKey);
|
||||||
|
if (stored) {
|
||||||
|
setParameters(mergeWithDefaults(stored));
|
||||||
|
}
|
||||||
|
hasHydratedFromStorage.current = true;
|
||||||
|
}, [mergeWithDefaults, preferences.rememberFormInputs, storageKey]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!storageKey || !preferences.rememberFormInputs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
saveToolParameters(storageKey, parameters);
|
||||||
|
}, [parameters, preferences.rememberFormInputs, storageKey]);
|
||||||
|
|
||||||
const endpointName = config.endpointName;
|
const endpointName = config.endpointName;
|
||||||
let getEndpointName: () => string;
|
let getEndpointName: () => string;
|
||||||
if (typeof endpointName === "string") {
|
if (typeof endpointName === "string") {
|
||||||
|
|||||||
@@ -57,5 +57,6 @@ export const useSplitParameters = (): SplitParametersHook => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
storageKey: 'split',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export interface UserPreferences {
|
|||||||
toolPanelModePromptSeen: boolean;
|
toolPanelModePromptSeen: boolean;
|
||||||
showLegacyToolDescriptions: boolean;
|
showLegacyToolDescriptions: boolean;
|
||||||
hasCompletedOnboarding: boolean;
|
hasCompletedOnboarding: boolean;
|
||||||
|
rememberFormInputs: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_PREFERENCES: UserPreferences = {
|
export const DEFAULT_PREFERENCES: UserPreferences = {
|
||||||
@@ -19,6 +20,7 @@ export const DEFAULT_PREFERENCES: UserPreferences = {
|
|||||||
toolPanelModePromptSeen: false,
|
toolPanelModePromptSeen: false,
|
||||||
showLegacyToolDescriptions: false,
|
showLegacyToolDescriptions: false,
|
||||||
hasCompletedOnboarding: false,
|
hasCompletedOnboarding: false,
|
||||||
|
rememberFormInputs: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const STORAGE_KEY = 'stirlingpdf_preferences';
|
const STORAGE_KEY = 'stirlingpdf_preferences';
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
const STORAGE_KEY = 'stirlingpdf_tool_parameters';
|
||||||
|
|
||||||
|
type SerializableValue = string | number | boolean | null | SerializableValue[] | { [key: string]: SerializableValue };
|
||||||
|
|
||||||
|
const isFile = (value: unknown): value is File => typeof File !== 'undefined' && value instanceof File;
|
||||||
|
const isBlob = (value: unknown): value is Blob => typeof Blob !== 'undefined' && value instanceof Blob;
|
||||||
|
|
||||||
|
function sanitizeValue(value: unknown): SerializableValue | undefined {
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const valueType = typeof value;
|
||||||
|
|
||||||
|
if (valueType === 'string' || valueType === 'number' || valueType === 'boolean') {
|
||||||
|
if (valueType === 'number' && Number.isNaN(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return value as SerializableValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueType === 'undefined' || valueType === 'function' || valueType === 'symbol' || valueType === 'bigint') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
const sanitizedArray = value
|
||||||
|
.map((item) => sanitizeValue(item))
|
||||||
|
.filter((item) => item !== undefined) as SerializableValue[];
|
||||||
|
return sanitizedArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFile(value) || isBlob(value)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueType === 'object' && value !== null) {
|
||||||
|
const entries = Object.entries(value as Record<string, unknown>);
|
||||||
|
const sanitizedEntries: Record<string, SerializableValue> = {};
|
||||||
|
|
||||||
|
for (const [key, entryValue] of entries) {
|
||||||
|
const sanitized = sanitizeValue(entryValue);
|
||||||
|
if (sanitized !== undefined) {
|
||||||
|
sanitizedEntries[key] = sanitized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sanitizedEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readStorage(): Record<string, SerializableValue> {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(STORAGE_KEY);
|
||||||
|
if (!raw) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
if (typeof parsed === 'object' && parsed !== null) {
|
||||||
|
return parsed as Record<string, SerializableValue>;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[toolParameterStorage] Failed to read stored parameters', error);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeStorage(map: Record<string, SerializableValue>): void {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(map));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[toolParameterStorage] Failed to write stored parameters', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadToolParameters<T>(toolKey: string): Partial<T> | null {
|
||||||
|
const storage = readStorage();
|
||||||
|
const stored = storage[toolKey];
|
||||||
|
|
||||||
|
if (!stored || typeof stored !== 'object') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stored as Partial<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveToolParameters<T>(toolKey: string, parameters: T): void {
|
||||||
|
const sanitized = sanitizeValue(parameters);
|
||||||
|
if (sanitized === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storage = readStorage();
|
||||||
|
storage[toolKey] = sanitized;
|
||||||
|
writeStorage(storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearToolParameters(toolKey: string): void {
|
||||||
|
const storage = readStorage();
|
||||||
|
if (Object.prototype.hasOwnProperty.call(storage, toolKey)) {
|
||||||
|
delete storage[toolKey];
|
||||||
|
writeStorage(storage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearAllToolParameters(): void {
|
||||||
|
try {
|
||||||
|
localStorage.removeItem(STORAGE_KEY);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[toolParameterStorage] Failed to clear stored parameters', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { PreferencesProvider } from '@app/contexts/PreferencesContext';
|
||||||
|
|
||||||
|
export const PreferencesTestWrapper = ({ children }: { children: React.ReactNode }) => (
|
||||||
|
<PreferencesProvider>{children}</PreferencesProvider>
|
||||||
|
);
|
||||||
@@ -4,7 +4,8 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"@app/*": [
|
"@app/*": [
|
||||||
"src/core/*"
|
"src/core/*"
|
||||||
]
|
],
|
||||||
|
"@testing/*": ["src/testing/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
],
|
],
|
||||||
"@desktop/*": ["src/desktop/*"],
|
"@desktop/*": ["src/desktop/*"],
|
||||||
"@proprietary/*": ["src/proprietary/*"],
|
"@proprietary/*": ["src/proprietary/*"],
|
||||||
"@core/*": ["src/core/*"]
|
"@core/*": ["src/core/*"],
|
||||||
|
"@testing/*": ["src/testing/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"src/proprietary/*",
|
"src/proprietary/*",
|
||||||
"src/core/*"
|
"src/core/*"
|
||||||
],
|
],
|
||||||
|
"@testing/*": ["src/testing/*"],
|
||||||
"@desktop/*": ["src/desktop/*"],
|
"@desktop/*": ["src/desktop/*"],
|
||||||
"@proprietary/*": ["src/proprietary/*"],
|
"@proprietary/*": ["src/proprietary/*"],
|
||||||
"@core/*": ["src/core/*"]
|
"@core/*": ["src/core/*"]
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
"src/proprietary/*",
|
"src/proprietary/*",
|
||||||
"src/core/*"
|
"src/core/*"
|
||||||
],
|
],
|
||||||
"@core/*": ["src/core/*"]
|
"@core/*": ["src/core/*"],
|
||||||
|
"@testing/*": ["src/testing/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
|||||||
Reference in New Issue
Block a user