test: move test files to lib

This commit is contained in:
DIYgod
2024-02-21 19:46:18 +08:00
parent c713674c35
commit 0d606a06c2
6 changed files with 26 additions and 26 deletions
-11
View File
@@ -1,11 +0,0 @@
import { describe, expect, it } from '@jest/globals';
import app from '../lib/app';
describe('index', () => {
it('serve index', async () => {
const res = await app.request('/');
expect(res.status).toBe(200);
expect(await res.text()).toContain('Welcome to RSSHub!');
});
});
-105
View File
@@ -1,105 +0,0 @@
import { describe, expect, it, afterEach, jest } from '@jest/globals';
import nock from 'nock';
afterEach(() => {
jest.resetModules();
});
describe('config', () => {
it('bilibilib cookie', async () => {
process.env.BILIBILI_COOKIE_12 = 'cookie1';
process.env.BILIBILI_COOKIE_34 = 'cookie2';
const { config } = await import('../lib/config');
expect(config.bilibili.cookies).toMatchObject({
12: 'cookie1',
34: 'cookie2',
});
delete process.env.BILIBILI_COOKIE_12;
delete process.env.BILIBILI_COOKIE_34;
});
it('email config', async () => {
process.env['EMAIL_CONFIG_xx.qq.com'] = 'token1';
process.env['EMAIL_CONFIG_oo.qq.com'] = 'token2';
const { config } = await import('../lib/config');
expect(config.email.config).toMatchObject({
'xx.qq.com': 'token1',
'oo.qq.com': 'token2',
});
delete process.env['EMAIL_CONFIG_xx.qq.com'];
delete process.env['EMAIL_CONFIG_oo.qq.com'];
});
it('discuz cookie', async () => {
process.env.DISCUZ_COOKIE_12 = 'cookie1';
process.env.DISCUZ_COOKIE_34 = 'cookie2';
const { config } = await import('../lib/config');
expect(config.discuz.cookies).toMatchObject({
12: 'cookie1',
34: 'cookie2',
});
delete process.env.DISCUZ_COOKIE_12;
delete process.env.DISCUZ_COOKIE_34;
});
it('medium cookie', async () => {
process.env.MEDIUM_COOKIE_12 = 'cookie1';
process.env.MEDIUM_COOKIE_34 = 'cookie2';
const { config } = await import('../lib/config');
expect(config.medium.cookies).toMatchObject({
12: 'cookie1',
34: 'cookie2',
});
delete process.env.MEDIUM_COOKIE_12;
delete process.env.MEDIUM_COOKIE_34;
});
it('discourse config', async () => {
process.env.DISCOURSE_CONFIG_12 = JSON.stringify({ a: 1 });
process.env.DISCOURSE_CONFIG_34 = JSON.stringify({ b: 2 });
const { config } = await import('../lib/config');
expect(config.discourse.config).toMatchObject({
12: { a: 1 },
34: { b: 2 },
});
delete process.env.DISCOURSE_CONFIG_12;
delete process.env.DISCOURSE_CONFIG_34;
});
it('no random ua', async () => {
process.env.NO_RANDOM_UA = '1';
const { config } = await import('../lib/config');
expect(config.ua).toBe('RSSHub/1.0 (+http://github.com/DIYgod/RSSHub; like FeedFetcher-Google)');
delete process.env.NO_RANDOM_UA;
});
it('random ua', async () => {
const { config } = await import('../lib/config');
expect(config.ua).not.toBe('RSSHub/1.0 (+http://github.com/DIYgod/RSSHub; like FeedFetcher-Google)');
});
it('remote config', async () => {
process.env.REMOTE_CONFIG = 'http://rsshub.test/config';
nock(/rsshub\.test/)
.get('/config')
.reply(200, {
UA: 'test',
});
const { config } = await import('../lib/config');
await new Promise((resolve) => setTimeout(resolve, 100));
expect(config.ua).toBe('test');
});
});
-83
View File
@@ -1,83 +0,0 @@
import { describe, expect, it, afterAll, jest } from '@jest/globals';
process.env.SOCKET = 'socket';
jest.mock('request-promise-native');
import app from '../lib/app';
import Parser from 'rss-parser';
const parser = new Parser();
import { config } from '../lib/config';
afterAll(() => {
delete process.env.SOCKET;
});
async function checkRSS(response) {
const checkDate = (date) => {
expect(date).toEqual(expect.any(String));
expect(Date.parse(date)).toEqual(expect.any(Number));
expect(Date.now() - +new Date(date)).toBeGreaterThan(-1000 * 60 * 60 * 24 * 5);
expect(Date.now() - +new Date(date)).toBeLessThan(1000 * 60 * 60 * 24 * 30 * 12 * 10);
};
const parsed = await parser.parseString(await response.text());
expect(parsed).toEqual(expect.any(Object));
expect(parsed.title).toEqual(expect.any(String));
expect(parsed.title).not.toBe('RSSHub');
expect(parsed.description).toEqual(expect.any(String));
expect(parsed.link).toEqual(expect.any(String));
expect(parsed.lastBuildDate).toEqual(expect.any(String));
expect(parsed.ttl).toEqual(Math.trunc(config.cache.routeExpire / 60) + '');
expect(parsed.items).toEqual(expect.any(Array));
checkDate(parsed.lastBuildDate);
// check items
const guids: (string | undefined)[] = [];
for (const item of parsed.items) {
expect(item).toEqual(expect.any(Object));
expect(item.title).toEqual(expect.any(String));
expect(item.link).toEqual(expect.any(String));
expect(item.content).toEqual(expect.any(String));
expect(item.guid).toEqual(expect.any(String));
if (item.pubDate) {
expect(item.pubDate).toEqual(expect.any(String));
checkDate(item.pubDate);
}
// guid must be unique
expect(guids).not.toContain(item.guid);
guids.push(item.guid);
}
}
describe('router', () => {
// root
it(`/`, async () => {
const response = await app.request('/');
expect(response.status).toBe(200);
expect(response.headers.get('content-type')).toBe('text/html; charset=UTF-8');
expect(response.headers.get('cache-control')).toBe('no-cache');
});
// route
it(`/test/1`, async () => {
const response = await app.request('/test/1');
expect(response.status).toBe(200);
await checkRSS(response);
});
// robots.txt
// TODO
// it('/robots.txt', async () => {
// config.disallowRobot = false;
// const response404 = await app.request('/robots.txt');
// expect(response404.status).toBe(404);
// config.disallowRobot = true;
// const response = await app.request('/robots.txt');
// expect(response.status).toBe(200);
// expect(await response.text()).toBe('User-agent: *\nDisallow: /');
// expect(response.headers.get('content-type')).toBe('text/plain');
// });
});
-144
View File
@@ -1,144 +0,0 @@
import { describe, expect, it, jest, afterEach } from '@jest/globals';
import wait from '../../lib/utils/wait';
import { type Browser } from 'puppeteer';
let browser: Browser | null = null;
afterEach(() => {
if (browser) {
// double insurance to close unclosed browser immediately after each test
// if a test closure fails before it can close the browser, the browser process will probably be unclosed,
// especially when the test unit is run through `npm run jest puppeteer`
browser.close();
browser = null;
}
delete process.env.PROXY_URI;
delete process.env.PROXY_PROTOCOL;
delete process.env.PROXY_HOST;
delete process.env.PROXY_PORT;
delete process.env.PROXY_AUTH;
jest.resetModules();
});
describe('puppeteer', () => {
it('puppeteer run', async () => {
const { default: puppeteer } = await import('../../lib/utils/puppeteer');
browser = await puppeteer();
const startTime = Date.now();
const page = await browser.newPage();
await page.goto('https://www.google.com', {
waitUntil: 'domcontentloaded',
});
const html = await page.evaluate(() => document.body.innerHTML);
expect(html.length).toBeGreaterThan(0);
expect(browser.process()?.exitCode).toBe(null); // browser is still running
const sleepTime = 31 * 1000 - (Date.now() - startTime); // prevent long loading time from failing the test
if (sleepTime > 0) {
await wait(sleepTime);
}
expect(browser.process()?.exitCode).toBe(0); // browser is closed
browser = null;
}, 45000);
if (!process.env.GITHUB_ACTIONS) {
it('puppeteer without stealth', async () => {
const { default: puppeteer } = await import('../../lib/utils/puppeteer');
browser = await puppeteer({ stealth: false });
const page = await browser.newPage();
await page.goto('https://bot.sannysoft.com', { waitUntil: 'networkidle0' });
// page rendering is not instant, wait for expected elements to appear
const [webDriverTest, chromeTest] = await Promise.all(['webdriver', 'chrome'].map((t) => page.waitForSelector(`td#${t}-result.result.failed`).then((hd) => hd?.evaluate((e) => e.textContent))));
// the website return empty string from time to time for no reason
// since we don't really care whether puppeteer without stealth passes the bot test, just let it go
expect(['present (failed)', '']).toContain(webDriverTest);
expect(['missing (failed)', '']).toContain(chromeTest);
}, 15000);
it('puppeteer with stealth', async () => {
const { default: puppeteer } = await import('../../lib/utils/puppeteer');
browser = await puppeteer({ stealth: true });
const page = await browser.newPage();
await page.goto('https://bot.sannysoft.com', { waitUntil: 'networkidle0' });
// page rendering is not instant, wait for expected elements to appear
const [webDriverTest, chromeTest] = await Promise.all(['webdriver', 'chrome'].map((t) => page.waitForSelector(`td#${t}-result.result.passed`).then((hd) => hd?.evaluate((e) => e.textContent))));
// these are something we really care about
expect(webDriverTest).toBe('missing (passed)');
expect(chromeTest).toBe('present (passed)');
}, 15000);
}
it('puppeteer accept http proxy uri w/ auth', async () => {
process.env.PROXY_URI = 'http://user:pass@rsshub.proxy:2333';
const { default: puppeteer } = await import('../../lib/utils/puppeteer');
browser = await puppeteer();
// trailing slash will cause net::ERR_NO_SUPPORTED_PROXIES, prohibit it
expect(browser.process()?.spawnargs.some((arg) => /^--proxy-server=http:\/\/.*[^/]$/.test(arg))).toBe(true);
});
it('puppeteer reject https proxy uri w/ auth', async () => {
process.env.PROXY_URI = 'https://user:pass@rsshub.proxy:2333';
const { default: puppeteer } = await import('../../lib/utils/puppeteer');
browser = await puppeteer();
expect(browser.process()?.spawnargs.some((arg) => arg.includes('--proxy-server'))).toBe(false);
});
it('puppeteer reject socks proxy uri w/ auth', async () => {
process.env.PROXY_URI = 'socks5://user:pass@rsshub.proxy:2333';
const { default: puppeteer } = await import('../../lib/utils/puppeteer');
browser = await puppeteer();
expect(browser.process()?.spawnargs.some((arg) => arg.includes('--proxy-server'))).toBe(false);
});
it('puppeteer accept http proxy', async () => {
process.env.PROXY_PROTOCOL = 'http';
process.env.PROXY_HOST = 'rsshub.proxy';
process.env.PROXY_PORT = '2333';
const { default: puppeteer } = await import('../../lib/utils/puppeteer');
browser = await puppeteer();
expect(browser.process()?.spawnargs.some((arg) => /^--proxy-server=http:\/\/rsshub.proxy:2333$/.test(arg))).toBe(true);
}, 10000);
it('puppeteer accept https proxy', async () => {
process.env.PROXY_PROTOCOL = 'https';
process.env.PROXY_HOST = 'rsshub.proxy';
process.env.PROXY_PORT = '2333';
const { default: puppeteer } = await import('../../lib/utils/puppeteer');
browser = await puppeteer();
expect(browser.process()?.spawnargs.some((arg) => /^--proxy-server=https:\/\/rsshub.proxy:2333$/.test(arg))).toBe(true);
}, 10000);
it('puppeteer accept socks4a proxy', async () => {
process.env.PROXY_PROTOCOL = 'socks4a';
process.env.PROXY_HOST = 'rsshub.proxy';
process.env.PROXY_PORT = '2333';
const { default: puppeteer } = await import('../../lib/utils/puppeteer');
browser = await puppeteer();
expect(browser.process()?.spawnargs.some((arg) => /^--proxy-server=socks4:\/\/rsshub.proxy:2333$/.test(arg))).toBe(true);
}, 10000);
it('puppeteer accept socks5h proxy', async () => {
process.env.PROXY_PROTOCOL = 'socks5h';
process.env.PROXY_HOST = 'rsshub.proxy';
process.env.PROXY_PORT = '2333';
const { default: puppeteer } = await import('../../lib/utils/puppeteer');
browser = await puppeteer();
expect(browser.process()?.spawnargs.some((arg) => /^--proxy-server=socks5:\/\/rsshub.proxy:2333$/.test(arg))).toBe(true);
}, 10000);
});