diff --git a/README.md b/README.md index 2860ccf3dc1f9a2786eb625f50365bb3cbb1fee6..d17e8053c4c9347231bb712b194464e3f1f462c8 100644 --- a/README.md +++ b/README.md @@ -16,25 +16,77 @@ https://code.vereign.com/light/documentation/-/blob/master/Validation.md#normali ## Testing -- `yarn test` -- `yarn test:watch` - -`eml` files with test cases provided in `__tests__/files` - -- `sent.eml` corresponds to the MIME string extract by integrator application -- `received.eml` - corresponds to the raw MIME message extracted manually from email client - -If you are going to create a new test case, please follow the structure inside this directory. - -_Important note: MIME normaliser does not cover all provided test cases. -Some of them explicitly ignored to indicate which tests has to be fixed. Please refer to `failingCases` arrays inside the test files._ - -Tests are using both JSDOM and custom Vereign [DOM parser](https://code.vereign.com/code/js-toolbox/gsdom). -Vereign DOM parser has been developed to support MIME normalisation in Google Add-on and is a must for testing. - -Whenever you develop a new normalisation logic, ensure that Vereign DOM parser and Google Add-on support functions you apply. - -## Coverage +### Running + +- `yarn test` - runs tests once +- `yarn test:watch` - runs tests in watch mode + - use `p` key to run cases by regular expression, e.g. + `html-` + `.*-outlook-outlook` + `plain-gmail-` + +### Test cases generation + +- Create a directory for .eml files. Use the next structure as an example `__tests__/files/outlook-gmail/chrome-chrome/<test-case-dir>`. +- Put `sent.eml` and `received.eml` files into the `<test-case-dir>` + - `sent.eml` contains MIME string logged by integrator application during the sending routine. + - `received.eml` contains MIME string extracted manually from email client or logged by the integrator application. + For outlook.com - extract MIME string by logging it in the application itself. + _Do not do export MIME via the web client using `Show message source` action. + It breaks spacing of the quoted-printable parts and parsing/validation of such MIME might fail._ + For mail.google.com - use `Show original` -> `Download original` actions in web client. + _Don't copy contents provided by just `Show original` action because they miss base64 strings of the attachments_ +- Create three test suites to cover html, plain and htmltext (pseudoplain) normalisation. E.g: + - `html-outlook-gmail.test.ts` + - `plain-outlook-gmail.test.ts` + - `htmltext-outlook-gmail.test.ts` +- For every test suite, use built in functions to automate running of test cases. + ``` + const testsPath = path.resolve(__dirname, `./files/outlook-gmail`); + + // in html-outlook-gmail.test.ts + const runTests = createHtmlTestsRunner(testsPath, EMAIL_VENDORS.OUTLOOK); + describe("Chrome-Chrome", runTests("chrome-chrome")); + ... + // in plain-outlook-gmail.test.ts + const runTests = createPlainTestsRunner(testsPath); + describe("Chrome-Chrome", runTests("chrome-chrome")); + ... + // in htmltext-outlook-gmail.test.ts + const runTests = createPseudoplainTestsRunner(testsPath, EMAIL_VENDORS.OUTLOOK); + describe("Chrome-Chrome", runTests("chrome-chrome")); + ``` + +### Important clues + +- MIME normaliser does not cover all provided test cases. Some of them pending to be fixed and ignored explicitly. + Example: + + ```javascript + describe( + "MacOS-MacOS", + runTests("macos-macos", { ignore: ["03", "04", "05", "08", "09"] }) + ); + ``` + + _Details about valid/failing cases presented in [coverage](#coverage) section._ + +- To debug specific test cases, please first isolate a desired test file using the regexp in watch mode + and then use `checkExclusively` filter of the describe function. + + ```javascript + describe( + "MacOS-MacOS", + runTests("macos-macos", { checkExclusively: ["03", "08", "09"] }) + ); + ``` + +- Tests are using both JSDOM and custom Vereign [DOM parser](https://code.vereign.com/code/js-toolbox/gsdom). + Vereign DOM parser has been developed to support MIME normalisation in Google Add-on and is a must for testing. + + Whenever you develop a new normalisation logic, ensure that Vereign DOM parser support functions that you are applying. + +### Coverage - GMail-GMail - [Chrome-Chrome](__tests__/files/gmail-gmail/chrome-chrome/README.md) diff --git a/__tests__/helpers/fileReader.ts b/__tests__/helpers/fileReader.ts new file mode 100644 index 0000000000000000000000000000000000000000..65c2653f1c6bffd1480ef5fbab0f6e28cac892f6 --- /dev/null +++ b/__tests__/helpers/fileReader.ts @@ -0,0 +1,16 @@ +const fs = require("fs"); + +export const listDirectories = (testCasesPath: string): Array<string> => { + return fs.readdirSync(testCasesPath).filter(function (file) { + return fs.statSync(testCasesPath + "/" + file).isDirectory(); + }); +}; + +const filesCache: { [key: string]: string } = {}; +export const readFile = (path: string): string => { + if (!filesCache[path]) { + filesCache[path] = fs.readFileSync(path).toString(); + } + + return filesCache[path]; +}; diff --git a/__tests__/helpers/index.ts b/__tests__/helpers/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..1dd32f6d14c83bfedcbb6a8b98dd97394ec2fae5 --- /dev/null +++ b/__tests__/helpers/index.ts @@ -0,0 +1,242 @@ +import { JSDOM } from "jsdom"; +const crypto = require("crypto"); +import MIMEParser from "@vereign/mime-parser"; +import { expect, test } from "@jest/globals"; +import { DOM } from "@vereign/dom"; + +import { PlainNormalizer, HTMLNormalizer } from "../../src"; +import { listDirectories, readFile } from "./fileReader"; +import { diffStringsUnified } from "jest-diff"; + +const SENT_EML_NAME = "sent.eml"; +const RECEIVED_EML_NAME = "received.eml"; + +/** + * Substitutes cid:* with base64 strings of the corresponding attachments + */ +const POPULATE_ATTACHMENTS = true; + +interface CasesFilteringOptions { + ignore?: string[]; + checkExclusively?: string[]; +} + +/** + * Hashes base64 of the attachments to improve performance and readability + * @param base64 + */ +const hashAttachment = (base64: string) => { + return crypto + .createHash("sha256") + .update(Buffer.from(base64, "base64")) + .digest() + .toString("base64"); +}; + +expect.extend({ + /** + * Extends "toEqual" with diff functionality + */ + toEqualWithDiff(target, source) { + let pass = true; + try { + expect(target).toEqual(source); + } catch (e) { + pass = false; + } + + return { + pass, + message: pass ? () => "Pass" : () => diffStringsUnified(source, target), + }; + }, +}); + +export const createHtmlTestsRunner = (testsPath: string, vendor: string) => ( + casesGroupName: string, + filteringOptions?: CasesFilteringOptions +) => (): void => { + const testCases = prepareTestCases( + testsPath, + casesGroupName, + filteringOptions + ); + + test.concurrent.each(testCases)( + "Case %s", + async (dirName, { sentMime, receivedMime }) => { + const { sentHtmlDocument, receivedHtmlDocument } = await getDOMDocuments( + sentMime, + receivedMime + ); + + const sentHtml = HTMLNormalizer.normalizeVendorHtml( + sentHtmlDocument, + vendor + ); + const receivedHtml = HTMLNormalizer.normalizeVendorHtml( + receivedHtmlDocument, + vendor + ); + + // eslint-disable-next-line + // @ts-ignore + expect(receivedHtml).toEqualWithDiff(sentHtml); + } + ); +}; + +export const createPlainTestsRunner = (testsPath: string) => ( + casesGroupName: string, + filteringOptions?: CasesFilteringOptions +) => (): void => { + const testCases = prepareTestCases( + testsPath, + casesGroupName, + filteringOptions + ); + + test.concurrent.each(testCases)( + "Case %s", + async (dirName, { sentMime, receivedMime }) => { + const sentNormalizedPlain = PlainNormalizer.normalizePlain( + await sentMime.getPlain({ + populateAttachments: POPULATE_ATTACHMENTS, + hashAttachment, + }) + ); + const receivedNormalizedPlain = PlainNormalizer.normalizePlain( + await receivedMime.getPlain({ + populateAttachments: POPULATE_ATTACHMENTS, + hashAttachment, + }) + ); + + // eslint-disable-next-line + // @ts-ignore + expect(receivedNormalizedPlain).toEqualWithDiff(sentNormalizedPlain); + } + ); +}; + +export const createPseudoplainTestsRunner = ( + testsPath: string, + vendor: string +) => ( + casesGroupName: string, + filteringOptions?: CasesFilteringOptions +) => (): void => { + const testCases = prepareTestCases( + testsPath, + casesGroupName, + filteringOptions + ); + + test.concurrent.each(testCases)( + "Case %s", + async (dirName, { sentMime, receivedMime }) => { + const { sentHtmlDocument, receivedHtmlDocument } = await getDOMDocuments( + sentMime, + receivedMime + ); + + HTMLNormalizer.normalizeVendorHtml(sentHtmlDocument, vendor); + HTMLNormalizer.normalizeVendorHtml(receivedHtmlDocument, vendor); + + const normalizedSentPseudoPlainText = HTMLNormalizer.extractPseudoPlainPart( + sentHtmlDocument + ); + + const normalizedReceivedPseudoPlainText = HTMLNormalizer.extractPseudoPlainPart( + receivedHtmlDocument + ); + + // eslint-disable-next-line + // @ts-ignore + expect(normalizedReceivedPseudoPlainText).toEqualWithDiff( + normalizedSentPseudoPlainText + ); + } + ); +}; + +const prepareTestCases = ( + path: string, + casesGroup: string, + filteringOptions: CasesFilteringOptions +): Array<[string, { sentMime: MIMEParser; receivedMime: MIMEParser }]> => { + const testsCasesPath = path + "/" + casesGroup; + const casesDirs = listDirectories(testsCasesPath); + const casesDirsFiltered = filterTestCases(casesDirs, filteringOptions); + + return casesDirsFiltered.map((caseDir) => { + const sentMimeString = readFile( + `${testsCasesPath}/${caseDir}/${SENT_EML_NAME}` + ); + const receivedMimeString = readFile( + `${testsCasesPath}/${caseDir}/${RECEIVED_EML_NAME}` + ); + + return [ + caseDir, + { + sentMime: new MIMEParser(sentMimeString), + receivedMime: new MIMEParser(receivedMimeString), + }, + ]; + }); +}; + +/** + * + * @param {Array<string>} casesNames + * @param {Object} options + * @param {Array<string>} options.ignore - ignores specific test cases + * @param {Array<string>} options.checkExclusively - focuses on specific test cases (disregards toIgnore) + */ +const filterTestCases = ( + casesNames: string[], + options: CasesFilteringOptions +): string[] => { + const ignore = options?.ignore; + const checkExclusively = options?.checkExclusively; + + if (checkExclusively?.length) { + return casesNames.filter((caseName) => checkExclusively.includes(caseName)); + } + + if (ignore?.length) { + return casesNames.filter((caseName) => !ignore.includes(caseName)); + } + + return casesNames; +}; + +export const getDOMDocuments = async ( + sentMime: MIMEParser, + receivedMime: MIMEParser +): Promise<{ + sentHtmlDocument: HTMLDocument; + receivedHtmlDocument: HTMLDocument; +}> => { + /** + * Usage of the @vereign/dom is a must, because of Google Add-on. + */ + const sentDOM = new DOM( + await sentMime.getHTML({ + populateAttachments: POPULATE_ATTACHMENTS, + hashAttachment, + }) + ); + const receivedDOM = new JSDOM( + await receivedMime.getHTML({ + populateAttachments: POPULATE_ATTACHMENTS, + hashAttachment, + }) + ); + + return { + sentHtmlDocument: sentDOM.window.document, + receivedHtmlDocument: receivedDOM.window.document, + }; +}; diff --git a/__tests__/html-gmail-gmail.test.ts b/__tests__/html-gmail-gmail.test.ts index bb4fa7a3e58a07ee640965e9f0c6a3799d6f4690..6f2b681210cd85d30eafabdcf00880b622e7d9ca 100644 --- a/__tests__/html-gmail-gmail.test.ts +++ b/__tests__/html-gmail-gmail.test.ts @@ -2,16 +2,13 @@ import { EMAIL_VENDORS } from "../src"; const path = require("path"); import { describe } from "@jest/globals"; -import { createDescribeHtmlTestCases } from "./utils"; +import { createHtmlTestsRunner } from "./helpers"; const TESTS_GLOBAL_PATH = "/files/gmail-gmail"; const testsPath = path.resolve(__dirname, `.${TESTS_GLOBAL_PATH}`); describe("[HTML] GMail-GMail", () => { - const describeFunction = createDescribeHtmlTestCases( - testsPath, - EMAIL_VENDORS.GMAIL - ); + const runTests = createHtmlTestsRunner(testsPath, EMAIL_VENDORS.GMAIL); - describe("Chrome-Chrome", describeFunction("chrome-chrome", [""])); + describe("Chrome-Chrome", runTests("chrome-chrome", {})); }); diff --git a/__tests__/html-gmail-outlook.test.ts b/__tests__/html-gmail-outlook.test.ts index 0f214527ac0011f1f9b422a5368dad452c407dff..8c03d5c54223617080c365fe5a7c89b94a7d8622 100644 --- a/__tests__/html-gmail-outlook.test.ts +++ b/__tests__/html-gmail-outlook.test.ts @@ -2,16 +2,13 @@ import { EMAIL_VENDORS } from "../src"; const path = require("path"); import { describe } from "@jest/globals"; -import { createDescribeHtmlTestCases } from "./utils"; +import { createHtmlTestsRunner } from "./helpers"; const TESTS_GLOBAL_PATH = "/files/gmail-outlook"; const testsPath = path.resolve(__dirname, `.${TESTS_GLOBAL_PATH}`); describe("[HTML] GMail-Outlook", () => { - const describeFunction = createDescribeHtmlTestCases( - testsPath, - EMAIL_VENDORS.GMAIL - ); + const runTests = createHtmlTestsRunner(testsPath, EMAIL_VENDORS.GMAIL); - describe("Chrome-Chrome", describeFunction("chrome-chrome", [""])); + describe("Chrome-Chrome", runTests("chrome-chrome")); }); diff --git a/__tests__/html-outlook-gmail.test.ts b/__tests__/html-outlook-gmail.test.ts index c0e8ad88283b0d459321ec0c67fd1e4a39d6f048..932517cc2602a73611ca6166f1c2aee96a05fdfe 100644 --- a/__tests__/html-outlook-gmail.test.ts +++ b/__tests__/html-outlook-gmail.test.ts @@ -1,16 +1,12 @@ import { describe } from "@jest/globals"; import { EMAIL_VENDORS } from "../src"; -import { createDescribeHtmlTestCases } from "./utils"; +import { createHtmlTestsRunner } from "./helpers"; const path = require("path"); -const TESTS_GLOBAL_PATH = "/files/outlook-gmail"; -const testsPath = path.resolve(__dirname, `.${TESTS_GLOBAL_PATH}`); +const testsPath = path.resolve(__dirname, `./files/outlook-gmail`); describe("[HTML] Outlook-GMail emails normalization", () => { - const describeFunction = createDescribeHtmlTestCases( - testsPath, - EMAIL_VENDORS.OUTLOOK - ); + const runTests = createHtmlTestsRunner(testsPath, EMAIL_VENDORS.OUTLOOK); - describe("Chrome-Chrome", describeFunction("chrome-chrome", [])); + describe("Chrome-Chrome", runTests("chrome-chrome")); }); diff --git a/__tests__/html-outlook-outlook.test.ts b/__tests__/html-outlook-outlook.test.ts index 684848daa2439887e34b77253611cda61f16b632..90f32830367ee1a9e05cbbb773d25b9914f5263b 100644 --- a/__tests__/html-outlook-outlook.test.ts +++ b/__tests__/html-outlook-outlook.test.ts @@ -1,24 +1,21 @@ import { describe } from "@jest/globals"; import { EMAIL_VENDORS } from "../src"; -import { createDescribeHtmlTestCases } from "./utils"; +import { createHtmlTestsRunner } from "./helpers"; const path = require("path"); const TESTS_GLOBAL_PATH = "/files/outlook-outlook"; const testsPath = path.resolve(__dirname, `.${TESTS_GLOBAL_PATH}`); describe("[HTML] Outlook-Outlook emails normalization", () => { - const describeFunction = createDescribeHtmlTestCases( - testsPath, - EMAIL_VENDORS.OUTLOOK - ); + const runTests = createHtmlTestsRunner(testsPath, EMAIL_VENDORS.OUTLOOK); - describe("Chrome-Chrome", describeFunction("chrome-chrome", [], [])); + describe("Chrome-Chrome", runTests("chrome-chrome")); describe( "MacOS-MacOS", - describeFunction("macos-macos", ["03", "04", "05", "08", "09"]) + runTests("macos-macos", { ignore: ["03", "04", "05", "08", "09"] }) ); describe( "Windows-Windows", - describeFunction("windows-windows", ["11", "12", "13", "16"]) + runTests("windows-windows", { ignore: ["11", "12", "13", "16"] }) ); }); diff --git a/__tests__/htmltext-gmail-gmail.test.ts b/__tests__/htmltext-gmail-gmail.test.ts index a23c2de1c1eed2c585f0b6dff6c47df53c75cb8a..e2a1fca7c35f7520802f334b5a02231e60396cb1 100644 --- a/__tests__/htmltext-gmail-gmail.test.ts +++ b/__tests__/htmltext-gmail-gmail.test.ts @@ -2,16 +2,13 @@ import { EMAIL_VENDORS } from "../src"; const path = require("path"); import { describe } from "@jest/globals"; -import { createDescribePseudoPlainTestCases } from "./utils"; +import { createPseudoplainTestsRunner } from "./helpers"; const TESTS_GLOBAL_PATH = "/files/gmail-gmail"; const testsPath = path.resolve(__dirname, `.${TESTS_GLOBAL_PATH}`); describe("[Pseudo PLAIN] GMail-GMail", () => { - const describeFunction = createDescribePseudoPlainTestCases( - testsPath, - EMAIL_VENDORS.GMAIL - ); + const runTests = createPseudoplainTestsRunner(testsPath, EMAIL_VENDORS.GMAIL); - describe("Gmail-Gmail", describeFunction("chrome-chrome")); + describe("Gmail-Gmail", runTests("chrome-chrome")); }); diff --git a/__tests__/htmltext-gmail-outlook.test.ts b/__tests__/htmltext-gmail-outlook.test.ts index 47bc081233251df2045ced8a3927b207609adb92..bd50043f2ca34e0951df3f8edcb6ee72310ae960 100644 --- a/__tests__/htmltext-gmail-outlook.test.ts +++ b/__tests__/htmltext-gmail-outlook.test.ts @@ -1,5 +1,5 @@ import { describe } from "@jest/globals"; -import { createDescribePseudoPlainTestCases } from "./utils"; +import { createPseudoplainTestsRunner } from "./helpers"; import { EMAIL_VENDORS } from "../src"; const path = require("path"); @@ -8,9 +8,6 @@ const TESTS_GLOBAL_PATH = "/files/gmail-outlook"; const testsPath = path.resolve(__dirname, `.${TESTS_GLOBAL_PATH}`); describe("[Pseudo PLAIN] Gmail-Outlook normalization", () => { - const describeFunction = createDescribePseudoPlainTestCases( - testsPath, - EMAIL_VENDORS.GMAIL - ); - describe("Chrome-Chrome", describeFunction("chrome-chrome")); + const runTests = createPseudoplainTestsRunner(testsPath, EMAIL_VENDORS.GMAIL); + describe("Chrome-Chrome", runTests("chrome-chrome")); }); diff --git a/__tests__/htmltext-outlook-gmail.test.ts b/__tests__/htmltext-outlook-gmail.test.ts index 08384831c2eaa9571988e89db1464f8e450aa73a..b32f7e3a7f3a39d386124be1f25054f7b8f03f9b 100644 --- a/__tests__/htmltext-outlook-gmail.test.ts +++ b/__tests__/htmltext-outlook-gmail.test.ts @@ -1,5 +1,5 @@ import { describe } from "@jest/globals"; -import { createDescribePseudoPlainTestCases } from "./utils"; +import { createPseudoplainTestsRunner } from "./helpers"; import { EMAIL_VENDORS } from "../src"; const path = require("path"); @@ -8,11 +8,11 @@ const TESTS_GLOBAL_PATH = "/files/outlook-gmail"; const testsPath = path.resolve(__dirname, `.${TESTS_GLOBAL_PATH}`); describe("[Pseudo PLAIN] Outlook-Gmail normalization", () => { - const describeFunction = createDescribePseudoPlainTestCases( + const runTests = createPseudoplainTestsRunner( testsPath, EMAIL_VENDORS.OUTLOOK ); // ["01"] - is a filter. Pass here names of directories with test cases you want to check - describe("Chrome-Chrome", describeFunction("chrome-chrome")); + describe("Chrome-Chrome", runTests("chrome-chrome")); }); diff --git a/__tests__/htmltext-outlook-outlook.test.ts b/__tests__/htmltext-outlook-outlook.test.ts index 0e2a9ad002316a7451cb1e5e5dd3187e3c0023ba..c6e69b00fb3b19e76276febadf641c271f53cc26 100644 --- a/__tests__/htmltext-outlook-outlook.test.ts +++ b/__tests__/htmltext-outlook-outlook.test.ts @@ -1,5 +1,5 @@ import { describe } from "@jest/globals"; -import { createDescribePseudoPlainTestCases } from "./utils"; +import { createPseudoplainTestsRunner } from "./helpers"; import { EMAIL_VENDORS } from "../src"; const path = require("path"); @@ -8,18 +8,18 @@ const TESTS_GLOBAL_PATH = "/files/outlook-outlook"; const testsPath = path.resolve(__dirname, `.${TESTS_GLOBAL_PATH}`); describe("[Pseudo PLAIN] Outlook-Outlook normalization", () => { - const describeFunction = createDescribePseudoPlainTestCases( + const runTests = createPseudoplainTestsRunner( testsPath, EMAIL_VENDORS.OUTLOOK ); - describe("Chrome-Chrome", describeFunction("chrome-chrome")); + describe("Chrome-Chrome", runTests("chrome-chrome")); describe( "MacOS-MacOS", - describeFunction("macos-macos", ["03", "04", "05", "08", "09"]) + runTests("macos-macos", { ignore: ["03", "04", "05", "08", "09"] }) ); describe( "Windows-Windows", - describeFunction("windows-windows", ["11", "12", "16"]) + runTests("windows-windows", { ignore: ["11", "12", "16"] }) ); }); diff --git a/__tests__/plain-gmail-gmail.test.ts b/__tests__/plain-gmail-gmail.test.ts index 33b9954f25323ea55bff2114a8b2b44c9c48b309..9ee86ae841e7701775b6c1df445f95a34411ecb1 100644 --- a/__tests__/plain-gmail-gmail.test.ts +++ b/__tests__/plain-gmail-gmail.test.ts @@ -1,12 +1,12 @@ const path = require("path"); import { describe } from "@jest/globals"; -import { createDescribePlainTestCases } from "./utils"; +import { createPlainTestsRunner } from "./helpers"; const TESTS_GLOBAL_PATH = "/files/gmail-gmail"; const testsPath = path.resolve(__dirname, `.${TESTS_GLOBAL_PATH}`); describe("[Plain] GMail-GMail", () => { - const describeFunction = createDescribePlainTestCases(testsPath); + const runTests = createPlainTestsRunner(testsPath); - describe("Chrome-Chrome", describeFunction("chrome-chrome", [])); + describe("Chrome-Chrome", runTests("chrome-chrome")); }); diff --git a/__tests__/plain-gmail-outlook.test.ts b/__tests__/plain-gmail-outlook.test.ts index d15505aafc861bc0a380af8b1e99c941507abcee..f1ae5d9281c7e61d926cc177fa519b5f364bd47d 100644 --- a/__tests__/plain-gmail-outlook.test.ts +++ b/__tests__/plain-gmail-outlook.test.ts @@ -1,5 +1,5 @@ import { describe } from "@jest/globals"; -import { createDescribePlainTestCases } from "./utils"; +import { createPlainTestsRunner } from "./helpers"; const path = require("path"); const TESTS_GLOBAL_PATH = "/files/gmail-outlook"; @@ -7,6 +7,6 @@ const TESTS_GLOBAL_PATH = "/files/gmail-outlook"; const testsPath = path.resolve(__dirname, `.${TESTS_GLOBAL_PATH}`); describe("[Plain] Gmail-Outlook normalization", () => { - const describeFunction = createDescribePlainTestCases(testsPath); - describe("Chrome-Chrome", describeFunction("chrome-chrome", [], [])); + const runTests = createPlainTestsRunner(testsPath); + describe("Chrome-Chrome", runTests("chrome-chrome")); }); diff --git a/__tests__/plain-outlook-gmail.test.ts b/__tests__/plain-outlook-gmail.test.ts index f74daacf5c16a94c018e0e2f7c751addbecf185d..44cfed3499d113892d17249f9b2951043a1df4b6 100644 --- a/__tests__/plain-outlook-gmail.test.ts +++ b/__tests__/plain-outlook-gmail.test.ts @@ -1,5 +1,5 @@ import { describe } from "@jest/globals"; -import { createDescribePlainTestCases } from "./utils"; +import { createPlainTestsRunner } from "./helpers"; const path = require("path"); const TESTS_GLOBAL_PATH = "/files/outlook-gmail"; @@ -7,6 +7,6 @@ const TESTS_GLOBAL_PATH = "/files/outlook-gmail"; const testsPath = path.resolve(__dirname, `.${TESTS_GLOBAL_PATH}`); describe("[Plain] Outlook-Gmail normalization", () => { - const describeFunction = createDescribePlainTestCases(testsPath); - describe("Chrome-Chrome", describeFunction("chrome-chrome")); + const runTests = createPlainTestsRunner(testsPath); + describe("Chrome-Chrome", runTests("chrome-chrome")); }); diff --git a/__tests__/plain-outlook-outlook.test.ts b/__tests__/plain-outlook-outlook.test.ts index 335a692e80ef15688f444b37deea6837ecbb54ae..f64cde40f55302d6477322c3009cc9aeb6ce456d 100644 --- a/__tests__/plain-outlook-outlook.test.ts +++ b/__tests__/plain-outlook-outlook.test.ts @@ -1,5 +1,5 @@ import { describe } from "@jest/globals"; -import { createDescribePlainTestCases } from "./utils"; +import { createPlainTestsRunner } from "./helpers"; const path = require("path"); const TESTS_GLOBAL_PATH = "/files/outlook-outlook"; @@ -7,20 +7,13 @@ const TESTS_GLOBAL_PATH = "/files/outlook-outlook"; const testsPath = path.resolve(__dirname, `.${TESTS_GLOBAL_PATH}`); describe("[Plain] Outlook-Outlook normalization", () => { - const describeFunction = createDescribePlainTestCases(testsPath); - describe("Chrome-Chrome", describeFunction("chrome-chrome")); - describe("MacOS-MacOS", describeFunction("macos-macos")); + const runTests = createPlainTestsRunner(testsPath); + describe("Chrome-Chrome", runTests("chrome-chrome")); + describe("MacOS-MacOS", runTests("macos-macos")); describe( "Windows-Windows", - describeFunction("windows-windows", [ - "09", - "10", - "11", - "12", - "13", - "14", - "15", - "16", - ]) + runTests("windows-windows", { + ignore: ["09", "10", "11", "12", "13", "14", "15", "16"], + }) ); }); diff --git a/__tests__/utils.ts b/__tests__/utils.ts deleted file mode 100644 index 520cfa9397351d8ab51ce0ce32cfd9b2fd8eb32c..0000000000000000000000000000000000000000 --- a/__tests__/utils.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { JSDOM } from "jsdom"; -const fs = require("fs"); -import MIMEParser from "@vereign/mime-parser"; -import { expect, test } from "@jest/globals"; -import { DOM } from "@vereign/dom"; -import { diffStringsUnified } from "jest-diff"; - -import { PlainNormalizer, HTMLNormalizer } from "../src"; - -const SENT_EML_NAME = "sent.eml"; -const RECEIVED_EML_NAME = "received.eml"; - -expect.extend({ - toEqualWithDiff(target, source) { - let pass = true; - try { - expect(target).toEqual(source); - } catch (e) { - pass = false; - } - - return { - pass, - message: pass ? () => "Pass" : () => diffStringsUnified(source, target), - }; - }, -}); - -const mimeCache: { [key: string]: MIMEParser } = {}; -const getMime = (path: string): MIMEParser => { - if (!mimeCache[path]) { - const mimeString = fs.readFileSync(path).toString(); - mimeCache[path] = new MIMEParser(mimeString); - } - - return mimeCache[path]; -}; - -export const getNormalizedPlain = ( - testCasePath: string -): { - sentPlain: string; - receivedPlain: string; -} => { - const sentMime = getMime(`${testCasePath}/${SENT_EML_NAME}`); - const receivedMime = getMime(`${testCasePath}/${RECEIVED_EML_NAME}`); - - const sentNormalizedPlain = PlainNormalizer.normalizePlain( - sentMime.getPlain(true) - ); - const receivedNormalizedPlain = PlainNormalizer.normalizePlain( - receivedMime.getPlain(true) - ); - - return { - sentPlain: sentNormalizedPlain, - receivedPlain: receivedNormalizedPlain, - }; -}; - -export const getTestCasesDirs = (testCasesPath: string): Array<string> => { - return fs.readdirSync(testCasesPath).filter(function (file) { - return fs.statSync(testCasesPath + "/" + file).isDirectory(); - }); -}; - -export const getNormalizedHtml = ( - testCasePath: string, - vendor: string -): { - sentHtml: string; - receivedHtml: string; -} => { - const sentMime = getMime(`${testCasePath}/${SENT_EML_NAME}`); - const receivedMime = getMime(`${testCasePath}/${RECEIVED_EML_NAME}`); - - const sentHtml = sentMime.getHTML(true); - const receivedHtml = receivedMime.getHTML(true); - - const sentDOM = new DOM(sentHtml); - const receivedDOM = new JSDOM(receivedHtml); - - const sentNormalizedHtml = HTMLNormalizer.normalizeVendorHtml( - sentDOM.window.document, - vendor - ); - const receivedNormalizedHtml = HTMLNormalizer.normalizeVendorHtml( - receivedDOM.window.document, - vendor - ); - - return { - sentHtml: sentNormalizedHtml, - receivedHtml: receivedNormalizedHtml, - }; -}; - -export const createDescribeHtmlTestCases = ( - testsPath: string, - vendor: string -) => - /** - * @param casesGroupName - name of the folder with cases - * @param failingCases - a list of cases that are failing and ignored. Pending to be fixed - * @param casesToCheckOnly - a filter to use if you want to check specific cases - */ - ( - casesGroupName: string, - failingCases?: Array<string>, - casesToCheckOnly?: Array<string> - ) => (): void => { - const testsCasesPath = testsPath + "/" + casesGroupName; - let testCasesDirs = getTestCasesDirs(testsCasesPath); - - if (casesToCheckOnly && casesToCheckOnly.length) { - testCasesDirs = testCasesDirs.filter((dir) => - casesToCheckOnly.includes(dir) - ); - } - - if (failingCases && failingCases.length) { - testCasesDirs = testCasesDirs.filter( - (dir) => !failingCases.includes(dir) - ); - } - - test.each(testCasesDirs)("Case %s", (dirName: string) => { - const testCasePath = testsCasesPath + "/" + dirName; - const normalizedHtmls = getNormalizedHtml(testCasePath, vendor); - const { sentHtml, receivedHtml } = normalizedHtmls; - - // expect(receivedHtml.length).toBeGreaterThan(0); - // expect(sentHtml.length).toBeGreaterThan(0); - - // eslint-disable-next-line - // @ts-ignore - // console.log(receivedHtml); - expect(receivedHtml).toEqualWithDiff(sentHtml); - }); - }; - -export const createDescribePlainTestCases = (testsPath: string) => ( - casesName: string, - failingCases: Array<string> = [], - casesToCheckOnly?: Array<string> -) => (): void => { - const testsCasesPath = testsPath + "/" + casesName; - let testCasesDirs = getTestCasesDirs(testsCasesPath); - - if (casesToCheckOnly && casesToCheckOnly.length) { - testCasesDirs = testCasesDirs.filter((dir) => - casesToCheckOnly.includes(dir) - ); - } - - if (failingCases && failingCases.length) { - testCasesDirs = testCasesDirs.filter((dir) => !failingCases.includes(dir)); - } - - test.each(testCasesDirs)("Case %s", (dirName: string) => { - const testCasePath = testsCasesPath + "/" + dirName; - const normalizedPlain = getNormalizedPlain(testCasePath); - - const { sentPlain, receivedPlain } = normalizedPlain; - // expect(sentPlain.length).toBeGreaterThan(0); - // expect(receivedPlain.length).toBeGreaterThan(0); - // eslint-disable-next-line - // @ts-ignore - expect(receivedPlain).toEqualWithDiff(sentPlain); - }); -}; - -export const createDescribePseudoPlainTestCases = ( - testsPath: string, - vendor: string -) => - /** - * @param casesGroupName - name of the folder with cases - * @param failingCases - a list of cases that are failing and ignored. Pending to be fixed - * @param casesToCheckOnly - a filter to use if you want to check specific cases - */ - ( - casesGroupName: string, - failingCases?: Array<string>, - casesToCheckOnly?: Array<string> - ) => (): void => { - const testsCasesPath = testsPath + "/" + casesGroupName; - let testCasesDirs = getTestCasesDirs(testsCasesPath); - - if (casesToCheckOnly && casesToCheckOnly.length) { - testCasesDirs = testCasesDirs.filter((dir) => - casesToCheckOnly.includes(dir) - ); - } - - if (failingCases && failingCases.length) { - testCasesDirs = testCasesDirs.filter( - (dir) => !failingCases.includes(dir) - ); - } - - test.each(testCasesDirs)("Case %s", (dirName: string) => { - const testCasePath = testsCasesPath + "/" + dirName; - const { sentHtmlDocument, receivedHtmlDocument } = getDOMDocuments( - testCasePath - ); - - HTMLNormalizer.normalizeVendorHtml(sentHtmlDocument, vendor); - HTMLNormalizer.normalizeVendorHtml(receivedHtmlDocument, vendor); - - const normalizedSentPseudoPlainText = HTMLNormalizer.extractPseudoPlainPart( - sentHtmlDocument - ); - - const normalizedReceivedPseudoPlainText = HTMLNormalizer.extractPseudoPlainPart( - receivedHtmlDocument - ); - - // eslint-disable-next-line - // @ts-ignore - expect(normalizedReceivedPseudoPlainText).toEqualWithDiff( - normalizedSentPseudoPlainText - ); - }); - }; - -export const getDOMDocuments = ( - testCasePath: string -): { - sentHtmlDocument: HTMLDocument; - receivedHtmlDocument: HTMLDocument; -} => { - const sentMime = getMime(`${testCasePath}/${SENT_EML_NAME}`); - const receivedMime = getMime(`${testCasePath}/${RECEIVED_EML_NAME}`); - - const sentDOM = new DOM(sentMime.getHTML(true)); - const receivedDOM = new JSDOM(receivedMime.getHTML(true)); - - return { - sentHtmlDocument: sentDOM.window.document, - receivedHtmlDocument: receivedDOM.window.document, - }; -}; diff --git a/jest.config.js b/jest.config.js index 216e02ed6b0bfb29264c3d559ea89249c600c2df..66ae80cdd4bba7aaec809bee515613485768a34c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -82,7 +82,7 @@ module.exports = { // moduleNameMapper: {}, // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - modulePathIgnorePatterns: ["__tests__/utils.ts"], + // modulePathIgnorePatterns: ["__tests__/utils.ts"], // Activates notifications for test results // notify: false, @@ -144,10 +144,10 @@ module.exports = { // testLocationInResults: false, // The glob patterns Jest uses to detect test files - // testMatch: [ - // "**/__tests__/**/*.[jt]s?(x)", - // "**/?(*.)+(spec|test).[tj]s?(x)" - // ], + testMatch: [ + // "**/__tests__/**/*.[jt]s?(x)", + "**/?(*.)+(spec|test).[tj]s?(x)", + ], // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped testPathIgnorePatterns: ["/node_modules/", "setupFiles.js"], diff --git a/yarn.lock b/yarn.lock index f785607ec98f7286cf4cdfeb6d38e1ffc084d9f4..a048b4662f3b845add43ce9ad98263d1b6cdc1df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1264,7 +1264,7 @@ "@vereign/mime-parser@git+ssh://git@code.vereign.com:code/js-toolbox/mime-parser.git": version "1.0.0" - resolved "git+ssh://git@code.vereign.com:code/js-toolbox/mime-parser.git#07fa6f0d595416f12baa601b9258acedf91c97c7" + resolved "git+ssh://git@code.vereign.com:code/js-toolbox/mime-parser.git#4b509038b448d0ce2f4e679beb5535e62ed7d6ad" dependencies: libmime "^5.0.0" libqp "^1.1.0"