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"