@@ -14,6 +14,10 @@ import {
1414 InstalledAppSummarySchema ,
1515 ListInstalledAppsRequestSchema ,
1616 ListInstalledAppsResponseSchema ,
17+ PreviewRequestSchema ,
18+ PreviewObjectSummarySchema ,
19+ PreviewViewSummarySchema ,
20+ PreviewResponseSchema ,
1721} from './app-store.zod' ;
1822
1923describe ( 'ReviewModerationStatusSchema' , ( ) => {
@@ -388,3 +392,180 @@ describe('ListInstalledAppsResponseSchema', () => {
388392 expect ( parsed . total ) . toBe ( 1 ) ;
389393 } ) ;
390394} ) ;
395+
396+ // ==========================================
397+ // Preview / Demo Mode Tests
398+ // ==========================================
399+
400+ describe ( 'PreviewRequestSchema' , ( ) => {
401+ it ( 'should accept minimal preview request' , ( ) => {
402+ const request = { listingId : 'listing-001' } ;
403+ const parsed = PreviewRequestSchema . parse ( request ) ;
404+ expect ( parsed . listingId ) . toBe ( 'listing-001' ) ;
405+ expect ( parsed . version ) . toBeUndefined ( ) ;
406+ expect ( parsed . includeContent ) . toBeUndefined ( ) ;
407+ } ) ;
408+
409+ it ( 'should accept preview request with specific version and content types' , ( ) => {
410+ const request = {
411+ listingId : 'listing-001' ,
412+ version : '2.0.0' ,
413+ includeContent : [ 'objects' , 'views' , 'sample_data' ] as const ,
414+ } ;
415+ const parsed = PreviewRequestSchema . parse ( request ) ;
416+ expect ( parsed . version ) . toBe ( '2.0.0' ) ;
417+ expect ( parsed . includeContent ) . toHaveLength ( 3 ) ;
418+ expect ( parsed . includeContent ) . toContain ( 'objects' ) ;
419+ } ) ;
420+
421+ it ( 'should accept all valid content types' , ( ) => {
422+ const request = {
423+ listingId : 'listing-001' ,
424+ includeContent : [ 'objects' , 'views' , 'dashboards' , 'flows' , 'sample_data' , 'navigation' ] as const ,
425+ } ;
426+ const parsed = PreviewRequestSchema . parse ( request ) ;
427+ expect ( parsed . includeContent ) . toHaveLength ( 6 ) ;
428+ } ) ;
429+
430+ it ( 'should reject invalid content type' , ( ) => {
431+ const request = {
432+ listingId : 'listing-001' ,
433+ includeContent : [ 'invalid_type' ] ,
434+ } ;
435+ expect ( ( ) => PreviewRequestSchema . parse ( request ) ) . toThrow ( ) ;
436+ } ) ;
437+ } ) ;
438+
439+ describe ( 'PreviewObjectSummarySchema' , ( ) => {
440+ it ( 'should accept object summary with fields' , ( ) => {
441+ const summary = {
442+ name : 'lead' ,
443+ label : 'Lead' ,
444+ fieldCount : 3 ,
445+ fields : [
446+ { name : 'first_name' , label : 'First Name' , type : 'text' } ,
447+ { name : 'email' , label : 'Email' , type : 'text' } ,
448+ { name : 'status' , label : 'Status' , type : 'select' } ,
449+ ] ,
450+ } ;
451+ const parsed = PreviewObjectSummarySchema . parse ( summary ) ;
452+ expect ( parsed . name ) . toBe ( 'lead' ) ;
453+ expect ( parsed . fieldCount ) . toBe ( 3 ) ;
454+ expect ( parsed . fields ) . toHaveLength ( 3 ) ;
455+ } ) ;
456+
457+ it ( 'should accept object summary without fields' , ( ) => {
458+ const summary = {
459+ name : 'account' ,
460+ label : 'Account' ,
461+ fieldCount : 15 ,
462+ } ;
463+ const parsed = PreviewObjectSummarySchema . parse ( summary ) ;
464+ expect ( parsed . fields ) . toBeUndefined ( ) ;
465+ } ) ;
466+ } ) ;
467+
468+ describe ( 'PreviewViewSummarySchema' , ( ) => {
469+ it ( 'should accept list view summary' , ( ) => {
470+ const summary = {
471+ name : 'all_leads' ,
472+ label : 'All Leads' ,
473+ type : 'list' as const ,
474+ objectName : 'lead' ,
475+ } ;
476+ const parsed = PreviewViewSummarySchema . parse ( summary ) ;
477+ expect ( parsed . type ) . toBe ( 'list' ) ;
478+ } ) ;
479+
480+ it ( 'should accept form view summary' , ( ) => {
481+ const summary = {
482+ name : 'lead_form' ,
483+ label : 'Lead Form' ,
484+ type : 'form' as const ,
485+ objectName : 'lead' ,
486+ } ;
487+ const parsed = PreviewViewSummarySchema . parse ( summary ) ;
488+ expect ( parsed . type ) . toBe ( 'form' ) ;
489+ } ) ;
490+
491+ it ( 'should reject invalid view type' , ( ) => {
492+ expect ( ( ) => PreviewViewSummarySchema . parse ( {
493+ name : 'test' ,
494+ label : 'Test' ,
495+ type : 'invalid' ,
496+ objectName : 'test' ,
497+ } ) ) . toThrow ( ) ;
498+ } ) ;
499+ } ) ;
500+
501+ describe ( 'PreviewResponseSchema' , ( ) => {
502+ it ( 'should accept minimal preview response' , ( ) => {
503+ const response = {
504+ listingId : 'listing-001' ,
505+ name : 'Acme CRM' ,
506+ version : '2.0.0' ,
507+ } ;
508+ const parsed = PreviewResponseSchema . parse ( response ) ;
509+ expect ( parsed . listingId ) . toBe ( 'listing-001' ) ;
510+ expect ( parsed . objects ) . toBeUndefined ( ) ;
511+ expect ( parsed . views ) . toBeUndefined ( ) ;
512+ } ) ;
513+
514+ it ( 'should accept full preview response with all content' , ( ) => {
515+ const response = {
516+ listingId : 'listing-001' ,
517+ name : 'Acme CRM' ,
518+ version : '2.0.0' ,
519+ demoUrl : 'https://demo.acme.com/crm' ,
520+ objects : [
521+ { name : 'lead' , label : 'Lead' , fieldCount : 10 , fields : [
522+ { name : 'first_name' , label : 'First Name' , type : 'text' } ,
523+ ] } ,
524+ { name : 'account' , label : 'Account' , fieldCount : 8 } ,
525+ ] ,
526+ views : [
527+ { name : 'all_leads' , label : 'All Leads' , type : 'list' as const , objectName : 'lead' } ,
528+ { name : 'lead_form' , label : 'Lead Form' , type : 'form' as const , objectName : 'lead' } ,
529+ ] ,
530+ dashboards : [
531+ { name : 'sales_overview' , label : 'Sales Overview' } ,
532+ ] ,
533+ flows : [
534+ { name : 'lead_assignment' , label : 'Lead Assignment' , type : 'autolaunched' } ,
535+ ] ,
536+ navigation : [
537+ { id : 'nav_leads' , label : 'Leads' , type : 'object' } ,
538+ { id : 'nav_dashboard' , label : 'Dashboard' , type : 'dashboard' } ,
539+ ] ,
540+ sampleData : {
541+ lead : 50 ,
542+ account : 20 ,
543+ } ,
544+ expiresAt : '2025-06-01T12:00:00Z' ,
545+ } ;
546+ const parsed = PreviewResponseSchema . parse ( response ) ;
547+ expect ( parsed . objects ) . toHaveLength ( 2 ) ;
548+ expect ( parsed . views ) . toHaveLength ( 2 ) ;
549+ expect ( parsed . dashboards ) . toHaveLength ( 1 ) ;
550+ expect ( parsed . flows ) . toHaveLength ( 1 ) ;
551+ expect ( parsed . navigation ) . toHaveLength ( 2 ) ;
552+ expect ( parsed . sampleData ?. lead ) . toBe ( 50 ) ;
553+ expect ( parsed . demoUrl ) . toBe ( 'https://demo.acme.com/crm' ) ;
554+ expect ( parsed . expiresAt ) . toBe ( '2025-06-01T12:00:00Z' ) ;
555+ } ) ;
556+
557+ it ( 'should accept preview response with only objects' , ( ) => {
558+ const response = {
559+ listingId : 'listing-001' ,
560+ name : 'Acme Utils' ,
561+ version : '1.0.0' ,
562+ objects : [
563+ { name : 'task' , label : 'Task' , fieldCount : 5 } ,
564+ ] ,
565+ } ;
566+ const parsed = PreviewResponseSchema . parse ( response ) ;
567+ expect ( parsed . objects ) . toHaveLength ( 1 ) ;
568+ expect ( parsed . views ) . toBeUndefined ( ) ;
569+ expect ( parsed . dashboards ) . toBeUndefined ( ) ;
570+ } ) ;
571+ } ) ;
0 commit comments