From 8f502b88dae495f0bc723c64492bb776269b2f42 Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 28 Oct 2025 07:11:21 +0000 Subject: [PATCH 01/39] Added downloaded pdf report verify --- ui-tests/cypress.config.sample.js | 114 +++ .../e2e/dashboard/dashboards/dashboards.cy.js | 52 +- ui-tests/package-lock.json | 712 +++++++++++++++++- ui-tests/package.json | 6 +- 4 files changed, 879 insertions(+), 5 deletions(-) diff --git a/ui-tests/cypress.config.sample.js b/ui-tests/cypress.config.sample.js index 2154821f775..99e47bdeb33 100644 --- a/ui-tests/cypress.config.sample.js +++ b/ui-tests/cypress.config.sample.js @@ -1,5 +1,9 @@ const { defineConfig } = require("cypress"); const fs = require('fs'); +const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.js"); +const PNG = require("pngjs").PNG; +const sharp = require("sharp"); +const extract = require("pdf-text-extract"); module.exports = defineConfig({ e2e: { @@ -14,6 +18,116 @@ module.exports = defineConfig({ watchForFileChanges: true, video: true, setupNodeEvents(on, config) { + //Task: checks if the PDF contains embedded images and verifies logo existence and text content + on("task", { + // --- Check if PDF contains any image --- + async verifyPdf({ filePath, options = {} }) { + // options: { referenceLogoPath: string, checkText: true/false } + try { + if (typeof global.DOMMatrix === "undefined") { + global.DOMMatrix = class DOMMatrix { }; + } + + // PDF loading + const data = new Uint8Array(fs.readFileSync(filePath)); + const pdfDoc = await pdfjsLib.getDocument({ data }).promise; + + // Dynamic import pixelmatch if logo check is needed + let pixelmatch; + const doLogoCheck = !!options.referenceLogoPath; + if (doLogoCheck) { + const pm = await import("pixelmatch"); + pixelmatch = pm.default; + } + + let hasImage = false; + let logoFound = false; + let extractedText = ""; + + for (let p = 1; p <= pdfDoc.numPages; p++) { + const page = await pdfDoc.getPage(p); + + // --- Text extraction --- + if (options.checkText) { + extractedText += await new Promise((resolve, reject) => { + extract(filePath, (err, pages) => { + if (err) return reject(err); + resolve(pages.join("\n")); + }); + }); + } + + const ops = await page.getOperatorList(); + + for (let i = 0; i < ops.fnArray.length; i++) { + const fn = ops.fnArray[i]; + const args = ops.argsArray[i]; + + // --- Image check --- + if ( + fn === pdfjsLib.OPS.paintImageXObject || + fn === pdfjsLib.OPS.paintJpegXObject || + fn === pdfjsLib.OPS.paintInlineImageXObject + ) { + hasImage = true; + + if (doLogoCheck && args[0]) { + const objName = args[0]; + const imgData = await page.objs.get(objName); + if (!imgData) continue; + + const pdfImg = new PNG({ width: imgData.width, height: imgData.height }); + pdfImg.data = imgData.data; + + // resize PDF image to reference logo size + const pdfBuffer = PNG.sync.write(pdfImg); + const refLogo = PNG.sync.read(fs.readFileSync(options.referenceLogoPath)); + const resizedPdfBuffer = await sharp(pdfBuffer) + .resize(refLogo.width, refLogo.height) + .png() + .toBuffer(); + + const resizedPdfImg = PNG.sync.read(resizedPdfBuffer); + + // pixelmatch + const diff = new PNG({ width: refLogo.width, height: refLogo.height }); + const mismatched = pixelmatch( + refLogo.data, + resizedPdfImg.data, + diff.data, + refLogo.width, + refLogo.height, + { threshold: 0.1 } + ); + + if (mismatched === 0) { + logoFound = true; + break; + } + } + } + } + + if ((doLogoCheck && logoFound) || (!doLogoCheck && hasImage)) { + break; + } + } + + if (doLogoCheck && !logoFound) { + throw new Error("Logo in PDF does not match reference image"); + } + + return { + hasImage, + logoFound, + text: extractedText, + numPages: pdfDoc.numPages + }; + } catch (err) { + throw err; + } + } + }); on('after:spec', (spec, results) => { if (results && results.video) { const failures = results.tests.some((test) => diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 08d44c44385..1b028e0016e 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -10,7 +10,7 @@ const { VISUALIZATION_TYPE, TIME_UNITS } = require('../../../support/constants') describe('Create New Custom Dashboard', () => { - beforeEach(function() { + beforeEach(function () { navigationHelpers.goToLoginPage(); loginHelpers.login(user.username, user.password); navigationHelpers.openDashboardsMenu(); @@ -29,7 +29,7 @@ describe('Create New Custom Dashboard', () => { //***Report*** Report Type: Dashboard Report Frequency: Daily - `, function() { + `, function () { const dashboard = generateDashboardFixture(); const report = generateReportFixture(); @@ -84,9 +84,55 @@ describe('Create New Custom Dashboard', () => { reportHelper.openReportPreviewButton(); reportHelper.verifyReportPreviewPageImage(); + + // Get the current URL + cy.url().then((currentUrl) => { + + //Get API key + getApiKey.request(user.username, user.password).then((apiKey) => { + + //Change preview to PDF and add api_key parameter + const urlObj = new URL(currentUrl); + urlObj.pathname = urlObj.pathname.replace('preview', 'pdf'); + urlObj.searchParams.set('api_key', apiKey); + const pdfURL = urlObj.toString(); + + cy.log('Generated PDF URL:', pdfURL); + + //Download the PDF and verify its content + cy.request({ + url: pdfURL, + encoding: 'binary', + }).then((response) => { + expect(response.status).to.eq(200); + expect(response.headers['content-type']).to.include('application/pdf'); + + const buf = Buffer.from(response.body, 'binary'); + expect(buf.slice(0, 4).toString()).to.eq('%PDF'); + expect(buf.length).to.be.greaterThan(50000); // More than 50KB to ensure it's not empty + + // Save the PDF to disk (optional) + cy.writeFile('cypress/downloads/generated-report.pdf', buf); + }); + }); + }); + + // Verify PDF content + cy.task("verifyPdf", { + filePath: "cypress/downloads/generated-report.pdf", + options: { + referenceLogoPath: "Cypress/fixtures/testFiles/countly-logo.png", + checkText: true + } + }).then((result) => { + expect(result.logoFound).to.be.true; + expect(result.hasImage).to.be.true; + expect(result.text).to.include("Sent by Countly | Unsubscribe"); + expect(result.text).to.include("Report settings | Get help"); + }); }); - it(`Create a private custom dashboard and duplicate it and edit it and delete it then verify the flow`, function() { + it(`Create a private custom dashboard and duplicate it and edit it and delete it then verify the flow`, function () { const dashboard = generateDashboardFixture(); const editedDashboard = generateDashboardFixture(); diff --git a/ui-tests/package-lock.json b/ui-tests/package-lock.json index ba44c9a2686..db48d1dcea4 100644 --- a/ui-tests/package-lock.json +++ b/ui-tests/package-lock.json @@ -13,7 +13,11 @@ "base-64": "^1.0.0", "chai": "^6.0.1", "cypress-file-upload": "^5.0.8", - "moment": "^2.29.4" + "moment": "^2.29.4", + "pdfjs-dist": "^5.4.296", + "pixelmatch": "^7.1.0", + "pngjs": "^7.0.0", + "sharp": "^0.34.4" }, "devDependencies": { "cypress": "^13.4.0" @@ -65,6 +69,16 @@ "ms": "^2.1.1" } }, + "node_modules/@emnapi/runtime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.6.0.tgz", + "integrity": "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@faker-js/faker": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.1.0.tgz", @@ -81,6 +95,618 @@ "npm": ">=10" } }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.4.tgz", + "integrity": "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.3" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.4.tgz", + "integrity": "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.3" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.3.tgz", + "integrity": "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.3.tgz", + "integrity": "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.3.tgz", + "integrity": "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.3.tgz", + "integrity": "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.3.tgz", + "integrity": "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.3.tgz", + "integrity": "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.3.tgz", + "integrity": "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.3.tgz", + "integrity": "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz", + "integrity": "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.4.tgz", + "integrity": "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.3" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.4.tgz", + "integrity": "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.3" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.4.tgz", + "integrity": "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.3" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.4.tgz", + "integrity": "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.3" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz", + "integrity": "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.3" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.4.tgz", + "integrity": "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.3" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz", + "integrity": "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.3" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.4.tgz", + "integrity": "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.5.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.4.tgz", + "integrity": "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.4.tgz", + "integrity": "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz", + "integrity": "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@napi-rs/canvas": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.81.tgz", + "integrity": "sha512-ReCjd5SYI/UKx/olaQLC4GtN6wUQGjlgHXs1lvUvWGXfBMR3Fxnik3cL+OxKN5ithNdoU0/GlCrdKcQDFh2XKQ==", + "license": "MIT", + "optional": true, + "workspaces": [ + "e2e/*" + ], + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.81", + "@napi-rs/canvas-darwin-arm64": "0.1.81", + "@napi-rs/canvas-darwin-x64": "0.1.81", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.81", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.81", + "@napi-rs/canvas-linux-arm64-musl": "0.1.81", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.81", + "@napi-rs/canvas-linux-x64-gnu": "0.1.81", + "@napi-rs/canvas-linux-x64-musl": "0.1.81", + "@napi-rs/canvas-win32-x64-msvc": "0.1.81" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.81.tgz", + "integrity": "sha512-78Lz+AUi+MsWupyZjXwpwQrp1QCwncPvRZrdvrROcZ9Gq9grP7LfQZiGdR8LKyHIq3OR18mDP+JESGT15V1nXw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.81.tgz", + "integrity": "sha512-omejuKgHWKDGoh8rsgsyhm/whwxMaryTQjJTd9zD7hiB9/rzcEEJLHnzXWR5ysy4/tTjHaQotE6k2t8eodTLnA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.81.tgz", + "integrity": "sha512-EYfk+co6BElq5DXNH9PBLYDYwc4QsvIVbyrsVHsxVpn4p6Y3/s8MChgC69AGqj3vzZBQ1qx2CRCMtg5cub+XuQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.81.tgz", + "integrity": "sha512-teh6Q74CyAcH31yLNQGR9MtXSFxlZa5CI6vvNUISI14gWIJWrhOwUAOly+KRe1aztWR0FWTVSPxM4p5y+06aow==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.81.tgz", + "integrity": "sha512-AGEopHFYRzJOjxY+2G1RmHPRnuWvO3Qdhq7sIazlSjxb3Z6dZHg7OB/4ZimXaimPjDACm9qWa6t5bn9bhXvkcw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.81.tgz", + "integrity": "sha512-Bj3m1cl4GIhsigkdwOxii4g4Ump3/QhNpx85IgAlCCYXpaly6mcsWpuDYEabfIGWOWhDUNBOndaQUPfWK1czOQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.81.tgz", + "integrity": "sha512-yg/5NkHykVdwPlD3XObwCa/EswkOwLHswJcI9rHrac+znHsmCSj5AMX/RTU9Z9F6lZTwL60JM2Esit33XhAMiw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.81.tgz", + "integrity": "sha512-tPfMpSEBuV5dJSKexO/UZxpOqnYTaNbG8aKa1ek8QsWu+4SJ/foWkaxscra/RUv85vepx6WWDjzBNbNJsTnO0w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.81.tgz", + "integrity": "sha512-1L0xnYgzqn8Baef+inPvY4dKqdmw3KCBoe0NEDgezuBZN7MA5xElwifoG8609uNdrMtJ9J6QZarsslLRVqri7g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.81.tgz", + "integrity": "sha512-57ryVbhm/z7RE9/UVcS7mrLPdlayLesy+9U0Uf6epCoeSGrs99tfieCcgZWFbIgmByQ1AZnNtFI2N6huqDLlWQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@types/node": { "version": "18.18.8", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.8.tgz", @@ -658,6 +1284,15 @@ "node": ">=0.4.0" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -1473,6 +2108,18 @@ "node": ">=8" } }, + "node_modules/pdfjs-dist": { + "version": "5.4.296", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.4.296.tgz", + "integrity": "sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.16.0 || >=22.3.0" + }, + "optionalDependencies": { + "@napi-rs/canvas": "^0.1.80" + } + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -1492,6 +2139,27 @@ "node": ">=0.10.0" } }, + "node_modules/pixelmatch": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-7.1.0.tgz", + "integrity": "sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==", + "license": "ISC", + "dependencies": { + "pngjs": "^7.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, + "node_modules/pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", + "license": "MIT", + "engines": { + "node": ">=14.19.0" + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -1611,6 +2279,48 @@ "node": ">=10" } }, + "node_modules/sharp": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz", + "integrity": "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.0", + "semver": "^7.7.2" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.4", + "@img/sharp-darwin-x64": "0.34.4", + "@img/sharp-libvips-darwin-arm64": "1.2.3", + "@img/sharp-libvips-darwin-x64": "1.2.3", + "@img/sharp-libvips-linux-arm": "1.2.3", + "@img/sharp-libvips-linux-arm64": "1.2.3", + "@img/sharp-libvips-linux-ppc64": "1.2.3", + "@img/sharp-libvips-linux-s390x": "1.2.3", + "@img/sharp-libvips-linux-x64": "1.2.3", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", + "@img/sharp-libvips-linuxmusl-x64": "1.2.3", + "@img/sharp-linux-arm": "0.34.4", + "@img/sharp-linux-arm64": "0.34.4", + "@img/sharp-linux-ppc64": "0.34.4", + "@img/sharp-linux-s390x": "0.34.4", + "@img/sharp-linux-x64": "0.34.4", + "@img/sharp-linuxmusl-arm64": "0.34.4", + "@img/sharp-linuxmusl-x64": "0.34.4", + "@img/sharp-wasm32": "0.34.4", + "@img/sharp-win32-arm64": "0.34.4", + "@img/sharp-win32-ia32": "0.34.4", + "@img/sharp-win32-x64": "0.34.4" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", diff --git a/ui-tests/package.json b/ui-tests/package.json index 2cdd3f309c8..c74f034ed56 100644 --- a/ui-tests/package.json +++ b/ui-tests/package.json @@ -13,7 +13,11 @@ "base-64": "^1.0.0", "chai": "^6.0.1", "cypress-file-upload": "^5.0.8", - "moment": "^2.29.4" + "moment": "^2.29.4", + "pdfjs-dist": "^5.4.296", + "pixelmatch": "^7.1.0", + "pngjs": "^7.0.0", + "sharp": "^0.34.4" }, "devDependencies": { "cypress": "^13.4.0" From 801ccb2ec16c1f37a54ce1cc53e7c7c3ea6ebfdc Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 28 Oct 2025 07:14:55 +0000 Subject: [PATCH 02/39] Added tewst suite name for only run --- ui-tests/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-tests/package.json b/ui-tests/package.json index c74f034ed56..4eaff562588 100644 --- a/ui-tests/package.json +++ b/ui-tests/package.json @@ -4,7 +4,7 @@ "description": "e2e testing", "author": "Countly, Inc.", "scripts": { - "cy:run:dashboard": "node ./cypress/fixtures/generators/generateFixtures.js && cypress run --record --key 00000000-0000-0000-0000-000000000000 --spec **/dashboard/**/*.cy.js --headless --no-runner-ui --browser chrome", + "cy:run:dashboard": "node ./cypress/fixtures/generators/generateFixtures.js && cypress run --record --key 00000000-0000-0000-0000-000000000000 --spec **/dashboard/**/dashboards.cy.js --headless --no-runner-ui --browser chrome", "cy:run:onboarding": "cypress run --record --key 00000000-0000-0000-0000-000000000000 --spec **/onboarding/**/*.cy.js --headless --no-runner-ui --browser chrome" }, "license": "ISC", From 5b8b33d1b60cca75d221dca0fc0f13ad2dd9bab8 Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 28 Oct 2025 07:39:14 +0000 Subject: [PATCH 03/39] Fixed linter errors --- .eslintrc.json | 6 +++++- ui-tests/cypress.config.sample.js | 11 ++++++++--- .../cypress/e2e/dashboard/dashboards/dashboards.cy.js | 7 ++++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 162dc7b5913..b376d091bae 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -629,8 +629,12 @@ "env": { "es2023": true, "node": true, - "mocha": true + "mocha": true, + "cypress/globals": true }, + "plugins": [ + "cypress" + ], "globals": { "Cypress": "readonly", "cy": "readonly" diff --git a/ui-tests/cypress.config.sample.js b/ui-tests/cypress.config.sample.js index 99e47bdeb33..a88af47d3e8 100644 --- a/ui-tests/cypress.config.sample.js +++ b/ui-tests/cypress.config.sample.js @@ -51,7 +51,9 @@ module.exports = defineConfig({ if (options.checkText) { extractedText += await new Promise((resolve, reject) => { extract(filePath, (err, pages) => { - if (err) return reject(err); + if (err) { + return reject(err); + } resolve(pages.join("\n")); }); }); @@ -74,7 +76,9 @@ module.exports = defineConfig({ if (doLogoCheck && args[0]) { const objName = args[0]; const imgData = await page.objs.get(objName); - if (!imgData) continue; + if (!imgData) { + continue; + } const pdfImg = new PNG({ width: imgData.width, height: imgData.height }); pdfImg.data = imgData.data; @@ -123,7 +127,8 @@ module.exports = defineConfig({ text: extractedText, numPages: pdfDoc.numPages }; - } catch (err) { + } + catch (err) { throw err; } } diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 1b028e0016e..0b96dbf4871 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -1,4 +1,5 @@ import user from '../../../fixtures/user.json'; +const getApiKey = require('../../../api/getApiKey'); const navigationHelpers = require('../../../support/navigations'); const helper = require('../../../support/helper'); const loginHelpers = require('../../../lib/login/login'); @@ -10,7 +11,7 @@ const { VISUALIZATION_TYPE, TIME_UNITS } = require('../../../support/constants') describe('Create New Custom Dashboard', () => { - beforeEach(function () { + beforeEach(function() { navigationHelpers.goToLoginPage(); loginHelpers.login(user.username, user.password); navigationHelpers.openDashboardsMenu(); @@ -29,7 +30,7 @@ describe('Create New Custom Dashboard', () => { //***Report*** Report Type: Dashboard Report Frequency: Daily - `, function () { + `, function() { const dashboard = generateDashboardFixture(); const report = generateReportFixture(); @@ -132,7 +133,7 @@ describe('Create New Custom Dashboard', () => { }); }); - it(`Create a private custom dashboard and duplicate it and edit it and delete it then verify the flow`, function () { + it(`Create a private custom dashboard and duplicate it and edit it and delete it then verify the flow`, function() { const dashboard = generateDashboardFixture(); const editedDashboard = generateDashboardFixture(); From 45053c73c74306bd2f9e0e1295466bce4ce98ba2 Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 28 Oct 2025 07:49:20 +0000 Subject: [PATCH 04/39] Fix linter errors --- .eslintrc.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index b376d091bae..9b7365895ac 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -630,11 +630,8 @@ "es2023": true, "node": true, "mocha": true, - "cypress/globals": true + "cypress": true }, - "plugins": [ - "cypress" - ], "globals": { "Cypress": "readonly", "cy": "readonly" From 9eabfc2268091a7915fe03605846374fa1192015 Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 28 Oct 2025 07:51:22 +0000 Subject: [PATCH 05/39] Removed cypress eslint parameters --- .eslintrc.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 9b7365895ac..162dc7b5913 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -629,8 +629,7 @@ "env": { "es2023": true, "node": true, - "mocha": true, - "cypress": true + "mocha": true }, "globals": { "Cypress": "readonly", From a4d36f77567055e46359da0c90daa11c9244434a Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 28 Oct 2025 07:54:15 +0000 Subject: [PATCH 06/39] Fix linter errors --- ui-tests/cypress.config.sample.js | 185 +++++++++--------- .../e2e/dashboard/dashboards/dashboards.cy.js | 3 + 2 files changed, 93 insertions(+), 95 deletions(-) diff --git a/ui-tests/cypress.config.sample.js b/ui-tests/cypress.config.sample.js index a88af47d3e8..ced149a1296 100644 --- a/ui-tests/cypress.config.sample.js +++ b/ui-tests/cypress.config.sample.js @@ -23,114 +23,109 @@ module.exports = defineConfig({ // --- Check if PDF contains any image --- async verifyPdf({ filePath, options = {} }) { // options: { referenceLogoPath: string, checkText: true/false } - try { - if (typeof global.DOMMatrix === "undefined") { - global.DOMMatrix = class DOMMatrix { }; - } + if (typeof global.DOMMatrix === "undefined") { + global.DOMMatrix = class DOMMatrix { }; + } - // PDF loading - const data = new Uint8Array(fs.readFileSync(filePath)); - const pdfDoc = await pdfjsLib.getDocument({ data }).promise; + // PDF loading + const data = new Uint8Array(fs.readFileSync(filePath)); + const pdfDoc = await pdfjsLib.getDocument({ data }).promise; - // Dynamic import pixelmatch if logo check is needed - let pixelmatch; - const doLogoCheck = !!options.referenceLogoPath; - if (doLogoCheck) { - const pm = await import("pixelmatch"); - pixelmatch = pm.default; - } + // Dynamic import pixelmatch if logo check is needed + let pixelmatch; + const doLogoCheck = !!options.referenceLogoPath; + if (doLogoCheck) { + const pm = await import("pixelmatch"); + pixelmatch = pm.default; + } - let hasImage = false; - let logoFound = false; - let extractedText = ""; - - for (let p = 1; p <= pdfDoc.numPages; p++) { - const page = await pdfDoc.getPage(p); - - // --- Text extraction --- - if (options.checkText) { - extractedText += await new Promise((resolve, reject) => { - extract(filePath, (err, pages) => { - if (err) { - return reject(err); - } - resolve(pages.join("\n")); - }); + let hasImage = false; + let logoFound = false; + let extractedText = ""; + + for (let p = 1; p <= pdfDoc.numPages; p++) { + const page = await pdfDoc.getPage(p); + + // --- Text extraction --- + if (options.checkText) { + extractedText += await new Promise((resolve, reject) => { + extract(filePath, (err, pages) => { + if (err) { + return reject(err); + } + resolve(pages.join("\n")); }); - } + }); + } - const ops = await page.getOperatorList(); - - for (let i = 0; i < ops.fnArray.length; i++) { - const fn = ops.fnArray[i]; - const args = ops.argsArray[i]; - - // --- Image check --- - if ( - fn === pdfjsLib.OPS.paintImageXObject || - fn === pdfjsLib.OPS.paintJpegXObject || - fn === pdfjsLib.OPS.paintInlineImageXObject - ) { - hasImage = true; - - if (doLogoCheck && args[0]) { - const objName = args[0]; - const imgData = await page.objs.get(objName); - if (!imgData) { - continue; - } - - const pdfImg = new PNG({ width: imgData.width, height: imgData.height }); - pdfImg.data = imgData.data; - - // resize PDF image to reference logo size - const pdfBuffer = PNG.sync.write(pdfImg); - const refLogo = PNG.sync.read(fs.readFileSync(options.referenceLogoPath)); - const resizedPdfBuffer = await sharp(pdfBuffer) - .resize(refLogo.width, refLogo.height) - .png() - .toBuffer(); - - const resizedPdfImg = PNG.sync.read(resizedPdfBuffer); - - // pixelmatch - const diff = new PNG({ width: refLogo.width, height: refLogo.height }); - const mismatched = pixelmatch( - refLogo.data, - resizedPdfImg.data, - diff.data, - refLogo.width, - refLogo.height, - { threshold: 0.1 } - ); - - if (mismatched === 0) { - logoFound = true; - break; - } + const ops = await page.getOperatorList(); + + for (let i = 0; i < ops.fnArray.length; i++) { + const fn = ops.fnArray[i]; + const args = ops.argsArray[i]; + + // --- Image check --- + if ( + fn === pdfjsLib.OPS.paintImageXObject || + fn === pdfjsLib.OPS.paintJpegXObject || + fn === pdfjsLib.OPS.paintInlineImageXObject + ) { + hasImage = true; + + if (doLogoCheck && args[0]) { + const objName = args[0]; + const imgData = await page.objs.get(objName); + if (!imgData) { + continue; } - } - } - if ((doLogoCheck && logoFound) || (!doLogoCheck && hasImage)) { - break; + const pdfImg = new PNG({ width: imgData.width, height: imgData.height }); + pdfImg.data = imgData.data; + + // resize PDF image to reference logo size + const pdfBuffer = PNG.sync.write(pdfImg); + const refLogo = PNG.sync.read(fs.readFileSync(options.referenceLogoPath)); + const resizedPdfBuffer = await sharp(pdfBuffer) + .resize(refLogo.width, refLogo.height) + .png() + .toBuffer(); + + const resizedPdfImg = PNG.sync.read(resizedPdfBuffer); + + // pixelmatch + const diff = new PNG({ width: refLogo.width, height: refLogo.height }); + const mismatched = pixelmatch( + refLogo.data, + resizedPdfImg.data, + diff.data, + refLogo.width, + refLogo.height, + { threshold: 0.1 } + ); + + if (mismatched === 0) { + logoFound = true; + break; + } + } } } - if (doLogoCheck && !logoFound) { - throw new Error("Logo in PDF does not match reference image"); + if ((doLogoCheck && logoFound) || (!doLogoCheck && hasImage)) { + break; } - - return { - hasImage, - logoFound, - text: extractedText, - numPages: pdfDoc.numPages - }; } - catch (err) { - throw err; + + if (doLogoCheck && !logoFound) { + throw new Error("Logo in PDF does not match reference image"); } + + return { + hasImage, + logoFound, + text: extractedText, + numPages: pdfDoc.numPages + }; } }); on('after:spec', (spec, results) => { diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 0b96dbf4871..2541a26dd2c 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -1,3 +1,6 @@ +/* eslint-env mocha */ +/* global cy, Cypress, expect */ + import user from '../../../fixtures/user.json'; const getApiKey = require('../../../api/getApiKey'); const navigationHelpers = require('../../../support/navigations'); From 9d2064657d2c6a890e9222a469fa14b9afafb60d Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 28 Oct 2025 08:02:37 +0000 Subject: [PATCH 07/39] Added pdfjs plugin --- ui-tests/package-lock.json | 851 +++++++++++++++++++++++++++++-------- ui-tests/package.json | 4 +- 2 files changed, 665 insertions(+), 190 deletions(-) diff --git a/ui-tests/package-lock.json b/ui-tests/package-lock.json index db48d1dcea4..4bec9a0f7dd 100644 --- a/ui-tests/package-lock.json +++ b/ui-tests/package-lock.json @@ -14,13 +14,13 @@ "chai": "^6.0.1", "cypress-file-upload": "^5.0.8", "moment": "^2.29.4", - "pdfjs-dist": "^5.4.296", "pixelmatch": "^7.1.0", "pngjs": "^7.0.0", "sharp": "^0.34.4" }, "devDependencies": { - "cypress": "^13.4.0" + "cypress": "^13.4.0", + "pdfjs-dist": "^3.11.174" } }, "node_modules/@cypress/request": { @@ -522,189 +522,26 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@napi-rs/canvas": { - "version": "0.1.81", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.81.tgz", - "integrity": "sha512-ReCjd5SYI/UKx/olaQLC4GtN6wUQGjlgHXs1lvUvWGXfBMR3Fxnik3cL+OxKN5ithNdoU0/GlCrdKcQDFh2XKQ==", - "license": "MIT", + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "dev": true, + "license": "BSD-3-Clause", "optional": true, - "workspaces": [ - "e2e/*" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" }, - "optionalDependencies": { - "@napi-rs/canvas-android-arm64": "0.1.81", - "@napi-rs/canvas-darwin-arm64": "0.1.81", - "@napi-rs/canvas-darwin-x64": "0.1.81", - "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.81", - "@napi-rs/canvas-linux-arm64-gnu": "0.1.81", - "@napi-rs/canvas-linux-arm64-musl": "0.1.81", - "@napi-rs/canvas-linux-riscv64-gnu": "0.1.81", - "@napi-rs/canvas-linux-x64-gnu": "0.1.81", - "@napi-rs/canvas-linux-x64-musl": "0.1.81", - "@napi-rs/canvas-win32-x64-msvc": "0.1.81" - } - }, - "node_modules/@napi-rs/canvas-android-arm64": { - "version": "0.1.81", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.81.tgz", - "integrity": "sha512-78Lz+AUi+MsWupyZjXwpwQrp1QCwncPvRZrdvrROcZ9Gq9grP7LfQZiGdR8LKyHIq3OR18mDP+JESGT15V1nXw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-darwin-arm64": { - "version": "0.1.81", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.81.tgz", - "integrity": "sha512-omejuKgHWKDGoh8rsgsyhm/whwxMaryTQjJTd9zD7hiB9/rzcEEJLHnzXWR5ysy4/tTjHaQotE6k2t8eodTLnA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-darwin-x64": { - "version": "0.1.81", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.81.tgz", - "integrity": "sha512-EYfk+co6BElq5DXNH9PBLYDYwc4QsvIVbyrsVHsxVpn4p6Y3/s8MChgC69AGqj3vzZBQ1qx2CRCMtg5cub+XuQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { - "version": "0.1.81", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.81.tgz", - "integrity": "sha512-teh6Q74CyAcH31yLNQGR9MtXSFxlZa5CI6vvNUISI14gWIJWrhOwUAOly+KRe1aztWR0FWTVSPxM4p5y+06aow==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-linux-arm64-gnu": { - "version": "0.1.81", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.81.tgz", - "integrity": "sha512-AGEopHFYRzJOjxY+2G1RmHPRnuWvO3Qdhq7sIazlSjxb3Z6dZHg7OB/4ZimXaimPjDACm9qWa6t5bn9bhXvkcw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-linux-arm64-musl": { - "version": "0.1.81", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.81.tgz", - "integrity": "sha512-Bj3m1cl4GIhsigkdwOxii4g4Ump3/QhNpx85IgAlCCYXpaly6mcsWpuDYEabfIGWOWhDUNBOndaQUPfWK1czOQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { - "version": "0.1.81", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.81.tgz", - "integrity": "sha512-yg/5NkHykVdwPlD3XObwCa/EswkOwLHswJcI9rHrac+znHsmCSj5AMX/RTU9Z9F6lZTwL60JM2Esit33XhAMiw==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-linux-x64-gnu": { - "version": "0.1.81", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.81.tgz", - "integrity": "sha512-tPfMpSEBuV5dJSKexO/UZxpOqnYTaNbG8aKa1ek8QsWu+4SJ/foWkaxscra/RUv85vepx6WWDjzBNbNJsTnO0w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-linux-x64-musl": { - "version": "0.1.81", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.81.tgz", - "integrity": "sha512-1L0xnYgzqn8Baef+inPvY4dKqdmw3KCBoe0NEDgezuBZN7MA5xElwifoG8609uNdrMtJ9J6QZarsslLRVqri7g==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-win32-x64-msvc": { - "version": "0.1.81", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.81.tgz", - "integrity": "sha512-57ryVbhm/z7RE9/UVcS7mrLPdlayLesy+9U0Uf6epCoeSGrs99tfieCcgZWFbIgmByQ1AZnNtFI2N6huqDLlWQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" } }, "node_modules/@types/node": { @@ -734,6 +571,28 @@ "@types/node": "*" } }, + "node_modules/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, + "license": "ISC", + "optional": true + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -790,6 +649,14 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -809,6 +676,22 @@ } ] }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", @@ -870,6 +753,14 @@ "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", "license": "MIT" }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/base-64": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", @@ -913,6 +804,18 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -981,6 +884,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -1030,6 +950,17 @@ "node": ">= 0.8.0" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "license": "ISC", + "optional": true, + "engines": { + "node": ">=10" + } + }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -1110,6 +1041,17 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -1153,6 +1095,22 @@ "node": ">=4.0.0" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -1275,6 +1233,20 @@ } } }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1284,6 +1256,14 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -1527,6 +1507,42 @@ "node": ">=10" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1536,6 +1552,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -1605,6 +1644,29 @@ "assert-plus": "^1.0.0" } }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/global-dirs": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", @@ -1671,6 +1733,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -1697,6 +1767,21 @@ "node": ">=0.10" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", @@ -1732,6 +1817,27 @@ "node": ">=8" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/ini": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", @@ -1971,6 +2077,34 @@ "node": ">=8" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -2014,6 +2148,34 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -2022,6 +2184,60 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "license": "ISC", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -2036,6 +2252,53 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/nan": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.23.0.tgz", + "integrity": "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -2047,6 +2310,32 @@ "node": ">=8" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -2100,6 +2389,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2108,16 +2408,29 @@ "node": ">=8" } }, + "node_modules/path2d-polyfill": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", + "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pdfjs-dist": { - "version": "5.4.296", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.4.296.tgz", - "integrity": "sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==", + "version": "3.11.174", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", + "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", + "dev": true, "license": "Apache-2.0", "engines": { - "node": ">=20.16.0 || >=22.3.0" + "node": ">=18" }, "optionalDependencies": { - "@napi-rs/canvas": "^0.1.80" + "canvas": "^2.11.2", + "path2d-polyfill": "^2.0.1" } }, "node_modules/pend": { @@ -2208,6 +2521,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/request-progress": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", @@ -2233,6 +2562,24 @@ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -2279,6 +2626,14 @@ "node": ">=10" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/sharp": { "version": "0.34.4", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz", @@ -2417,6 +2772,41 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/slice-ansi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", @@ -2455,6 +2845,17 @@ "node": ">=0.10.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -2501,6 +2902,25 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", @@ -2550,6 +2970,14 @@ "node": ">=16" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/tslib": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", @@ -2605,6 +3033,14 @@ "node": ">=8" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -2628,6 +3064,26 @@ "extsprintf": "^1.2.0" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2642,6 +3098,17 @@ "node": ">= 8" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -2663,6 +3130,14 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/ui-tests/package.json b/ui-tests/package.json index 4eaff562588..8eb4ada2f11 100644 --- a/ui-tests/package.json +++ b/ui-tests/package.json @@ -14,12 +14,12 @@ "chai": "^6.0.1", "cypress-file-upload": "^5.0.8", "moment": "^2.29.4", - "pdfjs-dist": "^5.4.296", "pixelmatch": "^7.1.0", "pngjs": "^7.0.0", "sharp": "^0.34.4" }, "devDependencies": { - "cypress": "^13.4.0" + "cypress": "^13.4.0", + "pdfjs-dist": "^3.11.174" } } From 2e39e938f2c37e025a6d34840fb132433467c954 Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 28 Oct 2025 08:10:05 +0000 Subject: [PATCH 08/39] Fixed missing dependencies fails --- ui-tests/package-lock.json | 59 ++++++++++++++++++++++++++++++++++---- ui-tests/package.json | 11 +++---- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/ui-tests/package-lock.json b/ui-tests/package-lock.json index 4bec9a0f7dd..18cd1d09451 100644 --- a/ui-tests/package-lock.json +++ b/ui-tests/package-lock.json @@ -13,14 +13,15 @@ "base-64": "^1.0.0", "chai": "^6.0.1", "cypress-file-upload": "^5.0.8", - "moment": "^2.29.4", - "pixelmatch": "^7.1.0", - "pngjs": "^7.0.0", - "sharp": "^0.34.4" + "moment": "^2.29.4" }, "devDependencies": { "cypress": "^13.4.0", - "pdfjs-dist": "^3.11.174" + "pdf-text-extract": "^1.5.0", + "pdfjs-dist": "^3.11.174", + "pixelmatch": "^7.1.0", + "pngjs": "^7.0.0", + "sharp": "^0.34.4" } }, "node_modules/@cypress/request": { @@ -73,6 +74,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.6.0.tgz", "integrity": "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -99,6 +101,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -111,6 +114,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -133,6 +137,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -155,6 +160,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -171,6 +177,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -187,6 +194,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -203,6 +211,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -219,6 +228,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -235,6 +245,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -251,6 +262,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -267,6 +279,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -283,6 +296,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -299,6 +313,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -321,6 +336,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -343,6 +359,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -365,6 +382,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -387,6 +405,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -409,6 +428,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -431,6 +451,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -453,6 +474,7 @@ "cpu": [ "wasm32" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { @@ -472,6 +494,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -491,6 +514,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -510,6 +534,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -1268,6 +1293,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -2419,6 +2445,19 @@ "node": ">=8" } }, + "node_modules/pdf-text-extract": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pdf-text-extract/-/pdf-text-extract-1.5.0.tgz", + "integrity": "sha512-5zpNQljVf4h0b9sY8KGKDHxYoTYqDjahvkxmpHwpxBe3p92AWnscpWausl5/OaedOgnS8Pw53DOQx7bqtYcpow==", + "dev": true, + "license": "BSD", + "dependencies": { + "yargs": "^1.2.5" + }, + "bin": { + "pdf-text-extract": "bin/pdf-text-extract.js" + } + }, "node_modules/pdfjs-dist": { "version": "3.11.174", "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", @@ -2456,6 +2495,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-7.1.0.tgz", "integrity": "sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==", + "dev": true, "license": "ISC", "dependencies": { "pngjs": "^7.0.0" @@ -2468,6 +2508,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.19.0" @@ -2638,6 +2679,7 @@ "version": "0.34.4", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz", "integrity": "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==", + "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -3138,6 +3180,13 @@ "license": "ISC", "optional": true }, + "node_modules/yargs": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", + "integrity": "sha512-7OGt4xXoWJQh5ulgZ78rKaqY7dNWbjfK+UKxGcIlaM2j7C4fqGchyv8CPvEWdRPrHp6Ula/YU8yGRpYGOHrI+g==", + "dev": true, + "license": "MIT/X11" + }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/ui-tests/package.json b/ui-tests/package.json index 8eb4ada2f11..6fc97402f96 100644 --- a/ui-tests/package.json +++ b/ui-tests/package.json @@ -13,13 +13,14 @@ "base-64": "^1.0.0", "chai": "^6.0.1", "cypress-file-upload": "^5.0.8", - "moment": "^2.29.4", - "pixelmatch": "^7.1.0", - "pngjs": "^7.0.0", - "sharp": "^0.34.4" + "moment": "^2.29.4" }, "devDependencies": { "cypress": "^13.4.0", - "pdfjs-dist": "^3.11.174" + "pdf-text-extract": "^1.5.0", + "pdfjs-dist": "^3.11.174", + "pixelmatch": "^7.1.0", + "pngjs": "^7.0.0", + "sharp": "^0.34.4" } } From 02cd9054f0bb0c9e866d6984da397b8c97972068 Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 28 Oct 2025 08:24:17 +0000 Subject: [PATCH 09/39] Fixed dep fails --- ui-tests/cypress.config.sample.js | 78 ++++++++++++------------------- ui-tests/package-lock.json | 6 +-- ui-tests/package.json | 4 +- 3 files changed, 33 insertions(+), 55 deletions(-) diff --git a/ui-tests/cypress.config.sample.js b/ui-tests/cypress.config.sample.js index ced149a1296..2e67e99998e 100644 --- a/ui-tests/cypress.config.sample.js +++ b/ui-tests/cypress.config.sample.js @@ -1,9 +1,11 @@ const { defineConfig } = require("cypress"); -const fs = require('fs'); +const fs = require("fs"); const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.js"); -const PNG = require("pngjs").PNG; +const { PNG } = require("pngjs"); const sharp = require("sharp"); -const extract = require("pdf-text-extract"); +const extractText = require("pdf-text-extract"); +const util = require("util"); +const extractTextAsync = util.promisify(extractText); module.exports = defineConfig({ e2e: { @@ -18,44 +20,34 @@ module.exports = defineConfig({ watchForFileChanges: true, video: true, setupNodeEvents(on, config) { - //Task: checks if the PDF contains embedded images and verifies logo existence and text content on("task", { - // --- Check if PDF contains any image --- async verifyPdf({ filePath, options = {} }) { - // options: { referenceLogoPath: string, checkText: true/false } + // DOMMatrix tanımı Node için if (typeof global.DOMMatrix === "undefined") { global.DOMMatrix = class DOMMatrix { }; } - // PDF loading const data = new Uint8Array(fs.readFileSync(filePath)); const pdfDoc = await pdfjsLib.getDocument({ data }).promise; - // Dynamic import pixelmatch if logo check is needed + let hasImage = false; + let logoFound = false; + let extractedText = ""; + + // Pixelmatch lazy import let pixelmatch; - const doLogoCheck = !!options.referenceLogoPath; - if (doLogoCheck) { + if (options.referenceLogoPath) { const pm = await import("pixelmatch"); pixelmatch = pm.default; } - let hasImage = false; - let logoFound = false; - let extractedText = ""; - for (let p = 1; p <= pdfDoc.numPages; p++) { const page = await pdfDoc.getPage(p); - // --- Text extraction --- + // Text extraction if (options.checkText) { - extractedText += await new Promise((resolve, reject) => { - extract(filePath, (err, pages) => { - if (err) { - return reject(err); - } - resolve(pages.join("\n")); - }); - }); + const pagesText = await extractTextAsync(filePath); + extractedText = pagesText.join("\n"); } const ops = await page.getOperatorList(); @@ -64,7 +56,6 @@ module.exports = defineConfig({ const fn = ops.fnArray[i]; const args = ops.argsArray[i]; - // --- Image check --- if ( fn === pdfjsLib.OPS.paintImageXObject || fn === pdfjsLib.OPS.paintJpegXObject || @@ -72,18 +63,15 @@ module.exports = defineConfig({ ) { hasImage = true; - if (doLogoCheck && args[0]) { + if (options.referenceLogoPath && args[0]) { const objName = args[0]; const imgData = await page.objs.get(objName); - if (!imgData) { - continue; - } + if (!imgData) continue; const pdfImg = new PNG({ width: imgData.width, height: imgData.height }); pdfImg.data = imgData.data; - - // resize PDF image to reference logo size const pdfBuffer = PNG.sync.write(pdfImg); + const refLogo = PNG.sync.read(fs.readFileSync(options.referenceLogoPath)); const resizedPdfBuffer = await sharp(pdfBuffer) .resize(refLogo.width, refLogo.height) @@ -91,8 +79,6 @@ module.exports = defineConfig({ .toBuffer(); const resizedPdfImg = PNG.sync.read(resizedPdfBuffer); - - // pixelmatch const diff = new PNG({ width: refLogo.width, height: refLogo.height }); const mismatched = pixelmatch( refLogo.data, @@ -111,12 +97,12 @@ module.exports = defineConfig({ } } - if ((doLogoCheck && logoFound) || (!doLogoCheck && hasImage)) { + if ((options.referenceLogoPath && logoFound) || (!options.referenceLogoPath && hasImage)) { break; } } - if (doLogoCheck && !logoFound) { + if (options.referenceLogoPath && !logoFound) { throw new Error("Logo in PDF does not match reference image"); } @@ -124,24 +110,20 @@ module.exports = defineConfig({ hasImage, logoFound, text: extractedText, - numPages: pdfDoc.numPages + numPages: pdfDoc.numPages, }; - } + }, }); - on('after:spec', (spec, results) => { - if (results && results.video) { - const failures = results.tests.some((test) => - test.attempts.some((attempt) => attempt.state === 'failed') - ); - if (!failures) { - // delete the video if the spec passed and no tests retried - const videoPath = results.video; - if (fs.existsSync(videoPath)) { - fs.unlinkSync(videoPath); - } + + on("after:spec", (spec, results) => { + if (results?.video) { + const hasFailures = results.tests.some((t) => t.attempts.some((a) => a.state === "failed")); + if (!hasFailures && fs.existsSync(results.video)) { + fs.unlinkSync(results.video); } } }); + on("before:browser:launch", (browser, launchOptions) => { if (["chrome", "edge", "electron"].includes(browser.name)) { if (browser.isHeadless) { @@ -157,5 +139,3 @@ module.exports = defineConfig({ }, }, }); - - diff --git a/ui-tests/package-lock.json b/ui-tests/package-lock.json index 18cd1d09451..4b3ff986607 100644 --- a/ui-tests/package-lock.json +++ b/ui-tests/package-lock.json @@ -13,11 +13,11 @@ "base-64": "^1.0.0", "chai": "^6.0.1", "cypress-file-upload": "^5.0.8", - "moment": "^2.29.4" + "moment": "^2.29.4", + "pdf-text-extract": "^1.5.0" }, "devDependencies": { "cypress": "^13.4.0", - "pdf-text-extract": "^1.5.0", "pdfjs-dist": "^3.11.174", "pixelmatch": "^7.1.0", "pngjs": "^7.0.0", @@ -2449,7 +2449,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/pdf-text-extract/-/pdf-text-extract-1.5.0.tgz", "integrity": "sha512-5zpNQljVf4h0b9sY8KGKDHxYoTYqDjahvkxmpHwpxBe3p92AWnscpWausl5/OaedOgnS8Pw53DOQx7bqtYcpow==", - "dev": true, "license": "BSD", "dependencies": { "yargs": "^1.2.5" @@ -3184,7 +3183,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", "integrity": "sha512-7OGt4xXoWJQh5ulgZ78rKaqY7dNWbjfK+UKxGcIlaM2j7C4fqGchyv8CPvEWdRPrHp6Ula/YU8yGRpYGOHrI+g==", - "dev": true, "license": "MIT/X11" }, "node_modules/yauzl": { diff --git a/ui-tests/package.json b/ui-tests/package.json index 6fc97402f96..5b1c2c9d875 100644 --- a/ui-tests/package.json +++ b/ui-tests/package.json @@ -13,11 +13,11 @@ "base-64": "^1.0.0", "chai": "^6.0.1", "cypress-file-upload": "^5.0.8", - "moment": "^2.29.4" + "moment": "^2.29.4", + "pdf-text-extract": "^1.5.0" }, "devDependencies": { "cypress": "^13.4.0", - "pdf-text-extract": "^1.5.0", "pdfjs-dist": "^3.11.174", "pixelmatch": "^7.1.0", "pngjs": "^7.0.0", From 03850b492ec44f240e3a6ca2bd501b1923dd966b Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 28 Oct 2025 08:34:25 +0000 Subject: [PATCH 10/39] Fixed cypress config errors --- ui-tests/cypress.config.sample.js | 18 ++- ui-tests/package-lock.json | 226 ++++++++++++++++++++++++++++-- ui-tests/package.json | 2 +- 3 files changed, 221 insertions(+), 25 deletions(-) diff --git a/ui-tests/cypress.config.sample.js b/ui-tests/cypress.config.sample.js index 2e67e99998e..8e9266ce232 100644 --- a/ui-tests/cypress.config.sample.js +++ b/ui-tests/cypress.config.sample.js @@ -3,9 +3,7 @@ const fs = require("fs"); const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.js"); const { PNG } = require("pngjs"); const sharp = require("sharp"); -const extractText = require("pdf-text-extract"); -const util = require("util"); -const extractTextAsync = util.promisify(extractText); +const pdfParse = require("pdf-parse"); module.exports = defineConfig({ e2e: { @@ -34,6 +32,13 @@ module.exports = defineConfig({ let logoFound = false; let extractedText = ""; + // Text extraction Node-only + if (options.checkText) { + const dataBuffer = fs.readFileSync(filePath); + const pdfData = await pdfParse(dataBuffer); + extractedText = pdfData.text; + } + // Pixelmatch lazy import let pixelmatch; if (options.referenceLogoPath) { @@ -43,13 +48,6 @@ module.exports = defineConfig({ for (let p = 1; p <= pdfDoc.numPages; p++) { const page = await pdfDoc.getPage(p); - - // Text extraction - if (options.checkText) { - const pagesText = await extractTextAsync(filePath); - extractedText = pagesText.join("\n"); - } - const ops = await page.getOperatorList(); for (let i = 0; i < ops.fnArray.length; i++) { diff --git a/ui-tests/package-lock.json b/ui-tests/package-lock.json index 4b3ff986607..6c359359bb1 100644 --- a/ui-tests/package-lock.json +++ b/ui-tests/package-lock.json @@ -14,7 +14,7 @@ "chai": "^6.0.1", "cypress-file-upload": "^5.0.8", "moment": "^2.29.4", - "pdf-text-extract": "^1.5.0" + "pdf-parse": "^2.4.5" }, "devDependencies": { "cypress": "^13.4.0", @@ -569,6 +569,190 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, + "node_modules/@napi-rs/canvas": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.80.tgz", + "integrity": "sha512-DxuT1ClnIPts1kQx8FBmkk4BQDTfI5kIzywAaMjQSXfNnra5UFU9PwurXrl+Je3bJ6BGsp/zmshVVFbCmyI+ww==", + "license": "MIT", + "workspaces": [ + "e2e/*" + ], + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.80", + "@napi-rs/canvas-darwin-arm64": "0.1.80", + "@napi-rs/canvas-darwin-x64": "0.1.80", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.80", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.80", + "@napi-rs/canvas-linux-arm64-musl": "0.1.80", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.80", + "@napi-rs/canvas-linux-x64-gnu": "0.1.80", + "@napi-rs/canvas-linux-x64-musl": "0.1.80", + "@napi-rs/canvas-win32-x64-msvc": "0.1.80" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.80.tgz", + "integrity": "sha512-sk7xhN/MoXeuExlggf91pNziBxLPVUqF2CAVnB57KLG/pz7+U5TKG8eXdc3pm0d7Od0WreB6ZKLj37sX9muGOQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.80.tgz", + "integrity": "sha512-O64APRTXRUiAz0P8gErkfEr3lipLJgM6pjATwavZ22ebhjYl/SUbpgM0xcWPQBNMP1n29afAC/Us5PX1vg+JNQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.80.tgz", + "integrity": "sha512-FqqSU7qFce0Cp3pwnTjVkKjjOtxMqRe6lmINxpIZYaZNnVI0H5FtsaraZJ36SiTHNjZlUB69/HhxNDT1Aaa9vA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.80.tgz", + "integrity": "sha512-eyWz0ddBDQc7/JbAtY4OtZ5SpK8tR4JsCYEZjCE3dI8pqoWUC8oMwYSBGCYfsx2w47cQgQCgMVRVTFiiO38hHQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.80.tgz", + "integrity": "sha512-qwA63t8A86bnxhuA/GwOkK3jvb+XTQaTiVML0vAWoHyoZYTjNs7BzoOONDgTnNtr8/yHrq64XXzUoLqDzU+Uuw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.80.tgz", + "integrity": "sha512-1XbCOz/ymhj24lFaIXtWnwv/6eFHXDrjP0jYkc6iHQ9q8oXKzUX1Lc6bu+wuGiLhGh2GS/2JlfORC5ZcXimRcg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.80.tgz", + "integrity": "sha512-XTzR125w5ZMs0lJcxRlS1K3P5RaZ9RmUsPtd1uGt+EfDyYMu4c6SEROYsxyatbbu/2+lPe7MPHOO/0a0x7L/gw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.80.tgz", + "integrity": "sha512-BeXAmhKg1kX3UCrJsYbdQd3hIMDH/K6HnP/pG2LuITaXhXBiNdh//TVVVVCBbJzVQaV5gK/4ZOCMrQW9mvuTqA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.80.tgz", + "integrity": "sha512-x0XvZWdHbkgdgucJsRxprX/4o4sEed7qo9rCQA9ugiS9qE2QvP0RIiEugtZhfLH3cyI+jIRFJHV4Fuz+1BHHMg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.80.tgz", + "integrity": "sha512-Z8jPsM6df5V8B1HrCHB05+bDiCxjE9QA//3YrkKIdVDEwn5RKaqOxCJDRJkl48cJbylcrJbW4HxZbTte8juuPg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@types/node": { "version": "18.18.8", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.8.tgz", @@ -2445,16 +2629,36 @@ "node": ">=8" } }, - "node_modules/pdf-text-extract": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/pdf-text-extract/-/pdf-text-extract-1.5.0.tgz", - "integrity": "sha512-5zpNQljVf4h0b9sY8KGKDHxYoTYqDjahvkxmpHwpxBe3p92AWnscpWausl5/OaedOgnS8Pw53DOQx7bqtYcpow==", - "license": "BSD", + "node_modules/pdf-parse": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/pdf-parse/-/pdf-parse-2.4.5.tgz", + "integrity": "sha512-mHU89HGh7v+4u2ubfnevJ03lmPgQ5WU4CxAVmTSh/sxVTEDYd1er/dKS/A6vg77NX47KTEoihq8jZBLr8Cxuwg==", + "license": "Apache-2.0", "dependencies": { - "yargs": "^1.2.5" + "@napi-rs/canvas": "0.1.80", + "pdfjs-dist": "5.4.296" }, "bin": { - "pdf-text-extract": "bin/pdf-text-extract.js" + "pdf-parse": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.16.0 <21 || >=22.3.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/mehmet-kozan" + } + }, + "node_modules/pdf-parse/node_modules/pdfjs-dist": { + "version": "5.4.296", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.4.296.tgz", + "integrity": "sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.16.0 || >=22.3.0" + }, + "optionalDependencies": { + "@napi-rs/canvas": "^0.1.80" } }, "node_modules/pdfjs-dist": { @@ -3179,12 +3383,6 @@ "license": "ISC", "optional": true }, - "node_modules/yargs": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", - "integrity": "sha512-7OGt4xXoWJQh5ulgZ78rKaqY7dNWbjfK+UKxGcIlaM2j7C4fqGchyv8CPvEWdRPrHp6Ula/YU8yGRpYGOHrI+g==", - "license": "MIT/X11" - }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/ui-tests/package.json b/ui-tests/package.json index 5b1c2c9d875..4d16f5c99ba 100644 --- a/ui-tests/package.json +++ b/ui-tests/package.json @@ -14,7 +14,7 @@ "chai": "^6.0.1", "cypress-file-upload": "^5.0.8", "moment": "^2.29.4", - "pdf-text-extract": "^1.5.0" + "pdf-parse": "^2.4.5" }, "devDependencies": { "cypress": "^13.4.0", From 7889c6aac1046304c5efc43db5763d2b1d099cbe Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 28 Oct 2025 08:43:44 +0000 Subject: [PATCH 11/39] Fixed pdfParse is not a function error --- ui-tests/cypress.config.sample.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ui-tests/cypress.config.sample.js b/ui-tests/cypress.config.sample.js index 8e9266ce232..aacfbad3ab8 100644 --- a/ui-tests/cypress.config.sample.js +++ b/ui-tests/cypress.config.sample.js @@ -5,6 +5,8 @@ const { PNG } = require("pngjs"); const sharp = require("sharp"); const pdfParse = require("pdf-parse"); +const pdfParseFn = typeof pdfParse === "function" ? pdfParse : pdfParse.default; + module.exports = defineConfig({ e2e: { baseUrl: "http://localhost", @@ -20,7 +22,6 @@ module.exports = defineConfig({ setupNodeEvents(on, config) { on("task", { async verifyPdf({ filePath, options = {} }) { - // DOMMatrix tanımı Node için if (typeof global.DOMMatrix === "undefined") { global.DOMMatrix = class DOMMatrix { }; } @@ -35,11 +36,11 @@ module.exports = defineConfig({ // Text extraction Node-only if (options.checkText) { const dataBuffer = fs.readFileSync(filePath); - const pdfData = await pdfParse(dataBuffer); + const pdfData = await pdfParseFn(dataBuffer); extractedText = pdfData.text; } - // Pixelmatch lazy import + // Pixelmatch import let pixelmatch; if (options.referenceLogoPath) { const pm = await import("pixelmatch"); @@ -64,7 +65,9 @@ module.exports = defineConfig({ if (options.referenceLogoPath && args[0]) { const objName = args[0]; const imgData = await page.objs.get(objName); - if (!imgData) continue; + if (!imgData) { + continue; + } const pdfImg = new PNG({ width: imgData.width, height: imgData.height }); pdfImg.data = imgData.data; @@ -136,4 +139,4 @@ module.exports = defineConfig({ }); }, }, -}); +}); \ No newline at end of file From 7c1dac2f28d324e2f132069b5efac4f905ef6ed6 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 10:07:56 +0000 Subject: [PATCH 12/39] Fixed missing dependencies fails --- .github/workflows/main.yml | 6 +- ui-tests/cypress.config.sample.js | 175 ++++++++++++----------- ui-tests/package-lock.json | 225 +----------------------------- ui-tests/package.json | 3 +- 4 files changed, 105 insertions(+), 304 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f7fa5223a5d..fa3240c034c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -270,11 +270,15 @@ jobs: steps: - uses: actions/checkout@v5 - - name: Install Chrome + - name: Install Chrome + dependencies (including libvips for sharp) shell: bash run: | apt update + # Required for Chrome apt install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb wget + # Required for 'sharp' (used in PDF image comparison) + apt install -y libvips-dev + # Install Chrome wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -O /tmp/chrome.deb apt install -y /tmp/chrome.deb diff --git a/ui-tests/cypress.config.sample.js b/ui-tests/cypress.config.sample.js index aacfbad3ab8..6800b99123d 100644 --- a/ui-tests/cypress.config.sample.js +++ b/ui-tests/cypress.config.sample.js @@ -20,100 +20,115 @@ module.exports = defineConfig({ watchForFileChanges: true, video: true, setupNodeEvents(on, config) { + //Task: checks if the PDF contains embedded images and verifies logo existence and text content on("task", { + // --- Check if PDF contains any image --- async verifyPdf({ filePath, options = {} }) { - if (typeof global.DOMMatrix === "undefined") { - global.DOMMatrix = class DOMMatrix { }; - } - - const data = new Uint8Array(fs.readFileSync(filePath)); - const pdfDoc = await pdfjsLib.getDocument({ data }).promise; + // options: { referenceLogoPath: string, checkText: true/false } + try { + if (typeof global.DOMMatrix === "undefined") { + global.DOMMatrix = class DOMMatrix { }; + } - let hasImage = false; - let logoFound = false; - let extractedText = ""; + // PDF loading + const data = new Uint8Array(fs.readFileSync(filePath)); + const pdfDoc = await pdfjsLib.getDocument({ data }).promise; - // Text extraction Node-only - if (options.checkText) { - const dataBuffer = fs.readFileSync(filePath); - const pdfData = await pdfParseFn(dataBuffer); - extractedText = pdfData.text; - } - - // Pixelmatch import - let pixelmatch; - if (options.referenceLogoPath) { - const pm = await import("pixelmatch"); - pixelmatch = pm.default; - } + // Dynamic import pixelmatch if logo check is needed + let pixelmatch; + const doLogoCheck = !!options.referenceLogoPath; + if (doLogoCheck) { + const pm = await import("pixelmatch"); + pixelmatch = pm.default; + } - for (let p = 1; p <= pdfDoc.numPages; p++) { - const page = await pdfDoc.getPage(p); - const ops = await page.getOperatorList(); - - for (let i = 0; i < ops.fnArray.length; i++) { - const fn = ops.fnArray[i]; - const args = ops.argsArray[i]; - - if ( - fn === pdfjsLib.OPS.paintImageXObject || - fn === pdfjsLib.OPS.paintJpegXObject || - fn === pdfjsLib.OPS.paintInlineImageXObject - ) { - hasImage = true; - - if (options.referenceLogoPath && args[0]) { - const objName = args[0]; - const imgData = await page.objs.get(objName); - if (!imgData) { - continue; - } + let hasImage = false; + let logoFound = false; + let extractedText = ""; + + for (let p = 1; p <= pdfDoc.numPages; p++) { + const page = await pdfDoc.getPage(p); + + // --- Text extraction --- + if (options.checkText) { + extractedText += await new Promise((resolve, reject) => { + extract(filePath, (err, pages) => { + if (err) return reject(err); + resolve(pages.join("\n")); + }); + }); + } - const pdfImg = new PNG({ width: imgData.width, height: imgData.height }); - pdfImg.data = imgData.data; - const pdfBuffer = PNG.sync.write(pdfImg); - - const refLogo = PNG.sync.read(fs.readFileSync(options.referenceLogoPath)); - const resizedPdfBuffer = await sharp(pdfBuffer) - .resize(refLogo.width, refLogo.height) - .png() - .toBuffer(); - - const resizedPdfImg = PNG.sync.read(resizedPdfBuffer); - const diff = new PNG({ width: refLogo.width, height: refLogo.height }); - const mismatched = pixelmatch( - refLogo.data, - resizedPdfImg.data, - diff.data, - refLogo.width, - refLogo.height, - { threshold: 0.1 } - ); - - if (mismatched === 0) { - logoFound = true; - break; + const ops = await page.getOperatorList(); + + for (let i = 0; i < ops.fnArray.length; i++) { + const fn = ops.fnArray[i]; + const args = ops.argsArray[i]; + + // --- Image check --- + if ( + fn === pdfjsLib.OPS.paintImageXObject || + fn === pdfjsLib.OPS.paintJpegXObject || + fn === pdfjsLib.OPS.paintInlineImageXObject + ) { + hasImage = true; + + if (doLogoCheck && args[0]) { + const objName = args[0]; + const imgData = await page.objs.get(objName); + if (!imgData) continue; + + const pdfImg = new PNG({ width: imgData.width, height: imgData.height }); + pdfImg.data = imgData.data; + + // resize PDF image to reference logo size + const pdfBuffer = PNG.sync.write(pdfImg); + const refLogo = PNG.sync.read(fs.readFileSync(options.referenceLogoPath)); + const resizedPdfBuffer = await sharp(pdfBuffer) + .resize(refLogo.width, refLogo.height) + .png() + .toBuffer(); + + const resizedPdfImg = PNG.sync.read(resizedPdfBuffer); + + // pixelmatch + const diff = new PNG({ width: refLogo.width, height: refLogo.height }); + const mismatched = pixelmatch( + refLogo.data, + resizedPdfImg.data, + diff.data, + refLogo.width, + refLogo.height, + { threshold: 0.1 } + ); + + if (mismatched === 0) { + logoFound = true; + break; + } } } } + + if ((doLogoCheck && logoFound) || (!doLogoCheck && hasImage)) { + break; + } } - if ((options.referenceLogoPath && logoFound) || (!options.referenceLogoPath && hasImage)) { - break; + if (doLogoCheck && !logoFound) { + throw new Error("Logo in PDF does not match reference image"); } - } - if (options.referenceLogoPath && !logoFound) { - throw new Error("Logo in PDF does not match reference image"); + return { + hasImage, + logoFound, + text: extractedText, + numPages: pdfDoc.numPages + }; + } catch (err) { + throw err; } - - return { - hasImage, - logoFound, - text: extractedText, - numPages: pdfDoc.numPages, - }; - }, + } }); on("after:spec", (spec, results) => { diff --git a/ui-tests/package-lock.json b/ui-tests/package-lock.json index 6c359359bb1..100fbf5c3eb 100644 --- a/ui-tests/package-lock.json +++ b/ui-tests/package-lock.json @@ -13,8 +13,7 @@ "base-64": "^1.0.0", "chai": "^6.0.1", "cypress-file-upload": "^5.0.8", - "moment": "^2.29.4", - "pdf-parse": "^2.4.5" + "moment": "^2.29.4" }, "devDependencies": { "cypress": "^13.4.0", @@ -71,9 +70,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.6.0.tgz", - "integrity": "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.0.tgz", + "integrity": "sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==", "dev": true, "license": "MIT", "optional": true, @@ -569,190 +568,6 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, - "node_modules/@napi-rs/canvas": { - "version": "0.1.80", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.80.tgz", - "integrity": "sha512-DxuT1ClnIPts1kQx8FBmkk4BQDTfI5kIzywAaMjQSXfNnra5UFU9PwurXrl+Je3bJ6BGsp/zmshVVFbCmyI+ww==", - "license": "MIT", - "workspaces": [ - "e2e/*" - ], - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@napi-rs/canvas-android-arm64": "0.1.80", - "@napi-rs/canvas-darwin-arm64": "0.1.80", - "@napi-rs/canvas-darwin-x64": "0.1.80", - "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.80", - "@napi-rs/canvas-linux-arm64-gnu": "0.1.80", - "@napi-rs/canvas-linux-arm64-musl": "0.1.80", - "@napi-rs/canvas-linux-riscv64-gnu": "0.1.80", - "@napi-rs/canvas-linux-x64-gnu": "0.1.80", - "@napi-rs/canvas-linux-x64-musl": "0.1.80", - "@napi-rs/canvas-win32-x64-msvc": "0.1.80" - } - }, - "node_modules/@napi-rs/canvas-android-arm64": { - "version": "0.1.80", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.80.tgz", - "integrity": "sha512-sk7xhN/MoXeuExlggf91pNziBxLPVUqF2CAVnB57KLG/pz7+U5TKG8eXdc3pm0d7Od0WreB6ZKLj37sX9muGOQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-darwin-arm64": { - "version": "0.1.80", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.80.tgz", - "integrity": "sha512-O64APRTXRUiAz0P8gErkfEr3lipLJgM6pjATwavZ22ebhjYl/SUbpgM0xcWPQBNMP1n29afAC/Us5PX1vg+JNQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-darwin-x64": { - "version": "0.1.80", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.80.tgz", - "integrity": "sha512-FqqSU7qFce0Cp3pwnTjVkKjjOtxMqRe6lmINxpIZYaZNnVI0H5FtsaraZJ36SiTHNjZlUB69/HhxNDT1Aaa9vA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { - "version": "0.1.80", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.80.tgz", - "integrity": "sha512-eyWz0ddBDQc7/JbAtY4OtZ5SpK8tR4JsCYEZjCE3dI8pqoWUC8oMwYSBGCYfsx2w47cQgQCgMVRVTFiiO38hHQ==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-linux-arm64-gnu": { - "version": "0.1.80", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.80.tgz", - "integrity": "sha512-qwA63t8A86bnxhuA/GwOkK3jvb+XTQaTiVML0vAWoHyoZYTjNs7BzoOONDgTnNtr8/yHrq64XXzUoLqDzU+Uuw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-linux-arm64-musl": { - "version": "0.1.80", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.80.tgz", - "integrity": "sha512-1XbCOz/ymhj24lFaIXtWnwv/6eFHXDrjP0jYkc6iHQ9q8oXKzUX1Lc6bu+wuGiLhGh2GS/2JlfORC5ZcXimRcg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { - "version": "0.1.80", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.80.tgz", - "integrity": "sha512-XTzR125w5ZMs0lJcxRlS1K3P5RaZ9RmUsPtd1uGt+EfDyYMu4c6SEROYsxyatbbu/2+lPe7MPHOO/0a0x7L/gw==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-linux-x64-gnu": { - "version": "0.1.80", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.80.tgz", - "integrity": "sha512-BeXAmhKg1kX3UCrJsYbdQd3hIMDH/K6HnP/pG2LuITaXhXBiNdh//TVVVVCBbJzVQaV5gK/4ZOCMrQW9mvuTqA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-linux-x64-musl": { - "version": "0.1.80", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.80.tgz", - "integrity": "sha512-x0XvZWdHbkgdgucJsRxprX/4o4sEed7qo9rCQA9ugiS9qE2QvP0RIiEugtZhfLH3cyI+jIRFJHV4Fuz+1BHHMg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/canvas-win32-x64-msvc": { - "version": "0.1.80", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.80.tgz", - "integrity": "sha512-Z8jPsM6df5V8B1HrCHB05+bDiCxjE9QA//3YrkKIdVDEwn5RKaqOxCJDRJkl48cJbylcrJbW4HxZbTte8juuPg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@types/node": { "version": "18.18.8", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.8.tgz", @@ -2629,38 +2444,6 @@ "node": ">=8" } }, - "node_modules/pdf-parse": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/pdf-parse/-/pdf-parse-2.4.5.tgz", - "integrity": "sha512-mHU89HGh7v+4u2ubfnevJ03lmPgQ5WU4CxAVmTSh/sxVTEDYd1er/dKS/A6vg77NX47KTEoihq8jZBLr8Cxuwg==", - "license": "Apache-2.0", - "dependencies": { - "@napi-rs/canvas": "0.1.80", - "pdfjs-dist": "5.4.296" - }, - "bin": { - "pdf-parse": "bin/cli.mjs" - }, - "engines": { - "node": ">=20.16.0 <21 || >=22.3.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/mehmet-kozan" - } - }, - "node_modules/pdf-parse/node_modules/pdfjs-dist": { - "version": "5.4.296", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.4.296.tgz", - "integrity": "sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==", - "license": "Apache-2.0", - "engines": { - "node": ">=20.16.0 || >=22.3.0" - }, - "optionalDependencies": { - "@napi-rs/canvas": "^0.1.80" - } - }, "node_modules/pdfjs-dist": { "version": "3.11.174", "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", diff --git a/ui-tests/package.json b/ui-tests/package.json index 4d16f5c99ba..cf46e76489a 100644 --- a/ui-tests/package.json +++ b/ui-tests/package.json @@ -13,8 +13,7 @@ "base-64": "^1.0.0", "chai": "^6.0.1", "cypress-file-upload": "^5.0.8", - "moment": "^2.29.4", - "pdf-parse": "^2.4.5" + "moment": "^2.29.4" }, "devDependencies": { "cypress": "^13.4.0", From 9c63d70ddb388c63065df67b2a3aee2f54f4b747 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 10:17:32 +0000 Subject: [PATCH 13/39] Fxed linter errors --- ui-tests/cypress.config.sample.js | 177 ++++++++++++++---------------- 1 file changed, 80 insertions(+), 97 deletions(-) diff --git a/ui-tests/cypress.config.sample.js b/ui-tests/cypress.config.sample.js index 6800b99123d..9015b11a504 100644 --- a/ui-tests/cypress.config.sample.js +++ b/ui-tests/cypress.config.sample.js @@ -3,9 +3,11 @@ const fs = require("fs"); const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.js"); const { PNG } = require("pngjs"); const sharp = require("sharp"); -const pdfParse = require("pdf-parse"); -const pdfParseFn = typeof pdfParse === "function" ? pdfParse : pdfParse.default; +// Define missing DOMMatrix in Node context (for pdfjs) +if (typeof global.DOMMatrix === "undefined") { + global.DOMMatrix = class DOMMatrix { }; +} module.exports = defineConfig({ e2e: { @@ -20,117 +22,98 @@ module.exports = defineConfig({ watchForFileChanges: true, video: true, setupNodeEvents(on, config) { - //Task: checks if the PDF contains embedded images and verifies logo existence and text content + // ✅ Task: verify PDF images and logo on("task", { - // --- Check if PDF contains any image --- async verifyPdf({ filePath, options = {} }) { - // options: { referenceLogoPath: string, checkText: true/false } - try { - if (typeof global.DOMMatrix === "undefined") { - global.DOMMatrix = class DOMMatrix { }; - } + // options: { referenceLogoPath: string } + + // Load PDF + const data = new Uint8Array(fs.readFileSync(filePath)); + const pdfDoc = await pdfjsLib.getDocument({ data }).promise; + + // Import pixelmatch only if logo check is needed + let pixelmatch; + const doLogoCheck = !!options.referenceLogoPath; + if (doLogoCheck) { + const pm = await import("pixelmatch"); + pixelmatch = pm.default; + } - // PDF loading - const data = new Uint8Array(fs.readFileSync(filePath)); - const pdfDoc = await pdfjsLib.getDocument({ data }).promise; + let hasImage = false; + let logoFound = false; + + for (let p = 1; p <= pdfDoc.numPages; p++) { + const page = await pdfDoc.getPage(p); + const ops = await page.getOperatorList(); + + for (let i = 0; i < ops.fnArray.length; i++) { + const fn = ops.fnArray[i]; + const args = ops.argsArray[i]; + + // --- Image check --- + if ( + fn === pdfjsLib.OPS.paintImageXObject || + fn === pdfjsLib.OPS.paintJpegXObject || + fn === pdfjsLib.OPS.paintInlineImageXObject + ) { + hasImage = true; + + if (doLogoCheck && args[0]) { + const objName = args[0]; + const imgData = await page.objs.get(objName); + if (!imgData) { + continue; + } - // Dynamic import pixelmatch if logo check is needed - let pixelmatch; - const doLogoCheck = !!options.referenceLogoPath; - if (doLogoCheck) { - const pm = await import("pixelmatch"); - pixelmatch = pm.default; - } + const pdfImg = new PNG({ width: imgData.width, height: imgData.height }); + pdfImg.data = imgData.data; - let hasImage = false; - let logoFound = false; - let extractedText = ""; - - for (let p = 1; p <= pdfDoc.numPages; p++) { - const page = await pdfDoc.getPage(p); - - // --- Text extraction --- - if (options.checkText) { - extractedText += await new Promise((resolve, reject) => { - extract(filePath, (err, pages) => { - if (err) return reject(err); - resolve(pages.join("\n")); - }); - }); - } + const pdfBuffer = PNG.sync.write(pdfImg); + const refLogo = PNG.sync.read(fs.readFileSync(options.referenceLogoPath)); + + const resizedPdfBuffer = await sharp(pdfBuffer) + .resize(refLogo.width, refLogo.height) + .png() + .toBuffer(); + + const resizedPdfImg = PNG.sync.read(resizedPdfBuffer); - const ops = await page.getOperatorList(); - - for (let i = 0; i < ops.fnArray.length; i++) { - const fn = ops.fnArray[i]; - const args = ops.argsArray[i]; - - // --- Image check --- - if ( - fn === pdfjsLib.OPS.paintImageXObject || - fn === pdfjsLib.OPS.paintJpegXObject || - fn === pdfjsLib.OPS.paintInlineImageXObject - ) { - hasImage = true; - - if (doLogoCheck && args[0]) { - const objName = args[0]; - const imgData = await page.objs.get(objName); - if (!imgData) continue; - - const pdfImg = new PNG({ width: imgData.width, height: imgData.height }); - pdfImg.data = imgData.data; - - // resize PDF image to reference logo size - const pdfBuffer = PNG.sync.write(pdfImg); - const refLogo = PNG.sync.read(fs.readFileSync(options.referenceLogoPath)); - const resizedPdfBuffer = await sharp(pdfBuffer) - .resize(refLogo.width, refLogo.height) - .png() - .toBuffer(); - - const resizedPdfImg = PNG.sync.read(resizedPdfBuffer); - - // pixelmatch - const diff = new PNG({ width: refLogo.width, height: refLogo.height }); - const mismatched = pixelmatch( - refLogo.data, - resizedPdfImg.data, - diff.data, - refLogo.width, - refLogo.height, - { threshold: 0.1 } - ); - - if (mismatched === 0) { - logoFound = true; - break; - } + const diff = new PNG({ width: refLogo.width, height: refLogo.height }); + const mismatched = pixelmatch( + refLogo.data, + resizedPdfImg.data, + diff.data, + refLogo.width, + refLogo.height, + { threshold: 0.1 } + ); + + if (mismatched === 0) { + logoFound = true; + break; } } } - - if ((doLogoCheck && logoFound) || (!doLogoCheck && hasImage)) { - break; - } } - if (doLogoCheck && !logoFound) { - throw new Error("Logo in PDF does not match reference image"); + if ((doLogoCheck && logoFound) || (!doLogoCheck && hasImage)) { + break; } + } - return { - hasImage, - logoFound, - text: extractedText, - numPages: pdfDoc.numPages - }; - } catch (err) { - throw err; + if (doLogoCheck && !logoFound) { + throw new Error("Logo in PDF does not match reference image"); } - } + + return { + hasImage, + logoFound, + numPages: pdfDoc.numPages + }; + }, }); + on("after:spec", (spec, results) => { if (results?.video) { const hasFailures = results.tests.some((t) => t.attempts.some((a) => a.state === "failed")); From 18ed7a6936c37ebb811789175f61fa8087e7b89c Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 10:24:18 +0000 Subject: [PATCH 14/39] Logo added --- .../cypress/fixtures/testFiles/countly-logo.png | Bin 0 -> 2738 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ui-tests/cypress/fixtures/testFiles/countly-logo.png diff --git a/ui-tests/cypress/fixtures/testFiles/countly-logo.png b/ui-tests/cypress/fixtures/testFiles/countly-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..af726355af02f13932b67248a1d1ab3b2848912a GIT binary patch literal 2738 zcmV;j3QhHiP)oAcTnW&I4EyLXzqK z&(6k~JF~kpyEB_?oIB?~ft@>dX72yZ{r~&le+*axvmKpFa5Mc3pF8~0%R?1$KYYEn4dj3i|ldms)!2+dd3! zI$phJS;P7#BQRPeO^Yz{_`UDw0Y@Q0-}p?w$Dy_U%w4bYU6Sp5R|w&%8|3%gVQC}{ z3sp&71rXII1(8mW#%-I&cXVHpf%IlWd3ZluO9r2Dg{7G^D`6ifNr-fSEmcWY$ix!VRjbkYF9vn+qHfkV2QczHE zts~#%%%QotIW#jhg&_H=Ng$RTULRB0dO$)b$5+kQB$)dRX;C@1qdwV;TBhq0Kh*gc73wiH>Z~rPv9wi~{(#X!^PchjU>Jf9v`@ znxk`^Oi}o$=Z3*=S4FA&S#auaiHI7Y=$lFFa2)sfUKm*Rn~~p#bKKWHc}QHD;d8?^ z(5|6)zi~mLn615S(e!uXfs~tD@YQJ7MNVF%_44w#n={0GA(;Xv|92r@f3Ary|7ZvQ z!rm2%Kw=6(YSnJi*q@Ul4M60LY6hI_e4_q^tdS#Sxl!2p0L?PkcS&UwYlb$SC694X z>_hT;+y<3%FCi2@r}sXb%sI)vlX-c}t?+k;%J~~|D6TNhh$NE;m{CDeTo=1Kiu*8& zcnA+7NGAUrbgoXouvAcnwir#1Lk z?@LD=xQ<5%NH!_2m3>35NOqoNUr64*3@lQ*9W+;<6{Or;*G;iN3Xi(7V>*Tv6ns(T z`fKI=#?C;HE*c3^c8U8sLsC+N3;^FW?I6i-4&)E)E6-v`BKMI;gq0P}Ps9N(nX zVTX<^GY_OVf}=r3IOQf;kOZ@@a1WRw*|q2A|4eZND-@XvPXy~_iv_v6!ufDkc@c4R3LX5HERox(n8QSvOgqsy20;! zPj+sanHT}-oZ+S|{9-`Trp@m6PS>G)*^`PRM2}2t3 zM_+EFk<))+wkMmkaQ6wn!x9tGH|^*KL_j(@Ae?QQts^>jZXzIwPo#XdBbho&&gUbe z;5xSuCUt~#iDX~@1e!IA`K9Tr+pGpM2f@puXDIig7 zd7_bRcrgD(#N;Lr{c=JUlm(}FS3e$+D)pp_z|9>al-L^SWVvZ!iZDh(n4p=G{W}Ro zS4cZehyar@CYpUdtR${57SLjR>M{XKu@N9a-Cq+k$$F`yt_LJIHlGZ@5`NQ*L}Hs~ zgP9=RvvI2CMcZ-P=96i+x)yC6PUik7F_eAygb9&bn*E>JerbeSk*_0~N({V-BM}K~ z4=!N{K9RJg94}EgVxi8Z{t2C}oWuanLE;Qz31qlWWW;|OLHNaFE})z8Jfu6OkxM@ls?;rvf2XD@!w zBk@4GWA#MgrN)R1fvm|?fRs$Ct+3!49vK?cOc{1234q$FzhKUs+#zy}3r!U`_?~Fr zDiD0OaF)Sd6{Q}+2(jAvaiLavo=DW1s8b^|tCBbuo)>3&Ce$3Xn*6T?9s9>HEY1*Qu=76%U0i|6^1xRyuFX20TIu#IMZaDp)#}ker zS;eH(UGRm-oGmo>v9ct0nhg?~xM+S6zTbA|zaO<;+3sgW5l@5FgLvt-e>58;d^J0k zlik{Rj(=?XpCoO0Ct0fOyMoI?igXo7e2WcIsdso^gM`~faJD1wwOOCF>2tF-g8=E6 zCWjrAS7jzh_;t3|;Hx9EYhL4@*s(~+1#b$SP{8!k{s7iLXnkm_ug#h~Y=KF2nhw0x z@4X2?Sb?*pg!6}jzA<{%+VEva{5Fylq_-L?&RC!R>)Rr{-X4yX_2zD4C_z^vwz6M+ z9b!upAn*EB@#V=5jbL=cM@$Fn`4}lmUE7gvcn$o*#*g2xdE@Z9DejVzD=k$Hz>@WH z@zod@#3(alEItHZQk#vRLI%)+xH=C~gTTR>U2l%GJ>Z!kW?qJbPbi092H2h%@RY*7 szhdSi)c4p+J@!TQi>|eLIsME30rR3-AYnU6umAu607*qoM6N<$f*s>I=>Px# literal 0 HcmV?d00001 From c9c91b88d73f6a696133fbe7d0da2f74f220a373 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 11:20:20 +0000 Subject: [PATCH 15/39] Fixed logo path --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 2541a26dd2c..c185ff678b1 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -116,16 +116,16 @@ describe('Create New Custom Dashboard', () => { expect(buf.length).to.be.greaterThan(50000); // More than 50KB to ensure it's not empty // Save the PDF to disk (optional) - cy.writeFile('cypress/downloads/generated-report.pdf', buf); + cy.writeFile('/cypress/downloads/generated-report.pdf', buf); }); }); }); // Verify PDF content cy.task("verifyPdf", { - filePath: "cypress/downloads/generated-report.pdf", + filePath: "/cypress/downloads/generated-report.pdf", options: { - referenceLogoPath: "Cypress/fixtures/testFiles/countly-logo.png", + referenceLogoPath: "/testFiles/countly-logo.png", checkText: true } }).then((result) => { From de2e7a4756a73770cabd9f52480baf37c5a07473 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 11:36:46 +0000 Subject: [PATCH 16/39] Fixed logo path --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index c185ff678b1..9f13ef6be8c 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -116,14 +116,14 @@ describe('Create New Custom Dashboard', () => { expect(buf.length).to.be.greaterThan(50000); // More than 50KB to ensure it's not empty // Save the PDF to disk (optional) - cy.writeFile('/cypress/downloads/generated-report.pdf', buf); + cy.writeFile('/fixtures/cypress/downloads/generated-report.pdf', buf); }); }); }); // Verify PDF content cy.task("verifyPdf", { - filePath: "/cypress/downloads/generated-report.pdf", + filePath: "/fixtures/cypress/downloads/generated-report.pdf", options: { referenceLogoPath: "/testFiles/countly-logo.png", checkText: true From 6cd94d0e16e06a084dd64e46f061452d039c5c78 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 11:41:49 +0000 Subject: [PATCH 17/39] Fixed countly logo path --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 9f13ef6be8c..73f96388ae4 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -116,16 +116,16 @@ describe('Create New Custom Dashboard', () => { expect(buf.length).to.be.greaterThan(50000); // More than 50KB to ensure it's not empty // Save the PDF to disk (optional) - cy.writeFile('/fixtures/cypress/downloads/generated-report.pdf', buf); + cy.writeFile('/cypress/downloads/generated-report.pdf', buf); }); }); }); // Verify PDF content cy.task("verifyPdf", { - filePath: "/fixtures/cypress/downloads/generated-report.pdf", + filePath: "/cypress/downloads/generated-report.pdf", options: { - referenceLogoPath: "/testFiles/countly-logo.png", + referenceLogoPath: "../../fixtures/testFiles/countly-logo.png", checkText: true } }).then((result) => { From 06601fbb53d484e37238878cf43fb5a39e5bba9d Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 15:26:53 +0000 Subject: [PATCH 18/39] Added 2mins timeout --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 73f96388ae4..853226a8e86 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -107,6 +107,7 @@ describe('Create New Custom Dashboard', () => { cy.request({ url: pdfURL, encoding: 'binary', + timeout: 120000, }).then((response) => { expect(response.status).to.eq(200); expect(response.headers['content-type']).to.include('application/pdf'); From bfa327530dd4fd76bcdb9e49fd9f9b9999673186 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 15:35:52 +0000 Subject: [PATCH 19/39] fixed countly logo path --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 853226a8e86..9c6f310b1ce 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -126,7 +126,7 @@ describe('Create New Custom Dashboard', () => { cy.task("verifyPdf", { filePath: "/cypress/downloads/generated-report.pdf", options: { - referenceLogoPath: "../../fixtures/testFiles/countly-logo.png", + referenceLogoPath: "/cypress/fixtures/testFiles/countly-logo.png", checkText: true } }).then((result) => { From b19aabff4a2ebab5350d9b0f9b47d885ef6fd560 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 15:46:47 +0000 Subject: [PATCH 20/39] Fixed logo path --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 9c6f310b1ce..65c7eb2a248 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -126,7 +126,7 @@ describe('Create New Custom Dashboard', () => { cy.task("verifyPdf", { filePath: "/cypress/downloads/generated-report.pdf", options: { - referenceLogoPath: "/cypress/fixtures/testFiles/countly-logo.png", + referenceLogoPath: "cypress/fixtures/testFiles/countly-logo.png", checkText: true } }).then((result) => { From cb5731bdf13f184180e53546b5f91a75c1a2bfa0 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 15:58:33 +0000 Subject: [PATCH 21/39] Added downloads upload --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fa3240c034c..bad7d98641c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -335,6 +335,6 @@ jobs: working-directory: /opt/countly/ui-tests/cypress run: | ARTIFACT_ARCHIVE_NAME="$(date '+%Y%m%d-%H.%M')_${GITHUB_REPOSITORY#*/}_CI#${{ github.run_number }}_${{ matrix.test_type }}.tar.gz" - mkdir -p screenshots videos - tar zcvf "$ARTIFACT_ARCHIVE_NAME" screenshots videos + mkdir -p screenshots videos downloads + tar zcvf "$ARTIFACT_ARCHIVE_NAME" screenshots videos downloads curl -o /tmp/uploader.log -u "${{ secrets.BOX_UPLOAD_AUTH }}" ${{ secrets.BOX_UPLOAD_PATH }} -T "$ARTIFACT_ARCHIVE_NAME" From 2a156bc88ec9b6b19a56f2b12aaa18f71d259417 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 16:28:14 +0000 Subject: [PATCH 22/39] Fixed downloaded pdf path --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 65c7eb2a248..7370ee622eb 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -116,15 +116,15 @@ describe('Create New Custom Dashboard', () => { expect(buf.slice(0, 4).toString()).to.eq('%PDF'); expect(buf.length).to.be.greaterThan(50000); // More than 50KB to ensure it's not empty - // Save the PDF to disk (optional) - cy.writeFile('/cypress/downloads/generated-report.pdf', buf); + // Save the PDF to disk + cy.writeFile('cypress/downloads/generated-report.pdf', buf); }); }); }); // Verify PDF content cy.task("verifyPdf", { - filePath: "/cypress/downloads/generated-report.pdf", + filePath: "cypress/downloads/generated-report.pdf", options: { referenceLogoPath: "cypress/fixtures/testFiles/countly-logo.png", checkText: true From fe513d041d1a359f8e9a70b8562100e4753c408f Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 17:21:01 +0000 Subject: [PATCH 23/39] Edited pdf path for test --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 7370ee622eb..43e9e9fe967 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -124,7 +124,7 @@ describe('Create New Custom Dashboard', () => { // Verify PDF content cy.task("verifyPdf", { - filePath: "cypress/downloads/generated-report.pdf", + filePath: "cypress/downloads/generated-report2.pdf", options: { referenceLogoPath: "cypress/fixtures/testFiles/countly-logo.png", checkText: true From bab52fb71e73dd3c0645d0157aaf57af55ed261c Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 17:28:47 +0000 Subject: [PATCH 24/39] Fixed path --- .../cypress/e2e/dashboard/dashboards/dashboards.cy.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 43e9e9fe967..cac9b8365da 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -124,16 +124,16 @@ describe('Create New Custom Dashboard', () => { // Verify PDF content cy.task("verifyPdf", { - filePath: "cypress/downloads/generated-report2.pdf", + filePath: "cypress/downloads/generated-report.pdf", options: { referenceLogoPath: "cypress/fixtures/testFiles/countly-logo.png", checkText: true } }).then((result) => { - expect(result.logoFound).to.be.true; - expect(result.hasImage).to.be.true; + //expect(result.logoFound).to.be.true; + //expect(result.hasImage).to.be.true; expect(result.text).to.include("Sent by Countly | Unsubscribe"); - expect(result.text).to.include("Report settings | Get help"); + //expect(result.text).to.include("Report settings | Get help"); }); }); From 6d819509d93633cfce504ab67a7ac886dbdd002c Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 17:42:50 +0000 Subject: [PATCH 25/39] Removed expects for test --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index cac9b8365da..c4bf1d6b589 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -132,7 +132,7 @@ describe('Create New Custom Dashboard', () => { }).then((result) => { //expect(result.logoFound).to.be.true; //expect(result.hasImage).to.be.true; - expect(result.text).to.include("Sent by Countly | Unsubscribe"); + //expect(result.text).to.include("Sent by Countly | Unsubscribe"); //expect(result.text).to.include("Report settings | Get help"); }); }); From 57b1685f76171e55263dcb45d80749bcb06b64ec Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 17:50:35 +0000 Subject: [PATCH 26/39] Added hasImage logoFound expect --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index c4bf1d6b589..718f2aacaab 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -130,7 +130,7 @@ describe('Create New Custom Dashboard', () => { checkText: true } }).then((result) => { - //expect(result.logoFound).to.be.true; + expect(result.logoFound).to.be.true; //expect(result.hasImage).to.be.true; //expect(result.text).to.include("Sent by Countly | Unsubscribe"); //expect(result.text).to.include("Report settings | Get help"); From bc7f5385e1f154236b695235039e2475c77d8888 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 20:05:19 +0000 Subject: [PATCH 27/39] Added image verify --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 718f2aacaab..e78fa584f8e 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -131,7 +131,7 @@ describe('Create New Custom Dashboard', () => { } }).then((result) => { expect(result.logoFound).to.be.true; - //expect(result.hasImage).to.be.true; + expect(result.hasImage).to.be.true; //expect(result.text).to.include("Sent by Countly | Unsubscribe"); //expect(result.text).to.include("Report settings | Get help"); }); From 8b8220be38540b90cb3e199e5aa54bc21e6e5a6b Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 20:21:17 +0000 Subject: [PATCH 28/39] Added first text verify --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index e78fa584f8e..b2dd75ea84c 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -132,7 +132,7 @@ describe('Create New Custom Dashboard', () => { }).then((result) => { expect(result.logoFound).to.be.true; expect(result.hasImage).to.be.true; - //expect(result.text).to.include("Sent by Countly | Unsubscribe"); + expect(result.text).to.include("Sent by Countly | Unsubscribe"); //expect(result.text).to.include("Report settings | Get help"); }); }); From 9ca77c6d0c5f05340ded3e116a7ce2e7660259e5 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 20:41:27 +0000 Subject: [PATCH 29/39] Added text verfiy --- ui-tests/cypress.config.sample.js | 21 ++++++++++++------- .../e2e/dashboard/dashboards/dashboards.cy.js | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ui-tests/cypress.config.sample.js b/ui-tests/cypress.config.sample.js index 9015b11a504..93aa512eb09 100644 --- a/ui-tests/cypress.config.sample.js +++ b/ui-tests/cypress.config.sample.js @@ -22,12 +22,12 @@ module.exports = defineConfig({ watchForFileChanges: true, video: true, setupNodeEvents(on, config) { - // ✅ Task: verify PDF images and logo + // Task: verify PDF images, logo, and text content on("task", { async verifyPdf({ filePath, options = {} }) { // options: { referenceLogoPath: string } - // Load PDF + // Load PDF file const data = new Uint8Array(fs.readFileSync(filePath)); const pdfDoc = await pdfjsLib.getDocument({ data }).promise; @@ -41,16 +41,24 @@ module.exports = defineConfig({ let hasImage = false; let logoFound = false; + let extractedText = ""; //store text here + // Loop through all pages for (let p = 1; p <= pdfDoc.numPages; p++) { const page = await pdfDoc.getPage(p); + + //Extract text content from page + const textContent = await page.getTextContent(); + const pageText = textContent.items.map((item) => item.str).join(" "); + extractedText += pageText + "\n"; + + //Check for image operators const ops = await page.getOperatorList(); for (let i = 0; i < ops.fnArray.length; i++) { const fn = ops.fnArray[i]; const args = ops.argsArray[i]; - // --- Image check --- if ( fn === pdfjsLib.OPS.paintImageXObject || fn === pdfjsLib.OPS.paintJpegXObject || @@ -61,9 +69,7 @@ module.exports = defineConfig({ if (doLogoCheck && args[0]) { const objName = args[0]; const imgData = await page.objs.get(objName); - if (!imgData) { - continue; - } + if (!imgData) continue; const pdfImg = new PNG({ width: imgData.width, height: imgData.height }); pdfImg.data = imgData.data; @@ -105,15 +111,16 @@ module.exports = defineConfig({ throw new Error("Logo in PDF does not match reference image"); } + //Return with extracted text return { hasImage, logoFound, + text: extractedText, numPages: pdfDoc.numPages }; }, }); - on("after:spec", (spec, results) => { if (results?.video) { const hasFailures = results.tests.some((t) => t.attempts.some((a) => a.state === "failed")); diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index b2dd75ea84c..7370ee622eb 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -133,7 +133,7 @@ describe('Create New Custom Dashboard', () => { expect(result.logoFound).to.be.true; expect(result.hasImage).to.be.true; expect(result.text).to.include("Sent by Countly | Unsubscribe"); - //expect(result.text).to.include("Report settings | Get help"); + expect(result.text).to.include("Report settings | Get help"); }); }); From 26c17264c0994fad9926e3410903af2b8d85a766 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 21:01:35 +0000 Subject: [PATCH 30/39] Updated text --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index 7370ee622eb..a4e6f62f9b2 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -132,8 +132,8 @@ describe('Create New Custom Dashboard', () => { }).then((result) => { expect(result.logoFound).to.be.true; expect(result.hasImage).to.be.true; - expect(result.text).to.include("Sent by Countly | Unsubscribe"); - expect(result.text).to.include("Report settings | Get help"); + expect(result.text).to.include("Sent by Countly | Unsubscribe"); + expect(result.text).to.include("Report settings | Get help"); }); }); From c4947fab9e65e8ef4c4f194e8ff3dddc5dc37bd4 Mon Sep 17 00:00:00 2001 From: can-angun Date: Mon, 3 Nov 2025 21:14:01 +0000 Subject: [PATCH 31/39] Opened all tests --- ui-tests/cypress.config.sample.js | 4 +++- ui-tests/package.json | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ui-tests/cypress.config.sample.js b/ui-tests/cypress.config.sample.js index 93aa512eb09..ed64da51c46 100644 --- a/ui-tests/cypress.config.sample.js +++ b/ui-tests/cypress.config.sample.js @@ -69,7 +69,9 @@ module.exports = defineConfig({ if (doLogoCheck && args[0]) { const objName = args[0]; const imgData = await page.objs.get(objName); - if (!imgData) continue; + if (!imgData) { + continue; + } const pdfImg = new PNG({ width: imgData.width, height: imgData.height }); pdfImg.data = imgData.data; diff --git a/ui-tests/package.json b/ui-tests/package.json index cf46e76489a..18d3d9c46b9 100644 --- a/ui-tests/package.json +++ b/ui-tests/package.json @@ -4,7 +4,7 @@ "description": "e2e testing", "author": "Countly, Inc.", "scripts": { - "cy:run:dashboard": "node ./cypress/fixtures/generators/generateFixtures.js && cypress run --record --key 00000000-0000-0000-0000-000000000000 --spec **/dashboard/**/dashboards.cy.js --headless --no-runner-ui --browser chrome", + "cy:run:dashboard": "node ./cypress/fixtures/generators/generateFixtures.js && cypress run --record --key 00000000-0000-0000-0000-000000000000 --spec **/dashboard/**/*.cy.js --headless --no-runner-ui --browser chrome", "cy:run:onboarding": "cypress run --record --key 00000000-0000-0000-0000-000000000000 --spec **/onboarding/**/*.cy.js --headless --no-runner-ui --browser chrome" }, "license": "ISC", From 942784823971f36f53c8086dc83cdbbdfb9966d8 Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 4 Nov 2025 06:49:40 +0000 Subject: [PATCH 32/39] Empty-Commit From 0ccd622bc90485ed609454d0eb7a4a01f5416a67 Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 4 Nov 2025 07:27:06 +0000 Subject: [PATCH 33/39] Updated install chrome and dependencies scripts --- .github/workflows/main.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bad7d98641c..5a12c971aaa 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -270,17 +270,19 @@ jobs: steps: - uses: actions/checkout@v5 - - name: Install Chrome + dependencies (including libvips for sharp) + - name: Install Chrome shell: bash run: | - apt update - # Required for Chrome - apt install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb wget - # Required for 'sharp' (used in PDF image comparison) - apt install -y libvips-dev - # Install Chrome + export DEBIAN_FRONTEND=noninteractive wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -O /tmp/chrome.deb - apt install -y /tmp/chrome.deb + apt-get install -y /tmp/chrome.deb + + - name: Install system dependencies (for Cypress + Sharp) + shell: bash + run: | + export DEBIAN_FRONTEND=noninteractive + apt-get update -y + apt-get install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb wget libvips-dev - name: Copy code shell: bash From bce02e0d2c3ef513be0e9275d9c330a44d56a86a Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 4 Nov 2025 07:30:44 +0000 Subject: [PATCH 34/39] Updated install chrome script --- .github/workflows/main.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5a12c971aaa..e885588ff71 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -273,9 +273,10 @@ jobs: - name: Install Chrome shell: bash run: | - export DEBIAN_FRONTEND=noninteractive + apt update + apt install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb wget wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -O /tmp/chrome.deb - apt-get install -y /tmp/chrome.deb + apt install -y /tmp/chrome.deb - name: Install system dependencies (for Cypress + Sharp) shell: bash From 4d63099ee235472ad268c2e8e2c8d1feb977dacf Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 4 Nov 2025 07:35:25 +0000 Subject: [PATCH 35/39] Updated install scripts --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e885588ff71..0abcf6f4b0b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -273,17 +273,17 @@ jobs: - name: Install Chrome shell: bash run: | - apt update - apt install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb wget + apt-get update + apt-get install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb wget wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -O /tmp/chrome.deb - apt install -y /tmp/chrome.deb + apt-get install -y /tmp/chrome.deb - name: Install system dependencies (for Cypress + Sharp) shell: bash run: | export DEBIAN_FRONTEND=noninteractive apt-get update -y - apt-get install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb wget libvips-dev + apt-get install -y libvips-dev - name: Copy code shell: bash From ca0a9431e08704ada7614ababe47700d522ea8e5 Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 4 Nov 2025 07:50:10 +0000 Subject: [PATCH 36/39] Fixed install chrome script --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0abcf6f4b0b..be08a4b51e6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -273,10 +273,10 @@ jobs: - name: Install Chrome shell: bash run: | - apt-get update - apt-get install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb wget + apt update + apt install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb wget wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -O /tmp/chrome.deb - apt-get install -y /tmp/chrome.deb + apt install -y /tmp/chrome.deb - name: Install system dependencies (for Cypress + Sharp) shell: bash From 158494783efd13661c6bc5f259e6b70156766170 Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 4 Nov 2025 12:22:53 +0000 Subject: [PATCH 37/39] Empty-Commit From 053b9fe5ad44fe63d87500bd3a4c48966ba4dc1f Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 4 Nov 2025 13:02:27 +0000 Subject: [PATCH 38/39] Updated cases it desc --- ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js index a4e6f62f9b2..b4c85b30251 100644 --- a/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js +++ b/ui-tests/cypress/e2e/dashboard/dashboards/dashboards.cy.js @@ -21,7 +21,7 @@ describe('Create New Custom Dashboard', () => { }); it(` - Create a custom dashboard with a widget and an email report, and then verify the report preview using these parameters: + Create a custom dashboard with a widget and an email report, verify the report preview, and validate the downloaded PDF content: //***Dashboard*** Dashboard Visibility: All Users (default) //***Widget*** From e2372a9b21590ef4586fcd114d8d89cfac5fc8e9 Mon Sep 17 00:00:00 2001 From: can-angun Date: Tue, 4 Nov 2025 13:10:33 +0000 Subject: [PATCH 39/39] Updated job name desc --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index be08a4b51e6..e21a6099b11 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -278,7 +278,7 @@ jobs: wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -O /tmp/chrome.deb apt install -y /tmp/chrome.deb - - name: Install system dependencies (for Cypress + Sharp) + - name: Install Sharp dependencies for image processing shell: bash run: | export DEBIAN_FRONTEND=noninteractive