- Introduced DrawLine component for drawing animations. - Added LazyRevealImage component for lazy loading images with reveal animations. - Implemented TextDiffuseReveal for animated text reveals with staggered effects. - Created TopProgressBar for a dynamic loading indicator. - Added PointCloud mock for testing animations. - Developed useReducedMotion hook to handle user preferences for reduced motion. - Centralized animation configurations in config.ts for easier management. - Defined animation variants in variants.ts for consistent animation effects. - Established AnimationProvider to supply global animation settings. - Created tests for AnimationProvider and useReducedMotion hook. - Added SVG assets for branding and UI elements. - Documented frontend review plan and hero circuit board animation plan.
265 lines
8.5 KiB
TypeScript
265 lines
8.5 KiB
TypeScript
import { render } from "@testing-library/react";
|
|
import Footer from "./Footer";
|
|
import fc from "fast-check";
|
|
|
|
describe("Property 3: Responsive Component Layout", () => {
|
|
it("should include Tailwind responsive utility classes for grid layout", () => {
|
|
/**
|
|
* **Validates: Requirements 2.6**
|
|
*
|
|
* Property: For any Footer component, it should include Tailwind responsive
|
|
* utility classes (sm:, md:, lg:) to adapt the grid layout across viewport sizes.
|
|
* This ensures the component is responsive and provides optimal layout at different
|
|
* screen widths.
|
|
*/
|
|
fc.assert(
|
|
fc.property(
|
|
fc.constant(null), // No random input needed, testing static component
|
|
() => {
|
|
const { container } = render(<Footer />);
|
|
|
|
// Find the main grid container
|
|
const gridContainer = container.querySelector("footer .grid");
|
|
|
|
// Verify grid container exists
|
|
if (!gridContainer) {
|
|
return false;
|
|
}
|
|
|
|
const className = gridContainer.className;
|
|
|
|
// Check for responsive grid-cols classes
|
|
// Should have base grid-cols-1 and responsive variants
|
|
const hasBaseGridCols = className.includes("grid-cols-1");
|
|
const hasMdResponsive = className.includes("md:grid-cols-");
|
|
const hasLgResponsive = className.includes("lg:grid-cols-");
|
|
|
|
return hasBaseGridCols && hasMdResponsive && hasLgResponsive;
|
|
},
|
|
),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
|
|
it("should include responsive padding classes", () => {
|
|
/**
|
|
* **Validates: Requirements 2.6**
|
|
*
|
|
* Property: For any Footer component, the container should use the design system
|
|
* section class (ds-section) which provides responsive padding that scales
|
|
* appropriately across viewport sizes. This ensures consistent spacing that
|
|
* adapts to different screen widths.
|
|
*/
|
|
fc.assert(
|
|
fc.property(fc.constant(null), () => {
|
|
const { container } = render(<Footer />);
|
|
|
|
// Find the footer element
|
|
const footer = container.querySelector("footer");
|
|
|
|
if (!footer) {
|
|
return false;
|
|
}
|
|
|
|
const className = footer.className;
|
|
|
|
// Check for design system section class which handles responsive padding
|
|
const hasDsSection = className.includes("ds-section");
|
|
|
|
// The ds-section class in globals.css provides responsive padding via CSS
|
|
// padding: var(--sp-20) var(--sp-16) on desktop
|
|
// padding: var(--sp-16) var(--sp-6) on mobile (via @media query)
|
|
return hasDsSection;
|
|
}),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
|
|
it("should include responsive gap classes for grid spacing", () => {
|
|
/**
|
|
* **Validates: Requirements 2.6**
|
|
*
|
|
* Property: For any Footer component grid, it should include gap
|
|
* classes to adjust spacing between grid items.
|
|
* This ensures optimal spacing that scales with the layout.
|
|
*/
|
|
fc.assert(
|
|
fc.property(fc.constant(null), () => {
|
|
const { container } = render(<Footer />);
|
|
|
|
// Find the grid container
|
|
const gridContainer = container.querySelector("footer .grid");
|
|
|
|
if (!gridContainer) {
|
|
return false;
|
|
}
|
|
|
|
const className = gridContainer.className;
|
|
|
|
// Check for gap classes (base gap)
|
|
const hasGap = className.includes("gap-sp-");
|
|
|
|
// Should have at least base gap
|
|
return hasGap;
|
|
}),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
|
|
it("should maintain responsive classes across multiple renders", () => {
|
|
/**
|
|
* **Validates: Requirements 2.6**
|
|
*
|
|
* Property: For any number of component renders, the Footer should consistently
|
|
* maintain its responsive utility classes. This verifies that responsive behavior
|
|
* is not accidentally removed during re-renders.
|
|
*/
|
|
fc.assert(
|
|
fc.property(
|
|
fc.integer({ min: 1, max: 5 }), // Test 1-5 renders
|
|
(numRenders) => {
|
|
let allRendersValid = true;
|
|
|
|
for (let i = 0; i < numRenders; i++) {
|
|
const { container, unmount } = render(<Footer />);
|
|
|
|
// Check grid container
|
|
const gridContainer = container.querySelector("footer .grid");
|
|
|
|
if (!gridContainer) {
|
|
allRendersValid = false;
|
|
unmount();
|
|
continue;
|
|
}
|
|
|
|
const className = gridContainer.className;
|
|
|
|
// Verify responsive classes are present
|
|
const hasResponsiveClasses =
|
|
className.includes("grid-cols-1") &&
|
|
className.includes("md:grid-cols-") &&
|
|
className.includes("lg:grid-cols-");
|
|
|
|
if (!hasResponsiveClasses) {
|
|
allRendersValid = false;
|
|
}
|
|
|
|
unmount();
|
|
}
|
|
|
|
return allRendersValid;
|
|
},
|
|
),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
|
|
it("should have responsive column span for copyright section", () => {
|
|
/**
|
|
* **Validates: Requirements 2.6**
|
|
*
|
|
* Property: For any Footer component, the copyright section should include
|
|
* responsive column span classes (md:col-span-2, lg:col-span-1) to adapt
|
|
* its position in the grid layout across different viewport sizes.
|
|
*/
|
|
fc.assert(
|
|
fc.property(fc.constant(null), () => {
|
|
const { container } = render(<Footer />);
|
|
|
|
// Find the copyright section (contains "Informacoes legais" heading)
|
|
const copyrightSection = Array.from(
|
|
container.querySelectorAll("footer h3"),
|
|
).find((h3) =>
|
|
h3.textContent?.includes("Informacoes legais"),
|
|
)?.parentElement;
|
|
|
|
if (!copyrightSection) {
|
|
return false;
|
|
}
|
|
|
|
const className = copyrightSection.className;
|
|
|
|
// Check for responsive column span classes
|
|
const hasMdColSpan = className.includes("md:col-span-");
|
|
const hasLgColSpan = className.includes("lg:col-span-");
|
|
|
|
return hasMdColSpan && hasLgColSpan;
|
|
}),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
|
|
it("should use consistent responsive breakpoint prefixes", () => {
|
|
/**
|
|
* **Validates: Requirements 2.6**
|
|
*
|
|
* Property: For any Footer component, all responsive utility classes should
|
|
* use consistent Tailwind breakpoint prefixes (md:, lg:). This ensures the
|
|
* component follows Tailwind's responsive design system correctly.
|
|
*/
|
|
fc.assert(
|
|
fc.property(fc.constant(null), () => {
|
|
const { container } = render(<Footer />);
|
|
|
|
// Get all elements with classes in the footer
|
|
const allElements = container.querySelectorAll("footer *");
|
|
|
|
let hasMdPrefix = false;
|
|
let hasLgPrefix = false;
|
|
let hasInvalidPrefix = false;
|
|
|
|
allElements.forEach((element) => {
|
|
const className = element.className;
|
|
|
|
if (typeof className === "string") {
|
|
// Check for valid responsive prefixes
|
|
if (className.includes("md:")) hasMdPrefix = true;
|
|
if (className.includes("lg:")) hasLgPrefix = true;
|
|
|
|
// Check for invalid/inconsistent prefixes (sm: should not be used based on design)
|
|
// We're looking for md: and lg: specifically
|
|
}
|
|
});
|
|
|
|
// Should have md: and lg: prefixes, no invalid ones
|
|
return hasMdPrefix && hasLgPrefix && !hasInvalidPrefix;
|
|
}),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
|
|
it("should have mobile-first responsive design with base classes", () => {
|
|
/**
|
|
* **Validates: Requirements 2.6**
|
|
*
|
|
* Property: For any Footer component, it should follow mobile-first responsive
|
|
* design by having base classes for mobile and progressive enhancement with
|
|
* responsive variants. This ensures the component works on all devices.
|
|
*/
|
|
fc.assert(
|
|
fc.property(fc.constant(null), () => {
|
|
const { container } = render(<Footer />);
|
|
|
|
// Find the grid container
|
|
const gridContainer = container.querySelector("footer .grid");
|
|
|
|
if (!gridContainer) {
|
|
return false;
|
|
}
|
|
|
|
const className = gridContainer.className;
|
|
|
|
// Mobile-first means base class (grid-cols-1) should be present
|
|
// Then enhanced with md: and lg: variants
|
|
const hasMobileBase = className.includes("grid-cols-1");
|
|
const hasTabletEnhancement = className.includes("md:grid-cols-");
|
|
const hasDesktopEnhancement = className.includes("lg:grid-cols-");
|
|
|
|
// Verify progressive enhancement: mobile -> tablet -> desktop
|
|
return hasMobileBase && hasTabletEnhancement && hasDesktopEnhancement;
|
|
}),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
});
|