Merge pull request #21295 from Snuffleupagus/PDFDocumentProperties-more-tests

Add more integration-tests, with multi-page documents, for the `PDFDocumentProperties` dialog
This commit is contained in:
Tim van der Meij 2026-05-18 20:24:41 +02:00 committed by GitHub
commit 00af75905f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 288 additions and 69 deletions

View File

@ -33,21 +33,50 @@ const FIELDS = [
"linearized",
];
describe("PDFDocumentProperties", () => {
async function getFieldProperties(page) {
const promises = [];
async function openDocumentProperties(page) {
await page.click("#secondaryToolbarToggleButton");
await page.waitForSelector("#secondaryToolbar", { hidden: false });
for (const name of FIELDS) {
promises.push(
page.evaluate(
n => [n, document.getElementById(`${n}Field`).textContent],
name
)
);
}
return Object.fromEntries(await Promise.all(promises));
await page.click("#documentProperties");
await page.waitForSelector("#documentPropertiesDialog", {
hidden: false,
});
}
async function closeDocumentProperties(page) {
await page.click("#documentPropertiesClose");
await page.waitForSelector("#documentPropertiesDialog", {
hidden: true,
});
}
async function checkFieldProperties(page, expectedProps) {
await page.waitForFunction(
`document.getElementById("fileSizeField").textContent !== "-"`
);
const promises = [];
for (const name of FIELDS) {
promises.push(
page.evaluate(
n => [n, document.getElementById(`${n}Field`).textContent],
name
)
);
}
const props = Object.fromEntries(await Promise.all(promises));
expect(props).toEqual(expectedProps);
}
function getFieldDataLastUpdated(page) {
return page.evaluate(
() =>
document.getElementById("documentPropertiesDialog").dataset
.fieldDataLastUpdated
);
}
describe("PDFDocumentProperties", () => {
describe("Document with both /Info and /Metadata", () => {
let pages;
@ -59,23 +88,12 @@ describe("PDFDocumentProperties", () => {
await closePages(pages);
});
it("must check that the document properties dialog has the correct information", async () => {
it("check that the document properties dialog has the correct information", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await page.click("#secondaryToolbarToggleButton");
await page.waitForSelector("#secondaryToolbar", { hidden: false });
await openDocumentProperties(page);
await page.click("#documentProperties");
await page.waitForSelector("#documentPropertiesDialog", {
hidden: false,
});
await page.waitForFunction(
`document.getElementById("fileSizeField").textContent !== "-"`
);
const props = await getFieldProperties(page);
expect(props).toEqual({
await checkFieldProperties(page, {
fileName: "basicapi.pdf",
fileSize: `${FSI}103${PDI} KB (${FSI}105,779${PDI} bytes)`,
title: "Basic API Test",
@ -92,10 +110,7 @@ describe("PDFDocumentProperties", () => {
linearized: "No",
});
await page.click("#documentPropertiesClose");
await page.waitForSelector("#documentPropertiesDialog", {
hidden: true,
});
await closeDocumentProperties(page);
})
);
});
@ -115,23 +130,12 @@ describe("PDFDocumentProperties", () => {
await closePages(pages);
});
it("must check that the document properties dialog has the correct information", async () => {
it("check that the document properties dialog has the correct information", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await page.click("#secondaryToolbarToggleButton");
await page.waitForSelector("#secondaryToolbar", { hidden: false });
await openDocumentProperties(page);
await page.click("#documentProperties");
await page.waitForSelector("#documentPropertiesDialog", {
hidden: false,
});
await page.waitForFunction(
`document.getElementById("fileSizeField").textContent !== "-"`
);
const props = await getFieldProperties(page);
expect(props).toEqual({
await checkFieldProperties(page, {
fileName: "arial_unicode_en_cidfont.pdf",
fileSize: `${FSI}15.4${PDI} KB (${FSI}15,779${PDI} bytes)`,
title: "-",
@ -148,10 +152,7 @@ describe("PDFDocumentProperties", () => {
linearized: "No",
});
await page.click("#documentPropertiesClose");
await page.waitForSelector("#documentPropertiesDialog", {
hidden: true,
});
await closeDocumentProperties(page);
})
);
});
@ -168,7 +169,7 @@ describe("PDFDocumentProperties", () => {
await closePages(pages);
});
it("must check that the document properties dialog has the correct information", async () => {
it("check that the document properties dialog has the correct information", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
// Open a binary PDF document, such that `contentLength` is undefined.
@ -182,20 +183,9 @@ describe("PDFDocumentProperties", () => {
});
}, base64);
await page.click("#secondaryToolbarToggleButton");
await page.waitForSelector("#secondaryToolbar", { hidden: false });
await openDocumentProperties(page);
await page.click("#documentProperties");
await page.waitForSelector("#documentPropertiesDialog", {
hidden: false,
});
await page.waitForFunction(
`document.getElementById("fileSizeField").textContent !== "-"`
);
const props = await getFieldProperties(page);
expect(props).toEqual({
await checkFieldProperties(page, {
fileName: "document.pdf",
fileSize: `${FSI}0.448${PDI} KB (${FSI}459${PDI} bytes)`,
title: "-",
@ -212,10 +202,226 @@ describe("PDFDocumentProperties", () => {
linearized: "No",
});
await page.click("#documentPropertiesClose");
await page.waitForSelector("#documentPropertiesDialog", {
hidden: true,
await closeDocumentProperties(page);
})
);
});
});
describe("Document with multiple pages, and changed viewer page/rotation", () => {
let pages;
beforeEach(async () => {
pages = await loadAndWait("basicapi.pdf", ".textLayer .endOfContent");
});
afterEach(async () => {
await closePages(pages);
});
it("check that the document properties dialog has the correct information", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await openDocumentProperties(page);
await checkFieldProperties(page, {
fileName: "basicapi.pdf",
fileSize: `${FSI}103${PDI} KB (${FSI}105,779${PDI} bytes)`,
title: "Basic API Test",
author: "Brendan Dahl",
subject: "-",
keywords: "TCPDF",
creationDate: "4/10/12, 7:30:26 AM",
modificationDate: "4/10/12, 7:30:26 AM",
creator: "TCPDF",
producer: "TCPDF 5.9.133 (http://www.tcpdf.org)",
version: "1.7",
pageCount: "3",
pageSize: `${FSI}8.27${PDI} × ${FSI}11.69${PDI} ${FSI}in${PDI} (${FSI}A4${PDI}, ${FSI}portrait${PDI})`,
linearized: "No",
});
const fieldDataLastUpdated = await getFieldDataLastUpdated(page);
await closeDocumentProperties(page);
// Ensure that immediately re-opening the dialog doesn't cause
// the field-data to be fetched and parsed again.
await openDocumentProperties(page);
expect(await getFieldDataLastUpdated(page)).toEqual(
fieldDataLastUpdated
);
await closeDocumentProperties(page);
// Goto the second page, and rotate the document.
await page.click("#next");
await page.waitForFunction(
() => window.PDFViewerApplication.page === 2
);
await page.keyboard.press("r");
await page.waitForFunction(
() => window.PDFViewerApplication.pdfViewer.pagesRotation === 90
);
await openDocumentProperties(page);
await checkFieldProperties(page, {
fileName: "basicapi.pdf",
fileSize: `${FSI}103${PDI} KB (${FSI}105,779${PDI} bytes)`,
title: "Basic API Test",
author: "Brendan Dahl",
subject: "-",
keywords: "TCPDF",
creationDate: "4/10/12, 7:30:26 AM",
modificationDate: "4/10/12, 7:30:26 AM",
creator: "TCPDF",
producer: "TCPDF 5.9.133 (http://www.tcpdf.org)",
version: "1.7",
pageCount: "3",
pageSize: `${FSI}11.69${PDI} × ${FSI}8.27${PDI} ${FSI}in${PDI} (${FSI}A4${PDI}, ${FSI}landscape${PDI})`,
linearized: "No",
});
await closeDocumentProperties(page);
})
);
});
});
describe("Document with different page sizes", () => {
let pages;
beforeEach(async () => {
pages = await loadAndWait("sizes.pdf", ".textLayer .endOfContent");
});
afterEach(async () => {
await closePages(pages);
});
it("check that the document properties dialog has the correct information", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await openDocumentProperties(page);
await checkFieldProperties(page, {
fileName: "sizes.pdf",
fileSize: `${FSI}13.4${PDI} KB (${FSI}13,739${PDI} bytes)`,
title: "-",
author: "Yury ",
subject: "-",
keywords: "-",
creationDate: "6/26/11, 1:26:03 PM",
modificationDate: "-",
creator: "Writer",
producer: "OpenOffice.org 3.3",
version: "1.4",
pageCount: "3",
pageSize: `${FSI}8.5${PDI} × ${FSI}11${PDI} ${FSI}in${PDI} (${FSI}Letter${PDI}, ${FSI}portrait${PDI})`,
linearized: "No",
});
await closeDocumentProperties(page);
// Goto the second page.
await page.click("#next");
await page.waitForFunction(
() => window.PDFViewerApplication.page === 2
);
await openDocumentProperties(page);
await checkFieldProperties(page, {
fileName: "sizes.pdf",
fileSize: `${FSI}13.4${PDI} KB (${FSI}13,739${PDI} bytes)`,
title: "-",
author: "Yury ",
subject: "-",
keywords: "-",
creationDate: "6/26/11, 1:26:03 PM",
modificationDate: "-",
creator: "Writer",
producer: "OpenOffice.org 3.3",
version: "1.4",
pageCount: "3",
pageSize: `${FSI}9.01${PDI} × ${FSI}4.49${PDI} ${FSI}in${PDI} (${FSI}landscape${PDI})`,
linearized: "No",
});
await closeDocumentProperties(page);
})
);
});
});
describe("Document with corrupt page", () => {
let pages;
beforeEach(async () => {
pages = await loadAndWait(
"Pages-tree-refs.pdf",
".textLayer .endOfContent",
null,
null,
{ page: 2 }
);
});
afterEach(async () => {
await closePages(pages);
});
it("check that the document properties dialog has the correct information", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await openDocumentProperties(page);
await checkFieldProperties(page, {
fileName: "Pages-tree-refs.pdf",
fileSize: `${FSI}1.07${PDI} KB (${FSI}1,098${PDI} bytes)`,
title: "-",
author: "-",
subject: "-",
keywords: "-",
creationDate: "-",
modificationDate: "-",
creator: "-",
producer: "-",
version: "1.7",
pageCount: "2",
pageSize: "-",
linearized: "No",
});
await closeDocumentProperties(page);
// Goto the first page (which is *not* corrupt).
await page.click("#previous");
await page.waitForFunction(
() => window.PDFViewerApplication.page === 1
);
await openDocumentProperties(page);
await checkFieldProperties(page, {
fileName: "Pages-tree-refs.pdf",
fileSize: `${FSI}1.07${PDI} KB (${FSI}1,098${PDI} bytes)`,
title: "-",
author: "-",
subject: "-",
keywords: "-",
creationDate: "-",
modificationDate: "-",
creator: "-",
producer: "-",
version: "1.7",
pageCount: "2",
pageSize: `${FSI}8.27${PDI} × ${FSI}11.69${PDI} ${FSI}in${PDI} (${FSI}A4${PDI}, ${FSI}portrait${PDI})`,
linearized: "No",
});
await closeDocumentProperties(page);
})
);
});

View File

@ -111,6 +111,9 @@ class PDFDocumentProperties {
this.#updateUI();
return;
}
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
this._fieldDataLastUpdated = Date.now();
}
// Get the document properties.
const [
@ -118,7 +121,13 @@ class PDFDocumentProperties {
pdfPage,
] = await Promise.all([
this.pdfDocument.getMetadata(),
this.pdfDocument.getPage(currentPageNumber),
this.pdfDocument.getPage(currentPageNumber).catch(reason => {
console.error(
`PDFDocumentProperties - unable to get page ${currentPageNumber}.`,
reason
);
return null;
}),
]);
const [
@ -135,7 +144,7 @@ class PDFDocumentProperties {
this._titleLookup(),
this.#parseDate(metadata?.get("xmp:createdate"), info.CreationDate),
this.#parseDate(metadata?.get("xmp:modifydate"), info.ModDate),
this.#parsePageSize(getPageSizeInches(pdfPage), pagesRotation),
this.#parsePageSize(pdfPage, pagesRotation),
this.#parseLinearization(info.IsLinearized),
]);
@ -220,6 +229,9 @@ class PDFDocumentProperties {
// since it will be updated the next time `this.open` is called.
return;
}
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
this.dialog.dataset.fieldDataLastUpdated = this._fieldDataLastUpdated;
}
for (const id in this.fields) {
const content = this.#fieldData?.[id];
this.fields[id].textContent = content || content === 0 ? content : "-";
@ -239,10 +251,11 @@ class PDFDocumentProperties {
: undefined;
}
async #parsePageSize(pageSizeInches, pagesRotation) {
if (!pageSizeInches) {
async #parsePageSize(pdfPage, pagesRotation) {
if (!pdfPage) {
return undefined;
}
let pageSizeInches = getPageSizeInches(pdfPage);
// Take the viewer rotation into account as well; compare with Adobe Reader.
if (pagesRotation % 180 !== 0) {
pageSizeInches = {