11import { describe , it , expect } from 'vitest' ;
22import {
33 PageSchema ,
4+ PAGE_TYPE_ROADMAP ,
45 PageComponentSchema ,
56 PageRegionSchema ,
67 PageTypeSchema ,
@@ -199,12 +200,8 @@ describe('PageSchema', () => {
199200 expect ( page . isDefault ) . toBe ( true ) ;
200201 } ) ;
201202
202- it ( 'should accept different page types' , ( ) => {
203- const types : Array < Page [ 'type' ] > = [
204- 'record' , 'home' , 'app' , 'utility' ,
205- 'dashboard' , 'list' , 'form' , 'record_detail' , 'overview' ,
206- ] ;
207-
203+ it ( 'should accept the live page types' , ( ) => {
204+ const types : Array < Page [ 'type' ] > = [ 'record' , 'home' , 'app' , 'utility' , 'list' ] ;
208205 types . forEach ( type => {
209206 const page = PageSchema . parse ( {
210207 name : 'test_page' ,
@@ -214,29 +211,18 @@ describe('PageSchema', () => {
214211 } ) ;
215212 expect ( page . type ) . toBe ( type ) ;
216213 } ) ;
214+ } ) ;
217215
218- // record_review requires recordReview config
219- const reviewPage = PageSchema . parse ( {
220- name : 'test_page' ,
221- label : 'Test Page' ,
222- type : 'record_review' ,
223- regions : [ ] ,
224- recordReview : {
225- object : 'case' ,
226- actions : [ { label : 'Approve' , type : 'approve' } ] ,
227- } ,
228- } ) ;
229- expect ( reviewPage . type ) . toBe ( 'record_review' ) ;
230-
231- // blank requires blankLayout config
232- const blankPage = PageSchema . parse ( {
233- name : 'test_page' ,
234- label : 'Test Page' ,
235- type : 'blank' ,
236- regions : [ ] ,
237- blankLayout : { items : [ ] } ,
238- } ) ;
239- expect ( blankPage . type ) . toBe ( 'blank' ) ;
216+ it ( 'should reject roadmap page types that have no renderer (enforce-or-remove)' , ( ) => {
217+ // dashboard / form / record_detail / record_review / overview / blank were
218+ // removed from PageTypeSchema — authoring one used to pass validation then
219+ // break at runtime ("Unknown component type"). The enum is now the live set.
220+ for ( const type of PAGE_TYPE_ROADMAP ) {
221+ expect (
222+ ( ) => PageSchema . parse ( { name : 'test_page' , label : 'Test Page' , type, regions : [ ] } ) ,
223+ `roadmap type "${ type } " must be rejected until it ships a renderer` ,
224+ ) . toThrow ( ) ;
225+ }
240226 } ) ;
241227
242228 it ( 'should accept record page' , ( ) => {
@@ -483,13 +469,13 @@ describe('PageTypeSchema', () => {
483469 } ) ;
484470 } ) ;
485471
486- it ( 'should accept all interface page types ' , ( ) => {
487- const types = [
488- 'dashboard' , 'list' , 'form' , 'record_detail' , 'record_review' , 'overview' , 'blank' ,
489- ] ;
490-
491- types . forEach ( type => {
492- expect ( ( ) => PageTypeSchema . parse ( type ) ) . not . toThrow ( ) ;
472+ it ( 'should accept the live interface page type and reject roadmap ones ' , ( ) => {
473+ // `list` is the only live interface page type. The rest were declared for
474+ // "roadmap parity" but never rendered — removed from PageTypeSchema
475+ // (enforce-or-remove, tracked in PAGE_TYPE_ROADMAP).
476+ expect ( ( ) => PageTypeSchema . parse ( 'list' ) ) . not . toThrow ( ) ;
477+ PAGE_TYPE_ROADMAP . forEach ( type => {
478+ expect ( ( ) => PageTypeSchema . parse ( type ) , `roadmap type " ${ type } "` ) . toThrow ( ) ;
493479 } ) ;
494480 } ) ;
495481
@@ -587,25 +573,24 @@ describe('RecordReviewConfigSchema', () => {
587573// PageSchema with page types
588574// ---------------------------------------------------------------------------
589575describe ( 'PageSchema with page types' , ( ) => {
590- it ( 'should accept minimal interface-style page' , ( ) => {
576+ it ( 'should accept a minimal live page' , ( ) => {
591577 const page : Page = PageSchema . parse ( {
592578 name : 'page_overview' ,
593579 label : 'Overview' ,
594- type : 'blank' ,
595- blankLayout : { items : [ ] } ,
580+ type : 'home' ,
596581 regions : [ ] ,
597582 } ) ;
598583
599584 expect ( page . name ) . toBe ( 'page_overview' ) ;
600- expect ( page . type ) . toBe ( 'blank ' ) ;
585+ expect ( page . type ) . toBe ( 'home ' ) ;
601586 expect ( page . template ) . toBe ( 'default' ) ;
602587 } ) ;
603588
604- it ( 'should accept dashboard page' , ( ) => {
589+ it ( 'should accept an app page with components ' , ( ) => {
605590 const page = PageSchema . parse ( {
606591 name : 'page_dashboard' ,
607592 label : 'Dashboard' ,
608- type : 'dashboard ' ,
593+ type : 'app ' ,
609594 regions : [
610595 {
611596 name : 'main' ,
@@ -616,36 +601,15 @@ describe('PageSchema with page types', () => {
616601 ] ,
617602 } ) ;
618603
619- expect ( page . type ) . toBe ( 'dashboard ' ) ;
604+ expect ( page . type ) . toBe ( 'app ' ) ;
620605 expect ( page . regions [ 0 ] . components ) . toHaveLength ( 1 ) ;
621606 } ) ;
622607
623- it ( 'should accept record_review page with config' , ( ) => {
624- const page = PageSchema . parse ( {
625- name : 'page_review' ,
626- label : 'Review Queue' ,
627- type : 'record_review' ,
628- object : 'order' ,
629- recordReview : {
630- object : 'order' ,
631- actions : [
632- { label : 'Approve' , type : 'approve' , field : 'status' , value : 'approved' } ,
633- { label : 'Reject' , type : 'reject' , field : 'status' , value : 'rejected' } ,
634- ] ,
635- } ,
636- regions : [ ] ,
637- } ) ;
638-
639- expect ( page . type ) . toBe ( 'record_review' ) ;
640- expect ( page . recordReview ?. actions ) . toHaveLength ( 2 ) ;
641- } ) ;
642-
643608 it ( 'should accept page with variables' , ( ) => {
644609 const page = PageSchema . parse ( {
645610 name : 'page_filtered' ,
646611 label : 'Filtered View' ,
647- type : 'blank' ,
648- blankLayout : { items : [ ] } ,
612+ type : 'home' ,
649613 variables : [
650614 { name : 'selectedId' , type : 'string' } ,
651615 { name : 'showArchived' , type : 'boolean' , defaultValue : false } ,
@@ -656,47 +620,11 @@ describe('PageSchema with page types', () => {
656620 expect ( page . variables ) . toHaveLength ( 2 ) ;
657621 } ) ;
658622
659- it ( 'should accept all interface page types' , ( ) => {
660- const basicTypes = [
661- 'dashboard' , 'list' , 'form' , 'record_detail' , 'overview' ,
662- ] ;
663-
664- basicTypes . forEach ( type => {
665- expect ( ( ) => PageSchema . parse ( {
666- name : 'test_page' ,
667- label : 'Test' ,
668- type,
669- regions : [ ] ,
670- } ) ) . not . toThrow ( ) ;
671- } ) ;
672-
673- // record_review requires recordReview config
674- expect ( ( ) => PageSchema . parse ( {
675- name : 'test_page' ,
676- label : 'Test' ,
677- type : 'record_review' ,
678- regions : [ ] ,
679- recordReview : {
680- object : 'case' ,
681- actions : [ { label : 'Approve' , type : 'approve' } ] ,
682- } ,
683- } ) ) . not . toThrow ( ) ;
684-
685- // blank requires blankLayout config
686- expect ( ( ) => PageSchema . parse ( {
687- name : 'test_page' ,
688- label : 'Test' ,
689- type : 'blank' ,
690- regions : [ ] ,
691- blankLayout : { items : [ ] } ,
692- } ) ) . not . toThrow ( ) ;
693- } ) ;
694-
695623 it ( 'should accept page with icon' , ( ) => {
696624 const page = PageSchema . parse ( {
697625 name : 'page_with_icon' ,
698626 label : 'Dashboard' ,
699- type : 'dashboard ' ,
627+ type : 'home ' ,
700628 icon : 'bar-chart' ,
701629 regions : [ ] ,
702630 } ) ;
@@ -839,7 +767,7 @@ describe('BlankPageLayoutSchema', () => {
839767 const page = PageSchema . parse ( {
840768 name : 'blank_canvas' ,
841769 label : 'Canvas' ,
842- type : 'blank ' ,
770+ type : 'home ' ,
843771 regions : [
844772 {
845773 name : 'main' ,
@@ -888,7 +816,7 @@ describe('PageVariableSchema record_id type', () => {
888816 const page = PageSchema . parse ( {
889817 name : 'blank_picker' ,
890818 label : 'Picker Page' ,
891- type : 'blank ' ,
819+ type : 'home ' ,
892820 blankLayout : { items : [ ] } ,
893821 variables : [
894822 { name : 'selected_id' , type : 'record_id' , source : 'account_picker' } ,
@@ -926,7 +854,7 @@ describe('Page end-to-end', () => {
926854 const page = PageSchema . parse ( {
927855 name : 'page_overview' ,
928856 label : 'Overview' ,
929- type : 'dashboard ' ,
857+ type : 'home ' ,
930858 object : 'order' ,
931859 regions : [
932860 {
@@ -967,7 +895,7 @@ describe('Page end-to-end', () => {
967895 const page = PageSchema . parse ( {
968896 name : 'page_review' ,
969897 label : 'Review Queue' ,
970- type : 'record_review ' ,
898+ type : 'home ' ,
971899 object : 'order' ,
972900 recordReview : {
973901 object : 'order' ,
@@ -1135,7 +1063,7 @@ describe('PageSchema with interfaceConfig', () => {
11351063 const page = PageSchema . parse ( {
11361064 name : 'sales_dashboard' ,
11371065 label : 'Sales Dashboard' ,
1138- type : 'dashboard ' ,
1066+ type : 'home ' ,
11391067 interfaceConfig : {
11401068 appearance : {
11411069 showDescription : false ,
@@ -1239,65 +1167,24 @@ describe('RecordReviewConfigSchema - Negative Validation', () => {
12391167} ) ;
12401168
12411169// ============================================================================
1242- // Issue #5: PageSchema conditional validation (superRefine )
1170+ // PageSchema cross-field requirements — none by design (enforce-or-remove )
12431171// ============================================================================
1244- describe ( 'PageSchema - conditional validation' , ( ) => {
1245- it ( 'should reject record_review page without recordReview config' , ( ) => {
1246- expect ( ( ) => PageSchema . parse ( {
1247- name : 'review_page' ,
1248- label : 'Review' ,
1249- type : 'record_review' ,
1250- regions : [ ] ,
1251- } ) ) . toThrow ( ) ;
1252- } ) ;
1253-
1254- it ( 'should accept record_review page with recordReview config' , ( ) => {
1255- expect ( ( ) => PageSchema . parse ( {
1256- name : 'review_page' ,
1257- label : 'Review' ,
1258- type : 'record_review' ,
1259- regions : [ ] ,
1260- recordReview : {
1261- object : 'order' ,
1262- actions : [ { label : 'Approve' , type : 'approve' } ] ,
1263- } ,
1264- } ) ) . not . toThrow ( ) ;
1265- } ) ;
1266-
1267- it ( 'should reject blank page without blankLayout config' , ( ) => {
1172+ describe ( 'PageSchema - no cross-field requirements' , ( ) => {
1173+ // The old superRefine required `recordReview`/`blankLayout` for the
1174+ // record_review/blank types and `slots` for kind:'slotted'. All three are
1175+ // gone: record_review/blank are unrendered roadmap types removed from the
1176+ // enum (PAGE_TYPE_ROADMAP), and an empty slotted page validly renders the
1177+ // synthesized default. Each was a "required-but-unauthorable field blocks the
1178+ // Studio create form" trap.
1179+ it ( 'parses a minimal page of each live type with no extra config' , ( ) => {
1180+ for ( const type of [ 'record' , 'home' , 'app' , 'utility' , 'list' ] as const ) {
1181+ expect ( ( ) => PageSchema . parse ( { name : 'test_page' , label : 'P' , type, regions : [ ] } ) ) . not . toThrow ( ) ;
1182+ }
1183+ } ) ;
1184+
1185+ it ( 'parses a slotted record page with no slots' , ( ) => {
12681186 expect ( ( ) => PageSchema . parse ( {
1269- name : 'blank_page' ,
1270- label : 'Blank' ,
1271- type : 'blank' ,
1272- regions : [ ] ,
1273- } ) ) . toThrow ( ) ;
1274- } ) ;
1275-
1276- it ( 'should accept blank page with blankLayout config' , ( ) => {
1277- expect ( ( ) => PageSchema . parse ( {
1278- name : 'blank_page' ,
1279- label : 'Blank' ,
1280- type : 'blank' ,
1281- regions : [ ] ,
1282- blankLayout : { items : [ ] } ,
1283- } ) ) . not . toThrow ( ) ;
1284- } ) ;
1285-
1286- it ( 'should not require recordReview for non-record_review types' , ( ) => {
1287- expect ( ( ) => PageSchema . parse ( {
1288- name : 'list_page' ,
1289- label : 'List' ,
1290- type : 'list' ,
1291- regions : [ ] ,
1292- } ) ) . not . toThrow ( ) ;
1293- } ) ;
1294-
1295- it ( 'should not require blankLayout for non-blank types' , ( ) => {
1296- expect ( ( ) => PageSchema . parse ( {
1297- name : 'dashboard_page' ,
1298- label : 'Dashboard' ,
1299- type : 'dashboard' ,
1300- regions : [ ] ,
1187+ name : 'test_page' , label : 'P' , type : 'record' , kind : 'slotted' , regions : [ ] ,
13011188 } ) ) . not . toThrow ( ) ;
13021189 } ) ;
13031190} ) ;
0 commit comments