@auto-engineer/frontend-generator-react-graphql 1.7.0 → 1.9.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.
@@ -1,16 +1,30 @@
1
- <% organisms.forEach(org => { -%>
2
- import { <%= org %> } from "@/components/organisms/<%= org %>";
3
- <% }) -%>
1
+ <%
2
+ // Convert template name to PascalCase for import (define at top for use throughout)
3
+ const templateComponentName = template ? template.split(/[-_\s]+/).map(w => w.charAt(0).toUpperCase() + w.slice(1)).join('') : 'div';
4
+ -%>
4
5
  <% if (template) { -%>
5
- import { <%= template.split(/[-_\s]+/).map(w => w.charAt(0).toUpperCase() + w.slice(1)).join('') %> } from "@/components/templates/<%= template %>";
6
+ import { <%= templateComponentName %> } from "@/components/templates/<%= template %>";
6
7
  <% } -%>
7
8
  <% if (typeGuidance && typeGuidance.imports && typeGuidance.imports.length > 0) { -%>
8
9
  import { <%= typeGuidance.imports.join(', ') %> } from '@/gql/graphql';
9
10
  <% } -%>
10
11
 
12
+ // PAGE: <%= name %>
13
+ // Route: <%= route %>
11
14
  // <%= description %>
15
+ //
16
+ // Pages are specific instances of templates with real representative content.
17
+ // They populate the template's layout structure with actual data and behavior.
18
+ //
19
+ <% if (template) { -%>
20
+ // Template: <%= template %>
21
+ <% if (templateDescription) { -%>
22
+ // Template Purpose: <%= templateDescription %>
23
+ <% } -%>
24
+ <% } -%>
12
25
  <% if (specs && specs.length) { -%>
13
- // Specs:
26
+ //
27
+ // Page Specs:
14
28
  <% specs.forEach(spec => { -%>
15
29
  // - <%- spec %>
16
30
  <% }) -%>
@@ -21,6 +35,11 @@ import { <%= typeGuidance.imports.join(', ') %> } from '@/gql/graphql';
21
35
  // PAGE COMPOSITION - Spec Coverage Analysis
22
36
  // ──────────────────────────────────────────────────────────────────────────────
23
37
  //
38
+ // This page uses the "<%= template %>" template which contains:
39
+ <% organisms.forEach(org => { -%>
40
+ // - <%= org %>
41
+ <% }) -%>
42
+ //
24
43
  <% if (specs && specs.length > 0) { -%>
25
44
  // YOUR SPECS (what this page must accomplish):
26
45
  //
@@ -28,39 +47,59 @@ import { <%= typeGuidance.imports.join(', ') %> } from '@/gql/graphql';
28
47
  <% const coveredBy = organisms.find(org => organismSpecs[org]?.includes(spec)); -%>
29
48
  // [<%= coveredBy ? '✓' : ' ' %>] <%= spec %>
30
49
  <% if (coveredBy) { -%>
31
- // └─ Implemented by <%= coveredBy %>
50
+ // └─ Implemented by <%= coveredBy %> (via template)
32
51
  <% } -%>
33
52
  <% }); -%>
34
53
  //
35
54
  <% } -%>
36
- // Available Organisms:
55
+ <% if (templateSpecs && templateSpecs.length > 0) { -%>
56
+ // TEMPLATE LAYOUT SPECS (handled by template):
57
+ //
58
+ <% templateSpecs.forEach(spec => { -%>
59
+ // • <%= spec %>
60
+ <% }); -%>
61
+ //
62
+ <% } -%>
63
+ // Available Organisms (via template):
37
64
  //
