@ordojs/core
Version:
Core compiler and runtime for OrdoJS framework
195 lines (167 loc) • 5.88 kB
text/typescript
/**
* @fileoverview Tests for OrdoJS SSR Engine
*/
import { describe, expect, it, vi } from 'vitest';
import { OrdoJSCodeGenerator } from './code-generator-fixed.js';
import { OrdoJSSSR } from './ssr-engine.js';
// Mock the code generator
vi.mock('./code-generator-fixed.js', () => {
return {
OrdoJSCodeGenerator: vi.fn().mockImplementation(() => {
return {
generateHTML: vi.fn().mockImplementation((ast, props) => {
return `<div data-ordojs-component="${ast.component.name}" data-ordojs-hydrate="true">
<h1>Hello, ${props?.name || 'World'}</h1>
<p>This is a test component</p>
</div>`;
})
};
})
};
});
describe('OrdoJSSSR', () => {
// Create a mock component AST
const mockAST: any = {
component: {
name: 'TestComponent',
props: [
{ name: 'name', isRequired: false, defaultValue: { expressionType: 'LITERAL', value: 'World' } }
],
clientBlock: {
reactiveVariables: [
{
name: 'count',
initialValue: { expressionType: 'LITERAL', value: 0 },
dataType: { name: 'number', isArray: false, isOptional: false, genericTypes: [] }
}
]
},
serverBlock: {
functions: [
{
name: 'getServerSideProps',
parameters: [],
body: [],
returnType: { name: 'object', isArray: false, isOptional: false, genericTypes: [] },
isAsync: true,
isPublic: true,
middleware: [],
permissions: []
}
]
},
markupBlock: {
elements: [],
textNodes: [],
interpolations: []
}
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
it('should register components', () => {
const ssr = new OrdoJSSSR();
ssr.registerComponent(mockAST);
// Use a private property accessor for testing
const registry = (ssr as any).componentRegistry;
expect(registry.has('TestComponent')).toBe(true);
});
it('should render a component to HTML', async () => {
const ssr = new OrdoJSSSR();
ssr.registerComponent(mockAST);
const html = await ssr.renderComponent('TestComponent', { name: 'Tester' });
// Check that the HTML contains the component name
expect(html).toContain('data-ordojs-component="TestComponent"');
// Check that props were passed correctly
expect(html).toContain('Hello, Tester');
// Check that hydration data was included
expect(html).toContain('<script type="application/json" id="ordojs-hydration-data">');
expect(html).toContain('"componentName": "TestComponent"');
});
it('should generate hydration data', () => {
const ssr = new OrdoJSSSR();
const hydrationData = ssr.generateHydrationData(mockAST, { name: 'Tester' });
expect(hydrationData.componentName).toBe('TestComponent');
expect(hydrationData.props).toEqual({ name: 'Tester' });
expect(hydrationData.initialState).toEqual({ count: 0 });
expect(hydrationData.version).toBe('1.0');
});
it('should handle data fetching', async () => {
const ssr = new OrdoJSSSR({
dataFetcher: async (component, props) => {
return { serverData: 'fetched data' };
}
});
ssr.registerComponent(mockAST);
const data = await ssr.handleDataFetching('TestComponent', { name: 'Tester' });
expect(data.props).toEqual({
name: 'Tester',
serverData: 'fetched data'
});
});
it('should render a route', async () => {
const ssr = new OrdoJSSSR({
routes: [
{
path: '/users/:id',
component: 'TestComponent',
dataFetcher: async (params, query) => {
return {
userId: params.id,
filter: query.filter
};
}
}
]
});
ssr.registerComponent(mockAST);
const html = await ssr.renderRoute('/users/123?filter=active');
// Check that route params were passed to the component
expect(html).toContain('data-ordojs-component="TestComponent"');
// The mock code generator doesn't actually use these props, but we can verify
// the route handling by checking that the function was called
expect(OrdoJSCodeGenerator).toHaveBeenCalled();
});
it('should generate a complete HTML document', () => {
const ssr = new OrdoJSSSR();
const content = '<div>Test content</div>';
const document = ssr.generateDocument(content, 'Test Page', ['/js/app.js'], ['/css/styles.css']);
expect(document).toContain('<!DOCTYPE html>');
expect(document).toContain('<title>Test Page</title>');
expect(document).toContain('<div id="app"><div>Test content</div></div>');
expect(document).toContain('<script src="/js/app.js" defer></script>');
expect(document).toContain('<link rel="stylesheet" href="/css/styles.css">');
});
it('should throw an error when component is not found', async () => {
const ssr = new OrdoJSSSR();
await expect(ssr.renderComponent('NonExistentComponent')).rejects.toThrow(
'Component "NonExistentComponent" not found in registry'
);
});
it('should throw an error when no routes are configured', async () => {
const ssr = new OrdoJSSSR();
await expect(ssr.renderRoute('/some-path')).rejects.toThrow(
'No routes configured for SSR'
);
});
it('should throw an error when no matching route is found', async () => {
const ssr = new OrdoJSSSR({
routes: [
{
path: '/users/:id',
component: 'TestComponent'
}
]
});
await expect(ssr.renderRoute('/products/123')).rejects.toThrow(
'No route found for path: /products/123'
);
});
});