@ordojs/core
Version:
Core compiler and runtime for OrdoJS framework
192 lines (167 loc) • 6.41 kB
text/typescript
/**
* @fileoverview Tests for RPC generator and client-server separation
*/
import { describe, expect, it } from 'vitest';
import { OrdoJSCodeGenerator } from './code-generator-fixed.js';
import { RPCGenerator } from './rpc-generator.js';
describe('RPC Generator', () => {
const rpcGenerator = new RPCGenerator({
endpoint: '/api/rpc',
timeout: 5000,
retries: 2,
errorHandling: 'throw',
authentication: true
});
// Mock component AST with server functions
const mockAST: any = {
component: {
name: 'TestComponent',
serverBlock: {
functions: [
{
name: 'fetchData',
parameters: [
{ name: 'id', isOptional: false, dataType: { name: 'string', isArray: false, isOptional: false, genericTypes: [] } },
{ name: 'filter', isOptional: true, dataType: { name: 'string', isArray: false, isOptional: true, genericTypes: [] } }
],
returnType: { name: 'object', isArray: false, isOptional: false, genericTypes: [] },
isAsync: true,
isPublic: true,
middleware: ['authMiddleware'],
permissions: ['read:data']
},
{
name: 'privateFunction',
parameters: [],
returnType: { name: 'void', isArray: false, isOptional: false, genericTypes: [] },
isAsync: false,
isPublic: false,
middleware: [],
permissions: []
}
]
}
}
};
it('should generate RPC stubs for public server functions', () => {
const stubs = rpcGenerator.generateRPCStubs(mockAST);
// Should only generate stubs for public functions
expect(stubs.length).toBe(1);
expect(stubs[0].functionName).toBe('fetchData');
// Should include metadata
expect(stubs[0].metadata.componentName).toBe('TestComponent');
expect(stubs[0].metadata.parameters.length).toBe(2);
expect(stubs[0].metadata.isAsync).toBe(true);
// Should generate correct endpoint
expect(stubs[0].serverEndpoint).toBe('/api/rpc/TestComponent/fetchData');
// Client code should be a string containing the function implementation
expect(typeof stubs[0].clientCode).toBe('string');
expect(stubs[0].clientCode).toContain('async function fetchData');
expect(stubs[0].clientCode).toContain('id, filter');
});
it('should generate client module with all RPC stubs', () => {
const stubs = rpcGenerator.generateRPCStubs(mockAST);
const clientModule = rpcGenerator.generateRPCClientModule(stubs, 'TestComponent');
// Should generate a class with the component name
expect(clientModule).toContain('export class TestComponentRPCClient');
// Should include authentication helper when authentication is enabled
expect(clientModule).toContain('function getAuthToken()');
// Should export a default instance
expect(clientModule).toContain('export default new TestComponentRPCClient()');
});
it('should generate server routes module', () => {
const stubs = rpcGenerator.generateRPCStubs(mockAST);
const serverModule = rpcGenerator.generateServerRoutesModule(stubs, 'TestComponent');
// Should import the server component
expect(serverModule).toContain("require('./testcomponent-server')");
// Should create route handlers for each RPC endpoint
expect(serverModule).toContain("app.post('/api/rpc/TestComponent/fetchData'");
// Should include middleware checks
expect(serverModule).toContain('await authMiddleware(req, res)');
// Should include permission checks
expect(serverModule).toContain('const requiredPermissions = ["read:data"]');
});
});
describe('Code Generator with RPC Integration', () => {
// Mock component AST with server functions
const mockAST: any = {
component: {
name: 'TestComponent',
serverBlock: {
functions: [
{
name: 'fetchData',
parameters: [
{ name: 'id', isOptional: false, dataType: { name: 'string', isArray: false, isOptional: false, genericTypes: [] } },
{ name: 'filter', isOptional: true, dataType: { name: 'string', isArray: false, isOptional: true, genericTypes: [] } }
],
returnType: { name: 'object', isArray: false, isOptional: false, genericTypes: [] },
isAsync: true,
isPublic: true,
middleware: ['authMiddleware'],
permissions: ['read:data']
}
]
},
clientBlock: {
reactiveVariables: [],
computedValues: [],
eventHandlers: [],
functions: [],
lifecycle: []
},
markupBlock: {
elements: [],
textNodes: [],
interpolations: []
},
props: []
},
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
it('should integrate RPC generator in code generation', () => {
// Create code generator with RPC options
const codeGenerator = new OrdoJSCodeGenerator({
minify: false,
sourceMaps: true,
target: 'development',
rpcOptions: {
endpoint: '/api/rpc',
timeout: 5000,
retries: 2,
errorHandling: 'throw'
}
});
// Generate client code
const clientCode = codeGenerator.generateClientCode(mockAST);
// Verify RPC stubs are generated in client code
expect(clientCode).toContain('component.server = component.server || {}');
expect(clientCode).toContain('component.server.fetchData = async function');
expect(clientCode).toContain('/api/rpc/TestComponent/fetchData');
expect(clientCode).toContain('const response = await fetch');
expect(clientCode).toContain('return result');
});
it('should generate server code with RPC endpoints', () => {
const codeGenerator = new OrdoJSCodeGenerator({
minify: false,
sourceMaps: true,
target: 'development',
rpcOptions: {
endpoint: '/api/rpc'
}
});
// Generate server code
const serverCode = codeGenerator.generateServerCode(mockAST);
// Verify server functions are exported
expect(serverCode).toContain('public async function fetchData');
expect(serverCode).toContain('serverModule.fetchData = fetchData');
});
});