@ordojs/core
Version:
Core compiler and runtime for OrdoJS framework
275 lines (259 loc) • 8.1 kB
text/typescript
/**
* @fileoverview Tests for OrdoJS Code Generator
*/
import { describe, expect, it } from 'vitest';
import {
ComponentAST,
ComponentNode,
HTMLElementNode,
MarkupBlockNode,
TextNode,
} from '../types/index.js';
import { OrdoJSCodeGenerator } from './code-generator.js';
// Helper to create a simple source range
function createRange(startLine: number, startCol: number, endLine: number, endCol: number) {
return {
start: { line: startLine, column: startCol, offset: 0 },
end: { line: endLine, column: endCol, offset: 0 }
};
}
describe('OrdoJSCodeGenerator', () => {
it('should generate client code for a simple component', () => {
// Create a simple AST manually
const ast: ComponentAST = {
component: {
type: 'Component',
name: 'SimpleComponent',
props: [],
markupBlock: {
type: 'MarkupBlock',
elements: [
{
type: 'HTMLElement',
tagName: 'div',
attributes: [
{
type: 'Attribute',
name: 'class',
value: 'container',
isDirective: false,
range: createRange(1, 1, 1, 20)
}
],
children: [
{
type: 'Text',
content: 'Hello, World!',
range: createRange(1, 21, 1, 34)
} as TextNode
],
isSelfClosing: false,
isVoidElement: false,
range: createRange(1, 1, 1, 40)
} as HTMLElementNode
],
textNodes: [],
interpolations: [],
range: createRange(1, 1, 1, 40)
} as MarkupBlockNode,
range: createRange(1, 1, 1, 50)
} as ComponentNode,
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
const generator = new OrdoJSCodeGenerator();
const code = generator.generateClientCode(ast);
// Verify the generated code contains expected elements
expect(code).toContain('function SimpleComponent(props = {})');
expect(code).toContain('document.createElement("div")');
expect(code).toContain('setAttribute("class", "container")');
expect(code).toContain('document.createTextNode("Hello, World!")');
});
it('should generate HTML for a simple component', () => {
// Create a simple AST manually
const ast: ComponentAST = {
component: {
type: 'Component',
name: 'SimpleComponent',
props: [],
markupBlock: {
type: 'MarkupBlock',
elements: [
{
type: 'HTMLElement',
tagName: 'div',
attributes: [
{
type: 'Attribute',
name: 'class',
value: 'container',
isDirective: false,
range: createRange(1, 1, 1, 20)
}
],
children: [
{
type: 'Text',
content: 'Hello, World!',
range: createRange(1, 21, 1, 34)
} as TextNode
],
isSelfClosing: false,
isVoidElement: false,
range: createRange(1, 1, 1, 40)
} as HTMLElementNode
],
textNodes: [],
interpolations: [],
range: createRange(1, 1, 1, 40)
} as MarkupBlockNode,
range: createRange(1, 1, 1, 50)
} as ComponentNode,
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
const generator = new OrdoJSCodeGenerator();
const html = generator.generateHTML(ast);
// Verify the generated HTML contains expected elements
expect(html).toContain('<div class="container" data-ordojs-hydrate="true">Hello, World!</div>');
expect(html).toContain('data-ordojs-component="SimpleComponent"');
expect(html).toContain('data-ordojs-version="1.0"');
});
it('should generate HTML with component props', () => {
// Create a component AST with props
const ast: ComponentAST = {
component: {
type: 'Component',
name: 'PropsComponent',
props: [
{
type: 'PropDefinition',
name: 'title',
dataType: { name: 'string', isArray: false, isOptional: false, genericTypes: [] },
isRequired: true,
range: createRange(1, 1, 1, 20)
},
{
type: 'PropDefinition',
name: 'count',
dataType: { name: 'number', isArray: false, isOptional: false, genericTypes: [] },
defaultValue: {
type: 'Expression',
expressionType: 'LITERAL',
value: 0,
range: createRange(1, 30, 1, 31)
},
isRequired: false,
range: createRange(1, 21, 1, 40)
}
],
markupBlock: {
type: 'MarkupBlock',
elements: [
{
type: 'HTMLElement',
tagName: 'div',
attributes: [],
children: [
{
type: 'Text',
content: 'Component with props',
range: createRange(1, 21, 1, 40)
} as TextNode
],
isSelfClosing: false,
isVoidElement: false,
range: createRange(1, 1, 1, 50)
} as HTMLElementNode
],
textNodes: [],
interpolations: [],
range: createRange(1, 1, 1, 60)
} as MarkupBlockNode,
range: createRange(1, 1, 1, 70)
} as ComponentNode,
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
// Generate HTML with initial props
const generator = new OrdoJSCodeGenerator();
const html = generator.generateHTML(ast, { title: 'Hello', count: 42 });
// Verify the generated HTML contains props data
expect(html).toContain('data-props=');
// Just check that the HTML contains the expected values
expect(html).toContain('title');
expect(html).toContain('Hello');
expect(html).toContain('count');
expect(html).toContain('42');
});
it('should generate complete code bundle', () => {
// Create a simple AST manually
const ast: ComponentAST = {
component: {
type: 'Component',
name: 'SimpleComponent',
props: [],
markupBlock: {
type: 'MarkupBlock',
elements: [
{
type: 'HTMLElement',
tagName: 'div',
attributes: [],
children: [
{
type: 'Text',
content: 'Hello, World!',
range: createRange(1, 21, 1, 34)
} as TextNode
],
isSelfClosing: false,
isVoidElement: false,
range: createRange(1, 1, 1, 40)
} as HTMLElementNode
],
textNodes: [],
interpolations: [],
range: createRange(1, 1, 1, 40)
} as MarkupBlockNode,
range: createRange(1, 1, 1, 50)
} as ComponentNode,
dependencies: [],
exports: [],
sourceMap: {
version: 3,
sources: [],
names: [],
mappings: '',
sourcesContent: []
}
};
const generator = new OrdoJSCodeGenerator();
const bundle = generator.generate(ast);
// Verify the bundle contains both client code and HTML
expect(bundle.client).toBeDefined();
expect(bundle.html).toBeDefined();
expect(bundle.sourceMap).toBeDefined();
});
});