# test.social/core/renderers/grid.renderer.test.ts

> 75 lines of code and 0 definitions.

Tree: Codebase Testing
Language: typescript
Canonical: https://banes-lab.com/anatomy/testing#file-testing-test-social-core-renderers-grid-renderer-test-ts
Source text: https://banes-lab.com/source/testing/test.social/core/renderers/grid.renderer.test.ts.txt

Listed in [test.social/core/renderers](https://banes-lab.com/api/source/testing/test.social/core/renderers.md), before [test.social/core/renderers/stage.renderer.test.ts](https://banes-lab.com/source/testing/test.social/core/renderers/stage.renderer.test.ts.md).

## Contained in

- [test.social/core/renderers](https://banes-lab.com/anatomy/testing/folder-testing-test-social-core-renderers.md)

## Source

```typescript
import type { CardPage, RegisteredCard } from "@banes-lab/social-share/types/card.types.ts";
import { describe, expect, it } from "vitest";
import { STAGE_HEADING } from "@banes-lab/social-share/configuration/strings/card.strings.ts";
import { createCard } from "@banes-lab/social-share/core/factories/card.factory.ts";
import { renderGrid } from "@banes-lab/social-share/core/renderers/grid.renderer.ts";

type Resize = (entries: readonly unknown[]) => void;

const observers: { resize: Resize; disconnected: boolean }[] = [];

class StubObserver {
    private readonly entry: { resize: Resize; disconnected: boolean };

    public constructor(callback: Resize) {
        this.entry = { disconnected: false, resize: callback };
        observers.push(this.entry);
    }

    public observe(): void {}

    public disconnect(): void {
        this.entry.disconnected = true;
    }
}

Reflect.set(globalThis, "ResizeObserver", StubObserver);
Reflect.set(globalThis, "IntersectionObserver", StubObserver);

const pageOf = function pageOf(id: string, headline: string, icon: string): CardPage {
    return {
        accent: "page-sky",
        address: `lab.example/${id}`,
        headline,
        icon,
        id,
        mark: "/mark.gif",
        tagline: "Answers",
    };
};

const HOME = pageOf("home", "Home", "bi-house");
const FAQ = pageOf("faq", "Questions", "bi-question-circle");

const cardOf = function cardOf(page: CardPage): RegisteredCard {
    return {
        id: page.id,
        origin: `/cards/${page.id}/plugins/${page.id}.plugin.ts`,
        spec: createCard({
            alt: "A card.",
            id: page.id,
            layers: [{ id: "title", kind: "text", placement: { x: 0.1, y: 0.1 }, text: page.headline }],
            page: page.id,
            stylesheet: "",
            tone: page.accent,
        }),
    };
};

describe("renderGrid", () => {
    it("lays one spread per card in page order, each titled by its page's icon and headline in its tone", () => {
        const host = document.createElement("main");
        const stop = renderGrid(
            host,
            [cardOf(FAQ), cardOf(HOME)],
            [HOME, FAQ],
            [{ card: "stray", message: "is orphaned." }],
        );
        expect(host.querySelector(".stage-heading")?.textContent).toBe(STAGE_HEADING);
        const spreads = [...host.querySelectorAll(".stage-spread")];
        expect(spreads.map((spread) => spread.querySelector(".stage-spread-title")?.textContent)).toStrictEqual([
            HOME.headline,
            FAQ.headline,
        ]);
        const [first] = spreads;
        expect(first?.classList.contains(HOME.accent)).toBe(true);
        expect(first?.querySelector(".stage-spread-title i")?.classList.contains(HOME.icon)).toBe(true);
        expect(first?.querySelector(".stage-spread-meta")?.textContent).toContain(HOME.address);
        expect(first?.querySelectorAll(".stage-tile")).toHaveLength(cardOf(HOME).spec.profiles.length);
        expect(host.querySelector(".stage-findings")?.textContent).toContain("stray");
        for (const observer of observers) {
            observer.resize([]);
        }
        stop();
        expect(observers.every((observer) => observer.disconnected)).toBe(true);
    });
});
```
