diff --git a/tests/integration/BlogCore.integration.test.jsx b/tests/integration/BlogCore.integration.test.jsx
new file mode 100644
index 0000000..175b594
--- /dev/null
+++ b/tests/integration/BlogCore.integration.test.jsx
@@ -0,0 +1,171 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { render, screen } from "@testing-library/react";
+import RelatedArticles from "../../app/components/RelatedArticles";
+
+// Mock ContentThumbnailTemplate with a simple implementation
+vi.mock("../../app/components/ContentThumbnailTemplate", () => ({
+ default: ({ post, variant }) => (
+
+ ),
+}));
+
+// Mock blog post data
+const mockRelatedPosts = [
+ {
+ slug: "resolving-active-conflicts",
+ frontmatter: {
+ title: "Resolving Active Conflicts",
+ description:
+ "Practical steps for resolving conflicts while maintaining trust",
+ author: "Test Author",
+ date: "2025-04-15",
+ },
+ },
+ {
+ slug: "operational-security-mutual-aid",
+ frontmatter: {
+ title: "Operational Security for Mutual Aid",
+ description:
+ "Tactics to protect members, secure communication, and prevent infiltration",
+ author: "Test Author",
+ date: "2025-04-14",
+ },
+ },
+ {
+ slug: "making-decisions-without-hierarchy",
+ frontmatter: {
+ title: "Making Decisions Without Hierarchy",
+ description:
+ "A brief guide to collaborative nonhierarchical decision making",
+ author: "Test Author",
+ date: "2025-04-13",
+ },
+ },
+];
+
+describe("Blog Core Integration", () => {
+ beforeEach(() => {
+ // Mock window.innerWidth for responsive tests
+ Object.defineProperty(window, "innerWidth", {
+ writable: true,
+ configurable: true,
+ value: 1024, // Desktop width
+ });
+ });
+
+ it("should render RelatedArticles component with correct structure", () => {
+ render(
+
+ );
+
+ // Verify the section exists
+ expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent(
+ "Related Articles"
+ );
+
+ // Verify thumbnails are rendered
+ expect(
+ screen.getByTestId("thumbnail-operational-security-mutual-aid")
+ ).toBeInTheDocument();
+ expect(
+ screen.getByTestId("thumbnail-making-decisions-without-hierarchy")
+ ).toBeInTheDocument();
+
+ // Current post should not be displayed
+ expect(
+ screen.queryByTestId("thumbnail-resolving-active-conflicts")
+ ).not.toBeInTheDocument();
+ });
+
+ it("should filter out current post from related articles", () => {
+ render(
+
+ );
+
+ // Current post should not be displayed
+ expect(
+ screen.queryByTestId("thumbnail-resolving-active-conflicts")
+ ).not.toBeInTheDocument();
+
+ // Other posts should be displayed
+ expect(
+ screen.getByTestId("thumbnail-operational-security-mutual-aid")
+ ).toBeInTheDocument();
+ expect(
+ screen.getByTestId("thumbnail-making-decisions-without-hierarchy")
+ ).toBeInTheDocument();
+ });
+
+ it("should display all posts when no current post is specified", () => {
+ render();
+
+ // All posts should be displayed
+ expect(
+ screen.getByTestId("thumbnail-resolving-active-conflicts")
+ ).toBeInTheDocument();
+ expect(
+ screen.getByTestId("thumbnail-operational-security-mutual-aid")
+ ).toBeInTheDocument();
+ expect(
+ screen.getByTestId("thumbnail-making-decisions-without-hierarchy")
+ ).toBeInTheDocument();
+ });
+
+ it("should handle empty related posts array", () => {
+ const { container } = render(
+
+ );
+
+ expect(container.firstChild).toBeNull();
+ });
+
+ it("should create correct links for each thumbnail", () => {
+ render(
+
+ );
+
+ // Verify links are created correctly
+ const operationalLink = screen
+ .getByTestId("thumbnail-operational-security-mutual-aid")
+ .querySelector("a");
+ const hierarchyLink = screen
+ .getByTestId("thumbnail-making-decisions-without-hierarchy")
+ .querySelector("a");
+
+ expect(operationalLink).toHaveAttribute(
+ "href",
+ "/blog/operational-security-mutual-aid"
+ );
+ expect(hierarchyLink).toHaveAttribute(
+ "href",
+ "/blog/making-decisions-without-hierarchy"
+ );
+ });
+
+ it("should display section heading", () => {
+ render(
+
+ );
+
+ expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent(
+ "Related Articles"
+ );
+ });
+});
diff --git a/tests/integration/ContentProcessing.integration.test.js b/tests/integration/ContentProcessing.integration.test.js
new file mode 100644
index 0000000..ef52701
--- /dev/null
+++ b/tests/integration/ContentProcessing.integration.test.js
@@ -0,0 +1,98 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import fs from "fs";
+import path from "path";
+
+// Mock fs and path modules
+vi.mock("fs");
+vi.mock("path");
+
+// Import the content processing functions
+import { getBlogPostFiles, markdownToHtml } from "../../lib/content";
+
+describe("Content Processing Integration", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ describe("File System Integration", () => {
+ it("should read blog post files from content directory", () => {
+ const mockFiles = ["post1.md", "post2.md", "image.png", "post3.md"];
+ fs.readdirSync.mockReturnValue(mockFiles);
+
+ const result = getBlogPostFiles();
+
+ expect(fs.readdirSync).toHaveBeenCalledWith(
+ path.join(process.cwd(), "content/blog")
+ );
+ expect(result).toEqual(["post1.md", "post2.md", "post3.md"]);
+ });
+
+ it("should handle directory read errors gracefully", () => {
+ fs.readdirSync.mockImplementation(() => {
+ throw new Error("Directory not found");
+ });
+
+ const result = getBlogPostFiles();
+
+ expect(result).toEqual([]);
+ });
+
+ it("should filter out non-markdown files", () => {
+ const mockFiles = [
+ "post1.md",
+ "post2.mdx",
+ "image.png",
+ "post3.md",
+ "readme.txt",
+ ];
+ fs.readdirSync.mockReturnValue(mockFiles);
+
+ const result = getBlogPostFiles();
+
+ expect(result).toEqual(["post1.md", "post2.mdx", "post3.md"]);
+ });
+ });
+
+ describe("Markdown to HTML Integration", () => {
+ it("should convert markdown to HTML with proper formatting", () => {
+ const markdown = `# Main Title
+
+## Subtitle
+
+This is a paragraph with **bold** and *italic* text.
+
+- List item 1
+- List item 2
+
+[Link text](https://example.com)`;
+
+ const result = markdownToHtml(markdown);
+
+ expect(result).toContain("Main Title
");
+ expect(result).toContain("Subtitle
");
+ expect(result).toContain("bold");
+ expect(result).toContain("italic");
+ expect(result).toContain('Link text');
+ });
+
+ it("should handle empty markdown gracefully", () => {
+ const result = markdownToHtml("");
+
+ expect(result).toBe("");
+ });
+
+ it("should handle markdown with special characters", () => {
+ const markdown = `# Title with Special Characters: & < > " '
+
+Content with **bold** and *italic* text.`;
+
+ const result = markdownToHtml(markdown);
+
+ expect(result).toContain(
+ "Title with Special Characters: & < > \" '
"
+ );
+ expect(result).toContain("bold");
+ expect(result).toContain("italic");
+ });
+ });
+});
diff --git a/tests/integration/RelatedArticles.integration.test.jsx b/tests/integration/RelatedArticles.integration.test.jsx
new file mode 100644
index 0000000..e4678a3
--- /dev/null
+++ b/tests/integration/RelatedArticles.integration.test.jsx
@@ -0,0 +1,214 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { render, screen, fireEvent, waitFor } from "@testing-library/react";
+import RelatedArticles from "../../app/components/RelatedArticles";
+
+// Mock ContentThumbnailTemplate
+vi.mock("../../app/components/ContentThumbnailTemplate", () => ({
+ default: ({ post, variant }) => (
+
+ ),
+}));
+
+// Mock blog post data
+const mockRelatedPosts = [
+ {
+ slug: "resolving-active-conflicts",
+ frontmatter: {
+ title: "Resolving Active Conflicts",
+ description:
+ "Practical steps for resolving conflicts while maintaining trust",
+ author: "Test Author",
+ date: "2025-04-15",
+ },
+ },
+ {
+ slug: "operational-security-mutual-aid",
+ frontmatter: {
+ title: "Operational Security for Mutual Aid",
+ description:
+ "Tactics to protect members, secure communication, and prevent infiltration",
+ author: "Test Author",
+ date: "2025-04-14",
+ },
+ },
+ {
+ slug: "making-decisions-without-hierarchy",
+ frontmatter: {
+ title: "Making Decisions Without Hierarchy",
+ description:
+ "A brief guide to collaborative nonhierarchical decision making",
+ author: "Test Author",
+ date: "2025-04-13",
+ },
+ },
+ {
+ slug: "building-community-trust",
+ frontmatter: {
+ title: "Building Community Trust",
+ description: "Strategies for fostering trust in community organizations",
+ author: "Test Author",
+ date: "2025-04-12",
+ },
+ },
+];
+
+describe("Related Articles Integration", () => {
+ beforeEach(() => {
+ // Mock window.innerWidth for responsive tests
+ Object.defineProperty(window, "innerWidth", {
+ writable: true,
+ configurable: true,
+ value: 1024, // Desktop width
+ });
+ });
+
+ it("should filter out current post from related articles", () => {
+ render(
+
+ );
+
+ // Current post should not be displayed
+ expect(
+ screen.queryByTestId("thumbnail-resolving-active-conflicts")
+ ).not.toBeInTheDocument();
+
+ // Other posts should be displayed
+ expect(
+ screen.getByTestId("thumbnail-operational-security-mutual-aid")
+ ).toBeInTheDocument();
+ expect(
+ screen.getByTestId("thumbnail-making-decisions-without-hierarchy")
+ ).toBeInTheDocument();
+ expect(
+ screen.getByTestId("thumbnail-building-community-trust")
+ ).toBeInTheDocument();
+ });
+
+ it("should display all posts when no current post is specified", () => {
+ render();
+
+ // All posts should be displayed
+ expect(
+ screen.getByTestId("thumbnail-resolving-active-conflicts")
+ ).toBeInTheDocument();
+ expect(
+ screen.getByTestId("thumbnail-operational-security-mutual-aid")
+ ).toBeInTheDocument();
+ expect(
+ screen.getByTestId("thumbnail-making-decisions-without-hierarchy")
+ ).toBeInTheDocument();
+ expect(
+ screen.getByTestId("thumbnail-building-community-trust")
+ ).toBeInTheDocument();
+ });
+
+ it("should create correct links for each thumbnail", () => {
+ render(
+
+ );
+
+ // Verify links are created correctly
+ expect(
+ screen.getByTestId("thumbnail-link-operational-security-mutual-aid")
+ ).toHaveAttribute("href", "/blog/operational-security-mutual-aid");
+ expect(
+ screen.getByTestId("thumbnail-link-making-decisions-without-hierarchy")
+ ).toHaveAttribute("href", "/blog/making-decisions-without-hierarchy");
+ expect(
+ screen.getByTestId("thumbnail-link-building-community-trust")
+ ).toHaveAttribute("href", "/blog/building-community-trust");
+ });
+
+ it("should handle empty related posts array", () => {
+ const { container } = render(
+
+ );
+
+ expect(container.firstChild).toBeNull();
+ });
+
+ it("should handle single related post", () => {
+ const singlePost = [mockRelatedPosts[0]];
+
+ render(
+
+ );
+
+ expect(
+ screen.getByTestId("thumbnail-resolving-active-conflicts")
+ ).toBeInTheDocument();
+ expect(
+ screen.queryByTestId("thumbnail-operational-security-mutual-aid")
+ ).not.toBeInTheDocument();
+ });
+
+ it("should handle all posts being filtered out", () => {
+ const currentPostOnly = [mockRelatedPosts[0]];
+
+ const { container } = render(
+
+ );
+
+ expect(container.firstChild).toBeNull();
+ });
+
+ it("should display section heading", () => {
+ render(
+
+ );
+
+ expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent(
+ "Related Articles"
+ );
+ });
+
+ it("should maintain consistent structure across different current posts", () => {
+ const slugs = [
+ "resolving-active-conflicts",
+ "operational-security-mutual-aid",
+ "making-decisions-without-hierarchy",
+ ];
+
+ slugs.forEach((slug) => {
+ const { unmount } = render(
+
+ );
+
+ // Verify consistent structure
+ expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent(
+ "Related Articles"
+ );
+ // Check that we have some thumbnails (the exact ones depend on the current post)
+ const thumbnails = screen.getAllByTestId(/thumbnail-/);
+ expect(thumbnails.length).toBeGreaterThan(0);
+
+ unmount();
+ });
+ });
+});