Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/lib/affiliates/validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,15 @@ describe("validateOfferInput", () => {
expect(result.errors.some((e) => e.includes("10 tags"))).toBe(true);
});

it("rejects non-string tags before sanitizing", () => {
const result = validateOfferInput({
...validInput,
tags: ["valid", 123] as any,
});
expect(result.ok).toBe(false);
expect(result.errors.some((e) => e.includes("tags") && e.includes("strings"))).toBe(true);
});
Comment on lines +173 to +180
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 No test for non-array tags value

The PR description says "reject non-array tags values," but the only new test uses an array that contains a non-string element (["valid", 123]). There is no test for the fully non-array case (e.g., tags: "string", tags: 42, or tags: null), leaving the new !Array.isArray(input.tags) branch untested. A test for tags: "not-an-array" would directly exercise the new guard and would also surface the null behavior described in the companion comment.


it("rejects title shorter than 3 characters", () => {
const result = validateOfferInput({ ...validInput, title: "AB" });
expect(result.ok).toBe(false);
Expand Down
13 changes: 11 additions & 2 deletions src/lib/affiliates/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,17 @@ export function validateOfferInput(input: OfferInput): ValidationResult {
errors.push(`Category must be one of: ${SKILL_CATEGORIES.join(", ")}`);
}

if (input.tags && input.tags.length > 10) {
errors.push("Maximum 10 tags");
if (input.tags !== undefined) {
if (!Array.isArray(input.tags)) {
errors.push("tags must be an array");
} else {
if (input.tags.length > 10) {
errors.push("Maximum 10 tags");
}
if (input.tags.some((tag) => typeof tag !== "string")) {
errors.push("tags must be strings");
}
}
}
Comment on lines +124 to 135
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 null tags now rejected as a non-array

The guard changed from if (input.tags && ...) (truthy check) to if (input.tags !== undefined), so a null value now enters the branch and triggers "tags must be an array". null is a realistic runtime value: JSON round-trips, database reads, or existing API callers may pass tags: null when no tags are set. Previously that was silently accepted; now it becomes a validation error that breaks those callers. The sanitization path at line 153 already handles null correctly via optional chaining (input.tags?.map(...) || []), making this inconsistency easy to miss. Consider using input.tags != null (loose inequality) or explicitly handling the null case alongside undefined to preserve the prior behavior.


if (errors.length > 0) {
Expand Down
Loading