38
65
  <% organisms.forEach(org => { -%>
39
66
  <% const orgSpecs = organismSpecs[org]; -%>
40
67
  <% if (orgSpecs && orgSpecs.length > 0) { -%>
41
68
  // **<%= org %>** capabilities:
42
- <% orgSpecs.forEach(spec => { -%>
69
+ <% orgSpecs.slice(0, 5).forEach(spec => { -%>
43
70
  // • <%= spec %>
44
71
  <% }); -%>
72
+ <% if (orgSpecs.length > 5) { -%>
73
+ // • ... and <%= orgSpecs.length - 5 %> more specs
74
+ <% } -%>
45
75
  //
46
76
  <% } else { -%>
47
77
  // **<%= org %>**
48
- // (Organism with specific purpose - compose as needed)
78
+ // (Organism with specific purpose)
49
79
  //
50
80
  <% } -%>
51
81
  <% }); -%>
52
- // Composition Rules:
82
+ // Page Responsibilities:
53
83
  //
54
- // 1. ✓ Checked specs = already implemented by organism
55
- // 2. [ ] Unchecked specs = your responsibility
56
- // 3. Your job: compose organisms into page layout
84
+ // 1. ✓ Checked specs = implemented by organism in template
85
+ // 2. [ ] Unchecked specs = your responsibility to implement
86
+ // 3. Pages provide real data to populate template structure
87
+ // 4. Handle page-level navigation and routing
88
+ // 5. Manage page-specific state if needed
57
89
  //
58
90
  <% } -%>
91
+ <% if (navigation && navigation.length > 0) { -%>
92
+ //
93
+ // NAVIGATION:
94
+ <% navigation.forEach(nav => { -%>
95
+ // - On "<%= nav.on %>" → Navigate to <%= nav.to %>
96
+ <% }) -%>
97
+ <% } -%>
59
98
  <% if (typeGuidance && (typeGuidance.queryGuidance.length > 0 || typeGuidance.mutationGuidance.length > 0 || typeGuidance.enumGuidance.length > 0)) { -%>
60
99
  //
61
- // CRITICAL - TYPE GUIDANCE - Child organism data requirements
100
+ // CRITICAL - TYPE GUIDANCE - Data requirements for this page
62
101
  //
63
- // The following operations are used by child organisms.
102
+ // The following operations are used by organisms in this page's template.
64
103
  // You can either:
65
104
  // A) Fetch here and pass as props (recommended for shared data/mutations)
66
105
  // B) Let each organism fetch its own data (simpler, but may duplicate queries)
@@ -81,35 +120,60 @@ import { <%= typeGuidance.imports.join(', ') %> } from '@/gql/graphql';
81
120
  <% }) -%>
82
121
  <% } -%>
83
122
  //
