Files
RenewCMS/features/public_article_listing.qa.md

3.7 KiB

QA procedure: public_article_listing

Package: test (black-box, extending article_test.go).

Setup shared by every case

  1. Call validator.InitValidator() once.
  2. Reuse mockArticleRepo (test/article_test.go) as-is; FindByFilters and the failSwitch already support everything this slice needs, no fake changes expected.
  3. Wire the real use cases over the fake: useCases.NewCreateArticleUseCase, useCases.NewGetArticleUseCase, useCases.NewListArticlesUseCase, useCases.NewDeleteArticleUseCase. Build article.NewHandler(create, get, list, delete).
  4. Build a test jwtauth.New("HS256", []byte("test-secret"), nil).
  5. Mount the routes on a fresh chi.NewRouter() mirroring the new api/router.go shape:
    • r.Route("/article", func(r chi.Router) { ... })
    • r.Use(jwtauth.Verifier(token)) on the whole /article group (parses, never rejects)
    • r.Get("/", articleHandler.ListArticles) directly under that Verifier-only group
    • a nested r.Group adding jwtauth.Authenticator(token), containing r.Get("/{id}", articleHandler.GetArticle), r.Post("/", articleHandler.PostArticle), r.Delete("/{id}", articleHandler.DeleteArticle) No live server.
  6. 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.
  7. Seed the repo for the listing cases via repo.articles[1] = article.Article{ID: 1, Title: "Backyard Renovation Update", IsOnline: true} and repo.articles[2] = article.Article{ID: 2, Title: "Draft: Kitchen Remodel", IsOnline: false} (same direct-map pattern as TestGetOnlineArticle).

HTTP checks

  1. GET /v1/article/ with no cookie, repo seeded per step 7 -> status 200; decode the JSON array and assert it has exactly one element, id 1; assert no element has id 2.
  2. GET /v1/article/ with the valid cookie from step 6, same seed -> status 200; decode the JSON array and assert it has exactly two elements, ids 1 and 2 both present.
  3. GET /v1/article/ with a cookie named jwt whose value is an arbitrary non-token string (e.g. "not-a-real-token"), same seed -> status 200; assert the same single-element (id 1) result as step 8, proving an invalid cookie falls back to the public list rather than erroring.
  4. GET /v1/article/1 with no cookie -> status 401 (regression: single-article read still gated).
  5. POST /v1/article/ with no cookie, JSON body {"title":"Valid Title","body":"Some content"} -> status 401 (regression: create still gated).
  6. DELETE /v1/article/1 with no cookie -> status 401 (regression: delete still gated).
  7. Configure the fake repo's failSwitch so the next FindByFilters call returns errRepositoryFailure (existing failNext("FindByFilters") helper). GET /v1/article/ with no cookie -> status 500, body "Failed to retrieve articles\n".
  8. As a regression on the valid-cookie path from step 9, also assert GET /v1/article/{id} and POST/DELETE still succeed as before with a valid cookie (existing coverage in article_test.go / article_title_rules_test.go / write_not_found_errors_test.go already covers this; no new assertions needed here beyond confirming the router restructuring didn't regress them -- rerun those suites as part of task test).

Manual verification (not exercised by the Go test)

  • SPA-visible behaviour: confirm the public front-office article list view (unauthenticated) only renders online articles, and the authenticated back-office article list view renders offline drafts too, against the real embedded frontend and a real SQLite file. Not exercised by task test; requires task dev or a built task build binary.
  • No SMTP involvement.