Skip to content

[Bug][P1] Fix QR/image download actions and add real browser download regression coverage #323

Description

@baixiangcpp

User signal

A product walkthrough reported that generated images cannot be downloaded, with QR Code Generator called out as an example.

Original feedback: 生成的图片无法下载 比如二维码.

Current implementation to inspect

QR Code Generator renders to a canvas and stores canvas.toDataURL("image/png") in component state. The PNG action calls downloadDataUrl(dataUrl, "qr-code.png"). SVG uses buildQrSvg(...) and downloadSvg(...).

The browser helpers currently create a detached <a>, set href and download, then call a.click(). For SVG, the object URL is revoked immediately after click().

Relevant files:

  • src/features/tools/qr-code-generator/page.tsx
  • src/features/tools/qr-code-generator/browser-actions.ts

Suspected cause

Some browsers are stricter about programmatic downloads:

  • a detached anchor click can be ignored;
  • object URLs may be revoked too early before the download is consumed;
  • canvas.toDataURL can be less reliable than canvas.toBlob for large images or browser-specific download handling;
  • the UI currently shows success after calling the helper, even if the browser blocked or ignored the download.

Recommended implementation

  • Replace detached-anchor helpers with a robust downloadBlob / downloadUrl helper:
    • append the anchor to document.body;
    • set rel="noopener" where appropriate;
    • call click() inside the user-triggered action;
    • remove the anchor in finally;
    • defer URL.revokeObjectURL(url) with setTimeout or after download initiation.
  • Prefer canvas.toBlob for PNG export; fall back to data URL only when needed.
  • Return an explicit result from the download helper so the action does not announce false success.
  • Add browser-level Playwright coverage using page.waitForEvent("download") for QR PNG and SVG.
  • Audit other generated-image/download tools for the same pattern.

Reproduction matrix

  • /en/qr-code-generator
  • generate default QR;
  • download PNG;
  • download SVG;
  • repeat after changing size/color;
  • repeat with logo enabled;
  • test Chrome, Edge, Safari where possible.

Acceptance criteria

  • QR PNG download produces a non-empty .png file in Chromium/Chrome.
  • QR SVG download produces a non-empty .svg file in Chromium/Chrome.
  • The success toast is only shown after a download helper returns success.
  • Object URLs are not revoked synchronously before the browser can consume them.
  • Add focused unit tests for helper behavior and Playwright download smoke for QR export.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions