@ucptools/validator 1.0.0 → 1.0.1

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 (236) hide show
  1. package/.claude/settings.local.json +60 -0
  2. package/.vercel/README.txt +11 -0
  3. package/.vercel/project.json +1 -0
  4. package/dist/cli/index.d.ts +6 -0
  5. package/dist/cli/index.d.ts.map +1 -0
  6. package/dist/cli/index.js +279 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/compliance/compliance-generator.d.ts +34 -0
  9. package/dist/compliance/compliance-generator.d.ts.map +1 -0
  10. package/dist/compliance/compliance-generator.js +320 -0
  11. package/dist/compliance/compliance-generator.js.map +1 -0
  12. package/dist/compliance/index.d.ts +8 -0
  13. package/dist/compliance/index.d.ts.map +1 -0
  14. package/dist/compliance/index.js +17 -0
  15. package/dist/compliance/index.js.map +1 -0
  16. package/dist/compliance/templates.d.ts +34 -0
  17. package/dist/compliance/templates.d.ts.map +1 -0
  18. package/{src/compliance/templates.ts → dist/compliance/templates.js} +117 -155
  19. package/dist/compliance/templates.js.map +1 -0
  20. package/dist/compliance/types.d.ts +64 -0
  21. package/dist/compliance/types.d.ts.map +1 -0
  22. package/dist/compliance/types.js +64 -0
  23. package/dist/compliance/types.js.map +1 -0
  24. package/dist/db/index.d.ts +11 -0
  25. package/dist/db/index.d.ts.map +1 -0
  26. package/dist/db/index.js +63 -0
  27. package/dist/db/index.js.map +1 -0
  28. package/dist/db/schema.d.ts +444 -0
  29. package/dist/db/schema.d.ts.map +1 -0
  30. package/dist/db/schema.js +65 -0
  31. package/dist/db/schema.js.map +1 -0
  32. package/dist/feed-analyzer/feed-analyzer.d.ts +26 -0
  33. package/dist/feed-analyzer/feed-analyzer.d.ts.map +1 -0
  34. package/{src/feed-analyzer/feed-analyzer.ts → dist/feed-analyzer/feed-analyzer.js} +642 -726
  35. package/dist/feed-analyzer/feed-analyzer.js.map +1 -0
  36. package/dist/feed-analyzer/index.d.ts +8 -0
  37. package/dist/feed-analyzer/index.d.ts.map +1 -0
  38. package/dist/feed-analyzer/index.js +19 -0
  39. package/dist/feed-analyzer/index.js.map +1 -0
  40. package/dist/feed-analyzer/types.d.ts +204 -0
  41. package/dist/feed-analyzer/types.d.ts.map +1 -0
  42. package/dist/feed-analyzer/types.js +162 -0
  43. package/dist/feed-analyzer/types.js.map +1 -0
  44. package/{src/generator/index.ts → dist/generator/index.d.ts} +1 -1
  45. package/dist/generator/index.d.ts.map +1 -0
  46. package/dist/generator/index.js +13 -0
  47. package/dist/generator/index.js.map +1 -0
  48. package/dist/generator/key-generator.d.ts +24 -0
  49. package/dist/generator/key-generator.d.ts.map +1 -0
  50. package/dist/generator/key-generator.js +144 -0
  51. package/dist/generator/key-generator.js.map +1 -0
  52. package/dist/generator/profile-builder.d.ts +15 -0
  53. package/dist/generator/profile-builder.d.ts.map +1 -0
  54. package/dist/generator/profile-builder.js +338 -0
  55. package/dist/generator/profile-builder.js.map +1 -0
  56. package/dist/hosting/artifacts-generator.d.ts +10 -0
  57. package/dist/hosting/artifacts-generator.d.ts.map +1 -0
  58. package/{src/hosting/artifacts-generator.ts → dist/hosting/artifacts-generator.js} +191 -241
  59. package/dist/hosting/artifacts-generator.js.map +1 -0
  60. package/{src/hosting/index.ts → dist/hosting/index.d.ts} +1 -1
  61. package/dist/hosting/index.d.ts.map +1 -0
  62. package/dist/hosting/index.js +10 -0
  63. package/dist/hosting/index.js.map +1 -0
  64. package/dist/index.d.ts +18 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +78 -0
  67. package/dist/index.js.map +1 -0
  68. package/{src/security/index.ts → dist/security/index.d.ts} +8 -15
  69. package/dist/security/index.d.ts.map +1 -0
  70. package/dist/security/index.js +12 -0
  71. package/dist/security/index.js.map +1 -0
  72. package/dist/security/security-scanner.d.ts +10 -0
  73. package/dist/security/security-scanner.d.ts.map +1 -0
  74. package/dist/security/security-scanner.js +541 -0
  75. package/dist/security/security-scanner.js.map +1 -0
  76. package/dist/security/types.d.ts +48 -0
  77. package/dist/security/types.d.ts.map +1 -0
  78. package/dist/security/types.js +21 -0
  79. package/dist/security/types.js.map +1 -0
  80. package/dist/services/directory.d.ts +104 -0
  81. package/dist/services/directory.d.ts.map +1 -0
  82. package/dist/services/directory.js +333 -0
  83. package/dist/services/directory.js.map +1 -0
  84. package/dist/simulator/agent-simulator.d.ts +69 -0
  85. package/dist/simulator/agent-simulator.d.ts.map +1 -0
  86. package/{src/simulator/agent-simulator.ts → dist/simulator/agent-simulator.js} +650 -941
  87. package/dist/simulator/agent-simulator.js.map +1 -0
  88. package/{src/simulator/index.ts → dist/simulator/index.d.ts} +7 -7
  89. package/dist/simulator/index.d.ts.map +1 -0
  90. package/dist/simulator/index.js +23 -0
  91. package/dist/simulator/index.js.map +1 -0
  92. package/{src/simulator/types.ts → dist/simulator/types.d.ts} +145 -170
  93. package/dist/simulator/types.d.ts.map +1 -0
  94. package/dist/simulator/types.js +18 -0
  95. package/dist/simulator/types.js.map +1 -0
  96. package/dist/types/generator.d.ts +106 -0
  97. package/dist/types/generator.d.ts.map +1 -0
  98. package/dist/types/generator.js +6 -0
  99. package/dist/types/generator.js.map +1 -0
  100. package/{src/types/index.ts → dist/types/index.d.ts} +1 -1
  101. package/dist/types/index.d.ts.map +1 -0
  102. package/dist/types/index.js +23 -0
  103. package/dist/types/index.js.map +1 -0
  104. package/dist/types/ucp-profile.d.ts +103 -0
  105. package/dist/types/ucp-profile.d.ts.map +1 -0
  106. package/dist/types/ucp-profile.js +45 -0
  107. package/dist/types/ucp-profile.js.map +1 -0
  108. package/dist/types/validation.d.ts +68 -0
  109. package/dist/types/validation.d.ts.map +1 -0
  110. package/dist/types/validation.js +32 -0
  111. package/dist/types/validation.js.map +1 -0
  112. package/dist/validator/index.d.ts +26 -0
  113. package/dist/validator/index.d.ts.map +1 -0
  114. package/dist/validator/index.js +161 -0
  115. package/dist/validator/index.js.map +1 -0
  116. package/dist/validator/network-validator.d.ts +28 -0
  117. package/dist/validator/network-validator.d.ts.map +1 -0
  118. package/dist/validator/network-validator.js +319 -0
  119. package/dist/validator/network-validator.js.map +1 -0
  120. package/dist/validator/rules-validator.d.ts +11 -0
  121. package/dist/validator/rules-validator.d.ts.map +1 -0
  122. package/dist/validator/rules-validator.js +257 -0
  123. package/dist/validator/rules-validator.js.map +1 -0
  124. package/dist/validator/sdk-validator.d.ts +58 -0
  125. package/dist/validator/sdk-validator.d.ts.map +1 -0
  126. package/{src/validator/sdk-validator.ts → dist/validator/sdk-validator.js} +273 -330
  127. package/dist/validator/sdk-validator.js.map +1 -0
  128. package/dist/validator/structural-validator.d.ts +11 -0
  129. package/dist/validator/structural-validator.d.ts.map +1 -0
  130. package/dist/validator/structural-validator.js +415 -0
  131. package/dist/validator/structural-validator.js.map +1 -0
  132. package/package.json +1 -1
  133. package/publish-output.txt +0 -0
  134. package/CLAUDE.md +0 -109
  135. package/api/analyze-feed.js +0 -140
  136. package/api/badge.js +0 -185
  137. package/api/benchmark.js +0 -177
  138. package/api/directory-stats.ts +0 -29
  139. package/api/directory.ts +0 -73
  140. package/api/generate-compliance.js +0 -143
  141. package/api/generate-schema.js +0 -457
  142. package/api/generate.js +0 -132
  143. package/api/security-scan.js +0 -133
  144. package/api/simulate.js +0 -187
  145. package/api/tsconfig.json +0 -10
  146. package/api/validate.js +0 -1351
  147. package/apify-actor/.actor/actor.json +0 -68
  148. package/apify-actor/.actor/input_schema.json +0 -32
  149. package/apify-actor/APIFY-STORE-LISTING.md +0 -412
  150. package/apify-actor/Dockerfile +0 -8
  151. package/apify-actor/README.md +0 -166
  152. package/apify-actor/main.ts +0 -111
  153. package/apify-actor/package.json +0 -17
  154. package/apify-actor/src/main.js +0 -199
  155. package/docs/BRAND-IDENTITY.md +0 -238
  156. package/docs/BRAND-STYLE-GUIDE.md +0 -356
  157. package/drizzle/0000_black_king_cobra.sql +0 -39
  158. package/drizzle/meta/0000_snapshot.json +0 -309
  159. package/drizzle/meta/_journal.json +0 -13
  160. package/drizzle.config.ts +0 -10
  161. package/public/.well-known/ucp +0 -25
  162. package/public/android-chrome-192x192.png +0 -0
  163. package/public/android-chrome-512x512.png +0 -0
  164. package/public/apple-touch-icon.png +0 -0
  165. package/public/brand.css +0 -321
  166. package/public/directory.html +0 -701
  167. package/public/favicon-16x16.png +0 -0
  168. package/public/favicon-32x32.png +0 -0
  169. package/public/favicon.ico +0 -0
  170. package/public/guides/bigcommerce.html +0 -743
  171. package/public/guides/fastucp.html +0 -838
  172. package/public/guides/magento.html +0 -779
  173. package/public/guides/shopify.html +0 -726
  174. package/public/guides/squarespace.html +0 -749
  175. package/public/guides/wix.html +0 -747
  176. package/public/guides/woocommerce.html +0 -733
  177. package/public/index.html +0 -3835
  178. package/public/learn.html +0 -396
  179. package/public/logo.jpeg +0 -0
  180. package/public/og-image-icon.png +0 -0
  181. package/public/og-image.png +0 -0
  182. package/public/robots.txt +0 -6
  183. package/public/site.webmanifest +0 -31
  184. package/public/sitemap.xml +0 -69
  185. package/public/social/linkedin-banner-1128x191.png +0 -0
  186. package/public/social/temp.PNG +0 -0
  187. package/public/social/x-header-1500x500.png +0 -0
  188. package/public/verify.html +0 -410
  189. package/scripts/generate-favicons.js +0 -44
  190. package/scripts/generate-ico.js +0 -23
  191. package/scripts/generate-og-image.js +0 -45
  192. package/scripts/reset-db.ts +0 -77
  193. package/scripts/seed-db.ts +0 -71
  194. package/scripts/setup-benchmark-db.js +0 -70
  195. package/src/api/server.ts +0 -266
  196. package/src/cli/index.ts +0 -302
  197. package/src/compliance/compliance-generator.ts +0 -452
  198. package/src/compliance/index.ts +0 -28
  199. package/src/compliance/types.ts +0 -170
  200. package/src/db/index.ts +0 -28
  201. package/src/db/schema.ts +0 -84
  202. package/src/feed-analyzer/index.ts +0 -34
  203. package/src/feed-analyzer/types.ts +0 -354
  204. package/src/generator/key-generator.ts +0 -124
  205. package/src/generator/profile-builder.ts +0 -402
  206. package/src/index.ts +0 -105
  207. package/src/security/security-scanner.ts +0 -604
  208. package/src/security/types.ts +0 -55
  209. package/src/services/directory.ts +0 -434
  210. package/src/types/generator.ts +0 -140
  211. package/src/types/ucp-profile.ts +0 -140
  212. package/src/types/validation.ts +0 -89
  213. package/src/validator/index.ts +0 -194
  214. package/src/validator/network-validator.ts +0 -417
  215. package/src/validator/rules-validator.ts +0 -297
  216. package/src/validator/structural-validator.ts +0 -476
  217. package/tests/fixtures/non-compliant-profile.json +0 -25
  218. package/tests/fixtures/official-sample-profile.json +0 -75
  219. package/tests/integration/benchmark.test.ts +0 -207
  220. package/tests/integration/database.test.ts +0 -163
  221. package/tests/integration/directory-api.test.ts +0 -268
  222. package/tests/integration/simulate-api.test.ts +0 -230
  223. package/tests/integration/validate-api.test.ts +0 -269
  224. package/tests/setup.ts +0 -15
  225. package/tests/unit/agent-simulator.test.ts +0 -575
  226. package/tests/unit/compliance-generator.test.ts +0 -374
  227. package/tests/unit/directory-service.test.ts +0 -272
  228. package/tests/unit/feed-analyzer.test.ts +0 -517
  229. package/tests/unit/lint-suggestions.test.ts +0 -423
  230. package/tests/unit/official-samples.test.ts +0 -211
  231. package/tests/unit/pdf-report.test.ts +0 -390
  232. package/tests/unit/sdk-validator.test.ts +0 -531
  233. package/tests/unit/security-scanner.test.ts +0 -410
  234. package/tests/unit/validation.test.ts +0 -390
  235. package/vercel.json +0 -34
  236. package/vitest.config.ts +0 -22
