@ucptools/validator 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/dist/auth/config.d.ts +20 -0
  2. package/dist/auth/config.d.ts.map +1 -0
  3. package/dist/auth/config.js +114 -0
  4. package/dist/auth/config.js.map +1 -0
  5. package/dist/auth/index.d.ts +5 -0
  6. package/dist/auth/index.d.ts.map +1 -0
  7. package/dist/auth/index.js +17 -0
  8. package/dist/auth/index.js.map +1 -0
  9. package/dist/auth/middleware.d.ts +45 -0
  10. package/dist/auth/middleware.d.ts.map +1 -0
  11. package/dist/auth/middleware.js +170 -0
  12. package/dist/auth/middleware.js.map +1 -0
  13. package/dist/auth/service.d.ts +80 -0
  14. package/dist/auth/service.d.ts.map +1 -0
  15. package/dist/auth/service.js +298 -0
  16. package/dist/auth/service.js.map +1 -0
  17. package/dist/cli/index.d.ts +6 -0
  18. package/dist/cli/index.d.ts.map +1 -0
  19. package/dist/cli/index.js +375 -0
  20. package/dist/cli/index.js.map +1 -0
  21. package/dist/cli/mock-server.d.ts +20 -0
  22. package/dist/cli/mock-server.d.ts.map +1 -0
  23. package/dist/cli/mock-server.js +261 -0
  24. package/dist/cli/mock-server.js.map +1 -0
  25. package/dist/compliance/compliance-generator.d.ts +34 -0
  26. package/dist/compliance/compliance-generator.d.ts.map +1 -0
  27. package/dist/compliance/compliance-generator.js +320 -0
  28. package/dist/compliance/compliance-generator.js.map +1 -0
  29. package/dist/compliance/index.d.ts +8 -0
  30. package/dist/compliance/index.d.ts.map +1 -0
  31. package/dist/compliance/index.js +17 -0
  32. package/dist/compliance/index.js.map +1 -0
  33. package/dist/compliance/templates.d.ts +34 -0
  34. package/dist/compliance/templates.d.ts.map +1 -0
  35. package/{src/compliance/templates.ts → dist/compliance/templates.js} +117 -155
  36. package/dist/compliance/templates.js.map +1 -0
  37. package/dist/compliance/types.d.ts +64 -0
  38. package/dist/compliance/types.d.ts.map +1 -0
  39. package/dist/compliance/types.js +64 -0
  40. package/dist/compliance/types.js.map +1 -0
  41. package/dist/db/index.d.ts +17 -0
  42. package/dist/db/index.d.ts.map +1 -0
  43. package/dist/db/index.js +80 -0
  44. package/dist/db/index.js.map +1 -0
  45. package/dist/db/schema.d.ts +3886 -0
  46. package/dist/db/schema.d.ts.map +1 -0
  47. package/dist/db/schema.js +425 -0
  48. package/dist/db/schema.js.map +1 -0
  49. package/dist/db/utils.d.ts +252 -0
  50. package/dist/db/utils.d.ts.map +1 -0
  51. package/dist/db/utils.js +295 -0
  52. package/dist/db/utils.js.map +1 -0
  53. package/dist/feed-analyzer/feed-analyzer.d.ts +26 -0
  54. package/dist/feed-analyzer/feed-analyzer.d.ts.map +1 -0
  55. package/{src/feed-analyzer/feed-analyzer.ts → dist/feed-analyzer/feed-analyzer.js} +856 -726
  56. package/dist/feed-analyzer/feed-analyzer.js.map +1 -0
  57. package/dist/feed-analyzer/index.d.ts +8 -0
  58. package/dist/feed-analyzer/index.d.ts.map +1 -0
  59. package/dist/feed-analyzer/index.js +19 -0
  60. package/dist/feed-analyzer/index.js.map +1 -0
  61. package/dist/feed-analyzer/types.d.ts +285 -0
  62. package/dist/feed-analyzer/types.d.ts.map +1 -0
  63. package/dist/feed-analyzer/types.js +175 -0
  64. package/dist/feed-analyzer/types.js.map +1 -0
  65. package/{src/generator/index.ts → dist/generator/index.d.ts} +1 -1
  66. package/dist/generator/index.d.ts.map +1 -0
  67. package/dist/generator/index.js +13 -0
  68. package/dist/generator/index.js.map +1 -0
  69. package/dist/generator/key-generator.d.ts +24 -0
  70. package/dist/generator/key-generator.d.ts.map +1 -0
  71. package/dist/generator/key-generator.js +144 -0
  72. package/dist/generator/key-generator.js.map +1 -0
  73. package/dist/generator/profile-builder.d.ts +15 -0
  74. package/dist/generator/profile-builder.d.ts.map +1 -0
  75. package/dist/generator/profile-builder.js +338 -0
  76. package/dist/generator/profile-builder.js.map +1 -0
  77. package/dist/hosting/artifacts-generator.d.ts +10 -0
  78. package/dist/hosting/artifacts-generator.d.ts.map +1 -0
  79. package/{src/hosting/artifacts-generator.ts → dist/hosting/artifacts-generator.js} +191 -241
  80. package/dist/hosting/artifacts-generator.js.map +1 -0
  81. package/{src/hosting/index.ts → dist/hosting/index.d.ts} +1 -1
  82. package/dist/hosting/index.d.ts.map +1 -0
  83. package/dist/hosting/index.js +10 -0
  84. package/dist/hosting/index.js.map +1 -0
  85. package/dist/index.d.ts +18 -0
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +78 -0
  88. package/dist/index.js.map +1 -0
  89. package/dist/lib/analytics.d.ts +337 -0
  90. package/dist/lib/analytics.d.ts.map +1 -0
  91. package/dist/lib/analytics.js +188 -0
  92. package/dist/lib/analytics.js.map +1 -0
  93. package/{src/security/index.ts → dist/security/index.d.ts} +8 -15
  94. package/dist/security/index.d.ts.map +1 -0
  95. package/dist/security/index.js +12 -0
  96. package/dist/security/index.js.map +1 -0
  97. package/dist/security/security-scanner.d.ts +10 -0
  98. package/dist/security/security-scanner.d.ts.map +1 -0
  99. package/dist/security/security-scanner.js +669 -0
  100. package/dist/security/security-scanner.js.map +1 -0
  101. package/dist/security/types.d.ts +80 -0
  102. package/dist/security/types.d.ts.map +1 -0
  103. package/dist/security/types.js +21 -0
  104. package/dist/security/types.js.map +1 -0
  105. package/dist/services/analytics.d.ts +114 -0
  106. package/dist/services/analytics.d.ts.map +1 -0
  107. package/dist/services/analytics.js +862 -0
  108. package/dist/services/analytics.js.map +1 -0
  109. package/dist/services/badge.d.ts +31 -0
  110. package/dist/services/badge.d.ts.map +1 -0
  111. package/dist/services/badge.js +152 -0
  112. package/dist/services/badge.js.map +1 -0
  113. package/dist/services/cron.d.ts +125 -0
  114. package/dist/services/cron.d.ts.map +1 -0
  115. package/dist/services/cron.js +613 -0
  116. package/dist/services/cron.js.map +1 -0
  117. package/dist/services/directory.d.ts +106 -0
  118. package/dist/services/directory.d.ts.map +1 -0
  119. package/dist/services/directory.js +351 -0
  120. package/dist/services/directory.js.map +1 -0
  121. package/dist/services/email.d.ts +112 -0
  122. package/dist/services/email.d.ts.map +1 -0
  123. package/dist/services/email.js +772 -0
  124. package/dist/services/email.js.map +1 -0
  125. package/dist/services/hosted-profiles.d.ts +77 -0
  126. package/dist/services/hosted-profiles.d.ts.map +1 -0
  127. package/dist/services/hosted-profiles.js +433 -0
  128. package/dist/services/hosted-profiles.js.map +1 -0
  129. package/dist/services/latency.d.ts +67 -0
  130. package/dist/services/latency.d.ts.map +1 -0
  131. package/dist/services/latency.js +274 -0
  132. package/dist/services/latency.js.map +1 -0
  133. package/dist/services/manifest-compliance.d.ts +64 -0
  134. package/dist/services/manifest-compliance.d.ts.map +1 -0
  135. package/dist/services/manifest-compliance.js +271 -0
  136. package/dist/services/manifest-compliance.js.map +1 -0
  137. package/dist/services/monitoring-diff.d.ts +31 -0
  138. package/dist/services/monitoring-diff.d.ts.map +1 -0
  139. package/dist/services/monitoring-diff.js +189 -0
  140. package/dist/services/monitoring-diff.js.map +1 -0
  141. package/dist/services/notifications.d.ts +46 -0
  142. package/dist/services/notifications.d.ts.map +1 -0
  143. package/dist/services/notifications.js +88 -0
  144. package/dist/services/notifications.js.map +1 -0
  145. package/dist/services/stripe.d.ts +93 -0
  146. package/dist/services/stripe.d.ts.map +1 -0
  147. package/dist/services/stripe.js +490 -0
  148. package/dist/services/stripe.js.map +1 -0
  149. package/dist/services/validation-history.d.ts +99 -0
  150. package/dist/services/validation-history.d.ts.map +1 -0
  151. package/dist/services/validation-history.js +344 -0
  152. package/dist/services/validation-history.js.map +1 -0
  153. package/dist/services/validation-logging.d.ts +103 -0
  154. package/dist/services/validation-logging.d.ts.map +1 -0
  155. package/dist/services/validation-logging.js +210 -0
  156. package/dist/services/validation-logging.js.map +1 -0
  157. package/dist/services/validation.d.ts +119 -0
  158. package/dist/services/validation.d.ts.map +1 -0
  159. package/dist/services/validation.js +1185 -0
  160. package/dist/services/validation.js.map +1 -0
  161. package/dist/simulator/agent-simulator.d.ts +69 -0
  162. package/dist/simulator/agent-simulator.d.ts.map +1 -0
  163. package/dist/simulator/agent-simulator.js +870 -0
  164. package/dist/simulator/agent-simulator.js.map +1 -0
  165. package/{src/simulator/index.ts → dist/simulator/index.d.ts} +7 -7
  166. package/dist/simulator/index.d.ts.map +1 -0
  167. package/dist/simulator/index.js +23 -0
  168. package/dist/simulator/index.js.map +1 -0
  169. package/{src/simulator/types.ts → dist/simulator/types.d.ts} +171 -170
  170. package/dist/simulator/types.d.ts.map +1 -0
  171. package/dist/simulator/types.js +18 -0
  172. package/dist/simulator/types.js.map +1 -0
  173. package/dist/types/acp-validation.d.ts +87 -0
  174. package/dist/types/acp-validation.d.ts.map +1 -0
  175. package/dist/types/acp-validation.js +40 -0
  176. package/dist/types/acp-validation.js.map +1 -0
  177. package/dist/types/analytics.d.ts +182 -0
  178. package/dist/types/analytics.d.ts.map +1 -0
  179. package/dist/types/analytics.js +7 -0
  180. package/dist/types/analytics.js.map +1 -0
  181. package/dist/types/generator.d.ts +106 -0
  182. package/dist/types/generator.d.ts.map +1 -0
  183. package/dist/types/generator.js +6 -0
  184. package/dist/types/generator.js.map +1 -0
  185. package/{src/types/index.ts → dist/types/index.d.ts} +1 -1
  186. package/dist/types/index.d.ts.map +1 -0
  187. package/dist/types/index.js +23 -0
  188. package/dist/types/index.js.map +1 -0
  189. package/dist/types/ucp-profile.d.ts +111 -0
  190. package/dist/types/ucp-profile.d.ts.map +1 -0
  191. package/dist/types/ucp-profile.js +45 -0
  192. package/dist/types/ucp-profile.js.map +1 -0
  193. package/dist/types/validation.d.ts +76 -0
  194. package/dist/types/validation.d.ts.map +1 -0
  195. package/dist/types/validation.js +42 -0
  196. package/dist/types/validation.js.map +1 -0
  197. package/dist/validator/acp/index.d.ts +31 -0
  198. package/dist/validator/acp/index.d.ts.map +1 -0
  199. package/dist/validator/acp/index.js +574 -0
  200. package/dist/validator/acp/index.js.map +1 -0
  201. package/dist/validator/index.d.ts +26 -0
  202. package/dist/validator/index.d.ts.map +1 -0
  203. package/dist/validator/index.js +161 -0
  204. package/dist/validator/index.js.map +1 -0
  205. package/dist/validator/network-validator.d.ts +28 -0
  206. package/dist/validator/network-validator.d.ts.map +1 -0
  207. package/dist/validator/network-validator.js +319 -0
  208. package/dist/validator/network-validator.js.map +1 -0
  209. package/dist/validator/rules-validator.d.ts +19 -0
  210. package/dist/validator/rules-validator.d.ts.map +1 -0
  211. package/dist/validator/rules-validator.js +306 -0
  212. package/dist/validator/rules-validator.js.map +1 -0
  213. package/dist/validator/sdk-validator.d.ts +58 -0
  214. package/dist/validator/sdk-validator.d.ts.map +1 -0
  215. package/{src/validator/sdk-validator.ts → dist/validator/sdk-validator.js} +273 -330
  216. package/dist/validator/sdk-validator.js.map +1 -0
  217. package/dist/validator/structural-validator.d.ts +11 -0
  218. package/dist/validator/structural-validator.d.ts.map +1 -0
  219. package/dist/validator/structural-validator.js +549 -0
  220. package/dist/validator/structural-validator.js.map +1 -0
  221. package/dist/validator/utils.d.ts +51 -0
  222. package/dist/validator/utils.d.ts.map +1 -0
  223. package/dist/validator/utils.js +132 -0
  224. package/dist/validator/utils.js.map +1 -0
  225. package/package.json +44 -12
  226. package/CLAUDE.md +0 -109
  227. package/api/analyze-feed.js +0 -140
  228. package/api/badge.js +0 -185
  229. package/api/benchmark.js +0 -177
  230. package/api/directory-stats.ts +0 -29
  231. package/api/directory.ts +0 -73
  232. package/api/generate-compliance.js +0 -143
  233. package/api/generate-schema.js +0 -457
  234. package/api/generate.js +0 -132
  235. package/api/security-scan.js +0 -133
  236. package/api/simulate.js +0 -187
  237. package/api/tsconfig.json +0 -10
  238. package/api/validate.js +0 -1351
  239. package/apify-actor/.actor/actor.json +0 -68
  240. package/apify-actor/.actor/input_schema.json +0 -32
  241. package/apify-actor/APIFY-STORE-LISTING.md +0 -412
  242. package/apify-actor/Dockerfile +0 -8
  243. package/apify-actor/README.md +0 -166
  244. package/apify-actor/main.ts +0 -111
  245. package/apify-actor/package.json +0 -17
  246. package/apify-actor/src/main.js +0 -199
  247. package/docs/BRAND-IDENTITY.md +0 -238
  248. package/docs/BRAND-STYLE-GUIDE.md +0 -356
  249. package/drizzle/0000_black_king_cobra.sql +0 -39
  250. package/drizzle/meta/0000_snapshot.json +0 -309
  251. package/drizzle/meta/_journal.json +0 -13
  252. package/drizzle.config.ts +0 -10
  253. package/public/.well-known/ucp +0 -25
  254. package/public/android-chrome-192x192.png +0 -0
  255. package/public/android-chrome-512x512.png +0 -0
  256. package/public/apple-touch-icon.png +0 -0
  257. package/public/brand.css +0 -321
  258. package/public/directory.html +0 -701
  259. package/public/favicon-16x16.png +0 -0
  260. package/public/favicon-32x32.png +0 -0
  261. package/public/favicon.ico +0 -0
  262. package/public/guides/bigcommerce.html +0 -743
  263. package/public/guides/fastucp.html +0 -838
  264. package/public/guides/magento.html +0 -779
  265. package/public/guides/shopify.html +0 -726
  266. package/public/guides/squarespace.html +0 -749
  267. package/public/guides/wix.html +0 -747
  268. package/public/guides/woocommerce.html +0 -733
  269. package/public/index.html +0 -3835
  270. package/public/learn.html +0 -396
  271. package/public/logo.jpeg +0 -0
  272. package/public/og-image-icon.png +0 -0
  273. package/public/og-image.png +0 -0
  274. package/public/robots.txt +0 -6
  275. package/public/site.webmanifest +0 -31
  276. package/public/sitemap.xml +0 -69
  277. package/public/social/linkedin-banner-1128x191.png +0 -0
  278. package/public/social/temp.PNG +0 -0
  279. package/public/social/x-header-1500x500.png +0 -0
  280. package/public/verify.html +0 -410
  281. package/scripts/generate-favicons.js +0 -44
  282. package/scripts/generate-ico.js +0 -23
  283. package/scripts/generate-og-image.js +0 -45
  284. package/scripts/reset-db.ts +0 -77
  285. package/scripts/seed-db.ts +0 -71
  286. package/scripts/setup-benchmark-db.js +0 -70
  287. package/src/api/server.ts +0 -266
  288. package/src/cli/index.ts +0 -302
  289. package/src/compliance/compliance-generator.ts +0 -452
  290. package/src/compliance/index.ts +0 -28
  291. package/src/compliance/types.ts +0 -170
  292. package/src/db/index.ts +0 -28
  293. package/src/db/schema.ts +0 -84
  294. package/src/feed-analyzer/index.ts +0 -34
  295. package/src/feed-analyzer/types.ts +0 -354
  296. package/src/generator/key-generator.ts +0 -124
  297. package/src/generator/profile-builder.ts +0 -402
  298. package/src/index.ts +0 -105
  299. package/src/security/security-scanner.ts +0 -604
  300. package/src/security/types.ts +0 -55
  301. package/src/services/directory.ts +0 -434
  302. package/src/simulator/agent-simulator.ts +0 -941
  303. package/src/types/generator.ts +0 -140
  304. package/src/types/ucp-profile.ts +0 -140
  305. package/src/types/validation.ts +0 -89
  306. package/src/validator/index.ts +0 -194
  307. package/src/validator/network-validator.ts +0 -417
  308. package/src/validator/rules-validator.ts +0 -297
  309. package/src/validator/structural-validator.ts +0 -476
  310. package/tests/fixtures/non-compliant-profile.json +0 -25
  311. package/tests/fixtures/official-sample-profile.json +0 -75
  312. package/tests/integration/benchmark.test.ts +0 -207
  313. package/tests/integration/database.test.ts +0 -163
  314. package/tests/integration/directory-api.test.ts +0 -268
  315. package/tests/integration/simulate-api.test.ts +0 -230
  316. package/tests/integration/validate-api.test.ts +0 -269
  317. package/tests/setup.ts +0 -15
  318. package/tests/unit/agent-simulator.test.ts +0 -575
  319. package/tests/unit/compliance-generator.test.ts +0 -374
  320. package/tests/unit/directory-service.test.ts +0 -272
  321. package/tests/unit/feed-analyzer.test.ts +0 -517
  322. package/tests/unit/lint-suggestions.test.ts +0 -423
  323. package/tests/unit/official-samples.test.ts +0 -211
  324. package/tests/unit/pdf-report.test.ts +0 -390
  325. package/tests/unit/sdk-validator.test.ts +0 -531
  326. package/tests/unit/security-scanner.test.ts +0 -410
  327. package/tests/unit/validation.test.ts +0 -390
  328. package/tsconfig.json +0 -20
  329. package/vercel.json +0 -34
  330. package/vitest.config.ts +0 -22
