test: wechat-mp
This commit is contained in:
parent
bdf8ace129
commit
01e142ccaf
|
|
@ -1,17 +1,7 @@
|
|||
process.env.REQUEST_TIMEOUT = '500';
|
||||
const cheerio = require('cheerio');
|
||||
const {
|
||||
_internal: { normalizeUrl },
|
||||
fetchArticle,
|
||||
finishArticleItem,
|
||||
fixArticleContent,
|
||||
} = require('../../lib/utils/wechat-mp');
|
||||
const nock = require('nock');
|
||||
const ctx = require('../../lib/app').context;
|
||||
|
||||
afterAll(() => {
|
||||
delete process.env.REQUEST_TIMEOUT;
|
||||
});
|
||||
import { describe, expect, it } from '@jest/globals';
|
||||
import { load } from 'cheerio';
|
||||
import nock from 'nock';
|
||||
import { fixArticleContent, fetchArticle, finishArticleItem, normalizeUrl } from '@/utils/wechat-mp';
|
||||
|
||||
// date from the cache will be an ISO8601 string, so we need to use this function
|
||||
const compareDate = (date1, date2) => {
|
||||
|
|
@ -56,20 +46,19 @@ describe('wechat-mp', () => {
|
|||
'<script>const test = "test"</script>';
|
||||
const expectedHtmlSection =
|
||||
expectedCodeSection + '<p>test</p>' + '<div><p>test</p></div>' + '<div><div>test</div></div>' + '<div><div><p>test</p></div></div>' + '<div><div><p>test</p></div></div>' + '<p>test</p>' + '<div><p>test</p></div>';
|
||||
let $ = cheerio.load(divHeader + htmlSection + divFooter);
|
||||
let $ = load(divHeader + htmlSection + divFooter);
|
||||
expect(fixArticleContent(htmlSection)).toBe(expectedHtmlSection);
|
||||
expect(fixArticleContent($('div#js_content.rich_media_content'))).toBe(expectedHtmlSection);
|
||||
|
||||
const htmlImg = '<img alt="test" data-src="http://rsshub.test/test.jpg" src="http://rsshub.test/test.jpg">' + '<img alt="test" data-src="http://rsshub.test/test.jpg">' + '<img alt="test" src="http://rsshub.test/test.jpg">';
|
||||
const expectedHtmlImg = Array.from({ length: 3 + 1 }).join('<img alt="test" src="http://rsshub.test/test.jpg">');
|
||||
$ = cheerio.load(divHeader + htmlImg + divFooter);
|
||||
$ = load(divHeader + htmlImg + divFooter);
|
||||
expect(fixArticleContent(htmlImg)).toBe(expectedHtmlImg);
|
||||
expect(fixArticleContent($('div#js_content.rich_media_content'))).toBe(expectedHtmlImg);
|
||||
expect(fixArticleContent(htmlImg, true)).toBe(htmlImg);
|
||||
expect(fixArticleContent($('div#js_content.rich_media_content'), true)).toBe(htmlImg);
|
||||
|
||||
expect(fixArticleContent('')).toBe('');
|
||||
expect(fixArticleContent(null)).toBe('');
|
||||
expect(fixArticleContent()).toBe('');
|
||||
expect(fixArticleContent($('div#something_not_in.the_document_tree'))).toBe('');
|
||||
});
|
||||
|
|
@ -121,7 +110,14 @@ describe('wechat-mp', () => {
|
|||
const httpsUrl = 'https://mp.weixin.qq.com/rsshub_test/wechatMp_fetchArticle';
|
||||
const httpUrl = httpsUrl.replace(/^https:\/\//, 'http://');
|
||||
|
||||
const expectedItem = {
|
||||
const expectedItem: {
|
||||
title: string;
|
||||
summary: string;
|
||||
author: string;
|
||||
description: string;
|
||||
mpName?: string;
|
||||
link: string;
|
||||
} = {
|
||||
title: 'title',
|
||||
summary: 'summary',
|
||||
author: 'author',
|
||||
|
|
@ -131,13 +127,13 @@ describe('wechat-mp', () => {
|
|||
};
|
||||
const expectedDate = new Date(ct * 1000);
|
||||
|
||||
const fetchArticleItem = await fetchArticle(ctx, httpUrl);
|
||||
const fetchArticleItem = await fetchArticle(httpUrl);
|
||||
expect(compareDate(fetchArticleItem.pubDate, expectedDate)).toBe(true);
|
||||
delete fetchArticleItem.pubDate;
|
||||
expect(fetchArticleItem).toEqual(expectedItem);
|
||||
|
||||
delete expectedItem.mpName;
|
||||
const finishedArticleItem = await finishArticleItem(ctx, { link: httpUrl });
|
||||
const finishedArticleItem = await finishArticleItem({ link: httpUrl });
|
||||
expect(compareDate(finishedArticleItem.pubDate, expectedDate)).toBe(true);
|
||||
delete finishedArticleItem.pubDate;
|
||||
expect(finishedArticleItem).toEqual(expectedItem);
|
||||
|
|
@ -26,8 +26,9 @@
|
|||
*/
|
||||
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { load, type Cheerio, type Element } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import cache from '@/utils/cache';
|
||||
|
||||
const replaceTag = ($, oldTag, newTagName) => {
|
||||
oldTag = $(oldTag);
|
||||
|
|
@ -76,12 +77,17 @@ const detectSourceUrl = ($) => {
|
|||
* @param {boolean} skipImg - Whether to skip fixing images.
|
||||
* @return {string} - The fixed html, a string.
|
||||
*/
|
||||
const fixArticleContent = (html, skipImg = false) => {
|
||||
html = html && html.html ? html.html() : html; // do not disturb the original tree
|
||||
if (!html) {
|
||||
const fixArticleContent = (html?: string | Cheerio<Element>, skipImg = false) => {
|
||||
let htmlResult = '';
|
||||
if (typeof html === 'string') {
|
||||
htmlResult = html;
|
||||
} else if (html?.html) {
|
||||
htmlResult = html.html() || '';
|
||||
}
|
||||
if (!htmlResult) {
|
||||
return '';
|
||||
}
|
||||
const $ = load(html, undefined, false);
|
||||
const $ = load(htmlResult, undefined, false);
|
||||
if (!skipImg) {
|
||||
// fix img lazy loading
|
||||
$('img[data-src]').each((_, img) => {
|
||||
|
|
@ -187,9 +193,9 @@ const normalizeUrl = (url, bypassHostCheck = false) => {
|
|||
* @param {boolean} bypassHostCheck - Whether to bypass host check.
|
||||
* @return {Promise<object>} - An object containing the article and its metadata.
|
||||
*/
|
||||
const fetchArticle = (ctx, url, bypassHostCheck = false) => {
|
||||
const fetchArticle = (url, bypassHostCheck = false) => {
|
||||
url = normalizeUrl(url, bypassHostCheck);
|
||||
return ctx.cache.tryGet(url, async () => {
|
||||
return cache.tryGet(url, async () => {
|
||||
const response = await got(url);
|
||||
// @ts-expect-error custom field
|
||||
const $ = load(response.data);
|
||||
|
|
@ -225,7 +231,15 @@ const fetchArticle = (ctx, url, bypassHostCheck = false) => {
|
|||
let mpName = $('.profile_nickname').first().text();
|
||||
mpName = mpName && mpName.trim();
|
||||
return { title, author, description, summary, pubDate, mpName, link: response.url };
|
||||
});
|
||||
}) as Promise<{
|
||||
title: string;
|
||||
author: string;
|
||||
description: string;
|
||||
summary: string;
|
||||
pubDate?: Date;
|
||||
mpName?: string;
|
||||
link: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -244,8 +258,8 @@ const fetchArticle = (ctx, url, bypassHostCheck = false) => {
|
|||
* @param {boolean} skipLink - Whether to skip overriding `item.link` with the normalized url.
|
||||
* @return {Promise<object>} - The incoming `item` object, with the article and its metadata filled in.
|
||||
*/
|
||||
const finishArticleItem = async (ctx, item, setMpNameAsAuthor = false, skipLink = false) => {
|
||||
const { title, author, description, summary, pubDate, mpName, link } = await fetchArticle(ctx, item.link);
|
||||
const finishArticleItem = async (item, setMpNameAsAuthor = false, skipLink = false) => {
|
||||
const { title, author, description, summary, pubDate, mpName, link } = await fetchArticle(item.link);
|
||||
item.title = title || item.title;
|
||||
item.description = description || item.description;
|
||||
item.summary = summary || item.summary;
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ const gdgov = async (info, ctx) => {
|
|||
});
|
||||
} else if (idlink.host === 'mp.weixin.qq.com') {
|
||||
const { finishArticleItem } = require('@/utils/wechat-mp');
|
||||
return finishArticleItem(ctx, { link });
|
||||
return finishArticleItem({ link });
|
||||
} else {
|
||||
return ctx.cache.tryGet(link, async () => {
|
||||
// 获取网页
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ module.exports = async (ctx) => {
|
|||
return item;
|
||||
});
|
||||
} else if (/^https:\/\/mp\.weixin\.qq\.com\//.test(item.link)) {
|
||||
return finishArticleItem(ctx, item);
|
||||
return finishArticleItem(item);
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ module.exports = async (ctx) => {
|
|||
const content = cheerio.load(detailResponse.data);
|
||||
item.description = content('.article').html();
|
||||
} else if (new URL(item.link).hostname === 'mp.weixin.qq.com') {
|
||||
await finishArticleItem(ctx, item);
|
||||
await finishArticleItem(item);
|
||||
} else {
|
||||
item.description = '本文需跳转,请点击标题后阅读';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ module.exports = async (ctx) => {
|
|||
const $1 = cheerio.load(resp.data);
|
||||
item.description = $1('div#print').html();
|
||||
} else if (new URL(item.link).hostname === 'mp.weixin.qq.com') {
|
||||
await finishArticleItem(ctx, item);
|
||||
await finishArticleItem(item);
|
||||
} else {
|
||||
item.description = '本文需跳转,请点击标题后阅读';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ module.exports = async (ctx) => {
|
|||
link: item.url,
|
||||
pubDate: item.publicTime,
|
||||
}));
|
||||
await Promise.all(items.map((item) => finishArticleItem(ctx, item)));
|
||||
await Promise.all(items.map((item) => finishArticleItem(item)));
|
||||
|
||||
ctx.state.data = {
|
||||
title: name + ' - 微信公众号',
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ const ProcessFeed = (items, artiContent, ctx) =>
|
|||
return item;
|
||||
}
|
||||
case 'wechat-mp':
|
||||
return fetchArticle(ctx, item.link);
|
||||
return fetchArticle(item.link);
|
||||
case 'unknown':
|
||||
default:
|
||||
item.description = `暂不支持解析该内容,请点击 ${arti_link('原文', item.link)}`;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ module.exports = async (ctx) => {
|
|||
list.map((item) => {
|
||||
switch (item.type) {
|
||||
case 'wechat-mp':
|
||||
return finishArticleItem(ctx, item);
|
||||
return finishArticleItem(item);
|
||||
case 'pku-news':
|
||||
return ctx.cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got({ url: item.link, https: { rejectUnauthorized: false } });
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ module.exports = async (ctx) => {
|
|||
item.map((item) =>
|
||||
ctx.cache.tryGet(item.link, async () => {
|
||||
if (new URL(item.link).hostname === 'mp.weixin.qq.com') {
|
||||
return finishArticleItem(ctx, item);
|
||||
return finishArticleItem(item);
|
||||
} else if (new URL(item.link).hostname !== 'www.cs.sdu.edu.cn') {
|
||||
return item;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ module.exports = async (ctx) => {
|
|||
list.map((item) =>
|
||||
ctx.cache.tryGet(item.link, async () => {
|
||||
if (new URL(item.link).hostname === 'mp.weixin.qq.com') {
|
||||
item.description = (await fetchArticle(ctx, item.link)).description;
|
||||
item.description = (await fetchArticle(item.link)).description;
|
||||
} else {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ module.exports = async (ctx) => {
|
|||
pubDate: parseDate(item.date),
|
||||
}));
|
||||
|
||||
items = await Promise.all(items.map((item) => finishArticleItem(ctx, item)));
|
||||
items = await Promise.all(items.map((item) => finishArticleItem(item)));
|
||||
|
||||
ctx.state.data = {
|
||||
title,
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ module.exports = async (ctx) => {
|
|||
list.map((item) => {
|
||||
switch (item.type) {
|
||||
case 'wechat-mp':
|
||||
return finishArticleItem(ctx, item);
|
||||
return finishArticleItem(item);
|
||||
case 'tju-oaa':
|
||||
case 'in-site':
|
||||
return ctx.cache.tryGet(item.link, async () => {
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ module.exports = async (ctx) => {
|
|||
throw err;
|
||||
}
|
||||
|
||||
await Promise.all(items.map((item) => finishArticleItem(ctx, item, !!categoryPage)));
|
||||
await Promise.all(items.map((item) => finishArticleItem(item, !!categoryPage)));
|
||||
|
||||
ctx.state.data = {
|
||||
title,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ module.exports = async (ctx) => {
|
|||
})
|
||||
.get();
|
||||
|
||||
await Promise.all(items.map((item) => finishArticleItem(ctx, item)));
|
||||
await Promise.all(items.map((item) => finishArticleItem(item)));
|
||||
|
||||
ctx.state.data = {
|
||||
title: `微信公众号 - ${$('span.name').text()}`,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ module.exports = async (ctx) => {
|
|||
guid: item.id,
|
||||
}));
|
||||
|
||||
items = await Promise.all(items.map((item) => finishArticleItem(ctx, item)));
|
||||
items = await Promise.all(items.map((item) => finishArticleItem(item)));
|
||||
|
||||
ctx.state.data = {
|
||||
title: response.data.title,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ module.exports = async (ctx) => {
|
|||
link: item.link,
|
||||
guid: item.link,
|
||||
}));
|
||||
await Promise.all(items.map((item) => finishArticleItem(ctx, item)));
|
||||
await Promise.all(items.map((item) => finishArticleItem(item)));
|
||||
|
||||
ctx.state.data = {
|
||||
title: feed.title,
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ module.exports = async (ctx) => {
|
|||
link: item.link,
|
||||
guid: item.link,
|
||||
};
|
||||
return finishArticleItem(ctx, single);
|
||||
return finishArticleItem(single);
|
||||
})
|
||||
);
|
||||
ctx.state.data = {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module.exports = async (ctx) => {
|
|||
link,
|
||||
guid: link,
|
||||
};
|
||||
return finishArticleItem(ctx, single);
|
||||
return finishArticleItem(single);
|
||||
})
|
||||
);
|
||||
ctx.state.data = {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ module.exports = async (ctx) => {
|
|||
guid: link,
|
||||
};
|
||||
|
||||
await finishArticleItem(ctx, item);
|
||||
await finishArticleItem(item);
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${title} 的微信公众号`,
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ module.exports = async (ctx) => {
|
|||
|
||||
if (link !== undefined) {
|
||||
try {
|
||||
return await finishArticleItem(ctx, single);
|
||||
return await finishArticleItem(single);
|
||||
} catch {
|
||||
single.description = item.find('.tgme_widget_message_text').html();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ module.exports = async (ctx) => {
|
|||
link: i.link,
|
||||
}));
|
||||
|
||||
items = await Promise.all(items.map((item) => finishArticleItem(ctx, item)));
|
||||
items = await Promise.all(items.map((item) => finishArticleItem(item)));
|
||||
|
||||
ctx.state.data = {
|
||||
title,
|
||||
|
|
|
|||
Loading…
Reference in New Issue