-
Notifications
You must be signed in to change notification settings - Fork 0
🧪 QA: Add tests for common utilities #387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: staging
Are you sure you want to change the base?
Changes from all commits
9d8d4af
8507a69
ef4edd1
30738df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,13 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { describe, expect, it } from "vitest" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { unescapeHTML } from "./common" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| describe("common utilities", () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it("unescapes HTML entities in VNode children", () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const node = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: "div", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| children: "<b>bold</b> & beautiful", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const result = unescapeHTML(node) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(result.children).toBe("<b>bold</b> & beautiful") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+11
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { describe, expect, it } from "vitest" | |
| import { unescapeHTML } from "./common" | |
| describe("common utilities", () => { | |
| it("unescapes HTML entities in VNode children", () => { | |
| const node = { | |
| type: "div", | |
| children: "<b>bold</b> & beautiful", | |
| } | |
| const result = unescapeHTML(node) | |
| expect(result.children).toBe("<b>bold</b> & beautiful") | |
| import { describe, expect, it } from 'vitest' | |
| import { unescapeHTML } from './common' | |
| describe('common utilities', () => { | |
| it('unescapes HTML entities in VNode children', () => { | |
| const node = { | |
| type: 'div', | |
| children: '<b>bold</b> & beautiful', | |
| } | |
| const result = unescapeHTML(node) | |
| expect(result.children).toBe('<b>bold</b> & beautiful') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test only covers the happy path where children is a simple string containing a few entities. If unescapeHTML is meant to be a general utility, it’s easy for regressions to slip in without covering common shapes (e.g., missing/undefined children, array children, nested nodes, already-unescaped strings, or other entities). Adding a small table-driven set of cases would make this much harder to break accidentally.
Suggestion
Expand coverage with a small set of additional cases (table-driven) that reflect the function’s expected contract, e.g.:
childrenmissing /null/ non-stringchildrenarray (if supported) and nested nodes- idempotency (calling twice yields same result)
- a few more entities (e.g.,
",', numeric entities) if supported
If you want, reply with "@CharlieHelps yes please" and I’ll add a commit that introduces a describe.each/it.each matrix covering these cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Expand test coverage to include edge cases and additional entity types.
The PR description states this adds tests "to cover missing edge cases," but currently only one basic happy-path test exists. The unescapeHTML implementation handles several scenarios not covered here:
Missing test cases:
- Additional entity types:
",',/,=(implementation handles 7 entity types total, test only covers 3) - Array children: Recursive processing of arrays containing strings and VNodes
- Nested VNode children: Recursive unescaping of nested object children
- Edge cases: null/undefined node, empty children, no children property
📝 Proposed additional test cases to improve coverage
describe("common utilities", () => {
it("unescapes HTML entities in VNode children", () => {
const node = {
type: "div",
children: "<b>bold</b> & beautiful",
}
const result = unescapeHTML(node)
expect(result.children).toBe("<b>bold</b> & beautiful")
})
+
+ it("unescapes all supported HTML entities", () => {
+ const node = {
+ type: "div",
+ children: "<>"'/=&",
+ }
+ const result = unescapeHTML(node)
+ expect(result.children).toBe("<>\"'/=&")
+ })
+
+ it("unescapes HTML entities in array children", () => {
+ const node = {
+ type: "div",
+ children: [
+ "<text>",
+ { type: "span", children: "& more "text"" },
+ ],
+ }
+ const result = unescapeHTML(node)
+ expect(result.children).toEqual([
+ "<text>",
+ { type: "span", children: "& more \"text\"" },
+ ])
+ })
+
+ it("handles null or undefined nodes", () => {
+ expect(unescapeHTML(null as any)).toBe(null)
+ expect(unescapeHTML(undefined as any)).toBe(undefined)
+ })
+
+ it("handles nodes without children", () => {
+ const node = { type: "div" }
+ const result = unescapeHTML(node)
+ expect(result).toEqual({ type: "div" })
+ })
+
+ it("handles deeply nested VNode children", () => {
+ const node = {
+ type: "div",
+ children: {
+ type: "p",
+ children: {
+ type: "span",
+ children: "<nested> & deep",
+ },
+ },
+ }
+ const result = unescapeHTML(node)
+ expect(result.children).toEqual({
+ type: "p",
+ children: {
+ type: "span",
+ children: "<nested> & deep",
+ },
+ })
+ })Would you like me to open an issue to track these additional test cases?
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| describe("common utilities", () => { | |
| it("unescapes HTML entities in VNode children", () => { | |
| const node = { | |
| type: "div", | |
| children: "<b>bold</b> & beautiful", | |
| } | |
| const result = unescapeHTML(node) | |
| expect(result.children).toBe("<b>bold</b> & beautiful") | |
| }) | |
| }) | |
| describe("common utilities", () => { | |
| it("unescapes HTML entities in VNode children", () => { | |
| const node = { | |
| type: "div", | |
| children: "<b>bold</b> & beautiful", | |
| } | |
| const result = unescapeHTML(node) | |
| expect(result.children).toBe("<b>bold</b> & beautiful") | |
| }) | |
| it("unescapes all supported HTML entities", () => { | |
| const node = { | |
| type: "div", | |
| children: "<>"'/=&", | |
| } | |
| const result = unescapeHTML(node) | |
| expect(result.children).toBe("<>\"'/=&") | |
| }) | |
| it("unescapes HTML entities in array children", () => { | |
| const node = { | |
| type: "div", | |
| children: [ | |
| "<text>", | |
| { type: "span", children: "& more "text"" }, | |
| ], | |
| } | |
| const result = unescapeHTML(node) | |
| expect(result.children).toEqual([ | |
| "<text>", | |
| { type: "span", children: "& more \"text\"" }, | |
| ]) | |
| }) | |
| it("handles null or undefined nodes", () => { | |
| expect(unescapeHTML(null as any)).toBe(null) | |
| expect(unescapeHTML(undefined as any)).toBe(undefined) | |
| }) | |
| it("handles nodes without children", () => { | |
| const node = { type: "div" } | |
| const result = unescapeHTML(node) | |
| expect(result).toEqual({ type: "div" }) | |
| }) | |
| it("handles deeply nested VNode children", () => { | |
| const node = { | |
| type: "div", | |
| children: { | |
| type: "p", | |
| children: { | |
| type: "span", | |
| children: "<nested> & deep", | |
| }, | |
| }, | |
| } | |
| const result = unescapeHTML(node) | |
| expect(result.children).toEqual({ | |
| type: "p", | |
| children: { | |
| type: "span", | |
| children: "<nested> & deep", | |
| }, | |
| }) | |
| }) | |
| }) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/utils/common.test.ts` around lines 4 - 13, Add expanded tests for
unescapeHTML in src/utils/common.test.ts to cover the missing edge cases: assert
additional entity types (", ', /, =) are decoded by
unescapeHTML; verify array children are processed recursively (arrays with
strings and VNode-like objects passed to unescapeHTML); verify nested VNode
children (objects with children that are VNodes) are unescaped recursively; and
add edge-case tests for null/undefined node, empty children, and nodes with no
children property. Reference the unescapeHTML function in your new test cases
and ensure each scenario has an expectation that matches the implementation's
return shape (e.g., result.children is the unescaped string or array).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test doesn’t clarify whether
unescapeHTMLis expected to mutate the input node or return a new node. That behavior matters to callers and is easy to change unintentionally. Consider asserting the intended behavior explicitly (eitherresult === nodefor mutation orresult !== nodefor immutability).Suggestion
Add an explicit assertion for mutation vs immutability based on the intended contract, e.g.:
expect(result).not.toBe(node)expect(result).toBe(node)Optionally, deep-freeze
nodeto ensure immutability is enforced if that’s the goal. Reply with "@CharlieHelps yes please" if you’d like me to add a commit with the assertion that matches the intended behavior.