splitting tests
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
import { expect, type Download, type Locator, type Page } from '@playwright/test';
|
||||
import {
|
||||
decodePDFRawStream,
|
||||
degrees,
|
||||
PDFArray,
|
||||
PDFDocument,
|
||||
PDFRawStream,
|
||||
StandardFonts,
|
||||
rgb
|
||||
} from 'pdf-lib';
|
||||
import { PDFDocument as EncryptablePdfDocument } from '@cantoo/pdf-lib';
|
||||
import { zipSync } from 'fflate';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
|
||||
export const createPdf = async (pageCount: number, label: string) => {
|
||||
const document = await PDFDocument.create();
|
||||
const font = await document.embedFont(StandardFonts.Helvetica);
|
||||
for (let pageNumber = 1; pageNumber <= pageCount; pageNumber += 1) {
|
||||
const page = document.addPage([420, 594]);
|
||||
page.drawText(`${label} – Seite ${pageNumber}`, {
|
||||
x: 40,
|
||||
y: 520,
|
||||
size: 20,
|
||||
font,
|
||||
color: rgb(0.1, 0.2, 0.4)
|
||||
});
|
||||
}
|
||||
return Buffer.from(await document.save());
|
||||
};
|
||||
|
||||
export const createStampPng = (page: Page) =>
|
||||
page.evaluate(
|
||||
async () =>
|
||||
new Promise<string>((resolve, reject) => {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 32;
|
||||
canvas.height = 32;
|
||||
const context = canvas.getContext('2d');
|
||||
if (!context) {
|
||||
reject(new Error('Kein 2D-Kontext'));
|
||||
return;
|
||||
}
|
||||
context.fillStyle = '#cc1a1a';
|
||||
context.fillRect(0, 0, 32, 32);
|
||||
canvas.toBlob(async (blob) => {
|
||||
if (!blob) {
|
||||
reject(new Error('PNG konnte nicht erzeugt werden'));
|
||||
return;
|
||||
}
|
||||
const bytes = new Uint8Array(await blob.arrayBuffer());
|
||||
let binary = '';
|
||||
bytes.forEach((byte) => {
|
||||
binary += String.fromCharCode(byte);
|
||||
});
|
||||
resolve(btoa(binary));
|
||||
}, 'image/png');
|
||||
})
|
||||
);
|
||||
|
||||
export const dropFiles = async (
|
||||
page: Page,
|
||||
target: Locator | 'window',
|
||||
files: Array<{ name: string; mimeType: string; buffer: Buffer }>
|
||||
) => {
|
||||
await page.locator('[data-dropzone-ready="true"]').first().waitFor();
|
||||
const dataTransfer = await page.evaluateHandle(
|
||||
(droppedFiles) => {
|
||||
const transfer = new DataTransfer();
|
||||
for (const droppedFile of droppedFiles) {
|
||||
const bytes = Uint8Array.from(atob(droppedFile.base64), (character) =>
|
||||
character.charCodeAt(0)
|
||||
);
|
||||
transfer.items.add(
|
||||
new File([bytes], droppedFile.name, {
|
||||
type: droppedFile.mimeType,
|
||||
lastModified: Date.now()
|
||||
})
|
||||
);
|
||||
}
|
||||
return transfer;
|
||||
},
|
||||
files.map((file) => ({
|
||||
name: file.name,
|
||||
mimeType: file.mimeType,
|
||||
base64: file.buffer.toString('base64')
|
||||
}))
|
||||
);
|
||||
|
||||
if (target === 'window') {
|
||||
await page.evaluate((transfer) => {
|
||||
window.dispatchEvent(
|
||||
new DragEvent('drop', { dataTransfer: transfer, bubbles: true, cancelable: true })
|
||||
);
|
||||
}, dataTransfer);
|
||||
} else {
|
||||
await target.dispatchEvent('drop', { dataTransfer });
|
||||
}
|
||||
await dataTransfer.dispose();
|
||||
};
|
||||
|
||||
export const expectPdfDownload = async (download: Download, name: RegExp) => {
|
||||
expect(download.suggestedFilename()).toMatch(name);
|
||||
const path = await download.path();
|
||||
expect(path).not.toBeNull();
|
||||
const bytes = await readFile(path!);
|
||||
expect(bytes.subarray(0, 5).toString()).toBe('%PDF-');
|
||||
return bytes;
|
||||
};
|
||||
|
||||
export const getPageContentStreamCount = (document: PDFDocument, pageIndex: number) => {
|
||||
const contents = document.getPage(pageIndex).node.Contents();
|
||||
if (!contents) return 0;
|
||||
return contents instanceof PDFArray ? contents.size() : 1;
|
||||
};
|
||||
|
||||
export const getPageContentText = (document: PDFDocument, pageIndex: number) => {
|
||||
const contents = document.getPage(pageIndex).node.Contents();
|
||||
const refs = contents instanceof PDFArray ? contents.asArray() : contents ? [contents] : [];
|
||||
return refs
|
||||
.map((ref) => document.context.lookup(ref))
|
||||
.filter((stream): stream is PDFRawStream => stream instanceof PDFRawStream)
|
||||
.map((stream) => Buffer.from(decodePDFRawStream(stream).decode()).toString('latin1'))
|
||||
.join('\n');
|
||||
};
|
||||
|
||||
export const createEncryptedPdf = async (pageCount: number, label: string, password: string) => {
|
||||
const document = await EncryptablePdfDocument.load(await createPdf(pageCount, label));
|
||||
document.encrypt({
|
||||
userPassword: password,
|
||||
ownerPassword: 'owner-passwort',
|
||||
permissions: { printing: true, copying: true }
|
||||
});
|
||||
return Buffer.from(await document.save());
|
||||
};
|
||||
|
||||
export const createPreRotatedPdf = async (pageCount: number, label: string) => {
|
||||
const document = await PDFDocument.create();
|
||||
const font = await document.embedFont(StandardFonts.Helvetica);
|
||||
for (let pageNumber = 1; pageNumber <= pageCount; pageNumber += 1) {
|
||||
const page = document.addPage([420, 594]);
|
||||
page.drawText(`${label} – Seite ${pageNumber}`, {
|
||||
x: 40,
|
||||
y: 520,
|
||||
size: 20,
|
||||
font,
|
||||
color: rgb(0.1, 0.2, 0.4)
|
||||
});
|
||||
if (pageNumber === 1) page.setRotation(degrees(90));
|
||||
}
|
||||
return Buffer.from(await document.save());
|
||||
};
|
||||
|
||||
export const trackPageErrors = (page: Page) => {
|
||||
const errors: Error[] = [];
|
||||
page.on('pageerror', (error) => errors.push(error));
|
||||
return errors;
|
||||
};
|
||||
|
||||
export const pdfDropzone = (page: Page) =>
|
||||
page.getByRole('button', { name: 'PDF-Dateien hinzufügen' });
|
||||
export const zipDropzone = (page: Page) =>
|
||||
page.getByRole('button', { name: 'beA-ZIP-Dateien hinzufügen' });
|
||||
|
||||
export const createZip = async (label: string, pageCount = 1) =>
|
||||
Buffer.from(zipSync({ [`${label}.pdf`]: await createPdf(pageCount, label) }));
|
||||
|
||||
export const newZipButton = (page: Page) =>
|
||||
page.getByRole('button', { name: 'Neue ZIP bearbeiten' });
|
||||
export const settingsButton = (page: Page) =>
|
||||
page.getByRole('button', { name: 'Einstellungen', exact: true });
|
||||
export const replaceZipInput = (page: Page) => page.locator('input[data-zip-picker="replace-zip"]');
|
||||
export const appendZipInput = (page: Page) => page.locator('input[data-zip-picker="append-zip"]');
|
||||
export const workspaceStatus = (page: Page, pattern: RegExp) => page.getByText(pattern);
|
||||
|
||||
export const waitForLoadedWorkspace = async (
|
||||
page: Page,
|
||||
status: RegExp,
|
||||
options?: { timeout?: number }
|
||||
) => {
|
||||
await expect(newZipButton(page)).toBeVisible();
|
||||
await expect(workspaceStatus(page, status)).toBeVisible({ timeout: options?.timeout ?? 15_000 });
|
||||
};
|
||||
|
||||
export const replaceThroughDialog = async (page: Page, zip: Buffer, confirm: boolean) => {
|
||||
await newZipButton(page).click();
|
||||
await replaceZipInput(page).setInputFiles([
|
||||
{ name: 'archiv-b.zip', mimeType: 'application/zip', buffer: zip }
|
||||
]);
|
||||
await expect(page.getByText('Aktuelle Bearbeitung ersetzen?')).toBeVisible();
|
||||
if (confirm) {
|
||||
await page.getByRole('button', { name: 'Neue ZIP öffnen' }).click();
|
||||
} else {
|
||||
await page.getByRole('button', { name: 'Abbrechen' }).click();
|
||||
}
|
||||
await expect(page.getByText('Aktuelle Bearbeitung ersetzen?')).toBeHidden();
|
||||
};
|
||||
Reference in New Issue
Block a user