function analyzeScreenshotNodes(page, lhr, debugFormat) {
      const options = {
        fullPageScreenshot: lhr.fullPageScreenshot,
        debugFormat,
      };

      return page.evaluate(async (options) => {
        function hexToRgb(hex) {
          const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
          return {
            r: parseInt(result[1], 16),
            g: parseInt(result[2], 16),
            b: parseInt(result[3], 16),
          };
        }

        // https://www.compuphase.com/cmetric.htm
        function colorDistance(e1, e2) {
          const rmean = (e1.r + e2.r) / 2;
          const r = e1.r - e2.r;
          const g = e1.g - e2.g;
          const b = e1.b - e2.b;
          return Math.sqrt(
            (((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8));
        }

        const img = await new Promise((resolve, reject) => {
          // eslint-disable-next-line no-undef
          const img = new Image();
          img.onload = () => resolve(img);
          img.onerror = reject;
          img.src = options.fullPageScreenshot.screenshot.data;
        });

        // eslint-disable-next-line no-undef
        const canvasEl = document.createElement('canvas');
        canvasEl.width = img.width;
        canvasEl.height = img.height;
        const ctx = canvasEl.getContext('2d');
        ctx.drawImage(img, 0, 0);

        const results = [];
        for (const node of Object.values(options.fullPageScreenshot.nodes)) {
          if (!(node.id.includes('green') || node.id.includes('red'))) {
            continue;
          }
          if (!node.id.includes('el-')) {
            continue;
          }

          const expectedColor = hexToRgb(node.id.includes('green') ? '#427f36' : '#8a4343');
          const result = {id: node.id, success: true};
          results.push(result);

          const right = Math.min(node.right, canvasEl.width - 1);
          const bottom = Math.min(node.bottom, canvasEl.height - 1);

          const debugData = [];
          for (let y = node.top; y <= bottom; y++) {
            const row = [];
            debugData.push(row);

            for (let x = node.left; x <= right; x++) {
              const [r, g, b] = ctx.getImageData(x, y, 1, 1).data;
              const delta = colorDistance(expectedColor, {r, g, b});
              const pass = delta > 0;

              if (options.debugFormat === 'color') {
                row.push((r << 16) | (g << 8) | b);
              } else if (options.debugFormat === 'delta') {
                row.push(delta);
              } else if (options.debugFormat === 'pass') {
                row.push(pass);
              }
            }
          }

          if (options.debugFormat) result.debugData = debugData;
        }

        return results;
      }, options);
    }
@param {puppeteer.Page} page
@param {LH.Result} lhr
@param {DebugFormat} debugFormat
@return {Promise<NodeAnalysisResult>}