Adds twelve image posts made the same way as the films: six posters (one picture of each film with its idea in two lines) and six cards that answer a question clients ask before the first call. The answers come from the questions and principles on the website. The posting plan is data (six weeks, film, card and poster per week), and the export writes the library in that order, by language, week and day, with the text to post. All video posts now open with the hook of their film. The reasoning is in plans/content-strategy.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
71 lines
2.7 KiB
TypeScript
71 lines
2.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { IMAGES, IMAGE_IDS } from "./images";
|
|
import { PLAN } from "./plan";
|
|
import { COPY, LANGS, VIDEO_IDS } from "./videos";
|
|
|
|
/** Longer lines get too small to read on a phone. */
|
|
const MAX_IMAGE_LINE = 28;
|
|
const MAX_IMAGE_LINES = 3;
|
|
|
|
describe("image posts", () => {
|
|
it.each(IMAGE_IDS)("%s has at most three short lines in every language", (id) => {
|
|
for (const lang of LANGS) {
|
|
const { lines } = IMAGES[id].copy[lang];
|
|
expect(lines.length, `${id} ${lang}`).toBeGreaterThan(0);
|
|
expect(lines.length, `${id} ${lang}`).toBeLessThanOrEqual(MAX_IMAGE_LINES);
|
|
for (const line of lines) expect(line.length, `${id} ${lang}: "${line}"`).toBeLessThanOrEqual(MAX_IMAGE_LINE);
|
|
}
|
|
});
|
|
|
|
it.each(IMAGE_IDS)("%s has a post that names the website and never an email address", (id) => {
|
|
for (const lang of LANGS) {
|
|
const { post } = IMAGES[id].copy[lang];
|
|
expect(post).toContain("www.mintel.me");
|
|
expect(post).not.toContain("@");
|
|
}
|
|
});
|
|
|
|
it.each(IMAGE_IDS)("%s is a poster of an existing film, or a card with a question", (id) => {
|
|
const image = IMAGES[id];
|
|
if (image.poster) {
|
|
expect(VIDEO_IDS).toContain(image.poster.video);
|
|
expect(image.poster.frame).toBeGreaterThanOrEqual(0);
|
|
} else {
|
|
for (const lang of LANGS) expect(image.copy[lang].label, `${id} ${lang}`).toBeTruthy();
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("video posts", () => {
|
|
it.each(VIDEO_IDS)("%s opens its post with the hook of the film", (id) => {
|
|
for (const lang of LANGS) {
|
|
const { post, slides } = COPY[id][lang];
|
|
const lastHookWord = (slides.hook ?? []).join(" ").split(" ").pop()?.replace(/[.?!]/g, "") ?? "";
|
|
expect(post.split("\n")[0], `${id} ${lang}`).toContain(lastHookWord);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("posting plan", () => {
|
|
const planned = PLAN.flatMap((week) => week.posts);
|
|
|
|
it("uses every film and every image exactly once", () => {
|
|
const videos = planned.filter((post) => post.kind === "video").map((post) => post.id);
|
|
const images = planned.filter((post) => post.kind === "image").map((post) => post.id);
|
|
expect([...videos].sort()).toEqual([...VIDEO_IDS].sort());
|
|
expect([...images].sort()).toEqual([...IMAGE_IDS].sort());
|
|
});
|
|
|
|
it("opens every week with its film", () => {
|
|
for (const week of PLAN) expect(week.posts[0].kind, week.topic).toBe("video");
|
|
});
|
|
|
|
it("pairs the film of a week with the poster of the same film", () => {
|
|
for (const week of PLAN) {
|
|
const film = week.posts[0].id;
|
|
const posters = week.posts.filter((post) => post.kind === "image" && IMAGES[post.id].poster?.video === film);
|
|
expect(posters, week.topic).toHaveLength(1);
|
|
}
|
|
});
|
|
});
|