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,
);
});