mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-10-28 23:19:27 +08:00
150 lines
6.4 KiB
TypeScript
150 lines
6.4 KiB
TypeScript
import { raw } from 'hono/html';
|
|
import { renderToString } from 'hono/jsx/dom/server';
|
|
import Parser from 'rss-parser';
|
|
import { describe, expect, it } from 'vitest';
|
|
|
|
import RSS from '@/views/rss';
|
|
|
|
describe('RSS view', () => {
|
|
it.each(['audio/mpeg', 'audio/mp4', 'video/mp4'])('preserves the explicit %s enclosure for RSS consumers', async (mimeType) => {
|
|
const html = renderToString(
|
|
<RSS
|
|
data={{
|
|
title: 'Feed',
|
|
item: [
|
|
{
|
|
title: 'Media',
|
|
image: 'https://example.com/thumbnail',
|
|
enclosure_url: 'https://example.com/download?id=media',
|
|
enclosure_length: 123,
|
|
enclosure_type: mimeType,
|
|
},
|
|
],
|
|
}}
|
|
/>
|
|
);
|
|
|
|
expect(html).toContain(`<enclosure url="https://example.com/download?id=media" length="123" type="${mimeType}"`);
|
|
const feed = await new Parser().parseString(html);
|
|
expect(feed.items[0].enclosure).toEqual({ url: 'https://example.com/download?id=media', length: '123', type: mimeType });
|
|
expect(html.match(/<enclosure /g)).toHaveLength(1);
|
|
});
|
|
|
|
it('renders itunes, media, and telegram image variants', () => {
|
|
const html = renderToString(
|
|
<RSS
|
|
data={{
|
|
title: 'RSS Feed',
|
|
link: 'https://t.me/s/rsshub',
|
|
atomlink: 'https://example.com/feed.xml',
|
|
description: 'RSS Description',
|
|
language: 'en',
|
|
lastBuildDate: '2024-01-01T00:00:00Z',
|
|
ttl: 60,
|
|
itunes_author: 'Podcast Author',
|
|
itunes_category: 'Tech',
|
|
itunes_explicit: 'true',
|
|
image: 'https://example.com/image.jpg',
|
|
item: [
|
|
{
|
|
title: 'Episode One',
|
|
link: 'https://example.com/one',
|
|
description: 'Episode One',
|
|
guid: 'episode-1',
|
|
pubDate: '2024-01-01T00:00:00Z',
|
|
author: 'Host',
|
|
image: 'https://example.com/episode.jpg',
|
|
itunes_item_image: 'https://example.com/itunes.jpg',
|
|
itunes_duration: '01:02:03',
|
|
enclosure_url: 'https://example.com/audio.mp3',
|
|
enclosure_length: 123,
|
|
enclosure_type: 'audio/mpeg',
|
|
category: 'Podcast',
|
|
media: {
|
|
content: {
|
|
url: 'https://example.com/media.mp4',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
title: 'Episode Two',
|
|
link: 'https://example.com/two',
|
|
description: 'Episode Two',
|
|
category: ['News', 'Updates'],
|
|
},
|
|
],
|
|
}}
|
|
/>
|
|
);
|
|
|
|
expect(html).toContain('xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"');
|
|
expect(html).toContain('xmlns:media="http://search.yahoo.com/mrss/"');
|
|
expect(html).toContain('xmlns:dc="http://purl.org/dc/elements/1.1/"');
|
|
expect(html).toContain('<dc:creator>Host</dc:creator>');
|
|
expect(html).not.toContain('<author>');
|
|
expect(html).toContain('<itunes:author>Podcast Author</itunes:author>');
|
|
expect(html).toContain('itunes:category text="Tech"');
|
|
expect(html).toContain('<itunes:explicit>true</itunes:explicit>');
|
|
expect(html).toContain('<height>31</height>');
|
|
expect(html).toContain('<width>88</width>');
|
|
expect(html).toContain('media:content');
|
|
expect(html).toContain('<itunes:image href="https://example.com/itunes.jpg"');
|
|
expect(html).toContain('<enclosure url="https://example.com/audio.mp3"');
|
|
expect(html).toContain('<category>Podcast</category>');
|
|
expect(html).toContain('<category>News</category>');
|
|
});
|
|
|
|
it('uses the first attachment when no explicit enclosure is provided', () => {
|
|
const html = renderToString(
|
|
<RSS
|
|
data={{
|
|
title: 'Attachments',
|
|
item: [
|
|
{
|
|
title: 'Post',
|
|
image: 'https://example.com/cover.png',
|
|
attachments: [
|
|
{ url: 'https://example.com/audio.mp3', mime_type: 'audio/mpeg' },
|
|
{ url: 'https://example.com/cover.png', mime_type: 'image/png' },
|
|
],
|
|
},
|
|
],
|
|
}}
|
|
/>
|
|
);
|
|
expect(html.match(/<enclosure /g)).toHaveLength(1);
|
|
expect(html).toContain('<enclosure url="https://example.com/audio.mp3" length="0" type="audio/mpeg"');
|
|
expect(html).not.toContain('xmlns:dc');
|
|
});
|
|
|
|
it('emits a single enclosure when the thumbnail is also an attachment', () => {
|
|
const html = renderToString(
|
|
<RSS
|
|
data={{
|
|
title: 'Image attachment',
|
|
item: [
|
|
{
|
|
title: 'Post',
|
|
image: 'https://example.com/cover.png',
|
|
attachments: [{ url: 'https://example.com/cover.png', mime_type: 'image/png' }],
|
|
},
|
|
],
|
|
}}
|
|
/>
|
|
);
|
|
expect(html.match(/<enclosure /g)).toHaveLength(1);
|
|
expect(html).toContain('<enclosure url="https://example.com/cover.png" length="0" type="image/png"');
|
|
});
|
|
|
|
it('does not let hono hoist feed titles and links as document metadata', () => {
|
|
const html = String(
|
|
<probe>
|
|
{raw('</head>')}
|
|
<RSS data={{ title: 'Feed', item: [{ title: 'Item', link: 'https://example.com/item' }] }} />
|
|
</probe>
|
|
);
|
|
|
|
expect(html).toMatch(/^<probe><\/head><rss/);
|
|
});
|
|
});
|