194 lines
5.9 KiB
JavaScript
194 lines
5.9 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
|
|
const source = fs.readFileSync('sidepanel/contribution-content-update-service.js', 'utf8');
|
|
|
|
function createContributionContentService(options = {}) {
|
|
const cache = new Map();
|
|
const windowObject = {};
|
|
let fetchCalls = 0;
|
|
const fetchUrls = [];
|
|
|
|
const localStorage = {
|
|
getItem(key) {
|
|
return cache.has(key) ? cache.get(key) : null;
|
|
},
|
|
setItem(key, value) {
|
|
cache.set(key, String(value));
|
|
},
|
|
removeItem(key) {
|
|
cache.delete(key);
|
|
},
|
|
};
|
|
|
|
if (options.cachedSnapshot) {
|
|
cache.set(
|
|
options.cacheKey || 'multipage-contribution-content-summary-v2:openai:cpa',
|
|
JSON.stringify(options.cachedSnapshot)
|
|
);
|
|
}
|
|
|
|
const fetchImpl = options.fetchImpl || (async () => ({
|
|
ok: true,
|
|
async json() {
|
|
return {
|
|
ok: true,
|
|
items: [],
|
|
prompt_version: '',
|
|
has_visible_updates: false,
|
|
latest_updated_at: '',
|
|
latest_updated_at_display: '',
|
|
};
|
|
},
|
|
}));
|
|
|
|
const wrappedFetch = async (...args) => {
|
|
fetchCalls += 1;
|
|
fetchUrls.push(String(args[0] || ''));
|
|
return fetchImpl(...args);
|
|
};
|
|
|
|
const api = new Function(
|
|
'window',
|
|
'localStorage',
|
|
'fetch',
|
|
'AbortController',
|
|
'setTimeout',
|
|
'clearTimeout',
|
|
`${source}; return window.SidepanelContributionContentService;`
|
|
)(
|
|
windowObject,
|
|
localStorage,
|
|
wrappedFetch,
|
|
AbortController,
|
|
setTimeout,
|
|
clearTimeout
|
|
);
|
|
|
|
return {
|
|
api,
|
|
getFetchCalls() {
|
|
return fetchCalls;
|
|
},
|
|
getFetchUrls() {
|
|
return fetchUrls.slice();
|
|
},
|
|
};
|
|
}
|
|
|
|
test('getContentUpdateSnapshot returns a prompt version for visible contribution content updates', async () => {
|
|
const { api, getFetchUrls } = createContributionContentService({
|
|
fetchImpl: async () => ({
|
|
ok: true,
|
|
async json() {
|
|
return {
|
|
ok: true,
|
|
prompt_version: 'auto_run_notice:2026-04-21T12:05:00Z',
|
|
has_visible_updates: true,
|
|
latest_updated_at: '2026-04-21T12:05:00Z',
|
|
latest_updated_at_display: '2026-04-21 20:05',
|
|
items: [
|
|
{
|
|
slug: 'auto_run_notice',
|
|
title: '自动提示',
|
|
text: '公告和使用教程更新了,可点上方“贡献/使用教程”查看。',
|
|
is_enabled: true,
|
|
has_content: true,
|
|
is_visible: true,
|
|
updated_at: '2026-04-21T12:05:00Z',
|
|
updated_at_display: '2026-04-21 20:05',
|
|
},
|
|
],
|
|
};
|
|
},
|
|
}),
|
|
});
|
|
|
|
const snapshot = await api.getContentUpdateSnapshot({ flowId: 'kiro', targetId: 'kiro-rs' });
|
|
|
|
assert.equal(snapshot.status, 'update-available');
|
|
assert.equal(snapshot.promptVersion, 'auto_run_notice:2026-04-21T12:05:00Z');
|
|
assert.equal(snapshot.flowId, 'kiro');
|
|
assert.equal(snapshot.targetId, 'kiro-rs');
|
|
assert.equal(getFetchUrls()[0], 'https://flowpilot.qlhazycoder.top/api/content-summary?flow=kiro&target=kiro-rs');
|
|
assert.equal(snapshot.hasVisibleUpdates, true);
|
|
assert.equal(snapshot.latestUpdatedAt, '2026-04-21T12:05:00Z');
|
|
assert.equal(snapshot.items.length, 1);
|
|
assert.deepEqual(
|
|
snapshot.items.map((item) => [item.slug, item.isVisible, item.text]),
|
|
[['auto_run_notice', true, '公告和使用教程更新了,可点上方“贡献/使用教程”查看。']]
|
|
);
|
|
});
|
|
|
|
test('getContentUpdateSnapshot falls back to cached snapshot when the live request fails', async () => {
|
|
const cachedSnapshot = {
|
|
status: 'update-available',
|
|
promptVersion: 'announcement:2026-04-20T00:00:00Z',
|
|
hasVisibleUpdates: true,
|
|
latestUpdatedAt: '2026-04-20T00:00:00Z',
|
|
latestUpdatedAtDisplay: '2026-04-20 08:00',
|
|
items: [
|
|
{
|
|
slug: 'announcement',
|
|
title: '站点公告',
|
|
isEnabled: true,
|
|
hasContent: true,
|
|
isVisible: true,
|
|
updatedAt: '2026-04-20T00:00:00Z',
|
|
updatedAtDisplay: '2026-04-20 08:00',
|
|
},
|
|
],
|
|
portalUrl: 'https://flowpilot.qlhazycoder.top',
|
|
apiUrl: 'https://flowpilot.qlhazycoder.top/api/content-summary?flow=openai&target=cpa',
|
|
checkedAt: Date.now() - 1000,
|
|
};
|
|
|
|
const { api, getFetchCalls } = createContributionContentService({
|
|
cachedSnapshot,
|
|
fetchImpl: async () => {
|
|
throw new Error('offline');
|
|
},
|
|
});
|
|
|
|
const snapshot = await api.getContentUpdateSnapshot();
|
|
|
|
assert.equal(getFetchCalls(), 1);
|
|
assert.equal(snapshot.fromCache, true);
|
|
assert.equal(snapshot.promptVersion, cachedSnapshot.promptVersion);
|
|
assert.equal(snapshot.errorMessage, 'offline');
|
|
assert.equal(snapshot.items[0].slug, 'announcement');
|
|
});
|
|
|
|
test('getContentUpdateSnapshot keeps flow caches isolated', async () => {
|
|
const cachedSnapshot = {
|
|
status: 'update-available',
|
|
promptVersion: 'flow:kiro|target:kiro-rs|auto_run_notice:2026-04-22T00:00:00Z',
|
|
hasVisibleUpdates: true,
|
|
latestUpdatedAt: '2026-04-22T00:00:00Z',
|
|
latestUpdatedAtDisplay: '2026-04-22 08:00',
|
|
flowId: 'kiro',
|
|
targetId: 'kiro-rs',
|
|
items: [{ slug: 'auto_run_notice', isVisible: true, text: 'Kiro 提示' }],
|
|
checkedAt: Date.now() - 1000,
|
|
};
|
|
|
|
const { api } = createContributionContentService({
|
|
cachedSnapshot,
|
|
cacheKey: 'multipage-contribution-content-summary-v2:kiro:kiro-rs',
|
|
fetchImpl: async () => {
|
|
throw new Error('offline');
|
|
},
|
|
});
|
|
|
|
const openAiSnapshot = await api.getContentUpdateSnapshot({ flowId: 'openai', targetId: 'cpa' });
|
|
const kiroSnapshot = await api.getContentUpdateSnapshot({ flowId: 'kiro', targetId: 'kiro-rs' });
|
|
|
|
assert.equal(openAiSnapshot.status, 'error');
|
|
assert.equal(openAiSnapshot.fromCache, undefined);
|
|
assert.equal(openAiSnapshot.flowId, 'openai');
|
|
assert.equal(kiroSnapshot.fromCache, true);
|
|
assert.equal(kiroSnapshot.flowId, 'kiro');
|
|
assert.equal(kiroSnapshot.promptVersion, cachedSnapshot.promptVersion);
|
|
});
|