268 lines
9.1 KiB
TypeScript
268 lines
9.1 KiB
TypeScript
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
|
import * as smartfeed from '../ts/index.js';
|
|
|
|
let testSmartFeed: smartfeed.Smartfeed;
|
|
let testPodcast: smartfeed.PodcastFeed;
|
|
|
|
tap.test('setup', async () => {
|
|
testSmartFeed = new smartfeed.Smartfeed();
|
|
});
|
|
|
|
tap.test('should create a podcast feed', async () => {
|
|
testPodcast = testSmartFeed.createPodcastFeed({
|
|
domain: 'podcast.example.com',
|
|
title: 'Test Podcast',
|
|
description: 'A test podcast about testing',
|
|
category: 'Technology',
|
|
company: 'Test Podcast Inc',
|
|
companyEmail: 'podcast@example.com',
|
|
companyDomain: 'https://example.com',
|
|
itunesCategory: 'Technology',
|
|
itunesAuthor: 'John Tester',
|
|
itunesOwner: {
|
|
name: 'John Tester',
|
|
email: 'john@example.com',
|
|
},
|
|
itunesImage: 'https://example.com/podcast-artwork.jpg',
|
|
itunesExplicit: false,
|
|
podcastGuid: 'test-podcast-guid-001',
|
|
});
|
|
|
|
expect(testPodcast).toBeInstanceOf(smartfeed.PodcastFeed);
|
|
expect(testPodcast.podcastOptions.itunesCategory).toEqual('Technology');
|
|
expect(testPodcast.podcastOptions.itunesAuthor).toEqual('John Tester');
|
|
});
|
|
|
|
tap.test('should create podcast feed with episodic type', async () => {
|
|
const podcast = testSmartFeed.createPodcastFeed({
|
|
domain: 'episodic.example.com',
|
|
title: 'Episodic Podcast',
|
|
description: 'An episodic podcast',
|
|
category: 'Comedy',
|
|
company: 'Comedy Inc',
|
|
companyEmail: 'comedy@example.com',
|
|
companyDomain: 'https://example.com',
|
|
itunesCategory: 'Comedy',
|
|
itunesAuthor: 'Comedian',
|
|
itunesOwner: { name: 'Comedian', email: 'comedian@example.com' },
|
|
itunesImage: 'https://example.com/comedy.jpg',
|
|
itunesExplicit: true,
|
|
podcastGuid: 'test-podcast-guid-002',
|
|
itunesType: 'episodic',
|
|
});
|
|
|
|
expect(podcast.podcastOptions.itunesType).toEqual('episodic');
|
|
expect(podcast.podcastOptions.itunesExplicit).toEqual(true);
|
|
});
|
|
|
|
tap.test('should create podcast feed with serial type', async () => {
|
|
const podcast = testSmartFeed.createPodcastFeed({
|
|
domain: 'serial.example.com',
|
|
title: 'Serial Podcast',
|
|
description: 'A serial podcast',
|
|
category: 'True Crime',
|
|
company: 'Crime Inc',
|
|
companyEmail: 'crime@example.com',
|
|
companyDomain: 'https://example.com',
|
|
itunesCategory: 'True Crime',
|
|
itunesAuthor: 'Detective',
|
|
itunesOwner: { name: 'Detective', email: 'detective@example.com' },
|
|
itunesImage: 'https://example.com/crime.jpg',
|
|
itunesExplicit: false,
|
|
podcastGuid: 'test-podcast-guid-003',
|
|
itunesType: 'serial',
|
|
});
|
|
|
|
expect(podcast.podcastOptions.itunesType).toEqual('serial');
|
|
});
|
|
|
|
tap.test('should add episode to podcast', async () => {
|
|
testPodcast.addEpisode({
|
|
title: 'Episode 1: Introduction',
|
|
authorName: 'John Tester',
|
|
imageUrl: 'https://example.com/episode1.jpg',
|
|
timestamp: Date.now(),
|
|
url: 'https://podcast.example.com/episode/1',
|
|
content: 'In this episode, we introduce the podcast',
|
|
audioUrl: 'https://example.com/audio/episode1.mp3',
|
|
audioType: 'audio/mpeg',
|
|
audioLength: 45678900,
|
|
itunesDuration: 3600,
|
|
itunesEpisode: 1,
|
|
itunesSeason: 1,
|
|
itunesEpisodeType: 'full',
|
|
});
|
|
|
|
expect(testPodcast.episodes.length).toEqual(1);
|
|
expect(testPodcast.episodes[0].title).toEqual('Episode 1: Introduction');
|
|
expect(testPodcast.episodes[0].itunesEpisode).toEqual(1);
|
|
});
|
|
|
|
tap.test('should add multiple episodes', async () => {
|
|
const podcast = testSmartFeed.createPodcastFeed({
|
|
domain: 'multi.example.com',
|
|
title: 'Multi-Episode Podcast',
|
|
description: 'Podcast with multiple episodes',
|
|
category: 'Education',
|
|
company: 'Edu Inc',
|
|
companyEmail: 'edu@example.com',
|
|
companyDomain: 'https://example.com',
|
|
itunesCategory: 'Education',
|
|
itunesAuthor: 'Teacher',
|
|
itunesOwner: { name: 'Teacher', email: 'teacher@example.com' },
|
|
itunesImage: 'https://example.com/edu.jpg',
|
|
itunesExplicit: false,
|
|
podcastGuid: 'test-podcast-guid-004',
|
|
});
|
|
|
|
for (let i = 1; i <= 5; i++) {
|
|
podcast.addEpisode({
|
|
title: `Episode ${i}`,
|
|
authorName: 'Teacher',
|
|
imageUrl: `https://example.com/episode${i}.jpg`,
|
|
timestamp: Date.now() + i,
|
|
url: `https://example.com/episode/${i}`,
|
|
content: `Content for episode ${i}`,
|
|
audioUrl: `https://example.com/audio/episode${i}.mp3`,
|
|
audioType: 'audio/mpeg',
|
|
audioLength: 40000000 + i * 1000000,
|
|
itunesDuration: 3000 + i * 100,
|
|
itunesEpisode: i,
|
|
itunesSeason: 1,
|
|
});
|
|
}
|
|
|
|
expect(podcast.episodes.length).toEqual(5);
|
|
});
|
|
|
|
tap.test('should add episode with trailer type', async () => {
|
|
const podcast = testSmartFeed.createPodcastFeed({
|
|
domain: 'trailer.example.com',
|
|
title: 'Podcast with Trailer',
|
|
description: 'Podcast with trailer episode',
|
|
category: 'News',
|
|
company: 'News Inc',
|
|
companyEmail: 'news@example.com',
|
|
companyDomain: 'https://example.com',
|
|
itunesCategory: 'News',
|
|
itunesAuthor: 'Reporter',
|
|
itunesOwner: { name: 'Reporter', email: 'reporter@example.com' },
|
|
itunesImage: 'https://example.com/news.jpg',
|
|
itunesExplicit: false,
|
|
podcastGuid: 'test-podcast-guid-005',
|
|
});
|
|
|
|
podcast.addEpisode({
|
|
title: 'Season 1 Trailer',
|
|
authorName: 'Reporter',
|
|
imageUrl: 'https://example.com/trailer.jpg',
|
|
timestamp: Date.now(),
|
|
url: 'https://example.com/episode/trailer',
|
|
content: 'Trailer for season 1',
|
|
audioUrl: 'https://example.com/audio/trailer.mp3',
|
|
audioType: 'audio/mpeg',
|
|
audioLength: 5000000,
|
|
itunesDuration: 300,
|
|
itunesEpisodeType: 'trailer',
|
|
itunesSeason: 1,
|
|
});
|
|
|
|
expect(podcast.episodes[0].itunesEpisodeType).toEqual('trailer');
|
|
});
|
|
|
|
tap.test('should add episode with bonus type', async () => {
|
|
const podcast = testSmartFeed.createPodcastFeed({
|
|
domain: 'bonus.example.com',
|
|
title: 'Podcast with Bonus',
|
|
description: 'Podcast with bonus episode',
|
|
category: 'Business',
|
|
company: 'Business Inc',
|
|
companyEmail: 'business@example.com',
|
|
companyDomain: 'https://example.com',
|
|
itunesCategory: 'Business',
|
|
itunesAuthor: 'Entrepreneur',
|
|
itunesOwner: { name: 'Entrepreneur', email: 'entrepreneur@example.com' },
|
|
itunesImage: 'https://example.com/business.jpg',
|
|
itunesExplicit: false,
|
|
podcastGuid: 'test-podcast-guid-006',
|
|
});
|
|
|
|
podcast.addEpisode({
|
|
title: 'Bonus: Behind the Scenes',
|
|
authorName: 'Entrepreneur',
|
|
imageUrl: 'https://example.com/bonus.jpg',
|
|
timestamp: Date.now(),
|
|
url: 'https://example.com/episode/bonus',
|
|
content: 'Bonus behind the scenes content',
|
|
audioUrl: 'https://example.com/audio/bonus.mp3',
|
|
audioType: 'audio/mpeg',
|
|
audioLength: 8000000,
|
|
itunesDuration: 600,
|
|
itunesEpisodeType: 'bonus',
|
|
});
|
|
|
|
expect(podcast.episodes[0].itunesEpisodeType).toEqual('bonus');
|
|
});
|
|
|
|
tap.test('should support M4A audio format', async () => {
|
|
const podcast = testSmartFeed.createPodcastFeed({
|
|
domain: 'm4a.example.com',
|
|
title: 'M4A Podcast',
|
|
description: 'Podcast with M4A audio',
|
|
category: 'Music',
|
|
company: 'Music Inc',
|
|
companyEmail: 'music@example.com',
|
|
companyDomain: 'https://example.com',
|
|
itunesCategory: 'Music',
|
|
itunesAuthor: 'Musician',
|
|
itunesOwner: { name: 'Musician', email: 'musician@example.com' },
|
|
itunesImage: 'https://example.com/music.jpg',
|
|
itunesExplicit: false,
|
|
podcastGuid: 'test-podcast-guid-007',
|
|
});
|
|
|
|
podcast.addEpisode({
|
|
title: 'Musical Episode',
|
|
authorName: 'Musician',
|
|
imageUrl: 'https://example.com/musical.jpg',
|
|
timestamp: Date.now(),
|
|
url: 'https://example.com/episode/musical',
|
|
content: 'A musical episode',
|
|
audioUrl: 'https://example.com/audio/episode.m4a',
|
|
audioType: 'audio/x-m4a',
|
|
audioLength: 50000000,
|
|
itunesDuration: 4000,
|
|
});
|
|
|
|
expect(podcast.episodes[0].audioType).toEqual('audio/x-m4a');
|
|
});
|
|
|
|
tap.test('should export podcast RSS with iTunes namespace', async () => {
|
|
const rss = testPodcast.exportPodcastRss();
|
|
|
|
expect(rss).toInclude('<?xml version="1.0" encoding="UTF-8"?>');
|
|
expect(rss).toInclude('xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"');
|
|
expect(rss).toInclude('<itunes:author>John Tester</itunes:author>');
|
|
expect(rss).toInclude('<itunes:owner>');
|
|
expect(rss).toInclude('<itunes:name>John Tester</itunes:name>');
|
|
expect(rss).toInclude('<itunes:email>john@example.com</itunes:email>');
|
|
expect(rss).toInclude('<itunes:category text="Technology"');
|
|
expect(rss).toInclude('<itunes:image href="https://example.com/podcast-artwork.jpg"');
|
|
expect(rss).toInclude('<itunes:explicit>false</itunes:explicit>');
|
|
});
|
|
|
|
tap.test('should include episode in RSS export', async () => {
|
|
const rss = testPodcast.exportPodcastRss();
|
|
|
|
expect(rss).toInclude('Episode 1: Introduction');
|
|
expect(rss).toInclude('https://example.com/audio/episode1.mp3');
|
|
expect(rss).toInclude('<enclosure url="https://example.com/audio/episode1.mp3"');
|
|
expect(rss).toInclude('length="45678900"');
|
|
expect(rss).toInclude('type="audio/mpeg"');
|
|
expect(rss).toInclude('<itunes:duration>01:00:00</itunes:duration>');
|
|
expect(rss).toInclude('<itunes:episode>1</itunes:episode>');
|
|
expect(rss).toInclude('<itunes:season>1</itunes:season>');
|
|
});
|
|
|
|
export default tap.start();
|