diff --git a/package.json b/package.json index 897acd971..668cff49f 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "prototype": "pnpm --filter prototype dev", "playground": "pnpm --filter @apps/playground dev", "build": "pnpm -r build", - "test": "pnpm -r test", + "pretest": "pnpm --filter @object-ui/types build && pnpm --filter @object-ui/core build && pnpm --filter @object-ui/react build && pnpm --filter @object-ui/components build", + "test": "vitest run", "docs:dev": "pnpm --filter object-ui-docs dev", "docs:build": "pnpm --filter object-ui-docs build", "docs:preview": "pnpm --filter object-ui-docs preview", diff --git a/packages/plugin-charts/package.json b/packages/plugin-charts/package.json index d95d0eb99..a462b91a8 100644 --- a/packages/plugin-charts/package.json +++ b/packages/plugin-charts/package.json @@ -16,6 +16,7 @@ "scripts": { "build": "vite build", "test": "vitest run", + "test:watch": "vitest", "type-check": "tsc --noEmit", "lint": "eslint ." }, diff --git a/packages/plugin-charts/src/index.test.ts b/packages/plugin-charts/src/index.test.ts index eb24e67ea..154927a01 100644 --- a/packages/plugin-charts/src/index.test.ts +++ b/packages/plugin-charts/src/index.test.ts @@ -1,7 +1,128 @@ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, beforeAll } from 'vitest'; +import { ComponentRegistry } from '@object-ui/core'; -describe('@object-ui/plugin-charts', () => { - it('should pass', () => { - expect(true).toBe(true); +describe('Plugin Charts', () => { + // Import all renderers to register them + beforeAll(async () => { + await import('./index'); + }); + + describe('chart-bar component', () => { + it('should be registered in ComponentRegistry', () => { + const chartBarRenderer = ComponentRegistry.get('chart-bar'); + expect(chartBarRenderer).toBeDefined(); + }); + + it('should have proper metadata', () => { + const config = ComponentRegistry.getConfig('chart-bar'); + expect(config).toBeDefined(); + expect(config?.label).toBe('Bar Chart'); + expect(config?.category).toBe('plugin'); + expect(config?.inputs).toBeDefined(); + expect(config?.defaultProps).toBeDefined(); + }); + + it('should have expected inputs', () => { + const config = ComponentRegistry.getConfig('chart-bar'); + const inputNames = config?.inputs?.map((input: any) => input.name) || []; + + expect(inputNames).toContain('data'); + expect(inputNames).toContain('dataKey'); + expect(inputNames).toContain('xAxisKey'); + expect(inputNames).toContain('height'); + expect(inputNames).toContain('color'); + }); + + it('should have data as required input', () => { + const config = ComponentRegistry.getConfig('chart-bar'); + const dataInput = config?.inputs?.find((input: any) => input.name === 'data'); + + expect(dataInput).toBeDefined(); + expect(dataInput?.required).toBe(true); + expect(dataInput?.type).toBe('array'); + }); + + it('should have sensible default props', () => { + const config = ComponentRegistry.getConfig('chart-bar'); + const defaults = config?.defaultProps; + + expect(defaults).toBeDefined(); + expect(defaults?.dataKey).toBe('value'); + expect(defaults?.xAxisKey).toBe('name'); + expect(defaults?.height).toBe(400); + expect(defaults?.color).toBe('#8884d8'); + expect(defaults?.data).toBeDefined(); + expect(Array.isArray(defaults?.data)).toBe(true); + expect(defaults?.data.length).toBeGreaterThan(0); + }); + }); + + describe('chart (advanced) component', () => { + it('should be registered in ComponentRegistry', () => { + const chartRenderer = ComponentRegistry.get('chart'); + expect(chartRenderer).toBeDefined(); + }); + + it('should have proper metadata', () => { + const config = ComponentRegistry.getConfig('chart'); + expect(config).toBeDefined(); + expect(config?.label).toBe('Chart'); + expect(config?.category).toBe('plugin'); + expect(config?.inputs).toBeDefined(); + expect(config?.defaultProps).toBeDefined(); + }); + + it('should have expected inputs', () => { + const config = ComponentRegistry.getConfig('chart'); + const inputNames = config?.inputs?.map((input: any) => input.name) || []; + + expect(inputNames).toContain('chartType'); + expect(inputNames).toContain('data'); + expect(inputNames).toContain('config'); + expect(inputNames).toContain('xAxisKey'); + expect(inputNames).toContain('series'); + expect(inputNames).toContain('className'); + }); + + it('should have chartType as enum input', () => { + const config = ComponentRegistry.getConfig('chart'); + const chartTypeInput = config?.inputs?.find((input: any) => input.name === 'chartType'); + + expect(chartTypeInput).toBeDefined(); + expect(chartTypeInput?.type).toBe('enum'); + expect(chartTypeInput?.enum).toBeDefined(); + expect(Array.isArray(chartTypeInput?.enum)).toBe(true); + + const enumValues = chartTypeInput?.enum?.map((e: any) => e.value) || []; + expect(enumValues).toContain('bar'); + expect(enumValues).toContain('line'); + expect(enumValues).toContain('area'); + }); + + it('should have data and series as required inputs', () => { + const config = ComponentRegistry.getConfig('chart'); + const dataInput = config?.inputs?.find((input: any) => input.name === 'data'); + const seriesInput = config?.inputs?.find((input: any) => input.name === 'series'); + + expect(dataInput?.required).toBe(true); + expect(seriesInput?.required).toBe(true); + }); + + it('should have sensible default props', () => { + const config = ComponentRegistry.getConfig('chart'); + const defaults = config?.defaultProps; + + expect(defaults).toBeDefined(); + expect(defaults?.chartType).toBe('bar'); + expect(defaults?.xAxisKey).toBe('name'); + expect(defaults?.data).toBeDefined(); + expect(Array.isArray(defaults?.data)).toBe(true); + expect(defaults?.data.length).toBeGreaterThan(0); + expect(defaults?.config).toBeDefined(); + expect(typeof defaults?.config).toBe('object'); + expect(defaults?.series).toBeDefined(); + expect(Array.isArray(defaults?.series)).toBe(true); + expect(defaults?.series.length).toBeGreaterThan(0); + }); }); }); diff --git a/packages/plugin-editor/package.json b/packages/plugin-editor/package.json index acbb08776..09ddecb94 100644 --- a/packages/plugin-editor/package.json +++ b/packages/plugin-editor/package.json @@ -16,6 +16,7 @@ "scripts": { "build": "vite build", "test": "vitest run", + "test:watch": "vitest", "type-check": "tsc --noEmit", "lint": "eslint ." }, diff --git a/packages/plugin-editor/src/index.test.ts b/packages/plugin-editor/src/index.test.ts index 7eb4084b1..3d1e07ec6 100644 --- a/packages/plugin-editor/src/index.test.ts +++ b/packages/plugin-editor/src/index.test.ts @@ -1,7 +1,90 @@ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, beforeAll } from 'vitest'; +import { ComponentRegistry } from '@object-ui/core'; -describe('@object-ui/plugin-editor', () => { - it('should pass', () => { - expect(true).toBe(true); +describe('Plugin Editor', () => { + // Import all renderers to register them + beforeAll(async () => { + await import('./index'); + }); + + describe('code-editor component', () => { + it('should be registered in ComponentRegistry', () => { + const editorRenderer = ComponentRegistry.get('code-editor'); + expect(editorRenderer).toBeDefined(); + }); + + it('should have proper metadata', () => { + const config = ComponentRegistry.getConfig('code-editor'); + expect(config).toBeDefined(); + expect(config?.label).toBe('Code Editor'); + expect(config?.category).toBe('plugin'); + expect(config?.inputs).toBeDefined(); + expect(config?.defaultProps).toBeDefined(); + }); + + it('should have expected inputs', () => { + const config = ComponentRegistry.getConfig('code-editor'); + const inputNames = config?.inputs?.map((input: any) => input.name) || []; + + expect(inputNames).toContain('value'); + expect(inputNames).toContain('language'); + expect(inputNames).toContain('theme'); + expect(inputNames).toContain('height'); + expect(inputNames).toContain('readOnly'); + }); + + it('should have language as enum input', () => { + const config = ComponentRegistry.getConfig('code-editor'); + const languageInput = config?.inputs?.find((input: any) => input.name === 'language'); + + expect(languageInput).toBeDefined(); + expect(languageInput?.type).toBe('enum'); + expect(languageInput?.enum).toBeDefined(); + expect(Array.isArray(languageInput?.enum)).toBe(true); + + const enumValues = languageInput?.enum || []; + expect(enumValues).toContain('javascript'); + expect(enumValues).toContain('typescript'); + expect(enumValues).toContain('python'); + expect(enumValues).toContain('json'); + expect(enumValues).toContain('html'); + expect(enumValues).toContain('css'); + }); + + it('should have theme as enum input', () => { + const config = ComponentRegistry.getConfig('code-editor'); + const themeInput = config?.inputs?.find((input: any) => input.name === 'theme'); + + expect(themeInput).toBeDefined(); + expect(themeInput?.type).toBe('enum'); + expect(themeInput?.enum).toBeDefined(); + expect(Array.isArray(themeInput?.enum)).toBe(true); + + const enumValues = themeInput?.enum || []; + expect(enumValues).toContain('vs-dark'); + expect(enumValues).toContain('light'); + }); + + it('should have sensible default props', () => { + const config = ComponentRegistry.getConfig('code-editor'); + const defaults = config?.defaultProps; + + expect(defaults).toBeDefined(); + expect(defaults?.value).toBeDefined(); + expect(typeof defaults?.value).toBe('string'); + expect(defaults?.language).toBe('javascript'); + expect(defaults?.theme).toBe('vs-dark'); + expect(defaults?.height).toBe('400px'); + expect(defaults?.readOnly).toBe(false); + }); + + it('should have readOnly as boolean input', () => { + const config = ComponentRegistry.getConfig('code-editor'); + const readOnlyInput = config?.inputs?.find((input: any) => input.name === 'readOnly'); + + expect(readOnlyInput).toBeDefined(); + expect(readOnlyInput?.type).toBe('boolean'); + expect(readOnlyInput?.defaultValue).toBe(false); + }); }); }); diff --git a/packages/plugin-kanban/package.json b/packages/plugin-kanban/package.json index 85b352c08..2ccb23358 100644 --- a/packages/plugin-kanban/package.json +++ b/packages/plugin-kanban/package.json @@ -16,6 +16,7 @@ "scripts": { "build": "vite build", "test": "vitest run", + "test:watch": "vitest", "type-check": "tsc --noEmit", "lint": "eslint ." }, diff --git a/packages/plugin-kanban/src/index.test.ts b/packages/plugin-kanban/src/index.test.ts index 241b2f2fa..57cf5f228 100644 --- a/packages/plugin-kanban/src/index.test.ts +++ b/packages/plugin-kanban/src/index.test.ts @@ -1,7 +1,104 @@ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, beforeAll } from 'vitest'; +import { ComponentRegistry } from '@object-ui/core'; -describe('@object-ui/plugin-kanban', () => { - it('should pass', () => { - expect(true).toBe(true); +describe('Plugin Kanban', () => { + // Import all renderers to register them + beforeAll(async () => { + await import('./index'); + }); + + describe('kanban component', () => { + it('should be registered in ComponentRegistry', () => { + const kanbanRenderer = ComponentRegistry.get('kanban'); + expect(kanbanRenderer).toBeDefined(); + }); + + it('should have proper metadata', () => { + const config = ComponentRegistry.getConfig('kanban'); + expect(config).toBeDefined(); + expect(config?.label).toBe('Kanban Board'); + expect(config?.icon).toBe('LayoutDashboard'); + expect(config?.category).toBe('plugin'); + expect(config?.inputs).toBeDefined(); + expect(config?.defaultProps).toBeDefined(); + }); + + it('should have expected inputs', () => { + const config = ComponentRegistry.getConfig('kanban'); + const inputNames = config?.inputs?.map((input: any) => input.name) || []; + + expect(inputNames).toContain('columns'); + expect(inputNames).toContain('onCardMove'); + expect(inputNames).toContain('className'); + }); + + it('should have columns as required input', () => { + const config = ComponentRegistry.getConfig('kanban'); + const columnsInput = config?.inputs?.find((input: any) => input.name === 'columns'); + + expect(columnsInput).toBeDefined(); + expect(columnsInput?.required).toBe(true); + expect(columnsInput?.type).toBe('array'); + expect(columnsInput?.description).toBeDefined(); + }); + + it('should have onCardMove as code input', () => { + const config = ComponentRegistry.getConfig('kanban'); + const onCardMoveInput = config?.inputs?.find((input: any) => input.name === 'onCardMove'); + + expect(onCardMoveInput).toBeDefined(); + expect(onCardMoveInput?.type).toBe('code'); + expect(onCardMoveInput?.advanced).toBe(true); + expect(onCardMoveInput?.description).toBeDefined(); + }); + + it('should have sensible default props', () => { + const config = ComponentRegistry.getConfig('kanban'); + const defaults = config?.defaultProps; + + expect(defaults).toBeDefined(); + expect(defaults?.columns).toBeDefined(); + expect(Array.isArray(defaults?.columns)).toBe(true); + expect(defaults?.columns.length).toBeGreaterThan(0); + expect(defaults?.className).toBe('w-full'); + }); + + it('should have default columns with proper structure', () => { + const config = ComponentRegistry.getConfig('kanban'); + const defaults = config?.defaultProps; + const columns = defaults?.columns || []; + + // Verify at least 3 columns exist (todo, in-progress, done) + expect(columns.length).toBeGreaterThanOrEqual(3); + + // Verify each column has required properties + columns.forEach((column: any) => { + expect(column.id).toBeDefined(); + expect(column.title).toBeDefined(); + expect(column.cards).toBeDefined(); + expect(Array.isArray(column.cards)).toBe(true); + }); + + // Verify at least one column has cards + const hasCards = columns.some((column: any) => column.cards.length > 0); + expect(hasCards).toBe(true); + }); + + it('should have cards with proper structure', () => { + const config = ComponentRegistry.getConfig('kanban'); + const defaults = config?.defaultProps; + const columns = defaults?.columns || []; + + // Find a column with cards + const columnWithCards = columns.find((column: any) => column.cards.length > 0); + expect(columnWithCards).toBeDefined(); + + const card = columnWithCards.cards[0]; + expect(card.id).toBeDefined(); + expect(card.title).toBeDefined(); + expect(card.description).toBeDefined(); + expect(card.badges).toBeDefined(); + expect(Array.isArray(card.badges)).toBe(true); + }); }); }); diff --git a/packages/plugin-markdown/package.json b/packages/plugin-markdown/package.json index 053d8d4ea..f42ebefa1 100644 --- a/packages/plugin-markdown/package.json +++ b/packages/plugin-markdown/package.json @@ -16,6 +16,7 @@ "scripts": { "build": "vite build", "test": "vitest run", + "test:watch": "vitest", "type-check": "tsc --noEmit", "lint": "eslint ." }, diff --git a/packages/plugin-markdown/src/index.test.ts b/packages/plugin-markdown/src/index.test.ts index a9985cd23..a457be4c4 100644 --- a/packages/plugin-markdown/src/index.test.ts +++ b/packages/plugin-markdown/src/index.test.ts @@ -1,7 +1,55 @@ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, beforeAll } from 'vitest'; +import { ComponentRegistry } from '@object-ui/core'; -describe('@object-ui/plugin-markdown', () => { - it('should pass', () => { - expect(true).toBe(true); +describe('Plugin Markdown', () => { + // Import all renderers to register them + beforeAll(async () => { + await import('./index'); + }); + + describe('markdown component', () => { + it('should be registered in ComponentRegistry', () => { + const markdownRenderer = ComponentRegistry.get('markdown'); + expect(markdownRenderer).toBeDefined(); + }); + + it('should have proper metadata', () => { + const config = ComponentRegistry.getConfig('markdown'); + expect(config).toBeDefined(); + expect(config?.label).toBe('Markdown'); + expect(config?.category).toBe('plugin'); + expect(config?.inputs).toBeDefined(); + expect(config?.defaultProps).toBeDefined(); + }); + + it('should have expected inputs', () => { + const config = ComponentRegistry.getConfig('markdown'); + const inputNames = config?.inputs?.map((input: any) => input.name) || []; + + expect(inputNames).toContain('content'); + expect(inputNames).toContain('className'); + }); + + it('should have content as required input', () => { + const config = ComponentRegistry.getConfig('markdown'); + const contentInput = config?.inputs?.find((input: any) => input.name === 'content'); + + expect(contentInput).toBeDefined(); + expect(contentInput?.required).toBe(true); + expect(contentInput?.type).toBe('string'); + expect(contentInput?.inputType).toBe('textarea'); + }); + + it('should have sensible default props', () => { + const config = ComponentRegistry.getConfig('markdown'); + const defaults = config?.defaultProps; + + expect(defaults).toBeDefined(); + expect(defaults?.content).toBeDefined(); + expect(typeof defaults?.content).toBe('string'); + expect(defaults?.content.length).toBeGreaterThan(0); + // Verify it contains markdown syntax + expect(defaults?.content).toContain('#'); + }); }); });