Implement Operation ujsx component with props and leaf node behavior
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
export { Operation } from "./operation.js";
|
||||||
|
export type { OperationProps } from "./operation.js";
|
||||||
export { Parallel } from "./parallel.js";
|
export { Parallel } from "./parallel.js";
|
||||||
export type { ParallelProps } from "./parallel.js";
|
export type { ParallelProps } from "./parallel.js";
|
||||||
export { Sequential } from "./sequential.js";
|
export { Sequential } from "./sequential.js";
|
||||||
|
|||||||
@@ -1 +1,32 @@
|
|||||||
export {};
|
import type { UComponent, UElement, UNode, UniversalProps } from "@alkdev/ujsx";
|
||||||
|
import type { PropValue } from "@alkdev/ujsx";
|
||||||
|
|
||||||
|
export interface OperationProps extends UniversalProps {
|
||||||
|
name: string;
|
||||||
|
input?: PropValue;
|
||||||
|
retries?: number;
|
||||||
|
timeout?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Operation: UComponent<OperationProps> = (
|
||||||
|
props: OperationProps & { children?: UNode[] },
|
||||||
|
): UElement => {
|
||||||
|
const { name, input, retries, timeout, children, ...rest } = props;
|
||||||
|
const elementProps: UniversalProps = { ...rest, name };
|
||||||
|
if (input !== undefined) {
|
||||||
|
elementProps.input = input;
|
||||||
|
}
|
||||||
|
if (retries !== undefined) {
|
||||||
|
elementProps.retries = retries;
|
||||||
|
}
|
||||||
|
if (timeout !== undefined) {
|
||||||
|
elementProps.timeout = timeout;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: "operation",
|
||||||
|
props: elementProps,
|
||||||
|
children: [],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Operation.displayName = "Operation";
|
||||||
87
test/component/operation.test.ts
Normal file
87
test/component/operation.test.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import { Operation } from "../../src/component/operation.js";
|
||||||
|
import type { OperationProps } from "../../src/component/operation.js";
|
||||||
|
import type { UElement, UNode } from "@alkdev/ujsx";
|
||||||
|
|
||||||
|
describe("Operation", () => {
|
||||||
|
it("produces UElement with type operation", () => {
|
||||||
|
const el = Operation({ name: "classify" } as OperationProps & { children?: UNode[] });
|
||||||
|
expect(el.type).toBe("operation");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("requires name prop", () => {
|
||||||
|
const el = Operation({ name: "architect" } as OperationProps & { children?: UNode[] });
|
||||||
|
expect((el as UElement).props.name).toBe("architect");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has no children (leaf node)", () => {
|
||||||
|
const el = Operation({ name: "classify" } as OperationProps & { children?: UNode[] });
|
||||||
|
expect(el.children).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores children even if provided (leaf node)", () => {
|
||||||
|
const el = Operation({
|
||||||
|
name: "classify",
|
||||||
|
children: ["child1"],
|
||||||
|
} as OperationProps & { children?: UNode[] });
|
||||||
|
expect(el.children).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves optional input prop", () => {
|
||||||
|
const el = Operation({
|
||||||
|
name: "process",
|
||||||
|
input: { key: "value" },
|
||||||
|
} as OperationProps & { children?: UNode[] });
|
||||||
|
expect((el as UElement).props.input).toEqual({ key: "value" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves optional retries prop", () => {
|
||||||
|
const el = Operation({
|
||||||
|
name: "fetch",
|
||||||
|
retries: 3,
|
||||||
|
} as OperationProps & { children?: UNode[] });
|
||||||
|
expect((el as UElement).props.retries).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves optional timeout prop", () => {
|
||||||
|
const el = Operation({
|
||||||
|
name: "fetch",
|
||||||
|
timeout: 5000,
|
||||||
|
} as OperationProps & { children?: UNode[] });
|
||||||
|
expect((el as UElement).props.timeout).toBe(5000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("omits optional props when not provided", () => {
|
||||||
|
const el = Operation({ name: "classify" } as OperationProps & { children?: UNode[] });
|
||||||
|
expect((el as UElement).props.input).toBeUndefined();
|
||||||
|
expect((el as UElement).props.retries).toBeUndefined();
|
||||||
|
expect((el as UElement).props.timeout).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves all props together", () => {
|
||||||
|
const el = Operation({
|
||||||
|
name: "fetch",
|
||||||
|
input: "data",
|
||||||
|
retries: 2,
|
||||||
|
timeout: 10000,
|
||||||
|
} as OperationProps & { children?: UNode[] });
|
||||||
|
expect((el as UElement).props.name).toBe("fetch");
|
||||||
|
expect((el as UElement).props.input).toBe("data");
|
||||||
|
expect((el as UElement).props.retries).toBe(2);
|
||||||
|
expect((el as UElement).props.timeout).toBe(10000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("is a valid UElement (has type, props, children)", () => {
|
||||||
|
const el = Operation({ name: "test" } as OperationProps & { children?: UNode[] });
|
||||||
|
expect(el).toHaveProperty("type");
|
||||||
|
expect(el).toHaveProperty("props");
|
||||||
|
expect(el).toHaveProperty("children");
|
||||||
|
expect(typeof el.type).toBe("string");
|
||||||
|
expect(typeof el.props).toBe("object");
|
||||||
|
expect(Array.isArray(el.children)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("displayName is Operation", () => {
|
||||||
|
expect(Operation.displayName).toBe("Operation");
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user