Gate B #26: shared validation module (V-1, V-2, V-3)

- V-1: SKU charset [A-Z0-9-]{3,24}, accepted/rejected with specific error codes
- V-2: title/short_title/description UTF-8 within WooCommerce maxLength,
  enforced at field-exit and submit (200/200/2500 chars, Unicode code-point counting)
- V-3: validation module version hash, client caches, submit carries hash,
  mismatch returns 412 with fresh module (not 409)

25 unit tests green, zero browser/DOM/network dependencies.
Re-exports through pipeline/index.ts for shared use.
This commit is contained in:
grokbot_ty
2026-09-07 07:43:50 +00:00
parent 34dbfa5d7d
commit d5d8c49e04
8 changed files with 667 additions and 0 deletions
@@ -0,0 +1,113 @@
/** Boundary strings for shared validation unit tests (V-1, V-2, V-3). */
// ---------------------------------------------------------------------------
// V-1: SKU [A-Z0-9-]{3,24}
// ---------------------------------------------------------------------------
/** Valid SKUs spanning the charset and length boundaries. */
export const validSkuStrings = [
// Minimum length (3 chars) — all letter, all digit, mixed, hyphen edges.
"ABC",
"012",
"A0A",
"A-B",
"0-1",
// Mid-range typical.
"BW-0042",
"SLAB-UAT-001",
"A9Z",
// Maximum length (24 chars).
"AAAAAAAAAAAAAAAAAAAAAAAA",
"A1B2C3D4E5F6G7H8I9J0K-12",
// Edge cases within charset.
"A-A-A-A-A-A",
"1-2-3-4-5-6",
"ABCDEF",
];
/** Invalid SKUs: wrong charset, too short, too long. */
export const invalidSkuStrings = [
// Too short (1–2 chars).
"A",
"AB",
// Too long (25+ chars).
"AAAAAAAAAAAAAAAAAAAAAAAAA",
// Lowercase letters (outside charset).
"abc",
"bw-0042",
"aB3",
// Special characters outside charset.
"ABC!",
"A B",
"A_B",
"ABC.D",
"ABC#1",
"ABC/1",
"ABC\\1",
// Empty.
"",
];
// ---------------------------------------------------------------------------
// V-2: Title / short_title / description maxLength (UTF-8)
// ---------------------------------------------------------------------------
import {
MAX_TITLE_LENGTH,
MAX_SHORT_TITLE_LENGTH,
MAX_DESCRIPTION_LENGTH,
} from "../../lib/validation/constants.js";
const TITLE_LEN = MAX_TITLE_LENGTH;
const SHORT_TITLE_LEN = MAX_SHORT_TITLE_LENGTH;
const DESC_LEN = MAX_DESCRIPTION_LENGTH;
function repeat(char: string, count: number): string {
return char.repeat(count);
}
function buildTitle(): { title: string; length: number } {
return { title: repeat("A", TITLE_LEN), length: TITLE_LEN };
}
function buildShortTitle(): { shortTitle: string; length: number } {
return { shortTitle: repeat("B", SHORT_TITLE_LEN), length: SHORT_TITLE_LEN };
}
function buildDescription(): { description: string; length: number } {
return { description: repeat("C", DESC_LEN), length: DESC_LEN };
}
export function validTitleFixture(): { title: string; length: number } {
return buildTitle();
}
export function invalidTitleFixture(): { title: string; length: number } {
return { title: repeat("A", TITLE_LEN + 1), length: TITLE_LEN + 1 };
}
export function validShortTitleFixture(): { shortTitle: string; length: number } {
return buildShortTitle();
}
export function invalidShortTitleFixture(): { shortTitle: string; length: number } {
return { shortTitle: repeat("B", SHORT_TITLE_LEN + 1), length: SHORT_TITLE_LEN + 1 };
}
export function validDescriptionFixture(): { description: string; length: number } {
return buildDescription();
}
export function invalidDescriptionFixture(): { description: string; length: number } {
return { description: repeat("C", DESC_LEN + 1), length: DESC_LEN + 1 };
}
// ---------------------------------------------------------------------------
// V-3: Validation module version hash
// ---------------------------------------------------------------------------
/** Expected hash for the current module (constants v1). */
export const expectedHash = "v1";
/** A stale hash to test mismatch detection. */
export const staleHash = "v0";