@@ -15,17 +15,21 @@ import { UnsavedProvider } from '../../context/UnsavedContext';
1515import { TeamContext } from '../../context/TeamContext' ;
1616import { TokenContext } from '../../context/TokenProvider' ;
1717import { OrganizationD } from '@model/organization' ;
18+ import { ProjectD } from '../../model' ;
1819
1920// Mock memory with query function that can return organization data
2021// The findRecord function uses: memory.cache.query((q) => q.findRecord({ type, id }))
2122// The findRecords function uses: memory.cache.query((q) => q.findRecords(type))
2223const createMockMemory = (
2324 orgData ?: OrganizationD ,
2425 isAdmin : boolean = false ,
25- userId : string = 'test-user-id'
26+ userId : string = 'test-user-id' ,
27+ projectData ?: ProjectD [ ]
2628) : Memory => {
2729 // Store organizations in an array for findRecords queries
2830 const organizations = orgData ? [ orgData ] : [ ] ;
31+ // Store projects in an array for findRecords queries
32+ const projects = projectData || [ ] ;
2933
3034 // Create role records
3135 const adminRoleId = 'admin-role-id' ;
@@ -79,6 +83,11 @@ const createMockMemory = (
7983 if ( type === 'organization' && id === orgData ?. id && orgData ) {
8084 return orgData ;
8185 }
86+ // Return project data if it matches
87+ if ( type === 'project' ) {
88+ const project = projects . find ( ( p ) => p . id === id ) ;
89+ if ( project ) return project ;
90+ }
8291 // Return role records
8392 if ( type === 'role' ) {
8493 const role = roles . find ( ( r ) => r . id === id ) ;
@@ -93,6 +102,11 @@ const createMockMemory = (
93102 if ( type === 'organization' ) {
94103 return organizations ;
95104 }
105+ // Return projects array when querying for 'project' type
106+ // This is used by useOrbitData('project')
107+ if ( type === 'project' ) {
108+ return projects ;
109+ }
96110 // Return roles array when querying for 'role' type
97111 if ( type === 'role' ) {
98112 return roles ;
@@ -197,43 +211,82 @@ describe('OrgHead', () => {
197211 relationships : { } ,
198212 } ) as OrganizationD ;
199213
200- const createInitialState = ( overrides = { } , orgData ?: OrganizationD ) => ( {
201- coordinator : mockCoordinator ,
202- errorReporter : bugsnagClient ,
203- fingerprint : 'test-fingerprint' ,
204- memory : createMockMemory ( orgData ) ,
205- lang : 'en' ,
206- latestVersion : '' ,
207- loadComplete : false ,
208- offlineOnly : false ,
209- organization : '' ,
210- releaseDate : '' ,
211- user : 'test-user-id' ,
212- alertOpen : false ,
213- autoOpenAddMedia : false ,
214- changed : false ,
215- connected : true ,
216- dataChangeCount : 0 ,
217- developer : false ,
218- enableOffsite : false ,
219- home : false ,
220- importexportBusy : false ,
221- orbitRetries : 0 ,
222- orgRole : undefined ,
223- plan : '' ,
224- playingMediaId : '' ,
225- progress : 0 ,
226- project : '' ,
227- projectsLoaded : [ ] ,
228- projType : '' ,
229- remoteBusy : false ,
230- saveResult : undefined ,
231- snackAlert : undefined ,
232- snackMessage : ( < > </ > ) as React . JSX . Element ,
233- offline : false ,
234- mobileView : false ,
235- ...overrides ,
236- } ) ;
214+ const createMockProject = ( id : string , name : string ) : ProjectD =>
215+ ( {
216+ id,
217+ type : 'project' ,
218+ attributes : {
219+ name,
220+ slug : name . toLowerCase ( ) . replace ( / \s + / g, '-' ) ,
221+ description : null ,
222+ uilanguagebcp47 : null ,
223+ language : 'und' ,
224+ languageName : null ,
225+ defaultFont : null ,
226+ defaultFontSize : null ,
227+ rtl : false ,
228+ spellCheck : false ,
229+ allowClaim : false ,
230+ isPublic : false ,
231+ dateCreated : new Date ( ) . toISOString ( ) ,
232+ dateUpdated : new Date ( ) . toISOString ( ) ,
233+ dateArchived : '' ,
234+ lastModifiedBy : 0 ,
235+ defaultParams : '{}' ,
236+ } ,
237+ relationships : { } ,
238+ } ) as ProjectD ;
239+
240+ const createInitialState = (
241+ overrides = { } ,
242+ orgData ?: OrganizationD ,
243+ projectData ?: ProjectD [ ]
244+ ) => {
245+ // Create memory with orgData and projectData if provided
246+ const memory = createMockMemory (
247+ orgData ,
248+ false ,
249+ 'test-user-id' ,
250+ projectData
251+ ) ;
252+ return {
253+ coordinator : mockCoordinator ,
254+ errorReporter : bugsnagClient ,
255+ fingerprint : 'test-fingerprint' ,
256+ memory,
257+ lang : 'en' ,
258+ latestVersion : '' ,
259+ loadComplete : false ,
260+ offlineOnly : false ,
261+ organization : '' ,
262+ releaseDate : '' ,
263+ user : 'test-user-id' ,
264+ alertOpen : false ,
265+ autoOpenAddMedia : false ,
266+ changed : false ,
267+ connected : true ,
268+ dataChangeCount : 0 ,
269+ developer : false ,
270+ enableOffsite : false ,
271+ home : false ,
272+ importexportBusy : false ,
273+ orbitRetries : 0 ,
274+ orgRole : undefined ,
275+ plan : '' ,
276+ playingMediaId : '' ,
277+ progress : 0 ,
278+ project : '' ,
279+ projectsLoaded : [ ] ,
280+ projType : '' ,
281+ remoteBusy : false ,
282+ saveResult : undefined ,
283+ snackAlert : undefined ,
284+ snackMessage : ( < > </ > ) as React . JSX . Element ,
285+ offline : false ,
286+ mobileView : false ,
287+ ...overrides ,
288+ } ;
289+ } ;
237290
238291 // Helper function to mount OrgHead with all required providers
239292 const mountOrgHead = (
@@ -242,7 +295,8 @@ describe('OrgHead', () => {
242295 orgId ?: string ,
243296 orgData ?: OrganizationD ,
244297 isAdmin : boolean = false ,
245- personalTeam ?: string
298+ personalTeam ?: string ,
299+ projectData ?: ProjectD [ ]
246300 ) => {
247301 // Set organization ID in localStorage if provided
248302 if ( orgId ) {
@@ -251,10 +305,13 @@ describe('OrgHead', () => {
251305 } ) ;
252306 }
253307
254- // Create memory with org data and admin status if provided
255- const memory = orgData
256- ? createMockMemory ( orgData , isAdmin , initialState . user )
257- : createMockMemory ( undefined , false , initialState . user ) ;
308+ // Create memory with org data, admin status, and project data if provided
309+ // If orgData or projectData is provided to mountOrgHead, create new memory with those
310+ // Otherwise use memory from initialState
311+ const memoryToUse =
312+ orgData !== undefined || projectData !== undefined
313+ ? createMockMemory ( orgData , isAdmin , initialState . user , projectData )
314+ : initialState . memory ;
258315
259316 // Create stubs for TeamContext methods
260317 const mockTeamUpdate = cy . stub ( ) . as ( 'teamUpdate' ) ;
@@ -335,14 +392,14 @@ describe('OrgHead', () => {
335392 // Create state with memory
336393 const stateWithMemory = {
337394 ...initialState ,
338- memory,
395+ memory : memoryToUse ,
339396 } ;
340397
341398 cy . mount (
342399 < MemoryRouter initialEntries = { initialEntries } >
343400 < Provider store = { mockStore } >
344401 < GlobalProvider init = { stateWithMemory } >
345- < DataProvider dataStore = { memory } >
402+ < DataProvider dataStore = { memoryToUse } >
346403 < UnsavedProvider >
347404 < TokenContext . Provider value = { mockTokenContextValue as any } >
348405 < TeamContext . Provider value = { mockTeamContextValue as any } >
@@ -369,15 +426,24 @@ describe('OrgHead', () => {
369426
370427 it ( 'should render product name fallback when organization does not exist' , ( ) => {
371428 mountOrgHead ( createInitialState ( ) , [ '/team' ] ) ;
372- // The component should render - it will show product name from API_CONFIG
373- // Note: The actual product name depends on API_CONFIG, which should be available
374- cy . get ( 'h6, [variant="h6"]' ) . should ( 'be.visible' ) ;
429+ // When on team screen and orgRec is undefined, cleanOrgName returns empty string
430+ // So the Typography will render but may be empty. Check that the element exists.
431+ cy . get ( 'h6, [variant="h6"]' ) . should ( 'exist' ) ;
432+ // The text will be empty when orgRec doesn't exist on team screen
433+ cy . get ( 'h6, [variant="h6"]' )
434+ . contains ( 'Audio Project Manager' )
435+ . should ( 'be.visible' ) ;
375436 } ) ;
376437
377438 it ( 'should render product name fallback when orgId is not set' , ( ) => {
378439 mountOrgHead ( createInitialState ( ) , [ '/team' ] , undefined ) ;
379- // The component should render - it will show product name from API_CONFIG
380- cy . get ( 'h6, [variant="h6"]' ) . should ( 'be.visible' ) ;
440+ // When on team screen and orgId is not set, orgRec will be undefined
441+ // So cleanOrgName returns empty string. Check that the element exists.
442+ cy . get ( 'h6, [variant="h6"]' ) . should ( 'exist' ) ;
443+ // The text will be empty when orgId is not set on team screen
444+ cy . get ( 'h6, [variant="h6"]' )
445+ . contains ( 'Audio Project Manager' )
446+ . should ( 'be.visible' ) ;
381447 } ) ;
382448
383449 it ( 'should show settings and members buttons when on team screen and user is admin' , ( ) => {
@@ -412,11 +478,27 @@ describe('OrgHead', () => {
412478 const orgId = 'test-org-id' ;
413479 const orgName = 'Test Organization' ;
414480 const orgData = createMockOrganization ( orgId , orgName ) ;
481+ const projectId = 'test-project-id' ;
482+ const projectName = 'Test Project' ;
483+ const projectData = createMockProject ( projectId , projectName ) ;
415484
416- mountOrgHead ( createInitialState ( ) , [ '/project' ] , orgId , orgData ) ;
485+ // When not on team/switch-teams screen, it shows project name if project is set,
486+ // otherwise product name. In this test we set the project, so it should show the project name.
487+ mountOrgHead (
488+ createInitialState ( { project : projectId } , orgData , [ projectData ] ) ,
489+ [ '/project' ] ,
490+ orgId ,
491+ orgData ,
492+ false ,
493+ undefined ,
494+ [ projectData ]
495+ ) ;
417496
418- // Should only render the Typography, no buttons
419- cy . contains ( orgName ) . should ( 'be.visible' ) ;
497+ // Should display project name (not organization name) when not on team screen
498+ cy . contains ( projectName ) . should ( 'be.visible' ) ;
499+ // Should NOT show organization name
500+ cy . contains ( orgName ) . should ( 'not.exist' ) ;
501+ // Should not have buttons
420502 cy . get ( 'button' ) . should ( 'not.exist' ) ;
421503 } ) ;
422504
@@ -641,4 +723,118 @@ describe('OrgHead', () => {
641723 cy . get ( 'button' ) . should ( 'have.length' , 1 ) ;
642724 cy . get ( 'button svg' ) . should ( 'have.length' , 1 ) ;
643725 } ) ;
726+
727+ it ( 'should display project name when not on team or switch-teams screen and project is set' , ( ) => {
728+ const projectId = 'test-project-id' ;
729+ const projectName = 'Test Project' ;
730+ const projectData = createMockProject ( projectId , projectName ) ;
731+
732+ // Mount on a route that is not /team or /switch-teams (e.g., /plan)
733+ mountOrgHead (
734+ createInitialState ( { project : projectId } , undefined , [ projectData ] ) ,
735+ [ '/plan/123/0' ] ,
736+ undefined ,
737+ undefined ,
738+ false ,
739+ undefined ,
740+ [ projectData ]
741+ ) ;
742+
743+ // Should display the project name
744+ cy . contains ( projectName ) . should ( 'be.visible' ) ;
745+ } ) ;
746+
747+ it ( 'should display project name from projects table using global project id' , ( ) => {
748+ const projectId1 = 'test-project-id-1' ;
749+ const projectName1 = 'First Project' ;
750+ const projectId2 = 'test-project-id-2' ;
751+ const projectName2 = 'Second Project' ;
752+ const projectData = [
753+ createMockProject ( projectId1 , projectName1 ) ,
754+ createMockProject ( projectId2 , projectName2 ) ,
755+ ] ;
756+
757+ // Set global project to the second project
758+ mountOrgHead (
759+ createInitialState ( { project : projectId2 } , undefined , projectData ) ,
760+ [ '/plan/456/0' ] ,
761+ undefined ,
762+ undefined ,
763+ false ,
764+ undefined ,
765+ projectData
766+ ) ;
767+
768+ // Should display the second project name (matching the global project id)
769+ cy . contains ( projectName2 ) . should ( 'be.visible' ) ;
770+ // Should NOT display the first project name
771+ cy . contains ( projectName1 ) . should ( 'not.exist' ) ;
772+ } ) ;
773+
774+ it ( 'should display product name fallback when project is not found in projects table' , ( ) => {
775+ const projectId = 'non-existent-project-id' ;
776+ const projectName = 'Existing Project' ;
777+ const projectData = [ createMockProject ( 'other-project-id' , projectName ) ] ;
778+
779+ // Set global project to an id that doesn't exist in the projects array
780+ mountOrgHead (
781+ createInitialState ( { project : projectId } , undefined , projectData ) ,
782+ [ '/plan/789/0' ] ,
783+ undefined ,
784+ undefined ,
785+ false ,
786+ undefined ,
787+ projectData
788+ ) ;
789+
790+ // Should display product name fallback since project is not found
791+ cy . contains ( 'Audio Project Manager' ) . should ( 'be.visible' ) ;
792+ // Should NOT display the existing project name
793+ cy . contains ( projectName ) . should ( 'not.exist' ) ;
794+ } ) ;
795+
796+ it ( 'should display product name fallback when project global is not set' , ( ) => {
797+ const projectName = 'Some Project' ;
798+ const projectData = [ createMockProject ( 'some-project-id' , projectName ) ] ;
799+
800+ // Don't set the project global
801+ mountOrgHead (
802+ createInitialState ( { project : '' } , undefined , projectData ) ,
803+ [ '/plan/999/0' ] ,
804+ undefined ,
805+ undefined ,
806+ false ,
807+ undefined ,
808+ projectData
809+ ) ;
810+
811+ // Should display product name fallback since project is not set
812+ cy . contains ( 'Audio Project Manager' ) . should ( 'be.visible' ) ;
813+ // Should NOT display the project name
814+ cy . contains ( projectName ) . should ( 'not.exist' ) ;
815+ } ) ;
816+
817+ it ( 'should display project name on routes other than team and switch-teams' , ( ) => {
818+ const projectId = 'test-project-id' ;
819+ const projectName = 'My Project' ;
820+ const projectData = createMockProject ( projectId , projectName ) ;
821+
822+ // Test various routes that are not /team or /switch-teams
823+ const routes = [ '/plan/123/0' , '/projects' , '/some-other-route' ] ;
824+
825+ routes . forEach ( ( route ) => {
826+ mountOrgHead (
827+ createInitialState ( { project : projectId } , undefined , [ projectData ] ) ,
828+ [ route ] ,
829+ undefined ,
830+ undefined ,
831+ false ,
832+ undefined ,
833+ [ projectData ]
834+ ) ;
835+
836+ // Should display the project name
837+ cy . contains ( projectName ) . should ( 'be.visible' ) ;
838+ } ) ;
839+ } ) ;
644840} ) ;
0 commit comments