84
- // CRITICAL - CONTAINER-AWARE RESPONSIVE DESIGN:
85
- //
86
- // THIS COMPONENT WILL BE USED IN UNPREDICTABLE CONTAINER SIZES:
87
- // - Narrow sidebars: 300-400px
88
- // - Medium containers: 500-800px
89
- // - Wide layouts: 800px+
90
- // - Mobile viewports: 320-640px
91
- // - Flex layouts where space is shared with siblings (flex-1)
92
- //
93
- // 🎯 MANDATORY RESPONSIVE PATTERNS:
94
- //
95
- // 1. GRIDS: Always start mobile-first, progressively enhance
96
- // WRONG: grid grid-cols-3
97
- // RIGHT: grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3
98
- //
99
- // 2. TEXT SIZING: Use responsive classes, never fixed large sizes
100
- // WRONG: text-5xl (too big for narrow containers)
101
- // RIGHT: text-2xl sm:text-3xl lg:text-4xl
102
- //
103
- // 3. FLEX LAYOUTS: Prefer flex-col with responsive row breakpoints
104
- // RIGHT: flex flex-col lg:flex-row gap-4
105
- //
106
- // 4. PREVENT OVERFLOW: Use min-w-0 and truncation
107
- // RIGHT: min-w-0 truncate OR overflow-hidden
108
- //
109
- // 5. MENTAL TEST: Would this work in a 320px wide container?
110
- // If no make it responsive!
123
+ // ------------------------------------------------------------------------------
124
+ // PAGE-LEVEL CONSIDERATIONS & VISUAL REQUIREMENTS
125
+ // ------------------------------------------------------------------------------
126
+ //
127
+ // As a PAGE (not a template or component), this component:
128
+ // - Is the entry point for route "<%= route %>"
129
+ // - Should handle route parameters if needed
130
+ // - May coordinate data fetching for child organisms
131
+ // - Should handle page-level loading and error states
132
+ //
133
+ // VISUAL REQUIREMENTS FOR PAGES:
134
+ //
135
+ // LOADING STATES (use beautiful skeletons, not spinners):
136
+ // - Use Skeleton components that match the layout of actual content
137
+ // - Include skeletons for title, grid items, and other key elements
138
+ // - Maintain the same spacing and structure as loaded state
139
+ // - Example pattern:
140
+ // if (loading) return (
141
+ // <<%= template ? templateComponentName : 'div' %>>
142
+ // {/* Skeleton layout matching content structure */}
143
+ // </<%= template ? templateComponentName : 'div' %>>
144
+ // );
145
+ //
146
+ // ERROR STATES (user-friendly, not technical):
147
+ // - Center the error message vertically and horizontally
148
+ // - Include an error icon with appropriate styling
149
+ // - Use clear, non-technical language
150
+ // - Provide a recovery action (refresh, go back, etc.)
151
+ // - Example pattern:
152
+ // if (error) return (
153
+ // <<%= template ? templateComponentName : 'div' %>>
154
+ // {/* Centered error with icon, message, and action button */}
155
+ // </<%= template ? templateComponentName : 'div' %>>
156
+ // );
157
+ //
158
+ // IMPLEMENTATION PATTERN:
159
+ //
160
+ // 1. SIMPLE PAGE (template handles everything):
161
+ // return <<%= template ? templateComponentName : 'div' %> />;
162
+ //
163
+ // 2. PAGE WITH PROPS/CHILDREN (pass additional content):
164
+ // return (
165
+ // <<%= template ? templateComponentName : 'div' %>>
166
+ // {/* Additional page-specific content */}
167
+ // </<%= template ? templateComponentName : 'div' %>>
168
+ // );
169
+ //
170
+ // 3. PAGE WITH DATA FETCHING (with beautiful loading/error states):
171
+ // const { data, loading, error } = useQuery(SomeQuery);
172
+ // if (loading) return <PageSkeleton />; // Custom skeleton component
173
+ // if (error) return <PageError error={error} />; // Custom error component
174
+ // return <<%= template ? templateComponentName : 'div' %> data={data} />;
111
175
  //
112
176
 
113
177
  export function <%= name %>() {
114
- return <div />;
115
- }
178
+ return <<%= templateComponentName %> />;
179
+ }
@@ -7,33 +7,43 @@ const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
8
8
  const pageTemplate = fs.readFileSync(path.resolve(__dirname, 'page.ejs'), 'utf-8');
