pdfdancer-client-typescript 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +19 -0
- package/README.md +267 -0
- package/dist/__tests__/e2e/test-helpers.d.ts +32 -0
- package/dist/__tests__/e2e/test-helpers.d.ts.map +1 -0
- package/dist/__tests__/e2e/test-helpers.js +157 -0
- package/dist/__tests__/e2e/test-helpers.js.map +1 -0
- package/dist/client-v1.d.ts +169 -0
- package/dist/client-v1.d.ts.map +1 -0
- package/dist/client-v1.js +558 -0
- package/dist/client-v1.js.map +1 -0
- package/dist/exceptions.d.ts +43 -0
- package/dist/exceptions.d.ts.map +1 -0
- package/dist/exceptions.js +66 -0
- package/dist/exceptions.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/models.d.ts +216 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +427 -0
- package/dist/models.js.map +1 -0
- package/dist/paragraph-builder.d.ts +67 -0
- package/dist/paragraph-builder.d.ts.map +1 -0
- package/dist/paragraph-builder.js +160 -0
- package/dist/paragraph-builder.js.map +1 -0
- package/example.ts +103 -0
- package/fixtures/DancingScript-Regular.ttf +0 -0
- package/fixtures/JetBrainsMono-Regular.ttf +0 -0
- package/fixtures/ObviouslyAwesome.pdf +0 -0
- package/fixtures/README.md +25 -0
- package/fixtures/basic-paths.pdf +0 -0
- package/fixtures/logo-80.png +0 -0
- package/fixtures/mixed-form-types.pdf +0 -0
- package/jest.config.js +26 -0
- package/package.json +38 -0
- package/scripts/release.js +91 -0
- package/scripts/test-release.js +59 -0
- package/src/__tests__/client-v1.test.ts +111 -0
- package/src/__tests__/e2e/form.test.ts +51 -0
- package/src/__tests__/e2e/image.test.ts +108 -0
- package/src/__tests__/e2e/line.test.ts +134 -0
- package/src/__tests__/e2e/page.test.ts +45 -0
- package/src/__tests__/e2e/paragraph.test.ts +210 -0
- package/src/__tests__/e2e/path.test.ts +72 -0
- package/src/__tests__/e2e/test-helpers.ts +132 -0
- package/src/client-v1.ts +673 -0
- package/src/exceptions.ts +67 -0
- package/src/index.ts +34 -0
- package/src/models.ts +476 -0
- package/src/paragraph-builder.ts +184 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E tests for text line operations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import { ClientV1, Position } from '../../index';
|
|
7
|
+
import { requireEnvAndFixture, createTempPath } from './test-helpers';
|
|
8
|
+
|
|
9
|
+
describe('Line E2E Tests', () => {
|
|
10
|
+
// Tests should fail properly if environment is not configured
|
|
11
|
+
|
|
12
|
+
test('find lines by position', async () => {
|
|
13
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
14
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
15
|
+
await client.init();
|
|
16
|
+
|
|
17
|
+
const lines = await client.findTextLines();
|
|
18
|
+
expect(lines).toHaveLength(340);
|
|
19
|
+
|
|
20
|
+
const first = lines[0];
|
|
21
|
+
expect(first.internalId).toBe('LINE_000001');
|
|
22
|
+
expect(first.position).toBeDefined();
|
|
23
|
+
expect(first.position.boundingRect?.x).toBeCloseTo(326, 1);
|
|
24
|
+
expect(first.position.boundingRect?.y).toBeCloseTo(706, 1);
|
|
25
|
+
|
|
26
|
+
const last = lines[lines.length - 1];
|
|
27
|
+
expect(last.internalId).toBe('LINE_000340');
|
|
28
|
+
expect(last.position).toBeDefined();
|
|
29
|
+
expect(last.position.boundingRect?.x).toBeCloseTo(548, 2);
|
|
30
|
+
expect(last.position.boundingRect?.y).toBeCloseTo(35, 2);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('find lines by text', async () => {
|
|
34
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
35
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
36
|
+
await client.init();
|
|
37
|
+
|
|
38
|
+
const pos = Position.fromPageIndex(0);
|
|
39
|
+
pos.textStartsWith = 'the complete';
|
|
40
|
+
const lines = await client.findTextLines(pos);
|
|
41
|
+
expect(lines).toHaveLength(1);
|
|
42
|
+
|
|
43
|
+
const line = lines[0];
|
|
44
|
+
expect(line.internalId).toBe('LINE_000002');
|
|
45
|
+
expect(line.position).toBeDefined();
|
|
46
|
+
expect(line.position.boundingRect?.x).toBeCloseTo(54, 1);
|
|
47
|
+
expect(line.position.boundingRect?.y).toBeCloseTo(606, 2);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('delete line', async () => {
|
|
51
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
52
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
53
|
+
await client.init();
|
|
54
|
+
|
|
55
|
+
const pos = Position.fromPageIndex(0);
|
|
56
|
+
pos.textStartsWith = 'The Complete';
|
|
57
|
+
const ref = (await client.findTextLines(pos))[0];
|
|
58
|
+
expect(await client.delete(ref)).toBe(true);
|
|
59
|
+
|
|
60
|
+
const pos2 = Position.fromPageIndex(0);
|
|
61
|
+
pos2.textStartsWith = 'The Complete';
|
|
62
|
+
expect(await client.findTextLines(pos2)).toHaveLength(0);
|
|
63
|
+
|
|
64
|
+
// Save PDF to verify operation (Node.js environment)
|
|
65
|
+
const outPath = createTempPath('deleteLine.pdf');
|
|
66
|
+
const outputPdfData = await client.getPdfFile();
|
|
67
|
+
fs.writeFileSync(outPath, outputPdfData);
|
|
68
|
+
expect(fs.existsSync(outPath)).toBe(true);
|
|
69
|
+
expect(fs.statSync(outPath).size).toBeGreaterThan(0);
|
|
70
|
+
|
|
71
|
+
// Cleanup
|
|
72
|
+
fs.unlinkSync(outPath);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('move line', async () => {
|
|
76
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
77
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
78
|
+
await client.init();
|
|
79
|
+
|
|
80
|
+
const pos3 = Position.fromPageIndex(0);
|
|
81
|
+
pos3.textStartsWith = 'The Complete';
|
|
82
|
+
const ref = (await client.findTextLines(pos3))[0];
|
|
83
|
+
const newPos = ref.position.copy();
|
|
84
|
+
newPos.moveX(100);
|
|
85
|
+
expect(await client.move(ref, newPos)).toBe(true);
|
|
86
|
+
|
|
87
|
+
const ref2 = (await client.findParagraphs(newPos))[0];
|
|
88
|
+
expect(ref2).toBeDefined();
|
|
89
|
+
|
|
90
|
+
// Save PDF to verify operation
|
|
91
|
+
const outPath = createTempPath('moveLine.pdf');
|
|
92
|
+
const outputPdfData = await client.getPdfFile();
|
|
93
|
+
fs.writeFileSync(outPath, outputPdfData);
|
|
94
|
+
expect(fs.existsSync(outPath)).toBe(true);
|
|
95
|
+
expect(fs.statSync(outPath).size).toBeGreaterThan(0);
|
|
96
|
+
|
|
97
|
+
// Cleanup
|
|
98
|
+
fs.unlinkSync(outPath);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('modify line', async () => {
|
|
102
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
103
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
104
|
+
await client.init();
|
|
105
|
+
|
|
106
|
+
const pos4 = Position.fromPageIndex(0);
|
|
107
|
+
pos4.textStartsWith = 'The Complete';
|
|
108
|
+
const ref = (await client.findTextLines(pos4))[0];
|
|
109
|
+
expect(await client.modifyTextLine(ref, ' replaced ')).toBe(true);
|
|
110
|
+
|
|
111
|
+
// Save PDF to verify operation
|
|
112
|
+
const outPath = createTempPath('modifyLine.pdf');
|
|
113
|
+
const outputPdfData = await client.getPdfFile();
|
|
114
|
+
fs.writeFileSync(outPath, outputPdfData);
|
|
115
|
+
expect(fs.existsSync(outPath)).toBe(true);
|
|
116
|
+
expect(fs.statSync(outPath).size).toBeGreaterThan(0);
|
|
117
|
+
|
|
118
|
+
// Verify the text was replaced
|
|
119
|
+
const pos5 = Position.fromPageIndex(0);
|
|
120
|
+
pos5.textStartsWith = 'The Complete';
|
|
121
|
+
expect(await client.findTextLines(pos5)).toHaveLength(0);
|
|
122
|
+
|
|
123
|
+
const pos6 = Position.fromPageIndex(0);
|
|
124
|
+
pos6.textStartsWith = ' replaced ';
|
|
125
|
+
expect(await client.findTextLines(pos6)).not.toHaveLength(0);
|
|
126
|
+
|
|
127
|
+
const pos7 = Position.fromPageIndex(0);
|
|
128
|
+
pos7.textStartsWith = ' replaced ';
|
|
129
|
+
expect(await client.findParagraphs(pos7)).not.toHaveLength(0);
|
|
130
|
+
|
|
131
|
+
// Cleanup
|
|
132
|
+
fs.unlinkSync(outPath);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E tests for page operations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ClientV1, ObjectType } from '../../index';
|
|
6
|
+
import { requireEnvAndFixture } from './test-helpers';
|
|
7
|
+
|
|
8
|
+
describe('Page E2E Tests', () => {
|
|
9
|
+
// Tests should fail properly if environment is not configured
|
|
10
|
+
|
|
11
|
+
test('get pages', async () => {
|
|
12
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
13
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
14
|
+
await client.init();
|
|
15
|
+
|
|
16
|
+
const pages = await client.getPages();
|
|
17
|
+
expect(pages).toBeDefined();
|
|
18
|
+
expect(pages[0].type).toBe(ObjectType.PAGE);
|
|
19
|
+
expect(pages).toHaveLength(12);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('get page', async () => {
|
|
23
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
24
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
25
|
+
await client.init();
|
|
26
|
+
|
|
27
|
+
const page = await client.getPage(2);
|
|
28
|
+
expect(page).toBeDefined();
|
|
29
|
+
expect(page!.position.pageIndex).toBe(2);
|
|
30
|
+
expect(page!.internalId).toBeDefined();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('delete page', async () => {
|
|
34
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
35
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
36
|
+
await client.init();
|
|
37
|
+
|
|
38
|
+
const page3 = await client.getPage(3);
|
|
39
|
+
expect(page3).toBeDefined();
|
|
40
|
+
expect(await client.deletePage(page3!)).toBe(true);
|
|
41
|
+
|
|
42
|
+
const newPages = await client.getPages();
|
|
43
|
+
expect(newPages).toHaveLength(11);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E tests for paragraph operations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ClientV1, Position, Font, Color, FontNotFoundException } from '../../index';
|
|
6
|
+
import { requireEnvAndFixture, readFontFixture } from './test-helpers';
|
|
7
|
+
|
|
8
|
+
describe('Paragraph E2E Tests', () => {
|
|
9
|
+
// Tests should fail properly if environment is not configured
|
|
10
|
+
|
|
11
|
+
test('find paragraphs by position', async () => {
|
|
12
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
13
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
14
|
+
await client.init();
|
|
15
|
+
|
|
16
|
+
const paras = await client.findParagraphs();
|
|
17
|
+
expect(paras).toHaveLength(172);
|
|
18
|
+
|
|
19
|
+
const parasPage0 = await client.findParagraphs(Position.fromPageIndex(0));
|
|
20
|
+
expect(parasPage0).toHaveLength(2);
|
|
21
|
+
|
|
22
|
+
const first = parasPage0[0];
|
|
23
|
+
expect(first.internalId).toBe('PARAGRAPH_000003');
|
|
24
|
+
expect(first.position).toBeDefined();
|
|
25
|
+
expect(first.position.boundingRect?.x).toBeCloseTo(326, 1);
|
|
26
|
+
expect(first.position.boundingRect?.y).toBeCloseTo(706, 1);
|
|
27
|
+
|
|
28
|
+
const last = parasPage0[parasPage0.length - 1];
|
|
29
|
+
expect(last.internalId).toBe('PARAGRAPH_000004');
|
|
30
|
+
expect(last.position).toBeDefined();
|
|
31
|
+
expect(last.position.boundingRect?.x).toBeCloseTo(54, 1);
|
|
32
|
+
expect(last.position.boundingRect?.y).toBeCloseTo(496, 2);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('find paragraphs by text', async () => {
|
|
36
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
37
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
38
|
+
await client.init();
|
|
39
|
+
|
|
40
|
+
const pos = Position.fromPageIndex(0);
|
|
41
|
+
pos.textStartsWith = 'The Complete';
|
|
42
|
+
const paras = await client.findParagraphs(pos);
|
|
43
|
+
expect(paras).toHaveLength(1);
|
|
44
|
+
|
|
45
|
+
const p = paras[0];
|
|
46
|
+
expect(p.internalId).toBe('PARAGRAPH_000004');
|
|
47
|
+
expect(p.position).toBeDefined();
|
|
48
|
+
expect(p.position.boundingRect?.x).toBeCloseTo(54, 1);
|
|
49
|
+
expect(p.position.boundingRect?.y).toBeCloseTo(496, 2);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('delete paragraph', async () => {
|
|
53
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
54
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
55
|
+
await client.init();
|
|
56
|
+
|
|
57
|
+
const posDel = Position.fromPageIndex(0);
|
|
58
|
+
posDel.textStartsWith = 'The Complete';
|
|
59
|
+
const ref = (await client.findParagraphs(posDel))[0];
|
|
60
|
+
expect(await client.delete(ref)).toBe(true);
|
|
61
|
+
|
|
62
|
+
const posDel2 = Position.fromPageIndex(0);
|
|
63
|
+
posDel2.textStartsWith = 'The Complete';
|
|
64
|
+
expect(await client.findParagraphs(posDel2)).toHaveLength(0);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('move paragraph', async () => {
|
|
68
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
69
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
70
|
+
await client.init();
|
|
71
|
+
|
|
72
|
+
const posMove = Position.fromPageIndex(0);
|
|
73
|
+
posMove.textStartsWith = 'The Complete';
|
|
74
|
+
const ref = (await client.findParagraphs(posMove))[0];
|
|
75
|
+
const newPos = Position.onPageCoordinates(0, 0.1, 300);
|
|
76
|
+
expect(await client.move(ref, newPos)).toBe(true);
|
|
77
|
+
|
|
78
|
+
const ref2 = (await client.findParagraphs(newPos))[0];
|
|
79
|
+
expect(ref2).toBeDefined();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
async function assertNewParagraphExists(client: ClientV1): Promise<void> {
|
|
83
|
+
// Validate via find_text_lines for text starting with 'Awesomely'
|
|
84
|
+
const pos = Position.fromPageIndex(0);
|
|
85
|
+
pos.textStartsWith = 'Awesomely';
|
|
86
|
+
const lines = await client.findTextLines(pos);
|
|
87
|
+
expect(lines.length).toBeGreaterThanOrEqual(1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
test('modify paragraph', async () => {
|
|
91
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
92
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
93
|
+
await client.init();
|
|
94
|
+
|
|
95
|
+
const posMod = Position.fromPageIndex(0);
|
|
96
|
+
posMod.textStartsWith = 'The Complete';
|
|
97
|
+
const ref = (await client.findParagraphs(posMod))[0];
|
|
98
|
+
|
|
99
|
+
const newParagraph = client.paragraphBuilder()
|
|
100
|
+
.fromString('Awesomely\\nObvious!')
|
|
101
|
+
.withFont(new Font('Helvetica', 14))
|
|
102
|
+
.withLineSpacing(0.7)
|
|
103
|
+
.withPosition(Position.onPageCoordinates(0, 300.1, 500))
|
|
104
|
+
.build();
|
|
105
|
+
|
|
106
|
+
expect(await client.modifyParagraph(ref, newParagraph)).toBe(true);
|
|
107
|
+
await assertNewParagraphExists(client);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('modify paragraph simple', async () => {
|
|
111
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
112
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
113
|
+
await client.init();
|
|
114
|
+
|
|
115
|
+
const posMod2 = Position.fromPageIndex(0);
|
|
116
|
+
posMod2.textStartsWith = 'The Complete';
|
|
117
|
+
const ref = (await client.findParagraphs(posMod2))[0];
|
|
118
|
+
expect(await client.modifyParagraph(ref, 'Awesomely\\nObvious!')).toBe(true);
|
|
119
|
+
await assertNewParagraphExists(client);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('add paragraph with custom font - expect not found', async () => {
|
|
123
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
124
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
125
|
+
await client.init();
|
|
126
|
+
|
|
127
|
+
const pb = client.paragraphBuilder()
|
|
128
|
+
.fromString('Awesomely\\nObvious!')
|
|
129
|
+
.withFont(new Font('Roboto', 14))
|
|
130
|
+
.withLineSpacing(0.7)
|
|
131
|
+
.withPosition(Position.onPageCoordinates(0, 300.1, 500));
|
|
132
|
+
|
|
133
|
+
await expect(client.addParagraph(pb.build())).rejects.toThrow('Font not found');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('add paragraph with custom font - Roboto-Regular', async () => {
|
|
137
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
138
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
139
|
+
await client.init();
|
|
140
|
+
|
|
141
|
+
const pb = client.paragraphBuilder()
|
|
142
|
+
.fromString('Awesomely\\nObvious!')
|
|
143
|
+
.withFont(new Font('Roboto-Regular', 14))
|
|
144
|
+
.withLineSpacing(0.7)
|
|
145
|
+
.withPosition(Position.onPageCoordinates(0, 300.1, 500));
|
|
146
|
+
|
|
147
|
+
expect(await client.addParagraph(pb.build())).toBe(true);
|
|
148
|
+
await assertNewParagraphExists(client);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('add paragraph with found font', async () => {
|
|
152
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
153
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
154
|
+
await client.init();
|
|
155
|
+
|
|
156
|
+
const fonts = await client.findFonts('Roboto', 14);
|
|
157
|
+
expect(fonts.length).toBeGreaterThan(0);
|
|
158
|
+
expect(fonts[0].name).toBe('Roboto-Regular');
|
|
159
|
+
|
|
160
|
+
const roboto = fonts[0];
|
|
161
|
+
const pb = client.paragraphBuilder()
|
|
162
|
+
.fromString('Awesomely\\nObvious!')
|
|
163
|
+
.withFont(roboto)
|
|
164
|
+
.withLineSpacing(0.7)
|
|
165
|
+
.withPosition(Position.onPageCoordinates(0, 300.1, 500));
|
|
166
|
+
|
|
167
|
+
expect(await client.addParagraph(pb.build())).toBe(true);
|
|
168
|
+
await assertNewParagraphExists(client);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test('add paragraph with Asimovian font', async () => {
|
|
172
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
173
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
174
|
+
await client.init();
|
|
175
|
+
|
|
176
|
+
const fonts = await client.findFonts('Asimovian', 14);
|
|
177
|
+
expect(fonts.length).toBeGreaterThan(0);
|
|
178
|
+
expect(fonts[0].name).toBe('Asimovian-Regular');
|
|
179
|
+
|
|
180
|
+
const asimovian = fonts[0];
|
|
181
|
+
const pb = client.paragraphBuilder()
|
|
182
|
+
.fromString('Awesomely\\nObvious!')
|
|
183
|
+
.withFont(asimovian)
|
|
184
|
+
.withLineSpacing(0.7)
|
|
185
|
+
.withPosition(Position.onPageCoordinates(0, 300.1, 500));
|
|
186
|
+
|
|
187
|
+
expect(await client.addParagraph(pb.build())).toBe(true);
|
|
188
|
+
await assertNewParagraphExists(client);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test('add paragraph with custom TTF font', async () => {
|
|
192
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
193
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
194
|
+
await client.init();
|
|
195
|
+
|
|
196
|
+
// Use DancingScript-Regular.ttf from fixtures directory
|
|
197
|
+
const ttfData = readFontFixture('DancingScript-Regular.ttf');
|
|
198
|
+
|
|
199
|
+
const pb = client.paragraphBuilder()
|
|
200
|
+
.fromString('Awesomely\\nObvious!')
|
|
201
|
+
.withLineSpacing(1.8)
|
|
202
|
+
.withColor(new Color(0, 0, 255))
|
|
203
|
+
.withPosition(Position.onPageCoordinates(0, 300.1, 500));
|
|
204
|
+
|
|
205
|
+
await pb.withFontFile(ttfData, 24);
|
|
206
|
+
|
|
207
|
+
expect(await client.addParagraph(pb.build())).toBe(true);
|
|
208
|
+
await assertNewParagraphExists(client);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E tests for path operations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ClientV1, Position, ObjectType } from '../../index';
|
|
6
|
+
import { requireEnvAndFixture } from './test-helpers';
|
|
7
|
+
|
|
8
|
+
describe('Path E2E Tests', () => {
|
|
9
|
+
// Remove the misleading beforeAll - tests should fail properly if not configured
|
|
10
|
+
|
|
11
|
+
test('find paths', async () => {
|
|
12
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('basic-paths.pdf');
|
|
13
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
14
|
+
await client.init();
|
|
15
|
+
|
|
16
|
+
const paths = await client.findPaths();
|
|
17
|
+
expect(paths).toHaveLength(9);
|
|
18
|
+
expect(paths[0].type).toBe(ObjectType.PATH);
|
|
19
|
+
|
|
20
|
+
const p1 = paths[0];
|
|
21
|
+
expect(p1).toBeDefined();
|
|
22
|
+
expect(p1.internalId).toBe('PATH_000001');
|
|
23
|
+
expect(p1.position.boundingRect?.x).toBeCloseTo(80, 1);
|
|
24
|
+
expect(p1.position.boundingRect?.y).toBeCloseTo(720, 1);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('find paths by position', async () => {
|
|
28
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('basic-paths.pdf');
|
|
29
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
30
|
+
await client.init();
|
|
31
|
+
|
|
32
|
+
const paths = await client.findPaths(Position.onPageCoordinates(0, 80, 720));
|
|
33
|
+
expect(paths).toHaveLength(1);
|
|
34
|
+
expect(paths[0].internalId).toBe('PATH_000001');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('delete path', async () => {
|
|
38
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('basic-paths.pdf');
|
|
39
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
40
|
+
await client.init();
|
|
41
|
+
|
|
42
|
+
let paths = await client.findPaths(Position.onPageCoordinates(0, 80, 720));
|
|
43
|
+
expect(paths).toHaveLength(1);
|
|
44
|
+
expect(paths[0].internalId).toBe('PATH_000001');
|
|
45
|
+
expect(await client.delete(paths[0])).toBe(true);
|
|
46
|
+
|
|
47
|
+
expect(await client.findPaths(Position.onPageCoordinates(0, 80, 720))).toHaveLength(0);
|
|
48
|
+
expect(await client.findPaths()).toHaveLength(8);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('move path', async () => {
|
|
52
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('basic-paths.pdf');
|
|
53
|
+
const client = new ClientV1(token, pdfData, baseUrl, 30000);
|
|
54
|
+
await client.init();
|
|
55
|
+
|
|
56
|
+
let paths = await client.findPaths(Position.onPageCoordinates(0, 80, 720));
|
|
57
|
+
const ref = paths[0];
|
|
58
|
+
const pos = ref.position;
|
|
59
|
+
expect(pos.boundingRect?.x).toBeCloseTo(80, 1);
|
|
60
|
+
expect(pos.boundingRect?.y).toBeCloseTo(720, 1);
|
|
61
|
+
|
|
62
|
+
expect(await client.move(ref, Position.onPageCoordinates(0, 50.1, 100))).toBe(true);
|
|
63
|
+
|
|
64
|
+
expect(await client.findPaths(Position.onPageCoordinates(0, 80, 720))).toHaveLength(0);
|
|
65
|
+
|
|
66
|
+
paths = await client.findPaths(Position.onPageCoordinates(0, 50.1, 100));
|
|
67
|
+
const movedRef = paths[0];
|
|
68
|
+
const newPos = movedRef.position;
|
|
69
|
+
expect(newPos.boundingRect?.x).toBeCloseTo(50.1, 0.05);
|
|
70
|
+
expect(newPos.boundingRect?.y).toBeCloseTo(100, 0.05);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper functions for e2e tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get the base URL from environment variable or default
|
|
10
|
+
*/
|
|
11
|
+
export function getBaseUrl(): string {
|
|
12
|
+
return process.env.PDFDANCER_BASE_URL || 'http://localhost:8080';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Read authentication token from environment or token files
|
|
17
|
+
*/
|
|
18
|
+
export function readToken(): string | null {
|
|
19
|
+
const token = process.env.PDFDANCER_TOKEN;
|
|
20
|
+
if (token) {
|
|
21
|
+
return token.trim();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Try common token files in project root
|
|
25
|
+
const projectRoot = path.resolve(__dirname, '../../..');
|
|
26
|
+
const candidates = findFiles(projectRoot, 'jwt-token-*.txt');
|
|
27
|
+
|
|
28
|
+
for (const file of candidates) {
|
|
29
|
+
try {
|
|
30
|
+
return fs.readFileSync(file, 'utf-8').trim();
|
|
31
|
+
} catch {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check if server is up and running
|
|
41
|
+
*/
|
|
42
|
+
export async function serverUp(baseUrl: string): Promise<boolean> {
|
|
43
|
+
try {
|
|
44
|
+
const response = await fetch(`${baseUrl}/ping`, {
|
|
45
|
+
signal: AbortSignal.timeout(3000)
|
|
46
|
+
});
|
|
47
|
+
const text = await response.text();
|
|
48
|
+
return response.status === 200 && text.includes('Pong');
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Helper to find files matching a pattern
|
|
56
|
+
*/
|
|
57
|
+
function findFiles(dir: string, pattern: string): string[] {
|
|
58
|
+
try {
|
|
59
|
+
const files = fs.readdirSync(dir);
|
|
60
|
+
const regex = new RegExp(pattern.replace('*', '.*'));
|
|
61
|
+
return files
|
|
62
|
+
.filter(file => regex.test(file))
|
|
63
|
+
.map(file => path.join(dir, file));
|
|
64
|
+
} catch {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Require environment variables and PDF fixture for testing
|
|
71
|
+
*/
|
|
72
|
+
export async function requireEnvAndFixture(pdfFilename: string): Promise<[string, string, Uint8Array]> {
|
|
73
|
+
const baseUrl = getBaseUrl();
|
|
74
|
+
const token = readToken();
|
|
75
|
+
|
|
76
|
+
if (!await serverUp(baseUrl)) {
|
|
77
|
+
throw new Error(`PDFDancer server not reachable at ${baseUrl}; set PDFDANCER_BASE_URL or start server`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!token) {
|
|
81
|
+
throw new Error('PDFDANCER_TOKEN not set and no token file found; set env or place jwt-token-*.txt in repo');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Look for PDF fixture file
|
|
85
|
+
const fixturesDir = path.resolve(__dirname, '../../../fixtures');
|
|
86
|
+
const pdfPath = path.join(fixturesDir, pdfFilename);
|
|
87
|
+
|
|
88
|
+
if (!fs.existsSync(pdfPath)) {
|
|
89
|
+
throw new Error(`${pdfFilename} fixture not found at ${pdfPath}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const pdfData = fs.readFileSync(pdfPath);
|
|
93
|
+
return [baseUrl, token, new Uint8Array(pdfData)];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Helper to create temporary file path (for Node.js environment)
|
|
98
|
+
*/
|
|
99
|
+
export function createTempPath(filename: string): string {
|
|
100
|
+
const tmpDir = process.env.TMPDIR || '/tmp';
|
|
101
|
+
return path.join(tmpDir, filename);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Helper to read image file for tests
|
|
106
|
+
*/
|
|
107
|
+
export function readImageFixture(filename: string): Uint8Array {
|
|
108
|
+
const fixturesDir = path.resolve(__dirname, '../../../fixtures');
|
|
109
|
+
const imagePath = path.join(fixturesDir, filename);
|
|
110
|
+
|
|
111
|
+
if (!fs.existsSync(imagePath)) {
|
|
112
|
+
throw new Error(`Image fixture not found: ${filename}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const imageData = fs.readFileSync(imagePath);
|
|
116
|
+
return new Uint8Array(imageData);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Helper to read font file for tests
|
|
121
|
+
*/
|
|
122
|
+
export function readFontFixture(filename: string): Uint8Array {
|
|
123
|
+
const fixturesDir = path.resolve(__dirname, '../../../fixtures');
|
|
124
|
+
const fontPath = path.join(fixturesDir, filename);
|
|
125
|
+
|
|
126
|
+
if (!fs.existsSync(fontPath)) {
|
|
127
|
+
throw new Error(`Font fixture not found: ${filename}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const fontData = fs.readFileSync(fontPath);
|
|
131
|
+
return new Uint8Array(fontData);
|
|
132
|
+
}
|