Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,18 @@ dist/
*.sqlite3
progress.txt
progress*.txt

# Security-sensitive files
.env
.env.local
.env.*.local
*.key
*.pem
*.secret

# Test/Coverage
coverage/
.nyc_output/

# Logs
*.log
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@ antfarm dashboard status # Check status
| `antfarm dashboard` | Start the web dashboard |
| `antfarm logs [<lines>]` | View recent log entries |

### Scripts

| Script | Description |
|--------|-------------|
| `npm run hello` | Run the hello-world demo script (prints current date) |

---

## Requirements
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
},
"scripts": {
"build": "tsc -p tsconfig.json && cp src/server/index.html dist/server/index.html && chmod +x dist/cli/cli.js && node scripts/inject-version.js",
"start": "node dist/cli/cli.js"
"start": "node dist/cli/cli.js",
"hello": "node scripts/hello-world.js"
},
"dependencies": {
"json5": "^2.2.3",
Expand Down
139 changes: 139 additions & 0 deletions scripts/__tests__/hello-world.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { execFileSync, execSync } from "node:child_process";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { readFileSync } from "node:fs";

const __dirname = dirname(fileURLToPath(import.meta.url));
const scriptPath = join(__dirname, "..", "hello-world.js");
const repoRoot = join(__dirname, "..", "..");

describe("hello-world", () => {
it("executes without errors", () => {
assert.doesNotThrow(() => {
execFileSync("node", [scriptPath], { encoding: "utf8" });
}, "Script should execute without throwing errors");
});

it("output contains 'Hello World!'", () => {
const output = execFileSync("node", [scriptPath], { encoding: "utf8" });
assert.ok(
output.includes("Hello World!"),
"Output should contain 'Hello World!'"
);
});

it("output contains a valid date/time string", () => {
const output = execFileSync("node", [scriptPath], { encoding: "utf8" });
assert.ok(
output.includes("Current date:"),
"Output should contain 'Current date:' label"
);

// Verify that output contains something that looks like a date/time
// Should have digits, colons, and hyphens typical of ISO-style datetime
const dateTimePattern = /\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}/;
assert.ok(
dateTimePattern.test(output),
"Output should contain a valid date/time string in format YYYY-MM-DD HH:MM:SS"
);
});

it("output format is consistent (date format verified by regex)", () => {
const output = execFileSync("node", [scriptPath], { encoding: "utf8" });

// Test the exact expected format: "Hello World! Current date: YYYY-MM-DD HH:MM:SS"
const formatPattern = /^Hello World! Current date: \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\n$/;
assert.ok(
formatPattern.test(output),
`Output format should match pattern exactly. Got: "${output}"`
);
});

it("date string represents a valid date", () => {
const output = execFileSync("node", [scriptPath], { encoding: "utf8" });

// Extract the date/time portion
const match = output.match(/(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/);
assert.ok(match, "Should find a date/time string in output");

const dateString = match[1].replace(" ", "T");
const parsedDate = new Date(dateString);

// Verify it's a valid date (not NaN)
assert.ok(
!isNaN(parsedDate.getTime()),
"Extracted date string should be parseable as a valid date"
);
});
});

describe("hello-world npm script integration", () => {
it("package.json includes 'hello' script", () => {
const packageJsonPath = join(repoRoot, "package.json");
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));

assert.ok(
packageJson.scripts && packageJson.scripts.hello,
"package.json should have a 'hello' script defined"
);

assert.equal(
packageJson.scripts.hello,
"node scripts/hello-world.js",
"The 'hello' script should run the hello-world.js script"
);
});

it("npm run hello executes successfully", () => {
assert.doesNotThrow(() => {
execSync("npm run hello", {
cwd: repoRoot,
encoding: "utf8",
stdio: "pipe"
});
}, "npm run hello should execute without errors");
});

it("npm run hello produces correct output", () => {
const output = execSync("npm run hello", {
cwd: repoRoot,
encoding: "utf8",
stdio: "pipe"
});

// Output from npm run includes extra lines, so check for the content
assert.ok(
output.includes("Hello World!"),
"npm run hello output should contain 'Hello World!'"
);

assert.ok(
output.includes("Current date:"),
"npm run hello output should contain 'Current date:'"
);

// Verify date/time format is present
const dateTimePattern = /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/;
assert.ok(
dateTimePattern.test(output),
"npm run hello output should contain a valid date/time string"
);
});

it("README.md documents the hello script", () => {
const readmePath = join(repoRoot, "README.md");
const readmeContent = readFileSync(readmePath, "utf8");

assert.ok(
readmeContent.includes("npm run hello") || readmeContent.includes("`npm run hello`"),
"README.md should document the 'npm run hello' command"
);

assert.ok(
readmeContent.toLowerCase().includes("hello"),
"README.md should mention the hello script"
);
});
});
10 changes: 10 additions & 0 deletions scripts/hello-world.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env node
/**
* Hello World script that prints the current date and time.
* Simple utility script for demonstration purposes.
*/

const now = new Date();
const formattedDate = now.toISOString().replace('T', ' ').substring(0, 19);

console.log(`Hello World! Current date: ${formattedDate}`);
39 changes: 39 additions & 0 deletions tests/hello-world.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Tests for the hello-world.js script.
* Verifies that the script outputs "Hello World!" with current date and time.
*/
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import path from "node:path";

const SCRIPT = path.resolve(import.meta.dirname, "..", "scripts", "hello-world.js");

describe("hello-world.js script", () => {
it("prints 'Hello World!' followed by current date", () => {
const output = execFileSync("node", [SCRIPT], { encoding: "utf-8" });
assert.ok(output.includes("Hello World!"), "should include 'Hello World!'");
assert.ok(output.includes("Current date:"), "should include 'Current date:'");
});

it("output includes date in YYYY-MM-DD format", () => {
const output = execFileSync("node", [SCRIPT], { encoding: "utf-8" });
// Match YYYY-MM-DD pattern
const datePattern = /\d{4}-\d{2}-\d{2}/;
assert.ok(datePattern.test(output), `output should contain date in YYYY-MM-DD format, got: "${output}"`);
});

it("output includes time in HH:MM:SS format", () => {
const output = execFileSync("node", [SCRIPT], { encoding: "utf-8" });
// Match HH:MM:SS pattern
const timePattern = /\d{2}:\d{2}:\d{2}/;
assert.ok(timePattern.test(output), `output should contain time in HH:MM:SS format, got: "${output}"`);
});

it("script is executable", async () => {
const { statSync } = await import("node:fs");
const stats = statSync(SCRIPT);
const isExecutable = !!(stats.mode & 0o111);
assert.ok(isExecutable, "script should have executable permissions");
});
});