143 lines
4.5 KiB
TypeScript
143 lines
4.5 KiB
TypeScript
|
|
import { describe, it, expect } from "vitest";
|
||
|
|
import { readFileSync } from "node:fs";
|
||
|
|
import { resolve } from "node:path";
|
||
|
|
|
||
|
|
describe("Mietkatalog Page (list)", () => {
|
||
|
|
const pagePath = resolve(__dirname, "../../pages/mietkatalog.vue");
|
||
|
|
const content = readFileSync(pagePath, "utf-8");
|
||
|
|
|
||
|
|
it("should use useAsyncData for SSR data fetching", () => {
|
||
|
|
expect(content).toContain("useAsyncData");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should use useEquipment composable", () => {
|
||
|
|
expect(content).toContain("useEquipment");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should have search input with data-testid equipment-search", () => {
|
||
|
|
expect(content).toContain('data-testid="equipment-search"');
|
||
|
|
expect(content).toContain('type="text"');
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should have sort dropdown with name_asc and name_desc options", () => {
|
||
|
|
expect(content).toContain('data-testid="sort-select"');
|
||
|
|
expect(content).toContain('value="name_asc"');
|
||
|
|
expect(content).toContain('value="name_desc"');
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should have category filter chips", () => {
|
||
|
|
expect(content).toContain('data-testid="category-chips"');
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should have reset filters button", () => {
|
||
|
|
expect(content).toContain('data-testid="reset-filters"');
|
||
|
|
expect(content).toContain('resetFilters');
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should show result count", () => {
|
||
|
|
expect(content).toContain('data-testid="result-count"');
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should have pagination with prev/next buttons", () => {
|
||
|
|
expect(content).toContain('data-testid="pagination"');
|
||
|
|
expect(content).toContain('data-testid="prev-page"');
|
||
|
|
expect(content).toContain('data-testid="next-page"');
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should show loading skeleton state", () => {
|
||
|
|
expect(content).toContain('data-testid="loading-state"');
|
||
|
|
expect(content).toContain("skeleton-shimmer");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should use EmptyState component for empty results", () => {
|
||
|
|
expect(content).toContain("EmptyState");
|
||
|
|
expect(content).toContain("Keine Artikel gefunden");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should use ErrorState component for errors", () => {
|
||
|
|
expect(content).toContain("ErrorState");
|
||
|
|
expect(content).toContain("retry");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should render EquipmentCard for each item", () => {
|
||
|
|
expect(content).toContain("EquipmentCard");
|
||
|
|
expect(content).toContain('v-for="item in data.items"');
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should have debounce on search input", () => {
|
||
|
|
expect(content).toContain("setTimeout");
|
||
|
|
expect(content).toContain("clearTimeout");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should reset to page 1 on search, sort, or category change", () => {
|
||
|
|
expect(content).toContain("currentPage.value = 1");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should use useHead for page title", () => {
|
||
|
|
expect(content).toContain('useHead');
|
||
|
|
expect(content).toContain("Mietkatalog");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should use Tailwind classes, no inline styles", () => {
|
||
|
|
expect(content).not.toContain('style="');
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should use TypeScript with lang=ts", () => {
|
||
|
|
expect(content).toContain('<script setup lang="ts">');
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should use equipment grid layout", () => {
|
||
|
|
expect(content).toContain('data-testid="equipment-grid"');
|
||
|
|
expect(content).toContain("grid-cols");
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("EquipmentCard Component", () => {
|
||
|
|
const cardPath = resolve(__dirname, "../../components/EquipmentCard.vue");
|
||
|
|
const content = readFileSync(cardPath, "utf-8");
|
||
|
|
|
||
|
|
it("should have image with fallback placeholder", () => {
|
||
|
|
expect(content).toContain("v-if=\"equipment.image_url\"");
|
||
|
|
expect(content).toContain("v-else");
|
||
|
|
expect(content).toContain("svg");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should show category badge", () => {
|
||
|
|
expect(content).toContain("equipment.category");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should display equipment name", () => {
|
||
|
|
expect(content).toContain("equipment.name");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should show truncated description", () => {
|
||
|
|
expect(content).toContain("equipment.description");
|
||
|
|
expect(content).toContain("line-clamp");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should display rental_price formatted", () => {
|
||
|
|
expect(content).toContain("equipment.rental_price");
|
||
|
|
expect(content).toContain("formatPrice");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should emit add-to-cart with id and name", () => {
|
||
|
|
expect(content).toContain("add-to-cart");
|
||
|
|
expect(content).toContain("equipment.id");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should have Mietanfrage button", () => {
|
||
|
|
expect(content).toContain("Mietanfrage");
|
||
|
|
expect(content).toContain("btn-primary");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should link to detail page", () => {
|
||
|
|
expect(content).toContain("NuxtLink");
|
||
|
|
expect(content).toContain("/mietkatalog/");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("should use TypeScript with EquipmentItem type", () => {
|
||
|
|
expect(content).toContain('<script setup lang="ts">');
|
||
|
|
expect(content).toContain("EquipmentItem");
|
||
|
|
});
|
||
|
|
});
|