Page MenuHomeSealhub

test.ts
No OneTemporary

import Koa from "koa";
import http, { IncomingMessage } from "http";
import assert from "assert";
import { promisify } from "util";
import { Templatable, tempstream } from ".";
import { Slot } from "./slot";
import streamToString from "./tostring";
import sinon from "sinon";
const st = (time: number, cb: () => void) => setTimeout(cb, time);
const sleep = promisify(st);
// template`hello ${world}, and ${name}`.pipe(process.stdout);
describe("tempstream", () => {
it("renders properly in the basic case", async () => {
const list_items = Promise.resolve(
["one", "two", "three"].map((e) => `<li>${e}</li>`)
);
const title = new Slot("Default page title");
setTimeout(() => title.set("Changed page title"), 20);
const slept = sleep(100).then(() => "slept");
const result = await streamToString(tempstream`<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>${title}</title>
</head>
<body>
hello World, I ${slept}.
<ul>
${list_items}
</ul>
</body> `);
assert.strictEqual(
result,
`<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>Changed page title</title>
</head>
<body>
hello World, I slept.
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
</body> `
);
});
it("doesn't add unecessary 'null' when encountering an unresolved slot", async () => {
const title = new Slot("unchanged");
const result = await streamToString(
tempstream`<title>${title}</title>`
);
assert.strictEqual(result, `<title>unchanged</title>`);
});
it("handles stream within a stream", async () => {
const item_elements = Promise.resolve(["one", "two", "three"]);
const inside_stream = tempstream`Here's a list: ${item_elements}`;
const outside_stream = tempstream`<div>${inside_stream}</div>`;
const result = await streamToString(outside_stream);
assert.strictEqual(
result,
`<div>Here's a list: one
two
three</div>`
);
});
it("warns about unset slots", async () => {
const console_warn = sinon.spy(console, "warn");
const title = new Slot("unchanged");
const result = await streamToString(
tempstream`<title>${title}</title>`
);
assert.strictEqual(result, `<title>unchanged</title>`);
assert.strictEqual(console_warn.callCount, 1);
console_warn.restore();
});
it("handles an array of promises", async () => {
async function process(text: string) {
return "processed " + text;
}
const result = await streamToString(
tempstream`${["a", "b", "c"].map(process)}`
);
assert.strictEqual(
result,
`processed a
processed b
processed c`
);
});
it("handles an array of promises of streams", async () => {
async function process(text: string) {
return tempstream`processed ${text}`;
}
const result = await streamToString(
tempstream`${["a", "b", "c"].map(process)}`
);
assert.strictEqual(
result,
`processed a
processed b
processed c`
);
});
it("handles an array of promises of streams nested within a stream", async () => {
async function process(text: string) {
return tempstream`processed ${text}`;
}
const result = await streamToString(
tempstream`PREFIX: ${tempstream`${["a", "b", "c"].map(process)}`}`
);
assert.strictEqual(
result,
`PREFIX: processed a
processed b
processed c`
);
});
it("handles an array of delayed promises of streams nested within a stream", async () => {
async function process(text: string) {
await sleep(100);
return tempstream`processed ${text}`;
}
const result = await streamToString(
tempstream`PREFIX: ${tempstream`${["a", "b", "c"].map(process)}`}`
);
assert.strictEqual(
result,
`PREFIX: processed a
processed b
processed c`
);
});
it("sends the first byte as soon as possible when dealing with delayed promises of streams nested within a stream", async () => {
async function process(text: string) {
await sleep(100);
return tempstream`processed ${text}`;
}
const stream_start_ts = Date.now();
const stream = tempstream`PREFIX: ${tempstream`${["a", "b", "c"].map(
process
)}`}`;
let result = "";
let ttfb: number | null = null;
await new Promise((resolve) => {
stream.on("data", (newdata) => {
result += newdata.toString();
if (ttfb === null) {
ttfb = Date.now() - stream_start_ts;
}
});
stream.on("end", () => resolve(result));
});
assert(ttfb !== null && ttfb < 10);
assert.strictEqual(
result,
`PREFIX: processed a
processed b
processed c`
);
});
it("orders pieces correctly a slot preceeds nested tempstream", async () => {
const slot1 = new Slot("Slot1");
const result = await streamToString(
tempstream`PREFIX: ${slot1} ${tempstream`a`}----`
);
assert.strictEqual(result, `PREFIX: Slot1 a----`);
});
it("properly renders `(Templatable | Promise<Templatable>)[]`", async () => {
const items = [
tempstream`hello`,
tempstream`world`,
Promise.resolve(tempstream`I am`) as Promise<Templatable>,
"testing",
];
const result = await streamToString(tempstream`${items}`);
assert.strictEqual(
result,
`hello
world
I am
testing`
);
});
it("properly renders `Promise<(Templatable | Promise<Templatable>)[]>`", async () => {
const items = Promise.resolve([
tempstream`hello`,
tempstream`world`,
Promise.resolve(tempstream`I am`) as Promise<Templatable>,
"testing",
]);
const result = await streamToString(tempstream`${items}`);
assert.strictEqual(
result,
`hello
world
I am
testing`
);
});
it("properly closes the stream to prevent premature ending when sending over HTTP", async () => {
const app = new Koa();
async function generateOptions() {
const ret = {} as Record<string, unknown>;
for (let i = 0; i <= 4000; i++) {
ret[i.toString()] = i;
}
return ret;
}
app.use(async (ctx) => {
ctx.body = tempstream/* HTML */ `<select>
${Promise.resolve(generateOptions()).then((options) =>
Object.entries(options).map(
([value, text]) => `<option value="${value}"></option>`
)
)}
</select>`;
});
const port = 3787;
const server = app.listen(port);
await sleep(100);
const response = (await new Promise((resolve) => {
http.get(`http://127.0.0.1:${port}`, {}, (res) => {
resolve(streamToString(res));
// res.on("end", resolve);
});
})) as string;
server.close();
assert(
response.endsWith("</select>"),
"Response should be transmitted in full, and not cut before it ends"
);
});
});

File Metadata

Mime Type
text/html
Expires
Sun, Nov 2, 19:57 (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1030498
Default Alt Text
test.ts (6 KB)

Event Timeline