108 lines
3.2 KiB
TypeScript
108 lines
3.2 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { App } from "../core/app.ts";
|
|
import { Controller, Module, Root, ViewRoot } from "../decorators/index.ts";
|
|
import { View } from "../decorators/View.ts";
|
|
import { TemplateEngine } from "../views/engine/runtime.ts";
|
|
import { Views } from "../views/api.ts";
|
|
|
|
/**
|
|
* Tests of the file based router: the relative views, the static roots of the
|
|
* controllers and the renderers that are applied inline.
|
|
*/
|
|
|
|
const dir = await mkdtemp(join(tmpdir(), "muddle-router-"));
|
|
|
|
await mkdir(join(dir, "views"), { recursive: true });
|
|
await mkdir(join(dir, "public"), { recursive: true });
|
|
|
|
await writeFile(
|
|
join(dir, "views/index.spug"),
|
|
"props\n title: string\n\nh1= title",
|
|
"utf8",
|
|
);
|
|
await writeFile(join(dir, "views/about.spug"), "h2 About", "utf8");
|
|
await writeFile(
|
|
join(dir, "views/card.spug"),
|
|
"props\n title: string\n content?: () => string | Promise<string>\n\narticle.card\n h3= title\n if content\n .card__content!= content()",
|
|
"utf8",
|
|
);
|
|
await writeFile(join(dir, "public/robots.txt"), "Allow: /", "utf8");
|
|
|
|
describe("file based router", () => {
|
|
test("resolves the views of the view root", async () => {
|
|
const engine = new TemplateEngine({
|
|
viewsDir: join(dir, "views"),
|
|
root: dir,
|
|
});
|
|
const html = await engine.render("index.spug", { title: "Hello" });
|
|
expect(html).toBe("<h1>Hello</h1>");
|
|
});
|
|
|
|
test("derives the route from the view", async () => {
|
|
const html = await engine("about.spug");
|
|
expect(html).toBe("<h2>About</h2>");
|
|
|
|
async function engine(path: string): Promise<string> {
|
|
return new TemplateEngine({
|
|
viewsDir: join(dir, "views"),
|
|
root: dir,
|
|
}).render(path);
|
|
}
|
|
});
|
|
|
|
test("renders a renderer that is applied inline", async () => {
|
|
const engine = new TemplateEngine({
|
|
viewsDir: join(dir, "views"),
|
|
root: dir,
|
|
});
|
|
const html = await engine.render("card.spug", {
|
|
title: "Card",
|
|
content: async () => "<p>inline</p>",
|
|
});
|
|
expect(html).toContain("<h3>Card</h3>");
|
|
expect(html).toContain('<div class="card__content"><p>inline</p></div>');
|
|
});
|
|
|
|
test("serves the static root of a controller", async () => {
|
|
@Controller("/assets")
|
|
@Root(join(dir, "public"))
|
|
class AssetController {}
|
|
|
|
@Controller("/")
|
|
@ViewRoot(join(dir, "views"))
|
|
class PageController {
|
|
@View("index.spug")
|
|
index() {
|
|
return { title: "Hello" };
|
|
}
|
|
}
|
|
|
|
@Module({ controllers: [AssetController, PageController] })
|
|
class AppModule {}
|
|
|
|
const app = await App.create({
|
|
modules: [AppModule],
|
|
views: new Views({ viewsDir: join(dir, "views"), root: dir }),
|
|
});
|
|
|
|
const page = await app.fetch(new Request("http://localhost/"));
|
|
expect(page.status).toBe(200);
|
|
expect(await page.text()).toBe("<h1>Hello</h1>");
|
|
|
|
const asset = await app.fetch(
|
|
new Request("http://localhost/assets/robots.txt"),
|
|
);
|
|
expect(asset.status).toBe(200);
|
|
expect(await asset.text()).toBe("Allow: /");
|
|
|
|
const missing = await app.fetch(
|
|
new Request("http://localhost/assets/nope.txt"),
|
|
);
|
|
expect(missing.status).toBe(404);
|
|
|
|
await rm(dir, { recursive: true, force: true });
|
|
});
|
|
});
|