Value Generators
Value generators create dynamic test data that QA can use in visual test flows.
Export Pattern
// src/generators/index.ts
import type { ValueFunction } from "../types";
export const $$ValueFunctions: ValueFunction[] = [
generateUserId,
generateTestUser,
generateOrder,
];Function Signature
Generators accept 0 or 1 parameter:
// No parameters
async function generateTimestamp()
// Single parameter (object for flexibility)
async function generateTestUser(options?: { role?: string; verified?: boolean })Example: Simple Generator
export const generateUserId: ValueFunction = {
id: "generate-user-id",
name: "Generate User ID",
description: "Creates a unique user identifier",
enabled: true,
deprecated: false,
tested: true,
function: async () => {
return `user_${Date.now()}_${_.random(1000, 9999)}`;
},
};Example: Parameterized Generator
import { z } from "zod";
const TestUserSchema = z.object({
role: z.enum(["admin", "user", "guest"]).default("user"),
verified: z.boolean().default(false),
count: z.number().int().positive().default(1),
});
export const generateTestUsers: ValueFunction = {
id: "generate-test-users",
name: "Generate Test Users",
description: "Creates test user objects with configurable options",
enabled: true,
deprecated: false,
tested: true,
function: async (options?: unknown) => {
const config = TestUserSchema.parse(options || {});
const users = [];
for (let i = 0; i < config.count; i++) {
users.push({
id: faker.number.int({ min: 1000, max: 9999 }),
email: faker.internet.email(),
name: faker.person.fullName(),
role: config.role,
verified: config.verified,
createdAt: Date.now(),
});
}
return config.count === 1 ? users[0] : users;
},
};Example: Using Context
export const generateOrderForUser: ValueFunction = {
id: "generate-order-for-user",
name: "Generate Order for User",
description: "Creates an order linked to the current user in context",
enabled: true,
deprecated: false,
tested: true,
function: async (options?: { itemCount?: number }) => {
const itemCount = options?.itemCount || 3;
const userId = $context.userId; // Read from test context
const items = [];
let total = 0;
for (let i = 0; i < itemCount; i++) {
const price = _.random(10, 200);
const quantity = _.random(1, 5);
items.push({
id: faker.string.uuid(),
name: faker.commerce.productName(),
price,
quantity,
});
total += price * quantity;
}
return {
id: faker.string.uuid(),
userId,
items,
total,
currency: "USD",
createdAt: Date.now(),
};
},
};Example: Fetching Remote Data
export const fetchTestUser: ValueFunction = {
id: "fetch-test-user",
name: "Fetch Test User",
description: "Retrieves a test user from the test data API",
enabled: true,
deprecated: false,
tested: true,
function: async (criteria?: { role?: string }) => {
const baseUrl = $vars.testDataApiUrl || "https://test-data.example.com";
const params = new URLSearchParams();
if (criteria?.role) {
params.append("role", criteria.role);
}
const response = await ky.get(`${baseUrl}/users?${params}`).json();
return response.data;
},
};Parameter Validation
Always validate parameters with Zod:
const OptionsSchema = z.object({
count: z.number().int().positive().default(10),
type: z.enum(["user", "admin"]).default("user"),
}).default({});
function: async (options?: unknown) => {
const config = OptionsSchema.parse(options);
// Use validated config
}Best Practices
Use Object Parameters
// ✅ Good: Flexible, extensible
function: async (options?: { count?: number; type?: string })
// ❌ Bad: Hard to extend
function: async (count: number, type: string, verified: boolean)Provide Defaults
const config = OptionsSchema.parse(options || {});
// If options is undefined, defaults are appliedUse Descriptive Names
// ✅ Good
id: "generate-authenticated-user-with-permissions"
// ❌ Bad
id: "gen-user"Usage in Tests
Once synced and enabled:
- Context Operations → Select from dropdown
- Script Node →
const user = await $gen.generateTestUser({ role: "admin" }) - JS Expression →
js: $gen.generateUserId()