diff --git a/app/components/ContentBanner.js b/app/components/ContentBanner.js index 698e05a..a5e4c9c 100644 --- a/app/components/ContentBanner.js +++ b/app/components/ContentBanner.js @@ -20,7 +20,7 @@ export default function ContentBanner({ post }) { className="absolute inset-0 w-full h-full bg-cover bg-no-repeat aspect-[640/224] md:block hidden" style={{ backgroundImage: `url(${getAssetPath( - "assets/Content_Banner_2.svg" + "assets/Content_Banner_2.svg", )})`, backgroundPosition: "center bottom", }} diff --git a/app/components/Logo.js b/app/components/Logo.js index f00b7d3..53d9a39 100644 --- a/app/components/Logo.js +++ b/app/components/Logo.js @@ -94,26 +94,26 @@ export default function Logo({ size = "default", showText = true }) { size === "homeHeaderXsmall" ? sizes.homeHeaderXsmall : size === "homeHeaderSm" - ? sizes.homeHeaderSm - : size === "homeHeaderMd" - ? sizes.homeHeaderMd - : size === "homeHeaderLg" - ? sizes.homeHeaderLg - : size === "homeHeaderXl" - ? sizes.homeHeaderXl - : size === "header" - ? sizes.header - : size === "headerMd" - ? sizes.headerMd - : size === "headerLg" - ? sizes.headerLg - : size === "headerXl" - ? sizes.headerXl - : size === "footer" - ? sizes.footer - : size === "footerLg" - ? sizes.footerLg - : sizes.default; + ? sizes.homeHeaderSm + : size === "homeHeaderMd" + ? sizes.homeHeaderMd + : size === "homeHeaderLg" + ? sizes.homeHeaderLg + : size === "homeHeaderXl" + ? sizes.homeHeaderXl + : size === "header" + ? sizes.header + : size === "headerMd" + ? sizes.headerMd + : size === "headerLg" + ? sizes.headerLg + : size === "headerXl" + ? sizes.headerXl + : size === "footer" + ? sizes.footer + : size === "footerLg" + ? sizes.footerLg + : sizes.default; return ( diff --git a/app/components/RelatedArticles.js b/app/components/RelatedArticles.js index cab114f..9164d3a 100644 --- a/app/components/RelatedArticles.js +++ b/app/components/RelatedArticles.js @@ -6,7 +6,7 @@ import ContentThumbnailTemplate from "./ContentThumbnailTemplate"; export default function RelatedArticles({ relatedPosts, currentPostSlug }) { // Filter out the current post from related posts const filteredPosts = relatedPosts.filter( - (post) => post.slug !== currentPostSlug + (post) => post.slug !== currentPostSlug, ); const [currentIndex, setCurrentIndex] = useState(0); @@ -93,7 +93,7 @@ export default function RelatedArticles({ relatedPosts, currentPostSlug }) { const handleMouseUp = () => { document.removeEventListener( "mousemove", - handleMouseMove + handleMouseMove, ); document.removeEventListener("mouseup", handleMouseUp); }; @@ -133,8 +133,8 @@ export default function RelatedArticles({ relatedPosts, currentPostSlug }) { index === currentIndex ? `${progress}%` : index < currentIndex - ? "100%" - : "0%", + ? "100%" + : "0%", }} /> diff --git a/app/tailwind.css b/app/tailwind.css index f8a2885..5ce56f7 100644 --- a/app/tailwind.css +++ b/app/tailwind.css @@ -29,12 +29,15 @@ --color-*: initial; /* Font families */ - --font-sans: var(--font-inter), ui-sans-serif, system-ui, -apple-system, + --font-sans: + var(--font-inter), ui-sans-serif, system-ui, -apple-system, "Segoe UI", + Roboto, "Helvetica Neue", Arial, sans-serif; + --font-display: + var(--font-bricolage-grotesque), ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; - --font-display: var(--font-bricolage-grotesque), ui-sans-serif, system-ui, - -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; - --font-mono: var(--font-space-grotesk), ui-monospace, SFMono-Regular, - "SF Mono", Consolas, "Liberation Mono", Menlo, monospace; + --font-mono: + var(--font-space-grotesk), ui-monospace, SFMono-Regular, "SF Mono", + Consolas, "Liberation Mono", Menlo, monospace; /* Dimension */ --spacing-scale-000: 0px; diff --git a/app/test-thumbnail/page.js b/app/test-thumbnail/page.js index c82a2ed..18ab2f1 100644 --- a/app/test-thumbnail/page.js +++ b/app/test-thumbnail/page.js @@ -92,8 +92,8 @@ export default function TestThumbnailPage() { className - Additional CSS classes
  • - variant - "vertical" (default) or "horizontal" - (for development/testing) + variant - "vertical" (default) or + "horizontal" (for development/testing)
  • diff --git a/lib/content.js b/lib/content.js index 0d5c363..480968c 100644 --- a/lib/content.js +++ b/lib/content.js @@ -60,7 +60,7 @@ export function getBlogPostFiles() { try { const files = fs.readdirSync(contentDirectory); return files.filter( - (file) => file.endsWith(".md") || file.endsWith(".mdx") + (file) => file.endsWith(".md") || file.endsWith(".mdx"), ); } catch (error) { console.error("Error reading blog content directory:", error); @@ -84,7 +84,7 @@ export function parseBlogPost(filePath) { if (!validationResult.isValid) { console.error( `Validation errors for ${filePath}:`, - validationResult.errors + validationResult.errors, ); return null; } @@ -116,7 +116,7 @@ export function getAllBlogPosts() { .map((fileName) => parseBlogPost(fileName)) .filter(Boolean) // Filter out nulls (invalid posts) .sort( - (a, b) => new Date(b.frontmatter.date) - new Date(a.frontmatter.date) + (a, b) => new Date(b.frontmatter.date) - new Date(a.frontmatter.date), ); // Sort by date descending return allPosts; } @@ -141,11 +141,11 @@ export function getBlogPostBySlug(slug) { export function getRelatedBlogPosts( currentPostSlug, relatedSlugs = [], - limit = 3 + limit = 3, ) { const allPosts = getAllBlogPosts(); const filteredPosts = allPosts.filter( - (post) => post.slug !== currentPostSlug + (post) => post.slug !== currentPostSlug, ); let related = []; @@ -191,7 +191,7 @@ export function getAllTags() { export function getBlogPostsByTag(tag) { const allPosts = getAllBlogPosts(); return allPosts.filter( - (post) => post.frontmatter.tags && post.frontmatter.tags.includes(tag) + (post) => post.frontmatter.tags && post.frontmatter.tags.includes(tag), ); } @@ -216,7 +216,7 @@ export function searchBlogPosts(query, limit = 10) { .includes(searchTerm); const contentMatch = post.content.toLowerCase().includes(searchTerm); const tagMatch = post.frontmatter.tags?.some((tag) => - tag.toLowerCase().includes(searchTerm) + tag.toLowerCase().includes(searchTerm), ); return titleMatch || descriptionMatch || contentMatch || tagMatch; @@ -233,7 +233,7 @@ export function searchBlogPosts(query, limit = 10) { export function getBlogPostsByAuthor(author) { const allPosts = getAllBlogPosts(); return allPosts.filter( - (post) => post.frontmatter.author.toLowerCase() === author.toLowerCase() + (post) => post.frontmatter.author.toLowerCase() === author.toLowerCase(), ); } @@ -274,9 +274,9 @@ export function getBlogStats() { 1, (new Date(allPosts[0].frontmatter.date) - new Date(allPosts[allPosts.length - 1].frontmatter.date)) / - (1000 * 60 * 60 * 24 * 30) + (1000 * 60 * 60 * 24 * 30), )) * - 10 + 10, ) / 10 : 0, }; diff --git a/lib/contentProcessor.js b/lib/contentProcessor.js index f7138e2..d5e0128 100644 --- a/lib/contentProcessor.js +++ b/lib/contentProcessor.js @@ -41,7 +41,7 @@ class ContentProcessor { // Warm up cache await warmCache( () => this.getAllPosts(), - () => this.getAllTags() + () => this.getAllTags(), ); this.isInitialized = true; @@ -60,7 +60,7 @@ class ContentProcessor { try { const files = fs.readdirSync(this.contentDirectory); return files.filter( - (file) => file.endsWith(".md") || file.endsWith(".mdx") + (file) => file.endsWith(".md") || file.endsWith(".mdx"), ); } catch (error) { console.error("Error reading blog content directory:", error); @@ -85,7 +85,7 @@ class ContentProcessor { if (!validationResult.isValid) { console.error( `Validation errors for ${filePath}:`, - validationResult.errors + validationResult.errors, ); return null; } @@ -145,7 +145,7 @@ class ContentProcessor { .map((fileName) => this.processBlogPost(fileName)) .filter(Boolean) .sort( - (a, b) => new Date(b.frontmatter.date) - new Date(a.frontmatter.date) + (a, b) => new Date(b.frontmatter.date) - new Date(a.frontmatter.date), ); // Cache the result @@ -230,7 +230,7 @@ class ContentProcessor { return { totalPosts: allPosts.length, totalAuthors: new Set( - allPosts.map((post) => post.frontmatter.author).size + allPosts.map((post) => post.frontmatter.author).size, ), dateRange: { earliest: @@ -247,9 +247,9 @@ class ContentProcessor { 1, (new Date(allPosts[0].frontmatter.date) - new Date(allPosts[allPosts.length - 1].frontmatter.date)) / - (1000 * 60 * 60 * 24 * 30) + (1000 * 60 * 60 * 24 * 30), )) * - 10 + 10, ) / 10 : 0, }; diff --git a/lib/mdx.js b/lib/mdx.js index 3ba71fb..de67c15 100644 --- a/lib/mdx.js +++ b/lib/mdx.js @@ -159,34 +159,34 @@ function markdownToHtml(markdown) { // Headers with IDs .replace( /^###### (.*$)/gim, - (m, t) => `
    ${t}
    ` + (m, t) => `
    ${t}
    `, ) .replace( /^##### (.*$)/gim, - (m, t) => `
    ${t}
    ` + (m, t) => `
    ${t}
    `, ) .replace( /^#### (.*$)/gim, - (m, t) => `

    ${t}

    ` + (m, t) => `

    ${t}

    `, ) .replace( /^### (.*$)/gim, - (m, t) => `

    ${t}

    ` + (m, t) => `

    ${t}

    `, ) .replace( /^## (.*$)/gim, - (m, t) => `

    ${t}

    ` + (m, t) => `

    ${t}

    `, ) .replace( /^# (.*$)/gim, - (m, t) => `

    ${t}

    ` + (m, t) => `

    ${t}

    `, ) // Code fences (block) and inline code .replace( /```(\w+)?\n([\s\S]*?)\n```/g, (m, lang = "", code) => - `
    ${code}
    ` + `
    ${code}
    `, ) .replace(/`([^`]+)`/g, "$1") @@ -198,12 +198,12 @@ function markdownToHtml(markdown) { .replace( /!\[([^\]]*)\]\(([^)\s]+)(?:\s+"([^"]+)")?\)/g, (m, alt, src, title = "") => - `${alt}` + `${alt}`, ) .replace( /\[([^\]]+)\]\(([^)\s]+)(?:\s+"([^"]+)")?\)/g, (m, text, href, title = "") => - `${text}` + `${text}`, ) // Blockquotes @@ -211,7 +211,7 @@ function markdownToHtml(markdown) { const inner = m.replace(/^>\s?/gm, ""); return `

    ${inner.replace( /\n{2,}/g, - "

    " + "

    ", )}

    `; }) @@ -247,7 +247,7 @@ function markdownToHtml(markdown) { // (Also skip our GAP_TOKEN so we can turn it into gap paragraphs later.) .replace( /^(?!\s*<(h[1-6]|ul|ol|li|blockquote|hr|pre|code|table|img)\b)(?!\s*<\/)(?!\s*)(.+)$/gim, - "

    $2

    " + "

    $2

    ", ) // Clean up truly empty paragraphs but keep   gap paragraphs @@ -258,8 +258,8 @@ function markdownToHtml(markdown) { //g, (m, n) => `` + n, + )}" aria-hidden="true">`, ) ); } diff --git a/lib/validation.js b/lib/validation.js index e1fde28..9cf8c43 100644 --- a/lib/validation.js +++ b/lib/validation.js @@ -81,12 +81,12 @@ export function validateBlogPost(frontmatter) { if (config.type === "string" && typeof frontmatter[field] === "string") { if (config.minLength && frontmatter[field].length < config.minLength) { errors.push( - `Field ${field} must be at least ${config.minLength} characters` + `Field ${field} must be at least ${config.minLength} characters`, ); } if (config.maxLength && frontmatter[field].length > config.maxLength) { errors.push( - `Field ${field} must be no more than ${config.maxLength} characters` + `Field ${field} must be no more than ${config.maxLength} characters`, ); } } @@ -105,12 +105,12 @@ export function validateBlogPost(frontmatter) { } if (config.items.minLength && item.length < config.items.minLength) { errors.push( - `Item ${i} in ${field} must be at least ${config.items.minLength} characters` + `Item ${i} in ${field} must be at least ${config.items.minLength} characters`, ); } if (config.items.maxLength && item.length > config.items.maxLength) { errors.push( - `Item ${i} in ${field} must be no more than ${config.items.maxLength} characters` + `Item ${i} in ${field} must be no more than ${config.items.maxLength} characters`, ); } } diff --git a/tests/e2e/BlogNavigation.e2e.test.jsx b/tests/e2e/BlogNavigation.e2e.test.jsx index c2aabb6..8d4777d 100644 --- a/tests/e2e/BlogNavigation.e2e.test.jsx +++ b/tests/e2e/BlogNavigation.e2e.test.jsx @@ -87,7 +87,7 @@ describe("Blog Navigation E2E", () => { expect(thumbnailLink).toBeInTheDocument(); expect(thumbnailLink).toHaveAttribute( "href", - "/blog/resolving-active-conflicts" + "/blog/resolving-active-conflicts", ); // Click the thumbnail @@ -102,12 +102,12 @@ describe("Blog Navigation E2E", () => { // Verify post content is displayed expect( - screen.getByText("Resolving Active Conflicts") + screen.getByText("Resolving Active Conflicts"), ).toBeInTheDocument(); expect( screen.getByText( - "Practical steps for resolving conflicts while maintaining trust" - ) + "Practical steps for resolving conflicts while maintaining trust", + ), ).toBeInTheDocument(); expect(screen.getByText("Test Author")).toBeInTheDocument(); expect(screen.getByText("April 2025")).toBeInTheDocument(); @@ -128,10 +128,10 @@ describe("Blog Navigation E2E", () => { // Verify related articles are displayed expect( - screen.getByText("Operational Security for Mutual Aid") + screen.getByText("Operational Security for Mutual Aid"), ).toBeInTheDocument(); expect( - screen.getByText("Making Decisions Without Hierarchy") + screen.getByText("Making Decisions Without Hierarchy"), ).toBeInTheDocument(); // Verify links are present @@ -139,11 +139,11 @@ describe("Blog Navigation E2E", () => { expect(relatedLinks).toHaveLength(2); expect(relatedLinks[0]).toHaveAttribute( "href", - "/blog/operational-security-mutual-aid" + "/blog/operational-security-mutual-aid", ); expect(relatedLinks[1]).toHaveAttribute( "href", - "/blog/making-decisions-without-hierarchy" + "/blog/making-decisions-without-hierarchy", ); }); @@ -160,7 +160,7 @@ describe("Blog Navigation E2E", () => { // Verify navigation was called expect(mockPush).toHaveBeenCalledWith( - "/blog/operational-security-mutual-aid" + "/blog/operational-security-mutual-aid", ); }); @@ -176,7 +176,7 @@ describe("Blog Navigation E2E", () => { it("should complete navigation flow: thumbnail → related article", () => { // Render thumbnail const { rerender } = render( - + , ); // Click thumbnail @@ -194,7 +194,7 @@ describe("Blog Navigation E2E", () => { .closest("a"); fireEvent.click(relatedLink); expect(mockPush).toHaveBeenCalledWith( - "/blog/operational-security-mutual-aid" + "/blog/operational-security-mutual-aid", ); }); }); diff --git a/tests/e2e/ContentPageRendering.e2e.test.jsx b/tests/e2e/ContentPageRendering.e2e.test.jsx index 168f3e3..843ee69 100644 --- a/tests/e2e/ContentPageRendering.e2e.test.jsx +++ b/tests/e2e/ContentPageRendering.e2e.test.jsx @@ -66,7 +66,7 @@ describe("Content Page Rendering E2E", () => { // Verify banner content expect(screen.getByText("Test Article Title")).toBeInTheDocument(); expect( - screen.getByText("This is a test article description") + screen.getByText("This is a test article description"), ).toBeInTheDocument(); expect(screen.getByText("Test Author")).toBeInTheDocument(); expect(screen.getByText("April 2025")).toBeInTheDocument(); @@ -112,16 +112,16 @@ describe("Content Page Rendering E2E", () => { title="Still have questions?" subtitle="Get help from our community organizers" description="We're here to help you with any questions or concerns." - /> + />, ); // Verify ask organizer content expect(screen.getByText("Still have questions?")).toBeInTheDocument(); expect( - screen.getByText("Get help from our community organizers") + screen.getByText("Get help from our community organizers"), ).toBeInTheDocument(); expect( - screen.getByRole("link", { name: /ask an organizer/i }) + screen.getByRole("link", { name: /ask an organizer/i }), ).toBeInTheDocument(); }); @@ -131,16 +131,16 @@ describe("Content Page Rendering E2E", () => { variant="inverse" title="Still have questions?" subtitle="Get help from our community organizers" - /> + />, ); // Verify ask organizer content is still present expect(screen.getByText("Still have questions?")).toBeInTheDocument(); expect( - screen.getByText("Get help from our community organizers") + screen.getByText("Get help from our community organizers"), ).toBeInTheDocument(); expect( - screen.getByRole("link", { name: /ask an organizer/i }) + screen.getByRole("link", { name: /ask an organizer/i }), ).toBeInTheDocument(); }); @@ -163,7 +163,7 @@ describe("Content Page Rendering E2E", () => { title="Still have questions?" subtitle="Get help from our community organizers" /> - + , ); // Verify both components are rendered @@ -179,7 +179,7 @@ describe("Content Page Rendering E2E", () => { title="Still have questions?" subtitle="Get help from our community organizers" /> - + , ); // Verify semantic structure diff --git a/tests/integration/BlogCore.integration.test.jsx b/tests/integration/BlogCore.integration.test.jsx index 175b594..4fb0619 100644 --- a/tests/integration/BlogCore.integration.test.jsx +++ b/tests/integration/BlogCore.integration.test.jsx @@ -63,25 +63,25 @@ describe("Blog Core Integration", () => { + />, ); // Verify the section exists expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent( - "Related Articles" + "Related Articles", ); // Verify thumbnails are rendered expect( - screen.getByTestId("thumbnail-operational-security-mutual-aid") + screen.getByTestId("thumbnail-operational-security-mutual-aid"), ).toBeInTheDocument(); expect( - screen.getByTestId("thumbnail-making-decisions-without-hierarchy") + screen.getByTestId("thumbnail-making-decisions-without-hierarchy"), ).toBeInTheDocument(); // Current post should not be displayed expect( - screen.queryByTestId("thumbnail-resolving-active-conflicts") + screen.queryByTestId("thumbnail-resolving-active-conflicts"), ).not.toBeInTheDocument(); }); @@ -90,20 +90,20 @@ describe("Blog Core Integration", () => { + />, ); // Current post should not be displayed expect( - screen.queryByTestId("thumbnail-resolving-active-conflicts") + screen.queryByTestId("thumbnail-resolving-active-conflicts"), ).not.toBeInTheDocument(); // Other posts should be displayed expect( - screen.getByTestId("thumbnail-operational-security-mutual-aid") + screen.getByTestId("thumbnail-operational-security-mutual-aid"), ).toBeInTheDocument(); expect( - screen.getByTestId("thumbnail-making-decisions-without-hierarchy") + screen.getByTestId("thumbnail-making-decisions-without-hierarchy"), ).toBeInTheDocument(); }); @@ -112,19 +112,19 @@ describe("Blog Core Integration", () => { // All posts should be displayed expect( - screen.getByTestId("thumbnail-resolving-active-conflicts") + screen.getByTestId("thumbnail-resolving-active-conflicts"), ).toBeInTheDocument(); expect( - screen.getByTestId("thumbnail-operational-security-mutual-aid") + screen.getByTestId("thumbnail-operational-security-mutual-aid"), ).toBeInTheDocument(); expect( - screen.getByTestId("thumbnail-making-decisions-without-hierarchy") + screen.getByTestId("thumbnail-making-decisions-without-hierarchy"), ).toBeInTheDocument(); }); it("should handle empty related posts array", () => { const { container } = render( - + , ); expect(container.firstChild).toBeNull(); @@ -135,7 +135,7 @@ describe("Blog Core Integration", () => { + />, ); // Verify links are created correctly @@ -148,11 +148,11 @@ describe("Blog Core Integration", () => { expect(operationalLink).toHaveAttribute( "href", - "/blog/operational-security-mutual-aid" + "/blog/operational-security-mutual-aid", ); expect(hierarchyLink).toHaveAttribute( "href", - "/blog/making-decisions-without-hierarchy" + "/blog/making-decisions-without-hierarchy", ); }); @@ -161,11 +161,11 @@ describe("Blog Core Integration", () => { + />, ); expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent( - "Related Articles" + "Related Articles", ); }); }); diff --git a/tests/integration/ContentProcessing.integration.test.js b/tests/integration/ContentProcessing.integration.test.js index ef52701..dd43c18 100644 --- a/tests/integration/ContentProcessing.integration.test.js +++ b/tests/integration/ContentProcessing.integration.test.js @@ -22,7 +22,7 @@ describe("Content Processing Integration", () => { const result = getBlogPostFiles(); expect(fs.readdirSync).toHaveBeenCalledWith( - path.join(process.cwd(), "content/blog") + path.join(process.cwd(), "content/blog"), ); expect(result).toEqual(["post1.md", "post2.md", "post3.md"]); }); @@ -89,7 +89,7 @@ Content with **bold** and *italic* text.`; const result = markdownToHtml(markdown); expect(result).toContain( - "

    Title with Special Characters: & < > \" '

    " + "

    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 index e4678a3..44a5132 100644 --- a/tests/integration/RelatedArticles.integration.test.jsx +++ b/tests/integration/RelatedArticles.integration.test.jsx @@ -75,23 +75,23 @@ describe("Related Articles Integration", () => { + />, ); // Current post should not be displayed expect( - screen.queryByTestId("thumbnail-resolving-active-conflicts") + screen.queryByTestId("thumbnail-resolving-active-conflicts"), ).not.toBeInTheDocument(); // Other posts should be displayed expect( - screen.getByTestId("thumbnail-operational-security-mutual-aid") + screen.getByTestId("thumbnail-operational-security-mutual-aid"), ).toBeInTheDocument(); expect( - screen.getByTestId("thumbnail-making-decisions-without-hierarchy") + screen.getByTestId("thumbnail-making-decisions-without-hierarchy"), ).toBeInTheDocument(); expect( - screen.getByTestId("thumbnail-building-community-trust") + screen.getByTestId("thumbnail-building-community-trust"), ).toBeInTheDocument(); }); @@ -100,16 +100,16 @@ describe("Related Articles Integration", () => { // All posts should be displayed expect( - screen.getByTestId("thumbnail-resolving-active-conflicts") + screen.getByTestId("thumbnail-resolving-active-conflicts"), ).toBeInTheDocument(); expect( - screen.getByTestId("thumbnail-operational-security-mutual-aid") + screen.getByTestId("thumbnail-operational-security-mutual-aid"), ).toBeInTheDocument(); expect( - screen.getByTestId("thumbnail-making-decisions-without-hierarchy") + screen.getByTestId("thumbnail-making-decisions-without-hierarchy"), ).toBeInTheDocument(); expect( - screen.getByTestId("thumbnail-building-community-trust") + screen.getByTestId("thumbnail-building-community-trust"), ).toBeInTheDocument(); }); @@ -118,24 +118,24 @@ describe("Related Articles Integration", () => { + />, ); // Verify links are created correctly expect( - screen.getByTestId("thumbnail-link-operational-security-mutual-aid") + screen.getByTestId("thumbnail-link-operational-security-mutual-aid"), ).toHaveAttribute("href", "/blog/operational-security-mutual-aid"); expect( - screen.getByTestId("thumbnail-link-making-decisions-without-hierarchy") + screen.getByTestId("thumbnail-link-making-decisions-without-hierarchy"), ).toHaveAttribute("href", "/blog/making-decisions-without-hierarchy"); expect( - screen.getByTestId("thumbnail-link-building-community-trust") + 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(); @@ -148,14 +148,14 @@ describe("Related Articles Integration", () => { + />, ); expect( - screen.getByTestId("thumbnail-resolving-active-conflicts") + screen.getByTestId("thumbnail-resolving-active-conflicts"), ).toBeInTheDocument(); expect( - screen.queryByTestId("thumbnail-operational-security-mutual-aid") + screen.queryByTestId("thumbnail-operational-security-mutual-aid"), ).not.toBeInTheDocument(); }); @@ -166,7 +166,7 @@ describe("Related Articles Integration", () => { + />, ); expect(container.firstChild).toBeNull(); @@ -177,11 +177,11 @@ describe("Related Articles Integration", () => { + />, ); expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent( - "Related Articles" + "Related Articles", ); }); @@ -197,12 +197,12 @@ describe("Related Articles Integration", () => { + />, ); // Verify consistent structure expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent( - "Related Articles" + "Related Articles", ); // Check that we have some thumbnails (the exact ones depend on the current post) const thumbnails = screen.getAllByTestId(/thumbnail-/); diff --git a/tests/unit/BlogPage.test.jsx b/tests/unit/BlogPage.test.jsx index 3e1ec9c..3440778 100644 --- a/tests/unit/BlogPage.test.jsx +++ b/tests/unit/BlogPage.test.jsx @@ -131,7 +131,7 @@ describe("BlogPostPage", () => { "min-h-screen", "bg-[#F4F3F1]", "relative", - "overflow-hidden" + "overflow-hidden", ); }); @@ -144,7 +144,7 @@ describe("BlogPostPage", () => { expect(screen.getByTestId("content-banner")).toBeInTheDocument(); expect(screen.getByText("Test Article Title")).toBeInTheDocument(); expect( - screen.getByText("This is a test article description") + screen.getByText("This is a test article description"), ).toBeInTheDocument(); }); @@ -158,7 +158,7 @@ describe("BlogPostPage", () => { expect(article).toBeInTheDocument(); expect(article).toHaveClass( "p-[var(--spacing-scale-024)]", - "sm:py-[var(--spacing-scale-032)]" + "sm:py-[var(--spacing-scale-032)]", ); // Check content is rendered @@ -188,7 +188,7 @@ describe("BlogPostPage", () => { expect(screen.getByTestId("ask-organizer")).toBeInTheDocument(); expect(screen.getByText("Still have questions?")).toBeInTheDocument(); expect( - screen.getByText("Get answers from an experienced organizer") + screen.getByText("Get answers from an experienced organizer"), ).toBeInTheDocument(); expect(screen.getByText("Ask an organizer")).toBeInTheDocument(); }); @@ -220,7 +220,7 @@ describe("BlogPostPage", () => { expect(contentDiv).toHaveClass("post-body"); expect(contentDiv).toHaveClass("-mt-[var(--spacing-scale-048)]"); expect(contentDiv).toHaveClass( - "text-[var(--color-content-inverse-primary)]" + "text-[var(--color-content-inverse-primary)]", ); expect(contentDiv).toHaveClass("text-[16px]"); expect(contentDiv).toHaveClass("leading-[24px]"); @@ -267,7 +267,7 @@ describe("BlogPostPage", () => { // Check for script elements using querySelector since RTL ignores them const scripts = document.querySelectorAll( - 'script[type="application/ld+json"]' + 'script[type="application/ld+json"]', ); expect(scripts).toHaveLength(2); @@ -285,7 +285,7 @@ describe("BlogPostPage", () => { // The component should throw an error when post is null // This happens because notFound() is called await expect( - BlogPostPage({ params: { slug: "non-existent" } }) + BlogPostPage({ params: { slug: "non-existent" } }), ).rejects.toThrow(); }); @@ -297,7 +297,7 @@ describe("BlogPostPage", () => { // Current post should not appear in related articles expect( - screen.queryByTestId("related-test-article") + screen.queryByTestId("related-test-article"), ).not.toBeInTheDocument(); // Other related posts should appear @@ -322,7 +322,7 @@ describe("BlogPostPage", () => { "top-1/4", "right-0", "pointer-events-none", - "z-10" + "z-10", ); // Second shape (left side) @@ -334,7 +334,7 @@ describe("BlogPostPage", () => { "top-1/2", "left-0", "pointer-events-none", - "z-10" + "z-10", ); }); diff --git a/tests/unit/ContentBanner.test.jsx b/tests/unit/ContentBanner.test.jsx index fc34f63..97143c0 100644 --- a/tests/unit/ContentBanner.test.jsx +++ b/tests/unit/ContentBanner.test.jsx @@ -39,7 +39,7 @@ describe("ContentBanner", () => { // Check that the banner container exists - it's the first div with the specific classes const banner = document.querySelector( - "div[class*='pt-[var(--measures-spacing-016)]']" + "div[class*='pt-[var(--measures-spacing-016)]']", ); expect(banner).toBeInTheDocument(); expect(banner).toHaveClass( @@ -54,7 +54,7 @@ describe("ContentBanner", () => { "xl:h-[504px]", "relative", "w-full", - "sm:overflow-hidden" + "sm:overflow-hidden", ); }); @@ -63,7 +63,7 @@ describe("ContentBanner", () => { // Check for background div with correct styling const backgroundDiv = document.querySelector( - "div[style*='background-image']" + "div[style*='background-image']", ); expect(backgroundDiv).toBeInTheDocument(); expect(backgroundDiv).toHaveClass( @@ -73,7 +73,7 @@ describe("ContentBanner", () => { "h-full", "bg-cover", "bg-no-repeat", - "aspect-[320/225.5]" + "aspect-[320/225.5]", ); }); @@ -82,7 +82,7 @@ describe("ContentBanner", () => { // Check for the md+ background div const mdBackgroundDiv = document.querySelector( - "div[style*='Content_Banner_2.svg']" + "div[style*='Content_Banner_2.svg']", ); expect(mdBackgroundDiv).toBeInTheDocument(); expect(mdBackgroundDiv).toHaveClass("hidden", "md:block"); @@ -98,7 +98,7 @@ describe("ContentBanner", () => { render(); expect( - screen.getByText("This is a test article description") + screen.getByText("This is a test article description"), ).toBeInTheDocument(); }); @@ -114,7 +114,7 @@ describe("ContentBanner", () => { // Check the content container div const contentContainer = document.querySelector( - "div[class*='relative z-10']" + "div[class*='relative z-10']", ); expect(contentContainer).toBeInTheDocument(); expect(contentContainer).toHaveClass( @@ -122,7 +122,7 @@ describe("ContentBanner", () => { "z-10", "h-full", "flex", - "flex-col" + "flex-col", ); }); @@ -135,7 +135,7 @@ describe("ContentBanner", () => { "font-medium", "text-[18px]", "leading-[120%]", - "text-[var(--color-content-inverse-brand-royal)]" + "text-[var(--color-content-inverse-brand-royal)]", ); const description = screen.getByText("This is a test article description"); @@ -144,7 +144,7 @@ describe("ContentBanner", () => { "font-normal", "text-[12px]", "leading-[16px]", - "text-[var(--color-content-inverse-brand-royal)]" + "text-[var(--color-content-inverse-brand-royal)]", ); }); @@ -157,7 +157,7 @@ describe("ContentBanner", () => { "font-normal", "text-[10px]", "leading-[14px]", - "text-[var(--color-content-inverse-brand-royal)]" + "text-[var(--color-content-inverse-brand-royal)]", ); const date = screen.getByText("April 2025"); @@ -166,7 +166,7 @@ describe("ContentBanner", () => { "font-normal", "text-[10px]", "leading-[14px]", - "text-[var(--color-content-inverse-brand-royal)]" + "text-[var(--color-content-inverse-brand-royal)]", ); }); @@ -175,7 +175,7 @@ describe("ContentBanner", () => { // Check the ContentContainer spacing const contentContainer = document.querySelector( - "div[class*='relative z-20']" + "div[class*='relative z-20']", ); expect(contentContainer).toHaveClass("gap-[var(--measures-spacing-012)]"); }); @@ -184,13 +184,13 @@ describe("ContentBanner", () => { render(); const outerContainer = document.querySelector( - "div[class*='pt-[var(--measures-spacing-016)]']" + "div[class*='pt-[var(--measures-spacing-016)]']", ); expect(outerContainer).toHaveClass( "pt-[var(--measures-spacing-016)]", "md:pt-[var(--measures-spacing-008)]", "lg:pt-[50px]", - "xl:pt-[112px]" + "xl:pt-[112px]", ); }); @@ -216,7 +216,7 @@ describe("ContentBanner", () => { "sm:text-[24px]", "md:text-[32px]", "lg:text-[44px]", - "xl:text-[64px]" + "xl:text-[64px]", ); const description = screen.getByText("This is a test article description"); @@ -224,7 +224,7 @@ describe("ContentBanner", () => { "sm:text-[14px]", "md:text-[14px]", "lg:text-[18px]", - "xl:text-[24px]" + "xl:text-[24px]", ); }); diff --git a/tests/unit/ContentContainer.test.jsx b/tests/unit/ContentContainer.test.jsx index ac52118..4f4c689 100644 --- a/tests/unit/ContentContainer.test.jsx +++ b/tests/unit/ContentContainer.test.jsx @@ -36,7 +36,7 @@ describe("ContentContainer", () => { "z-20", "h-full", "flex", - "flex-col" + "flex-col", ); }); @@ -59,7 +59,7 @@ describe("ContentContainer", () => { "font-medium", "text-[18px]", "leading-[120%]", - "text-[var(--color-content-inverse-brand-royal)]" + "text-[var(--color-content-inverse-brand-royal)]", ); }); @@ -73,7 +73,7 @@ describe("ContentContainer", () => { "font-normal", "text-[12px]", "leading-[16px]", - "text-[var(--color-content-inverse-brand-royal)]" + "text-[var(--color-content-inverse-brand-royal)]", ); }); @@ -108,7 +108,7 @@ describe("ContentContainer", () => { // Check the content container (parent of icon) expect(iconContainer.parentElement).toHaveClass( - "gap-[var(--measures-spacing-008)]" + "gap-[var(--measures-spacing-008)]", ); // Check the text container (parent of title) - it has responsive gap classes expect(textContainer.parentElement).toHaveClass("flex", "flex-col"); @@ -121,7 +121,7 @@ describe("ContentContainer", () => { expect(metadataContainer).toHaveClass( "flex", "items-center", - "gap-[var(--measures-spacing-008)]" + "gap-[var(--measures-spacing-008)]", ); }); @@ -134,7 +134,7 @@ describe("ContentContainer", () => { "font-normal", "text-[10px]", "leading-[14px]", - "text-[var(--color-content-inverse-brand-royal)]" + "text-[var(--color-content-inverse-brand-royal)]", ); const date = screen.getByText("April 2025"); @@ -143,7 +143,7 @@ describe("ContentContainer", () => { "font-normal", "text-[10px]", "leading-[14px]", - "text-[var(--color-content-inverse-brand-royal)]" + "text-[var(--color-content-inverse-brand-royal)]", ); }); @@ -229,7 +229,7 @@ describe("ContentContainer", () => { render(); expect( - screen.getByText(/This is a very long article title/) + screen.getByText(/This is a very long article title/), ).toBeInTheDocument(); }); @@ -246,7 +246,7 @@ describe("ContentContainer", () => { render(); expect( - screen.getByText(/This is a very long article description/) + screen.getByText(/This is a very long article description/), ).toBeInTheDocument(); }); }); diff --git a/tests/unit/ContentThumbnailTemplate.test.jsx b/tests/unit/ContentThumbnailTemplate.test.jsx index 7cdc9f7..4e258f8 100644 --- a/tests/unit/ContentThumbnailTemplate.test.jsx +++ b/tests/unit/ContentThumbnailTemplate.test.jsx @@ -50,7 +50,7 @@ describe("ContentThumbnailTemplate", () => { expect(screen.getByText("Test Blog Post Title")).toBeInTheDocument(); expect( - screen.getByText(/This is a test description/) + screen.getByText(/This is a test description/), ).toBeInTheDocument(); }); @@ -79,7 +79,7 @@ describe("ContentThumbnailTemplate", () => { expect(screen.getByText("Test Blog Post Title")).toBeInTheDocument(); expect( - screen.getByText(/This is a test description/) + screen.getByText(/This is a test description/), ).toBeInTheDocument(); expect(screen.getByText("Test Author")).toBeInTheDocument(); }); @@ -88,7 +88,7 @@ describe("ContentThumbnailTemplate", () => { describe("Props and Customization", () => { it("should apply custom className", () => { render( - + , ); const container = screen.getByRole("link"); diff --git a/tests/unit/Footer.test.jsx b/tests/unit/Footer.test.jsx index 8298f00..fefe69b 100644 --- a/tests/unit/Footer.test.jsx +++ b/tests/unit/Footer.test.jsx @@ -27,7 +27,7 @@ describe("Footer", () => { expect(schemaData.email).toBe("medlab@colorado.edu"); expect(schemaData.url).toBe("https://communityrule.com"); expect(schemaData.sameAs).toContain( - "https://bsky.app/profile/medlabboulder" + "https://bsky.app/profile/medlabboulder", ); expect(schemaData.sameAs).toContain("https://gitlab.com/medlabboulder"); }); @@ -36,7 +36,7 @@ describe("Footer", () => { render(