Skip to content

Commit 4bfb75a

Browse files
author
Taois
committed
fix: 测试案例不完善的问题
1 parent 2a2b92a commit 4bfb75a

File tree

4 files changed

+285
-5
lines changed

4 files changed

+285
-5
lines changed

package.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {join, basename, dirname, resolve, relative} from 'path';
44
import url from 'url';
55

66
// 要排除的目录列表
7-
const EXCLUDE_DIRS = ['.git', '.idea', 'soft', 'examples', 'apps/cat', 'plugins/pvideo', 'plugins/req-proxy', 'plugins/pup-sniffer', 'plugins/mediaProxy', 'pyTools', 'drop_code', 'jstest', 'local', 'logs', '对话1.txt', 'vod_cache', 'data/mv'];
7+
const EXCLUDE_DIRS = ['.git', '.idea', 'soft', 'examples', 'apps/cat', 'plugins/pvideo', 'plugins/req-proxy', 'plugins/pup-sniffer', 'plugins/mediaProxy', 'pyTools', 'drop_code','local', 'logs', '对话1.txt', 'vod_cache', 'data/mv'];
88

99
// 要排除的文件列表
1010
const EXCLUDE_FILES = ['config/env.json', '.env', '.claude', 'clipboard.txt', 'clipboard.txt.bak', '.plugins.js', 'yarn.lock', 't4_daemon.pid', 'spider/js/UC分享.js', 'spider/js/百忙无果[官].js', 'spider/catvod/mtv60w[差].js', 'json/UC分享.json', 'jx/_30wmv.js', 'jx/奇奇.js', 'jx/芒果关姐.js', 'data/settings/link_data.json', 'index.json', 'custom.json'];

package.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
EXCLUDE_DIRS = ['.git', '.idea', 'soft', 'examples', 'apps/cat', 'plugins/pvideo', 'plugins/req-proxy',
88
'plugins/pup-sniffer', 'plugins/mediaProxy',
99
'pyTools', 'drop_code',
10-
'jstest',
1110
'local', 'logs',
1211
'对话1.txt',
1312
'vod_cache', 'data/mv']

