74 lines
4.2 KiB
Markdown
74 lines
4.2 KiB
Markdown
# QA procedure: upload_article_image
|
|
|
|
Package: `test` (black-box, extending `article_test.go` / `image_test.go`).
|
|
|
|
## Setup shared by every case
|
|
1. Call `validator.InitValidator()` once.
|
|
2. Reuse `mockArticleRepo` (`test/article_test.go`) and `mockImageRepo`
|
|
(`test/image_test.go`) as-is; both already implement `AddImage` /
|
|
`Create` returning `article.ErrArticleNotFound` / `image.ErrImageNotFound`
|
|
for an unknown id, per `features/write_not_found_errors.feature`.
|
|
3. Wire the real use cases over the fakes: `useCases.NewCreateArticleUseCase`,
|
|
`useCases.NewGetArticleUseCase`, `useCases.NewListArticlesUseCase`,
|
|
`useCases.NewUpdateArticleUseCase(articleRepo)`,
|
|
`useCases.NewDeleteArticleUseCase(articleRepo, imageRepo)`,
|
|
`useCases.NewCreateImageUseCase(imageRepo)`.
|
|
4. Build `article.NewHandler(...)` with its existing constructor shape, and
|
|
`image.NewHandler(createImageUseCase, updateArticleUseCase)`
|
|
(`api/handlers/image`).
|
|
5. Build a test `jwtauth.New("HS256", []byte("test-secret"), nil)`.
|
|
6. Mount the routes on a fresh `chi.NewRouter()` mirroring `api/router.go`'s
|
|
shape after this slice: `GET /` under `jwtauth.Verifier` only;
|
|
`GET /{id}`, `POST /`, `DELETE /{id}`, `PATCH /{id}`,
|
|
`PATCH /{id}/publish`, `PATCH /{id}/unpublish` and the new
|
|
`POST /{id}/image` (routed to `imageHandler.PostImage`) under
|
|
`jwtauth.Verifier` + `jwtauth.Authenticator`.
|
|
7. Mint a valid jwt cookie for user id 1:
|
|
`token.Encode(map[string]any{"user_id": uint32(1)})`, set as the `jwt`
|
|
cookie on the relevant `httptest.NewRequest`.
|
|
8. Build multipart request bodies with `mime/multipart.Writer`, field name
|
|
`"file"`, setting the part's `Content-Type` header explicitly (Go's
|
|
multipart writer defaults to sniffing otherwise, so set it via
|
|
`CreatePart` with an explicit MIME header rather than
|
|
`CreateFormFile`), and set the request's `Content-Type` header to the
|
|
writer's `FormDataContentType()`.
|
|
|
|
## HTTP checks
|
|
9. Seed `articleRepo.articles[1] = article.Article{ID: 1, Title: "Backyard
|
|
Renovation Update"}`. Send `POST /v1/article/1/image` with the valid
|
|
cookie and a multipart `"file"` part named `"before.png"`,
|
|
content type `"image/png"`, some non-empty byte content. Assert status
|
|
`201`; decode the JSON body and assert `location` equals
|
|
`"/static/uploadedImages/before.png"`; assert `imageRepo.images` gained
|
|
exactly one entry whose `Path` matches that location; assert
|
|
`articleRepo.articles[1].Images` now contains that image's id.
|
|
10. Empty `articleRepo`, empty `imageRepo`. Send `POST /v1/article/9999/image`
|
|
with the valid cookie and the same `"before.png"` / `"image/png"` part.
|
|
Assert status `404`, body `"Article not found\n"`; assert
|
|
`imageRepo.images` is still empty (the article's existence is confirmed
|
|
before any image is created, so nothing is left orphaned).
|
|
11. Seed `articleRepo.articles[1] = article.Article{ID: 1, Title: "Backyard
|
|
Renovation Update"}` with an empty `Images` slice. Send
|
|
`POST /v1/article/1/image` with the valid cookie and a multipart
|
|
`"file"` part named `"notes.pdf"`, content type `"application/pdf"`.
|
|
Assert status `400`, body
|
|
`"the file must be a PNG, JPEG, WEBP, or SVG image\n"`; assert
|
|
`imageRepo.images` is still empty; assert
|
|
`articleRepo.articles[1].Images` is still empty.
|
|
12. Seed the same article id 1 as step 11. Send `POST /v1/article/1/image`
|
|
with **no** cookie and the `"before.png"` / `"image/png"` part. Assert
|
|
status `401`; assert `imageRepo.images` is still empty; assert
|
|
`articleRepo.articles[1].Images` is still empty.
|
|
|
|
## Manual verification (not exercised by the Go test)
|
|
- Real upload against a real SQLite file and real `UPLOAD_DIR`: confirm that
|
|
after `POST /v1/article/{id}/image` on a real running instance, the file
|
|
actually lands on disk under `UPLOAD_DIR`, the `images` row's `path`
|
|
resolves to a URL the SPA can load, and the `article_images` join table
|
|
gets the new row. Not exercised by `task test` (fakes only); requires
|
|
`task dev` or a built `task build` binary with a scratch DB/upload dir.
|
|
- SPA-visible behaviour: confirm the back-office article editor (if/when an
|
|
image-upload UI exists) shows the uploaded image at that location. No such
|
|
UI exists yet as of this slice.
|
|
- No SMTP involvement.
|