@@ -1,390 +0,0 @@
1
- /**
2
- * Unit Tests for PDF Report Generation (Issue #7)
3
- * Tests the data transformation and formatting logic for PDF reports
4
- */
5
-
6
- import { describe, it, expect } from 'vitest';
7
-
8
- // Types matching the validation API response
9
- interface ValidationData {
10
- domain?: string;
11
- ucp?: {
12
- found: boolean;
13
- issues: Array<{ code: string; message: string; severity: 'error' | 'warn' }>;
14
- };
15
- schema?: {
16
- found: boolean;
17
- issues: Array<{ code: string; message: string; severity: 'error' | 'warn'; category?: string }>;
18
- stats: {
19
- products: number;
20
- returnPolicies: number;
21
- organizations?: number;
22
- };
23
- };
24
- ai_readiness?: {
25
- score: number;
26
- grade: string;
27
- label: string;
28
- };
29
- benchmark?: {
30
- percentile: number;
31
- total_sites_analyzed: number;
32
- avg_score?: number;
33
- };
34
- product_quality?: {
35
- completeness: number;
36
- };
37
- lint_suggestions?: Array<{
38
- severity: string;
39
- title: string;
40
- code: string;
41
- impact: string;
42
- fix?: string;
43
- codeSnippet?: string;
44
- docLink?: string;
45
- }>;
46
- }
47
-
48
- // Helper functions that mirror the PDF generation logic
49
- function getGradeColor(grade: string): [number, number, number] {
50
- const gradeColors: Record<string, [number, number, number]> = {
51
- 'A': [22, 163, 74], // Green
52
- 'B': [37, 99, 235], // Blue
53
- 'C': [202, 138, 4], // Yellow
54
- 'D': [234, 88, 12], // Orange
55
- 'F': [220, 38, 38] // Red
56
- };
57
- return gradeColors[grade] || gradeColors['F'];
58
- }
59
-
60
- function countIssuesBySeverity(issues: Array<{ severity: string }>): { errors: number; warnings: number } {
61
- return {
62
- errors: issues.filter(i => i.severity === 'error').length,
63
- warnings: issues.filter(i => i.severity === 'warn').length
64
- };
65
- }
66
-
67
- function truncateText(text: string, maxLength: number): string {
68
- if (text.length <= maxLength) return text;
69
- return text.substring(0, maxLength) + '...';
70
- }
71
-
72
- function generateFilename(domain: string): string {
73
- return `ucp-report-${domain.replace(/\./g, '-')}.pdf`;
74
- }
75
-
76
- function extractReportData(data: ValidationData, domain: string) {
77
- return {
78
- domain,
79
- score: data.ai_readiness?.score ?? 0,
80
- grade: data.ai_readiness?.grade ?? 'F',
81
- readinessLabel: data.ai_readiness?.label ?? 'Not Ready',
82
- ucpFound: data.ucp?.found ?? false,
83
- ucpIssues: data.ucp?.issues ?? [],
84
- schemaStats: data.schema?.stats ?? { products: 0, returnPolicies: 0 },
85
- schemaIssues: data.schema?.issues ?? [],
86
- productQuality: data.product_quality?.completeness ?? null,
87
- benchmark: data.benchmark ?? null,
88
- suggestions: data.lint_suggestions ?? [],
89
- };
90
- }
91
-
92
- describe('PDF Report Generation (Issue #7)', () => {
93
- describe('Grade Color Mapping', () => {
94
- it('should return green for grade A', () => {
95
- const color = getGradeColor('A');
96
- expect(color).toEqual([22, 163, 74]);
97
- });
98
-
99
- it('should return blue for grade B', () => {
100
- const color = getGradeColor('B');
101
- expect(color).toEqual([37, 99, 235]);
102
- });
103
-
104
- it('should return yellow for grade C', () => {
105
- const color = getGradeColor('C');
106
- expect(color).toEqual([202, 138, 4]);
107
- });
108
-
109
- it('should return orange for grade D', () => {
110
- const color = getGradeColor('D');
111
- expect(color).toEqual([234, 88, 12]);
112
- });
113
-
114
- it('should return red for grade F', () => {
115
- const color = getGradeColor('F');
116
- expect(color).toEqual([220, 38, 38]);
117
- });
118
-
119
- it('should default to red for unknown grade', () => {
120
- const color = getGradeColor('X');
121
- expect(color).toEqual([220, 38, 38]);
122
- });
123
- });
124
-
125
- describe('Issue Counting', () => {
126
- it('should correctly count errors and warnings', () => {
127
- const issues = [
128
- { severity: 'error', code: 'ERR1', message: 'Error 1' },
129
- { severity: 'error', code: 'ERR2', message: 'Error 2' },
130
- { severity: 'warn', code: 'WARN1', message: 'Warning 1' },
131
- ];
132
- const counts = countIssuesBySeverity(issues);
133
-
134
- expect(counts.errors).toBe(2);
135
- expect(counts.warnings).toBe(1);
136
- });
137
-
138
- it('should return zeros for empty array', () => {
139
- const counts = countIssuesBySeverity([]);
140
-
141
- expect(counts.errors).toBe(0);
142
- expect(counts.warnings).toBe(0);
143
- });
144
-
145
- it('should handle only errors', () => {
146
- const issues = [
147
- { severity: 'error', code: 'ERR1', message: 'Error 1' },
148
- { severity: 'error', code: 'ERR2', message: 'Error 2' },
149
- ];
150
- const counts = countIssuesBySeverity(issues);
151
-
152
- expect(counts.errors).toBe(2);
153
- expect(counts.warnings).toBe(0);
154
- });
155
-
156
- it('should handle only warnings', () => {
157
- const issues = [
158
- { severity: 'warn', code: 'WARN1', message: 'Warning 1' },
159
- { severity: 'warn', code: 'WARN2', message: 'Warning 2' },
160
- ];
161
- const counts = countIssuesBySeverity(issues);
162
-
163
- expect(counts.errors).toBe(0);
164
- expect(counts.warnings).toBe(2);
165
- });
166
- });
167
-
168
- describe('Text Truncation', () => {
169
- it('should not truncate short text', () => {
170
- const result = truncateText('Short text', 70);
171
- expect(result).toBe('Short text');
172
- });
173
-
174
- it('should truncate long text with ellipsis', () => {
175
- const longText = 'This is a very long message that should be truncated because it exceeds the maximum allowed length for display';
176
- const result = truncateText(longText, 70);
177
-
178
- expect(result.length).toBe(73); // 70 + '...'
179
- expect(result.endsWith('...')).toBe(true);
180
- });
181
-
182
- it('should handle exact length text', () => {
183
- const text = 'A'.repeat(70);
184
- const result = truncateText(text, 70);
185
-
186
- expect(result.length).toBe(70);
187
- expect(result.endsWith('...')).toBe(false);
188
- });
189
- });
190
-
191
- describe('Filename Generation', () => {
192
- it('should replace dots with dashes in domain', () => {
193
- const filename = generateFilename('example.com');
194
- expect(filename).toBe('ucp-report-example-com.pdf');
195
- });
196
-
197
- it('should handle subdomains', () => {
198
- const filename = generateFilename('shop.example.com');
199
- expect(filename).toBe('ucp-report-shop-example-com.pdf');
200
- });
201
-
202
- it('should handle multiple dots', () => {
203
- const filename = generateFilename('www.shop.example.co.uk');
204
- expect(filename).toBe('ucp-report-www-shop-example-co-uk.pdf');
205
- });
206
- });
207
-
208
- describe('Report Data Extraction', () => {
209
- it('should extract all fields from complete data', () => {
210
- const data: ValidationData = {
211
- ai_readiness: { score: 85, grade: 'B', label: 'Partially Ready' },
212
- ucp: { found: true, issues: [{ code: 'TEST', message: 'Test', severity: 'error' }] },
213
- schema: {
214
- found: true,
215
- issues: [{ code: 'SCHEMA_TEST', message: 'Schema test', severity: 'warn' }],
216
- stats: { products: 10, returnPolicies: 2 }
217
- },
218
- product_quality: { completeness: 78 },
219
- benchmark: { percentile: 75, total_sites_analyzed: 1000 },
220
- lint_suggestions: [{ severity: 'critical', title: 'Test', code: 'TEST', impact: 'Test impact' }]
221
- };
222
-
223
- const result = extractReportData(data, 'example.com');
224
-
225
- expect(result.domain).toBe('example.com');
226
- expect(result.score).toBe(85);
227
- expect(result.grade).toBe('B');
228
- expect(result.readinessLabel).toBe('Partially Ready');
229
- expect(result.ucpFound).toBe(true);
230
- expect(result.ucpIssues).toHaveLength(1);
231
- expect(result.schemaStats.products).toBe(10);
232
- expect(result.schemaStats.returnPolicies).toBe(2);
233
- expect(result.schemaIssues).toHaveLength(1);
234
- expect(result.productQuality).toBe(78);
235
- expect(result.benchmark?.percentile).toBe(75);
236
- expect(result.suggestions).toHaveLength(1);
237
- });
238
-
239
- it('should provide defaults for missing data', () => {
240
- const data: ValidationData = {};
241
-
242
- const result = extractReportData(data, 'test.com');
243
-
244
- expect(result.domain).toBe('test.com');
245
- expect(result.score).toBe(0);
246
- expect(result.grade).toBe('F');
247
- expect(result.readinessLabel).toBe('Not Ready');
248
- expect(result.ucpFound).toBe(false);
249
- expect(result.ucpIssues).toEqual([]);
250
- expect(result.schemaStats).toEqual({ products: 0, returnPolicies: 0 });
251
- expect(result.schemaIssues).toEqual([]);
252
- expect(result.productQuality).toBeNull();
253
- expect(result.benchmark).toBeNull();
254
- expect(result.suggestions).toEqual([]);
255
- });
256
-
257
- it('should handle partial data', () => {
258
- const data: ValidationData = {
259
- ai_readiness: { score: 45, grade: 'F', label: 'Not Ready' },
260
- ucp: { found: false, issues: [] },
261
- };
262
-
263
- const result = extractReportData(data, 'partial.com');
264
-
265
- expect(result.score).toBe(45);
266
- expect(result.ucpFound).toBe(false);
267
- expect(result.schemaStats).toEqual({ products: 0, returnPolicies: 0 });
268
- });
269
- });
270
-
271
- describe('PDF Content Sections', () => {
272
- it('should limit displayed issues to prevent overflow', () => {
273
- const issues = Array.from({ length: 20 }, (_, i) => ({
274
- code: `ERR${i}`,
275
- message: `Error message ${i}`,
276
- severity: 'error' as const
277
- }));
278
-
279
- // PDF logic limits to 8 issues
280
- const displayedIssues = issues.slice(0, 8);
281
- expect(displayedIssues).toHaveLength(8);
282
- });
283
-
284
- it('should limit displayed suggestions to prevent overflow', () => {
285
- const suggestions = Array.from({ length: 10 }, (_, i) => ({
286
- severity: 'warning',
287
- title: `Suggestion ${i}`,
288
- code: `SUGG${i}`,
289
- impact: `Impact ${i}`
290
- }));
291
-
292
- // PDF logic limits to 5 suggestions
293
- const displayedSuggestions = suggestions.slice(0, 5);
294
- expect(displayedSuggestions).toHaveLength(5);
295
- });
296
- });
297
-
298
- describe('Validation Data Requirements', () => {
299
- it('should validate that data is available before generating', () => {
300
- const data = null;
301
- const domain = null;
302
-
303
- const isValid = data !== null && domain !== null;
304
- expect(isValid).toBe(false);
305
- });
306
-
307
- it('should accept valid data for PDF generation', () => {
308
- const data: ValidationData = {
309
- ai_readiness: { score: 70, grade: 'C', label: 'Partially Ready' }
310
- };
311
- const domain = 'test.com';
312
-
313
- const isValid = data !== null && domain !== null;
314
- expect(isValid).toBe(true);
315
- });
316
- });
317
-
318
- describe('Brand Colors', () => {
319
- it('should use correct brand blue', () => {
320
- const brandBlue: [number, number, number] = [46, 134, 171];
321
- expect(brandBlue).toEqual([46, 134, 171]);
322
- });
323
-
324
- it('should use correct brand teal', () => {
325
- const brandTeal: [number, number, number] = [54, 181, 162];
326
- expect(brandTeal).toEqual([54, 181, 162]);
327
- });
328
-
329
- it('should use correct severity colors', () => {
330
- const severityColors = {
331
- error: [220, 38, 38],
332
- warn: [202, 138, 4]
333
- };
334
-
335
- expect(severityColors.error).toEqual([220, 38, 38]);
336
- expect(severityColors.warn).toEqual([202, 138, 4]);
337
- });
338
- });
339
- });
340
-
341
- describe('PDF Report Integration Requirements', () => {
342
- describe('Data Storage', () => {
343
- it('should store validation data in expected format', () => {
344
- // Simulates window.lastValidationData structure
345
- const storedData: ValidationData = {
346
- ai_readiness: { score: 85, grade: 'B', label: 'Partially Ready' },
347
- ucp: { found: true, issues: [] },
348
- schema: { found: true, issues: [], stats: { products: 5, returnPolicies: 1 } },
349
- lint_suggestions: []
350
- };
351
-
352
- expect(storedData.ai_readiness).toBeDefined();
353
- expect(storedData.ucp).toBeDefined();
354
- expect(storedData.schema).toBeDefined();
355
- expect(storedData.lint_suggestions).toBeDefined();
356
- });
357
-
358
- it('should store domain for filename generation', () => {
359
- // Simulates window.lastValidatedDomain
360
- const storedDomain = 'example.com';
361
-
362
- expect(storedDomain).toBeDefined();
363
- expect(typeof storedDomain).toBe('string');
364
- expect(storedDomain.length).toBeGreaterThan(0);
365
- });
366
- });
367
-
368
- describe('Download Trigger', () => {
369
- it('should generate correct filename from domain', () => {
370
- const domain = 'shop.example.com';
371
- const filename = `ucp-report-${domain.replace(/\./g, '-')}.pdf`;
372
-
373
- expect(filename).toBe('ucp-report-shop-example-com.pdf');
374
- });
375
- });
376
-
377
- describe('Analytics Event', () => {
378
- it('should include required tracking fields', () => {
379
- const eventData = {
380
- domain: 'example.com',
381
- score: 85,
382
- grade: 'B'
383
- };
384
-
385
- expect(eventData).toHaveProperty('domain');
386
- expect(eventData).toHaveProperty('score');
387
- expect(eventData).toHaveProperty('grade');
388
- });
389
- });
390
- });