GithubHelp home page GithubHelp logo

thomaschaaf / compare-pdf Goto Github PK

View Code? Open in Web Editor NEW

This project forked from marcdacz/compare-pdf

0.0 1.0 0.0 834 KB

Standalone node module that compares pdfs

License: MIT License

JavaScript 100.00%

compare-pdf's Introduction

compare-pdf

Standalone node module that compares pdfs

Setup

To use GraphicsMagick (gm) Engine, install the following system dependencies

Install npm module

npm install compare-pdf

Default Configuration

Below is the default configuration showing the paths where the pdfs should be placed. By default, they are in the root folder of your project inside the folder data.

The config also contains settings for image comparison such as density, quality, tolerance and threshold. It also has flag to enable or disable cleaning up of the actual and baseline png folders.

{
    paths: {
        actualPdfRootFolder: process.cwd() + "/data/actualPdfs",
        baselinePdfRootFolder: process.cwd() + "/data/baselinePdfs",
        actualPngRootFolder: process.cwd() + "/data/actualPngs",
        baselinePngRootFolder: process.cwd() + "/data/baselinePngs",
        diffPngRootFolder: process.cwd() + "/data/diffPngs"
    },
    settings: {
        imageEngine: 'graphicsMagick',
        density: 100,
        quality: 70,
        tolerance: 0,
        threshold: 0.05,
        cleanPngPaths: true,
        matchPageCount: true
    }
}

Settings:

PDF to Image Conversion

  • imageEngine: (experimental) This config allows you to specify which image engine to use: graphicsMagick or native
  • density: (from gm) This option specifies the image resolution to store while encoding a raster image or the canvas resolution while rendering (reading) vector formats into an image.
  • quality: (from gm) Adjusts the jpeg|miff|png|tiff compression level. val ranges from 0 to 100 (best).
  • cleanPngPaths: This is a boolean flag for cleaning png folders automatically
  • matchPageCount: This is a boolean flag that enables or disables the page count verification between the actual and baseline pdfs

Image Comparison

  • tolerance: This is the allowable pixel count that is different between the compared images.
  • threshold: (from pixelmatch) Matching threshold, ranges from 0 to 1. Smaller values make the comparison more sensitive. 0.1 by default.

Compare Pdfs By Image

Basic Usage

By default, pdfs are compared using the comparison type as "byImage"

it("Should be able to verify same PDFs", async () => {
    let comparisonResults = await new comparePdf()
        .actualPdfFile("same.pdf")
        .baselinePdfFile("baseline.pdf")
        .compare();
    expect(comparisonResults.status).to.equal("passed");
});

it("Should be able to verify different PDFs", async () => {
    const ComparePdf = new comparePdf();
    let comparisonResults = await ComparePdf.actualPdfFile("notSame.pdf")
        .baselinePdfFile("baseline.pdf")
        .compare("byImage");
    expect(comparisonResults.status).to.equal("failed");
    expect(comparisonResults.message).to.equal("notSame.pdf is not the same as baseline.pdf.");
    expect(comparisonResults.details).to.not.be.null;
});

Using Masks

You can mask areas of the images that has dynamic values (ie. Dates, or Ids) before the comparison. Just use the addMask method and indicate the pageIndex (starts at 0) and the coordinates.

it("Should be able to verify same PDFs with Masks", async () => {
    let comparisonResults = await new comparePdf()
        .actualPdfFile("maskedSame.pdf")
        .baselinePdfFile("baseline.pdf")
        .addMask(1, { x0: 35, y0: 70, x1: 145, y1: 95 })
        .addMask(1, { x0: 185, y0: 70, x1: 285, y1: 95 })
        .compare();
    expect(comparisonResults.status).to.equal("passed");
});

You can also indicate the page masks in bulk by passing an array of it in the addMasks method

it("Should be able to verify different PDFs with Masks", async () => {
    const ComparePdf = new comparePdf();
    let masks = [
        { pageIndex: 1, coordinates: { x0: 35, y0: 70, x1: 145, y1: 95 } },
        { pageIndex: 1, coordinates: { x0: 185, y0: 70, x1: 285, y1: 95 } }
    ];
    let comparisonResults = await ComparePdf.actualPdfFile("maskedNotSame.pdf")
        .baselinePdfFile("baseline.pdf")
        .addMasks(masks)
        .compare();
    expect(comparisonResults.status).to.equal("failed");
    expect(comparisonResults.message).to.equal("maskedNotSame.pdf is not the same as baseline.pdf.");
    expect(comparisonResults.details).to.not.be.null;
});

Cropping Pages

If you need to compare only a certain area of the pdf, you can do so by utilising the cropPage method and passing the pageIndex (starts at 0), the width and height along with the x and y coordinates.

it("Should be able to verify same PDFs with Croppings", async () => {
    let comparisonResults = await new comparePdf()
        .actualPdfFile("same.pdf")
        .baselinePdfFile("baseline.pdf")
        .cropPage(1, { width: 530, height: 210, x: 0, y: 415 })
        .compare();
    expect(comparisonResults.status).to.equal("passed");
});

Similar to masks, you can also pass all cropping in bulk into the cropPages method. You can have multiple croppings in the same page.

it("Should be able to verify same PDFs with Croppings", async () => {
    let croppings = [
        { pageIndex: 0, coordinates: { width: 210, height: 180, x: 615, y: 265 } },
        { pageIndex: 0, coordinates: { width: 210, height: 180, x: 615, y: 520 } },
        { pageIndex: 1, coordinates: { width: 530, height: 210, x: 0, y: 415 } }
    ];

    let comparisonResults = await new comparePdf()
        .actualPdfFile("same.pdf")
        .baselinePdfFile("baseline.pdf")
        .cropPages(croppings)
        .compare();
    expect(comparisonResults.status).to.equal("passed");
});

