Barazo AppView backend barazo.forum
at main 258 lines 8.4 kB view raw
1import { describe, it, expect } from 'vitest' 2import { 3 userPreferencesSchema, 4 communityPreferencesSchema, 5 ageDeclarationSchema, 6} from '../../../src/validation/profiles.js' 7 8// =========================================================================== 9// Tests 10// =========================================================================== 11 12describe('profile validation schemas', () => { 13 // ========================================================================= 14 // userPreferencesSchema 15 // ========================================================================= 16 17 describe('userPreferencesSchema', () => { 18 it('parses a fully populated valid body', () => { 19 const result = userPreferencesSchema.safeParse({ 20 maturityLevel: 'mature', 21 mutedWords: ['spoiler', 'nsfw'], 22 blockedDids: ['did:plc:blocked1'], 23 mutedDids: ['did:plc:muted1'], 24 crossPostBluesky: true, 25 crossPostFrontpage: false, 26 }) 27 28 expect(result.success).toBe(true) 29 if (result.success) { 30 expect(result.data.maturityLevel).toBe('mature') 31 expect(result.data.mutedWords).toEqual(['spoiler', 'nsfw']) 32 expect(result.data.crossPostBluesky).toBe(true) 33 } 34 }) 35 36 it('parses an empty body (all fields optional)', () => { 37 const result = userPreferencesSchema.safeParse({}) 38 39 expect(result.success).toBe(true) 40 if (result.success) { 41 expect(result.data.maturityLevel).toBeUndefined() 42 expect(result.data.mutedWords).toBeUndefined() 43 expect(result.data.blockedDids).toBeUndefined() 44 expect(result.data.mutedDids).toBeUndefined() 45 expect(result.data.crossPostBluesky).toBeUndefined() 46 expect(result.data.crossPostFrontpage).toBeUndefined() 47 } 48 }) 49 50 it('parses partial updates (only maturityLevel)', () => { 51 const result = userPreferencesSchema.safeParse({ 52 maturityLevel: 'sfw', 53 }) 54 55 expect(result.success).toBe(true) 56 if (result.success) { 57 expect(result.data.maturityLevel).toBe('sfw') 58 } 59 }) 60 61 it('fails for invalid maturityLevel', () => { 62 const result = userPreferencesSchema.safeParse({ 63 maturityLevel: 'adult', 64 }) 65 expect(result.success).toBe(false) 66 }) 67 68 it('fails for empty strings in mutedWords', () => { 69 const result = userPreferencesSchema.safeParse({ 70 mutedWords: [''], 71 }) 72 expect(result.success).toBe(false) 73 }) 74 75 it('fails for non-boolean crossPostBluesky', () => { 76 const result = userPreferencesSchema.safeParse({ 77 crossPostBluesky: 'yes', 78 }) 79 expect(result.success).toBe(false) 80 }) 81 82 it("accepts maturityLevel 'sfw'", () => { 83 const result = userPreferencesSchema.safeParse({ 84 maturityLevel: 'sfw', 85 }) 86 expect(result.success).toBe(true) 87 }) 88 89 it("accepts maturityLevel 'mature'", () => { 90 const result = userPreferencesSchema.safeParse({ 91 maturityLevel: 'mature', 92 }) 93 expect(result.success).toBe(true) 94 }) 95 }) 96 97 // ========================================================================= 98 // communityPreferencesSchema 99 // ========================================================================= 100 101 describe('communityPreferencesSchema', () => { 102 it('parses a fully populated valid body', () => { 103 const result = communityPreferencesSchema.safeParse({ 104 maturityOverride: 'mature', 105 mutedWords: ['spoiler'], 106 blockedDids: ['did:plc:blocked1'], 107 mutedDids: ['did:plc:muted1'], 108 notificationPrefs: { 109 replies: true, 110 reactions: false, 111 mentions: true, 112 modActions: true, 113 }, 114 }) 115 116 expect(result.success).toBe(true) 117 if (result.success) { 118 expect(result.data.maturityOverride).toBe('mature') 119 expect(result.data.notificationPrefs?.replies).toBe(true) 120 expect(result.data.notificationPrefs?.reactions).toBe(false) 121 } 122 }) 123 124 it('parses an empty body (all fields optional)', () => { 125 const result = communityPreferencesSchema.safeParse({}) 126 127 expect(result.success).toBe(true) 128 if (result.success) { 129 expect(result.data.maturityOverride).toBeUndefined() 130 expect(result.data.mutedWords).toBeUndefined() 131 expect(result.data.notificationPrefs).toBeUndefined() 132 } 133 }) 134 135 it('accepts null values for nullable fields', () => { 136 const result = communityPreferencesSchema.safeParse({ 137 maturityOverride: null, 138 mutedWords: null, 139 blockedDids: null, 140 mutedDids: null, 141 notificationPrefs: null, 142 }) 143 144 expect(result.success).toBe(true) 145 if (result.success) { 146 expect(result.data.maturityOverride).toBeNull() 147 expect(result.data.mutedWords).toBeNull() 148 expect(result.data.notificationPrefs).toBeNull() 149 } 150 }) 151 152 it('fails for invalid maturityOverride', () => { 153 const result = communityPreferencesSchema.safeParse({ 154 maturityOverride: 'adult', 155 }) 156 expect(result.success).toBe(false) 157 }) 158 159 it('fails for incomplete notificationPrefs', () => { 160 const result = communityPreferencesSchema.safeParse({ 161 notificationPrefs: { 162 replies: true, 163 // missing other required fields 164 }, 165 }) 166 expect(result.success).toBe(false) 167 }) 168 169 it('fails for non-boolean values in notificationPrefs', () => { 170 const result = communityPreferencesSchema.safeParse({ 171 notificationPrefs: { 172 replies: 'yes', 173 reactions: true, 174 mentions: true, 175 modActions: true, 176 }, 177 }) 178 expect(result.success).toBe(false) 179 }) 180 }) 181 182 // ========================================================================= 183 // ageDeclarationSchema 184 // ========================================================================= 185 186 describe('ageDeclarationSchema', () => { 187 it('parses valid declaredAge: 0 (rather not say)', () => { 188 const result = ageDeclarationSchema.safeParse({ declaredAge: 0 }) 189 expect(result.success).toBe(true) 190 if (result.success) { 191 expect(result.data.declaredAge).toBe(0) 192 } 193 }) 194 195 it('parses valid declaredAge: 13', () => { 196 const result = ageDeclarationSchema.safeParse({ declaredAge: 13 }) 197 expect(result.success).toBe(true) 198 if (result.success) { 199 expect(result.data.declaredAge).toBe(13) 200 } 201 }) 202 203 it('parses valid declaredAge: 14', () => { 204 const result = ageDeclarationSchema.safeParse({ declaredAge: 14 }) 205 expect(result.success).toBe(true) 206 }) 207 208 it('parses valid declaredAge: 15', () => { 209 const result = ageDeclarationSchema.safeParse({ declaredAge: 15 }) 210 expect(result.success).toBe(true) 211 }) 212 213 it('parses valid declaredAge: 16', () => { 214 const result = ageDeclarationSchema.safeParse({ declaredAge: 16 }) 215 expect(result.success).toBe(true) 216 }) 217 218 it('parses valid declaredAge: 18', () => { 219 const result = ageDeclarationSchema.safeParse({ declaredAge: 18 }) 220 expect(result.success).toBe(true) 221 }) 222 223 it('fails for declaredAge: 1 (invalid value)', () => { 224 const result = ageDeclarationSchema.safeParse({ declaredAge: 1 }) 225 expect(result.success).toBe(false) 226 }) 227 228 it('fails for declaredAge: 12 (below minimum)', () => { 229 const result = ageDeclarationSchema.safeParse({ declaredAge: 12 }) 230 expect(result.success).toBe(false) 231 }) 232 233 it('fails for declaredAge: 17 (not a valid bracket)', () => { 234 const result = ageDeclarationSchema.safeParse({ declaredAge: 17 }) 235 expect(result.success).toBe(false) 236 }) 237 238 it('fails for declaredAge: 19 (above valid range)', () => { 239 const result = ageDeclarationSchema.safeParse({ declaredAge: 19 }) 240 expect(result.success).toBe(false) 241 }) 242 243 it('fails for declaredAge: -1 (negative)', () => { 244 const result = ageDeclarationSchema.safeParse({ declaredAge: -1 }) 245 expect(result.success).toBe(false) 246 }) 247 248 it("fails for declaredAge: 'sixteen' (string)", () => { 249 const result = ageDeclarationSchema.safeParse({ declaredAge: 'sixteen' }) 250 expect(result.success).toBe(false) 251 }) 252 253 it('fails when declaredAge is missing', () => { 254 const result = ageDeclarationSchema.safeParse({}) 255 expect(result.success).toBe(false) 256 }) 257 }) 258})