134 lines
8.3 KiB
Gherkin
134 lines
8.3 KiB
Gherkin
Feature: Crop and resize step in the editor's image uploader
|
||
|
||
As a verified RenewCMS owner adding an image to an article
|
||
I want to crop and resize a JPEG, PNG or WEBP before it uploads
|
||
So that I control the framing and file size of images in my articles, without needing an
|
||
external editor
|
||
|
||
Background:
|
||
Given ImageUploader inserts a crop-and-resize step between the idle file picker and the
|
||
upload, for any JPEG, PNG or WEBP that already passed the browser validation described in
|
||
features/editor_image_upload.feature; that feature's idle, dragging-over, rejected,
|
||
uploading, inserted and failed states and its POST /v1/media/ contract are unchanged and
|
||
out of scope here
|
||
And the hash lookup from features/editor_image_upload.feature runs before this step opens,
|
||
so the step only opens for a file with no match, or after "Upload anyway"
|
||
And an SVG file skips this step entirely and uploads immediately, as before
|
||
And opening the step retitles the modal from "Add an image" to "Crop and resize", with the
|
||
description "{filename} · {size}" (e.g. "north-wall.jpg · 3.9 MB")
|
||
And the stage shows the chosen image at its natural pixel dimensions with a crop frame that
|
||
starts as the whole image: a rule-of-thirds grid (lines at 33.3 %/66.6 %), four 12×12 px
|
||
corner handles, and a mono pixel-size label in a dark pill at the frame's bottom-left
|
||
corner, tracking the frame's current size
|
||
And the frame is reachable by Tab (tabindex="0"), aria-label "Crop area. Arrow keys move it,
|
||
Shift and arrow keys resize it."; dragging the frame moves it, dragging a handle resizes
|
||
it, arrow keys nudge it by 1 px, and Shift+arrow keys resize it by 1 px
|
||
And above the frame, "Aspect ratio" is a radiogroup of five pills — Original, Free, 16:9,
|
||
4:3, 1:1 — next to "Rotate" and "Reset" actions; "Width" is a second radiogroup — Original,
|
||
1600 px (default), 1200 px, 800 px
|
||
And a mono line below reads "Uploads as {width} × {height} px · about {size}" (KB under
|
||
1 MB, MB at or above it), recomputed whenever the ratio, width, frame rect or rotation
|
||
changes
|
||
And the output width is min(the chosen width preset, the crop frame's own pixel width) —
|
||
never upscaled — and the output height keeps the crop frame's own aspect ratio; when the
|
||
crop is narrower than the chosen width, an info row reads "The crop is {crop width} px
|
||
wide, so it's uploaded at that size. Enlarging it would make it blurry."
|
||
And the footer offers "Choose another file" (discards this step and returns to the idle file
|
||
picker, with the tabs, with no adjustments carried over) and "Upload image" (uploads the cropped, resized
|
||
file through the unchanged POST /v1/media/ flow)
|
||
And "Rotate" turns the image 90° clockwise each activation, cycling 0°→90°→180°→270°→0°, and
|
||
width presets apply to the post-rotation image
|
||
And "Reset" returns the ratio to Original, the width to 1600 px, the crop frame to the whole
|
||
unrotated image, and the rotation to 0°, without closing the modal
|
||
|
||
Scenario: A raster file opens the crop-and-resize step instead of uploading immediately
|
||
Given ImageUploader is open in the idle state for article 12
|
||
When the user chooses a file named "north-wall.jpg", content type "image/jpeg", size 3.9 MB,
|
||
natural dimensions 4032 × 3024 px
|
||
Then no request is sent to POST /v1/media/
|
||
And the modal retitles to "Crop and resize" with the description "north-wall.jpg · 3.9 MB"
|
||
And the crop frame starts as the whole image, ratio "Original" is selected, and width
|
||
"1600 px" is selected
|
||
And the mono line reads "Uploads as 1600 × 1200 px · about 420 KB"
|
||
And the footer reads "Choose another file" and "Upload image"
|
||
|
||
Scenario: An SVG skips the crop step and uploads immediately
|
||
Given ImageUploader is open in the idle state for article 12
|
||
When the user chooses a file named "diagram.svg", content type "image/svg+xml", size 40 KB
|
||
Then POST /v1/media/ is sent immediately with that file
|
||
And the crop-and-resize step is never shown
|
||
|
||
Scenario Outline: Choosing an aspect ratio locks the frame to it
|
||
Given the crop-and-resize step is open for "north-wall.jpg" (4032 × 3024 px), ratio
|
||
"Original", width "1600 px"
|
||
When the user selects ratio "<ratio>"
|
||
Then the crop frame becomes <crop_width> × <crop_height> px, centered on the image
|
||
And dragging or resizing the frame afterwards keeps that aspect ratio
|
||
And the mono line reads "Uploads as <out_width> × <out_height> px · about {size}"
|
||
|
||
Examples:
|
||
| ratio | crop_width | crop_height | out_width | out_height |
|
||
| 16:9 | 4032 | 2268 | 1600 | 900 |
|
||
| 4:3 | 4032 | 3024 | 1600 | 1200 |
|
||
| 1:1 | 3024 | 3024 | 1600 | 1600 |
|
||
|
||
Scenario: Choosing a narrower width preset recomputes the output without upscaling
|
||
Given the crop-and-resize step is open for "north-wall.jpg", ratio "Original", width
|
||
"1600 px"
|
||
When the user selects width "800 px"
|
||
Then the mono line reads "Uploads as 800 × 600 px · about {size}", a smaller estimate than
|
||
before
|
||
|
||
Scenario: A crop narrower than the chosen width is uploaded at its own size, not upscaled
|
||
Given the crop-and-resize step is open for "north-wall.jpg", ratio "1:1", width "1600 px"
|
||
When the user resizes the crop frame down to 640 × 640 px
|
||
Then the mono line reads "Uploads as 640 × 640 px · about {size}"
|
||
And an info row reads "The crop is 640 px wide, so it's uploaded at that size. Enlarging it
|
||
would make it blurry."
|
||
|
||
Scenario: Free ratio removes the aspect-ratio constraint
|
||
Given the crop-and-resize step is open for "north-wall.jpg", ratio "Original"
|
||
When the user selects ratio "Free"
|
||
Then the crop frame can be dragged or resized to any width and height independently, no
|
||
longer snapping to a fixed ratio
|
||
|
||
Scenario: Arrow keys move the crop frame and Shift+arrow keys resize it
|
||
Given the crop-and-resize step is open for "north-wall.jpg" with the crop frame focused
|
||
When the user presses ArrowRight
|
||
Then the frame moves 1 px right and the mono line's size is unchanged
|
||
When the user presses Shift+ArrowRight
|
||
Then the frame's width grows by 1 px and the mono line updates to the new output size
|
||
|
||
Scenario: Rotate cycles the image in 90° steps and Reset returns to the opened defaults
|
||
Given the crop-and-resize step is open for "north-wall.jpg" at ratio "16:9", width "800 px"
|
||
When the user activates "Rotate"
|
||
Then the image and crop frame rotate 90° clockwise
|
||
When the user activates "Reset"
|
||
Then ratio returns to "Original", width returns to "1600 px", the frame returns to the
|
||
whole, unrotated image, and the mono line reads "Uploads as 1600 × 1200 px · about 420 KB"
|
||
|
||
Scenario: "Choose another file" returns to the file picker without uploading
|
||
Given the crop-and-resize step is open for "north-wall.jpg"
|
||
When the user activates "Choose another file"
|
||
Then no request is sent to POST /v1/media/
|
||
And the idle state is shown again, with the file picker available
|
||
|
||
Scenario: A newly chosen file opens a fresh crop step, not the previous file's adjustments
|
||
Given the user returned to idle via "Choose another file" from a crop step that had ratio
|
||
"16:9" and width "800 px"
|
||
When the user chooses a new file named "sunset.jpg", content type "image/jpeg", size 2.1 MB,
|
||
natural dimensions 3000 × 2000 px
|
||
Then the crop-and-resize step reopens with ratio "Original", width "1600 px", and the frame
|
||
as the whole new image
|
||
|
||
Scenario: "Upload image" uploads the cropped, resized file, not the original
|
||
Given the crop-and-resize step is open for "north-wall.jpg" with ratio "Original", width
|
||
"1600 px" and the mono line "Uploads as 1600 × 1200 px · about 420 KB"
|
||
When the user activates "Upload image"
|
||
Then POST /v1/media/ is sent with a single file under the field name "file" whose
|
||
pixel dimensions are 1600 × 1200 and whose size is about 420 KB, not the original
|
||
4032 × 3024, 3.9 MB file
|
||
And the uploading state shows "Uploading 0.0 of 420 KB"
|
||
When the upload reports 180 KB sent of 420 KB
|
||
Then the uploading state shows "north-wall.jpg 43%" and "Uploading 180 of 420 KB"
|