Skip to content

Masks applied at incorrect positions if doing multiple PDF comparison in a single spec file #71

@GrayedFox

Description

@GrayedFox

Background

I started encountering this issue recently - I'm using PlayWright and Mailpit to perform a PDF diff against PDF files sent as email attachments.

Will link relevant parts of the code here for now, can't provide a minimal reproduction base right now as I'm pressed for time but I will edit the issue description to link to a public repo that reproduces the issue in a bit.

Describing the issue now just in case it's easy to spot and fix on your end ⚡

Bug

When performing two diffs of the same PDF file from within a single PlayWright spec the PDF comparison fails for the 2nd diff due to the masks not being applied in the correct location.

// spec
...

        // if I skip this test the 2nd comparison passes
        test.skip('signer sees confirmation email with holiday letting agreement attached', async ({}, testInfo) => {
            await signer.seesEmail({
                subject: `Holiday Letting agreement - ${address}`,
                specFile: testInfo.file,
                pdfs: [pdfs.document],
                masks: masks.document,
                markAsRead: false
            });
        });

        // if I skip this test and don't skip the above test, the 1st one passes
        test('agent sees confirmation email with holiday letting agreement attached', async ({}, testInfo) => {
            await agent.seesEmail({
                subject: `Holiday Letting agreement - ${address}`,
                specFile: testInfo.file,
                pdfs: [pdfs.document],
                masks: masks.document
            });
        });

Here's the relevant part of the class method:

// Actor class
...

        // do a PDF diff for each PDF attachment
        if (pdfs.length > 0) {
            const messageSummary = await getMail(message.ID);
            const messageAttachments = messageSummary.Attachments;

            for (const attachment of messageAttachments) {
                const pdf = pdfs.find(pdf => this.#safeStringCompare(pdf, attachment.FileName));

                // assert that we found a matching pdf based on the filename
                expect(pdf).toBeDefined();
                // assert that the attachment is indeed a PDF file
                expect(attachment.ContentType).toBe('application/pdf');

                // convert the pdf file name to a normalized string for the snapshot path
                const pdfSafeName = this.#safeguardString(pdf);

                // get the PDF buffer and perform a visual diff against our local snapshot
                const buffer = await getMailAttachment(message.ID, attachment.PartID);
                const result = await comparePdfs({ buffer, path: specPath, name: pdfSafeName, masks });

                // expect the comparison to return true
                expect(result).toBe(true);
            }
        }

I know there's a lot of hidden logic here, what I can say with 100% certainty is that the PDF being used in each comparison is pulled from the exact same email - what happens is we send an email with that PDF to two recipients. The spec file simply does two comparisons because sometimes we send slightly different PDFs based on the recipient (which would be two different emails). In this case the agent and signer get the exact same copy.

I get these results:

Base
snapshot-base

Diff
snapshot-diff

New
snapshot-new

Skipping either of those two comparisons causes the other to pass:
passes-if-skipping

Misc

I didn't go to deep into the pdf-diff code. I get the feeling there is something about how the PDF canvas is cleaning up that causes the masks to be applied in the wrong location on the 2nd comparison, I inserted a hard coded 30 second wait before doing the 2nd comparison and got the same result, so it doesn't seem like it's a race condition.

The error might actually be coming from a dependency and not this module itself, will move this report there if that's the case.

Expected Behaviour

Doing multiple PDF comparisons in a single spec file should apply the masks consistently.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions