diff --git a/frontend/src/components/tools/removePassword/RemovePasswordSettings.test.tsx b/frontend/src/components/tools/removePassword/RemovePasswordSettings.test.tsx
new file mode 100644
index 000000000..9aac9cd31
--- /dev/null
+++ b/frontend/src/components/tools/removePassword/RemovePasswordSettings.test.tsx
@@ -0,0 +1,127 @@
+import { describe, expect, test, vi, beforeEach } from 'vitest';
+import { render, screen, fireEvent } from '@testing-library/react';
+import { MantineProvider } from '@mantine/core';
+import RemovePasswordSettings from './RemovePasswordSettings';
+import { defaultParameters } from '../../../hooks/tools/removePassword/useRemovePasswordParameters';
+
+// Mock useTranslation with predictable return values
+const mockT = vi.fn((key: string) => `mock-${key}`);
+vi.mock('react-i18next', () => ({
+ useTranslation: () => ({ t: mockT })
+}));
+
+// Wrapper component to provide Mantine context
+const TestWrapper = ({ children }: { children: React.ReactNode }) => (
+ {children}
+);
+
+describe('RemovePasswordSettings', () => {
+ const mockOnParameterChange = vi.fn();
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ test('should render password input field', () => {
+ render(
+
+
+
+ );
+
+ expect(screen.getByText('mock-removePassword.password.label')).toBeInTheDocument();
+ });
+
+ test('should call onParameterChange when password is entered', () => {
+ render(
+
+
+
+ );
+
+ const passwordInput = screen.getByPlaceholderText('mock-removePassword.password.placeholder');
+ fireEvent.change(passwordInput, { target: { value: 'test-password' } });
+
+ expect(mockOnParameterChange).toHaveBeenCalledWith('password', 'test-password');
+ });
+
+ test('should display current password value', () => {
+ const parametersWithPassword = { ...defaultParameters, password: 'current-password' };
+
+ render(
+
+
+
+ );
+
+ const passwordInput = screen.getByPlaceholderText('mock-removePassword.password.placeholder') as HTMLInputElement;
+ expect(passwordInput.value).toBe('current-password');
+ });
+
+ test('should disable password input when disabled prop is true', () => {
+ render(
+
+
+
+ );
+
+ const passwordInput = screen.getByPlaceholderText('mock-removePassword.password.placeholder');
+ expect(passwordInput).toBeDisabled();
+ });
+
+ test('should enable password input when disabled prop is false', () => {
+ render(
+
+
+
+ );
+
+ const passwordInput = screen.getByPlaceholderText('mock-removePassword.password.placeholder');
+ expect(passwordInput).not.toBeDisabled();
+ });
+
+ test('should show password input as required', () => {
+ render(
+
+
+
+ );
+
+ const passwordInput = screen.getByPlaceholderText('mock-removePassword.password.placeholder');
+ expect(passwordInput).toHaveAttribute('required');
+ });
+
+ test('should call translation function with correct keys', () => {
+ render(
+
+
+
+ );
+
+ expect(mockT).toHaveBeenCalledWith('removePassword.password.label', 'Current Password');
+ expect(mockT).toHaveBeenCalledWith('removePassword.password.placeholder', 'Enter current password');
+ });
+});
diff --git a/frontend/src/hooks/tools/removePassword/useRemovePasswordOperation.test.ts b/frontend/src/hooks/tools/removePassword/useRemovePasswordOperation.test.ts
new file mode 100644
index 000000000..66cd240fc
--- /dev/null
+++ b/frontend/src/hooks/tools/removePassword/useRemovePasswordOperation.test.ts
@@ -0,0 +1,104 @@
+import { describe, expect, test, vi, beforeEach } from 'vitest';
+import { renderHook } from '@testing-library/react';
+import { useRemovePasswordOperation } from './useRemovePasswordOperation';
+import type { RemovePasswordParameters } from './useRemovePasswordParameters';
+
+// Mock the useToolOperation hook
+vi.mock('../shared/useToolOperation', () => ({
+ useToolOperation: vi.fn()
+}));
+
+// Mock the translation hook
+const mockT = vi.fn((key: string) => `translated-${key}`);
+vi.mock('react-i18next', () => ({
+ useTranslation: () => ({ t: mockT })
+}));
+
+// Mock the error handler
+vi.mock('../../../utils/toolErrorHandler', () => ({
+ createStandardErrorHandler: vi.fn(() => 'error-handler-function')
+}));
+
+// Import the mocked function
+import { ToolOperationConfig, ToolOperationHook, useToolOperation } from '../shared/useToolOperation';
+
+describe('useRemovePasswordOperation', () => {
+ const mockUseToolOperation = vi.mocked(useToolOperation);
+
+ const getToolConfig = (): ToolOperationConfig => mockUseToolOperation.mock.calls[0][0];
+
+ const mockToolOperationReturn: ToolOperationHook = {
+ files: [],
+ thumbnails: [],
+ downloadUrl: null,
+ downloadFilename: '',
+ isLoading: false,
+ errorMessage: null,
+ status: '',
+ isGeneratingThumbnails: false,
+ progress: null,
+ executeOperation: vi.fn(),
+ resetResults: vi.fn(),
+ clearError: vi.fn(),
+ cancelOperation: vi.fn(),
+ };
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ mockUseToolOperation.mockReturnValue(mockToolOperationReturn);
+ });
+
+ test.each([
+ {
+ description: 'with valid password',
+ password: 'test-password'
+ },
+ {
+ description: 'with complex password',
+ password: 'C0mpl3x@P@ssw0rd!'
+ },
+ {
+ description: 'with single character password',
+ password: 'a'
+ }
+ ])('should create form data correctly $description', ({ password }) => {
+ renderHook(() => useRemovePasswordOperation());
+
+ const callArgs = getToolConfig();
+ const buildFormData = callArgs.buildFormData;
+
+ const testParameters: RemovePasswordParameters = {
+ password
+ };
+
+ const testFile = new File(['test content'], 'test.pdf', { type: 'application/pdf' });
+ const formData = buildFormData(testParameters, testFile as any);
+
+ // Verify the form data contains the file
+ expect(formData.get('fileInput')).toBe(testFile);
+
+ // Verify password parameter
+ expect(formData.get('password')).toBe(password);
+ });
+
+ test('should use correct translation for error messages', () => {
+ renderHook(() => useRemovePasswordOperation());
+
+ expect(mockT).toHaveBeenCalledWith(
+ 'removePassword.error.failed',
+ 'An error occurred while removing the password from the PDF.'
+ );
+ });
+
+ test.each([
+ { property: 'multiFileEndpoint' as const, expectedValue: false },
+ { property: 'endpoint' as const, expectedValue: '/api/v1/security/remove-password' },
+ { property: 'filePrefix' as const, expectedValue: 'translated-removePassword.filenamePrefix_' },
+ { property: 'operationType' as const, expectedValue: 'removePassword' }
+ ])('should configure $property correctly', ({ property, expectedValue }) => {
+ renderHook(() => useRemovePasswordOperation());
+
+ const callArgs = getToolConfig();
+ expect(callArgs[property]).toBe(expectedValue);
+ });
+});
diff --git a/frontend/src/hooks/tools/removePassword/useRemovePasswordParameters.test.ts b/frontend/src/hooks/tools/removePassword/useRemovePasswordParameters.test.ts
new file mode 100644
index 000000000..f7310847b
--- /dev/null
+++ b/frontend/src/hooks/tools/removePassword/useRemovePasswordParameters.test.ts
@@ -0,0 +1,81 @@
+import { describe, expect, test } from 'vitest';
+import { renderHook, act } from '@testing-library/react';
+import { useRemovePasswordParameters, defaultParameters } from './useRemovePasswordParameters';
+
+describe('useRemovePasswordParameters', () => {
+ test('should initialize with default parameters', () => {
+ const { result } = renderHook(() => useRemovePasswordParameters());
+
+ expect(result.current.parameters).toStrictEqual(defaultParameters);
+ });
+
+ test('should update password parameter', () => {
+ const { result } = renderHook(() => useRemovePasswordParameters());
+
+ act(() => {
+ result.current.updateParameter('password', 'test-password');
+ });
+
+ expect(result.current.parameters.password).toBe('test-password');
+ });
+
+ test('should reset parameters to defaults', () => {
+ const { result } = renderHook(() => useRemovePasswordParameters());
+
+ // First, change the password
+ act(() => {
+ result.current.updateParameter('password', 'test-password');
+ });
+
+ expect(result.current.parameters.password).toBe('test-password');
+
+ // Then reset
+ act(() => {
+ result.current.resetParameters();
+ });
+
+ expect(result.current.parameters).toStrictEqual(defaultParameters);
+ });
+
+ test('should return correct endpoint name', () => {
+ const { result } = renderHook(() => useRemovePasswordParameters());
+
+ expect(result.current.getEndpointName()).toBe('remove-password');
+ });
+
+ test.each([
+ {
+ description: 'with valid password',
+ password: 'valid-password',
+ expectedValid: true
+ },
+ {
+ description: 'with empty password',
+ password: '',
+ expectedValid: false
+ },
+ {
+ description: 'with whitespace only password',
+ password: ' \t ',
+ expectedValid: true
+ },
+ {
+ description: 'with password containing special characters',
+ password: 'p@ssw0rd!',
+ expectedValid: true
+ },
+ {
+ description: 'with single character password',
+ password: 'a',
+ expectedValid: true
+ }
+ ])('should validate parameters correctly $description', ({ password, expectedValid }) => {
+ const { result } = renderHook(() => useRemovePasswordParameters());
+
+ act(() => {
+ result.current.updateParameter('password', password);
+ });
+
+ expect(result.current.validateParameters()).toBe(expectedValid);
+ });
+});