Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 83 additions & 7 deletions src/__tests__/routes.config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@

import { test, expect, describe } from 'vitest';
import { routes, routesInHeader, routesInSideNav } from '../routes/config';
import Dashboard from '../pages/dashboard/Dashboard';
import NotFound from '../pages/not-found/NotFound';
import Placeholder from '../pages/placeholder/Placeholder';
import Welcome from '../pages/welcome/Welcome';

describe('routes configuration', () => {
test('routes array contains expected structure', () => {
Expand All @@ -22,18 +18,22 @@ describe('routes configuration', () => {
const indexRoute = routes.find((route) => route.index === true);
expect(indexRoute).toBeDefined();
expect(indexRoute.path).toBe('/');
expect(indexRoute.element).toBe(Welcome);
expect(indexRoute.element).toBeDefined();
// Check for lazy component (has $$typeof and _payload properties)
expect(indexRoute.element.$$typeof).toBeDefined();

// Check that the NotFound route is defined correctly
const notFoundRoute = routes.find((route) => route.path === '*');
expect(notFoundRoute).toBeDefined();
expect(notFoundRoute.element).toBe(NotFound);
expect(notFoundRoute.element).toBeDefined();
expect(notFoundRoute.element.$$typeof).toBeDefined();
expect(notFoundRoute.status).toBe(404);

// Check that a regular route is defined correctly
const dashboardRoute = routes.find((route) => route.path === '/dashboard');
expect(dashboardRoute).toBeDefined();
expect(dashboardRoute.element).toBe(Dashboard);
expect(dashboardRoute.element).toBeDefined();
expect(dashboardRoute.element.$$typeof).toBeDefined();
expect(dashboardRoute.carbon).toBeDefined();
expect(dashboardRoute.carbon.label).toBe('Dashboard');
expect(dashboardRoute.carbon.inHeader).toBe(true);
Expand Down Expand Up @@ -112,4 +112,80 @@ describe('routes configuration', () => {
}
});
});

test('route components are lazy-loaded for code splitting', () => {
// Get all routes with elements
const routesWithElements = routes.filter((route) => route.element);

expect(routesWithElements.length).toBeGreaterThan(0);

routesWithElements.forEach((route) => {
const element = route.element;

// Verify it's a lazy component by checking React's internal structure
// Lazy components have $$typeof symbol and _payload/_init properties
expect(element).toBeDefined();
expect(element.$$typeof).toBeDefined();
expect(typeof element.$$typeof).toBe('symbol');

// Verify the lazy component has the expected structure
// _payload contains the import promise, _init is the initialization function
expect(element._payload).toBeDefined();
expect(element._init).toBeDefined();
expect(typeof element._init).toBe('function');
});
});

test('lazy components have correct React.lazy structure', () => {
// Test that lazy components have the expected React.lazy structure
const indexRoute = routes.find((route) => route.index === true);
expect(indexRoute).toBeDefined();
expect(indexRoute.element).toBeDefined();

const lazyComponent = indexRoute.element;

// Verify it has the React lazy component structure
expect(lazyComponent._payload).toBeDefined();
expect(lazyComponent._init).toBeDefined();
expect(typeof lazyComponent._init).toBe('function');

// Verify the $$typeof is the REACT_LAZY_TYPE symbol
expect(lazyComponent.$$typeof).toBeDefined();
expect(typeof lazyComponent.$$typeof).toBe('symbol');
expect(String(lazyComponent.$$typeof)).toContain('react.lazy');
});

test('lazy components can be dynamically imported', async () => {
// Test that lazy components point to valid importable modules
// by directly importing the component files
const componentImports = {
'/': () => import('../pages/welcome/Welcome'),
'/dashboard': () => import('../pages/dashboard/Dashboard'),
'*': () => import('../pages/not-found/NotFound'),
};

for (const [path, importFn] of Object.entries(componentImports)) {
const route = routes.find((r) => r.path === path);
expect(route).toBeDefined();
expect(route.element).toBeDefined();

// Verify the route has a lazy component
const lazyComponent = route.element;
expect(lazyComponent.$$typeof).toBeDefined();
expect(String(lazyComponent.$$typeof)).toContain('react.lazy');

// Verify we can actually import the component module
const module = await importFn();
expect(module).toBeDefined();
expect(module.default).toBeDefined();
expect(typeof module.default).toBe('function');

// Verify it's a valid React component
const component = module.default;
const componentName = component.displayName || component.name;
expect(componentName).toBeDefined();
expect(typeof componentName).toBe('string');
expect(componentName.length).toBeGreaterThan(0);
}
});
});
10 changes: 6 additions & 4 deletions src/routes/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
import { lazy } from 'react';
import { MagicWand, LogoGithub } from '@carbon/icons-react';
import Dashboard from '../pages/dashboard/Dashboard';
import NotFound from '../pages/not-found/NotFound';
import Placeholder from '../pages/placeholder/Placeholder';
import Welcome from '../pages/welcome/Welcome';

const Dashboard = lazy(() => import('../pages/dashboard/Dashboard'));
const NotFound = lazy(() => import('../pages/not-found/NotFound'));
const Placeholder = lazy(() => import('../pages/placeholder/Placeholder'));
const Welcome = lazy(() => import('../pages/welcome/Welcome'));

// type carbonRouteType = {
// virtualPath: string; // related to path, used for arranging Carbon menu when no path exists
Expand Down
14 changes: 9 additions & 5 deletions src/routes/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@
* LICENSE file in the root directory of this source tree.
*/

import { Suspense } from 'react';
import { Route, Routes } from 'react-router';
import { Loading } from '@carbon/react';

import { routes } from './config.js';

export const Router = () => {
return (
<Routes>
{routes.map(({ element: Element, ...rest }) => (
<Route key={rest.path} {...rest} element={Element && <Element />} />
))}
</Routes>
<Suspense fallback={<Loading />}>
<Routes>
{routes.map(({ element: Element, ...rest }) => (
<Route key={rest.path} {...rest} element={Element && <Element />} />
))}
</Routes>
</Suspense>
);
};
Loading