The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/e2e/cypress/plugins/smtpTester.js

129 lines
3.5 KiB

const fs = require('fs');
const { Jimp, diff } = require('jimp');
const pdf = require('pdf-parse');
const ms = require('smtp-tester');
const PORT = 7777;
const initialize = (on, config) => {
// starts the SMTP server at localhost:7777
const mailServer = ms.init(PORT);
console.log('mail server at port %d', PORT);
let lastEmail = {};
// process all emails
mailServer.bind((addr, id, email) => {
lastEmail[email.headers.to] = email;
});
on('task', {
resetEmails(recipient) {
if (recipient) {
console.log('reset all emails for recipient %s', recipient);
delete lastEmail[recipient];
} else {
console.log('reset all emails');
lastEmail = {};
}
},
getLastEmail(email) {
return lastEmail[email] || null;
},
});
on('task', {
async compareImages({ expectedImageFilepath, newImageContent, updateExpectedImage = false }) {
const inputBuffer = Buffer.from(newImageContent.data);
if (updateExpectedImage) {
fs.writeFileSync(expectedImageFilepath, inputBuffer);
return true;
}
const inputImage = await Jimp.read(inputBuffer);
const expectedImage = await Jimp.read(expectedImageFilepath);
const pixelDiff = diff(expectedImage, inputImage, 0.3);
return pixelDiff.percent <= 0.1;
},
});
on('task', {
async compareCSVs({ expectedCSVFilepath, newCSVContent, updateExpectedCSV = false }) {
const inputBuffer = Buffer.from(newCSVContent.data);
if (updateExpectedCSV) {
await fs.writeFileSync(expectedCSVFilepath, inputBuffer);
return true;
}
const inputCSV = toCSV(inputBuffer);
const expectedCSV = toCSV(fs.readFileSync(expectedCSVFilepath));
if (inputCSV.length !== expectedCSV.length) {
return false;
}
for (let i = 0; i < expectedCSV.length; i++) {
const line = expectedCSV[i];
for (let j = 0; j < line.length; j++) {
if (line[j] !== inputCSV[i][j]) {
return false;
}
}
}
return true;
},
});
on('task', {
async comparePDFs({ expectedPDFFilepath, newPDFContent, updateExpectedPDF = false }) {
const inputBuffer = Buffer.from(newPDFContent.data);
if (updateExpectedPDF) {
fs.writeFileSync(expectedPDFFilepath, inputBuffer);
return true;
}
const inputDoc = await pdf(inputBuffer);
const expectedDoc = await pdf(expectedPDFFilepath);
removePDFGeneratedOnDate(inputDoc);
removePDFGeneratedOnDate(expectedDoc);
if (inputDoc.numpages !== expectedDoc.numpages) {
console.log('PDFs do not contain the same number of pages');
return false;
}
if (inputDoc.text !== expectedDoc.text) {
console.log('PDFs do not contain the same text');
console.log('PDF expected text: ', expectedDoc.text);
console.log('PDF input text: ', inputDoc.text);
return false;
}
return true;
},
});
};
const toCSV = (buffer) => {
return buffer
.toString()
.split('\n')
.map((e) => e.trim())
.map((e) => e.split(',').map((e) => e.trim()));
};
// remove the date part of the "Generated on <date>" header in PDFs as it's too complicated to set it to a fixed date
const removePDFGeneratedOnDate = (pdfDoc) => {
const regex = /(Generated on )(.*)(Data time range)/;
// removes the text in the second set of parenthesis of the regex above
pdfDoc.text = pdfDoc.text.replace(regex, (match, p1, p2, p3) => {
return `${p1} ${p3}`;
});
};
exports.initialize = initialize;