Verify Specific Page Indexes

Should you need to test only specific page indexes in a pdf, you can do so by specifying an array of page indexes using the onlyPageIndexes method as shown below.

it("Should be able to verify only specific page indexes", async () => {
    let comparisonResults = await new comparePdf()
        .actualPdfFile("notSame.pdf")
        .baselinePdfFile("baseline.pdf")
        .onlyPageIndexes([1])
        .compare();
    expect(comparisonResults.status).to.equal("passed");
});

Skip Specific Page Indexes

On the flip side, should you need to skip specific page indexes in a pdf, you can do so by specifying an array of page indexes using the skipPageIndexes method as shown below.

it("Should be able to skip specific page indexes", async () => {
    let comparisonResults = await new comparePdf()
        .actualPdfFile("notSame.pdf")
        .baselinePdfFile("baseline.pdf")
        .skipPageIndexes([0])
        .compare();
    expect(comparisonResults.status).to.equal("passed");
});

Compare Pdfs By Base64

Basic Usage

By passing "byBase64" as the comparison type parameter in the compare method, the pdfs will be compared whether the actual and baseline's converted file in base64 format are the same.

it("Should be able to verify same PDFs", async () => {
    let comparisonResults = await new comparePdf()
        .actualPdfFile("same.pdf")
        .baselinePdfFile("baseline.pdf")
        .compare("byBase64");
    expect(comparisonResults.status).to.equal("passed");
});

it("Should be able to verify different PDFs", async () => {
    let comparisonResults = await new comparePdf()
        .actualPdfFile("notSame.pdf")
        .baselinePdfFile("baseline.pdf")
        .compare("byBase64");
    expect(comparisonResults.status).to.equal("failed");
    expect(comparisonResults.message).to.equal("notSame.pdf is not the same as baseline.pdf.");
});

Other Capabilities

Overriding Default Configuration

Users can override the default configuration by passing their custom config when initialising the class

it("Should be able to override default configs", async () => {
    let config = {
        paths: {
            actualPdfRootFolder: process.cwd() + "/data/newActualPdfs",
            baselinePdfRootFolder: process.cwd() + "/data/baselinePdfs",
            actualPngRootFolder: process.cwd() + "/data/actualPngs",
            baselinePngRootFolder: process.cwd() + "/data/baselinePngs",
            diffPngRootFolder: process.cwd() + "/data/diffPngs"
        },
        settings: {
            density: 100,
            quality: 70,
            tolerance: 0,
            threshold: 0.05,
            cleanPngPaths: false,
            matchPageCount: true
    };
    let comparisonResults = await new comparePdf(config)
        .actualPdfFile("newSame.pdf")
        .baselinePdfFile("baseline.pdf")
        .compare();
    expect(comparisonResults.status).to.equal("passed");
});

it("Should be able to override specific config property", async () => {
    const ComparePdf = new comparePdf();
    ComparePdf.config.paths.actualPdfRootFolder = process.cwd() + "/data/newActualPdfs";
    let comparisonResults = await ComparePdf.actualPdfFile("newSame.pdf")
        .baselinePdfFile("baseline.pdf")
        .compare();
    expect(comparisonResults.status).to.equal("passed");
});

Pdf File Paths

Users can pass just the filename with or without extension as long as the pdfs are inside the default or custom configured actual and baseline paths

it("Should be able to pass just the name of the pdf with extension", async () => {
    let comparisonResults = await new comparePdf()
        .actualPdfFile("same.pdf")
        .baselinePdfFile("baseline.pdf")
        .compare();
    expect(comparisonResults.status).to.equal("passed");
});

it("Should be able to pass just the name of the pdf without extension", async () => {
    let comparisonResults = await new comparePdf()
        .actualPdfFile("same")
        .baselinePdfFile("baseline")
        .compare();
    expect(comparisonResults.status).to.equal("passed");
});

Users can also pass a relative path of the pdf files as parameters

it("Should be able to verify same PDFs using relative paths", async () => {
    let comparisonResults = await new comparePdf()
        .actualPdfFile("../data/actualPdfs/same.pdf")
        .baselinePdfFile("../data/baselinePdfs/baseline.pdf")
        .compare();
    expect(comparisonResults.status).to.equal("passed");
});

Tips and Tricks

Speed up your tests

To speed up your test executions, you can utilise the comparison type "byBase64" first and only when it fails you comapre it "byImage". This provides the best of both worlds where you get the speed of execution and when there is a difference, you can check the image diff.

it("Should be able to verify PDFs byBase64 and when it fails then byImage", async () => {
    let comparisonResultsByBase64 = await new comparePdf()
        .actualPdfFile("notSame.pdf")
        .baselinePdfFile("baseline.pdf")
        .compare("byBase64");
    expect(comparisonResultsByBase64.status).to.equal("failed");
    expect(comparisonResultsByBase64.message).to.equal(
        "notSame.pdf is not the same as baseline.pdf compared by their base64 values."
    );

    if (comparisonResultsByBase64.status === "failed") {
        let comparisonResultsByImage = await new comparePdf()
            .actualPdfFile("notSame.pdf")
            .baselinePdfFile("baseline.pdf")
            .compare("byImage");
        expect(comparisonResultsByImage.status).to.equal("failed");
        expect(comparisonResultsByImage.message).to.equal(
            "notSame.pdf is not the same as baseline.pdf compared by their images."
        );
        expect(comparisonResultsByImage.details).to.not.be.null;
    }
});

Libary not loaded error

macOS users encountering "dyld: Library not loaded" error? Then follow the answer from this stackoverflow post to set the correct path to *.dylib.

Example Projects

compare-pdf's People

Contributors

marcdacz avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.