Run lint and prettier
CI Pipeline / test (20) (pull_request) Failing after 8m5s
CI Pipeline / test (18) (pull_request) Failing after 8m36s
CI Pipeline / e2e (chromium) (pull_request) Successful in 2m32s
CI Pipeline / e2e (webkit) (pull_request) Successful in 3m40s
CI Pipeline / e2e (firefox) (pull_request) Successful in 5m43s
CI Pipeline / performance (pull_request) Failing after 3m18s
CI Pipeline / visual-regression (pull_request) Failing after 3m20s
CI Pipeline / lint (pull_request) Successful in 1m7s
CI Pipeline / storybook (pull_request) Successful in 1m32s
CI Pipeline / build (pull_request) Successful in 1m22s

This commit is contained in:
adilallo
2025-09-12 14:33:46 -06:00
parent 8daea70cb8
commit 500d2d0965
22 changed files with 237 additions and 234 deletions
+1 -1
View File
@@ -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" className="absolute inset-0 w-full h-full bg-cover bg-no-repeat aspect-[640/224] md:block hidden"
style={{ style={{
backgroundImage: `url(${getAssetPath( backgroundImage: `url(${getAssetPath(
"assets/Content_Banner_2.svg" "assets/Content_Banner_2.svg",
)})`, )})`,
backgroundPosition: "center bottom", backgroundPosition: "center bottom",
}} }}
+2 -2
View File
@@ -6,7 +6,7 @@ import ContentThumbnailTemplate from "./ContentThumbnailTemplate";
export default function RelatedArticles({ relatedPosts, currentPostSlug }) { export default function RelatedArticles({ relatedPosts, currentPostSlug }) {
// Filter out the current post from related posts // Filter out the current post from related posts
const filteredPosts = relatedPosts.filter( const filteredPosts = relatedPosts.filter(
(post) => post.slug !== currentPostSlug (post) => post.slug !== currentPostSlug,
); );
const [currentIndex, setCurrentIndex] = useState(0); const [currentIndex, setCurrentIndex] = useState(0);
@@ -93,7 +93,7 @@ export default function RelatedArticles({ relatedPosts, currentPostSlug }) {
const handleMouseUp = () => { const handleMouseUp = () => {
document.removeEventListener( document.removeEventListener(
"mousemove", "mousemove",
handleMouseMove handleMouseMove,
); );
document.removeEventListener("mouseup", handleMouseUp); document.removeEventListener("mouseup", handleMouseUp);
}; };
+8 -5
View File
@@ -29,12 +29,15 @@
--color-*: initial; --color-*: initial;
/* Font families */ /* 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; "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
--font-display: var(--font-bricolage-grotesque), ui-sans-serif, system-ui, --font-mono:
-apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; var(--font-space-grotesk), ui-monospace, SFMono-Regular, "SF Mono",
--font-mono: var(--font-space-grotesk), ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
"SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
/* Dimension */ /* Dimension */
--spacing-scale-000: 0px; --spacing-scale-000: 0px;
+2 -2
View File
@@ -92,8 +92,8 @@ export default function TestThumbnailPage() {
<code>className</code> - Additional CSS classes <code>className</code> - Additional CSS classes
</li> </li>
<li> <li>
<code>variant</code> - "vertical" (default) or "horizontal" <code>variant</code> - &quot;vertical&quot; (default) or
(for development/testing) &quot;horizontal&quot; (for development/testing)
</li> </li>
</ul> </ul>
</div> </div>
+10 -10
View File
@@ -60,7 +60,7 @@ export function getBlogPostFiles() {
try { try {
const files = fs.readdirSync(contentDirectory); const files = fs.readdirSync(contentDirectory);
return files.filter( return files.filter(
(file) => file.endsWith(".md") || file.endsWith(".mdx") (file) => file.endsWith(".md") || file.endsWith(".mdx"),
); );
} catch (error) { } catch (error) {
console.error("Error reading blog content directory:", error); console.error("Error reading blog content directory:", error);
@@ -84,7 +84,7 @@ export function parseBlogPost(filePath) {
if (!validationResult.isValid) { if (!validationResult.isValid) {
console.error( console.error(
`Validation errors for ${filePath}:`, `Validation errors for ${filePath}:`,
validationResult.errors validationResult.errors,
); );
return null; return null;
} }
@@ -116,7 +116,7 @@ export function getAllBlogPosts() {
.map((fileName) => parseBlogPost(fileName)) .map((fileName) => parseBlogPost(fileName))
.filter(Boolean) // Filter out nulls (invalid posts) .filter(Boolean) // Filter out nulls (invalid posts)
.sort( .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 ); // Sort by date descending
return allPosts; return allPosts;
} }
@@ -141,11 +141,11 @@ export function getBlogPostBySlug(slug) {
export function getRelatedBlogPosts( export function getRelatedBlogPosts(
currentPostSlug, currentPostSlug,
relatedSlugs = [], relatedSlugs = [],
limit = 3 limit = 3,
) { ) {
const allPosts = getAllBlogPosts(); const allPosts = getAllBlogPosts();
const filteredPosts = allPosts.filter( const filteredPosts = allPosts.filter(
(post) => post.slug !== currentPostSlug (post) => post.slug !== currentPostSlug,
); );
let related = []; let related = [];
@@ -191,7 +191,7 @@ export function getAllTags() {
export function getBlogPostsByTag(tag) { export function getBlogPostsByTag(tag) {
const allPosts = getAllBlogPosts(); const allPosts = getAllBlogPosts();
return allPosts.filter( 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); .includes(searchTerm);
const contentMatch = post.content.toLowerCase().includes(searchTerm); const contentMatch = post.content.toLowerCase().includes(searchTerm);
const tagMatch = post.frontmatter.tags?.some((tag) => const tagMatch = post.frontmatter.tags?.some((tag) =>
tag.toLowerCase().includes(searchTerm) tag.toLowerCase().includes(searchTerm),
); );
return titleMatch || descriptionMatch || contentMatch || tagMatch; return titleMatch || descriptionMatch || contentMatch || tagMatch;
@@ -233,7 +233,7 @@ export function searchBlogPosts(query, limit = 10) {
export function getBlogPostsByAuthor(author) { export function getBlogPostsByAuthor(author) {
const allPosts = getAllBlogPosts(); const allPosts = getAllBlogPosts();
return allPosts.filter( 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, 1,
(new Date(allPosts[0].frontmatter.date) - (new Date(allPosts[0].frontmatter.date) -
new Date(allPosts[allPosts.length - 1].frontmatter.date)) / new Date(allPosts[allPosts.length - 1].frontmatter.date)) /
(1000 * 60 * 60 * 24 * 30) (1000 * 60 * 60 * 24 * 30),
)) * )) *
10 10,
) / 10 ) / 10
: 0, : 0,
}; };
+7 -7
View File
@@ -41,7 +41,7 @@ class ContentProcessor {
// Warm up cache // Warm up cache
await warmCache( await warmCache(
() => this.getAllPosts(), () => this.getAllPosts(),
() => this.getAllTags() () => this.getAllTags(),
); );
this.isInitialized = true; this.isInitialized = true;
@@ -60,7 +60,7 @@ class ContentProcessor {
try { try {
const files = fs.readdirSync(this.contentDirectory); const files = fs.readdirSync(this.contentDirectory);
return files.filter( return files.filter(
(file) => file.endsWith(".md") || file.endsWith(".mdx") (file) => file.endsWith(".md") || file.endsWith(".mdx"),
); );
} catch (error) { } catch (error) {
console.error("Error reading blog content directory:", error); console.error("Error reading blog content directory:", error);
@@ -85,7 +85,7 @@ class ContentProcessor {
if (!validationResult.isValid) { if (!validationResult.isValid) {
console.error( console.error(
`Validation errors for ${filePath}:`, `Validation errors for ${filePath}:`,
validationResult.errors validationResult.errors,
); );
return null; return null;
} }
@@ -145,7 +145,7 @@ class ContentProcessor {
.map((fileName) => this.processBlogPost(fileName)) .map((fileName) => this.processBlogPost(fileName))
.filter(Boolean) .filter(Boolean)
.sort( .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 // Cache the result
@@ -230,7 +230,7 @@ class ContentProcessor {
return { return {
totalPosts: allPosts.length, totalPosts: allPosts.length,
totalAuthors: new Set( totalAuthors: new Set(
allPosts.map((post) => post.frontmatter.author).size allPosts.map((post) => post.frontmatter.author).size,
), ),
dateRange: { dateRange: {
earliest: earliest:
@@ -247,9 +247,9 @@ class ContentProcessor {
1, 1,
(new Date(allPosts[0].frontmatter.date) - (new Date(allPosts[0].frontmatter.date) -
new Date(allPosts[allPosts.length - 1].frontmatter.date)) / new Date(allPosts[allPosts.length - 1].frontmatter.date)) /
(1000 * 60 * 60 * 24 * 30) (1000 * 60 * 60 * 24 * 30),
)) * )) *
10 10,
) / 10 ) / 10
: 0, : 0,
}; };
+13 -13
View File
@@ -159,34 +159,34 @@ function markdownToHtml(markdown) {
// Headers with IDs // Headers with IDs
.replace( .replace(
/^###### (.*$)/gim, /^###### (.*$)/gim,
(m, t) => `<h6 id="${generateHeadingId(t)}">${t}</h6>` (m, t) => `<h6 id="${generateHeadingId(t)}">${t}</h6>`,
) )
.replace( .replace(
/^##### (.*$)/gim, /^##### (.*$)/gim,
(m, t) => `<h5 id="${generateHeadingId(t)}">${t}</h5>` (m, t) => `<h5 id="${generateHeadingId(t)}">${t}</h5>`,
) )
.replace( .replace(
/^#### (.*$)/gim, /^#### (.*$)/gim,
(m, t) => `<h4 id="${generateHeadingId(t)}">${t}</h4>` (m, t) => `<h4 id="${generateHeadingId(t)}">${t}</h4>`,
) )
.replace( .replace(
/^### (.*$)/gim, /^### (.*$)/gim,
(m, t) => `<h3 id="${generateHeadingId(t)}">${t}</h3>` (m, t) => `<h3 id="${generateHeadingId(t)}">${t}</h3>`,
) )
.replace( .replace(
/^## (.*$)/gim, /^## (.*$)/gim,
(m, t) => `<h2 id="${generateHeadingId(t)}">${t}</h2>` (m, t) => `<h2 id="${generateHeadingId(t)}">${t}</h2>`,
) )
.replace( .replace(
/^# (.*$)/gim, /^# (.*$)/gim,
(m, t) => `<h1 id="${generateHeadingId(t)}">${t}</h1>` (m, t) => `<h1 id="${generateHeadingId(t)}">${t}</h1>`,
) )
// Code fences (block) and inline code // Code fences (block) and inline code
.replace( .replace(
/```(\w+)?\n([\s\S]*?)\n```/g, /```(\w+)?\n([\s\S]*?)\n```/g,
(m, lang = "", code) => (m, lang = "", code) =>
`<pre><code class="language-${lang}">${code}</code></pre>` `<pre><code class="language-${lang}">${code}</code></pre>`,
) )
.replace(/`([^`]+)`/g, "<code>$1</code>") .replace(/`([^`]+)`/g, "<code>$1</code>")
@@ -198,12 +198,12 @@ function markdownToHtml(markdown) {
.replace( .replace(
/!\[([^\]]*)\]\(([^)\s]+)(?:\s+"([^"]+)")?\)/g, /!\[([^\]]*)\]\(([^)\s]+)(?:\s+"([^"]+)")?\)/g,
(m, alt, src, title = "") => (m, alt, src, title = "") =>
`<img alt="${alt}" src="${src}"${title ? ` title="${title}"` : ""}>` `<img alt="${alt}" src="${src}"${title ? ` title="${title}"` : ""}>`,
) )
.replace( .replace(
/\[([^\]]+)\]\(([^)\s]+)(?:\s+"([^"]+)")?\)/g, /\[([^\]]+)\]\(([^)\s]+)(?:\s+"([^"]+)")?\)/g,
(m, text, href, title = "") => (m, text, href, title = "") =>
`<a href="${href}"${title ? ` title="${title}"` : ""}>${text}</a>` `<a href="${href}"${title ? ` title="${title}"` : ""}>${text}</a>`,
) )
// Blockquotes // Blockquotes
@@ -211,7 +211,7 @@ function markdownToHtml(markdown) {
const inner = m.replace(/^>\s?/gm, ""); const inner = m.replace(/^>\s?/gm, "");
return `<blockquote><p>${inner.replace( return `<blockquote><p>${inner.replace(
/\n{2,}/g, /\n{2,}/g,
"</p><p>" "</p><p>",
)}</p></blockquote>`; )}</p></blockquote>`;
}) })
@@ -247,7 +247,7 @@ function markdownToHtml(markdown) {
// (Also skip our GAP_TOKEN so we can turn it into gap paragraphs later.) // (Also skip our GAP_TOKEN so we can turn it into gap paragraphs later.)
.replace( .replace(
/^(?!\s*<(h[1-6]|ul|ol|li|blockquote|hr|pre|code|table|img)\b)(?!\s*<\/)(?!\s*<GAP\/>)(.+)$/gim, /^(?!\s*<(h[1-6]|ul|ol|li|blockquote|hr|pre|code|table|img)\b)(?!\s*<\/)(?!\s*<GAP\/>)(.+)$/gim,
"<p>$2</p>" "<p>$2</p>",
) )
// Clean up truly empty paragraphs but keep &nbsp; gap paragraphs // Clean up truly empty paragraphs but keep &nbsp; gap paragraphs
@@ -258,8 +258,8 @@ function markdownToHtml(markdown) {
/<GAP:(\d+)\/>/g, /<GAP:(\d+)\/>/g,
(m, n) => (m, n) =>
`<div class="md-gap" style="--gap:${Number( `<div class="md-gap" style="--gap:${Number(
n n,
)}" aria-hidden="true"></div>` )}" aria-hidden="true"></div>`,
) )
); );
} }
+4 -4
View File
@@ -81,12 +81,12 @@ export function validateBlogPost(frontmatter) {
if (config.type === "string" && typeof frontmatter[field] === "string") { if (config.type === "string" && typeof frontmatter[field] === "string") {
if (config.minLength && frontmatter[field].length < config.minLength) { if (config.minLength && frontmatter[field].length < config.minLength) {
errors.push( 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) { if (config.maxLength && frontmatter[field].length > config.maxLength) {
errors.push( 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) { if (config.items.minLength && item.length < config.items.minLength) {
errors.push( 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) { if (config.items.maxLength && item.length > config.items.maxLength) {
errors.push( 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`,
); );
} }
} }
+11 -11
View File
@@ -87,7 +87,7 @@ describe("Blog Navigation E2E", () => {
expect(thumbnailLink).toBeInTheDocument(); expect(thumbnailLink).toBeInTheDocument();
expect(thumbnailLink).toHaveAttribute( expect(thumbnailLink).toHaveAttribute(
"href", "href",
"/blog/resolving-active-conflicts" "/blog/resolving-active-conflicts",
); );
// Click the thumbnail // Click the thumbnail
@@ -102,12 +102,12 @@ describe("Blog Navigation E2E", () => {
// Verify post content is displayed // Verify post content is displayed
expect( expect(
screen.getByText("Resolving Active Conflicts") screen.getByText("Resolving Active Conflicts"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByText( screen.getByText(
"Practical steps for resolving conflicts while maintaining trust" "Practical steps for resolving conflicts while maintaining trust",
) ),
).toBeInTheDocument(); ).toBeInTheDocument();
expect(screen.getByText("Test Author")).toBeInTheDocument(); expect(screen.getByText("Test Author")).toBeInTheDocument();
expect(screen.getByText("April 2025")).toBeInTheDocument(); expect(screen.getByText("April 2025")).toBeInTheDocument();
@@ -128,10 +128,10 @@ describe("Blog Navigation E2E", () => {
// Verify related articles are displayed // Verify related articles are displayed
expect( expect(
screen.getByText("Operational Security for Mutual Aid") screen.getByText("Operational Security for Mutual Aid"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByText("Making Decisions Without Hierarchy") screen.getByText("Making Decisions Without Hierarchy"),
).toBeInTheDocument(); ).toBeInTheDocument();
// Verify links are present // Verify links are present
@@ -139,11 +139,11 @@ describe("Blog Navigation E2E", () => {
expect(relatedLinks).toHaveLength(2); expect(relatedLinks).toHaveLength(2);
expect(relatedLinks[0]).toHaveAttribute( expect(relatedLinks[0]).toHaveAttribute(
"href", "href",
"/blog/operational-security-mutual-aid" "/blog/operational-security-mutual-aid",
); );
expect(relatedLinks[1]).toHaveAttribute( expect(relatedLinks[1]).toHaveAttribute(
"href", "href",
"/blog/making-decisions-without-hierarchy" "/blog/making-decisions-without-hierarchy",
); );
}); });
@@ -160,7 +160,7 @@ describe("Blog Navigation E2E", () => {
// Verify navigation was called // Verify navigation was called
expect(mockPush).toHaveBeenCalledWith( 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", () => { it("should complete navigation flow: thumbnail → related article", () => {
// Render thumbnail // Render thumbnail
const { rerender } = render( const { rerender } = render(
<ContentThumbnailTemplate post={mockBlogPost} /> <ContentThumbnailTemplate post={mockBlogPost} />,
); );
// Click thumbnail // Click thumbnail
@@ -194,7 +194,7 @@ describe("Blog Navigation E2E", () => {
.closest("a"); .closest("a");
fireEvent.click(relatedLink); fireEvent.click(relatedLink);
expect(mockPush).toHaveBeenCalledWith( expect(mockPush).toHaveBeenCalledWith(
"/blog/operational-security-mutual-aid" "/blog/operational-security-mutual-aid",
); );
}); });
}); });
+9 -9
View File
@@ -66,7 +66,7 @@ describe("Content Page Rendering E2E", () => {
// Verify banner content // Verify banner content
expect(screen.getByText("Test Article Title")).toBeInTheDocument(); expect(screen.getByText("Test Article Title")).toBeInTheDocument();
expect( expect(
screen.getByText("This is a test article description") screen.getByText("This is a test article description"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect(screen.getByText("Test Author")).toBeInTheDocument(); expect(screen.getByText("Test Author")).toBeInTheDocument();
expect(screen.getByText("April 2025")).toBeInTheDocument(); expect(screen.getByText("April 2025")).toBeInTheDocument();
@@ -112,16 +112,16 @@ describe("Content Page Rendering E2E", () => {
title="Still have questions?" title="Still have questions?"
subtitle="Get help from our community organizers" subtitle="Get help from our community organizers"
description="We're here to help you with any questions or concerns." description="We're here to help you with any questions or concerns."
/> />,
); );
// Verify ask organizer content // Verify ask organizer content
expect(screen.getByText("Still have questions?")).toBeInTheDocument(); expect(screen.getByText("Still have questions?")).toBeInTheDocument();
expect( expect(
screen.getByText("Get help from our community organizers") screen.getByText("Get help from our community organizers"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByRole("link", { name: /ask an organizer/i }) screen.getByRole("link", { name: /ask an organizer/i }),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
@@ -131,16 +131,16 @@ describe("Content Page Rendering E2E", () => {
variant="inverse" variant="inverse"
title="Still have questions?" title="Still have questions?"
subtitle="Get help from our community organizers" subtitle="Get help from our community organizers"
/> />,
); );
// Verify ask organizer content is still present // Verify ask organizer content is still present
expect(screen.getByText("Still have questions?")).toBeInTheDocument(); expect(screen.getByText("Still have questions?")).toBeInTheDocument();
expect( expect(
screen.getByText("Get help from our community organizers") screen.getByText("Get help from our community organizers"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByRole("link", { name: /ask an organizer/i }) screen.getByRole("link", { name: /ask an organizer/i }),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
@@ -163,7 +163,7 @@ describe("Content Page Rendering E2E", () => {
title="Still have questions?" title="Still have questions?"
subtitle="Get help from our community organizers" subtitle="Get help from our community organizers"
/> />
</div> </div>,
); );
// Verify both components are rendered // Verify both components are rendered
@@ -179,7 +179,7 @@ describe("Content Page Rendering E2E", () => {
title="Still have questions?" title="Still have questions?"
subtitle="Get help from our community organizers" subtitle="Get help from our community organizers"
/> />
</main> </main>,
); );
// Verify semantic structure // Verify semantic structure
+18 -18
View File
@@ -63,25 +63,25 @@ describe("Blog Core Integration", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="resolving-active-conflicts" currentPostSlug="resolving-active-conflicts"
/> />,
); );
// Verify the section exists // Verify the section exists
expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent( expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent(
"Related Articles" "Related Articles",
); );
// Verify thumbnails are rendered // Verify thumbnails are rendered
expect( expect(
screen.getByTestId("thumbnail-operational-security-mutual-aid") screen.getByTestId("thumbnail-operational-security-mutual-aid"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-making-decisions-without-hierarchy") screen.getByTestId("thumbnail-making-decisions-without-hierarchy"),
).toBeInTheDocument(); ).toBeInTheDocument();
// Current post should not be displayed // Current post should not be displayed
expect( expect(
screen.queryByTestId("thumbnail-resolving-active-conflicts") screen.queryByTestId("thumbnail-resolving-active-conflicts"),
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
}); });
@@ -90,20 +90,20 @@ describe("Blog Core Integration", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="resolving-active-conflicts" currentPostSlug="resolving-active-conflicts"
/> />,
); );
// Current post should not be displayed // Current post should not be displayed
expect( expect(
screen.queryByTestId("thumbnail-resolving-active-conflicts") screen.queryByTestId("thumbnail-resolving-active-conflicts"),
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
// Other posts should be displayed // Other posts should be displayed
expect( expect(
screen.getByTestId("thumbnail-operational-security-mutual-aid") screen.getByTestId("thumbnail-operational-security-mutual-aid"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-making-decisions-without-hierarchy") screen.getByTestId("thumbnail-making-decisions-without-hierarchy"),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
@@ -112,19 +112,19 @@ describe("Blog Core Integration", () => {
// All posts should be displayed // All posts should be displayed
expect( expect(
screen.getByTestId("thumbnail-resolving-active-conflicts") screen.getByTestId("thumbnail-resolving-active-conflicts"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-operational-security-mutual-aid") screen.getByTestId("thumbnail-operational-security-mutual-aid"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-making-decisions-without-hierarchy") screen.getByTestId("thumbnail-making-decisions-without-hierarchy"),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it("should handle empty related posts array", () => { it("should handle empty related posts array", () => {
const { container } = render( const { container } = render(
<RelatedArticles relatedPosts={[]} currentPostSlug="test-post" /> <RelatedArticles relatedPosts={[]} currentPostSlug="test-post" />,
); );
expect(container.firstChild).toBeNull(); expect(container.firstChild).toBeNull();
@@ -135,7 +135,7 @@ describe("Blog Core Integration", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="resolving-active-conflicts" currentPostSlug="resolving-active-conflicts"
/> />,
); );
// Verify links are created correctly // Verify links are created correctly
@@ -148,11 +148,11 @@ describe("Blog Core Integration", () => {
expect(operationalLink).toHaveAttribute( expect(operationalLink).toHaveAttribute(
"href", "href",
"/blog/operational-security-mutual-aid" "/blog/operational-security-mutual-aid",
); );
expect(hierarchyLink).toHaveAttribute( expect(hierarchyLink).toHaveAttribute(
"href", "href",
"/blog/making-decisions-without-hierarchy" "/blog/making-decisions-without-hierarchy",
); );
}); });
@@ -161,11 +161,11 @@ describe("Blog Core Integration", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="resolving-active-conflicts" currentPostSlug="resolving-active-conflicts"
/> />,
); );
expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent( expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent(
"Related Articles" "Related Articles",
); );
}); });
}); });
@@ -22,7 +22,7 @@ describe("Content Processing Integration", () => {
const result = getBlogPostFiles(); const result = getBlogPostFiles();
expect(fs.readdirSync).toHaveBeenCalledWith( 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"]); expect(result).toEqual(["post1.md", "post2.md", "post3.md"]);
}); });
@@ -89,7 +89,7 @@ Content with **bold** and *italic* text.`;
const result = markdownToHtml(markdown); const result = markdownToHtml(markdown);
expect(result).toContain( expect(result).toContain(
"<h1>Title with Special Characters: & < > \" '</h1>" "<h1>Title with Special Characters: & < > \" '</h1>",
); );
expect(result).toContain("<strong>bold</strong>"); expect(result).toContain("<strong>bold</strong>");
expect(result).toContain("<em>italic</em>"); expect(result).toContain("<em>italic</em>");
@@ -75,23 +75,23 @@ describe("Related Articles Integration", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="resolving-active-conflicts" currentPostSlug="resolving-active-conflicts"
/> />,
); );
// Current post should not be displayed // Current post should not be displayed
expect( expect(
screen.queryByTestId("thumbnail-resolving-active-conflicts") screen.queryByTestId("thumbnail-resolving-active-conflicts"),
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
// Other posts should be displayed // Other posts should be displayed
expect( expect(
screen.getByTestId("thumbnail-operational-security-mutual-aid") screen.getByTestId("thumbnail-operational-security-mutual-aid"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-making-decisions-without-hierarchy") screen.getByTestId("thumbnail-making-decisions-without-hierarchy"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-building-community-trust") screen.getByTestId("thumbnail-building-community-trust"),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
@@ -100,16 +100,16 @@ describe("Related Articles Integration", () => {
// All posts should be displayed // All posts should be displayed
expect( expect(
screen.getByTestId("thumbnail-resolving-active-conflicts") screen.getByTestId("thumbnail-resolving-active-conflicts"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-operational-security-mutual-aid") screen.getByTestId("thumbnail-operational-security-mutual-aid"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-making-decisions-without-hierarchy") screen.getByTestId("thumbnail-making-decisions-without-hierarchy"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-building-community-trust") screen.getByTestId("thumbnail-building-community-trust"),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
@@ -118,24 +118,24 @@ describe("Related Articles Integration", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="resolving-active-conflicts" currentPostSlug="resolving-active-conflicts"
/> />,
); );
// Verify links are created correctly // Verify links are created correctly
expect( expect(
screen.getByTestId("thumbnail-link-operational-security-mutual-aid") screen.getByTestId("thumbnail-link-operational-security-mutual-aid"),
).toHaveAttribute("href", "/blog/operational-security-mutual-aid"); ).toHaveAttribute("href", "/blog/operational-security-mutual-aid");
expect( expect(
screen.getByTestId("thumbnail-link-making-decisions-without-hierarchy") screen.getByTestId("thumbnail-link-making-decisions-without-hierarchy"),
).toHaveAttribute("href", "/blog/making-decisions-without-hierarchy"); ).toHaveAttribute("href", "/blog/making-decisions-without-hierarchy");
expect( expect(
screen.getByTestId("thumbnail-link-building-community-trust") screen.getByTestId("thumbnail-link-building-community-trust"),
).toHaveAttribute("href", "/blog/building-community-trust"); ).toHaveAttribute("href", "/blog/building-community-trust");
}); });
it("should handle empty related posts array", () => { it("should handle empty related posts array", () => {
const { container } = render( const { container } = render(
<RelatedArticles relatedPosts={[]} currentPostSlug="test-post" /> <RelatedArticles relatedPosts={[]} currentPostSlug="test-post" />,
); );
expect(container.firstChild).toBeNull(); expect(container.firstChild).toBeNull();
@@ -148,14 +148,14 @@ describe("Related Articles Integration", () => {
<RelatedArticles <RelatedArticles
relatedPosts={singlePost} relatedPosts={singlePost}
currentPostSlug="different-post" currentPostSlug="different-post"
/> />,
); );
expect( expect(
screen.getByTestId("thumbnail-resolving-active-conflicts") screen.getByTestId("thumbnail-resolving-active-conflicts"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.queryByTestId("thumbnail-operational-security-mutual-aid") screen.queryByTestId("thumbnail-operational-security-mutual-aid"),
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
}); });
@@ -166,7 +166,7 @@ describe("Related Articles Integration", () => {
<RelatedArticles <RelatedArticles
relatedPosts={currentPostOnly} relatedPosts={currentPostOnly}
currentPostSlug="resolving-active-conflicts" currentPostSlug="resolving-active-conflicts"
/> />,
); );
expect(container.firstChild).toBeNull(); expect(container.firstChild).toBeNull();
@@ -177,11 +177,11 @@ describe("Related Articles Integration", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="resolving-active-conflicts" currentPostSlug="resolving-active-conflicts"
/> />,
); );
expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent( expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent(
"Related Articles" "Related Articles",
); );
}); });
@@ -197,12 +197,12 @@ describe("Related Articles Integration", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug={slug} currentPostSlug={slug}
/> />,
); );
// Verify consistent structure // Verify consistent structure
expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent( 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) // Check that we have some thumbnails (the exact ones depend on the current post)
const thumbnails = screen.getAllByTestId(/thumbnail-/); const thumbnails = screen.getAllByTestId(/thumbnail-/);
+10 -10
View File
@@ -131,7 +131,7 @@ describe("BlogPostPage", () => {
"min-h-screen", "min-h-screen",
"bg-[#F4F3F1]", "bg-[#F4F3F1]",
"relative", "relative",
"overflow-hidden" "overflow-hidden",
); );
}); });
@@ -144,7 +144,7 @@ describe("BlogPostPage", () => {
expect(screen.getByTestId("content-banner")).toBeInTheDocument(); expect(screen.getByTestId("content-banner")).toBeInTheDocument();
expect(screen.getByText("Test Article Title")).toBeInTheDocument(); expect(screen.getByText("Test Article Title")).toBeInTheDocument();
expect( expect(
screen.getByText("This is a test article description") screen.getByText("This is a test article description"),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
@@ -158,7 +158,7 @@ describe("BlogPostPage", () => {
expect(article).toBeInTheDocument(); expect(article).toBeInTheDocument();
expect(article).toHaveClass( expect(article).toHaveClass(
"p-[var(--spacing-scale-024)]", "p-[var(--spacing-scale-024)]",
"sm:py-[var(--spacing-scale-032)]" "sm:py-[var(--spacing-scale-032)]",
); );
// Check content is rendered // Check content is rendered
@@ -188,7 +188,7 @@ describe("BlogPostPage", () => {
expect(screen.getByTestId("ask-organizer")).toBeInTheDocument(); expect(screen.getByTestId("ask-organizer")).toBeInTheDocument();
expect(screen.getByText("Still have questions?")).toBeInTheDocument(); expect(screen.getByText("Still have questions?")).toBeInTheDocument();
expect( expect(
screen.getByText("Get answers from an experienced organizer") screen.getByText("Get answers from an experienced organizer"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect(screen.getByText("Ask an organizer")).toBeInTheDocument(); expect(screen.getByText("Ask an organizer")).toBeInTheDocument();
}); });
@@ -220,7 +220,7 @@ describe("BlogPostPage", () => {
expect(contentDiv).toHaveClass("post-body"); expect(contentDiv).toHaveClass("post-body");
expect(contentDiv).toHaveClass("-mt-[var(--spacing-scale-048)]"); expect(contentDiv).toHaveClass("-mt-[var(--spacing-scale-048)]");
expect(contentDiv).toHaveClass( expect(contentDiv).toHaveClass(
"text-[var(--color-content-inverse-primary)]" "text-[var(--color-content-inverse-primary)]",
); );
expect(contentDiv).toHaveClass("text-[16px]"); expect(contentDiv).toHaveClass("text-[16px]");
expect(contentDiv).toHaveClass("leading-[24px]"); expect(contentDiv).toHaveClass("leading-[24px]");
@@ -267,7 +267,7 @@ describe("BlogPostPage", () => {
// Check for script elements using querySelector since RTL ignores them // Check for script elements using querySelector since RTL ignores them
const scripts = document.querySelectorAll( const scripts = document.querySelectorAll(
'script[type="application/ld+json"]' 'script[type="application/ld+json"]',
); );
expect(scripts).toHaveLength(2); expect(scripts).toHaveLength(2);
@@ -285,7 +285,7 @@ describe("BlogPostPage", () => {
// The component should throw an error when post is null // The component should throw an error when post is null
// This happens because notFound() is called // This happens because notFound() is called
await expect( await expect(
BlogPostPage({ params: { slug: "non-existent" } }) BlogPostPage({ params: { slug: "non-existent" } }),
).rejects.toThrow(); ).rejects.toThrow();
}); });
@@ -297,7 +297,7 @@ describe("BlogPostPage", () => {
// Current post should not appear in related articles // Current post should not appear in related articles
expect( expect(
screen.queryByTestId("related-test-article") screen.queryByTestId("related-test-article"),
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
// Other related posts should appear // Other related posts should appear
@@ -322,7 +322,7 @@ describe("BlogPostPage", () => {
"top-1/4", "top-1/4",
"right-0", "right-0",
"pointer-events-none", "pointer-events-none",
"z-10" "z-10",
); );
// Second shape (left side) // Second shape (left side)
@@ -334,7 +334,7 @@ describe("BlogPostPage", () => {
"top-1/2", "top-1/2",
"left-0", "left-0",
"pointer-events-none", "pointer-events-none",
"z-10" "z-10",
); );
}); });
+17 -17
View File
@@ -39,7 +39,7 @@ describe("ContentBanner", () => {
// Check that the banner container exists - it's the first div with the specific classes // Check that the banner container exists - it's the first div with the specific classes
const banner = document.querySelector( const banner = document.querySelector(
"div[class*='pt-[var(--measures-spacing-016)]']" "div[class*='pt-[var(--measures-spacing-016)]']",
); );
expect(banner).toBeInTheDocument(); expect(banner).toBeInTheDocument();
expect(banner).toHaveClass( expect(banner).toHaveClass(
@@ -54,7 +54,7 @@ describe("ContentBanner", () => {
"xl:h-[504px]", "xl:h-[504px]",
"relative", "relative",
"w-full", "w-full",
"sm:overflow-hidden" "sm:overflow-hidden",
); );
}); });
@@ -63,7 +63,7 @@ describe("ContentBanner", () => {
// Check for background div with correct styling // Check for background div with correct styling
const backgroundDiv = document.querySelector( const backgroundDiv = document.querySelector(
"div[style*='background-image']" "div[style*='background-image']",
); );
expect(backgroundDiv).toBeInTheDocument(); expect(backgroundDiv).toBeInTheDocument();
expect(backgroundDiv).toHaveClass( expect(backgroundDiv).toHaveClass(
@@ -73,7 +73,7 @@ describe("ContentBanner", () => {
"h-full", "h-full",
"bg-cover", "bg-cover",
"bg-no-repeat", "bg-no-repeat",
"aspect-[320/225.5]" "aspect-[320/225.5]",
); );
}); });
@@ -82,7 +82,7 @@ describe("ContentBanner", () => {
// Check for the md+ background div // Check for the md+ background div
const mdBackgroundDiv = document.querySelector( const mdBackgroundDiv = document.querySelector(
"div[style*='Content_Banner_2.svg']" "div[style*='Content_Banner_2.svg']",
); );
expect(mdBackgroundDiv).toBeInTheDocument(); expect(mdBackgroundDiv).toBeInTheDocument();
expect(mdBackgroundDiv).toHaveClass("hidden", "md:block"); expect(mdBackgroundDiv).toHaveClass("hidden", "md:block");
@@ -98,7 +98,7 @@ describe("ContentBanner", () => {
render(<ContentBanner post={mockPost} />); render(<ContentBanner post={mockPost} />);
expect( expect(
screen.getByText("This is a test article description") screen.getByText("This is a test article description"),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
@@ -114,7 +114,7 @@ describe("ContentBanner", () => {
// Check the content container div // Check the content container div
const contentContainer = document.querySelector( const contentContainer = document.querySelector(
"div[class*='relative z-10']" "div[class*='relative z-10']",
); );
expect(contentContainer).toBeInTheDocument(); expect(contentContainer).toBeInTheDocument();
expect(contentContainer).toHaveClass( expect(contentContainer).toHaveClass(
@@ -122,7 +122,7 @@ describe("ContentBanner", () => {
"z-10", "z-10",
"h-full", "h-full",
"flex", "flex",
"flex-col" "flex-col",
); );
}); });
@@ -135,7 +135,7 @@ describe("ContentBanner", () => {
"font-medium", "font-medium",
"text-[18px]", "text-[18px]",
"leading-[120%]", "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"); const description = screen.getByText("This is a test article description");
@@ -144,7 +144,7 @@ describe("ContentBanner", () => {
"font-normal", "font-normal",
"text-[12px]", "text-[12px]",
"leading-[16px]", "leading-[16px]",
"text-[var(--color-content-inverse-brand-royal)]" "text-[var(--color-content-inverse-brand-royal)]",
); );
}); });
@@ -157,7 +157,7 @@ describe("ContentBanner", () => {
"font-normal", "font-normal",
"text-[10px]", "text-[10px]",
"leading-[14px]", "leading-[14px]",
"text-[var(--color-content-inverse-brand-royal)]" "text-[var(--color-content-inverse-brand-royal)]",
); );
const date = screen.getByText("April 2025"); const date = screen.getByText("April 2025");
@@ -166,7 +166,7 @@ describe("ContentBanner", () => {
"font-normal", "font-normal",
"text-[10px]", "text-[10px]",
"leading-[14px]", "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 // Check the ContentContainer spacing
const contentContainer = document.querySelector( const contentContainer = document.querySelector(
"div[class*='relative z-20']" "div[class*='relative z-20']",
); );
expect(contentContainer).toHaveClass("gap-[var(--measures-spacing-012)]"); expect(contentContainer).toHaveClass("gap-[var(--measures-spacing-012)]");
}); });
@@ -184,13 +184,13 @@ describe("ContentBanner", () => {
render(<ContentBanner post={mockPost} />); render(<ContentBanner post={mockPost} />);
const outerContainer = document.querySelector( const outerContainer = document.querySelector(
"div[class*='pt-[var(--measures-spacing-016)]']" "div[class*='pt-[var(--measures-spacing-016)]']",
); );
expect(outerContainer).toHaveClass( expect(outerContainer).toHaveClass(
"pt-[var(--measures-spacing-016)]", "pt-[var(--measures-spacing-016)]",
"md:pt-[var(--measures-spacing-008)]", "md:pt-[var(--measures-spacing-008)]",
"lg:pt-[50px]", "lg:pt-[50px]",
"xl:pt-[112px]" "xl:pt-[112px]",
); );
}); });
@@ -216,7 +216,7 @@ describe("ContentBanner", () => {
"sm:text-[24px]", "sm:text-[24px]",
"md:text-[32px]", "md:text-[32px]",
"lg:text-[44px]", "lg:text-[44px]",
"xl:text-[64px]" "xl:text-[64px]",
); );
const description = screen.getByText("This is a test article description"); const description = screen.getByText("This is a test article description");
@@ -224,7 +224,7 @@ describe("ContentBanner", () => {
"sm:text-[14px]", "sm:text-[14px]",
"md:text-[14px]", "md:text-[14px]",
"lg:text-[18px]", "lg:text-[18px]",
"xl:text-[24px]" "xl:text-[24px]",
); );
}); });
+9 -9
View File
@@ -36,7 +36,7 @@ describe("ContentContainer", () => {
"z-20", "z-20",
"h-full", "h-full",
"flex", "flex",
"flex-col" "flex-col",
); );
}); });
@@ -59,7 +59,7 @@ describe("ContentContainer", () => {
"font-medium", "font-medium",
"text-[18px]", "text-[18px]",
"leading-[120%]", "leading-[120%]",
"text-[var(--color-content-inverse-brand-royal)]" "text-[var(--color-content-inverse-brand-royal)]",
); );
}); });
@@ -73,7 +73,7 @@ describe("ContentContainer", () => {
"font-normal", "font-normal",
"text-[12px]", "text-[12px]",
"leading-[16px]", "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) // Check the content container (parent of icon)
expect(iconContainer.parentElement).toHaveClass( 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 // Check the text container (parent of title) - it has responsive gap classes
expect(textContainer.parentElement).toHaveClass("flex", "flex-col"); expect(textContainer.parentElement).toHaveClass("flex", "flex-col");
@@ -121,7 +121,7 @@ describe("ContentContainer", () => {
expect(metadataContainer).toHaveClass( expect(metadataContainer).toHaveClass(
"flex", "flex",
"items-center", "items-center",
"gap-[var(--measures-spacing-008)]" "gap-[var(--measures-spacing-008)]",
); );
}); });
@@ -134,7 +134,7 @@ describe("ContentContainer", () => {
"font-normal", "font-normal",
"text-[10px]", "text-[10px]",
"leading-[14px]", "leading-[14px]",
"text-[var(--color-content-inverse-brand-royal)]" "text-[var(--color-content-inverse-brand-royal)]",
); );
const date = screen.getByText("April 2025"); const date = screen.getByText("April 2025");
@@ -143,7 +143,7 @@ describe("ContentContainer", () => {
"font-normal", "font-normal",
"text-[10px]", "text-[10px]",
"leading-[14px]", "leading-[14px]",
"text-[var(--color-content-inverse-brand-royal)]" "text-[var(--color-content-inverse-brand-royal)]",
); );
}); });
@@ -229,7 +229,7 @@ describe("ContentContainer", () => {
render(<ContentContainer post={longTitlePost} />); render(<ContentContainer post={longTitlePost} />);
expect( expect(
screen.getByText(/This is a very long article title/) screen.getByText(/This is a very long article title/),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
@@ -246,7 +246,7 @@ describe("ContentContainer", () => {
render(<ContentContainer post={longDescPost} />); render(<ContentContainer post={longDescPost} />);
expect( expect(
screen.getByText(/This is a very long article description/) screen.getByText(/This is a very long article description/),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
}); });
+3 -3
View File
@@ -50,7 +50,7 @@ describe("ContentThumbnailTemplate", () => {
expect(screen.getByText("Test Blog Post Title")).toBeInTheDocument(); expect(screen.getByText("Test Blog Post Title")).toBeInTheDocument();
expect( expect(
screen.getByText(/This is a test description/) screen.getByText(/This is a test description/),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
@@ -79,7 +79,7 @@ describe("ContentThumbnailTemplate", () => {
expect(screen.getByText("Test Blog Post Title")).toBeInTheDocument(); expect(screen.getByText("Test Blog Post Title")).toBeInTheDocument();
expect( expect(
screen.getByText(/This is a test description/) screen.getByText(/This is a test description/),
).toBeInTheDocument(); ).toBeInTheDocument();
expect(screen.getByText("Test Author")).toBeInTheDocument(); expect(screen.getByText("Test Author")).toBeInTheDocument();
}); });
@@ -88,7 +88,7 @@ describe("ContentThumbnailTemplate", () => {
describe("Props and Customization", () => { describe("Props and Customization", () => {
it("should apply custom className", () => { it("should apply custom className", () => {
render( render(
<ContentThumbnailTemplate post={mockPost} className="custom-class" /> <ContentThumbnailTemplate post={mockPost} className="custom-class" />,
); );
const container = screen.getByRole("link"); const container = screen.getByRole("link");
+15 -15
View File
@@ -27,7 +27,7 @@ describe("Footer", () => {
expect(schemaData.email).toBe("medlab@colorado.edu"); expect(schemaData.email).toBe("medlab@colorado.edu");
expect(schemaData.url).toBe("https://communityrule.com"); expect(schemaData.url).toBe("https://communityrule.com");
expect(schemaData.sameAs).toContain( expect(schemaData.sameAs).toContain(
"https://bsky.app/profile/medlabboulder" "https://bsky.app/profile/medlabboulder",
); );
expect(schemaData.sameAs).toContain("https://gitlab.com/medlabboulder"); expect(schemaData.sameAs).toContain("https://gitlab.com/medlabboulder");
}); });
@@ -36,7 +36,7 @@ describe("Footer", () => {
render(<Footer />); render(<Footer />);
expect( expect(
screen.getAllByText("Media Economies Design Lab").length screen.getAllByText("Media Economies Design Lab").length,
).toBeGreaterThan(0); ).toBeGreaterThan(0);
const emailLinks = screen.getAllByRole("link", { const emailLinks = screen.getAllByRole("link", {
@@ -86,13 +86,13 @@ describe("Footer", () => {
render(<Footer />); render(<Footer />);
expect( expect(
screen.getAllByRole("link", { name: "Use cases" }).length screen.getAllByRole("link", { name: "Use cases" }).length,
).toBeGreaterThan(0); ).toBeGreaterThan(0);
expect( expect(
screen.getAllByRole("link", { name: "Learn" }).length screen.getAllByRole("link", { name: "Learn" }).length,
).toBeGreaterThan(0); ).toBeGreaterThan(0);
expect( expect(
screen.getAllByRole("link", { name: "About" }).length screen.getAllByRole("link", { name: "About" }).length,
).toBeGreaterThan(0); ).toBeGreaterThan(0);
}); });
@@ -100,13 +100,13 @@ describe("Footer", () => {
render(<Footer />); render(<Footer />);
expect( expect(
screen.getAllByRole("link", { name: "Privacy Policy" }).length screen.getAllByRole("link", { name: "Privacy Policy" }).length,
).toBeGreaterThan(0); ).toBeGreaterThan(0);
expect( expect(
screen.getAllByRole("link", { name: "Terms of Service" }).length screen.getAllByRole("link", { name: "Terms of Service" }).length,
).toBeGreaterThan(0); ).toBeGreaterThan(0);
expect( expect(
screen.getAllByRole("link", { name: "Cookies Settings" }).length screen.getAllByRole("link", { name: "Cookies Settings" }).length,
).toBeGreaterThan(0); ).toBeGreaterThan(0);
}); });
@@ -114,7 +114,7 @@ describe("Footer", () => {
render(<Footer />); render(<Footer />);
expect(screen.getAllByText("© All right reserved").length).toBeGreaterThan( expect(screen.getAllByText("© All right reserved").length).toBeGreaterThan(
0 0,
); );
}); });
@@ -123,7 +123,7 @@ describe("Footer", () => {
// Check that logo containers exist for different breakpoints // Check that logo containers exist for different breakpoints
const logoContainers = document.querySelectorAll( const logoContainers = document.querySelectorAll(
'[class*="block sm:hidden"], [class*="hidden sm:block lg:hidden"], [class*="hidden lg:block"]' '[class*="block sm:hidden"], [class*="hidden sm:block lg:hidden"], [class*="hidden lg:block"]',
); );
expect(logoContainers.length).toBeGreaterThan(0); expect(logoContainers.length).toBeGreaterThan(0);
}); });
@@ -147,7 +147,7 @@ describe("Footer", () => {
// The Separator component should be rendered (it uses a div with border, not hr) // The Separator component should be rendered (it uses a div with border, not hr)
const separator = document.querySelector( const separator = document.querySelector(
".bg-\\[var\\(--border-color-default-secondary\\)\\]" ".bg-\\[var\\(--border-color-default-secondary\\)\\]",
); );
expect(separator).toBeInTheDocument(); expect(separator).toBeInTheDocument();
}); });
@@ -263,10 +263,10 @@ describe("Footer", () => {
expect(emailLink).toHaveClass("focus:ring-2"); expect(emailLink).toHaveClass("focus:ring-2");
expect(emailLink).toHaveClass("focus:ring-offset-2"); expect(emailLink).toHaveClass("focus:ring-offset-2");
expect(emailLink).toHaveClass( expect(emailLink).toHaveClass(
"focus:ring-[var(--color-content-default-primary)]" "focus:ring-[var(--color-content-default-primary)]",
); );
expect(emailLink).toHaveClass( expect(emailLink).toHaveClass(
"focus:ring-offset-[var(--color-surface-default-primary)]" "focus:ring-offset-[var(--color-surface-default-primary)]",
); );
}); });
@@ -276,10 +276,10 @@ describe("Footer", () => {
expect(link).toHaveClass("focus:ring-2"); expect(link).toHaveClass("focus:ring-2");
expect(link).toHaveClass("focus:ring-offset-2"); expect(link).toHaveClass("focus:ring-offset-2");
expect(link).toHaveClass( expect(link).toHaveClass(
"focus:ring-[var(--color-content-default-primary)]" "focus:ring-[var(--color-content-default-primary)]",
); );
expect(link).toHaveClass( expect(link).toHaveClass(
"focus:ring-offset-[var(--color-surface-default-primary)]" "focus:ring-offset-[var(--color-surface-default-primary)]",
); );
}); });
}); });
+10 -10
View File
@@ -22,14 +22,14 @@ describe("Header", () => {
// Check main header structure - use container to scope the search // Check main header structure - use container to scope the search
const header = container.querySelector( const header = container.querySelector(
'[role="banner"][aria-label="Main navigation header"]' '[role="banner"][aria-label="Main navigation header"]',
); );
expect(header).toBeInTheDocument(); expect(header).toBeInTheDocument();
expect(header).toHaveAttribute("aria-label", "Main navigation header"); expect(header).toHaveAttribute("aria-label", "Main navigation header");
// Check navigation - use container to scope the search // Check navigation - use container to scope the search
const nav = container.querySelector( const nav = container.querySelector(
'[role="navigation"][aria-label="Main navigation"]' '[role="navigation"][aria-label="Main navigation"]',
); );
expect(nav).toBeInTheDocument(); expect(nav).toBeInTheDocument();
expect(nav).toHaveAttribute("aria-label", "Main navigation"); expect(nav).toHaveAttribute("aria-label", "Main navigation");
@@ -41,15 +41,15 @@ describe("Header", () => {
// Check all navigation items have proper aria-labels - use menuitem role since they're in a menubar // Check all navigation items have proper aria-labels - use menuitem role since they're in a menubar
expect( expect(
screen.getAllByRole("menuitem", { name: "Navigate to Use cases page" }) screen.getAllByRole("menuitem", { name: "Navigate to Use cases page" })
.length .length,
).toBeGreaterThan(0); ).toBeGreaterThan(0);
expect( expect(
screen.getAllByRole("menuitem", { name: "Navigate to Learn page" }) screen.getAllByRole("menuitem", { name: "Navigate to Learn page" })
.length .length,
).toBeGreaterThan(0); ).toBeGreaterThan(0);
expect( expect(
screen.getAllByRole("menuitem", { name: "Navigate to About page" }) screen.getAllByRole("menuitem", { name: "Navigate to About page" })
.length .length,
).toBeGreaterThan(0); ).toBeGreaterThan(0);
}); });
}); });
@@ -59,7 +59,7 @@ describe("Header", () => {
render(<Header onToggle={mockOnToggle} />); render(<Header onToggle={mockOnToggle} />);
const script = document.querySelector( const script = document.querySelector(
'script[type="application/ld+json"]' 'script[type="application/ld+json"]',
); );
expect(script).toBeInTheDocument(); expect(script).toBeInTheDocument();
@@ -296,7 +296,7 @@ describe("Header", () => {
(img) => (img) =>
img.alt === "Avatar 1" || img.alt === "Avatar 1" ||
img.alt === "Avatar 2" || img.alt === "Avatar 2" ||
img.alt === "Avatar 3" img.alt === "Avatar 3",
); );
expect(avatarImages.length).toBeGreaterThan(0); expect(avatarImages.length).toBeGreaterThan(0);
}); });
@@ -324,17 +324,17 @@ describe("Header", () => {
const { container } = render(<Header onToggle={mockOnToggle} />); const { container } = render(<Header onToggle={mockOnToggle} />);
const header = container.querySelector( const header = container.querySelector(
'[role="banner"][aria-label="Main navigation header"]' '[role="banner"][aria-label="Main navigation header"]',
); );
expect(header).toHaveClass("bg-[var(--color-surface-default-primary)]"); expect(header).toHaveClass("bg-[var(--color-surface-default-primary)]");
expect(header).toHaveClass("w-full"); expect(header).toHaveClass("w-full");
expect(header).toHaveClass("border-b"); expect(header).toHaveClass("border-b");
expect(header).toHaveClass( expect(header).toHaveClass(
"border-[var(--border-color-default-tertiary)]" "border-[var(--border-color-default-tertiary)]",
); );
const nav = container.querySelector( const nav = container.querySelector(
'[role="navigation"][aria-label="Main navigation"]' '[role="navigation"][aria-label="Main navigation"]',
); );
expect(nav).toHaveClass("flex"); expect(nav).toHaveClass("flex");
expect(nav).toHaveClass("items-center"); expect(nav).toHaveClass("items-center");
+2 -2
View File
@@ -52,13 +52,13 @@ describe("Logo Component", () => {
const { rerender } = render(<Logo size="homeHeaderMd" />); const { rerender } = render(<Logo size="homeHeaderMd" />);
let textElement = screen.getByText("CommunityRule"); let textElement = screen.getByText("CommunityRule");
expect(textElement).toHaveClass( expect(textElement).toHaveClass(
"text-[var(--color-content-inverse-primary)]" "text-[var(--color-content-inverse-primary)]",
); );
rerender(<Logo size="header" />); rerender(<Logo size="header" />);
textElement = screen.getByText("CommunityRule"); textElement = screen.getByText("CommunityRule");
expect(textElement).toHaveClass( expect(textElement).toHaveClass(
"text-[var(--color-content-default-primary)]" "text-[var(--color-content-default-primary)]",
); );
}); });
+40 -40
View File
@@ -73,14 +73,14 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
const section = document.querySelector("section"); const section = document.querySelector("section");
expect(section).toBeInTheDocument(); expect(section).toBeInTheDocument();
expect(section).toHaveClass( expect(section).toHaveClass(
"py-[var(--spacing-scale-032)]", "py-[var(--spacing-scale-032)]",
"lg:py-[var(--spacing-scale-064)]" "lg:py-[var(--spacing-scale-064)]",
); );
}); });
@@ -89,7 +89,7 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
const heading = screen.getByRole("heading", { level: 2 }); const heading = screen.getByRole("heading", { level: 2 });
@@ -101,7 +101,7 @@ describe("RelatedArticles", () => {
"leading-[110%]", "leading-[110%]",
"font-medium", "font-medium",
"text-[var(--color-content-inverse-primary)]", "text-[var(--color-content-inverse-primary)]",
"text-center" "text-center",
); );
}); });
@@ -110,17 +110,17 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
expect( expect(
screen.getByTestId("thumbnail-related-article-1") screen.getByTestId("thumbnail-related-article-1"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-related-article-2") screen.getByTestId("thumbnail-related-article-2"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-related-article-3") screen.getByTestId("thumbnail-related-article-3"),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
@@ -142,29 +142,29 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={postsWithCurrent} relatedPosts={postsWithCurrent}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
// Should not render the current article // Should not render the current article
expect( expect(
screen.queryByTestId("thumbnail-current-article") screen.queryByTestId("thumbnail-current-article"),
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
// Should still render the other related articles // Should still render the other related articles
expect( expect(
screen.getByTestId("thumbnail-related-article-1") screen.getByTestId("thumbnail-related-article-1"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-related-article-2") screen.getByTestId("thumbnail-related-article-2"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-related-article-3") screen.getByTestId("thumbnail-related-article-3"),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it("renders nothing when no related posts", () => { it("renders nothing when no related posts", () => {
const { container } = render( const { container } = render(
<RelatedArticles relatedPosts={[]} currentPostSlug="current-article" /> <RelatedArticles relatedPosts={[]} currentPostSlug="current-article" />,
); );
expect(container.firstChild).toBeNull(); expect(container.firstChild).toBeNull();
@@ -187,7 +187,7 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={currentPostOnly} relatedPosts={currentPostOnly}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
expect(container.firstChild).toBeNull(); expect(container.firstChild).toBeNull();
@@ -198,7 +198,7 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
const container = document.querySelector("section > div"); const container = document.querySelector("section > div");
@@ -206,7 +206,7 @@ describe("RelatedArticles", () => {
"flex", "flex",
"flex-col", "flex-col",
"gap-[var(--spacing-scale-032)]", "gap-[var(--spacing-scale-032)]",
"lg:gap-[51px]" "lg:gap-[51px]",
); );
}); });
@@ -215,14 +215,14 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
const articlesContainer = document.querySelector("section > div > div"); const articlesContainer = document.querySelector("section > div > div");
expect(articlesContainer).toHaveClass( expect(articlesContainer).toHaveClass(
"flex", "flex",
"justify-center", "justify-center",
"overflow-hidden" "overflow-hidden",
); );
}); });
@@ -238,17 +238,17 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
const carouselContainer = document.querySelector( const carouselContainer = document.querySelector(
"section > div > div > div" "section > div > div > div",
); );
expect(carouselContainer).toHaveClass( expect(carouselContainer).toHaveClass(
"overflow-x-auto", "overflow-x-auto",
"scrollbar-hide", "scrollbar-hide",
"cursor-grab", "cursor-grab",
"active:cursor-grabbing" "active:cursor-grabbing",
); );
}); });
@@ -264,16 +264,16 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
const carouselContainer = document.querySelector( const carouselContainer = document.querySelector(
"section > div > div > div" "section > div > div > div",
); );
expect(carouselContainer).toHaveClass( expect(carouselContainer).toHaveClass(
"transition-transform", "transition-transform",
"duration-500", "duration-500",
"ease-in-out" "ease-in-out",
); );
}); });
@@ -284,17 +284,17 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={singlePost} relatedPosts={singlePost}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
expect( expect(
screen.getByTestId("thumbnail-related-article-1") screen.getByTestId("thumbnail-related-article-1"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.queryByTestId("thumbnail-related-article-2") screen.queryByTestId("thumbnail-related-article-2"),
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
expect( expect(
screen.queryByTestId("thumbnail-related-article-3") screen.queryByTestId("thumbnail-related-article-3"),
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
}); });
@@ -305,17 +305,17 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={twoPosts} relatedPosts={twoPosts}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
expect( expect(
screen.getByTestId("thumbnail-related-article-1") screen.getByTestId("thumbnail-related-article-1"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-related-article-2") screen.getByTestId("thumbnail-related-article-2"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.queryByTestId("thumbnail-related-article-3") screen.queryByTestId("thumbnail-related-article-3"),
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
}); });
@@ -324,7 +324,7 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
const section = document.querySelector("section"); const section = document.querySelector("section");
@@ -336,11 +336,11 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={mockRelatedPosts} relatedPosts={mockRelatedPosts}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
const carouselContainer = document.querySelector( const carouselContainer = document.querySelector(
"section > div > div > div" "section > div > div > div",
); );
expect(carouselContainer).toHaveClass("gap-0"); expect(carouselContainer).toHaveClass("gap-0");
}); });
@@ -350,13 +350,13 @@ describe("RelatedArticles", () => {
// Should still render all articles // Should still render all articles
expect( expect(
screen.getByTestId("thumbnail-related-article-1") screen.getByTestId("thumbnail-related-article-1"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-related-article-2") screen.getByTestId("thumbnail-related-article-2"),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByTestId("thumbnail-related-article-3") screen.getByTestId("thumbnail-related-article-3"),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
@@ -386,7 +386,7 @@ describe("RelatedArticles", () => {
<RelatedArticles <RelatedArticles
relatedPosts={malformedPosts} relatedPosts={malformedPosts}
currentPostSlug="current-article" currentPostSlug="current-article"
/> />,
); );
expect(screen.getByTestId("thumbnail-malformed-1")).toBeInTheDocument(); expect(screen.getByTestId("thumbnail-malformed-1")).toBeInTheDocument();