const { test } = require("node:test"); const assert = require("node:assert"); const crypto = require("node:crypto"); const { encrypt } = require("../src/lib/tokenCrypto"); const { getValidAccessToken } = require("../src/lib/tokenService"); const KEY_HEX = crypto.randomBytes(32).toString("hex"); const PLEASANTER = { baseUrl: "https://example.test/", apiKey: "k", siteId: 1, encryptionKey: KEY_HEX }; const OAUTH = { clientId: "cid", clientSecret: "secret" }; function itemResponse({ expiresAt, accessToken = "access-current", refreshToken = "refresh-current" }) { return { ok: true, json: async () => ({ StatusCode: 200, Response: { Data: [{ ResultId: 5, ClassHash: { ClassA: "lineworks-form-sync", Class001: "svc@example.co.jp", Class002: "form form.read" }, DescriptionHash: { Description001: encrypt(accessToken, KEY_HEX), Description002: encrypt(refreshToken, KEY_HEX) }, DateHash: { Date001: expiresAt }, }], TotalCount: 1, }, }), }; } test("returns the stored access token as-is when it is still valid (no refresh call made)", async () => { const now = () => new Date("2026-08-24T00:30:00.000Z"); let refreshCalled = false; const fetchImpl = async (url) => { if (url.endsWith("/get")) return itemResponse({ expiresAt: "2026-08-24T01:00:00.000Z" }); if (url.includes("auth.worksmobile.com")) { refreshCalled = true; } if (url.endsWith("/update")) return { ok: true, json: async () => ({ Id: 5, StatusCode: 200 }) }; throw new Error(`unexpected url ${url}`); }; const token = await getValidAccessToken({ key: "lineworks-form-sync", pleasanter: PLEASANTER, oauth: OAUTH, fetchImpl, now }); assert.strictEqual(token, "access-current"); assert.strictEqual(refreshCalled, false); }); test("refreshes and persists a new token when the stored one has expired", async () => { const now = () => new Date("2026-08-24T02:00:00.000Z"); let updateBody; const fetchImpl = async (url, opts) => { if (url.endsWith("/get")) return itemResponse({ expiresAt: "2026-08-24T01:00:00.000Z" }); if (url.includes("auth.worksmobile.com")) { return { ok: true, json: async () => ({ access_token: "access-new", refresh_token: "refresh-new", expires_in: 3600 }) }; } if (url.endsWith("/update")) { updateBody = JSON.parse(opts.body); return { ok: true, json: async () => ({ Id: 5, StatusCode: 200 }) }; } throw new Error(`unexpected url ${url}`); }; const token = await getValidAccessToken({ key: "lineworks-form-sync", pleasanter: PLEASANTER, oauth: OAUTH, fetchImpl, now }); assert.strictEqual(token, "access-new"); assert.strictEqual(updateBody.DateHash.Date001, "2026-08-24T03:00:00.000Z"); }); test("throws a descriptive error when the key is not registered", async () => { const fetchImpl = async (url) => { if (url.endsWith("/get")) return { ok: true, json: async () => ({ StatusCode: 200, Response: { Data: [], TotalCount: 0 } }) }; throw new Error(`unexpected url ${url}`); }; await assert.rejects( () => getValidAccessToken({ key: "unknown-key", pleasanter: PLEASANTER, oauth: OAUTH, fetchImpl, now: () => new Date() }), /unknown-key/ ); });