import assert from 'node:assert/strict'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import test from 'node:test'; import { PUBLIC_ZONE_DIR, PUBLISH_ROOT_DIR } from './user-publish.mjs'; import { startWechatNewsMorningDraftWorker } from './wechat-news-morning-draft-worker.mjs'; import { createWechatNewsMorningDraftService, wechatNewsMorningDraftInternals, } from './wechat-news-morning-draft.mjs'; const SAMPLE_HTML = `

📰 每日新闻早报

`; function createPool() { const rows = []; return { rows, async query(sql, params = []) { if (sql.includes('CREATE TABLE')) return [[], []]; if (sql.includes('FROM h5_wechat_admin_config')) return [[], []]; if (sql.includes('INSERT INTO h5_wechat_news_draft_runs')) { rows.push({ id: params[0], status: params[1], pageSlug: params[2], pageUrl: params[3], draftMediaId: params[4], errorMessage: params[5], triggeredBy: params[6], createdAt: Number(params[7]), }); return [[], []]; } if (sql.includes('FROM h5_wechat_news_draft_runs')) { return [rows.slice().reverse(), []]; } return [[], []]; }, }; } test('news morning draft worker auto-pushes at configured time', async () => { const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'news-draft-worker-')); const userId = 'user-news'; const publicDir = path.join(tmpRoot, PUBLISH_ROOT_DIR, userId, PUBLIC_ZONE_DIR); fs.mkdirSync(publicDir, { recursive: true }); fs.writeFileSync(path.join(publicDir, 'daily-news-0911.html'), SAMPLE_HTML); const pool = createPool(); const service = createWechatNewsMorningDraftService(pool, { mpConfig: { enabled: true, appId: 'app', appSecret: 'secret' }, h5Root: tmpRoot, env: { H5_WECHAT_NEWS_MORNING_DRAFT_ENABLED: '1', H5_WECHAT_NEWS_MORNING_DRAFT_AUTO: '1', H5_WECHAT_NEWS_MORNING_DRAFT_USER_ID: userId, H5_WECHAT_NEWS_MORNING_DRAFT_HOUR: '6', H5_WECHAT_NEWS_MORNING_DRAFT_MINUTE: '0', }, }); const pushCalls = []; service.pushDraft = async (options = {}) => { pushCalls.push(options); return { ok: true, draftMediaId: 'draft-1', preview: { page: { slug: 'daily-news-0911' } }, }; }; service.hasSuccessfulAutoPushToday = async () => false; const fixedNow = Date.UTC(2026, 8, 10, 22, 0, 0); const originalNow = Date.now; Date.now = () => fixedNow; try { const worker = startWechatNewsMorningDraftWorker({ wechatNewsMorningDraftService: service, mpConfig: { enabled: true }, userAuth: { canUseChat: async () => ({ ok: true }) }, tkmindProxy: { id: 'proxy' }, h5Root: tmpRoot, env: { H5_WECHAT_NEWS_MORNING_DRAFT_WORKER_ENABLED: '1', }, intervalMs: 30_000, runOnStart: false, setIntervalFn: () => ({ unref() {} }), }); await worker.runOnce(); assert.equal(pushCalls.length, 1); assert.deepEqual(pushCalls[0], { triggeredBy: 'auto-push' }); } finally { Date.now = originalNow; fs.rmSync(tmpRoot, { recursive: true, force: true }); } }); test('schedule helpers detect today page and due windows', () => { const { isNewsMorningPageForToday, isLocalScheduleDue, isWithinNewsMorningGenerateLeadWindow, formatLocalDateParts, } = wechatNewsMorningDraftInternals; const now = Date.UTC(2026, 8, 10, 22, 0, 0); const parts = formatLocalDateParts(new Date(now), 'Asia/Shanghai'); assert.equal(parts.mmdd, '0911'); assert.equal( isNewsMorningPageForToday( { slug: 'daily-news-0911' }, { date: new Date(now), timezone: 'Asia/Shanghai' }, ), true, ); assert.equal( isLocalScheduleDue( { hour: 6, minute: 0, timezone: 'Asia/Shanghai' }, now, 1, ), true, ); assert.equal( isWithinNewsMorningGenerateLeadWindow( { pushHour: 6, pushMinute: 0, generateLeadMinutes: 60, timezone: 'Asia/Shanghai', }, Date.UTC(2026, 8, 10, 21, 15, 0), ), true, ); });