@@ -1,230 +0,0 @@
1
- /**
2
- * Integration tests for the AI Agent Simulation API
3
- */
4
-
5
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
6
-
7
- // Mock profile for testing
8
- const mockProfile = {
9
- ucp: {
10
- version: '2026-01-11',
11
- services: {
12
- 'dev.ucp.shopping': {
13
- version: '2026-01-11',
14
- spec: 'https://ucp.dev/specs/shopping',
15
- rest: {
16
- schema: 'https://example.com/api/openapi.json',
17
- endpoint: 'https://example.com/api',
18
- },
19
- },
20
- },
21
- capabilities: [
22
- {
23
- name: 'dev.ucp.shopping.checkout',
24
- version: '2026-01-11',
25
- spec: 'https://ucp.dev/specs/shopping/checkout',
26
- schema: 'https://ucp.dev/schemas/shopping/checkout.json',
27
- },
28
- ],
29
- },
30
- signing_keys: [
31
- {
32
- kty: 'EC',
33
- crv: 'P-256',
34
- x: 'test-x',
35
- y: 'test-y',
36
- kid: 'key-1',
37
- },
38
- ],
39
- };
40
-
41
- // Mock fetch
42
- const originalFetch = global.fetch;
43
-
44
- describe('Simulate API', () => {
45
- beforeEach(() => {
46
- // Reset fetch mock
47
- global.fetch = vi.fn();
48
- });
49
-
50
- afterEach(() => {
51
- global.fetch = originalFetch;
52
- vi.restoreAllMocks();
53
- });
54
-
55
- describe('simulateAgentInteraction function', () => {
56
- it('should simulate agent interaction for valid domain', async () => {
57
- const mockFetch = global.fetch as ReturnType<typeof vi.fn>;
58
-
59
- // Mock successful profile fetch
60
- mockFetch.mockImplementation((url: string) => {
61
- if (url.includes('.well-known/ucp')) {
62
- return Promise.resolve({
63
- ok: true,
64
- status: 200,
65
- headers: new Map([['content-type', 'application/json']]),
66
- json: () => Promise.resolve(mockProfile),
67
- });
68
- }
69
- // Default to success for other URLs
70
- return Promise.resolve({
71
- ok: true,
72
- status: 200,
73
- headers: new Map([['content-type', 'application/json']]),
74
- json: () => Promise.resolve({ properties: { checkout_id: {} } }),
75
- });
76
- });
77
-
78
- const { simulateAgentInteraction } = await import('../../src/simulator/index.js');
79
- const result = await simulateAgentInteraction('example.com', { timeoutMs: 10000 });
80
-
81
- expect(result.ok).toBe(true);
82
- expect(result.domain).toBe('example.com');
83
- expect(result.discovery.success).toBe(true);
84
- expect(result.overallScore).toBeGreaterThan(0);
85
- });
86
-
87
- it('should return low score for unreachable domain', async () => {
88
- const mockFetch = global.fetch as ReturnType<typeof vi.fn>;
89
-
90
- mockFetch.mockResolvedValue({
91
- ok: false,
92
- status: 404,
93
- });
94
-
95
- const { simulateAgentInteraction } = await import('../../src/simulator/index.js');
96
- const result = await simulateAgentInteraction('nonexistent.example.com', { timeoutMs: 5000 });
97
-
98
- expect(result.ok).toBe(false);
99
- expect(result.overallScore).toBe(0);
100
- expect(result.recommendations).toContain('Ensure UCP profile is accessible at /.well-known/ucp or /.well-known/ucp.json');
101
- });
102
-
103
- it('should detect missing checkout capability', async () => {
104
- const mockFetch = global.fetch as ReturnType<typeof vi.fn>;
105
-
106
- const profileWithoutCheckout = {
107
- ucp: {
108
- version: '2026-01-11',
109
- services: {
110
- 'dev.ucp.shopping': {
111
- version: '2026-01-11',
112
- spec: 'https://ucp.dev/specs/shopping',
113
- rest: {
114
- schema: 'https://example.com/api/openapi.json',
115
- endpoint: 'https://example.com/api',
116
- },
117
- },
118
- },
119
- capabilities: [],
120
- },
121
- };
122
-
123
- mockFetch.mockImplementation((url: string) => {
124
- if (url.includes('.well-known/ucp')) {
125
- return Promise.resolve({
126
- ok: true,
127
- status: 200,
128
- headers: new Map([['content-type', 'application/json']]),
129
- json: () => Promise.resolve(profileWithoutCheckout),
130
- });
131
- }
132
- return Promise.resolve({ ok: true, status: 200 });
133
- });
134
-
135
- const { simulateAgentInteraction } = await import('../../src/simulator/index.js');
136
- const result = await simulateAgentInteraction('example.com', { timeoutMs: 10000 });
137
-
138
- expect(result.checkout?.canCreateCheckout).toBe(false);
139
- expect(result.recommendations).toContain('Add checkout capability (dev.ucp.shopping.checkout) to enable purchases');
140
- });
141
-
142
- it('should include all simulation phases', async () => {
143
- const mockFetch = global.fetch as ReturnType<typeof vi.fn>;
144
-
145
- mockFetch.mockImplementation((url: string) => {
146
- if (url.includes('.well-known/ucp')) {
147
- return Promise.resolve({
148
- ok: true,
149
- status: 200,
150
- headers: new Map([['content-type', 'application/json']]),
151
- json: () => Promise.resolve(mockProfile),
152
- });
153
- }
154
- return Promise.resolve({
155
- ok: true,
156
- status: 200,
157
- headers: new Map([['content-type', 'application/json']]),
158
- json: () => Promise.resolve({}),
159
- });
160
- });
161
-
162
- const { simulateAgentInteraction } = await import('../../src/simulator/index.js');
163
- const result = await simulateAgentInteraction('example.com', {
164
- timeoutMs: 10000,
165
- testCheckoutFlow: true,
166
- });
167
-
168
- // Check all phases are present
169
- expect(result.discovery).toBeDefined();
170
- expect(result.capabilities).toBeDefined();
171
- expect(result.services).toBeDefined();
172
- expect(result.restApi).toBeDefined();
173
- expect(result.checkout).toBeDefined();
174
- expect(result.payment).toBeDefined();
175
- expect(result.summary).toBeDefined();
176
- });
177
- });
178
-
179
- describe('API response structure', () => {
180
- it('should generate correct grade from score', async () => {
181
- const mockFetch = global.fetch as ReturnType<typeof vi.fn>;
182
-
183
- mockFetch.mockImplementation((url: string) => {
184
- if (url.includes('.well-known/ucp')) {
185
- return Promise.resolve({
186
- ok: true,
187
- status: 200,
188
- headers: new Map([['content-type', 'application/json']]),
189
- json: () => Promise.resolve(mockProfile),
190
- });
191
- }
192
- return Promise.resolve({
193
- ok: true,
194
- status: 200,
195
- headers: new Map([['content-type', 'application/json']]),
196
- json: () => Promise.resolve({ properties: { checkout_id: {} } }),
197
- });
198
- });
199
-
200
- const { simulateAgentInteraction } = await import('../../src/simulator/index.js');
201
- const result = await simulateAgentInteraction('example.com', { timeoutMs: 10000 });
202
-
203
- // Score should be between 0-100
204
- expect(result.overallScore).toBeGreaterThanOrEqual(0);
205
- expect(result.overallScore).toBeLessThanOrEqual(100);
206
- });
207
-
208
- it('should include timing information', async () => {
209
- const mockFetch = global.fetch as ReturnType<typeof vi.fn>;
210
-
211
- mockFetch.mockImplementation((url: string) => {
212
- if (url.includes('.well-known/ucp')) {
213
- return Promise.resolve({
214
- ok: true,
215
- status: 200,
216
- headers: new Map([['content-type', 'application/json']]),
217
- json: () => Promise.resolve(mockProfile),
218
- });
219
- }
220
- return Promise.resolve({ ok: true, status: 200 });
221
- });
222
-
223
- const { simulateAgentInteraction } = await import('../../src/simulator/index.js');
224
- const result = await simulateAgentInteraction('example.com', { timeoutMs: 10000 });
225
-
226
- expect(result.simulatedAt).toBeDefined();
227
- expect(result.durationMs).toBeGreaterThanOrEqual(0);
228
- });
229
- });
230
- });
@@ -1,269 +0,0 @@
1
- /**
2
- * Integration Tests for Validate API - Lint Suggestions (Issue #9)
3
- * Tests that the validate endpoint returns lint_suggestions in the response
4
- */
5
-
6
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
7
-
8
- // Mock validation response structure
9
- interface ValidationResponse {
10
- domain: string;
11
- ucp: {
12
- found: boolean;
13
- issues: Array<{ code: string; message: string; severity: string }>;
14
- };
15
- schema: {
16
- found: boolean;
17
- issues: Array<{ code: string; message: string; severity: string; 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
- lint_suggestions?: Array<{
30
- severity: string;
31
- title: string;
32
- code: string;
33
- impact: string;
34
- fix?: string;
35
- codeSnippet?: string;
36
- docLink?: string;
37
- generatorLink?: string;
38
- }>;
39
- }
40
-
41
- // Since we can't easily test the actual API endpoint in unit tests,
42
- // we'll test the lint_suggestions structure requirements
43
-
44
- describe('Validate API - Lint Suggestions Response (Issue #9)', () => {
45
- describe('Response Structure', () => {
46
- it('should include lint_suggestions array in response', () => {
47
- // Mock a typical response with issues
48
- const mockResponse: ValidationResponse = {
49
- domain: 'example.com',
50
- ucp: {
51
- found: false,
52
- issues: [{ code: 'UCP_FETCH_FAILED', message: 'No UCP profile found', severity: 'error' }]
53
- },
54
- schema: {
55
- found: true,
56
- issues: [
57
- { code: 'SCHEMA_NO_RETURN_POLICY', message: 'No return policy', severity: 'error', category: 'schema' }
58
- ],
59
- stats: { products: 5, returnPolicies: 0, organizations: 1 }
60
- },
61
- ai_readiness: {
62
- score: 45,
63
- grade: 'F',
64
- label: 'Not Ready'
65
- },
66
- lint_suggestions: [
67
- {
68
- severity: 'critical',
69
- title: 'Create a UCP Profile',
70
- code: 'UCP_FETCH_FAILED',
71
- impact: 'AI shopping agents cannot discover your store without a UCP profile',
72
- docLink: 'https://ucp.dev/docs/getting-started',
73
- generatorLink: '/generate'
74
- },
75
- {
76
- severity: 'critical',
77
- title: 'Add MerchantReturnPolicy Schema',
78
- code: 'SCHEMA_NO_RETURN_POLICY',
79
- impact: 'Required for AI commerce eligibility (Jan 2026 deadline)',
80
- docLink: 'https://schema.org/MerchantReturnPolicy',
81
- generatorLink: '/generate?tab=schema'
82
- }
83
- ]
84
- };
85
-
86
- // Verify structure
87
- expect(mockResponse.lint_suggestions).toBeDefined();
88
- expect(Array.isArray(mockResponse.lint_suggestions)).toBe(true);
89
- expect(mockResponse.lint_suggestions!.length).toBeGreaterThan(0);
90
- });
91
-
92
- it('each suggestion should have required fields', () => {
93
- const suggestion = {
94
- severity: 'critical',
95
- title: 'Create a UCP Profile',
96
- code: 'UCP_FETCH_FAILED',
97
- impact: 'AI shopping agents cannot discover your store without a UCP profile'
98
- };
99
-
100
- expect(suggestion).toHaveProperty('severity');
101
- expect(suggestion).toHaveProperty('title');
102
- expect(suggestion).toHaveProperty('code');
103
- expect(suggestion).toHaveProperty('impact');
104
- });
105
-
106
- it('severity should be valid enum value', () => {
107
- const validSeverities = ['critical', 'warning', 'info'];
108
-
109
- const suggestions = [
110
- { severity: 'critical', title: 'Test', code: 'TEST', impact: 'Test' },
111
- { severity: 'warning', title: 'Test', code: 'TEST', impact: 'Test' },
112
- { severity: 'info', title: 'Test', code: 'TEST', impact: 'Test' }
113
- ];
114
-
115
- suggestions.forEach(s => {
116
- expect(validSeverities).toContain(s.severity);
117
- });
118
- });
119
- });
120
-
121
- describe('Suggestion Content Quality', () => {
122
- it('should provide actionable fix guidance', () => {
123
- const suggestion = {
124
- severity: 'critical',
125
- title: 'Add UCP Version',
126
- code: 'UCP_MISSING_VERSION',
127
- impact: 'Agents cannot determine compatibility without a version',
128
- fix: 'Add a version field in YYYY-MM-DD format',
129
- codeSnippet: '"version": "2026-05-01"',
130
- docLink: 'https://ucp.dev/docs/versioning'
131
- };
132
-
133
- // Should have either fix text or code snippet
134
- expect(suggestion.fix || suggestion.codeSnippet).toBeDefined();
135
- });
136
-
137
- it('should include documentation link when available', () => {
138
- const suggestion = {
139
- severity: 'critical',
140
- title: 'Add MerchantReturnPolicy Schema',
141
- code: 'SCHEMA_NO_RETURN_POLICY',
142
- impact: 'Required for AI commerce eligibility',
143
- docLink: 'https://schema.org/MerchantReturnPolicy'
144
- };
145
-
146
- expect(suggestion.docLink).toMatch(/^https?:\/\//);
147
- });
148
-
149
- it('should include generator link for actionable issues', () => {
150
- const suggestion = {
151
- severity: 'critical',
152
- title: 'Create a UCP Profile',
153
- code: 'UCP_FETCH_FAILED',
154
- impact: 'AI shopping agents cannot discover your store',
155
- generatorLink: '/generate'
156
- };
157
-
158
- expect(suggestion.generatorLink).toBe('/generate');
159
- });
160
- });
161
-
162
- describe('Issue Code Mapping', () => {
163
- const knownIssueCodes = [
164
- // UCP Critical
165
- 'UCP_FETCH_FAILED',
166
- 'UCP_MISSING_ROOT',
167
- 'UCP_MISSING_VERSION',
168
- 'UCP_INVALID_VERSION',
169
- 'UCP_MISSING_SERVICES',
170
- 'UCP_MISSING_CAPABILITIES',
171
- 'UCP_MISSING_KEYS',
172
- 'UCP_ENDPOINT_NOT_HTTPS',
173
- 'UCP_NS_MISMATCH',
174
- // Schema Critical
175
- 'SCHEMA_NO_RETURN_POLICY',
176
- 'SCHEMA_NO_SHIPPING',
177
- // UCP Warnings
178
- 'UCP_NO_TRANSPORT',
179
- 'UCP_TRAILING_SLASH',
180
- 'UCP_ORPHAN_EXT',
181
- // Schema Warnings
182
- 'SCHEMA_NO_ORG',
183
- 'ORG_NO_NAME',
184
- 'SCHEMA_RETURN_NO_COUNTRY',
185
- 'SCHEMA_RETURN_NO_CATEGORY',
186
- // Product Warnings
187
- 'PRODUCT_NO_DESCRIPTION',
188
- 'PRODUCT_NO_IMAGE',
189
- // Contextual
190
- 'SUGGESTION_ADD_CHECKOUT',
191
- 'SUGGESTION_ADD_PRODUCTS',
192
- ];
193
-
194
- it('should have mappings for all known issue codes', () => {
195
- // This test ensures we have coverage for all common issues
196
- expect(knownIssueCodes.length).toBeGreaterThan(20);
197
- });
198
-
199
- it('critical issues should be sorted first', () => {
200
- const suggestions = [
201
- { severity: 'warning', title: 'Warning', code: 'WARN1', impact: 'Test' },
202
- { severity: 'critical', title: 'Critical', code: 'CRIT1', impact: 'Test' },
203
- { severity: 'info', title: 'Info', code: 'INFO1', impact: 'Test' },
204
- ];
205
-
206
- // Sort by severity
207
- const severityOrder: Record<string, number> = { critical: 0, warning: 1, info: 2 };
208
- const sorted = [...suggestions].sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
209
-
210
- expect(sorted[0].severity).toBe('critical');
211
- expect(sorted[1].severity).toBe('warning');
212
- expect(sorted[2].severity).toBe('info');
213
- });
214
- });
215
- });
216
-
217
- describe('Validate API - PDF Report Data (Issue #7)', () => {
218
- describe('Response Data for PDF Generation', () => {
219
- it('should include all data needed for PDF report', () => {
220
- const mockResponse: ValidationResponse = {
221
- domain: 'example.com',
222
- ucp: {
223
- found: true,
224
- issues: []
225
- },
226
- schema: {
227
- found: true,
228
- issues: [],
229
- stats: { products: 10, returnPolicies: 1, organizations: 1 }
230
- },
231
- ai_readiness: {
232
- score: 85,
233
- grade: 'B',
234
- label: 'Partially Ready'
235
- },
236
- lint_suggestions: []
237
- };
238
-
239
- // Required for PDF header
240
- expect(mockResponse.domain).toBeDefined();
241
- expect(mockResponse.ai_readiness.grade).toBeDefined();
242
- expect(mockResponse.ai_readiness.score).toBeDefined();
243
- expect(mockResponse.ai_readiness.label).toBeDefined();
244
-
245
- // Required for PDF sections
246
- expect(mockResponse.ucp).toBeDefined();
247
- expect(mockResponse.ucp.found).toBeDefined();
248
- expect(mockResponse.schema).toBeDefined();
249
- expect(mockResponse.schema.stats).toBeDefined();
250
-
251
- // Required for recommendations
252
- expect(mockResponse.lint_suggestions).toBeDefined();
253
- });
254
-
255
- it('should have grade within valid range A-F', () => {
256
- const validGrades = ['A', 'B', 'C', 'D', 'F'];
257
- const grade = 'B';
258
-
259
- expect(validGrades).toContain(grade);
260
- });
261
-
262
- it('should have score within 0-100 range', () => {
263
- const score = 85;
264
-
265
- expect(score).toBeGreaterThanOrEqual(0);
266
- expect(score).toBeLessThanOrEqual(100);
267
- });
268
- });
269
- });
package/tests/setup.ts DELETED
@@ -1,15 +0,0 @@
1
- /**
2
- * Vitest Test Setup
3
- * Runs before all tests
4
- */
5
-
6
- import { config } from 'dotenv';
7
- import { resolve } from 'path';
8
-
9
- // Load environment variables from .env.local
10
- config({ path: resolve(process.cwd(), '.env.local') });
11
-
12
- // Verify DATABASE_URL is set for integration tests
13
- if (!process.env.DATABASE_URL) {
14
- console.warn('⚠️ DATABASE_URL not set - integration tests will be skipped');
15
- }