# test.social/core/evaluators/card.evaluator.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-evaluators-card-evaluator-test-ts
Source text: https://banes-lab.com/source/testing/test.social/core/evaluators/card.evaluator.test.ts.txt

Listed in [test.social/core/evaluators](https://banes-lab.com/api/source/testing/test.social/core/evaluators.md), before [test.social/core/evaluators/card.fragment.evaluator.test.ts](https://banes-lab.com/source/testing/test.social/core/evaluators/card.fragment.evaluator.test.ts.md).

## Contained in

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

## Source

```typescript
import { describe, expect, it } from "vitest";
import {
    frameContext,
    resolveCard,
    resolveLayer,
    valueAt,
} from "@banes-lab/social-share/core/evaluators/card.evaluator.ts";
import type { EffectKind } from "@banes-lab/social-share/types/card.types.ts";
import { createCard } from "@banes-lab/social-share/core/factories/card.factory.ts";

const PROFILE = { height: 630, id: "og", width: 1200 };

const isForgedEffect = function isForgedEffect(name: string): name is EffectKind {
    return name.length > 0;
};

const spec = createCard({
    alt: "A test card.",
    id: "test",
    layers: [
        {
            effects: [{ amount: (frame) => frame.progress * 10, kind: "blur" }],
            id: "title",
            kind: "text",
            opacity: (frame) => frame.progress,
            placement: { anchor: "center", x: 0.5, y: (frame) => frame.progress },
            style: { color: "red", fontSize: "12px" },
            text: (frame) => `frame ${String(frame.frame)}`,
        },
        { id: "field", kind: "shader", placement: { x: 0, y: 0 }, shader: "fn shade(", uniforms: { glow: 2 } },
    ],
    page: "home",
    stylesheet: "",
    timeline: { fps: 10, frames: 10 },
    tone: "page-gold",
});

describe("createCard", () => {
    it("fills the timeline and profiles from the output config", () => {
        expect(spec.timeline).toStrictEqual({ fps: 10, frames: 10, keyFrame: 0, loop: true });
        expect(spec.profiles).toStrictEqual(["og", "x", "square"]);
    });
});

describe("valueAt and frameContext", () => {
    it("resolves constants and computed expressions against a frame", () => {
        const frame = frameContext(spec, PROFILE, 5);
        expect(frame).toStrictEqual({ frame: 5, frames: 10, profile: PROFILE, progress: 0.5, t: 0.5 });
        expect(valueAt(3, frame)).toBe(3);
        expect(valueAt((context) => context.t * 2, frame)).toBe(1);
    });
});

describe("resolveCard", () => {
    it("resolves every expression of every layer at a frame, fractional frames included", () => {
        const card = resolveCard(spec, PROFILE, 2.5);
        const [title, field] = card.layers;
        expect(card.progress).toBe(0.25);
        expect(card.tone).toBe("page-gold");
        expect(title?.content).toBe("frame 2.5");
        expect(title?.opacity).toBe(0.25);
        expect(title?.placement.y).toBe(0.25);
        expect(title?.filter).toBe("blur(2.5px)");
        expect(title?.style).toStrictEqual({ color: "red", fontSize: "12px" });
        expect(field?.uniforms).toStrictEqual([2]);
        expect(field?.content).toBe("fn shade(");
    });

    it("throws on an effect outside the vocabulary", () => {
        const frame = frameContext(spec, PROFILE, 0);
        const [attempt] = ["sparkle"]
            .filter(isForgedEffect)
            .map(
                (kind) => () =>
                    resolveLayer(
                        { effects: [{ amount: 1, kind }], id: "bad", kind: "box", placement: { x: 0, y: 0 } },
                        frame,
                    ),
            );
        expect(attempt).toThrow("sparkle");
    });
});
```
