Skip to content

Commit aba2133

Browse files
committed
tests: types tests
1 parent 742970d commit aba2133

1 file changed

Lines changed: 173 additions & 17 deletions

File tree

react/src/hook.test.ts

Lines changed: 173 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
1+
import { describe, it, expect, vi, beforeEach, afterEach, expectTypeOf } from 'vitest';
22
import { renderHook } from '@testing-library/react';
33
import { sendEvent, useEmbed, EmbedActions } from './hook';
44

@@ -232,22 +232,6 @@ describe('useEmbed', () => {
232232
expect(result.current.embedRef.current).toBeNull();
233233
expect(result.current.actions).toBeDefined();
234234
});
235-
236-
it('exposes all action methods', () => {
237-
const { result } = renderHook(() => useEmbed());
238-
239-
const expectedActions: (keyof EmbedActions)[] = [
240-
'goTo',
241-
'selectTool',
242-
'createField',
243-
'clearFields',
244-
'getDocumentContent',
245-
'submit',
246-
];
247-
expectedActions.forEach((action) => {
248-
expect(typeof result.current.actions[action]).toBe('function');
249-
});
250-
});
251235
});
252236

253237
describe('actions without ref attached', () => {
@@ -393,3 +377,175 @@ describe('useEmbed', () => {
393377
expect(result.current.actions.submit).toBe(initialActions.submit);
394378
});
395379
});
380+
381+
describe('Type assertions', () => {
382+
// These types are intentionally inlined to act as a "frozen" contract.
383+
// If the actual types change, these tests will fail at compile time.
384+
385+
type ExpectedToolType = 'TEXT' | 'BOXED_TEXT' | 'CHECKBOX' | 'PICTURE' | 'SIGNATURE';
386+
387+
type ExpectedBaseFieldOptions = {
388+
page: number;
389+
x: number;
390+
y: number;
391+
width: number;
392+
height: number;
393+
};
394+
395+
type ExpectedTextFieldOptions = ExpectedBaseFieldOptions & {
396+
type: 'TEXT' | 'BOXED_TEXT';
397+
value?: string;
398+
};
399+
400+
type ExpectedCheckboxFieldOptions = ExpectedBaseFieldOptions & {
401+
type: 'CHECKBOX';
402+
value?: 'checked' | 'unchecked';
403+
};
404+
405+
type ExpectedPictureFieldOptions = ExpectedBaseFieldOptions & {
406+
type: 'PICTURE';
407+
value?: string;
408+
};
409+
410+
type ExpectedSignatureFieldOptions = ExpectedBaseFieldOptions & {
411+
type: 'SIGNATURE';
412+
value?: string;
413+
};
414+
415+
type ExpectedCreateFieldOptions =
416+
| ExpectedTextFieldOptions
417+
| ExpectedCheckboxFieldOptions
418+
| ExpectedPictureFieldOptions
419+
| ExpectedSignatureFieldOptions;
420+
421+
type ExpectedErrorResult = {
422+
success: false;
423+
error: { code: string; message: string };
424+
};
425+
426+
type ExpectedSuccessResult<TData = undefined> = TData extends undefined
427+
? { success: true }
428+
: { success: true; data: TData };
429+
430+
type ExpectedActionResult<TData = undefined> = ExpectedSuccessResult<TData> | ExpectedErrorResult;
431+
432+
describe('EmbedActions', () => {
433+
it('goTo accepts { page: number } and returns ActionResult', () => {
434+
expectTypeOf<EmbedActions['goTo']>().parameter(0).toEqualTypeOf<{ page: number }>();
435+
expectTypeOf<EmbedActions['goTo']>().returns.resolves.toExtend<ExpectedActionResult>();
436+
});
437+
438+
it('selectTool accepts ToolType | null and returns ActionResult', () => {
439+
expectTypeOf<EmbedActions['selectTool']>().parameter(0).toEqualTypeOf<ExpectedToolType | null>();
440+
expectTypeOf<EmbedActions['selectTool']>().returns.resolves.toExtend<ExpectedActionResult>();
441+
});
442+
443+
it('createField accepts CreateFieldOptions and returns ActionResult with field_id', () => {
444+
expectTypeOf<EmbedActions['createField']>().parameter(0).toEqualTypeOf<ExpectedCreateFieldOptions>();
445+
expectTypeOf<EmbedActions['createField']>().returns.resolves.toExtend<
446+
ExpectedActionResult<{ field_id: string }>
447+
>();
448+
});
449+
450+
it('clearFields accepts optional { fieldIds?, page? } and returns ActionResult with cleared_count', () => {
451+
expectTypeOf<EmbedActions['clearFields']>()
452+
.parameter(0)
453+
.toEqualTypeOf<{ fieldIds?: string[]; page?: number } | undefined>();
454+
expectTypeOf<EmbedActions['clearFields']>().returns.resolves.toExtend<
455+
ExpectedActionResult<{ cleared_count: number }>
456+
>();
457+
});
458+
459+
it('getDocumentContent requires { extractionMode } and returns ActionResult with document content', () => {
460+
expectTypeOf<EmbedActions['getDocumentContent']>().parameter(0).toEqualTypeOf<{
461+
extractionMode: 'auto' | 'ocr';
462+
}>();
463+
expectTypeOf<EmbedActions['getDocumentContent']>().returns.resolves.toExtend<
464+
ExpectedActionResult<{ name: string; pages: { page: number; content: string }[] }>
465+
>();
466+
});
467+
468+
it('submit requires { downloadCopyOnDevice } and returns ActionResult', () => {
469+
expectTypeOf<EmbedActions['submit']>().parameter(0).toEqualTypeOf<{ downloadCopyOnDevice: boolean }>();
470+
expectTypeOf<EmbedActions['submit']>().returns.resolves.toExtend<ExpectedActionResult>();
471+
});
472+
});
473+
474+
describe('createField discriminated union', () => {
475+
it('TEXT field options are accepted', () => {
476+
const textField = {
477+
type: 'TEXT' as const,
478+
page: 1,
479+
x: 0,
480+
y: 0,
481+
width: 100,
482+
height: 20,
483+
value: 'hello',
484+
};
485+
expectTypeOf(textField).toExtend<ExpectedCreateFieldOptions>();
486+
});
487+
488+
it('BOXED_TEXT field options are accepted', () => {
489+
const boxedTextField = {
490+
type: 'BOXED_TEXT' as const,
491+
page: 1,
492+
x: 0,
493+
y: 0,
494+
width: 100,
495+
height: 20,
496+
value: 'hello',
497+
};
498+
expectTypeOf(boxedTextField).toExtend<ExpectedCreateFieldOptions>();
499+
});
500+
501+
it('CHECKBOX field accepts only checked/unchecked values', () => {
502+
const checkedField = {
503+
type: 'CHECKBOX' as const,
504+
page: 1,
505+
x: 0,
506+
y: 0,
507+
width: 20,
508+
height: 20,
509+
value: 'checked' as const,
510+
};
511+
expectTypeOf(checkedField).toExtend<ExpectedCreateFieldOptions>();
512+
513+
const uncheckedField = {
514+
type: 'CHECKBOX' as const,
515+
page: 1,
516+
x: 0,
517+
y: 0,
518+
width: 20,
519+
height: 20,
520+
value: 'unchecked' as const,
521+
};
522+
expectTypeOf(uncheckedField).toExtend<ExpectedCreateFieldOptions>();
523+
});
524+
525+
it('PICTURE field options are accepted', () => {
526+
const pictureField = {
527+
type: 'PICTURE' as const,
528+
page: 1,
529+
x: 0,
530+
y: 0,
531+
width: 100,
532+
height: 100,
533+
value: 'data:image/png;base64,...',
534+
};
535+
expectTypeOf(pictureField).toExtend<ExpectedCreateFieldOptions>();
536+
});
537+
538+
it('SIGNATURE field options are accepted', () => {
539+
const signatureField = {
540+
type: 'SIGNATURE' as const,
541+
page: 1,
542+
x: 0,
543+
y: 0,
544+
width: 150,
545+
height: 50,
546+
value: 'John Doe',
547+
};
548+
expectTypeOf(signatureField).toExtend<ExpectedCreateFieldOptions>();
549+
});
550+
});
551+
});

0 commit comments

Comments
 (0)