Files
screeps-deploy-action/__tests__/index.test.js
Philipp Horstenkamp 2be5b2a1bc
All checks were successful
Lint / pre-commit Linting (push) Successful in 36s
Test / Run Tests (push) Successful in 56s
chore: update @actions/core to v3 and migrate to ESM (#73)
This PR updates the `@actions/core` dependency from v2 to v3.0.0.

### Major Changes:
- **Dependency Update**: Updated `@actions/core` to `v3.0.0` in `package.json`.
- **ESM Migration**: Converted the entire project to ECMAScript Modules (ESM). This was necessary because `@actions/core` v3 is an ESM-only package and does not provide CommonJS exports.
- **`package.json` updates**: Added `"type": "module"` and updated the dependency version.
- **Code Refactor**:
    -   Converted `index.js` to use `import` and `export`.
    -   Updated the main execution check to use `import.meta.url` for ESM compatibility.
    -   Converted `__tests__/index.test.js` to use ESM imports for compatibility with the updated source code.
- **Production Build**: Re-generated the `dist/index.js` bundle using `ncc` to reflect the changes.
- **Node.js Version**: The project continues to use Node 20 (`node20` in `action.yaml`), which is fully compatible with these changes.

### Why these changes are needed:
- `@actions/core` v3 brings latest improvements and fixes from the GitHub Actions toolkit.
- Migrating to ESM is the modern standard for Node.js development and is required to consume ESM-only packages like the new `@actions/core` v3.

Verified with `npm test` and `npm run build`.

Reviewed-on: #73
2026-02-23 03:59:12 +01:00

200 lines
6.5 KiB
JavaScript

import {
validateAuthentication,
replacePlaceholders,
readReplaceAndWriteFiles,
readFilesIntoDict,
} from "../index.js";
import fs from "fs";
import path from "path";
import os from "os";
import { glob } from "glob";
describe("validateAuthentication", () => {
it("should return null when only token is provided", () => {
expect(validateAuthentication("token", null, null)).toBeNull();
});
it("should return an error message when token and username are provided", () => {
expect(validateAuthentication("token", "user", null)).toBe(
"Token is defined along with username and/or password.",
);
});
it("should return an error message when token and password are provided", () => {
expect(validateAuthentication("token", null, "pass")).toBe(
"Token is defined along with username and/or password.",
);
});
it("should return an error message when token, username, and password are provided", () => {
expect(validateAuthentication("token", "user", "pass")).toBe(
"Token is defined along with username and/or password.",
);
});
it("should return an error message when no credentials are provided", () => {
expect(validateAuthentication(null, null, null)).toBe(
"Neither token nor password and username are defined.",
);
});
it("should return an error message when only username is provided", () => {
expect(validateAuthentication(null, "user", null)).toBe(
"Username is defined but no password is provided.",
);
});
it("should return an error message when only password is provided", () => {
expect(validateAuthentication(null, null, "pass")).toBe(
"Password is defined but no username is provided.",
);
});
it("should return null when username and password are provided", () => {
expect(validateAuthentication(null, "user", "pass")).toBeNull();
});
});
describe("replacePlaceholders", () => {
beforeEach(() => {
process.env.GITHUB_SHA = "test-sha";
process.env.GITHUB_REF = "test-ref";
});
it("should replace all placeholders", () => {
const content =
"hash: {{gitHash}}, ref: {{gitRef}}, time: {{deployTime}}, host: {{hostname}}";
const replacedContent = replacePlaceholders(content, "test-host");
expect(replacedContent).toMatch(/hash: test-sha/);
expect(replacedContent).toMatch(/ref: test-ref/);
expect(replacedContent).toMatch(/time: .*/);
expect(replacedContent).toMatch(/host: test-host/);
});
});
describe("readReplaceAndWriteFiles", () => {
let tempDir;
beforeEach(async () => {
tempDir = await fs.promises.mkdtemp(
path.join(os.tmpdir(), "replace-test-"),
);
process.env.GITHUB_SHA = "test-sha";
process.env.GITHUB_REF = "test-ref";
});
afterEach(async () => {
if (tempDir) {
await fs.promises.rm(tempDir, { recursive: true, force: true });
}
});
it("should find files and replace placeholders", async () => {
const fileName = "test.js";
const filePath = path.join(tempDir, fileName);
const content = "hash: {{gitHash}}, ref: {{gitRef}}, host: {{hostname}}";
await fs.promises.writeFile(filePath, content);
const pattern = "*.js";
// We pass tempDir as the prefix so glob searches inside it
await readReplaceAndWriteFiles(pattern, tempDir, "test-host");
const updatedContent = await fs.promises.readFile(filePath, "utf8");
expect(updatedContent).toContain("hash: test-sha");
expect(updatedContent).toContain("ref: test-ref");
expect(updatedContent).toContain("host: test-host");
});
});
describe("readFilesIntoDict", () => {
let tempDir;
beforeEach(async () => {
tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "read-test-"));
await fs.promises.mkdir(path.join(tempDir, "subdir"), { recursive: true });
});
afterEach(async () => {
if (tempDir) {
await fs.promises.rm(tempDir, { recursive: true, force: true });
}
});
it("should read files into a dictionary with correct keys", async () => {
const file1 = "file1.js";
const content1 = "content1";
await fs.promises.writeFile(path.join(tempDir, file1), content1);
const file2 = "subdir/file2.js";
const content2 = "content2";
await fs.promises.writeFile(path.join(tempDir, file2), content2);
const pattern = "**/*.js";
const result = await readFilesIntoDict(pattern, tempDir);
// Keys should be relative paths without extension
// On Windows, the path separator might differ, so we should be careful or just check contents
// Based on implementation:
// key = key.slice(prefix.length);
// key = path.basename(key, path.extname(key)); // Drop the file suffix -> THIS IS BUGGY for subdirs?
// Let's check the implementation of readFilesIntoDict again in index.js
// It does: key = path.basename(key, path.extname(key));
// This removes the directory part! So subdir/file2.js becomes file2
expect(result["file1"]).toBe(content1);
expect(result["file2"]).toBe(content2);
});
});
describe("glob functionality", () => {
let tempDir;
beforeEach(async () => {
tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "glob-test-"));
await fs.promises.mkdir(path.join(tempDir, "lib"), { recursive: true });
await fs.promises.mkdir(path.join(tempDir, "deep", "folder"), {
recursive: true,
});
await fs.promises.writeFile(path.join(tempDir, "main.js"), "content");
await fs.promises.writeFile(path.join(tempDir, "utils.js"), "content");
await fs.promises.writeFile(
path.join(tempDir, "lib", "helper.js"),
"content",
);
await fs.promises.writeFile(
path.join(tempDir, "lib", "data.json"),
"content",
);
await fs.promises.writeFile(
path.join(tempDir, "deep", "folder", "main.js"),
"content",
);
});
afterEach(async () => {
if (tempDir) {
await fs.promises.rm(tempDir, { recursive: true, force: true });
}
});
it("should find all javascript files in the directory", async () => {
// Ensure pattern uses forward slashes for glob
const pattern = path.join(tempDir, "**", "*.js").split(path.sep).join("/");
const files = await glob(pattern);
// Normalize file paths to system separator (backslashes on Windows)
const normalizedFiles = files.map((f) => path.normalize(f));
const expectedFiles = [
path.join(tempDir, "deep", "folder", "main.js"),
path.join(tempDir, "lib", "helper.js"),
path.join(tempDir, "main.js"),
path.join(tempDir, "utils.js"),
].sort();
expect(normalizedFiles.sort()).toEqual(expectedFiles);
});
});