Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

pi/agent/skills/optional/quickshell/bin/test/qs-scaffold.test.mjs

Raw
// qs-scaffold.test.mjs
// Run: node --test bin/test/qs-scaffold.test.mjs

import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import {
	existsSync,
	mkdirSync,
	mkdtempSync,
	readdirSync,
	readFileSync,
	rmSync,
	writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import { test } from "node:test";
import { fileURLToPath } from "node:url";

const __dirname = dirname(fileURLToPath(import.meta.url));
const BIN = join(__dirname, "..", "qs-scaffold.mjs");

function makeTmp() {
	const dir = mkdtempSync(join(tmpdir(), "qs-scaffold-test-"));
	return dir;
}

test("qs-scaffold creates a config dir with shell.qml from default example", () => {
	const tmp = makeTmp();
	try {
		const result = spawnSync("node", [BIN, "mybar"], {
			encoding: "utf8",
			env: { ...process.env, XDG_CONFIG_HOME: tmp },
		});
		assert.equal(result.status, 0, `stderr: ${result.stderr}`);
		const target = join(tmp, "quickshell", "mybar");
		assert.ok(existsSync(target), `target dir not created: ${target}`);
		assert.ok(existsSync(join(target, "shell.qml")), "shell.qml missing");
		// The default example is 02-per-monitor-bar (canonical per-monitor shape).
		const content = readFileSync(join(target, "shell.qml"), "utf8");
		assert.match(content, /Variants/);
		assert.match(content, /Quickshell\.screens/);
	} finally {
		rmSync(tmp, { recursive: true, force: true });
	}
});

test("qs-scaffold with --from 01 uses 01-hello-bar", () => {
	const tmp = makeTmp();
	try {
		const result = spawnSync("node", [BIN, "mybar", "--from", "01-hello-bar"], {
			encoding: "utf8",
			env: { ...process.env, XDG_CONFIG_HOME: tmp },
		});
		assert.equal(result.status, 0, `stderr: ${result.stderr}`);
		const shell = readFileSync(
			join(tmp, "quickshell", "mybar", "shell.qml"),
			"utf8",
		);
		assert.match(shell, /hello quickshell/i);
	} finally {
		rmSync(tmp, { recursive: true, force: true });
	}
});

test("qs-scaffold with --from 07-composite-bar copies Bar.qml too", () => {
	const tmp = makeTmp();
	try {
		const result = spawnSync(
			"node",
			[BIN, "mybar", "--from", "07-composite-bar"],
			{
				encoding: "utf8",
				env: { ...process.env, XDG_CONFIG_HOME: tmp },
			},
		);
		assert.equal(result.status, 0, `stderr: ${result.stderr}`);
		const target = join(tmp, "quickshell", "mybar");
		const files = readdirSync(target);
		assert.ok(files.includes("shell.qml"), "shell.qml missing");
		assert.ok(
			files.includes("Bar.qml"),
			"Bar.qml missing (multi-file example not fully copied)",
		);
	} finally {
		rmSync(tmp, { recursive: true, force: true });
	}
});

test("qs-scaffold touches .qmlls.ini for LSP", () => {
	const tmp = makeTmp();
	try {
		const result = spawnSync("node", [BIN, "mybar"], {
			encoding: "utf8",
			env: { ...process.env, XDG_CONFIG_HOME: tmp },
		});
		assert.equal(result.status, 0, `stderr: ${result.stderr}`);
		assert.ok(
			existsSync(join(tmp, "quickshell", "mybar", ".qmlls.ini")),
			".qmlls.ini missing",
		);
	} finally {
		rmSync(tmp, { recursive: true, force: true });
	}
});

test("qs-scaffold without args exits non-zero with usage", () => {
	const result = spawnSync("node", [BIN], { encoding: "utf8" });
	assert.notEqual(result.status, 0);
	assert.match(result.stderr, /usage/i);
});

test("qs-scaffold with bad --from exits non-zero", () => {
	const tmp = makeTmp();
	try {
		const result = spawnSync(
			"node",
			[BIN, "mybar", "--from", "99-does-not-exist"],
			{
				encoding: "utf8",
				env: { ...process.env, XDG_CONFIG_HOME: tmp },
			},
		);
		assert.notEqual(result.status, 0);
		assert.match(result.stderr, /not found|does not exist/i);
	} finally {
		rmSync(tmp, { recursive: true, force: true });
	}
});

test("qs-scaffold rejects a config name that escapes the config root", () => {
	const tmp = makeTmp();
	try {
		const result = spawnSync("node", [BIN, "../escaped"], {
			encoding: "utf8",
			env: { ...process.env, XDG_CONFIG_HOME: tmp },
		});
		assert.notEqual(result.status, 0);
		assert.match(result.stderr, /single path segment/i);
		assert.equal(existsSync(join(tmp, "escaped")), false);
	} finally {
		rmSync(tmp, { recursive: true, force: true });
	}
});

test("qs-scaffold rejects an example name containing path traversal", () => {
	const tmp = makeTmp();
	try {
		const result = spawnSync(
			"node",
			[BIN, "mybar", "--from", "../01-hello-bar"],
			{
				encoding: "utf8",
				env: { ...process.env, XDG_CONFIG_HOME: tmp },
			},
		);
		assert.notEqual(result.status, 0);
		assert.match(result.stderr, /single path segment/i);
		assert.equal(existsSync(join(tmp, "quickshell", "mybar")), false);
	} finally {
		rmSync(tmp, { recursive: true, force: true });
	}
});

test("qs-scaffold with existing target dir exits non-zero (no clobber)", () => {
	const tmp = makeTmp();
	try {
		const target = join(tmp, "quickshell", "mybar");
		mkdirSync(target, { recursive: true });
		writeFileSync(join(target, "preexisting.txt"), "do not clobber");
		const result = spawnSync("node", [BIN, "mybar"], {
			encoding: "utf8",
			env: { ...process.env, XDG_CONFIG_HOME: tmp },
		});
		assert.notEqual(result.status, 0);
		// Preexisting file must still exist with original content.
		const still = readFileSync(join(target, "preexisting.txt"), "utf8");
		assert.equal(still, "do not clobber");
	} finally {
		rmSync(tmp, { recursive: true, force: true });
	}
});