async function getDebugImage(lhr) {
  if (!lhr.fullPageScreenshot) {
    return '';
  }

  const browser = await puppeteer.launch({
    headless: true,
    executablePath: getChromePath(),
    ignoreDefaultArgs: ['--enable-automation'],
  });
  const page = await browser.newPage();

  const debugDataUrl = await page.evaluate(async (fullPageScreenshot) => {
    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 = 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');
    if (!ctx) return '';

    ctx.drawImage(img, 0, 0);
    for (const [lhId, node] of Object.entries(fullPageScreenshot.nodes)) {
      if (!node.width && !node.height) continue;

      ctx.strokeStyle = '#D3E156';
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.rect(node.left, node.top, node.width, node.height);
      ctx.stroke();

      const txt = node.id || lhId;
      const txtWidth = Math.min(ctx.measureText(txt).width, node.width);
      const txtHeight = 10;
      const txtTop = node.top - 3;
      const txtLeft = node.left;
      ctx.fillStyle = '#FFFFFF88';
      ctx.fillRect(txtLeft, txtTop, txtWidth, txtHeight);
      ctx.fillStyle = '#000000';
      ctx.lineWidth = 1;
      ctx.textBaseline = 'top';
      ctx.fillText(txt, txtLeft, txtTop);
    }

    return canvasEl.toDataURL();
  }, lhr.fullPageScreenshot);

  await browser.close();

  if (!debugDataUrl.startsWith('data:image/')) {
    throw new Error('invalid data url');
  }

  return debugDataUrl;
}
@param {LH.Result} lhr
@return {Promise<string>}