code-docs/utils/block-dev.md
Block testing and development utilities.
Provides testing utilities for:
import { mockBlock, runBlockSchemaTests } from '@lowdefy/block-dev';
Create mock block environment for testing:
import { mockBlock } from '@lowdefy/block-dev';
const { block, methods, makeCssClass } = mockBlock({
meta: {
valueType: 'string',
category: 'input',
},
schema: buttonSchema,
});
// block contains mock block instance
// methods contains Jest mock functions
// makeCssClass is mocked CSS generator
Returns:
| Property | Description |
|---|---|
block | Mock block instance |
methods | Object with mock methods |
makeCssClass | CSS class generator |
lowdefy | Mock lowdefy context |
schemaError | Schema validation errors |
Mocked Methods:
setValue - Mock for input value changestriggerEvent - Mock for event triggeringregisterMethod - Mock for method registrationregisterEvent - Mock for event registrationmoveItemDown - Mock for list item movementmoveItemUp - Mock for list item movementpushItem - Mock for adding list itemsremoveItem - Mock for removing list itemsunshiftItem - Mock for prepending list itemsRun Jest schema validation tests:
import { runBlockSchemaTests } from '@lowdefy/block-dev';
describe('Button Schema', () => {
runBlockSchemaTests({
examples: [
{
id: 'basic',
type: 'Button',
properties: { label: 'Click' },
},
{
id: 'styled',
type: 'Button',
properties: { label: 'Submit', color: 'primary' },
},
],
schema: buttonSchema,
});
});
Render blocks and compare snapshots:
import { runRenderTests } from '@lowdefy/block-dev';
import Button from './Button';
describe('Button Render', () => {
runRenderTests({
examples: [
{
id: 'basic',
type: 'Button',
properties: { label: 'Click' },
},
],
Block: Button,
methods: {
triggerEvent: jest.fn(),
},
});
});
Render with mocked data:
import { runMockRenderTests } from '@lowdefy/block-dev';
describe('Table Render', () => {
runMockRenderTests({
examples: tableExamples,
Block: Table,
mockDataTest: (data) => {
return data.map((row) => ({ ...row, id: 'mock-id' }));
},
});
});
Test block methods in isolation:
import { runMockMethodTests } from '@lowdefy/block-dev';
describe('Input Methods', () => {
runMockMethodTests({
meta: {
valueType: 'string',
category: 'input',
},
schema: inputSchema,
});
});
Generate stub props for testing:
import { stubBlockProps } from '@lowdefy/block-dev';
const props = stubBlockProps({
block: {
id: 'test-button',
type: 'Button',
properties: { label: 'Test' },
},
meta: { category: 'display' },
schema: buttonSchema,
});
// props can be spread into component
<Button {...props} />;
Error class for schema violations:
import { BlockSchemaErrors } from '@lowdefy/block-dev';
try {
validateBlock(block);
} catch (error) {
if (error instanceof BlockSchemaErrors) {
console.log(error.errors);
}
}
mockBlock automatically mocks:
Math.random = () => 0.5; // Deterministic for snapshots
window.matchMedia = (query) => ({
matches: false,
media: query,
addListener: () => {},
removeListener: () => {},
});
window.AnimationEvent = function () {};
window.TransitionEvent = function () {};
@lowdefy/block-utils (4.4.0)@lowdefy/helpers (4.4.0)@testing-library/react@testing-library/domjest (28.1.3)@emotion/jestimport React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { mockBlock, runBlockSchemaTests, stubBlockProps } from '@lowdefy/block-dev';
import Button from '../Button';
import buttonSchema from '../buttonSchema';
import buttonExamples from '../examples.yaml';
describe('Button', () => {
// Schema tests
runBlockSchemaTests({
examples: buttonExamples,
schema: buttonSchema,
});
// Render test
test('renders with label', () => {
const props = stubBlockProps({
block: { id: 'btn', type: 'Button', properties: { label: 'Click' } },
meta: { category: 'input' },
schema: buttonSchema,
});
const { getByText } = render(<Button {...props} />);
expect(getByText('Click')).toBeInTheDocument();
});
// Event test
test('triggers onClick event', () => {
const { block, methods } = mockBlock({
meta: { category: 'input' },
schema: buttonSchema,
});
const props = stubBlockProps({
block: { id: 'btn', type: 'Button', properties: { label: 'Click' } },
meta: { category: 'input' },
schema: buttonSchema,
});
const { getByRole } = render(<Button {...props} methods={methods} />);
fireEvent.click(getByRole('button'));
expect(methods.triggerEvent).toHaveBeenCalledWith({ name: 'onClick' });
});
});
import { mockBlock, stubBlockProps } from '@lowdefy/block-dev';
import TextInput from '../TextInput';
import inputSchema from '../inputSchema';
describe('TextInput', () => {
test('calls setValue on change', () => {
const { methods } = mockBlock({
meta: { valueType: 'string', category: 'input' },
schema: inputSchema,
});
const props = stubBlockProps({
block: { id: 'input', type: 'TextInput', properties: {} },
meta: { valueType: 'string', category: 'input' },
schema: inputSchema,
});
const { getByRole } = render(<TextInput {...props} methods={methods} />);
fireEvent.change(getByRole('textbox'), { target: { value: 'test' } });
expect(methods.setValue).toHaveBeenCalledWith('test');
});
});
| File | Purpose |
|---|---|
src/mockBlock.js | Block environment mocking |
src/runBlockSchemaTests.js | Schema test runner |
src/runRenderTests.js | Render test runner |
src/stubBlockProps.js | Props generation |
src/BlockSchemaErrors.js | Error class |