feat(smartfeed): Implement Smartfeed core: add feed validation, parsing, exporting and comprehensive tests
This commit is contained in:
271
test/test.validation.node+bun+deno.ts
Normal file
271
test/test.validation.node+bun+deno.ts
Normal file
@@ -0,0 +1,271 @@
|
||||
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 validate required feed options', async () => {
|
||||
let errorThrown = false;
|
||||
try {
|
||||
testSmartFeed.createFeed({
|
||||
domain: '',
|
||||
title: '',
|
||||
description: '',
|
||||
category: '',
|
||||
company: '',
|
||||
companyEmail: '',
|
||||
companyDomain: '',
|
||||
} as any);
|
||||
} catch (error) {
|
||||
errorThrown = true;
|
||||
expect(error.message).toInclude('validation failed');
|
||||
}
|
||||
expect(errorThrown).toEqual(true);
|
||||
});
|
||||
|
||||
tap.test('should validate domain format', async () => {
|
||||
let errorThrown = false;
|
||||
try {
|
||||
testSmartFeed.createFeed({
|
||||
domain: 'not a domain!',
|
||||
title: 'Test',
|
||||
description: 'Test',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyEmail: 'test@example.com',
|
||||
companyDomain: 'https://example.com',
|
||||
});
|
||||
} catch (error) {
|
||||
errorThrown = true;
|
||||
expect(error.message).toInclude('Invalid domain format');
|
||||
}
|
||||
expect(errorThrown).toEqual(true);
|
||||
});
|
||||
|
||||
tap.test('should validate email format', async () => {
|
||||
let errorThrown = false;
|
||||
try {
|
||||
testSmartFeed.createFeed({
|
||||
domain: 'example.com',
|
||||
title: 'Test',
|
||||
description: 'Test',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyEmail: 'not-an-email',
|
||||
companyDomain: 'https://example.com',
|
||||
});
|
||||
} catch (error) {
|
||||
errorThrown = true;
|
||||
expect(error.message).toInclude('Invalid email');
|
||||
}
|
||||
expect(errorThrown).toEqual(true);
|
||||
});
|
||||
|
||||
tap.test('should validate company domain URL', async () => {
|
||||
let errorThrown = false;
|
||||
try {
|
||||
testSmartFeed.createFeed({
|
||||
domain: 'example.com',
|
||||
title: 'Test',
|
||||
description: 'Test',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyEmail: 'test@example.com',
|
||||
companyDomain: 'not-a-url',
|
||||
});
|
||||
} catch (error) {
|
||||
errorThrown = true;
|
||||
expect(error.message).toInclude('Invalid or relative URL');
|
||||
}
|
||||
expect(errorThrown).toEqual(true);
|
||||
});
|
||||
|
||||
tap.test('should validate item URLs', async () => {
|
||||
const feed = testSmartFeed.createFeed({
|
||||
domain: 'example.com',
|
||||
title: 'Test Feed',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyDomain: 'https://example.com',
|
||||
companyEmail: 'test@example.com',
|
||||
description: 'Test description',
|
||||
});
|
||||
|
||||
let errorThrown = false;
|
||||
try {
|
||||
feed.addItem({
|
||||
title: 'Test',
|
||||
authorName: 'John',
|
||||
imageUrl: 'not-a-url',
|
||||
timestamp: Date.now(),
|
||||
url: 'also-not-a-url',
|
||||
content: 'content',
|
||||
});
|
||||
} catch (error) {
|
||||
errorThrown = true;
|
||||
expect(error.message).toInclude('Invalid or relative URL');
|
||||
}
|
||||
expect(errorThrown).toEqual(true);
|
||||
});
|
||||
|
||||
tap.test('should validate relative URLs', async () => {
|
||||
const feed = testSmartFeed.createFeed({
|
||||
domain: 'example.com',
|
||||
title: 'Test Feed',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyDomain: 'https://example.com',
|
||||
companyEmail: 'test@example.com',
|
||||
description: 'Test description',
|
||||
});
|
||||
|
||||
let errorThrown = false;
|
||||
try {
|
||||
feed.addItem({
|
||||
title: 'Test',
|
||||
authorName: 'John',
|
||||
imageUrl: '/images/test.jpg',
|
||||
timestamp: Date.now(),
|
||||
url: '/posts/test',
|
||||
content: 'content',
|
||||
});
|
||||
} catch (error) {
|
||||
errorThrown = true;
|
||||
expect(error.message).toInclude('Invalid or relative URL');
|
||||
}
|
||||
expect(errorThrown).toEqual(true);
|
||||
});
|
||||
|
||||
tap.test('should validate duplicate IDs', async () => {
|
||||
const feed = testSmartFeed.createFeed({
|
||||
domain: 'example.com',
|
||||
title: 'Test Feed',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyDomain: 'https://example.com',
|
||||
companyEmail: 'test@example.com',
|
||||
description: 'Test description',
|
||||
});
|
||||
|
||||
const itemData = {
|
||||
title: 'Test Article',
|
||||
authorName: 'John',
|
||||
imageUrl: 'https://example.com/image.png',
|
||||
timestamp: Date.now(),
|
||||
url: 'https://example.com/article/test',
|
||||
content: 'content',
|
||||
};
|
||||
|
||||
feed.addItem(itemData);
|
||||
|
||||
// Try to add same item again (same URL = same ID)
|
||||
let errorThrown = false;
|
||||
try {
|
||||
feed.addItem(itemData);
|
||||
} catch (error) {
|
||||
errorThrown = true;
|
||||
expect(error.message).toInclude('Duplicate item ID');
|
||||
}
|
||||
expect(errorThrown).toEqual(true);
|
||||
});
|
||||
|
||||
tap.test('should validate duplicate custom IDs', async () => {
|
||||
const feed = testSmartFeed.createFeed({
|
||||
domain: 'example.com',
|
||||
title: 'Test Feed',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyDomain: 'https://example.com',
|
||||
companyEmail: 'test@example.com',
|
||||
description: 'Test description',
|
||||
});
|
||||
|
||||
feed.addItem({
|
||||
title: 'First Article',
|
||||
authorName: 'John',
|
||||
imageUrl: 'https://example.com/image1.png',
|
||||
timestamp: Date.now(),
|
||||
url: 'https://example.com/article/first',
|
||||
content: 'first content',
|
||||
id: 'custom-id-1',
|
||||
});
|
||||
|
||||
// Try to add another item with same custom ID
|
||||
let errorThrown = false;
|
||||
try {
|
||||
feed.addItem({
|
||||
title: 'Second Article',
|
||||
authorName: 'Jane',
|
||||
imageUrl: 'https://example.com/image2.png',
|
||||
timestamp: Date.now(),
|
||||
url: 'https://example.com/article/second',
|
||||
content: 'second content',
|
||||
id: 'custom-id-1',
|
||||
});
|
||||
} catch (error) {
|
||||
errorThrown = true;
|
||||
expect(error.message).toInclude('Duplicate item ID');
|
||||
}
|
||||
expect(errorThrown).toEqual(true);
|
||||
});
|
||||
|
||||
tap.test('should validate timestamp', async () => {
|
||||
const feed = testSmartFeed.createFeed({
|
||||
domain: 'example.com',
|
||||
title: 'Test Feed',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyDomain: 'https://example.com',
|
||||
companyEmail: 'test@example.com',
|
||||
description: 'Test description',
|
||||
});
|
||||
|
||||
let errorThrown = false;
|
||||
try {
|
||||
feed.addItem({
|
||||
title: 'Test',
|
||||
authorName: 'John',
|
||||
imageUrl: 'https://example.com/image.png',
|
||||
timestamp: -1,
|
||||
url: 'https://example.com/article/test',
|
||||
content: 'content',
|
||||
});
|
||||
} catch (error) {
|
||||
errorThrown = true;
|
||||
expect(error.message).toInclude('cannot be negative');
|
||||
}
|
||||
expect(errorThrown).toEqual(true);
|
||||
});
|
||||
|
||||
tap.test('should validate required item fields', async () => {
|
||||
const feed = testSmartFeed.createFeed({
|
||||
domain: 'example.com',
|
||||
title: 'Test Feed',
|
||||
category: 'Test',
|
||||
company: 'Test Inc',
|
||||
companyDomain: 'https://example.com',
|
||||
companyEmail: 'test@example.com',
|
||||
description: 'Test description',
|
||||
});
|
||||
|
||||
let errorThrown = false;
|
||||
try {
|
||||
feed.addItem({
|
||||
title: '',
|
||||
authorName: '',
|
||||
imageUrl: '',
|
||||
timestamp: Date.now(),
|
||||
url: '',
|
||||
content: '',
|
||||
} as any);
|
||||
} catch (error) {
|
||||
errorThrown = true;
|
||||
expect(error.message).toInclude('validation failed');
|
||||
}
|
||||
expect(errorThrown).toEqual(true);
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
Reference in New Issue
Block a user