From b6eddc40b5ddf15a4e1d6fedd8c2be08522a58e8 Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 10 Feb 2019 18:58:52 +0100 Subject: [PATCH 1/2] Write unit tests for the `string32` and `toRomanNumerals` utility functions --- test/unit/util_spec.js | 46 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/test/unit/util_spec.js b/test/unit/util_spec.js index 4d67f5815..5d626837a 100644 --- a/test/unit/util_spec.js +++ b/test/unit/util_spec.js @@ -17,7 +17,7 @@ import { bytesToString, createPromiseCapability, createValidAbsoluteUrl, getInheritableProperty, isArrayBuffer, isBool, isEmptyObj, isNum, isSameOrigin, isSpace, isString, log2, ReadableStream, removeNullCharacters, - stringToBytes, stringToPDFString, URL + string32, stringToBytes, stringToPDFString, toRomanNumerals, URL } from '../../src/shared/util'; import { Dict, Ref } from '../../src/core/primitives'; import { XRefMock } from './test_utils'; @@ -254,6 +254,14 @@ describe('util', function() { }); }); + describe('string32', function() { + it('converts unsigned 32-bit integers to strings', function() { + expect(string32(0x74727565)).toEqual('true'); + expect(string32(0x74797031)).toEqual('typ1'); + expect(string32(0x4F54544F)).toEqual('OTTO'); + }); + }); + describe('stringToBytes', function() { it('handles non-string arguments', function() { expect(function() { @@ -313,6 +321,42 @@ describe('util', function() { }); }); + describe('toRomanNumerals', function() { + it('handles invalid arguments', function() { + for (const input of ['foo', -1, 0]) { + expect(function() { + toRomanNumerals(input); + }).toThrow(new Error('The number should be a positive integer.')); + } + }); + + it('converts numbers to uppercase Roman numerals', function() { + expect(toRomanNumerals(1)).toEqual('I'); + expect(toRomanNumerals(6)).toEqual('VI'); + expect(toRomanNumerals(7)).toEqual('VII'); + expect(toRomanNumerals(8)).toEqual('VIII'); + expect(toRomanNumerals(10)).toEqual('X'); + expect(toRomanNumerals(40)).toEqual('XL'); + expect(toRomanNumerals(100)).toEqual('C'); + expect(toRomanNumerals(500)).toEqual('D'); + expect(toRomanNumerals(1000)).toEqual('M'); + expect(toRomanNumerals(2019)).toEqual('MMXIX'); + }); + + it('converts numbers to lowercase Roman numerals', function() { + expect(toRomanNumerals(1, /* lowercase = */ true)).toEqual('i'); + expect(toRomanNumerals(6, /* lowercase = */ true)).toEqual('vi'); + expect(toRomanNumerals(7, /* lowercase = */ true)).toEqual('vii'); + expect(toRomanNumerals(8, /* lowercase = */ true)).toEqual('viii'); + expect(toRomanNumerals(10, /* lowercase = */ true)).toEqual('x'); + expect(toRomanNumerals(40, /* lowercase = */ true)).toEqual('xl'); + expect(toRomanNumerals(100, /* lowercase = */ true)).toEqual('c'); + expect(toRomanNumerals(500, /* lowercase = */ true)).toEqual('d'); + expect(toRomanNumerals(1000, /* lowercase = */ true)).toEqual('m'); + expect(toRomanNumerals(2019, /* lowercase = */ true)).toEqual('mmxix'); + }); + }); + describe('URL', function() { it('should return an Object', function() { const url = new URL('https://example.com'); From 7c91e94b1977697eac31675f6bdbed91d16e879a Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 10 Feb 2019 19:29:38 +0100 Subject: [PATCH 2/2] Implement the `NodeCanvasFactory` class to execute more unit tests in Node.js --- package-lock.json | 282 +++++++++++++++++++++++++++++++++++++++ package.json | 1 + test/unit/api_spec.js | 29 ++-- test/unit/custom_spec.js | 11 +- test/unit/test_utils.js | 35 ++++- 5 files changed, 329 insertions(+), 29 deletions(-) diff --git a/package-lock.json b/package-lock.json index 89a321a54..347bd65d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1110,6 +1110,12 @@ "integrity": "sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==", "dev": true }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "acorn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.5.tgz", @@ -1324,6 +1330,16 @@ "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -2079,6 +2095,24 @@ "integrity": "sha512-n2w1gPQSsYyorSVYqPMqbSaz1w7o9ZC8VhOEGI9T5MfGDzp7sbopQxG6GaQmYsaq13Xfx/mkxJUWC1Dz3oZfzw==", "dev": true }, + "canvas": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.3.1.tgz", + "integrity": "sha512-jSxwf4V9AGD6t6yBC600xFZKjrfKTR0T0RUNlX/AODs/ifrfJHIQjFEK8iF2euNy6z7K3GNv82DJgTjYZZktqA==", + "dev": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.11.0" + }, + "dependencies": { + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==", + "dev": true + } + } + }, "catharsis": { "version": "0.8.9", "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz", @@ -2443,6 +2477,12 @@ "date-now": "^0.1.4" } }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, "constantinople": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz", @@ -2654,6 +2694,12 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -2734,6 +2780,12 @@ } } }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, "des.js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", @@ -2750,6 +2802,12 @@ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", "dev": true }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true + }, "diagnostics": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", @@ -3819,6 +3877,15 @@ "readable-stream": "^2.0.0" } }, + "fs-minipass": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "dev": true, + "requires": { + "minipass": "^2.2.1" + } + }, "fs-mkdirp-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", @@ -4407,6 +4474,44 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, "get-assigned-identifiers": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", @@ -4905,6 +5010,12 @@ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -5036,6 +5147,15 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "ignore-walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, "import-cwd": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", @@ -6247,6 +6367,33 @@ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, + "minipass": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + }, + "dependencies": { + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true + } + } + }, + "minizlib": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "dev": true, + "requires": { + "minipass": "^2.2.1" + } + }, "mississippi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", @@ -6386,6 +6533,17 @@ "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", "dev": true }, + "needle": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", + "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", + "dev": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, "neo-async": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.1.tgz", @@ -6449,6 +6607,24 @@ } } }, + "node-pre-gyp": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", + "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", + "dev": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, "node-releases": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.2.tgz", @@ -6458,6 +6634,16 @@ "semver": "^5.3.0" } }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", @@ -9577,6 +9763,22 @@ } } }, + "npm-bundled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", + "dev": true + }, + "npm-packlist": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.3.0.tgz", + "integrity": "sha512-qPBc6CnxEzpOcc4bjoIBJbYdy0D/LFFPUdxvfwor4/w3vxeE0h6TiOVurCEPpQ6trjN77u/ShyfeJGsbAfB3dA==", + "dev": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -9586,6 +9788,18 @@ "path-key": "^2.0.0" } }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, "num2fraction": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", @@ -9763,6 +9977,12 @@ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", "dev": true }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, "os-locale": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", @@ -9780,6 +10000,16 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -10433,6 +10663,26 @@ "safe-buffer": "^5.1.0" } }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -11509,6 +11759,29 @@ "integrity": "sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA==", "dev": true }, + "tar": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + }, + "dependencies": { + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true + } + } + }, "terser": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/terser/-/terser-3.14.1.tgz", @@ -12569,6 +12842,15 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, "window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", diff --git a/package.json b/package.json index 47d5e02f8..1c0b46234 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "acorn": "^6.0.5", "autoprefixer": "^9.4.5", "babel-loader": "^8.0.5", + "canvas": "^2.3.1", "core-js": "^2.6.2", "escodegen": "^1.11.0", "eslint": "^5.12.1", diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 025d1158b..851137089 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -14,7 +14,8 @@ */ import { - buildGetDocumentParams, NodeFileReaderFactory, TEST_PDFS_PATH + buildGetDocumentParams, NodeCanvasFactory, NodeFileReaderFactory, + TEST_PDFS_PATH } from './test_utils'; import { createPromiseCapability, FontType, InvalidPDFException, MissingPDFException, @@ -40,8 +41,7 @@ describe('api', function() { beforeAll(function(done) { if (isNodeJS()) { - // NOTE: To support running the canvas-related tests in Node.js, - // a `NodeCanvasFactory` would need to be added (in test_utils.js). + CanvasFactory = new NodeCanvasFactory(); } else { CanvasFactory = new DOMCanvasFactory(); } @@ -1275,9 +1275,6 @@ describe('api', function() { }); it('gets page stats after rendering page, with `pdfBug` set', function(done) { - if (isNodeJS()) { - pending('TODO: Support Canvas testing in Node.js.'); - } let loadingTask = getDocument( buildGetDocumentParams(basicApiFileName, { pdfBug: true, })); let canvasAndCtx; @@ -1289,6 +1286,7 @@ describe('api', function() { let renderTask = pdfPage.render({ canvasContext: canvasAndCtx.context, + canvasFactory: CanvasFactory, viewport, }); return renderTask.promise.then(() => { @@ -1315,14 +1313,12 @@ describe('api', function() { }); it('cancels rendering of page', function(done) { - if (isNodeJS()) { - pending('TODO: Support Canvas testing in Node.js.'); - } var viewport = page.getViewport({ scale: 1, }); var canvasAndCtx = CanvasFactory.create(viewport.width, viewport.height); var renderTask = page.render({ canvasContext: canvasAndCtx.context, + canvasFactory: CanvasFactory, viewport, }); renderTask.cancel(); @@ -1339,14 +1335,12 @@ describe('api', function() { it('re-render page, using the same canvas, after cancelling rendering', function(done) { - if (isNodeJS()) { - pending('TODO: Support Canvas testing in Node.js.'); - } let viewport = page.getViewport({ scale: 1, }); let canvasAndCtx = CanvasFactory.create(viewport.width, viewport.height); let renderTask = page.render({ canvasContext: canvasAndCtx.context, + canvasFactory: CanvasFactory, viewport, }); renderTask.cancel(); @@ -1358,6 +1352,7 @@ describe('api', function() { }).then(() => { let reRenderTask = page.render({ canvasContext: canvasAndCtx.context, + canvasFactory: CanvasFactory, viewport, }); return reRenderTask.promise; @@ -1368,18 +1363,17 @@ describe('api', function() { }); it('multiple render() on the same canvas', function(done) { - if (isNodeJS()) { - pending('TODO: Support Canvas testing in Node.js.'); - } var viewport = page.getViewport({ scale: 1, }); var canvasAndCtx = CanvasFactory.create(viewport.width, viewport.height); var renderTask1 = page.render({ canvasContext: canvasAndCtx.context, + canvasFactory: CanvasFactory, viewport, }); var renderTask2 = page.render({ canvasContext: canvasAndCtx.context, + canvasFactory: CanvasFactory, viewport, }); @@ -1418,6 +1412,7 @@ describe('api', function() { viewport.height); const renderTask = page.render({ canvasContext: canvasAndCtx.context, + canvasFactory: CanvasFactory, viewport, }); await renderTask.promise; @@ -1445,10 +1440,6 @@ describe('api', function() { }); it('should correctly render PDFs in parallel', function(done) { - if (isNodeJS()) { - pending('TODO: Support Canvas testing in Node.js.'); - } - var baseline1, baseline2, baseline3; var promiseDone = renderPDF(pdf1).then(function(data1) { baseline1 = data1; diff --git a/test/unit/custom_spec.js b/test/unit/custom_spec.js index f0a60a900..e729dc37b 100644 --- a/test/unit/custom_spec.js +++ b/test/unit/custom_spec.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { buildGetDocumentParams } from './test_utils'; +import { buildGetDocumentParams, NodeCanvasFactory } from './test_utils'; import { DOMCanvasFactory } from '../../src/display/dom_utils'; import { getDocument } from '../../src/display/api'; import isNodeJS from '../../src/shared/is_node'; @@ -37,8 +37,7 @@ describe('custom canvas rendering', function() { beforeAll(function(done) { if (isNodeJS()) { - // NOTE: To support running the canvas-related tests in Node.js, - // a `NodeCanvasFactory` would need to be added (in test_utils.js). + CanvasFactory = new NodeCanvasFactory(); } else { CanvasFactory = new DOMCanvasFactory(); } @@ -58,9 +57,6 @@ describe('custom canvas rendering', function() { }); it('renders to canvas with a default white background', function(done) { - if (isNodeJS()) { - pending('TODO: Support Canvas testing in Node.js.'); - } var viewport = page.getViewport({ scale: 1, }); var canvasAndCtx = CanvasFactory.create(viewport.width, viewport.height); @@ -77,9 +73,6 @@ describe('custom canvas rendering', function() { }); it('renders to canvas with a custom background', function(done) { - if (isNodeJS()) { - pending('TODO: Support Canvas testing in Node.js.'); - } var viewport = page.getViewport({ scale: 1, }); var canvasAndCtx = CanvasFactory.create(viewport.width, viewport.height); diff --git a/test/unit/test_utils.js b/test/unit/test_utils.js index c1e0337d4..175a8437d 100644 --- a/test/unit/test_utils.js +++ b/test/unit/test_utils.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { CMapCompressionType } from '../../src/shared/util'; +import { assert, CMapCompressionType } from '../../src/shared/util'; import isNodeJS from '../../src/shared/is_node'; import { isRef } from '../../src/core/primitives'; @@ -43,6 +43,38 @@ function buildGetDocumentParams(filename, options) { return params; } +class NodeCanvasFactory { + create(width, height) { + assert(width > 0 && height > 0, 'Invalid canvas size'); + + const Canvas = require('canvas'); + const canvas = Canvas.createCanvas(width, height); + return { + canvas, + context: canvas.getContext('2d'), + }; + } + + reset(canvasAndContext, width, height) { + assert(canvasAndContext.canvas, 'Canvas is not specified'); + assert(width > 0 && height > 0, 'Invalid canvas size'); + + canvasAndContext.canvas.width = width; + canvasAndContext.canvas.height = height; + } + + destroy(canvasAndContext) { + assert(canvasAndContext.canvas, 'Canvas is not specified'); + + // Zeroing the width and height cause Firefox to release graphics + // resources immediately, which can greatly reduce memory consumption. + canvasAndContext.canvas.width = 0; + canvasAndContext.canvas.height = 0; + canvasAndContext.canvas = null; + canvasAndContext.context = null; + } +} + class NodeCMapReaderFactory { constructor({ baseUrl = null, isCompressed = false, }) { this.baseUrl = baseUrl; @@ -111,6 +143,7 @@ class XRefMock { export { NodeFileReaderFactory, + NodeCanvasFactory, NodeCMapReaderFactory, XRefMock, buildGetDocumentParams,