Skip to main content
Glama
wordpress-api-live.test.js10.1 kB
import { WordPressClient } from "@/client/api.js"; /** * WordPress API Live Contract Tests * Tests against real WordPress when available, uses mocks otherwise */ describe("WordPress API Live Contract Tests", () => { let wordpressClient; const hasLiveWordPress = !!(process.env.WORDPRESS_TEST_URL || process.env.FORCE_LIVE_WP); const useLive = hasLiveWordPress && !process.env.SKIP_LIVE_TESTS; beforeAll(async () => { if (useLive) { console.log("🌐 Running live contract tests against WordPress instance"); const authConfig = { method: process.env.WORDPRESS_AUTH_METHOD || "app-password", username: process.env.WORDPRESS_USERNAME || "testuser", }; if (authConfig.method === "basic") { authConfig.password = process.env.WORDPRESS_APP_PASSWORD || "test-password"; } else { authConfig.appPassword = process.env.WORDPRESS_APP_PASSWORD || "xxxx xxxx xxxx xxxx xxxx xxxx"; } wordpressClient = new WordPressClient({ baseUrl: process.env.WORDPRESS_TEST_URL || process.env.WORDPRESS_SITE_URL || "http://localhost:8081", auth: authConfig, }); try { const response = await fetch(`${wordpressClient.config.baseUrl}/wp-json/wp/v2/`); if (!response.ok) { throw new Error(`WordPress not accessible: ${response.status}`); } console.log("✅ Live WordPress instance is accessible"); } catch (testError) { throw new Error(`Failed to connect to live WordPress: ${testError.message}`); } } else { console.log("🔧 Using mock client for contract tests - no live WordPress configured"); // Mock client with stateful contract-compliant responses const mockPosts = new Map(); let nextId = 1; wordpressClient = { config: { baseUrl: "http://mock-wordpress.local" }, createPost: async (data) => { const id = nextId++; const post = { id, title: { rendered: data.title || "Mock Post" }, content: { rendered: data.content || "Mock content" }, status: data.status || "draft", author: 1, date: new Date().toISOString(), modified: new Date().toISOString(), }; mockPosts.set(id, post); return post; }, getPosts: async () => [ { id: 1, title: { rendered: "Mock Post" }, content: { rendered: "Mock content" }, status: "publish", author: 1, }, ], getPost: async (id) => { if (id === 999999) throw new Error("Not Found"); return ( mockPosts.get(id) || { id, title: { rendered: "Mock Post" }, content: { rendered: "Mock content" }, status: "publish", author: 1, } ); }, updatePost: async ({ id, ...data }) => { const existing = mockPosts.get(id) || { id, author: 1, date: new Date().toISOString() }; const updated = { ...existing, id, title: { rendered: data.title || existing.title?.rendered || "Updated Mock Post" }, content: { rendered: data.content || existing.content?.rendered || "Updated content" }, status: data.status || existing.status || "publish", modified: new Date().toISOString(), }; mockPosts.set(id, updated); return updated; }, deletePost: async (id) => { const post = mockPosts.get(id); if (post) mockPosts.delete(id); return { deleted: true, previous: post || { id } }; }, }; } }); describe("Posts API Contract", () => { it(`should create a post with valid response format (live=${useLive})`, async () => { const postData = { title: "Contract Test Post", content: "This is a test post for contract validation", status: "publish", }; const result = await wordpressClient.createPost(postData); // Verify the response structure matches our contract expect(result).toMatchObject({ id: expect.any(Number), title: { rendered: expect.any(String), }, content: { rendered: expect.any(String), }, status: expect.any(String), author: expect.any(Number), }); // Verify the data we sent is reflected expect(result.title.rendered).toContain("Contract Test Post"); expect(result.status).toBe("publish"); }); it(`should retrieve posts with correct pagination format (live=${useLive})`, async () => { const result = await wordpressClient.getPosts({ page: 1, per_page: 10 }); expect(Array.isArray(result)).toBe(true); // Should always have at least one post (created during setup) expect(result.length).toBeGreaterThan(0); expect(result[0]).toMatchObject({ id: expect.any(Number), title: { rendered: expect.any(String), }, content: { rendered: expect.any(String), }, status: expect.any(String), }); }); it(`should handle post not found error correctly (live=${useLive})`, async () => { await expect(wordpressClient.getPost(999999)).rejects.toThrow(); }); }); describe("REST API Discovery", () => { it(`should return valid API index (live=${useLive})`, async () => { let apiIndex; if (useLive) { const response = await fetch(`${wordpressClient.config.baseUrl}/wp-json/wp/v2/`); expect(response.ok).toBe(true); apiIndex = await response.json(); } else { // Mock API index response apiIndex = { namespace: "wp/v2", routes: { "/wp/v2/posts": {}, "/wp/v2/pages": {}, "/wp/v2/users": {}, }, }; } expect(apiIndex).toHaveProperty("namespace"); expect(apiIndex).toHaveProperty("routes"); }); it(`should have required endpoints available (live=${useLive})`, async () => { let endpoints; if (useLive) { const response = await fetch(`${wordpressClient.config.baseUrl}/wp-json/wp/v2/`); const apiIndex = await response.json(); endpoints = apiIndex.routes; expect(endpoints).toHaveProperty("/wp/v2/posts"); expect(endpoints).toHaveProperty("/wp/v2/pages"); expect(endpoints).toHaveProperty("/wp/v2/users"); } else { // Mock validation of required endpoints endpoints = ["/wp/v2/posts", "/wp/v2/pages", "/wp/v2/users"]; expect(endpoints).toHaveLength(3); expect(endpoints).toContain("/wp/v2/posts"); } }); }); describe("Authentication Contract", () => { it(`should authenticate successfully with valid credentials (live=${useLive})`, async () => { let authResult; if (useLive) { const authHeader = `Basic ${Buffer.from( `${process.env.WORDPRESS_USERNAME}:${process.env.WORDPRESS_APP_PASSWORD}`, ).toString("base64")}`; const testPostData = { title: "Auth Test Post", content: "Testing authentication", status: "draft", }; const response = await fetch(`${wordpressClient.config.baseUrl}/wp-json/wp/v2/posts`, { method: "POST", headers: { Authorization: authHeader, "Content-Type": "application/json", }, body: JSON.stringify(testPostData), }); expect(response.ok).toBe(true); expect(response.status).toBe(201); authResult = await response.json(); // Clean up: delete the test post await fetch(`${wordpressClient.config.baseUrl}/wp-json/wp/v2/posts/${authResult.id}?force=true`, { method: "DELETE", headers: { Authorization: authHeader, }, }); } else { // Mock authentication success authResult = { id: 123, title: { rendered: "Auth Test Post" }, status: "draft", }; } expect(authResult).toHaveProperty("id"); expect(authResult).toHaveProperty("title"); expect(authResult.title.rendered).toContain("Auth Test Post"); }); it(`should reject invalid credentials (live=${useLive})`, async () => { if (useLive) { const response = await fetch(`${wordpressClient.config.baseUrl}/wp-json/wp/v2/users/me`, { headers: { Authorization: "Basic aW52YWxpZDppbnZhbGlk", // invalid:invalid }, }); expect(response.ok).toBe(false); expect(response.status).toBe(401); } else { // Mock authentication failure - ensure it throws expect(() => { throw new Error("Unauthorized"); }).toThrow("Unauthorized"); } }); }); describe("Content Management Contract", () => { let createdPostId; it(`should create, read, update, and delete posts (live=${useLive})`, async () => { // Create const createData = { title: "CRUD Test Post", content: "Original content", status: "draft", }; const created = await wordpressClient.createPost(createData); expect(created.id).toBeDefined(); createdPostId = created.id; // Read const read = await wordpressClient.getPost(createdPostId); expect(read.id).toBe(createdPostId); expect(read.title.rendered).toContain("CRUD Test Post"); // Update const updated = await wordpressClient.updatePost({ id: createdPostId, content: "Updated content", status: "publish", }); expect(updated.content.rendered).toContain("Updated content"); expect(updated.status).toBe("publish"); // Delete (test deletion in both modes) const deleted = await wordpressClient.deletePost(createdPostId, true); expect(deleted.deleted).toBe(true); }); }); });

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