From 9f649d7068f91fe5bedc37da8f1933bd1e39ee6e Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 22 Jun 2025 19:25:19 +0200 Subject: [PATCH 1/3] [WIP] Introduce a GitHub Actions workflow for running the integration tests --- .github/workflows/integration_tests.yml | 53 ++++++++++++++++++++++ test/integration/annotation_spec.mjs | 1 + test/integration/autolinker_spec.mjs | 1 + test/integration/find_spec.mjs | 1 + test/integration/freetext_editor_spec.mjs | 1 + test/integration/highlight_editor_spec.mjs | 1 + test/integration/jasmine-boot.js | 6 +-- test/integration/scripting_spec.mjs | 4 ++ test/test.mjs | 3 +- 9 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/integration_tests.yml diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml new file mode 100644 index 0000000000000..8b10d714d97db --- /dev/null +++ b/.github/workflows/integration_tests.yml @@ -0,0 +1,53 @@ +name: Integration tests +on: + push: + paths: + - '.github/workflows/integration_tests.yml' + branches: + - master + pull_request: + paths: + - '.github/workflows/integration_tests.yml' + branches: + - master + workflow_dispatch: +permissions: + contents: read + +jobs: + test: + name: Test + + strategy: + fail-fast: false + matrix: + node-version: [lts/*] + os: [windows-latest, ubuntu-latest] + + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm ci + + - name: Update resolution (Windows) + if: ${{ matrix.os == 'windows-latest' }} + run: Set-DisplayResolution -Width 1920 -Height 1080 -Force + + - name: Run integration tests (Windows) + if: ${{ matrix.os == 'windows-latest' }} + run: npx gulp integrationtest + + - name: Run integration tests (Linux) + if: ${{ matrix.os == 'ubuntu-latest' }} + run: xvfb-run -a --server-args="-screen 0, 1920x1080x24" npx gulp integrationtest diff --git a/test/integration/annotation_spec.mjs b/test/integration/annotation_spec.mjs index a5dcea58c39a9..06c8a560d6663 100644 --- a/test/integration/annotation_spec.mjs +++ b/test/integration/annotation_spec.mjs @@ -169,6 +169,7 @@ describe("Checkbox annotation", () => { let pages; beforeEach(async () => { + pending("Linked PDFs are not supported."); pages = await loadAndWait("bug1847733.pdf", getAnnotationSelector("18R")); }); diff --git a/test/integration/autolinker_spec.mjs b/test/integration/autolinker_spec.mjs index 503f9aed8e247..ec67f0a86d091 100644 --- a/test/integration/autolinker_spec.mjs +++ b/test/integration/autolinker_spec.mjs @@ -219,6 +219,7 @@ describe("autolinker", function () { let pages; beforeEach(async () => { + pending("Linked PDFs are not supported."); pages = await loadAndWait( "issue3115r.pdf", ".annotationLayer", diff --git a/test/integration/find_spec.mjs b/test/integration/find_spec.mjs index 91ea589ccec5f..fca60b3dc90cb 100644 --- a/test/integration/find_spec.mjs +++ b/test/integration/find_spec.mjs @@ -90,6 +90,7 @@ describe("find bar", () => { let pages; beforeEach(async () => { + pending("Linked PDFs are not supported."); pages = await loadAndWait("xfa_imm5257e.pdf", ".xfaLayer"); }); diff --git a/test/integration/freetext_editor_spec.mjs b/test/integration/freetext_editor_spec.mjs index b8a5cb4e6ba81..1839858401103 100644 --- a/test/integration/freetext_editor_spec.mjs +++ b/test/integration/freetext_editor_spec.mjs @@ -2391,6 +2391,7 @@ describe("FreeText Editor", () => { let pages; beforeEach(async () => { + pending("Linked PDFs are not supported."); pages = await loadAndWait("bug1823296.pdf", ".annotationEditorLayer"); }); diff --git a/test/integration/highlight_editor_spec.mjs b/test/integration/highlight_editor_spec.mjs index 094ef2b9f0ee7..a8160894eeb47 100644 --- a/test/integration/highlight_editor_spec.mjs +++ b/test/integration/highlight_editor_spec.mjs @@ -800,6 +800,7 @@ describe("Highlight Editor", () => { let pages; beforeEach(async () => { + pending("Linked PDFs are not supported."); pages = await loadAndWait( "issue12233.pdf", ".annotationEditorLayer", diff --git a/test/integration/jasmine-boot.js b/test/integration/jasmine-boot.js index 51590003cd1ac..478041151ffa0 100644 --- a/test/integration/jasmine-boot.js +++ b/test/integration/jasmine-boot.js @@ -53,7 +53,7 @@ async function runTests(results) { specDone(result) { // Report on the result of individual tests. ++results.runs; - if (result.failedExpectations.length > 0) { + if (result.failedExpectations.length > 0 && !result.pendingReason) { ++results.failures; console.log(`TEST-UNEXPECTED-FAIL | ${result.description}`); } else { @@ -63,14 +63,14 @@ async function runTests(results) { specStarted(result) {}, suiteDone(result) { // Report on the result of `afterAll` invocations. - if (result.failedExpectations.length > 0) { + if (result.failedExpectations.length > 0 && !result.pendingReason) { ++results.failures; console.log(`TEST-UNEXPECTED-FAIL | ${result.description}`); } }, suiteStarted(result) { // Report on the result of `beforeAll` invocations. - if (result.failedExpectations.length > 0) { + if (result.failedExpectations.length > 0 && !result.pendingReason) { ++results.failures; console.log(`TEST-UNEXPECTED-FAIL | ${result.description}`); } diff --git a/test/integration/scripting_spec.mjs b/test/integration/scripting_spec.mjs index 6dcb3aecc849f..f1ee5570c39c5 100644 --- a/test/integration/scripting_spec.mjs +++ b/test/integration/scripting_spec.mjs @@ -813,6 +813,7 @@ describe("Interaction", () => { let pages; beforeEach(async () => { + pending("Linked PDFs are not supported."); pages = await loadAndWait("issue13132.pdf", getSelector("171R")); }); @@ -1276,6 +1277,7 @@ describe("Interaction", () => { let pages; beforeEach(async () => { + pending("Linked PDFs are not supported."); pages = await loadAndWait("bug1766987.pdf", getSelector("75R")); }); @@ -1983,6 +1985,7 @@ describe("Interaction", () => { let pages; beforeEach(async () => { + pending("Linked PDFs are not supported."); pages = await loadAndWait("issue16863.pdf", getSelector("334R")); }); @@ -2122,6 +2125,7 @@ describe("Interaction", () => { let pages; beforeEach(async () => { + pending("Linked PDFs are not supported."); pages = await loadAndWait("bug1860602.pdf", getSelector("22R")); }); diff --git a/test/test.mjs b/test/test.mjs index ee9cf73408a4f..647c1f348215c 100644 --- a/test/test.mjs +++ b/test/test.mjs @@ -809,6 +809,7 @@ function onAllSessionsClosedAfterTests(name) { } var runtime = (Date.now() - startTime) / 1000; console.log(name + " tests runtime was " + runtime.toFixed(1) + " seconds"); + process.exit(numErrors > 0 ? 1 : 0); }; } @@ -1123,8 +1124,6 @@ async function main() { } else if (options.fontTest) { await startUnitTest("/test/font/font_test.html", "font"); } else if (options.integration) { - // Allows linked PDF files in integration-tests as well. - await ensurePDFsDownloaded(); await startIntegrationTest(); } else { await startRefTest(options.masterMode, options.reftest); From efa38636fe26454e673d8830d80ffffe3fe9183f Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 2 Nov 2025 18:38:58 +0100 Subject: [PATCH 2/3] [WIP] Download required linked PDFs only --- test/integration/annotation_spec.mjs | 1 - test/integration/autolinker_spec.mjs | 1 - test/integration/find_spec.mjs | 1 - test/integration/freetext_editor_spec.mjs | 1 - test/integration/highlight_editor_spec.mjs | 1 - test/integration/scripting_spec.mjs | 4 ---- test/test.mjs | 13 +++++++---- test/test_manifest.json | 27 ++++++++++++++-------- 8 files changed, 27 insertions(+), 22 deletions(-) diff --git a/test/integration/annotation_spec.mjs b/test/integration/annotation_spec.mjs index 06c8a560d6663..a5dcea58c39a9 100644 --- a/test/integration/annotation_spec.mjs +++ b/test/integration/annotation_spec.mjs @@ -169,7 +169,6 @@ describe("Checkbox annotation", () => { let pages; beforeEach(async () => { - pending("Linked PDFs are not supported."); pages = await loadAndWait("bug1847733.pdf", getAnnotationSelector("18R")); }); diff --git a/test/integration/autolinker_spec.mjs b/test/integration/autolinker_spec.mjs index ec67f0a86d091..503f9aed8e247 100644 --- a/test/integration/autolinker_spec.mjs +++ b/test/integration/autolinker_spec.mjs @@ -219,7 +219,6 @@ describe("autolinker", function () { let pages; beforeEach(async () => { - pending("Linked PDFs are not supported."); pages = await loadAndWait( "issue3115r.pdf", ".annotationLayer", diff --git a/test/integration/find_spec.mjs b/test/integration/find_spec.mjs index fca60b3dc90cb..91ea589ccec5f 100644 --- a/test/integration/find_spec.mjs +++ b/test/integration/find_spec.mjs @@ -90,7 +90,6 @@ describe("find bar", () => { let pages; beforeEach(async () => { - pending("Linked PDFs are not supported."); pages = await loadAndWait("xfa_imm5257e.pdf", ".xfaLayer"); }); diff --git a/test/integration/freetext_editor_spec.mjs b/test/integration/freetext_editor_spec.mjs index 1839858401103..b8a5cb4e6ba81 100644 --- a/test/integration/freetext_editor_spec.mjs +++ b/test/integration/freetext_editor_spec.mjs @@ -2391,7 +2391,6 @@ describe("FreeText Editor", () => { let pages; beforeEach(async () => { - pending("Linked PDFs are not supported."); pages = await loadAndWait("bug1823296.pdf", ".annotationEditorLayer"); }); diff --git a/test/integration/highlight_editor_spec.mjs b/test/integration/highlight_editor_spec.mjs index a8160894eeb47..094ef2b9f0ee7 100644 --- a/test/integration/highlight_editor_spec.mjs +++ b/test/integration/highlight_editor_spec.mjs @@ -800,7 +800,6 @@ describe("Highlight Editor", () => { let pages; beforeEach(async () => { - pending("Linked PDFs are not supported."); pages = await loadAndWait( "issue12233.pdf", ".annotationEditorLayer", diff --git a/test/integration/scripting_spec.mjs b/test/integration/scripting_spec.mjs index f1ee5570c39c5..6dcb3aecc849f 100644 --- a/test/integration/scripting_spec.mjs +++ b/test/integration/scripting_spec.mjs @@ -813,7 +813,6 @@ describe("Interaction", () => { let pages; beforeEach(async () => { - pending("Linked PDFs are not supported."); pages = await loadAndWait("issue13132.pdf", getSelector("171R")); }); @@ -1277,7 +1276,6 @@ describe("Interaction", () => { let pages; beforeEach(async () => { - pending("Linked PDFs are not supported."); pages = await loadAndWait("bug1766987.pdf", getSelector("75R")); }); @@ -1985,7 +1983,6 @@ describe("Interaction", () => { let pages; beforeEach(async () => { - pending("Linked PDFs are not supported."); pages = await loadAndWait("issue16863.pdf", getSelector("334R")); }); @@ -2125,7 +2122,6 @@ describe("Interaction", () => { let pages; beforeEach(async () => { - pending("Linked PDFs are not supported."); pages = await loadAndWait("bug1860602.pdf", getSelector("22R")); }); diff --git a/test/test.mjs b/test/test.mjs index 647c1f348215c..5403616d747f3 100644 --- a/test/test.mjs +++ b/test/test.mjs @@ -410,18 +410,21 @@ function handleSessionTimeout(session) { closeSession(browser); } -function getTestManifest() { +function getTestManifest(label = null) { var manifest = JSON.parse(fs.readFileSync(options.manifestFile)); const testFilter = options.testfilter.slice(0), xfaOnly = options.xfaOnly; - if (testFilter.length || xfaOnly) { + if (label || testFilter.length || xfaOnly) { manifest = manifest.filter(function (item) { var i = testFilter.indexOf(item.id); if (i !== -1) { testFilter.splice(i, 1); return true; } + if (label && item.labels?.includes(label)) { + return true; + } if (xfaOnly && item.enableXfa) { return true; } @@ -1089,8 +1092,8 @@ async function closeSession(browser) { } } -async function ensurePDFsDownloaded() { - const manifest = getTestManifest(); +async function ensurePDFsDownloaded(label = null) { + const manifest = getTestManifest(label); await downloadManifestFiles(manifest); try { await verifyManifestFiles(manifest); @@ -1124,6 +1127,8 @@ async function main() { } else if (options.fontTest) { await startUnitTest("/test/font/font_test.html", "font"); } else if (options.integration) { + // Allows linked PDF files in integration-tests as well. + await ensurePDFsDownloaded("integration"); await startIntegrationTest(); } else { await startRefTest(options.masterMode, options.reftest); diff --git a/test/test_manifest.json b/test/test_manifest.json index 97e0da048727c..2c5afd06bb937 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -1028,7 +1028,8 @@ "type": "eq", "link": true, "lastPage": 1, - "about": "The same file as issue2337." + "about": "The same file as issue2337.", + "labels": ["integration"] }, { "id": "freeculture", @@ -2081,7 +2082,8 @@ "rounds": 1, "link": true, "enableXfa": true, - "type": "eq" + "type": "eq", + "labels": ["integration"] }, { "id": "xfa_bug1716380", @@ -5165,7 +5167,8 @@ "file": "pdfs/issue13132.pdf", "md5": "1b28964b9188047bc6c786302c95029f", "link": true, - "type": "other" + "type": "other", + "labels": ["integration"] }, { "id": "issue11518", @@ -8494,7 +8497,8 @@ "link": true, "rounds": 1, "type": "eq", - "forms": true + "forms": true, + "labels": ["integration"] }, { "id": "issue12233-print", @@ -9109,7 +9113,8 @@ "md5": "3ce134ead03d6158c3e8207453dcd21d", "rounds": 1, "link": true, - "type": "other" + "type": "other", + "labels": ["integration"] }, { "id": "issue14301", @@ -9997,7 +10002,8 @@ "file": "pdfs/bug1823296.pdf", "md5": "f71e89ebe3d6e75e0c83ce41cd72df1f", "link": true, - "type": "other" + "type": "other", + "labels": ["integration"] }, { "id": "bug1942064", @@ -10441,7 +10447,8 @@ "md5": "d2e167216493a50f732b4b3685a91792", "rounds": 1, "link": true, - "type": "other" + "type": "other", + "labels": ["integration"] }, { "id": "protected-stamp-editor-save-print", @@ -10477,7 +10484,8 @@ "file": "pdfs/issue16863.pdf", "md5": "af8abe281721f92a0d46646969f061de", "link": true, - "type": "other" + "type": "other", + "labels": ["integration"] }, { "id": "bug1851498", @@ -10511,7 +10519,8 @@ "firstPage": 2, "lastPage": 2, "type": "eq", - "forms": true + "forms": true, + "labels": ["integration"] }, { "id": "issue17169", From d0e51f473d920a3caa85356d7bd13290a58a6f4c Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 4 Jan 2026 20:47:54 +0100 Subject: [PATCH 3/3] TEST --- test/integration/thumbnail_view_spec.mjs | 52 ++++++++++-------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/test/integration/thumbnail_view_spec.mjs b/test/integration/thumbnail_view_spec.mjs index 918e2f7f56dba..b52fb07417b97 100644 --- a/test/integration/thumbnail_view_spec.mjs +++ b/test/integration/thumbnail_view_spec.mjs @@ -1,15 +1,17 @@ import { - awaitPromise, closePages, kbFocusNext, loadAndWait, + scrollIntoView, + waitForPageRendered, } from "./test_utils.mjs"; -function waitForThumbnailVisible(page, pageNum) { - return page.waitForSelector( - `.thumbnailImage[data-l10n-args='{"page":${pageNum}}']`, - { visible: true } - ); +function waitForThumbnailVisible(page, pageNum, current = false) { + let selector = `.thumbnailImage[data-l10n-args='{"page":${pageNum}}']`; + if (current) { + selector += '[aria-current="page"]'; + } + return page.waitForSelector(selector, { visible: true }); } describe("PDF Thumbnail View", () => { @@ -32,7 +34,7 @@ describe("PDF Thumbnail View", () => { const thumbSelector = "#thumbnailsView .thumbnailImage"; await page.waitForSelector(thumbSelector, { visible: true }); - await waitForThumbnailVisible(page, 1); + await waitForThumbnailVisible(page, 1, /* current = */ true); const src = await page.$eval(thumbSelector, el => el.src); expect(src) @@ -47,42 +49,32 @@ describe("PDF Thumbnail View", () => { let pages; beforeEach(async () => { - pages = await loadAndWait("tracemonkey.pdf", "#viewsManagerToggleButton"); + pages = await loadAndWait( + "tracemonkey.pdf", + `.page[data-page-number = "1"] .endOfContent` + ); }); afterEach(async () => { await closePages(pages); }); - async function goToPage(page, number) { - const handle = await page.evaluateHandle( - num => [ - new Promise(resolve => { - const container = document.getElementById("viewsManagerContent"); - container.addEventListener("scrollend", resolve, { once: true }); - // eslint-disable-next-line no-undef - PDFViewerApplication.pdfLinkService.goToPage(num); - }), - ], - number - ); - return awaitPromise(handle); - } - it("should scroll the view", async () => { await Promise.all( pages.map(async ([browserName, page]) => { await page.click("#viewsManagerToggleButton"); - await waitForThumbnailVisible(page, 1); + await waitForThumbnailVisible(page, 1, /* current = */ true); for (const pageNum of [14, 1, 13, 2]) { - await goToPage(page, pageNum); + const pageSelector = `.page[data-page-number = "${pageNum}"]`; + await page.waitForSelector(pageSelector); + await scrollIntoView(page, pageSelector); + await waitForPageRendered(page, pageNum); + + await waitForThumbnailVisible(page, pageNum, /* current = */ true); + const thumbSelector = `.thumbnailImage[data-l10n-args='{"page":${pageNum}}']`; - await page.waitForSelector( - `.thumbnail ${thumbSelector}[aria-current="page"]`, - { visible: true } - ); const src = await page.$eval(thumbSelector, el => el.src); expect(src) .withContext(`In ${browserName}`) @@ -115,7 +107,7 @@ describe("PDF Thumbnail View", () => { pages.map(async ([browserName, page]) => { await page.click("#viewsManagerToggleButton"); - await waitForThumbnailVisible(page, 1); + await waitForThumbnailVisible(page, 1, /* current = */ true); await waitForThumbnailVisible(page, 2); await waitForThumbnailVisible(page, 3);