diff --git a/src/js/logic/add-watermark.ts b/src/js/logic/add-watermark.ts
index 537e368..61d5a20 100644
--- a/src/js/logic/add-watermark.ts
+++ b/src/js/logic/add-watermark.ts
@@ -4,7 +4,7 @@ import {
readFileAsArrayBuffer,
hexToRgb,
} from '../utils/helpers.js';
-import { state } from '../state.js';
+import { state, resetState } from '../state.js';
import {
PDFDocument as PDFLibDocument,
@@ -175,6 +175,15 @@ export async function addWatermark() {
new Blob([newPdfBytes], { type: 'application/pdf' }),
'watermarked.pdf'
);
+
+ const toolid = state.activeTool;
+ resetState();
+ if (toolid) {
+ const element = document.querySelector(
+ `[data-tool-id="${toolid}"]`
+ ) as HTMLElement;
+ if (element) element.click();
+ }
} catch (e) {
console.error(e);
showAlert(
diff --git a/src/tests/watermark.test.ts b/src/tests/watermark.test.ts
new file mode 100644
index 0000000..8100760
--- /dev/null
+++ b/src/tests/watermark.test.ts
@@ -0,0 +1,227 @@
+import { describe, it, expect, beforeEach } from 'vitest';
+import { state, resetState } from '../js/state';
+
+describe('Watermark Feature', () => {
+ beforeEach(() => {
+ document.body.innerHTML = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ state.activeTool = 'add-watermark';
+ state.files = [];
+ state.pdfDoc = null;
+ state.pdfPages = [];
+ state.currentPdfUrl = null;
+ });
+
+ describe('resetState', () => {
+ it('should clear watermark text input after reset', () => {
+ const watermarkText = document.getElementById(
+ 'watermark-text'
+ ) as HTMLInputElement;
+ watermarkText.value = 'CONFIDENTIAL';
+
+ resetState();
+
+ expect(state.activeTool).toBe(null);
+ expect(state.files).toEqual([]);
+ expect(state.pdfDoc).toBe(null);
+ expect(state.pdfPages).toEqual([]);
+ expect(state.currentPdfUrl).toBe(null);
+ });
+
+ it('should reset state files array', () => {
+ state.files = [new File(['content'], 'test.pdf')];
+
+ resetState();
+
+ expect(state.files).toEqual([]);
+ });
+
+ it('should reset activeTool to null', () => {
+ state.activeTool = 'add-watermark';
+
+ resetState();
+
+ expect(state.activeTool).toBe(null);
+ });
+
+ it('should reset pdfDoc to null', () => {
+ state.pdfDoc = {} as any;
+
+ resetState();
+
+ expect(state.pdfDoc).toBe(null);
+ });
+
+ it('should reset pdfPages array', () => {
+ state.pdfPages = [1, 2, 3] as any;
+
+ resetState();
+
+ expect(state.pdfPages).toEqual([]);
+ });
+
+ it('should reset currentPdfUrl to null', () => {
+ state.currentPdfUrl = 'blob:http://example.com/123';
+
+ resetState();
+
+ expect(state.currentPdfUrl).toBe(null);
+ });
+
+ it('should clear tool-content innerHTML', () => {
+ const toolContent = document.getElementById('tool-content');
+ if (toolContent) toolContent.innerHTML = 'Some content
';
+
+ resetState();
+
+ expect(toolContent?.innerHTML).toBe('');
+ });
+ });
+
+ describe('Watermark Type Toggle', () => {
+ it('should show text options by default', () => {
+ const textOptions = document.getElementById('text-watermark-options');
+ const imageOptions = document.getElementById('image-watermark-options');
+
+ expect(imageOptions?.classList.contains('hidden')).toBe(true);
+ expect(textOptions?.classList.contains('hidden')).toBe(false);
+ });
+
+ it('should have text radio checked by default', () => {
+ const textRadio = document.querySelector(
+ 'input[name="watermark-type"][value="text"]'
+ ) as HTMLInputElement;
+ const imageRadio = document.querySelector(
+ 'input[name="watermark-type"][value="image"]'
+ ) as HTMLInputElement;
+
+ expect(textRadio.checked).toBe(true);
+ expect(imageRadio.checked).toBe(false);
+ });
+ });
+
+ describe('Watermark Input Validation', () => {
+ it('should accept valid font size', () => {
+ const fontSize = document.getElementById('font-size') as HTMLInputElement;
+ fontSize.value = '48';
+
+ expect(parseInt(fontSize.value)).toBeGreaterThan(0);
+ expect(parseInt(fontSize.value)).toBeLessThanOrEqual(200);
+ });
+
+ it('should have default font size of 72', () => {
+ const fontSize = document.getElementById('font-size') as HTMLInputElement;
+
+ expect(parseInt(fontSize.value)).toBe(72);
+ });
+
+ it('should accept valid opacity range', () => {
+ const opacity = document.getElementById(
+ 'opacity-text'
+ ) as HTMLInputElement;
+ opacity.value = '0.5';
+
+ const opacityValue = parseFloat(opacity.value);
+ expect(opacityValue).toBeGreaterThanOrEqual(0);
+ expect(opacityValue).toBeLessThanOrEqual(1);
+ });
+
+ it('should have default opacity of 0.3', () => {
+ const opacity = document.getElementById(
+ 'opacity-text'
+ ) as HTMLInputElement;
+
+ expect(parseFloat(opacity.value)).toBe(0.3);
+ });
+
+ it('should accept valid angle range', () => {
+ const angle = document.getElementById('angle-text') as HTMLInputElement;
+ angle.value = '45';
+
+ const angleValue = parseInt(angle.value);
+ expect(angleValue).toBeGreaterThanOrEqual(-180);
+ expect(angleValue).toBeLessThanOrEqual(180);
+ });
+
+ it('should have default angle of 0', () => {
+ const angle = document.getElementById('angle-text') as HTMLInputElement;
+
+ expect(parseInt(angle.value)).toBe(0);
+ });
+
+ it('should accept valid hex color', () => {
+ const textColor = document.getElementById(
+ 'text-color'
+ ) as HTMLInputElement;
+ textColor.value = '#FF5733';
+
+ expect(textColor.value).toMatch(/^#[0-9A-F]{6}$/i);
+ });
+
+ it('should have default color of black', () => {
+ const textColor = document.getElementById(
+ 'text-color'
+ ) as HTMLInputElement;
+
+ expect(textColor.value).toBe('#000000');
+ });
+ });
+
+ describe('State Management', () => {
+ it('should maintain activeTool as add-watermark', () => {
+ expect(state.activeTool).toBe('add-watermark');
+ });
+
+ it('should start with empty files array', () => {
+ expect(state.files).toEqual([]);
+ });
+
+ it('should allow adding files to state', () => {
+ const file = new File(['content'], 'test.pdf', {
+ type: 'application/pdf',
+ });
+ state.files.push(file);
+
+ expect(state.files.length).toBe(1);
+ expect(state.files[0].name).toBe('test.pdf');
+ });
+ });
+
+ describe('UI Elements State', () => {
+ it('should have process button disabled by default', () => {
+ const processBtn = document.getElementById(
+ 'process-btn'
+ ) as HTMLButtonElement;
+
+ expect(processBtn.disabled).toBe(true);
+ });
+
+ it('should have file controls hidden by default', () => {
+ const fileControls = document.getElementById('file-controls');
+
+ expect(fileControls?.classList.contains('hidden')).toBe(true);
+ });
+
+ it('should have image watermark options hidden by default', () => {
+ const imageOptions = document.getElementById('image-watermark-options');
+
+ expect(imageOptions?.classList.contains('hidden')).toBe(true);
+ });
+ });
+});