9
9
  describe('page.ejs', () => {
10
- it('should generate a basic page with organisms and no type guidance', () => {
10
+ it('should generate a basic page with template and organisms', () => {
11
11
  const content = ejs.render(pageTemplate, {
12
12
  name: 'Dashboard',
13
13
  description: 'Main dashboard page',
14
14
  organisms: ['StatsOverview', 'ActivityFeed'],
15
- template: undefined,
15
+ template: 'DashboardTemplate',
16
+ templateDescription: 'Dashboard layout with stats and activity',
17
+ templateSpecs: [],
18
+ route: '/dashboard',
19
+ navigation: [],
16
20
  specs: [],
21
+ dataRequirements: [],
17
22
  typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
18
23
  organismSpecs: {},
19
24
  });
20
- expect(content).toContain('import { StatsOverview } from "@/components/organisms/StatsOverview";');
21
- expect(content).toContain('import { ActivityFeed } from "@/components/organisms/ActivityFeed";');
25
+ expect(content).toContain('import { DashboardTemplate } from "@/components/templates/DashboardTemplate";');
22
26
  expect(content).toContain('// Main dashboard page');
23
27
  expect(content).toContain('PAGE COMPOSITION');
24
28
  expect(content).toContain('export function Dashboard()');
29
+ expect(content).toContain('return <DashboardTemplate />');
25
30
  });
26
31
  it('should generate a page with organisms and specs', () => {
27
32
  const content = ejs.render(pageTemplate, {
28
33
  name: 'AdminPanel',
29
34
  description: 'Admin control panel',
30
35
  organisms: ['UserManagement', 'SystemSettings'],
31
- template: undefined,
36
+ template: 'AdminTemplate',
37
+ templateDescription: 'Admin layout template',
38
+ templateSpecs: [],
39
+ route: '/admin',
40
+ navigation: [],
32
41
  specs: ['manage users', 'configure system'],
42
+ dataRequirements: [],
33
43
  typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
34
44
  organismSpecs: {},
35
45
  });
36
- expect(content).toContain('// Specs:');
46
+ expect(content).toContain('// Page Specs:');
37
47
  expect(content).toContain('// - manage users');
38
48
  expect(content).toContain('// - configure system');
39
49
  expect(content).toContain('PAGE COMPOSITION');
@@ -43,8 +53,13 @@ describe('page.ejs', () => {
43
53
  name: 'UserProfile',
44
54
  description: 'User profile page',
45
55
  organisms: ['ProfileHeader', 'ProfileDetails'],
46
- template: undefined,
56
+ template: 'ProfileTemplate',
57
+ templateDescription: 'Profile page layout',
58
+ templateSpecs: [],
59
+ route: '/profile',
60
+ navigation: [],
47
61
  specs: ['display user info', 'show activity history'],
62
+ dataRequirements: [],
48
63
  typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
49
64
  organismSpecs: {
50
65
  ProfileHeader: ['display user info'],
@@ -53,29 +68,40 @@ describe('page.ejs', () => {
53
68
  });
54
69
  expect(content).toContain('YOUR SPECS (what this page must accomplish):');
55
70
  expect(content).toContain('[✓] display user info');
56
- expect(content).toContain('└─ Implemented by ProfileHeader');
71
+ expect(content).toContain('└─ Implemented by ProfileHeader (via template)');
57
72
  expect(content).toContain('[✓] show activity history');
58
- expect(content).toContain('└─ Implemented by ProfileDetails');
73
+ expect(content).toContain('└─ Implemented by ProfileDetails (via template)');
59
74
  });
60
- it('should generate a page with template import', () => {
75
+ it('should generate a page with template import using PascalCase conversion', () => {
61
76
  const content = ejs.render(pageTemplate, {
62
77
  name: 'Settings',
63
78
  description: 'Settings page',
64
79
  organisms: ['GeneralSettings'],
65
80
  template: 'single-column-layout',
81
+ templateDescription: 'Single column layout template',
82
+ templateSpecs: [],
83
+ route: '/settings',
84
+ navigation: [],
66
85
  specs: [],
86
+ dataRequirements: [],
67
87
  typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
68
88
  organismSpecs: {},
69
89
  });
70
90
  expect(content).toContain('import { SingleColumnLayout } from "@/components/templates/single-column-layout";');
91
+ expect(content).toContain('return <SingleColumnLayout />');
71
92
  });
72
93
  it('should generate a page with type guidance', () => {
73
94
  const content = ejs.render(pageTemplate, {
74
95
  name: 'TodoList',
75
96
  description: 'Todo list page',
76
97
  organisms: ['TodoGrid'],
77
- template: undefined,
98
+ template: 'TodoTemplate',
99
+ templateDescription: 'Todo page layout',
100
+ templateSpecs: [],
101
+ route: '/todos',
102
+ navigation: [],
78
103
  specs: ['display todos', 'filter by status'],
104
+ dataRequirements: [],
79
105
  typeGuidance: {
80
106
  imports: ['Todo', 'TodoStatus'],
81
107
  queryGuidance: [
@@ -97,8 +123,13 @@ describe('page.ejs', () => {
97
123
  name: 'TaskBoard',
98
124
  description: 'Task management board',
99
125
  organisms: ['TaskList', 'TaskFilters'],
100
- template: undefined,
126
+ template: 'BoardTemplate',
127
+ templateDescription: 'Board layout template',
128
+ templateSpecs: [],
129
+ route: '/tasks',
130
+ navigation: [],
101
131
  specs: ['display tasks', 'filter by status', 'sort by date', 'search tasks'],
132
+ dataRequirements: [],
102
133
  typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
103
134
  organismSpecs: {
104
135
  TaskList: ['display tasks', 'sort by date'],
@@ -106,21 +137,25 @@ describe('page.ejs', () => {
106
137
  },
107
138
  });
108
139
  expect(content).toContain('[✓] display tasks');
109
- expect(content).toContain('└─ Implemented by TaskList');
140
+ expect(content).toContain('└─ Implemented by TaskList (via template)');
110
141
  expect(content).toContain('[✓] filter by status');
111
- expect(content).toContain('└─ Implemented by TaskFilters');
142
+ expect(content).toContain('└─ Implemented by TaskFilters (via template)');
112
143
  expect(content).toContain('[✓] sort by date');
113
- expect(content).toContain('└─ Implemented by TaskList');
144
+ expect(content).toContain('└─ Implemented by TaskList (via template)');
114
145
  expect(content).toContain('[ ] search tasks');
115
- expect(content).not.toContain('search tasks\n// └─');
116
146
  });
117
147
  it('should generate a page with NO spec coverage', () => {
118
148
  const content = ejs.render(pageTemplate, {
119
149
  name: 'Analytics',
120
150
  description: 'Analytics dashboard',
121
151
  organisms: ['ChartPanel', 'MetricsPanel'],
122
- template: undefined,
152
+ template: 'AnalyticsTemplate',
153
+ templateDescription: 'Analytics layout template',
154
+ templateSpecs: [],
155
+ route: '/analytics',
156
+ navigation: [],
123
157
  specs: ['show revenue chart', 'display user metrics', 'export data'],
158
+ dataRequirements: [],
124
159
  typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
125
160
  organismSpecs: {
126
161
  ChartPanel: ['render line chart', 'render bar chart'],
@@ -131,15 +166,19 @@ describe('page.ejs', () => {
131
166
  expect(content).toContain('[ ] display user metrics');
132
167
  expect(content).toContain('[ ] export data');
133
168
  expect(content).not.toContain('[✓]');
134
- expect(content).not.toContain('└─ Implemented by');
135
169
  });
136
170
  it('should generate a page with mutation guidance', () => {
137
171
  const content = ejs.render(pageTemplate, {
138
172
  name: 'CreateItem',
139
173
  description: 'Create item page',
140
174
  organisms: ['ItemForm'],
141
- template: undefined,
175
+ template: 'FormTemplate',
176
+ templateDescription: 'Form page layout',
177
+ templateSpecs: [],
178
+ route: '/items/new',
179
+ navigation: [],
142
180
  specs: ['collect item data', 'submit item'],
181
+ dataRequirements: [],
143
182
  typeGuidance: {
144
183
  imports: ['CreateItemInput'],
145
184
  queryGuidance: [],
@@ -152,15 +191,20 @@ describe('page.ejs', () => {
152
191
  });
153
192
  expect(content).toContain('CRITICAL - TYPE GUIDANCE');
154
193
  expect(content).toContain('Mutation - CreateItem:');
155
- expect(content).toContain('Child organism data requirements');
194
+ expect(content).toContain('Data requirements for this page');
156
195
  });
157
196
  it('should generate a page with only mutation guidance (no queries)', () => {
158
197
  const content = ejs.render(pageTemplate, {
159
198
  name: 'DeleteConfirmation',
160
199
  description: 'Delete confirmation page',
161
200
  organisms: ['ConfirmDialog'],
162
- template: undefined,
201
+ template: 'DialogTemplate',
202
+ templateDescription: 'Dialog layout template',
203
+ templateSpecs: [],
204
+ route: '/delete/:id',
205
+ navigation: [],
163
206
  specs: ['confirm deletion'],
207
+ dataRequirements: [],
164
208
  typeGuidance: {
165
209
  imports: [],
166
210
  queryGuidance: [],
@@ -181,7 +225,12 @@ describe('page.ejs', () => {
181
225
  description: 'Product catalog page',
182
226
  organisms: ['ProductGrid', 'ProductFilters'],
183
227
  template: 'two-column-layout',
228
+ templateDescription: 'Two column layout with sidebar',
229
+ templateSpecs: ['responsive sidebar', 'main content area'],
230
+ route: '/products',
231
+ navigation: [],
184
232
  specs: ['display products', 'filter products'],
233
+ dataRequirements: [],
185
234
  typeGuidance: {
186
235
  imports: ['Product'],
187
236
  queryGuidance: [
@@ -199,30 +248,59 @@ describe('page.ejs', () => {
199
248
  expect(content).toContain('CRITICAL - TYPE GUIDANCE');
200
249
  expect(content).toContain('[✓] display products');
201
250
  expect(content).toContain('[✓] filter products');
251
+ expect(content).toContain('return <TwoColumnLayout />');
202
252
  });
203
- it('should include responsive design guidance', () => {
253
+ it('should include template specs when available', () => {
254
+ const content = ejs.render(pageTemplate, {
255
+ name: 'DashboardPage',
256
+ description: 'Main dashboard',
257
+ organisms: ['Header', 'Content'],
258
+ template: 'DashboardLayout',
259
+ templateDescription: 'Dashboard layout with header and content areas',
260
+ templateSpecs: ['fixed header', 'scrollable content area', 'responsive sidebar'],
261
+ route: '/',
262
+ navigation: [],
263
+ specs: [],
264
+ dataRequirements: [],
265
+ typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
266
+ organismSpecs: {},
267
+ });
268
+ expect(content).toContain('TEMPLATE LAYOUT SPECS (handled by template):');
269
+ expect(content).toContain('• fixed header');
270
+ expect(content).toContain('• scrollable content area');
271
+ expect(content).toContain('• responsive sidebar');
272
+ });
273
+ it('should include page-level considerations', () => {
204
274
  const content = ejs.render(pageTemplate, {
205
275
  name: 'SimpleList',
206
276
  description: 'Simple list page',
207
277
  organisms: ['ItemList'],
208
- template: undefined,
278
+ template: 'ListTemplate',
279
+ templateDescription: 'List page layout',
280
+ templateSpecs: [],
281
+ route: '/items',
282
+ navigation: [],
209
283
  specs: ['show items'],
284
+ dataRequirements: [],
210
285
  typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
211
286
  organismSpecs: {},
212
287
  });
213
- expect(content).toContain('CRITICAL - CONTAINER-AWARE RESPONSIVE DESIGN:');
214
- expect(content).toContain('GRIDS: Always start mobile-first');
215
- expect(content).toContain('grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3');
216
- expect(content).toContain('TEXT SIZING: Use responsive classes');
217
- expect(content).toContain('MENTAL TEST: Would this work in a 320px wide container?');
288
+ expect(content).toContain('PAGE-LEVEL CONSIDERATIONS & VISUAL REQUIREMENTS');
289
+ expect(content).toContain('Is the entry point for route "/items"');
290
+ expect(content).toContain('IMPLEMENTATION PATTERN');
218
291
  });
219
292
  it('should handle organisms without organismSpecs data', () => {
220
293
  const content = ejs.render(pageTemplate, {
221
294
  name: 'MixedPage',
222
295
  description: 'Page with documented and undocumented organisms',
223
296
  organisms: ['DocumentedOrg', 'UndocumentedOrg'],
224
- template: undefined,
297
+ template: 'MixedTemplate',
298
+ templateDescription: 'Mixed content template',
299
+ templateSpecs: [],
300
+ route: '/mixed',
301
+ navigation: [],
225
302
  specs: ['feature A', 'feature B'],
303
+ dataRequirements: [],
226
304
  typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
227
305
  organismSpecs: {
228
306
  DocumentedOrg: ['feature A'],
@@ -231,7 +309,29 @@ describe('page.ejs', () => {
231
309
  expect(content).toContain('**DocumentedOrg** capabilities:');
232
310
  expect(content).toContain('• feature A');
233
311
  expect(content).toContain('**UndocumentedOrg**');
234
- expect(content).toContain('(Organism with specific purpose - compose as needed)');
312
+ expect(content).toContain('(Organism with specific purpose)');
313
+ });
314
+ it('should include navigation information', () => {
315
+ const content = ejs.render(pageTemplate, {
316
+ name: 'ProductPage',
317
+ description: 'Product detail page',
318
+ organisms: ['ProductDetails'],
319
+ template: 'DetailTemplate',
320
+ templateDescription: 'Detail page layout',
321
+ templateSpecs: [],
322
+ route: '/product/:id',
323
+ navigation: [
324
+ { on: 'Click Back', to: 'ProductListPage' },
325
+ { on: 'Click Buy', to: 'CheckoutPage' },
326
+ ],
327
+ specs: [],
328
+ dataRequirements: [],
329
+ typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
330
+ organismSpecs: {},
331
+ });
332
+ expect(content).toContain('NAVIGATION:');
333
+ expect(content).toContain('On "Click Back" → Navigate to ProductListPage');
334
+ expect(content).toContain('On "Click Buy" → Navigate to CheckoutPage');
235
335
  });
236
336
  describe('Edge Cases', () => {
237
337
  it('should handle empty organisms array', () => {
@@ -239,26 +339,37 @@ describe('page.ejs', () => {
239
339
  name: 'EmptyPage',
240
340
  description: 'Page without organisms',
241
341
  organisms: [],
242
- template: undefined,
342
+ template: 'EmptyTemplate',
343
+ templateDescription: 'Empty page layout',
344
+ templateSpecs: [],
345
+ route: '/empty',
346
+ navigation: [],
243
347
  specs: [],
348
+ dataRequirements: [],
244
349
  typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
245
350
  organismSpecs: {},
246
351
  });
247
352
  expect(content).not.toContain('PAGE COMPOSITION');
248
- expect(content).not.toContain('Composition Rules');
353
+ expect(content).not.toContain('Page Responsibilities');
249
354
  expect(content).toContain('export function EmptyPage()');
355
+ expect(content).toContain('return <EmptyTemplate />');
250
356
  });
251
357
  it('should handle undefined specs gracefully', () => {
252
358
  const content = ejs.render(pageTemplate, {
253
359
  name: 'NoSpecs',
254
360
  description: 'Page without specs',
255
361
  organisms: ['SomeOrganism'],
256
- template: undefined,
362
+ template: 'BasicTemplate',
363
+ templateDescription: 'Basic layout',
364
+ templateSpecs: [],
365
+ route: '/no-specs',
366
+ navigation: [],
257
367
  specs: undefined,
368
+ dataRequirements: [],
258
369
  typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
259
370
  organismSpecs: {},
260
371
  });
261
- expect(content).not.toContain('// Specs:');
372
+ expect(content).not.toContain('// Page Specs:');
262
373
  expect(content).not.toContain('YOUR SPECS');
263
374
  expect(content).toContain('PAGE COMPOSITION');
264
375
  });
@@ -267,8 +378,13 @@ describe('page.ejs', () => {
267
378
  name: 'EmptySpecs',
268
379
  description: 'Organisms with no documented specs',
269
380
  organisms: ['Org1', 'Org2'],
270
- template: undefined,
381
+ template: 'BasicTemplate',
382
+ templateDescription: 'Basic layout',
383
+ templateSpecs: [],
384
+ route: '/empty-specs',
385
+ navigation: [],
271
386
  specs: ['feature X', 'feature Y'],
387
+ dataRequirements: [],
272
388
  typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
273
389
  organismSpecs: {
274
390
  Org1: [],
@@ -279,6 +395,24 @@ describe('page.ejs', () => {
279
395
  expect(content).toContain('[ ] feature Y');
280
396
  expect(content).not.toContain('[✓]');
281
397
  });
398
+ it('should handle page without template (fallback to div)', () => {
399
+ const content = ejs.render(pageTemplate, {
400
+ name: 'NoTemplatePage',
401
+ description: 'Page without template',
402
+ organisms: [],
403
+ template: undefined,
404
+ templateDescription: '',
405
+ templateSpecs: [],
406
+ route: '/no-template',
407
+ navigation: [],
408
+ specs: [],
409
+ dataRequirements: [],
410
+ typeGuidance: { imports: [], queryGuidance: [], mutationGuidance: [], enumGuidance: [] },
411
+ organismSpecs: {},
412
+ });
413
+ expect(content).not.toContain('import {');
414
+ expect(content).toContain('return <div />');
415
+ });
282
416
  });
283
417
  });
284
418
  //# sourceMappingURL=page.ejs.specs.js.map