Skip to main content
Glama
basic-property.test.js10.1 kB
import * as fc from "fast-check"; /** * Basic property-based testing demonstration * This demonstrates the concept and validates that fast-check is working */ describe("Basic Property-Based Testing", () => { describe("WordPress ID Properties", () => { it("should validate that positive integers remain positive after processing", () => { fc.assert( fc.property(fc.integer({ min: 1, max: 999999 }), (id) => { // Property: WordPress IDs should always be positive integers expect(id).toBeGreaterThan(0); expect(Number.isInteger(id)).toBe(true); // Property: String conversion and back should preserve value const stringId = id.toString(); const parsedId = parseInt(stringId, 10); expect(parsedId).toBe(id); }), ); }); it("should reject invalid ID values consistently", () => { fc.assert( fc.property( fc.oneof( fc.constant(0), fc.constant(-1), fc.constant(null), fc.constant(undefined), fc.constant("abc"), fc.constant(NaN), ), (invalidId) => { // Property: Invalid IDs should always fail validation const isInvalidId = invalidId === 0 || invalidId === -1 || invalidId === null || invalidId === undefined || typeof invalidId === "string" || isNaN(invalidId); expect(isInvalidId).toBe(true); // Additional validation for numbers expect(typeof invalidId === "number" ? invalidId <= 0 || isNaN(invalidId) : true).toBe(true); }, ), ); }); }); describe("String Processing Properties", () => { it("should handle safe strings without modification", () => { fc.assert( fc.property( fc.string({ minLength: 1, maxLength: 100 }).filter((s) => !s.includes("<") && !s.includes(">")), (safeString) => { // Property: Safe strings should pass through unchanged expect(typeof safeString).toBe("string"); expect(safeString.length).toBeGreaterThan(0); // Property: No dangerous content expect(safeString).not.toMatch(/<script/i); expect(safeString).not.toMatch(/javascript:/i); }, ), ); }); it("should handle malicious strings by rejecting them", () => { fc.assert( fc.property( fc.constantFrom( '<script>alert("xss")</script>', "javascript:alert(1)", "../../etc/passwd", "'; DROP TABLE posts; --", ), (maliciousString) => { // Property: Malicious strings should be identifiable const hasDangerousContent = maliciousString.includes("<script") || maliciousString.includes("javascript:") || maliciousString.includes("../") || maliciousString.includes("DROP TABLE"); expect(hasDangerousContent).toBe(true); }, ), ); }); }); describe("WordPress Data Structure Properties", () => { it("should validate post-like objects maintain required fields", () => { fc.assert( fc.property( fc.record({ id: fc.integer({ min: 1, max: 999999 }), title: fc.string({ minLength: 1, maxLength: 200 }), content: fc.string({ minLength: 0, maxLength: 10000 }), status: fc.constantFrom("publish", "draft", "private"), author: fc.integer({ min: 1, max: 999999 }), }), (postObject) => { // Property: Required fields should always be present and valid expect(postObject.id).toBeGreaterThan(0); expect(typeof postObject.title).toBe("string"); expect(postObject.title.length).toBeGreaterThan(0); expect(typeof postObject.content).toBe("string"); expect(["publish", "draft", "private"]).toContain(postObject.status); expect(postObject.author).toBeGreaterThan(0); }, ), ); }); it("should validate user-like objects maintain email format", () => { fc.assert( fc.property( fc.record({ id: fc.integer({ min: 1, max: 999999 }), username: fc .string({ minLength: 1, maxLength: 60 }) .map((s) => s.replace(/[^a-zA-Z0-9._@-]/g, "")) .filter((s) => s.length > 0), email: fc.emailAddress(), }), (userObject) => { // Property: User objects should have valid structure expect(userObject.id).toBeGreaterThan(0); expect(typeof userObject.username).toBe("string"); expect(userObject.username.length).toBeGreaterThan(0); expect(userObject.username.length).toBeLessThanOrEqual(60); // Property: Email should be valid format expect(typeof userObject.email).toBe("string"); expect(userObject.email).toMatch(/^[^\s@]+@[^\s@]+\.[^\s@]+$/); }, ), ); }); }); describe("Array and Collection Properties", () => { it("should handle arrays of IDs consistently", () => { fc.assert( fc.property(fc.array(fc.integer({ min: 1, max: 999999 }), { maxLength: 10 }), (idArray) => { // Property: All elements should be valid IDs expect(Array.isArray(idArray)).toBe(true); idArray.forEach((id) => { expect(id).toBeGreaterThan(0); expect(Number.isInteger(id)).toBe(true); }); // Property: Array operations should preserve validity const filtered = idArray.filter((id) => id > 0); expect(filtered).toHaveLength(idArray.length); }), ); }); it("should maintain uniqueness when required", () => { fc.assert( fc.property( fc.array(fc.integer({ min: 1, max: 100 }), { minLength: 5, maxLength: 10, }), (numbers) => { // Property: Deduplication should work correctly const unique = [...new Set(numbers)]; expect(unique.length).toBeLessThanOrEqual(numbers.length); // Property: All unique elements should be from original array unique.forEach((num) => { expect(numbers).toContain(num); }); }, ), ); }); }); describe("Query Parameter Properties", () => { it("should handle pagination parameters correctly", () => { fc.assert( fc.property( fc.record({ page: fc.option(fc.integer({ min: 1, max: 100 })), per_page: fc.option(fc.integer({ min: 1, max: 100 })), offset: fc.option(fc.integer({ min: 0, max: 1000 })), }), (paginationParams) => { // Property: Pagination parameters should be valid when present const pageValid = paginationParams.page === null || paginationParams.page === undefined || (paginationParams.page > 0 && paginationParams.page <= 100); expect(pageValid).toBe(true); const perPageValid = paginationParams.per_page === null || paginationParams.per_page === undefined || (paginationParams.per_page > 0 && paginationParams.per_page <= 100); expect(perPageValid).toBe(true); const offsetValid = paginationParams.offset === null || paginationParams.offset === undefined || (paginationParams.offset >= 0 && paginationParams.offset <= 1000); expect(offsetValid).toBe(true); }, ), ); }); }); describe("Error Handling Properties", () => { it("should handle edge case inputs gracefully", () => { fc.assert( fc.property( fc.oneof( fc.constant(""), fc.constant(" "), fc.constant("\n"), fc.constant("\t"), fc.string({ maxLength: 0 }), ), (edgeCaseString) => { // Property: Edge case strings should be handled predictably expect(typeof edgeCaseString).toBe("string"); expect(edgeCaseString.length).toBeLessThanOrEqual(10); // Reasonable limit }, ), ); }); it("should maintain type consistency across operations", () => { fc.assert( fc.property( fc.record({ stringField: fc.string(), numberField: fc.integer(), booleanField: fc.boolean(), arrayField: fc.array(fc.string(), { maxLength: 5 }), }), (mixedObject) => { // Property: Types should remain consistent expect(typeof mixedObject.stringField).toBe("string"); expect(typeof mixedObject.numberField).toBe("number"); expect(typeof mixedObject.booleanField).toBe("boolean"); expect(Array.isArray(mixedObject.arrayField)).toBe(true); expect(mixedObject.arrayField.length).toBeLessThanOrEqual(5); }, ), ); }); }); describe("Performance Properties", () => { it("should complete operations within reasonable time", () => { fc.assert( fc.property(fc.array(fc.string({ maxLength: 100 }), { maxLength: 100 }), (stringArray) => { const startTime = Date.now(); // Simulate some processing const processed = stringArray .filter((s) => s.length > 0) .map((s) => s.toLowerCase()) .slice(0, 50); const endTime = Date.now(); const duration = endTime - startTime; // Property: Operations should complete quickly expect(duration).toBeLessThan(50); // 50ms threshold expect(processed.length).toBeLessThanOrEqual(stringArray.length); }), ); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/docdyhr/mcp-wordpress'

If you have feedback or need assistance with the MCP directory API, please join our Discord server