
This is a public-UI test memo, not a claim about source code or internal architecture. Image conversion is a simple-looking interaction with several states worth making explicit: select files, choose quality, convert, and retrieve outputs.
State the visible contract
The public heictojpg.ai page accepts HEIC and HEIF inputs, displays a file list, offers a JPEG quality control, and advertises a maximum of 20 images. Those observations define product behavior; they do not reveal how decoding or storage is implemented.
type Job = {
files: Array<{ name: string; kind: "heic" | "heif" }>;
quality: number;
phase: "empty" | "selected" | "converting" | "complete" | "error";
};
Treat this type as a design proposal. A real implementation may use a different model.
Test transitions, not just the happy path
Treat quality as a product decision
The HEIC to JPG Converter displays JPEG quality at 70% by default. QA should not assert that this is visually correct for every photograph. Instead, use a high-detail photo, a low-light photo, and a document-like image; inspect the results at their delivery size; and record the quality selected for the job.
Model failure recovery
Include malformed inputs, a file with a misleading extension, a batch over the visible limit, and an interrupted download. The key invariant is recoverability: a rejected addition should explain the next action, while a recoverable failure should not silently discard the already selected list.
Check the output boundary
Verify that each downloaded file opens as JPEG, has a sensible name, and can be attached to the target service. Keep this separate from a claim that conversion preserves all HEIC features: JPG is lossy and downstream systems may have their own dimension, metadata, or size rules.
A converter UI is dependable when its state changes are understandable and reversible. That is a better acceptance target than guessing its hidden technical stack.
Separate conversion success from delivery success
An interface can report a completed job while the result still fails at the next boundary. Add a test that opens a downloaded output with an independent viewer and another that attaches it to the real target system or a representative fixture. This catches mismatches in extension, MIME handling, orientation, dimensions, and size policy without requiring knowledge of the converter's private implementation.
type AcceptanceEvidence = {
opensAsJpeg: boolean;
orientationReviewed: boolean;
targetAccepted: boolean;
originalRetained: boolean;
};
Again, this is an illustrative test record, not a prescribed data model. Its value is making the final handoff observable.
Accessibility belongs in the state model
File lists and progress labels should not depend on color alone. A keyboard user needs a predictable path to add files, change quality, begin conversion, and find download controls. A screen-reader user needs text that distinguishes “selected,” “converting,” “complete,” and “failed.” When a limit blocks the twenty-first file, the explanation should be associated with the action that caused it.
For visual review, do not let a progress spinner substitute for a status message. The page can remain compact while still saying which file failed and whether the remaining files can be downloaded.
Define observability without inventing metrics
Do not promise a speed number just because a flow looks quick in a single browser. Instead, capture categories of failure: unsupported input, decoder error, export error, interrupted download, and target rejection. This classification lets a product team identify the part of the handoff that needs work without claiming benchmark data it has not measured.
A release checklist
A user can remove or replace a selected file before conversion.
The current quality value is visible and survives a harmless UI change.
A batch reports individual outcomes rather than one ambiguous final message.
A successful output opens independently as a JPG.
Failed work offers recovery without hiding the original input.
The test plan remains useful even when the decoding library, processing location, or interface framework changes. It is based on what a user needs to accomplish, which is the stable part of the contract.
Keep test fixtures ethical and reproducible
Use synthetic or approved images for automated checks, particularly when examples include names, addresses, or document text. Store fixtures with a short description of what they are meant to reveal: orientation handling, fine-detail preservation, unsupported input, or a visible count-limit message. Reproducible fixtures turn a vague report such as “one iPhone photo failed” into a test a team can run again.
This also preserves the boundary of black-box analysis. The public interface gives enough evidence to test user outcomes; it does not authorize assumptions about private processing or data handling.
Top comments (0)