spider/js/七猫小说[书].js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,18 +113,20 @@ var rule = {
113113
},
114114
二级: async function () {
115115
let {input, pdfa, pdfh, pd} = this;
116+
// console.log('Detail Input:', input);
116117
let html = await this.request(input);
118+
// console.log('Detail HTML Length:', html.length);
117119
let VOD = {};
118-
VOD.vod_name = pdfh(html, 'span.txt&&Text');
120+
VOD.vod_name = pdfh(html, '.book-detail-info .title .txt&&Text');
119121
VOD.type_name = pdfh(html, '.qm-tag:eq(-1)&&Text');
120122
VOD.vod_pic = pd(html, '.wrap-pic&&img&&src');
121-
VOD.vod_content = pdfh(html, '.book-introduction-item&&.qm-with-title-tb&&Text');
123+
VOD.vod_content = pdfh(html, '.intro&&Text');
122124
VOD.vod_remarks = pdfh(html, '.qm-tag&&Text');
123125
VOD.vod_year = '';
124126
VOD.vod_area = '';
125127
VOD.vod_actor = pdfh(html, '.sub-title&&span:eq(1)&&Text');
126128
VOD.vod_director = pdfh(html, '.sub-title&&span&&a&&Text');
127-
VOD.vod_play_from = pdfh(html, '.qm-sheader&&img&&alt');
129+
VOD.vod_play_from = '七猫小说';
128130
let book_id = input.match(/shuku\/(\d+)/)[1];
129131
let listUrl = buildUrl(rule.listUrl2, {
130132
book_id: book_id

spider/jstest/demo_test.js

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
2+
import * as drpyS from '../../libs/drpyS.js';
3+
import path from 'path';
4+
import {fileURLToPath} from 'url';
5+
import {existsSync} from 'fs';
6+
7+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
8+
9+
// Mock server constants
10+
const PORT = 5705;
11+
const WsPORT = 5706;
12+
const protocol = 'http';
13+
const hostname = 'localhost:5705';
14+
15+
function getEnv(moduleName, query = {}) {
16+
const moduleExt = query.extend || '';
17+
const requestHost = `${protocol}://${hostname}`;
18+
const publicUrl = `${protocol}://${hostname}/public/`;
19+
const jsonUrl = `${protocol}://${hostname}/json/`;
20+
const httpUrl = `${protocol}://${hostname}/http`;
21+
const imageApi = `${protocol}://${hostname}/image`;
22+
const mediaProxyUrl = `${protocol}://${hostname}/mediaProxy`;
23+
const webdavProxyUrl = `${protocol}://${hostname}/webdav/`;
24+
const ftpProxyUrl = `${protocol}://${hostname}/ftp/`;
25+
const hostUrl = `${hostname.split(':')[0]}`;
26+
const wsName = hostname.replace(`:${PORT}`, `:${WsPORT}`);
27+
const fServer = null;
28+
29+
const proxyUrl = `${protocol}://${hostname}/proxy/${moduleName}/?do=${query.do || 'ds'}&extend=${encodeURIComponent(moduleExt)}`;
30+
const getProxyUrl = function () {
31+
return proxyUrl
32+
};
33+
34+
const env = {
35+
requestHost,
36+
proxyUrl,
37+
publicUrl,
38+
jsonUrl,
39+
httpUrl,
40+
imageApi,
41+
mediaProxyUrl,
42+
webdavProxyUrl,
43+
ftpProxyUrl,
44+
hostUrl,
45+
hostname,
46+
wsName,
47+
fServer,
48+
getProxyUrl,
49+
ext: moduleExt
50+
};
51+
52+
env.getRule = async function (_moduleName) {
53+
const _modulePath = path.join(__dirname, '../js', `${_moduleName}.js`);
54+
if (!existsSync(_modulePath)) {
55+
return null;
56+
}
57+
const _env = getEnv(_moduleName);
58+
const RULE = await drpyS.getRuleObject(_modulePath, _env);
59+
60+
RULE.callRuleFn = async function (_method, _args) {
61+
let invokeMethod = null;
62+
switch (_method) {
63+
case 'class_parse': invokeMethod = 'home'; break;
64+
case '推荐': invokeMethod = 'homeVod'; break;
65+
case '一级': invokeMethod = 'category'; break;
66+
case '二级': invokeMethod = 'detail'; break;
67+
case '搜索': invokeMethod = 'search'; break;
68+
case 'lazy': invokeMethod = 'play'; break;
69+
case 'proxy_rule': invokeMethod = 'proxy'; break;
70+
case 'action': invokeMethod = 'action'; break;
71+
}
72+
73+
if (!invokeMethod) {
74+
if (typeof RULE[_method] !== 'function') {
75+
return null
76+
} else {
77+
return await RULE[_method](..._args);
78+
}
79+
}
80+
81+
return await drpyS[invokeMethod](_modulePath, _env, ..._args);
82+
};
83+
84+
return RULE;
85+
}
86+
87+
return env;
88+
}
89+
90+
// Test Status Reporter
91+
const stats = {
92+
results: [],
93+
pass(name) { this.results.push({name, status: 'PASS'}); },
94+
fail(name, err) { this.results.push({name, status: 'FAIL', error: err}); },
95+
skip(name, reason) { this.results.push({name, status: 'SKIP', reason}); },
96+
summary() {
97+
const total = this.results.length;
98+
const passed = this.results.filter(r => r.status === 'PASS').length;
99+
const failed = this.results.filter(r => r.status === 'FAIL').length;
100+
const skipped = this.results.filter(r => r.status === 'SKIP').length;
101+
102+
console.log('\n\n==============================================');
103+
console.log(' TEST SUMMARY REPORT ');
104+
console.log('==============================================');
105+
console.log(`Total Steps : ${total}`);
106+
console.log(`Passed : ${passed}`);
107+
console.log(`Failed : ${failed}`);
108+
console.log(`Skipped : ${skipped}`);
109+
console.log('----------------------------------------------');
110+
111+
this.results.forEach(r => {
112+
let statusIcon = r.status === 'PASS' ? '✅' : (r.status === 'FAIL' ? '❌' : '⚠️');
113+
let msg = `${statusIcon} [${r.status}] ${r.name}`;
114+
if (r.error) msg += ` - Error: ${r.error}`;
115+
if (r.reason) msg += ` - Reason: ${r.reason}`;
116+
console.log(msg);
117+
});
118+
console.log('==============================================\n');
119+
}
120+
};
121+
122+
(async () => {
123+
// 设置目标模块路径
124+
const moduleName = '七猫小说[书]';
125+
const modulePath = path.join(__dirname, `../js/${moduleName}.js`);
126+
127+
// Create environment
128+
const env = getEnv(moduleName);
129+
130+
// Shared variables for test dependencies
131+
let homeResult;
132+
let cateResult;
133+
let searchResult;
134+
let detailResult;
135+
let detailUrl = '';
136+
137+
try {
138+
console.log('Initializing module...');
139+
await drpyS.init(modulePath);
140+
141+
// 1. 测试 Home/Category (分类列表)
142+
try {
143+
console.log('\n=== Testing Home/Category ===');
144+
homeResult = await drpyS.home(modulePath, env);
145+
console.log('Home Result:', JSON.stringify(homeResult.class.slice(0, 3))); // 只打印前3个分类
146+
147+
if (homeResult && homeResult.class && homeResult.class.length > 0) {
148+
stats.pass('Home/Category');
149+
} else {
150+
throw new Error('No classes returned');
151+
}
152+
} catch (e) {
153+
stats.fail('Home/Category', e.message);
154+
// If home fails, we can't test category, but maybe search works?
155+
}
156+
157+
// 2. 测试 Category Content (一级 - 分类内容)
158+
if (homeResult && homeResult.class && homeResult.class.length > 0) {
159+
try {
160+
// 使用第一个分类的 ID
161+
const classId = homeResult.class[0].type_id;
162+
console.log(`\n=== Testing Category Content (class_id=${classId}) ===`);
163+
// category(filePath, env, tid, pg, filter, extend)
164+
cateResult = await drpyS.category(modulePath, env, classId, 1);
165+
console.log('Category Result Count:', cateResult.list.length);
166+
if (cateResult.list.length > 0) {
167+
console.log('First Item:', cateResult.list[0]);
168+
stats.pass('Category Content');
169+
} else {
170+
stats.fail('Category Content', 'No items in category');
171+
}
172+
} catch (e) {
173+
stats.fail('Category Content', e.message);
174+
}
175+
} else {
176+
stats.skip('Category Content', 'Dependency failed: Home/Category');
177+
}
178+
179+
// 3. 测试 Search (搜索)
180+
try {
181+
const keyword = '剑来';
182+
console.log(`\n=== Testing Search (keyword=${keyword}) ===`);
183+
searchResult = await drpyS.search(modulePath, env, keyword);
184+
console.log('Search Result Count:', searchResult.list.length);
185+
if (searchResult.list.length > 0) {
186+
console.log('First Search Item:', searchResult.list[0]);
187+
stats.pass('Search');
188+
} else {
189+
stats.fail('Search', 'No search results found');
190+
}
191+
} catch (e) {
192+
stats.fail('Search', e.message);
193+
}
194+
195+
// 4. 测试 Detail (二级 - 详情)
196+
// 优先使用搜索结果中的 URL (vod_id),如果没有则尝试分类结果
197+
if (searchResult && searchResult.list && searchResult.list.length > 0) {
198+
detailUrl = searchResult.list[0].vod_id;
199+
} else if (cateResult && cateResult.list && cateResult.list.length > 0) {
200+
detailUrl = cateResult.list[0].vod_id;
201+
}
202+
203+
if (detailUrl) {
204+
try {
205+
console.log(`\n=== Testing Detail (url=${detailUrl}) ===`);
206+
const detailOrList = await drpyS.detail(modulePath, env, [detailUrl]);
207+
208+
if (detailOrList.list && Array.isArray(detailOrList.list)) {
209+
detailResult = detailOrList.list[0];
210+
} else if (Array.isArray(detailOrList)) {
211+
detailResult = detailOrList[0];
212+
} else {
213+
detailResult = detailOrList;
214+
}
215+
216+
if (!detailResult) {
217+
throw new Error('Detail result is empty or invalid');
218+
}
219+
220+
console.log('Detail Result:', {
221+
vod_name: detailResult.vod_name,
222+
vod_play_from: detailResult.vod_play_from,
223+
// 截取 play_url 防止日志过长
224+
vod_play_url: detailResult.vod_play_url ? (detailResult.vod_play_url.slice(0, 100) + '...') : 'N/A'
225+
});
226+
stats.pass('Detail');
227+
228+
} catch (e) {
229+
stats.fail('Detail', e.message);
230+
}
231+
} else {
232+
stats.skip('Detail', 'No valid URL found from Search or Category results');
233+
}
234+
235+
// 5. 测试 Play (播放/阅读)
236+
if (detailResult && detailResult.vod_play_url) {
237+
try {
238+
console.log('\n=== Testing Play ===');
239+
// 解析 vod_play_url 获取播放链接
240+
const flags = detailResult.vod_play_from.split('$$$');
241+
const urls = detailResult.vod_play_url.split('$$$');
242+
243+
// 取第一个播放源的第一个章节
244+
const firstFlagUrlList = urls[0].split('#');
245+
const firstChapter = firstFlagUrlList[0];
246+
// 格式: "章节名$参数" -> "第一章$1747899@@123456@@第一章"
247+
const playUrl = firstChapter.split('$')[1];
248+
249+
console.log(`Playing Chapter: ${firstChapter.split('$')[0]}`);
250+
console.log(`Play URL Params: ${playUrl}`);
251+
252+
const playResult = await drpyS.play(modulePath, env, flags[0], playUrl);
253+
254+
const logResult = {...playResult};
255+
if (logResult.url && logResult.url.startsWith('novel://')) {
256+
logResult.url = logResult.url.slice(0, 100) + '... (truncated content)';
257+
}
258+
console.log('Play Result:', logResult);
259+
260+
if (playResult.url || playResult.parse === 0) {
261+
stats.pass('Play');
262+
} else {
263+
stats.fail('Play', 'No play URL or content returned');
264+
}
265+
266+
} catch (e) {
267+
stats.fail('Play', e.message);
268+
}
269+
} else {
270+
const reason = !detailResult ? 'Dependency failed: Detail' : 'No vod_play_url in detail';
271+
stats.skip('Play', reason);
272+
}
273+
274+
} catch (error) {
275+
console.error('Critical Error during test initialization:', error);
276+
} finally {
277+
stats.summary();
278+
}
279+
})();

0 commit comments

Comments
 (0)