feat(parsing): Replace rss-parser with fast-xml-parser and add native feed parser; update Smartfeed to use parseFeedXML and adjust plugins/tests
This commit is contained in:
179
test/test.parsing.all.ts
Normal file
179
test/test.parsing.all.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||||
import * as smartfeed from '../ts/index.js';
|
||||
|
||||
let testSmartFeed: smartfeed.Smartfeed;
|
||||
|
||||
tap.test('setup', async () => {
|
||||
testSmartFeed = new smartfeed.Smartfeed();
|
||||
});
|
||||
|
||||
tap.test('should parse RSS feed from string', async () => {
|
||||
const feed = testSmartFeed.createFeed({
|
||||
domain: 'example.com',
|
||||
title: 'Example Feed',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyDomain: 'https://example.com',
|
||||
companyEmail: 'test@example.com',
|
||||
description: 'Test description',
|
||||
});
|
||||
|
||||
feed.addItem({
|
||||
title: 'Test Article',
|
||||
authorName: 'John Doe',
|
||||
imageUrl: 'https://example.com/image.png',
|
||||
timestamp: Date.now(),
|
||||
url: 'https://example.com/article/test',
|
||||
content: 'Test content',
|
||||
});
|
||||
|
||||
const rssFeed = feed.exportRssFeedString();
|
||||
const parsedFeed = await testSmartFeed.parseFeedFromString(rssFeed);
|
||||
|
||||
expect(parsedFeed.title).toEqual('Example Feed');
|
||||
expect(parsedFeed.description).toEqual('Test description');
|
||||
expect(parsedFeed.items).toBeArray();
|
||||
expect(parsedFeed.items.length).toEqual(1);
|
||||
expect(parsedFeed.items[0].title).toEqual('Test Article');
|
||||
});
|
||||
|
||||
tap.test('should parse Atom feed from string', async () => {
|
||||
const feed = testSmartFeed.createFeed({
|
||||
domain: 'example.com',
|
||||
title: 'Atom Test Feed',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyDomain: 'https://example.com',
|
||||
companyEmail: 'test@example.com',
|
||||
description: 'Atom test description',
|
||||
});
|
||||
|
||||
feed.addItem({
|
||||
title: 'Atom Article',
|
||||
authorName: 'Jane Doe',
|
||||
imageUrl: 'https://example.com/atom-image.png',
|
||||
timestamp: Date.now(),
|
||||
url: 'https://example.com/article/atom-test',
|
||||
content: 'Atom content',
|
||||
});
|
||||
|
||||
const atomFeed = feed.exportAtomFeed();
|
||||
const parsedFeed = await testSmartFeed.parseFeedFromString(atomFeed);
|
||||
|
||||
expect(parsedFeed.title).toEqual('Atom Test Feed');
|
||||
expect(parsedFeed.items).toBeArray();
|
||||
expect(parsedFeed.items.length).toEqual(1);
|
||||
expect(parsedFeed.items[0].title).toEqual('Atom Article');
|
||||
});
|
||||
|
||||
tap.test('should parse feed with multiple items', async () => {
|
||||
const feed = testSmartFeed.createFeed({
|
||||
domain: 'example.com',
|
||||
title: 'Multi-item Feed',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyDomain: 'https://example.com',
|
||||
companyEmail: 'test@example.com',
|
||||
description: 'Feed with multiple items',
|
||||
});
|
||||
|
||||
const itemCount = 10;
|
||||
for (let i = 1; i <= itemCount; i++) {
|
||||
feed.addItem({
|
||||
title: `Article ${i}`,
|
||||
authorName: `Author ${i}`,
|
||||
imageUrl: `https://example.com/image${i}.png`,
|
||||
timestamp: Date.now() + i,
|
||||
url: `https://example.com/article/${i}`,
|
||||
content: `Content ${i}`,
|
||||
});
|
||||
}
|
||||
|
||||
const rssFeed = feed.exportRssFeedString();
|
||||
const parsedFeed = await testSmartFeed.parseFeedFromString(rssFeed);
|
||||
|
||||
expect(parsedFeed.items.length).toEqual(itemCount);
|
||||
expect(parsedFeed.items[0].title).toEqual('Article 1');
|
||||
expect(parsedFeed.items[9].title).toEqual('Article 10');
|
||||
});
|
||||
|
||||
tap.test('should parse live RSS feed from URL', async () => {
|
||||
try {
|
||||
const parsedFeed = await testSmartFeed.parseFeedFromUrl(
|
||||
'https://www.theverge.com/rss/index.xml'
|
||||
);
|
||||
|
||||
expect(parsedFeed).toBeObject();
|
||||
expect(parsedFeed.title).toBeString();
|
||||
expect(parsedFeed.items).toBeArray();
|
||||
expect(parsedFeed.items.length).toBeGreaterThan(0);
|
||||
} catch (error) {
|
||||
// Network errors are acceptable in tests
|
||||
console.log('Network test skipped (expected in CI/offline):', error.message);
|
||||
}
|
||||
});
|
||||
|
||||
tap.test('should preserve feed metadata when parsing', async () => {
|
||||
const feed = testSmartFeed.createFeed({
|
||||
domain: 'meta.example.com',
|
||||
title: 'Metadata Test Feed',
|
||||
category: 'Metadata',
|
||||
company: 'Metadata Inc',
|
||||
companyDomain: 'https://meta.example.com',
|
||||
companyEmail: 'meta@example.com',
|
||||
description: 'Testing metadata preservation',
|
||||
});
|
||||
|
||||
feed.addItem({
|
||||
title: 'Meta Article',
|
||||
authorName: 'Meta Author',
|
||||
imageUrl: 'https://example.com/meta.png',
|
||||
timestamp: Date.now(),
|
||||
url: 'https://example.com/meta',
|
||||
content: 'Meta content',
|
||||
});
|
||||
|
||||
const rssFeed = feed.exportRssFeedString();
|
||||
const parsedFeed = await testSmartFeed.parseFeedFromString(rssFeed);
|
||||
|
||||
expect(parsedFeed.title).toEqual('Metadata Test Feed');
|
||||
expect(parsedFeed.description).toEqual('Testing metadata preservation');
|
||||
expect(parsedFeed.language).toEqual('en');
|
||||
expect(parsedFeed.generator).toEqual('@push.rocks/smartfeed');
|
||||
expect(parsedFeed.copyright).toInclude('Metadata Inc');
|
||||
});
|
||||
|
||||
tap.test('should handle feed with enclosures', async () => {
|
||||
const feed = testSmartFeed.createFeed({
|
||||
domain: 'example.com',
|
||||
title: 'Enclosure Test',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyDomain: 'https://example.com',
|
||||
companyEmail: 'test@example.com',
|
||||
description: 'Testing enclosures',
|
||||
});
|
||||
|
||||
feed.addItem({
|
||||
title: 'Article with image',
|
||||
authorName: 'Author',
|
||||
imageUrl: 'https://example.com/large-image.jpg',
|
||||
timestamp: Date.now(),
|
||||
url: 'https://example.com/article',
|
||||
content: 'Content with enclosure',
|
||||
});
|
||||
|
||||
const rssFeed = feed.exportRssFeedString();
|
||||
const parsedFeed = await testSmartFeed.parseFeedFromString(rssFeed);
|
||||
|
||||
// Enclosure support depends on the parser and feed format
|
||||
expect(parsedFeed.items.length).toBeGreaterThan(0);
|
||||
expect(parsedFeed.items[0].title).toEqual('Article with image');
|
||||
|
||||
// If enclosure exists, verify it
|
||||
if (parsedFeed.items[0].enclosure) {
|
||||
expect(parsedFeed.items[0].enclosure.url).toInclude('https://example.com/large-image.jpg');
|
||||
}
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
Reference in New Issue
Block a user