test(stores): cover settings merge/clamp + notification sanitizer (29→42 tests)
Extract two pure helpers so they're testable without zustand/expo: - settings-merge.ts: clampPageSize + forward-compatible mergeStoredSettings (the upgrade path where stored data predates a new notification category must yield the default, not undefined). stores/settings.ts now delegates. - notify-format.ts: sanitizeBody (strip C0/DEL control chars, trim, cap at 200) used for server-supplied notification text. stores/events.ts now imports it. Behavior unchanged; typecheck clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
25
src/lib/settings-merge.ts
Normal file
25
src/lib/settings-merge.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// Pure settings helpers extracted from stores/settings.ts so the clamp + the
|
||||
// forward-compatible merge (the upgrade path: stored data from an older app
|
||||
// version that predates a newer notification category) are unit-testable without
|
||||
// pulling in zustand / expo-secure-store.
|
||||
|
||||
export function clampPageSize(size: number): number {
|
||||
return Math.max(10, Math.min(200, size))
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge stored settings over defaults. Stored values win, but any top-level field
|
||||
* or notification category missing from storage falls back to its default — so a
|
||||
* user upgrading to a build with a new setting gets that setting's default rather
|
||||
* than `undefined`. Defaults are passed in to keep this module dependency-free.
|
||||
*/
|
||||
export function mergeStoredSettings<T extends { notifications: Record<string, boolean> }>(
|
||||
defaults: T,
|
||||
parsed: Partial<T>,
|
||||
): T {
|
||||
return {
|
||||
...defaults,
|
||||
...parsed,
|
||||
notifications: { ...defaults.notifications, ...parsed.notifications },
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user