mirror of
https://github.com/pdfme/pdfme.git
synced 2026-06-16 02:09:10 -04:00
802 lines
24 KiB
TypeScript
802 lines
24 KiB
TypeScript
import {
|
|
SchemaForUI,
|
|
Schema,
|
|
Template,
|
|
BLANK_PDF,
|
|
BasePdf,
|
|
PAGE_SIZE_PRESETS,
|
|
ZOOM,
|
|
pluginRegistry,
|
|
} from '@pdfme/common';
|
|
import {
|
|
uuid,
|
|
getUniqueSchemaName,
|
|
schemasList2template,
|
|
changeSchemas,
|
|
clampZoomLevel,
|
|
getFitZoomLevel,
|
|
getZoomAnchor,
|
|
getDynamicHeightReflowChanges,
|
|
restoreZoomAnchor,
|
|
setFontNameRecursively,
|
|
} from '../src/helper';
|
|
import { text, image } from '@pdfme/schemas';
|
|
|
|
const getSchema = (): Schema => ({
|
|
name: 'a',
|
|
type: 'text',
|
|
content: '',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
});
|
|
|
|
describe('getUniqSchemaName test', () => {
|
|
test('getUniqSchemaName case1', () => {
|
|
const copiedSchemaName = 'a';
|
|
const schema: SchemaForUI[] = [{ id: uuid(), ...getSchema(), name: 'b', content: 'b' }];
|
|
const stackUniqSchemaNames: string[] = [];
|
|
const uniqSchemaName = getUniqueSchemaName({
|
|
copiedSchemaName,
|
|
schema,
|
|
stackUniqueSchemaNames: stackUniqSchemaNames,
|
|
});
|
|
expect(uniqSchemaName).toBe('a copy');
|
|
});
|
|
|
|
test('getUniqSchemaName case2', () => {
|
|
const copiedSchemaName = 'a copy';
|
|
const schema: SchemaForUI[] = [{ id: uuid(), ...getSchema(), name: 'a copy', content: 'a' }];
|
|
const stackUniqSchemaNames: string[] = [];
|
|
const uniqSchemaName = getUniqueSchemaName({
|
|
copiedSchemaName,
|
|
schema,
|
|
stackUniqueSchemaNames: stackUniqSchemaNames,
|
|
});
|
|
expect(uniqSchemaName).toBe('a copy 2');
|
|
});
|
|
|
|
test('getUniqSchemaName case3', () => {
|
|
const copiedSchemaName = 'a';
|
|
const schema: SchemaForUI[] = [
|
|
{ id: uuid(), ...getSchema(), name: 'a', content: 'a' },
|
|
{ id: uuid(), ...getSchema(), name: 'a copy 2', content: 'a' },
|
|
];
|
|
const stackUniqSchemaNames: string[] = [];
|
|
const uniqSchemaName = getUniqueSchemaName({
|
|
copiedSchemaName,
|
|
schema,
|
|
stackUniqueSchemaNames: stackUniqSchemaNames,
|
|
});
|
|
expect(uniqSchemaName).toBe('a copy 3');
|
|
});
|
|
|
|
test('getUniqSchemaName case4', () => {
|
|
const copiedSchemaName = 'a';
|
|
const schema: SchemaForUI[] = [
|
|
{ id: uuid(), ...getSchema(), name: 'a', content: 'a' },
|
|
{ id: uuid(), ...getSchema(), name: 'a copy 2', content: 'a' },
|
|
];
|
|
const stackUniqSchemaNames: string[] = ['a copy 3'];
|
|
const uniqSchemaName = getUniqueSchemaName({
|
|
copiedSchemaName,
|
|
schema,
|
|
stackUniqueSchemaNames: stackUniqSchemaNames,
|
|
});
|
|
expect(uniqSchemaName).toBe('a copy 4');
|
|
});
|
|
|
|
test('getUniqSchemaName case5', () => {
|
|
const copiedSchemaName = 'a';
|
|
const schema: SchemaForUI[] = [
|
|
{ id: uuid(), ...getSchema(), name: 'a', content: 'a' },
|
|
{ id: uuid(), ...getSchema(), name: 'a copy 3', content: 'a' },
|
|
];
|
|
const stackUniqSchemaNames: string[] = [];
|
|
const uniqSchemaName = getUniqueSchemaName({
|
|
copiedSchemaName,
|
|
schema,
|
|
stackUniqueSchemaNames: stackUniqSchemaNames,
|
|
});
|
|
expect(uniqSchemaName).toBe('a copy 4');
|
|
});
|
|
|
|
test('getUniqSchemaName case6', () => {
|
|
const copiedSchemaName = 'a';
|
|
const schema: SchemaForUI[] = [
|
|
{ id: uuid(), ...getSchema(), name: 'a', content: 'a' },
|
|
{ id: uuid(), ...getSchema(), name: 'a copy 3', content: 'a' },
|
|
];
|
|
const stackUniqSchemaNames: string[] = ['a copy 4'];
|
|
const uniqSchemaName = getUniqueSchemaName({
|
|
copiedSchemaName,
|
|
schema,
|
|
stackUniqueSchemaNames: stackUniqSchemaNames,
|
|
});
|
|
expect(uniqSchemaName).toBe('a copy 5');
|
|
});
|
|
|
|
test('getUniqSchemaName case7', () => {
|
|
const copiedSchemaName = 'a';
|
|
const schema: SchemaForUI[] = [{ id: uuid(), ...getSchema(), name: 'a', content: 'a' }];
|
|
const stackUniqSchemaNames: string[] = ['a copy 2', 'a copy 3', 'a copy 4'];
|
|
const uniqSchemaName = getUniqueSchemaName({
|
|
copiedSchemaName,
|
|
schema,
|
|
stackUniqueSchemaNames: stackUniqSchemaNames,
|
|
});
|
|
expect(uniqSchemaName).toBe('a copy 5');
|
|
});
|
|
|
|
test('getUniqSchemaName case8', () => {
|
|
const copiedSchemaName = 'a copy 2';
|
|
const schema: SchemaForUI[] = [{ id: uuid(), ...getSchema(), name: 'a copy 2', content: 'a' }];
|
|
const stackUniqSchemaNames: string[] = ['a copy 3'];
|
|
const uniqSchemaName = getUniqueSchemaName({
|
|
copiedSchemaName,
|
|
schema,
|
|
stackUniqueSchemaNames: stackUniqSchemaNames,
|
|
});
|
|
expect(uniqSchemaName).toBe('a copy 4');
|
|
});
|
|
|
|
test('getUniqSchemaName case9', () => {
|
|
const copiedSchemaName = 'a copy 9';
|
|
const schema: SchemaForUI[] = [{ id: uuid(), ...getSchema(), name: 'a copy 9', content: 'a' }];
|
|
const stackUniqSchemaNames: string[] = ['a copy 10'];
|
|
const uniqSchemaName = getUniqueSchemaName({
|
|
copiedSchemaName,
|
|
schema,
|
|
stackUniqueSchemaNames: stackUniqSchemaNames,
|
|
});
|
|
expect(uniqSchemaName).toBe('a copy 11');
|
|
});
|
|
|
|
test('getUniqSchemaName case10', () => {
|
|
const copiedSchemaName = 'a copy 10';
|
|
const schema: SchemaForUI[] = [{ id: uuid(), ...getSchema(), name: 'a copy 10', content: 'a' }];
|
|
const stackUniqSchemaNames: string[] = [];
|
|
const uniqSchemaName = getUniqueSchemaName({
|
|
copiedSchemaName,
|
|
schema,
|
|
stackUniqueSchemaNames: stackUniqSchemaNames,
|
|
});
|
|
expect(uniqSchemaName).toBe('a copy 11');
|
|
});
|
|
});
|
|
|
|
describe('schemasList2template test', () => {
|
|
test('schemasList2template normal', () => {
|
|
const template: Template = {
|
|
basePdf: BLANK_PDF,
|
|
schemas: [[getSchema()]],
|
|
};
|
|
const schemasList: SchemaForUI[][] = [
|
|
[{ id: uuid(), ...getSchema(), name: 'b', content: 'b' }],
|
|
];
|
|
expect(schemasList2template(schemasList, template.basePdf)).toStrictEqual({
|
|
basePdf: BLANK_PDF,
|
|
schemas: [
|
|
[
|
|
{
|
|
name: 'b',
|
|
type: 'text',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
content: 'b',
|
|
},
|
|
],
|
|
],
|
|
});
|
|
});
|
|
|
|
test('schemasList2template readOnly', () => {
|
|
const template: Template = {
|
|
basePdf: BLANK_PDF,
|
|
schemas: [[getSchema()]],
|
|
};
|
|
const schemasList: SchemaForUI[][] = [
|
|
[{ id: uuid(), readOnly: true, ...getSchema(), name: 'b', content: 'b' }],
|
|
];
|
|
expect(schemasList2template(schemasList, template.basePdf)).toStrictEqual({
|
|
basePdf: BLANK_PDF,
|
|
schemas: [
|
|
[
|
|
{
|
|
name: 'b',
|
|
type: 'text',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
readOnly: true,
|
|
content: 'b',
|
|
},
|
|
],
|
|
],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('changeSchemas test', () => {
|
|
const schemaA = { id: uuid(), ...getSchema(), name: 'a', content: 'a' };
|
|
const schemaB = { id: uuid(), ...getSchema(), name: 'b', content: 'b' };
|
|
const schemas: SchemaForUI[] = [schemaA, schemaB];
|
|
const basePdf1: BasePdf = BLANK_PDF;
|
|
const basePdf2: BasePdf = { ...PAGE_SIZE_PRESETS.A4, padding: [10, 10, 10, 10] };
|
|
const pluginsRegistry = pluginRegistry({ text, image });
|
|
const pageSize = PAGE_SIZE_PRESETS.A4;
|
|
|
|
test('changeSchemas - change content with objs length = 1', () => {
|
|
const objs = [{ key: 'content', value: 'a!', schemaId: schemaA.id }];
|
|
const mockCallback = vi.fn();
|
|
|
|
changeSchemas({
|
|
schemas,
|
|
objs,
|
|
commitSchemas: mockCallback,
|
|
basePdf: basePdf1,
|
|
pluginsRegistry,
|
|
pageSize,
|
|
});
|
|
expect(mockCallback.mock.calls[0][0]).toStrictEqual([
|
|
{
|
|
id: schemaA.id,
|
|
name: 'a',
|
|
type: 'text',
|
|
content: 'a!',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
{
|
|
id: schemaB.id,
|
|
name: 'b',
|
|
type: 'text',
|
|
content: 'b',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('changeSchemas - change content with objs length = 2', () => {
|
|
const objs = [
|
|
{ key: 'content', value: 'a!', schemaId: schemaA.id },
|
|
{ key: 'content', value: 'b!', schemaId: schemaB.id },
|
|
];
|
|
const mockCallback = vi.fn();
|
|
|
|
changeSchemas({
|
|
schemas,
|
|
objs,
|
|
commitSchemas: mockCallback,
|
|
basePdf: basePdf1,
|
|
pluginsRegistry,
|
|
pageSize,
|
|
});
|
|
expect(mockCallback.mock.calls[0][0]).toStrictEqual([
|
|
{
|
|
id: schemaA.id,
|
|
name: 'a',
|
|
type: 'text',
|
|
content: 'a!',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
{
|
|
id: schemaB.id,
|
|
name: 'b',
|
|
type: 'text',
|
|
content: 'b!',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('changeSchemas - change width with objs length = 1', () => {
|
|
const objs = [{ key: 'width', value: 150, schemaId: schemaA.id }];
|
|
const mockCallback = vi.fn();
|
|
|
|
changeSchemas({
|
|
schemas,
|
|
objs,
|
|
commitSchemas: mockCallback,
|
|
basePdf: basePdf1,
|
|
pluginsRegistry,
|
|
pageSize,
|
|
});
|
|
expect(mockCallback.mock.calls[0][0]).toStrictEqual([
|
|
{
|
|
id: schemaA.id,
|
|
name: 'a',
|
|
type: 'text',
|
|
content: 'a',
|
|
position: { x: 0, y: 0 },
|
|
width: 150,
|
|
height: 100,
|
|
},
|
|
{
|
|
id: schemaB.id,
|
|
name: 'b',
|
|
type: 'text',
|
|
content: 'b',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('changeSchemas - change width and height with objs length = 2', () => {
|
|
const objs = [
|
|
{ key: 'width', value: 150, schemaId: schemaA.id },
|
|
{ key: 'height', value: 75, schemaId: schemaA.id },
|
|
];
|
|
const mockCallback = vi.fn();
|
|
|
|
changeSchemas({
|
|
schemas,
|
|
objs,
|
|
commitSchemas: mockCallback,
|
|
basePdf: basePdf1,
|
|
pluginsRegistry,
|
|
pageSize,
|
|
});
|
|
expect(mockCallback.mock.calls[0][0]).toStrictEqual([
|
|
{
|
|
id: schemaA.id,
|
|
name: 'a',
|
|
type: 'text',
|
|
content: 'a',
|
|
position: { x: 0, y: 0 },
|
|
width: 150,
|
|
height: 75,
|
|
},
|
|
{
|
|
id: schemaB.id,
|
|
name: 'b',
|
|
type: 'text',
|
|
content: 'b',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('changeSchemas - change type with objs length = 1', () => {
|
|
const objs = [{ key: 'type', value: 'image', schemaId: schemaA.id }];
|
|
const mockCallback = vi.fn();
|
|
|
|
changeSchemas({
|
|
schemas,
|
|
objs,
|
|
commitSchemas: mockCallback,
|
|
basePdf: basePdf1,
|
|
pluginsRegistry,
|
|
pageSize,
|
|
});
|
|
expect(mockCallback.mock.calls[0][0]).toStrictEqual([
|
|
{
|
|
id: schemaA.id,
|
|
name: 'a',
|
|
type: 'image',
|
|
content:
|
|
'data:image/png;base64,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',
|
|
position: { x: 0, y: 0 },
|
|
width: 40,
|
|
height: 40,
|
|
opacity: 1,
|
|
rotate: 0,
|
|
},
|
|
{
|
|
id: schemaB.id,
|
|
name: 'b',
|
|
type: 'text',
|
|
content: 'b',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('changeSchemas - change position.x and position.y with objs length = 2', () => {
|
|
const objs = [
|
|
{ key: 'position.x', value: 5, schemaId: schemaA.id },
|
|
{ key: 'position.y', value: 5, schemaId: schemaA.id },
|
|
];
|
|
const mockCallback = vi.fn();
|
|
|
|
changeSchemas({
|
|
schemas,
|
|
objs,
|
|
commitSchemas: mockCallback,
|
|
basePdf: basePdf1,
|
|
pluginsRegistry,
|
|
pageSize,
|
|
});
|
|
expect(mockCallback.mock.calls[0][0]).toStrictEqual([
|
|
{
|
|
id: schemaA.id,
|
|
name: 'a',
|
|
type: 'text',
|
|
content: 'a',
|
|
position: { x: 5, y: 5 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
{
|
|
id: schemaB.id,
|
|
name: 'b',
|
|
type: 'text',
|
|
content: 'b',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('changeSchemas - change position.x and position.y(padding in) with objs length = 2 and BlankPDF', () => {
|
|
const objs = [
|
|
{ key: 'position.x', value: 5, schemaId: schemaA.id },
|
|
{ key: 'position.y', value: 5, schemaId: schemaA.id },
|
|
];
|
|
const mockCallback = vi.fn();
|
|
|
|
changeSchemas({
|
|
schemas,
|
|
objs,
|
|
commitSchemas: mockCallback,
|
|
basePdf: basePdf2,
|
|
pluginsRegistry,
|
|
pageSize,
|
|
});
|
|
expect(mockCallback.mock.calls[0][0]).toStrictEqual([
|
|
{
|
|
id: schemaA.id,
|
|
name: 'a',
|
|
type: 'text',
|
|
content: 'a',
|
|
position: { x: 10, y: 10 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
{
|
|
id: schemaB.id,
|
|
name: 'b',
|
|
type: 'text',
|
|
content: 'b',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('changeSchemas - change position.x and position.y(padding out) with objs length = 2 and BlankPDF', () => {
|
|
const objs = [
|
|
{ key: 'position.x', value: 10, schemaId: schemaA.id },
|
|
{ key: 'position.y', value: 10, schemaId: schemaA.id },
|
|
];
|
|
const mockCallback = vi.fn();
|
|
|
|
changeSchemas({
|
|
schemas,
|
|
objs,
|
|
commitSchemas: mockCallback,
|
|
basePdf: basePdf2,
|
|
pluginsRegistry,
|
|
pageSize,
|
|
});
|
|
expect(mockCallback.mock.calls[0][0]).toStrictEqual([
|
|
{
|
|
id: schemaA.id,
|
|
name: 'a',
|
|
type: 'text',
|
|
content: 'a',
|
|
position: { x: 10, y: 10 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
{
|
|
id: schemaB.id,
|
|
name: 'b',
|
|
type: 'text',
|
|
content: 'b',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('changeSchemas - change width and height(padding out) with objs length = 2 and BlankPDF', () => {
|
|
const objs = [
|
|
{ key: 'width', value: 110, schemaId: schemaA.id },
|
|
{ key: 'height', value: 110, schemaId: schemaA.id },
|
|
];
|
|
const mockCallback = vi.fn();
|
|
|
|
changeSchemas({
|
|
schemas,
|
|
objs,
|
|
commitSchemas: mockCallback,
|
|
basePdf: basePdf2,
|
|
pluginsRegistry,
|
|
pageSize,
|
|
});
|
|
expect(mockCallback.mock.calls[0][0]).toStrictEqual([
|
|
{
|
|
id: schemaA.id,
|
|
name: 'a',
|
|
type: 'text',
|
|
content: 'a',
|
|
position: { x: 0, y: 0 },
|
|
width: 110,
|
|
height: 110,
|
|
},
|
|
{
|
|
id: schemaB.id,
|
|
name: 'b',
|
|
type: 'text',
|
|
content: 'b',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
]);
|
|
});
|
|
test('changeSchemas - change width and height(padding in) with objs length = 2 and BlankPDF', () => {
|
|
const objs = [
|
|
{ key: 'position.x', value: 100, schemaId: schemaA.id },
|
|
{ key: 'position.y', value: 197, schemaId: schemaA.id },
|
|
{ key: 'width', value: 110, schemaId: schemaA.id },
|
|
{ key: 'height', value: 110, schemaId: schemaA.id },
|
|
];
|
|
const mockCallback = vi.fn();
|
|
|
|
changeSchemas({
|
|
schemas,
|
|
objs,
|
|
commitSchemas: mockCallback,
|
|
basePdf: basePdf2,
|
|
pluginsRegistry,
|
|
pageSize,
|
|
});
|
|
expect(mockCallback.mock.calls[0][0]).toStrictEqual([
|
|
{
|
|
id: schemaA.id,
|
|
name: 'a',
|
|
type: 'text',
|
|
content: 'a',
|
|
position: { x: 100, y: 187 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
{
|
|
id: schemaB.id,
|
|
name: 'b',
|
|
type: 'text',
|
|
content: 'b',
|
|
position: { x: 0, y: 0 },
|
|
width: 100,
|
|
height: 100,
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('getDynamicHeightReflowChanges', () => {
|
|
test('pushes lower schemas down for list auto height changes', () => {
|
|
const listSchema = {
|
|
id: uuid(),
|
|
...getSchema(),
|
|
name: 'items',
|
|
type: 'list',
|
|
content: '[]',
|
|
position: { x: 0, y: 20 },
|
|
height: 10,
|
|
};
|
|
const belowSchema = {
|
|
id: uuid(),
|
|
...getSchema(),
|
|
name: 'below',
|
|
content: 'below',
|
|
position: { x: 0, y: 35 },
|
|
height: 10,
|
|
};
|
|
const aboveSchema = {
|
|
id: uuid(),
|
|
...getSchema(),
|
|
name: 'above',
|
|
content: 'above',
|
|
position: { x: 0, y: 5 },
|
|
height: 10,
|
|
};
|
|
|
|
expect(
|
|
getDynamicHeightReflowChanges({
|
|
schemas: [aboveSchema, listSchema, belowSchema],
|
|
schema: listSchema,
|
|
height: 25,
|
|
}),
|
|
).toStrictEqual([{ key: 'position.y', value: 50, schemaId: belowSchema.id }]);
|
|
});
|
|
|
|
test('ignores non-list and table schemas', () => {
|
|
const belowSchema = {
|
|
id: uuid(),
|
|
...getSchema(),
|
|
name: 'below',
|
|
content: 'below',
|
|
position: { x: 0, y: 35 },
|
|
height: 10,
|
|
};
|
|
|
|
for (const type of ['text', 'table']) {
|
|
const schema = {
|
|
id: uuid(),
|
|
...getSchema(),
|
|
name: 'items',
|
|
type,
|
|
position: { x: 0, y: 20 },
|
|
height: 10,
|
|
};
|
|
|
|
expect(
|
|
getDynamicHeightReflowChanges({
|
|
schemas: [schema, belowSchema],
|
|
schema,
|
|
height: 25,
|
|
}),
|
|
).toStrictEqual([]);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('setFontNameRecursively', () => {
|
|
it('sets fontName in object with undefined fontName property', () => {
|
|
const obj = { fontName: undefined, content: 'test' };
|
|
setFontNameRecursively(obj, 'Arial');
|
|
expect(obj.fontName).toEqual('Arial');
|
|
});
|
|
|
|
it('does not modify existing fontName values', () => {
|
|
const obj = { fontName: 'Helvetica', content: 'test' };
|
|
setFontNameRecursively(obj, 'Arial');
|
|
expect(obj.fontName).toEqual('Helvetica');
|
|
});
|
|
|
|
it('recursively sets fontName in nested objects and preserves other properties', () => {
|
|
const obj = {
|
|
outer: {
|
|
fontName: undefined,
|
|
otherProp: 'unchanged',
|
|
inner: {
|
|
fontName: undefined,
|
|
content: 'test',
|
|
style: { color: 'red' },
|
|
},
|
|
},
|
|
};
|
|
setFontNameRecursively(obj, 'Arial');
|
|
expect(obj.outer.fontName).toEqual('Arial');
|
|
expect(obj.outer.otherProp).toEqual('unchanged');
|
|
expect(obj.outer.inner.fontName).toEqual('Arial');
|
|
expect(obj.outer.inner.content).toEqual('test');
|
|
expect(obj.outer.inner.style.color).toEqual('red');
|
|
});
|
|
|
|
it('handles arrays of objects', () => {
|
|
const obj = {
|
|
items: [
|
|
{ fontName: undefined, content: 'item1' },
|
|
{ fontName: undefined, content: 'item2' },
|
|
],
|
|
};
|
|
setFontNameRecursively(obj, 'Arial');
|
|
expect(obj.items[0].fontName).toEqual('Arial');
|
|
expect(obj.items[1].fontName).toEqual('Arial');
|
|
});
|
|
|
|
it('ignores null values', () => {
|
|
const obj = { fontName: undefined, nullProp: null };
|
|
setFontNameRecursively(obj, 'Arial');
|
|
expect(obj.fontName).toEqual('Arial');
|
|
expect(obj.nullProp).toBeNull();
|
|
});
|
|
|
|
it('handles empty objects', () => {
|
|
const obj = {};
|
|
setFontNameRecursively(obj, 'Arial');
|
|
expect(obj).toEqual({});
|
|
});
|
|
|
|
it('returns early for null input or undefined input', () => {
|
|
expect(() => setFontNameRecursively(null as any, 'Arial')).not.toThrow();
|
|
expect(() => setFontNameRecursively(undefined as any, 'Arial')).not.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('zoom helpers', () => {
|
|
test('clampZoomLevel keeps zoom within min and max', () => {
|
|
expect(clampZoomLevel(0.1, 2)).toBe(0.25);
|
|
expect(clampZoomLevel(3, 2)).toBe(2);
|
|
expect(clampZoomLevel(1.25, 2)).toBe(1.25);
|
|
});
|
|
|
|
test('getFitZoomLevel computes width and height zoom against the container', () => {
|
|
const container = document.createElement('div');
|
|
Object.defineProperty(container, 'clientWidth', { value: 440 });
|
|
Object.defineProperty(container, 'clientHeight', { value: 520 });
|
|
const pageSize = { width: 100, height: 100 };
|
|
const baseScale = 0.5;
|
|
|
|
expect(
|
|
getFitZoomLevel({
|
|
mode: 'fit-width',
|
|
pageSize,
|
|
container,
|
|
baseScale,
|
|
maxZoom: 3,
|
|
}),
|
|
).toBeCloseTo(400 / (pageSize.width * ZOOM) / baseScale);
|
|
|
|
expect(
|
|
getFitZoomLevel({
|
|
mode: 'fit-height',
|
|
pageSize,
|
|
container,
|
|
baseScale,
|
|
maxZoom: 3,
|
|
}),
|
|
).toBe(1);
|
|
});
|
|
|
|
test('getZoomAnchor and restoreZoomAnchor keep the anchored point stable', () => {
|
|
const container = document.createElement('div');
|
|
container.scrollLeft = 100;
|
|
container.scrollTop = 100;
|
|
const paper = document.createElement('div');
|
|
vi.spyOn(paper, 'getBoundingClientRect').mockReturnValue({
|
|
left: 50,
|
|
top: 60,
|
|
right: 250,
|
|
bottom: 260,
|
|
width: 200,
|
|
height: 200,
|
|
x: 50,
|
|
y: 60,
|
|
toJSON: () => undefined,
|
|
});
|
|
|
|
const anchor = getZoomAnchor({
|
|
pageIndex: 0,
|
|
paper,
|
|
clientX: 90,
|
|
clientY: 120,
|
|
scale: 2,
|
|
});
|
|
|
|
expect(anchor).toEqual({
|
|
pageIndex: 0,
|
|
localX: 20,
|
|
localY: 30,
|
|
clientX: 90,
|
|
clientY: 120,
|
|
});
|
|
|
|
restoreZoomAnchor({ container, paper, anchor, scale: 3 });
|
|
|
|
expect(container.scrollLeft).toBe(120);
|
|
expect(container.scrollTop).toBe(130);
|
|
});
|
|
});
|