Enhance testing framework and add UI component tests. Integrated Vitest for testing with AstroContainer API. Updated package.json and bun.lock to include testing dependencies. Added comprehensive test cases for various UI components including Button, Alert, Badge, and more, ensuring proper rendering and functionality.
This commit is contained in:
59
src/components/ui/__tests__/Alert.test.ts
Normal file
59
src/components/ui/__tests__/Alert.test.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Alert from "../Alert.astro";
|
||||
|
||||
describe("Alert", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Alert, {
|
||||
slots: { default: "Alert message" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Alert message");
|
||||
expect(result).toContain('class="alert alert-info"');
|
||||
expect(result).toContain("<div");
|
||||
});
|
||||
|
||||
it("renders different variants", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const variants = ["success", "warning", "error", "info"] as const;
|
||||
|
||||
for (const variant of variants) {
|
||||
const result = await container.renderToString(Alert, {
|
||||
props: { variant },
|
||||
slots: { default: "Test message" },
|
||||
});
|
||||
|
||||
expect(result).toContain(`alert-${variant}`);
|
||||
}
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Alert, {
|
||||
props: { class: "custom-alert" },
|
||||
slots: { default: "Message" },
|
||||
});
|
||||
|
||||
expect(result).toContain("alert alert-info custom-alert");
|
||||
});
|
||||
|
||||
it("renders as div element", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Alert, {
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('<div class="alert alert-info"');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Alert, {
|
||||
props: { role: "alert" },
|
||||
slots: { default: "Important message" },
|
||||
});
|
||||
|
||||
expect(result).toContain('role="alert"');
|
||||
});
|
||||
});
|
65
src/components/ui/__tests__/Badge.test.ts
Normal file
65
src/components/ui/__tests__/Badge.test.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Badge from "../Badge.astro";
|
||||
|
||||
describe("Badge", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Badge, {
|
||||
slots: { default: "New" },
|
||||
});
|
||||
|
||||
expect(result).toContain("New");
|
||||
expect(result).toContain("badge-primary");
|
||||
expect(result).toContain("<span");
|
||||
});
|
||||
|
||||
it("renders different variants", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const variants = [
|
||||
"primary",
|
||||
"secondary",
|
||||
"success",
|
||||
"warning",
|
||||
"error",
|
||||
] as const;
|
||||
|
||||
for (const variant of variants) {
|
||||
const result = await container.renderToString(Badge, {
|
||||
props: { variant },
|
||||
slots: { default: "Badge" },
|
||||
});
|
||||
|
||||
expect(result).toContain(`badge-${variant}`);
|
||||
}
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Badge, {
|
||||
props: { class: "custom-badge" },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain("badge badge-primary custom-badge");
|
||||
});
|
||||
|
||||
it("renders as span element", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Badge, {
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('<span class="badge');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Badge, {
|
||||
props: { "data-count": "5" },
|
||||
slots: { default: "5" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-count="5"');
|
||||
});
|
||||
});
|
102
src/components/ui/__tests__/Button.test.ts
Normal file
102
src/components/ui/__tests__/Button.test.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Button from "../Button.astro";
|
||||
|
||||
describe("Button", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Button, {
|
||||
slots: { default: "Click me" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Click me");
|
||||
expect(result).toContain('class="btn btn-primary"');
|
||||
expect(result).toContain('type="button"');
|
||||
expect(result).toContain("<button");
|
||||
});
|
||||
|
||||
it("renders different variants", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const variants = ["primary", "secondary", "outline", "ghost"] as const;
|
||||
|
||||
for (const variant of variants) {
|
||||
const result = await container.renderToString(Button, {
|
||||
props: { variant },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain(`btn-${variant}`);
|
||||
}
|
||||
});
|
||||
|
||||
it("renders different sizes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const sizes = ["sm", "lg"] as const;
|
||||
|
||||
for (const size of sizes) {
|
||||
const result = await container.renderToString(Button, {
|
||||
props: { size },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain(`btn-${size}`);
|
||||
}
|
||||
});
|
||||
|
||||
it("renders as anchor when href is provided", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Button, {
|
||||
props: { href: "/test" },
|
||||
slots: { default: "Link" },
|
||||
});
|
||||
|
||||
expect(result).toContain("<a");
|
||||
expect(result).toContain('href="/test"');
|
||||
expect(result).toContain("Link");
|
||||
expect(result).not.toContain("<button");
|
||||
});
|
||||
|
||||
it("applies disabled state", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Button, {
|
||||
props: { disabled: true },
|
||||
slots: { default: "Disabled" },
|
||||
});
|
||||
|
||||
expect(result).toContain("disabled");
|
||||
});
|
||||
|
||||
it("applies icon styling", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Button, {
|
||||
props: { icon: true },
|
||||
slots: { default: "🔍" },
|
||||
});
|
||||
|
||||
expect(result).toContain("btn-icon");
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Button, {
|
||||
props: { class: "custom-class" },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain("custom-class");
|
||||
});
|
||||
|
||||
it("handles different button types", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const types = ["button", "submit", "reset"] as const;
|
||||
|
||||
for (const type of types) {
|
||||
const result = await container.renderToString(Button, {
|
||||
props: { type },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain(`type="${type}"`);
|
||||
}
|
||||
});
|
||||
});
|
45
src/components/ui/__tests__/Card.test.ts
Normal file
45
src/components/ui/__tests__/Card.test.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Card from "../Card.astro";
|
||||
|
||||
describe("Card", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Card, {
|
||||
slots: { default: "Card content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Card content");
|
||||
expect(result).toContain('class="card"');
|
||||
expect(result).toContain("<div");
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Card, {
|
||||
props: { class: "custom-card" },
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("card custom-card");
|
||||
});
|
||||
|
||||
it("renders as div element", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Card, {
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('<div class="card"');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Card, {
|
||||
props: { "data-testid": "test-card" },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-testid="test-card"');
|
||||
});
|
||||
});
|
106
src/components/ui/__tests__/Col.test.ts
Normal file
106
src/components/ui/__tests__/Col.test.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Col from "../Col.astro";
|
||||
|
||||
describe("Col", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Col, {
|
||||
slots: { default: "Column content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Column content");
|
||||
expect(result).toContain('class="col"');
|
||||
expect(result).toContain("<div");
|
||||
});
|
||||
|
||||
it("renders with responsive breakpoints", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Col, {
|
||||
props: {
|
||||
xs: 12,
|
||||
sm: 6,
|
||||
md: 4,
|
||||
lg: 3,
|
||||
},
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("col--12");
|
||||
expect(result).toContain("col-sm-6");
|
||||
expect(result).toContain("col-md-4");
|
||||
expect(result).toContain("col-lg-3");
|
||||
});
|
||||
|
||||
it("renders with auto sizing", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Col, {
|
||||
props: { md: "auto" },
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("col-md-auto");
|
||||
});
|
||||
|
||||
it("renders with offset classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Col, {
|
||||
props: {
|
||||
md: 6,
|
||||
offset: { md: 3, lg: 2 },
|
||||
},
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("col-md-6");
|
||||
expect(result).toContain("offset-md-3");
|
||||
expect(result).toContain("offset-lg-2");
|
||||
});
|
||||
|
||||
it("renders with xl and xxl breakpoints", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Col, {
|
||||
props: {
|
||||
xl: 4,
|
||||
xxl: 2,
|
||||
},
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("col-xl-4");
|
||||
expect(result).toContain("col-xxl-2");
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Col, {
|
||||
props: {
|
||||
class: "custom-col",
|
||||
md: 6,
|
||||
},
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("col-md-6");
|
||||
expect(result).toContain("custom-col");
|
||||
});
|
||||
|
||||
it("renders as div element", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Col, {
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('<div class="col"');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Col, {
|
||||
props: { "data-column": "main" },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-column="main"');
|
||||
});
|
||||
});
|
56
src/components/ui/__tests__/Container.test.ts
Normal file
56
src/components/ui/__tests__/Container.test.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Container from "../Container.astro";
|
||||
|
||||
describe("Container", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Container, {
|
||||
slots: { default: "Container content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Container content");
|
||||
expect(result).toContain('class="container"');
|
||||
expect(result).toContain("<div");
|
||||
});
|
||||
|
||||
it("renders as fluid container", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Container, {
|
||||
props: { fluid: true },
|
||||
slots: { default: "Fluid content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Fluid content");
|
||||
expect(result).toContain('class="container-fluid"');
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Container, {
|
||||
props: { class: "custom-container" },
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("container custom-container");
|
||||
});
|
||||
|
||||
it("renders as div element", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Container, {
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('<div class="container"');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Container, {
|
||||
props: { "data-section": "main" },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-section="main"');
|
||||
});
|
||||
});
|
44
src/components/ui/__tests__/FormGroup.test.ts
Normal file
44
src/components/ui/__tests__/FormGroup.test.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import FormGroup from "../FormGroup.astro";
|
||||
|
||||
describe("FormGroup", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(FormGroup, {
|
||||
slots: { default: "<label>Form content</label>" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Form content");
|
||||
expect(result).toContain('class="form-group"');
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(FormGroup, {
|
||||
props: { class: "custom-form-group" },
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("form-group custom-form-group");
|
||||
});
|
||||
|
||||
it("renders as div element", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(FormGroup, {
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('<div class="form-group"');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(FormGroup, {
|
||||
props: { "data-testid": "form-section" },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-testid="form-section"');
|
||||
});
|
||||
});
|
103
src/components/ui/__tests__/Input.test.ts
Normal file
103
src/components/ui/__tests__/Input.test.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Input from "../Input.astro";
|
||||
|
||||
describe("Input", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Input);
|
||||
|
||||
expect(result).toContain("<input");
|
||||
expect(result).toContain('type="text"');
|
||||
expect(result).toContain("form-control-base input");
|
||||
});
|
||||
|
||||
it("renders different input types", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const types = [
|
||||
"text",
|
||||
"email",
|
||||
"password",
|
||||
"number",
|
||||
"tel",
|
||||
"url",
|
||||
"search",
|
||||
] as const;
|
||||
|
||||
for (const type of types) {
|
||||
const result = await container.renderToString(Input, {
|
||||
props: { type },
|
||||
});
|
||||
|
||||
expect(result).toContain(`type="${type}"`);
|
||||
}
|
||||
});
|
||||
|
||||
it("renders different sizes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const sizes = ["sm", "lg"] as const;
|
||||
|
||||
for (const size of sizes) {
|
||||
const result = await container.renderToString(Input, {
|
||||
props: { size },
|
||||
});
|
||||
|
||||
expect(result).toContain(`input-${size}`);
|
||||
}
|
||||
});
|
||||
|
||||
it("applies placeholder", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Input, {
|
||||
props: { placeholder: "Enter text" },
|
||||
});
|
||||
|
||||
expect(result).toContain('placeholder="Enter text"');
|
||||
});
|
||||
|
||||
it("applies value", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Input, {
|
||||
props: { value: "test value" },
|
||||
});
|
||||
|
||||
expect(result).toContain('value="test value"');
|
||||
});
|
||||
|
||||
it("applies name and id attributes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Input, {
|
||||
props: { name: "username", id: "user-input" },
|
||||
});
|
||||
|
||||
expect(result).toContain('name="username"');
|
||||
expect(result).toContain('id="user-input"');
|
||||
});
|
||||
|
||||
it("applies disabled state", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Input, {
|
||||
props: { disabled: true },
|
||||
});
|
||||
|
||||
expect(result).toContain("disabled");
|
||||
});
|
||||
|
||||
it("applies required attribute", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Input, {
|
||||
props: { required: true },
|
||||
});
|
||||
|
||||
expect(result).toContain("required");
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Input, {
|
||||
props: { class: "custom-input" },
|
||||
});
|
||||
|
||||
expect(result).toContain("custom-input");
|
||||
});
|
||||
});
|
66
src/components/ui/__tests__/Modal.test.ts
Normal file
66
src/components/ui/__tests__/Modal.test.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Modal from "../Modal.astro";
|
||||
|
||||
describe("Modal", () => {
|
||||
it("renders with required id prop", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Modal, {
|
||||
props: { id: "test-modal" },
|
||||
slots: { default: "Modal content" },
|
||||
});
|
||||
|
||||
expect(result).toContain('class="modal-backdrop"');
|
||||
expect(result).toContain('class="modal"');
|
||||
expect(result).toContain('id="test-modal"');
|
||||
expect(result).toContain("Modal content");
|
||||
});
|
||||
|
||||
it("starts hidden by default", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Modal, {
|
||||
props: { id: "hidden-modal" },
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain('style="display: none;"');
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Modal, {
|
||||
props: {
|
||||
id: "custom-modal",
|
||||
class: "custom-modal-class",
|
||||
},
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("modal-backdrop custom-modal-class");
|
||||
});
|
||||
|
||||
it("renders nested modal structure", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Modal, {
|
||||
props: { id: "nested-modal" },
|
||||
slots: { default: "Nested content" },
|
||||
});
|
||||
|
||||
expect(result).toContain('class="modal-backdrop"');
|
||||
expect(result).toContain('class="modal"');
|
||||
expect(result).toContain("Nested content");
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Modal, {
|
||||
props: {
|
||||
id: "props-modal",
|
||||
"data-testid": "modal-test",
|
||||
},
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-testid="modal-test"');
|
||||
});
|
||||
});
|
44
src/components/ui/__tests__/ModalBody.test.ts
Normal file
44
src/components/ui/__tests__/ModalBody.test.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import ModalBody from "../ModalBody.astro";
|
||||
|
||||
describe("ModalBody", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalBody, {
|
||||
slots: { default: "Modal body content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Modal body content");
|
||||
expect(result).toContain('class="modal-body"');
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalBody, {
|
||||
props: { class: "custom-body" },
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("modal-body custom-body");
|
||||
});
|
||||
|
||||
it("renders as div element", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalBody, {
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('<div class="modal-body"');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalBody, {
|
||||
props: { "data-content": "main" },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-content="main"');
|
||||
});
|
||||
});
|
44
src/components/ui/__tests__/ModalFooter.test.ts
Normal file
44
src/components/ui/__tests__/ModalFooter.test.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import ModalFooter from "../ModalFooter.astro";
|
||||
|
||||
describe("ModalFooter", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalFooter, {
|
||||
slots: { default: "Footer buttons" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Footer buttons");
|
||||
expect(result).toContain('class="modal-footer"');
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalFooter, {
|
||||
props: { class: "custom-footer" },
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("modal-footer custom-footer");
|
||||
});
|
||||
|
||||
it("renders as div element", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalFooter, {
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('<div class="modal-footer"');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalFooter, {
|
||||
props: { "data-actions": "confirm" },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-actions="confirm"');
|
||||
});
|
||||
});
|
54
src/components/ui/__tests__/ModalHeader.test.ts
Normal file
54
src/components/ui/__tests__/ModalHeader.test.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import ModalHeader from "../ModalHeader.astro";
|
||||
|
||||
describe("ModalHeader", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalHeader, {
|
||||
slots: { default: "Modal Title" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Modal Title");
|
||||
expect(result).toContain('class="modal-header"');
|
||||
});
|
||||
|
||||
it("includes close button", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalHeader, {
|
||||
slots: { default: "Title" },
|
||||
});
|
||||
|
||||
expect(result).toContain("data-modal-close");
|
||||
expect(result).toContain("×");
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalHeader, {
|
||||
props: { class: "custom-header" },
|
||||
slots: { default: "Title" },
|
||||
});
|
||||
|
||||
expect(result).toContain("modal-header custom-header");
|
||||
});
|
||||
|
||||
it("renders as div element", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalHeader, {
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('<div class="modal-header"');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(ModalHeader, {
|
||||
props: { "data-header": "modal" },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-header="modal"');
|
||||
});
|
||||
});
|
113
src/components/ui/__tests__/MovieCard.test.ts
Normal file
113
src/components/ui/__tests__/MovieCard.test.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import MovieCard from "../MovieCard.astro";
|
||||
|
||||
describe("MovieCard", () => {
|
||||
const mockMovie = {
|
||||
title: "Test Movie",
|
||||
poster: "/test-poster.jpg",
|
||||
};
|
||||
|
||||
it("renders with required props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(MovieCard, {
|
||||
props: mockMovie,
|
||||
});
|
||||
|
||||
expect(result).toContain('class="movie-card"');
|
||||
expect(result).toContain("Test Movie");
|
||||
expect(result).toContain('src="/test-poster.jpg"');
|
||||
expect(result).toContain('alt="Test Movie"');
|
||||
expect(result).toContain('class="movie-title"');
|
||||
expect(result).toContain('class="movie-poster"');
|
||||
});
|
||||
|
||||
it("renders as div by default", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(MovieCard, {
|
||||
props: mockMovie,
|
||||
});
|
||||
|
||||
expect(result).toContain('<div class="movie-card"');
|
||||
});
|
||||
|
||||
it("renders as anchor when href provided", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(MovieCard, {
|
||||
props: { ...mockMovie, href: "/movie/123" },
|
||||
});
|
||||
|
||||
expect(result).toContain('<a class="movie-card"');
|
||||
expect(result).toContain('href="/movie/123"');
|
||||
});
|
||||
|
||||
it("displays movie year and genre", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(MovieCard, {
|
||||
props: { ...mockMovie, year: 2023, genre: "Action" },
|
||||
});
|
||||
|
||||
expect(result).toContain('class="movie-meta"');
|
||||
expect(result).toContain("2023");
|
||||
expect(result).toContain("Action");
|
||||
expect(result).toContain("•");
|
||||
});
|
||||
|
||||
it("displays only year when genre not provided", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(MovieCard, {
|
||||
props: { ...mockMovie, year: 2023 },
|
||||
});
|
||||
|
||||
expect(result).toContain("2023");
|
||||
expect(result).not.toContain("•");
|
||||
});
|
||||
|
||||
it("displays only genre when year not provided", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(MovieCard, {
|
||||
props: { ...mockMovie, genre: "Drama" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Drama");
|
||||
expect(result).not.toContain("•");
|
||||
});
|
||||
|
||||
it("displays rating when provided", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(MovieCard, {
|
||||
props: { ...mockMovie, rating: 8.5 },
|
||||
});
|
||||
|
||||
expect(result).toContain('class="movie-rating"');
|
||||
expect(result).toContain("⭐");
|
||||
expect(result).toContain("8.5/10");
|
||||
});
|
||||
|
||||
it("does not display rating when not provided", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(MovieCard, {
|
||||
props: mockMovie,
|
||||
});
|
||||
|
||||
expect(result).not.toContain('class="movie-rating"');
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(MovieCard, {
|
||||
props: { ...mockMovie, class: "featured-movie" },
|
||||
});
|
||||
|
||||
expect(result).toContain("movie-card featured-movie");
|
||||
});
|
||||
|
||||
it("applies lazy loading to poster", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(MovieCard, {
|
||||
props: mockMovie,
|
||||
});
|
||||
|
||||
expect(result).toContain('loading="lazy"');
|
||||
});
|
||||
});
|
85
src/components/ui/__tests__/NavLink.test.ts
Normal file
85
src/components/ui/__tests__/NavLink.test.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import NavLink from "../NavLink.astro";
|
||||
|
||||
describe("NavLink", () => {
|
||||
it("renders with required href prop", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(NavLink, {
|
||||
props: { href: "/home" },
|
||||
slots: { default: "Home" },
|
||||
});
|
||||
|
||||
expect(result).toContain("<li data-astro-source-file");
|
||||
expect(result).toContain("<a");
|
||||
expect(result).toContain('href="/home"');
|
||||
expect(result).toContain("Home");
|
||||
expect(result).toContain('class="nav-link"');
|
||||
});
|
||||
|
||||
it("applies active state", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(NavLink, {
|
||||
props: {
|
||||
href: "/current",
|
||||
active: true,
|
||||
},
|
||||
slots: { default: "Current Page" },
|
||||
});
|
||||
|
||||
expect(result).toContain("nav-link");
|
||||
expect(result).toContain("active");
|
||||
});
|
||||
|
||||
it("does not apply active class by default", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(NavLink, {
|
||||
props: { href: "/page" },
|
||||
slots: { default: "Page" },
|
||||
});
|
||||
|
||||
expect(result).toContain("nav-link");
|
||||
expect(result).not.toContain("active");
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(NavLink, {
|
||||
props: {
|
||||
href: "/test",
|
||||
class: "custom-nav-link",
|
||||
},
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain("nav-link");
|
||||
expect(result).toContain("custom-nav-link");
|
||||
});
|
||||
|
||||
it("wraps link in list item", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(NavLink, {
|
||||
props: { href: "/wrapped" },
|
||||
slots: { default: "Wrapped" },
|
||||
});
|
||||
|
||||
expect(result).toContain("<li data-astro-source-file");
|
||||
expect(result).toContain("<a");
|
||||
expect(result).toContain("Wrapped");
|
||||
});
|
||||
|
||||
it("passes through additional props to anchor", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(NavLink, {
|
||||
props: {
|
||||
href: "/props-test",
|
||||
target: "_blank",
|
||||
rel: "noopener",
|
||||
},
|
||||
slots: { default: "External" },
|
||||
});
|
||||
|
||||
expect(result).toContain('target="_blank"');
|
||||
expect(result).toContain('rel="noopener"');
|
||||
});
|
||||
});
|
81
src/components/ui/__tests__/Navbar.test.ts
Normal file
81
src/components/ui/__tests__/Navbar.test.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Navbar from "../Navbar.astro";
|
||||
|
||||
describe("Navbar", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Navbar, {
|
||||
slots: {
|
||||
brand: "Brand",
|
||||
nav: "Navigation",
|
||||
actions: "Actions",
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toContain('class="navbar"');
|
||||
expect(result).toContain("<nav");
|
||||
});
|
||||
|
||||
it("renders brand slot content", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Navbar, {
|
||||
slots: {
|
||||
brand: '<a href="/">MyBrand</a>',
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toContain("MyBrand");
|
||||
});
|
||||
|
||||
it("renders navigation slot content", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Navbar, {
|
||||
slots: {
|
||||
nav: "<ul><li>Home</li><li>About</li></ul>",
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toContain("<ul><li>Home</li><li>About</li></ul>");
|
||||
});
|
||||
|
||||
it("renders actions slot content", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Navbar, {
|
||||
slots: {
|
||||
actions: "<button>Login</button>",
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toContain("<button>Login</button>");
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Navbar, {
|
||||
props: { class: "custom-navbar" },
|
||||
});
|
||||
|
||||
expect(result).toContain("navbar custom-navbar");
|
||||
});
|
||||
|
||||
it("has proper grid structure", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Navbar);
|
||||
|
||||
expect(result).toContain('class="container"');
|
||||
expect(result).toContain(
|
||||
'class="row justify-content-between align-items-center"',
|
||||
);
|
||||
expect(result.match(/class="col-auto"/g)?.length).toBe(3);
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Navbar, {
|
||||
props: { "data-nav": "main" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-nav="main"');
|
||||
});
|
||||
});
|
60
src/components/ui/__tests__/NavbarBrand.test.ts
Normal file
60
src/components/ui/__tests__/NavbarBrand.test.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import NavbarBrand from "../NavbarBrand.astro";
|
||||
|
||||
describe("NavbarBrand", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(NavbarBrand, {
|
||||
slots: { default: "Brand Name" },
|
||||
});
|
||||
|
||||
expect(result).toContain('class="navbar-brand"');
|
||||
expect(result).toContain("<a");
|
||||
expect(result).toContain("Brand Name");
|
||||
expect(result).toContain('href="/"');
|
||||
});
|
||||
|
||||
it("applies custom href", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(NavbarBrand, {
|
||||
props: { href: "/dashboard" },
|
||||
slots: { default: "Dashboard" },
|
||||
});
|
||||
|
||||
expect(result).toContain('href="/dashboard"');
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(NavbarBrand, {
|
||||
props: { class: "custom-brand" },
|
||||
slots: { default: "Brand" },
|
||||
});
|
||||
|
||||
expect(result).toContain("navbar-brand custom-brand");
|
||||
});
|
||||
|
||||
it("renders as anchor element", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(NavbarBrand, {
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('<a class="navbar-brand"');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(NavbarBrand, {
|
||||
props: {
|
||||
title: "Go to homepage",
|
||||
"data-brand": "main",
|
||||
},
|
||||
slots: { default: "Home" },
|
||||
});
|
||||
|
||||
expect(result).toContain('title="Go to homepage"');
|
||||
expect(result).toContain('data-brand="main"');
|
||||
});
|
||||
});
|
91
src/components/ui/__tests__/Progress.test.ts
Normal file
91
src/components/ui/__tests__/Progress.test.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Progress from "../Progress.astro";
|
||||
|
||||
describe("Progress", () => {
|
||||
it("renders with required value prop", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Progress, {
|
||||
props: { value: 50 },
|
||||
});
|
||||
|
||||
expect(result).toContain('class="progress"');
|
||||
expect(result).toContain('class="progress-bar"');
|
||||
});
|
||||
|
||||
it("calculates correct percentage with default max", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Progress, {
|
||||
props: { value: 25 },
|
||||
});
|
||||
|
||||
expect(result).toContain("width: 25%");
|
||||
});
|
||||
|
||||
it("calculates correct percentage with custom max", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Progress, {
|
||||
props: { value: 30, max: 60 },
|
||||
});
|
||||
|
||||
expect(result).toContain("width: 50%");
|
||||
});
|
||||
|
||||
it("caps percentage at 100% when value exceeds max", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Progress, {
|
||||
props: { value: 150, max: 100 },
|
||||
});
|
||||
|
||||
expect(result).toContain("width: 100%");
|
||||
});
|
||||
|
||||
it("applies correct ARIA attributes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Progress, {
|
||||
props: { value: 40, max: 80 },
|
||||
});
|
||||
|
||||
expect(result).toContain('role="progressbar"');
|
||||
expect(result).toContain('aria-valuenow="40"');
|
||||
expect(result).toContain('aria-valuemin="0"');
|
||||
expect(result).toContain('aria-valuemax="80"');
|
||||
});
|
||||
|
||||
it("uses default max value of 100", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Progress, {
|
||||
props: { value: 75 },
|
||||
});
|
||||
|
||||
expect(result).toContain('aria-valuemax="100"');
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Progress, {
|
||||
props: { value: 60, class: "custom-progress" },
|
||||
});
|
||||
|
||||
expect(result).toContain("progress custom-progress");
|
||||
});
|
||||
|
||||
it("handles zero value", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Progress, {
|
||||
props: { value: 0 },
|
||||
});
|
||||
|
||||
expect(result).toContain("width: 0%");
|
||||
expect(result).toContain('aria-valuenow="0"');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Progress, {
|
||||
props: { value: 45, "data-progress": "loading" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-progress="loading"');
|
||||
});
|
||||
});
|
54
src/components/ui/__tests__/Row.test.ts
Normal file
54
src/components/ui/__tests__/Row.test.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Row from "../Row.astro";
|
||||
|
||||
describe("Row", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Row, {
|
||||
slots: { default: "Row content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Row content");
|
||||
expect(result).toContain('class="row"');
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Row, {
|
||||
props: { class: "custom-row" },
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain("row custom-row");
|
||||
});
|
||||
|
||||
it("applies inline styles", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Row, {
|
||||
props: { style: "margin-top: 20px;" },
|
||||
slots: { default: "Content" },
|
||||
});
|
||||
|
||||
expect(result).toContain('style="margin-top: 20px;"');
|
||||
});
|
||||
|
||||
it("renders as div element", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Row, {
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('<div class="row"');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Row, {
|
||||
props: { "data-row": "header" },
|
||||
slots: { default: "Test" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-row="header"');
|
||||
});
|
||||
});
|
94
src/components/ui/__tests__/SearchBar.test.ts
Normal file
94
src/components/ui/__tests__/SearchBar.test.ts
Normal file
@ -0,0 +1,94 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import SearchBar from "../SearchBar.astro";
|
||||
|
||||
describe("SearchBar", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(SearchBar);
|
||||
|
||||
expect(result).toContain('class="search-bar"');
|
||||
expect(result).toContain('type="search"');
|
||||
expect(result).toContain('class="search-icon"');
|
||||
});
|
||||
|
||||
it("applies default placeholder", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(SearchBar);
|
||||
|
||||
expect(result).toContain('placeholder="Rechercher..."');
|
||||
});
|
||||
|
||||
it("applies custom placeholder", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(SearchBar, {
|
||||
props: { placeholder: "Search movies..." },
|
||||
});
|
||||
|
||||
expect(result).toContain('placeholder="Search movies..."');
|
||||
});
|
||||
|
||||
it("applies value prop", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(SearchBar, {
|
||||
props: { value: "test query" },
|
||||
});
|
||||
|
||||
expect(result).toContain('value="test query"');
|
||||
});
|
||||
|
||||
it("applies default name and id", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(SearchBar);
|
||||
|
||||
expect(result).toContain('name="search"');
|
||||
expect(result).toContain('id="search"');
|
||||
});
|
||||
|
||||
it("applies custom name and id", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(SearchBar, {
|
||||
props: {
|
||||
name: "movie-search",
|
||||
id: "movie-search-input",
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toContain('name="movie-search"');
|
||||
expect(result).toContain('id="movie-search-input"');
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(SearchBar, {
|
||||
props: { class: "custom-search" },
|
||||
});
|
||||
|
||||
expect(result).toContain("search-bar custom-search");
|
||||
});
|
||||
|
||||
it("renders search icon with correct attributes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(SearchBar);
|
||||
|
||||
expect(result).toContain('width="16"');
|
||||
expect(result).toContain('height="16"');
|
||||
expect(result).toContain('viewBox="0 0 24 24"');
|
||||
});
|
||||
|
||||
it("input has search type", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(SearchBar);
|
||||
|
||||
expect(result).toContain('type="search"');
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(SearchBar, {
|
||||
props: { "data-testid": "search-component" },
|
||||
});
|
||||
|
||||
expect(result).toContain('data-testid="search-component"');
|
||||
});
|
||||
});
|
71
src/components/ui/__tests__/Select.test.ts
Normal file
71
src/components/ui/__tests__/Select.test.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Select from "../Select.astro";
|
||||
|
||||
describe("Select", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Select, {
|
||||
slots: {
|
||||
default:
|
||||
'<option value="1">Option 1</option><option value="2">Option 2</option>',
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toContain("<select");
|
||||
expect(result).toContain('class="select"');
|
||||
expect(result).toContain("Option 1");
|
||||
expect(result).toContain("Option 2");
|
||||
});
|
||||
|
||||
it("applies name and id attributes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Select, {
|
||||
props: { name: "category", id: "category-select" },
|
||||
});
|
||||
|
||||
expect(result).toContain('name="category"');
|
||||
expect(result).toContain('id="category-select"');
|
||||
});
|
||||
|
||||
it("applies disabled state", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Select, {
|
||||
props: { disabled: true },
|
||||
});
|
||||
|
||||
expect(result).toContain("disabled");
|
||||
});
|
||||
|
||||
it("applies required attribute", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Select, {
|
||||
props: { required: true },
|
||||
});
|
||||
|
||||
expect(result).toContain("required");
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Select, {
|
||||
props: { class: "custom-select" },
|
||||
});
|
||||
|
||||
expect(result).toContain("select custom-select");
|
||||
});
|
||||
|
||||
it("renders option content in slot", async () => {
|
||||
const options =
|
||||
'<option value="apple">Apple</option><option value="banana">Banana</option>';
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Select, {
|
||||
slots: { default: options },
|
||||
});
|
||||
|
||||
expect(result).toContain("Apple");
|
||||
expect(result).toContain("Banana");
|
||||
expect(result).toContain('value="apple"');
|
||||
expect(result).toContain('value="banana"');
|
||||
});
|
||||
});
|
71
src/components/ui/__tests__/Spinner.test.ts
Normal file
71
src/components/ui/__tests__/Spinner.test.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Spinner from "../Spinner.astro";
|
||||
|
||||
describe("Spinner", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Spinner);
|
||||
|
||||
expect(result).toContain('<div class="spinner"');
|
||||
expect(result).toContain("></div>");
|
||||
});
|
||||
|
||||
it("renders small size", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Spinner, {
|
||||
props: { size: "sm" },
|
||||
});
|
||||
|
||||
expect(result).toContain("spinner spinner-sm");
|
||||
});
|
||||
|
||||
it("renders large size", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Spinner, {
|
||||
props: { size: "lg" },
|
||||
});
|
||||
|
||||
expect(result).toContain("spinner spinner-lg");
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Spinner, {
|
||||
props: { class: "loading-spinner" },
|
||||
});
|
||||
|
||||
expect(result).toContain("spinner loading-spinner");
|
||||
});
|
||||
|
||||
it("applies custom classes with size", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Spinner, {
|
||||
props: { size: "lg", class: "custom-spinner" },
|
||||
});
|
||||
|
||||
expect(result).toContain("spinner spinner-lg custom-spinner");
|
||||
});
|
||||
|
||||
it("renders as empty div", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Spinner);
|
||||
|
||||
expect(result).toContain("></div>");
|
||||
// The div should be empty (no content between opening and closing tags, except for Astro metadata)
|
||||
expect(result).toMatch(/<div[^>]*><\/div>/);
|
||||
});
|
||||
|
||||
it("passes through additional props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Spinner, {
|
||||
props: {
|
||||
"data-testid": "loading-indicator",
|
||||
"aria-label": "Loading content",
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toContain('data-testid="loading-indicator"');
|
||||
expect(result).toContain('aria-label="Loading content"');
|
||||
});
|
||||
});
|
78
src/components/ui/__tests__/Textarea.test.ts
Normal file
78
src/components/ui/__tests__/Textarea.test.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Textarea from "../Textarea.astro";
|
||||
|
||||
describe("Textarea", () => {
|
||||
it("renders with default props", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Textarea);
|
||||
|
||||
expect(result).toContain("<textarea");
|
||||
expect(result).toContain('class="textarea"');
|
||||
expect(result).toContain('rows="4"');
|
||||
});
|
||||
|
||||
it("applies placeholder", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Textarea, {
|
||||
props: { placeholder: "Enter your message" },
|
||||
});
|
||||
|
||||
expect(result).toContain('placeholder="Enter your message"');
|
||||
});
|
||||
|
||||
it("applies value", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Textarea, {
|
||||
props: { value: "Initial text" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Initial text");
|
||||
});
|
||||
|
||||
it("applies name and id attributes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Textarea, {
|
||||
props: { name: "message", id: "message-input" },
|
||||
});
|
||||
|
||||
expect(result).toContain('name="message"');
|
||||
expect(result).toContain('id="message-input"');
|
||||
});
|
||||
|
||||
it("applies custom rows", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Textarea, {
|
||||
props: { rows: 8 },
|
||||
});
|
||||
|
||||
expect(result).toContain('rows="8"');
|
||||
});
|
||||
|
||||
it("applies disabled state", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Textarea, {
|
||||
props: { disabled: true },
|
||||
});
|
||||
|
||||
expect(result).toContain("disabled");
|
||||
});
|
||||
|
||||
it("applies required attribute", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Textarea, {
|
||||
props: { required: true },
|
||||
});
|
||||
|
||||
expect(result).toContain("required");
|
||||
});
|
||||
|
||||
it("applies custom classes", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Textarea, {
|
||||
props: { class: "custom-textarea" },
|
||||
});
|
||||
|
||||
expect(result).toContain("textarea custom-textarea");
|
||||
});
|
||||
});
|
15
src/components/ui/__tests__/basic.test.ts
Normal file
15
src/components/ui/__tests__/basic.test.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
||||
import Button from "../Button.astro";
|
||||
|
||||
describe("Basic Astro Component Test", () => {
|
||||
it("should render a simple button", async () => {
|
||||
const container = await AstroContainer.create();
|
||||
const result = await container.renderToString(Button, {
|
||||
slots: { default: "Test Button" },
|
||||
});
|
||||
|
||||
expect(result).toContain("Test Button");
|
||||
expect(result).toContain("btn");
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user