4.2 KiB
4.2 KiB
QA procedure: upload_article_image
Package: test (black-box, extending article_test.go / image_test.go).
Setup shared by every case
- Call
validator.InitValidator()once. - Reuse
mockArticleRepo(test/article_test.go) andmockImageRepo(test/image_test.go) as-is; both already implementAddImage/Createreturningarticle.ErrArticleNotFound/image.ErrImageNotFoundfor an unknown id, perfeatures/write_not_found_errors.feature. - Wire the real use cases over the fakes:
useCases.NewCreateArticleUseCase,useCases.NewGetArticleUseCase,useCases.NewListArticlesUseCase,useCases.NewUpdateArticleUseCase(articleRepo),useCases.NewDeleteArticleUseCase(articleRepo, imageRepo),useCases.NewCreateImageUseCase(imageRepo). - Build
article.NewHandler(...)with its existing constructor shape, andimage.NewHandler(createImageUseCase, updateArticleUseCase)(api/handlers/image). - Build a test
jwtauth.New("HS256", []byte("test-secret"), nil). - Mount the routes on a fresh
chi.NewRouter()mirroringapi/router.go's shape after this slice:GET /underjwtauth.Verifieronly;GET /{id},POST /,DELETE /{id},PATCH /{id},PATCH /{id}/publish,PATCH /{id}/unpublishand the newPOST /{id}/image(routed toimageHandler.PostImage) underjwtauth.Verifier+jwtauth.Authenticator. - Mint a valid jwt cookie for user id 1:
token.Encode(map[string]any{"user_id": uint32(1)}), set as thejwtcookie on the relevanthttptest.NewRequest. - Build multipart request bodies with
mime/multipart.Writer, field name"file", setting the part'sContent-Typeheader explicitly (Go's multipart writer defaults to sniffing otherwise, so set it viaCreatePartwith an explicit MIME header rather thanCreateFormFile), and set the request'sContent-Typeheader to the writer'sFormDataContentType().
HTTP checks
- Seed
articleRepo.articles[1] = article.Article{ID: 1, Title: "Backyard Renovation Update"}. SendPOST /v1/article/1/imagewith the valid cookie and a multipart"file"part named"before.png", content type"image/png", some non-empty byte content. Assert status201; decode the JSON body and assertlocationequals"/static/uploadedImages/before.png"; assertimageRepo.imagesgained exactly one entry whosePathmatches that location; assertarticleRepo.articles[1].Imagesnow contains that image's id. - Empty
articleRepo, emptyimageRepo. SendPOST /v1/article/9999/imagewith the valid cookie and the same"before.png"/"image/png"part. Assert status404, body"Article not found\n"; assertimageRepo.imagesis still empty (the article's existence is confirmed before any image is created, so nothing is left orphaned). - Seed
articleRepo.articles[1] = article.Article{ID: 1, Title: "Backyard Renovation Update"}with an emptyImagesslice. SendPOST /v1/article/1/imagewith the valid cookie and a multipart"file"part named"notes.pdf", content type"application/pdf". Assert status400, body"the file must be a PNG, JPEG, WEBP, or SVG image\n"; assertimageRepo.imagesis still empty; assertarticleRepo.articles[1].Imagesis still empty. - Seed the same article id 1 as step 11. Send
POST /v1/article/1/imagewith no cookie and the"before.png"/"image/png"part. Assert status401; assertimageRepo.imagesis still empty; assertarticleRepo.articles[1].Imagesis still empty.
Manual verification (not exercised by the Go test)
- Real upload against a real SQLite file and real
UPLOAD_DIR: confirm that afterPOST /v1/article/{id}/imageon a real running instance, the file actually lands on disk underUPLOAD_DIR, theimagesrow'spathresolves to a URL the SPA can load, and thearticle_imagesjoin table gets the new row. Not exercised bytask test(fakes only); requirestask devor a builttask buildbinary 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.