@ugurdemirel/landcraft 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,48 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { render, screen, fireEvent } from "@testing-library/react";
3
+ import { TestimonialCard } from "./TestimonialCard";
4
+ import { Testimonials } from "./Testimonials";
5
+
6
+ const items = [
7
+ { quote: "Great product.", author: "Ayşe Yıldız", role: "Founder", company: "Lumina", rating: 5 },
8
+ { quote: "Saved us hours.", author: "Mehmet Demir", company: "Nova" },
9
+ ];
10
+
11
+ describe("TestimonialCard", () => {
12
+ it("renders quote, author, role and company", () => {
13
+ render(<TestimonialCard testimonial={items[0]} />);
14
+ expect(screen.getByText("Great product.")).toBeInTheDocument();
15
+ expect(screen.getByText("Ayşe Yıldız")).toBeInTheDocument();
16
+ expect(screen.getByText("Founder · Lumina")).toBeInTheDocument();
17
+ });
18
+
19
+ it("renders initials for the default avatar", () => {
20
+ render(<TestimonialCard testimonial={items[0]} />);
21
+ expect(screen.getByText("AY")).toBeInTheDocument();
22
+ });
23
+ });
24
+
25
+ describe("Testimonials", () => {
26
+ it("renders all items in the grid (default) option", () => {
27
+ render(<Testimonials items={items} option="grid" />);
28
+ expect(screen.getByText("Great product.")).toBeInTheDocument();
29
+ expect(screen.getByText("Saved us hours.")).toBeInTheDocument();
30
+ });
31
+
32
+ it("renders the marquee option (items are duplicated for the loop)", () => {
33
+ render(<Testimonials items={items} option="marquee" />);
34
+ expect(screen.getAllByText("Great product.").length).toBeGreaterThan(0);
35
+ expect(screen.getAllByText("Saved us hours.").length).toBeGreaterThan(0);
36
+ });
37
+
38
+ it("renders a carousel that advances on next and cycles", () => {
39
+ render(<Testimonials items={items} option="carousel" />);
40
+ expect(screen.getByText("Great product.")).toBeInTheDocument();
41
+
42
+ fireEvent.click(screen.getByRole("button", { name: "Next testimonial" }));
43
+ expect(screen.getByText("Saved us hours.")).toBeInTheDocument();
44
+
45
+ fireEvent.click(screen.getByRole("button", { name: "Next testimonial" }));
46
+ expect(screen.getByText("Great product.")).toBeInTheDocument();
47
+ });
48
+ });
@@ -0,0 +1,7 @@
1
+ import "@testing-library/jest-dom/vitest";
2
+ import { cleanup } from "@testing-library/react";
3
+ import { afterEach } from "vitest";
4
+
5
+ afterEach(() => {
6
+ cleanup();
7
+ });
@@ -0,0 +1,21 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { cn } from "../utils/cn";
3
+
4
+ describe("cn", () => {
5
+ it("joins class names", () => {
6
+ expect(cn("a", "b", "c")).toBe("a b c");
7
+ });
8
+
9
+ it("filters out falsy values", () => {
10
+ expect(cn("a", false, null, undefined, 0, "b")).toBe("a b");
11
+ });
12
+
13
+ it("handles nested arrays and objects", () => {
14
+ expect(cn(["a", "b"], { c: true, d: false })).toBe("a b c");
15
+ });
16
+
17
+ it("merges conflicting tailwind classes keeping the last", () => {
18
+ expect(cn("px-2", "px-4")).toBe("px-4");
19
+ expect(cn("p-2", "p-4")).toBe("p-4");
20
+ });
21
+ });
@@ -0,0 +1,71 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { getContrastText } from "../utils/contrast";
3
+
4
+ describe("getContrastText", () => {
5
+ afterEach(() => {
6
+ vi.restoreAllMocks();
7
+ });
8
+
9
+ it("returns a light text on very dark backgrounds", () => {
10
+ expect(getContrastText("#000000")).toBe("#ffffff");
11
+ expect(getContrastText("#111111")).toBe("#ffffff");
12
+ expect(getContrastText("#0f172a")).toBe("#ffffff");
13
+ });
14
+
15
+ it("returns a dark text on very light backgrounds", () => {
16
+ expect(getContrastText("#ffffff")).toBe("#0f172a");
17
+ expect(getContrastText("#f5f5f5")).toBe("#0f172a");
18
+ expect(getContrastText("#fafafa")).toBe("#0f172a");
19
+ });
20
+
21
+ it("respects a custom light/dark candidate pair", () => {
22
+ // On white, the black candidate has more contrast than the white candidate.
23
+ expect(getContrastText("#ffffff", "#000000", "#ffffff")).toBe("#000000");
24
+ // On black, the white candidate has more contrast.
25
+ expect(getContrastText("#000000", "#000000", "#ffffff")).toBe("#ffffff");
26
+ });
27
+
28
+ it("handles 3-digit shorthand hex", () => {
29
+ expect(getContrastText("#fff")).toBe("#0f172a");
30
+ expect(getContrastText("#000")).toBe("#ffffff");
31
+ });
32
+
33
+ it("handles lowercase and mixed-case hex", () => {
34
+ expect(getContrastText("#FFFFFF")).toBe("#0f172a");
35
+ expect(getContrastText("#000000")).toBe("#ffffff");
36
+ });
37
+
38
+ it("handles bare RGB channel triplets", () => {
39
+ expect(getContrastText("21 128 61")).toBe("#ffffff");
40
+ expect(getContrastText("255 255 255")).toBe("#0f172a");
41
+ });
42
+
43
+ it("handles rgb() and rgba() functions", () => {
44
+ expect(getContrastText("rgb(0 0 0)")).toBe("#ffffff");
45
+ expect(getContrastText("rgb(255, 255, 255)")).toBe("#0f172a");
46
+ expect(getContrastText("rgb(0 0 0 / 0.9)")).toBe("#ffffff");
47
+ });
48
+
49
+ it("picks the high-contrast side for mid-luminance colors", () => {
50
+ // Amber (#eab308) is bright — dark text should win.
51
+ expect(getContrastText("#eab308")).toBe("#0f172a");
52
+ // A mid violet keeps white text readable.
53
+ expect(getContrastText("#4f46e5")).toBe("#ffffff");
54
+ });
55
+
56
+ it("resolves CSS variable references against the live stylesheet when in a DOM", () => {
57
+ const root = document.documentElement;
58
+ const getComputedStyle = vi.spyOn(window, "getComputedStyle");
59
+ getComputedStyle.mockReturnValue({
60
+ getPropertyValue: (name: string) => (name === "--color-primary" ? "21 128 61" : ""),
61
+ } as CSSStyleDeclaration);
62
+ root.setAttribute("style", "--color-primary: 21 128 61");
63
+
64
+ expect(getContrastText("rgb(var(--color-primary) / 0.85)")).toBe("#ffffff");
65
+ });
66
+
67
+ it("falls back to the light candidate when the input is unparsable", () => {
68
+ // An unknown color yields luminance 0, so light text wins by default.
69
+ expect(getContrastText("not-a-color")).toBe("#ffffff");
70
+ });
71
+ });
@@ -0,0 +1,26 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { iso2ToFlagEmoji } from "../utils/iso2Flag";
3
+
4
+ describe("iso2ToFlagEmoji", () => {
5
+ it("converts a known country code to its flag emoji", () => {
6
+ expect(iso2ToFlagEmoji("tr")).toBe("🇹🇷");
7
+ expect(iso2ToFlagEmoji("us")).toBe("🇺🇸");
8
+ expect(iso2ToFlagEmoji("de")).toBe("🇩🇪");
9
+ });
10
+
11
+ it("is case-insensitive", () => {
12
+ expect(iso2ToFlagEmoji("TR")).toBe("🇹🇷");
13
+ expect(iso2ToFlagEmoji("Tr")).toBe("🇹🇷");
14
+ });
15
+
16
+ it("returns an empty string for non-country codes like language codes", () => {
17
+ expect(iso2ToFlagEmoji("en")).toBe("");
18
+ expect(iso2ToFlagEmoji("qq")).toBe("");
19
+ });
20
+
21
+ it("returns an empty string for empty or invalid input", () => {
22
+ expect(iso2ToFlagEmoji("")).toBe("");
23
+ expect(iso2ToFlagEmoji("x")).toBe("");
24
+ expect(iso2ToFlagEmoji("zz")).toBe("");
25
+ });
26
+ });
@@ -0,0 +1,50 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { renderHook } from "@testing-library/react";
3
+ import { useTokenForeground } from "../utils/useTokenForeground";
4
+
5
+ class FakeMutationObserver {
6
+ observe() {}
7
+ disconnect() {}
8
+ }
9
+
10
+ describe("useTokenForeground", () => {
11
+ afterEach(() => {
12
+ vi.restoreAllMocks();
13
+ });
14
+
15
+ function stubComputedStyle(resolver: (name: string) => string) {
16
+ vi.stubGlobal(
17
+ "MutationObserver",
18
+ FakeMutationObserver as unknown as typeof MutationObserver,
19
+ );
20
+ vi.spyOn(window, "getComputedStyle").mockReturnValue({
21
+ getPropertyValue: (name: string) => resolver(name),
22
+ } as CSSStyleDeclaration);
23
+ }
24
+
25
+ it("returns the fallback when the token cannot be resolved", () => {
26
+ stubComputedStyle(() => "");
27
+ const { result } = renderHook(() => useTokenForeground("--color-primary"));
28
+ expect(result.current).toBe("#ffffff");
29
+ });
30
+
31
+ it("returns light text for a dark token value", () => {
32
+ stubComputedStyle(() => "21 128 61");
33
+ const { result } = renderHook(() => useTokenForeground("--color-primary"));
34
+ expect(result.current).toBe("#ffffff");
35
+ });
36
+
37
+ it("returns dark text for a light token value", () => {
38
+ stubComputedStyle(() => "255 255 255");
39
+ const { result } = renderHook(() => useTokenForeground("--color-secondary"));
40
+ expect(result.current).toBe("#0f172a");
41
+ });
42
+
43
+ it("honours a custom fallback", () => {
44
+ stubComputedStyle(() => "");
45
+ const { result } = renderHook(() =>
46
+ useTokenForeground("--color-missing", "#123456"),
47
+ );
48
+ expect(result.current).toBe("#123456");
49
+ });
50
+ });