Files
RenewCMS/features/article_body_format.qa.md

4.8 KiB

QA procedure: article_body_format

Package: test (black-box). New files: test/article_body_format_test.go, test/markdown_converter_test.go, test/json_blocks_converter_test.go. No live server, no real SQLite file, no real SMTP.

Setup

  1. Call validator.InitValidator() once.
  2. Reuse mockArticleRepo and mockUserRepo. Add a fake fakeBodyRenderer with a unique type name. It records each call's format and the html it received. For markdown it returns "MD:"+html. For html it returns the html unchanged. For json it returns [{"type":"paragraph","children":[{"type":"text","text":"FAKE","marks":[]}]}]. It has a failure switch.
  3. Wire the real use cases over the fakes, passing the renderer. Update every existing test that builds these use cases for the new constructor signatures. Build article.NewHandler(...).
  4. Mount a fresh chi.NewRouter() mirroring api/router.go for /v1/article: jwtauth.Verifier on the group, GET / and /{id} public, and Authenticator + RequireCurrentToken + RequireVerifiedUser for POST, DELETE and PATCH.
  5. Mint a jwt cookie for user_id 1 with token.Encode(map[string]any{"user_id": uint32(1)}). Seed a verified user. Seed articles 1 (online) and 2 (offline).

HTTP checks (fake renderer)

  1. Single read matrix: for each of none, ?format=, markdown, MarkDown, html, HTML, json, JSON, assert status 200, body_format, the renderer's recorded format and the stored HTML passed in. For json, decode body and assert it is a JSON array (not a string).
  2. List with none, ?format=html and ?format=json: every element has the matching body_format.
  3. format=pdf, xml and md on single, list and unknown-id paths return 400 with apperr.ArticleBodyFormatErrorMessage + "\n". The renderer and the repo are not called.
  4. GET /v1/article/abc?format=pdf returns 400 with apperr.IdUint32ErrorMessage + "\n".
  5. ?format=html&format=json returns html.
  6. GET /v1/article/2?format=json anonymous returns 404 "Article not found\n".
  7. Write-route matrix with a cookie (POST, PATCH, publish, unpublish, each with none, html and json where listed): assert status, body_format, and that the repo holds the HTML that was sent.
  8. PATCH /v1/article/1?format=pdf and POST /v1/article/?format=pdf with a cookie return 400. The repo is unchanged and no article is created.
  9. Authenticated GET /v1/article/?format=json includes articles 1 and 2.
  10. Renderer failure switch, then GET /v1/article/1 returns 500 "Internal server error\n".

Domain

  1. ParseBodyFormat: "", markdown, MARKDOWN, html, Html, json, JSON are accepted (empty returns markdown). pdf, md and " html" return errors.Is(err, ErrUnsupportedBodyFormat).

Converter tests (real library, real Tiptap HTML samples)

  1. test/markdown_converter_test.go: every row of the markdown fidelity table, plus a combined document (heading, paragraph with marks, list, image, code block, quote, hr). Assert exact output. For format html, assert the input comes back byte-identical. 17b. Alignment and escaping: every row of the alignment and plain-text tables, for markdown and json, in test/markdown_converter_test.go and test/json_blocks_converter_test.go. test/body_converter_documents_test.go covers the combined hostile document (no raw script, style, iframe or span leaks in markdown or json), its block types, and code block text extraction.
  2. test/json_blocks_converter_test.go: every row of the json shapes table. Assert by unmarshalling both sides and comparing with deep equality. This also asserts marks is [] rather than null or absent, ordered is a bool, and code language is "" when absent. Also include a combined document with nested list, blockquote and an image inside a paragraph. Assert that script and style content never appears, and that no raw HTML survives in any output for any format except html.
  3. test/json_blocks_converter_test.go also asserts that html "" produces [], and that the output is a non-null JSON array.

SPA (Vitest, task test:web)

  1. Mock /v1/article/12?format=html and assert EditorView requests that URL and loads the HTML body into the draft.
  2. Assert useArticles.listArticles requests /v1/article/?format=html.
  3. Assert the ArticleView image count is computed from the HTML.
  4. Assert useArticleDraft.save sends PATCH /v1/article/{id}?format=html with the JSON body.
  5. Reported as NOT RUN if there is no runner. No visual check applies, because no visual change is expected.

Docs

  1. Check that a docs/api article read page, the IntegrationView snippets and a docs/releases note exist as described.

Manual verification

  • In the embedded SPA, edit and save an article against a real SQLite file and confirm the stored body is still HTML.
  • curl the public list and a single article with no format, ?format=html and ?format=json against a built binary.
  • No SMTP involvement.