miniflux-rss
Version:
Binding to Miniflux 2 REST API
525 lines (497 loc) • 18.5 kB
text/typescript
import { Miniflux, User, MinifluxError, Feed, FeedLink, Icon, CreatedFeed, Entry, EntryDirection, EntryStatus, EntryOrder, Category } from '../src/module';
import { expect } from 'chai';
import 'mocha';
import * as nock from "nock";
// TODO: Add live server testing
let mock_server = 'https://miniflux.mock';
let mock = nock(mock_server);
let miniflux_server = () => new Miniflux(mock_server, 'isavegas', '****');
// Simple way to validate that our methods are sending JSON to the server.
let json_validate = (body: string) => {
if (typeof body == 'string') {
try {
JSON.parse(body);
} catch (e) {
throw new Error(`Invalid request JSON: ${body}`)
}
}
return body;
}
describe('discover', () => {
let miniflux = miniflux_server();
it('should get data', () => {
let expected: FeedLink[] = [{ url: 'https://medium.com/feed/@monkeytypewritr', title: 'RSS', type: 'rss' }];
mock.filteringRequestBody(json_validate).post('/v1/discover').reply(200, expected);
return miniflux.discover('https://medium.com/@monkeytypewritr')
.then(res => expect(res).to.deep.equal(expected))
.catch(err => new Error('Expected 200.'));
});
it('should handle errors', () => {
let expected: MinifluxError = { error_message: 'No subscription found'};
mock.filteringRequestBody(json_validate).post('/v1/discover').reply(404, expected);
return miniflux.discover('https://medium.com/abc')
.then(res => new Error('Expected 404.'))
.catch(err => expect(err).to.deep.equal(expected));
});
});
describe('feeds', () => {
let miniflux = miniflux_server();
it('should retrieve feeds', () => {
let expected: Feed[] = [{
id: 42,
user_id: 123,
title: "Example Feed",
site_url: "http://example.org",
feed_url: "http://example.org/feed.atom",
rewrite_rules: "",
scraper_rules: "",
crawler: false,
checked_at: "2017-12-22T21:06:03.133839-05:00",
etag_header: "KyLxEflwnTGF5ecaiqZ2G0TxBCc",
last_modified_header: "Sat, 23 Dec 2017 01:04:21 GMT",
parsing_error_count: 0,
parsing_error_message: "",
category: {
id: 793,
user_id: 123,
title: "Some category"
},
icon: {
feed_id: 42,
icon_id: 84
}
}];
mock.get('/v1/feeds').reply(200, expected);
return miniflux.feeds()
.then(res => expect(res).to.deep.equal(expected))
.catch(err => new Error('Expected 200.'));
});
});
describe('get_feed', () => {
let miniflux = miniflux_server();
it('should retrieve feed data', () => {
let expected: Feed = {
id: 42,
user_id: 123,
title: "Example Feed",
site_url: "http://example.org",
feed_url: "http://example.org/feed.atom",
rewrite_rules: "",
scraper_rules: "",
crawler: false,
checked_at: "2017-12-22T21:06:03.133839-05:00",
etag_header: "KyLxEflwnTGF5ecaiqZ2G0TxBCc",
last_modified_header: "Sat, 23 Dec 2017 01:04:21 GMT",
parsing_error_count: 0,
parsing_error_message: "",
category: {
id: 793,
user_id: 123,
title: "Some category"
},
icon: {
feed_id: 42,
icon_id: 84
}
};
let feed_id = 1;
mock.get(`/v1/feeds/${feed_id}`).reply(200, expected);
return miniflux.get_feed(feed_id)
.then(res => expect(res).to.deep.equal(expected))
.catch(err => new Error('Expected 200.'));
})
});
describe('get_feed_icon', () => {
let miniflux = miniflux_server();
it('should retrieve feed icon', () => {
let expected: Icon = {
id: 1,
data: 'dummy_data',
mime_type: 'image/png',
}
let feed_id = 1;
mock.get(`/v1/feeds/${feed_id}/icon`).reply(200, expected);
return miniflux.get_feed_icon(feed_id)
.then(res => expect(res).to.deep.equal(expected))
.catch(err => new Error('Expected 200.'));
})
});
describe('create_feed', () => {
let miniflux = miniflux_server();
it('should create feed', () => {
let expected: CreatedFeed = {
feed_id: 42
}
let feed_id = 1;
mock.filteringRequestBody(json_validate).post(`/v1/feeds`).reply(200, expected);
return miniflux.create_feed(feed_id, 1)
.then(res => expect(res).to.deep.equal(expected))
.catch(err => new Error('Expected 200.'));
});
it('shouldn\'t require a category', () => {
let expected: CreatedFeed = {
feed_id: 42
}
let feed_id = 1;
mock.filteringRequestBody(json_validate).post(`/v1/feeds`).reply(200, expected);
return miniflux.create_feed(feed_id)
.then(res => expect(res).to.deep.equal(expected))
.catch(err => new Error('Expected 200.'));
});
});
describe('update_feed', () => {
let miniflux = miniflux_server();
let dummy_feed: Feed = {
id: 42,
user_id: 123,
title: "Example Feed",
site_url: "http://example.org",
feed_url: "http://example.org/feed.atom",
rewrite_rules: "",
scraper_rules: "",
crawler: false,
checked_at: "2017-12-22T21:06:03.133839-05:00",
etag_header: "KyLxEflwnTGF5ecaiqZ2G0TxBCc",
last_modified_header: "Sat, 23 Dec 2017 01:04:21 GMT",
parsing_error_count: 0,
parsing_error_message: "",
category: {
id: 1,
user_id: 123,
title: "Some category"
},
icon: {
feed_id: 42,
icon_id: 84
}
};
it('should update feed', () => {
let expected = dummy_feed;
let feed_id = 1;
mock.filteringRequestBody(json_validate).put(`/v1/feeds/${feed_id}`).reply(200, expected);
return miniflux.update_feed(feed_id, 'Example Feed', 1)
.then(res => expect(res).to.deep.equal(expected))
.catch(err => new Error('Expected 200.'));
});
it('should accept only a new title', () => {
let expected = dummy_feed;
let feed_id = 1;
mock.filteringRequestBody(json_validate).put(`/v1/feeds/${feed_id}`).reply(200, expected);
return miniflux.update_feed(feed_id, 'New Title', null)
.then(res => new Error('Expected error'))
.catch(err => expect(err).to.equal('No title or category specified'));
});
it('should accept only a new category', () => {
let expected = dummy_feed;
let feed_id = 1;
mock.filteringRequestBody(json_validate).put(`/v1/feeds/${feed_id}`).reply(200, expected);
return miniflux.update_feed(feed_id, null, 10)
.then(res => new Error('Expected error'))
.catch(err => expect(err).to.equal('No title or category specified'));
});
it('should require title or category', () => {
let feed_id = 1;
return miniflux.update_feed(feed_id, null, null)
.then(res => new Error('Expected error'))
.catch(err => expect(err).to.equal('No title or category specified'));
});
});
describe('refresh_feed', () => {
let miniflux = miniflux_server();
it('should refresh the feed', () => {
let feed_id = 1;
mock.filteringRequestBody(json_validate).put(`/v1/feeds/${feed_id}/refresh`).reply(204)
return miniflux.refresh_feed(feed_id)
.then(res => expect(res).to.equal(null));
});
});
let dummy_entry: Entry = {
id: 888,
user_id: 123,
feed_id: 42,
title: 'Entry Title',
url: 'http://example.org/article.html',
comments_url: '',
author: 'Foobar',
content: '<p>HTML contents</p>',
hash: '29f99e4074cdacca1766f47697d03c66070ef6a14770a1fd5a867483c207a1bb',
published_at: '2016-12-12T16:15:19Z',
status: 'read',
starred: false,
feed: {
id: 42,
user_id: 123,
title: 'New Feed Title',
site_url: 'http://example.org',
feed_url: 'http://example.org/feed.atom',
rewrite_rules: '',
scraper_rules: '',
crawler: false,
checked_at: '2017-12-22T21:06:03.133839-05:00',
etag_header: 'KyLxEflwnTGF5ecaiqZ2G0TxBCc',
last_modified_header: 'Sat, 23 Dec 2017 01:04:21 GMT',
parsing_error_count: 0,
parsing_error_message: '',
category: {
id: 22,
user_id: 123,
title: 'Another category'
},
icon: {
feed_id: 42,
icon_id: 84
}
}
};
describe('get_feed_entry', () => {
let miniflux = miniflux_server();
it('should get the feed\'s entry', () => {
let expected = dummy_entry;
let feed_id = 1;
let entry_id = 1;
mock.get(`/v1/feeds/${feed_id}/entries/${entry_id}`).reply(200, expected);
return miniflux.get_feed_entry(feed_id, entry_id)
.then(res => expect(res).to.deep.equal(expected));
});
});
describe('get_entry', () => {
let miniflux = miniflux_server();
it('should get the entry', () => {
let expected = dummy_entry;
let entry_id = 1;
mock.get(`/v1/entries/${entry_id}`).reply(200, expected);
return miniflux.get_entry(entry_id)
.then(res => expect(res).to.deep.equal(expected));
});
});
describe('get_feed_entries', () => {
let miniflux = miniflux_server();
it('should get feed entries without filter', () => {
let expected = [dummy_entry];
let feed_id = 1;
mock.get(`/v1/feeds/${feed_id}/entries`).reply(200, expected);
return miniflux.get_feed_entries(feed_id)
.then(res => expect(res).to.deep.equal(expected));
});
it('should get feed entries with limit', () => {
let expected = [dummy_entry];
let feed_id = 1;
mock.get(`/v1/feeds/${feed_id}/entries`)
.query({limit: 10})
.reply(200, expected);
return miniflux.get_feed_entries(feed_id, {limit: 10})
.then(res => expect(res).to.deep.equal(expected));
});
it('should get feed entries with offset', () => {
let expected = [dummy_entry];
let feed_id = 1;
mock.get(`/v1/feeds/${feed_id}/entries`)
.query({offset: 10})
.reply(200, expected);
return miniflux.get_feed_entries(feed_id, {offset: 10})
.then(res => expect(res).to.deep.equal(expected));
});
it('should get feed entries with direction', () => {
let expected = [dummy_entry];
let feed_id = 1;
mock.get(`/v1/feeds/${feed_id}/entries`)
.query({direction: EntryDirection.DESCENDING})
.reply(200, expected);
return miniflux.get_feed_entries(feed_id, {direction: EntryDirection.DESCENDING})
.then(res => expect(res).to.deep.equal(expected));
});
it('should get feed entries with specified status', () => {
let expected = [dummy_entry];
let feed_id = 1;
mock.get(`/v1/feeds/${feed_id}/entries`)
.query({status: EntryStatus.UNREAD})
.reply(200, expected);
return miniflux.get_feed_entries(feed_id, {status: EntryStatus.UNREAD})
.then(res => expect(res).to.deep.equal(expected));
});
it('should get feed entries with order', () => {
let expected = [dummy_entry];
let feed_id = 1;
mock.get(`/v1/feeds/${feed_id}/entries`)
.query({order: EntryOrder.PUBLISHED_AT})
.reply(200, expected);
return miniflux.get_feed_entries(feed_id, {order: EntryOrder.PUBLISHED_AT})
.then(res => expect(res).to.deep.equal(expected));
});
it('should get feed entries with all filters', () => {
let expected = [dummy_entry];
let feed_id = 1;
let filter = {
order: EntryOrder.PUBLISHED_AT,
status: EntryStatus.UNREAD,
direction: EntryDirection.DESCENDING,
limit: 10,
offset: 10,
}
mock.get(`/v1/feeds/${feed_id}/entries`)
.query(filter)
.reply(200, expected);
return miniflux.get_feed_entries(feed_id, filter)
.then(res => expect(res).to.deep.equal(expected));
});
});
describe('update_entries', () => {
let miniflux = miniflux_server();
it('should get feed entry', () => {
let entry_ids = [1, 2, 3];
let status = EntryStatus.UNREAD;
mock.filteringRequestBody(json_validate).put(`/v1/entries`).reply(204);
return miniflux.update_entries(entry_ids, status)
.then(res => expect(res).to.equal(null));
});
});
describe('toggle_bookmark', () => {
let miniflux = miniflux_server();
it('should toggle bookmark', () => {
let entry_id = 1;
mock.filteringRequestBody(json_validate).put(`/v1/entries/${entry_id}/bookmark`).reply(204);
return miniflux.toggle_bookmark(entry_id)
.then(res => expect(res).to.equal(null));
});
});
describe('categories', () => {
let miniflux = miniflux_server();
it('should get categories', () => {
let expected: Category[] = [{
id: 1,
user_id: 1,
title: 'Stuff',
}];
mock.filteringRequestBody(json_validate).get(`/v1/categories`).reply(200, expected);
return miniflux.categories()
.then(res => expect(res).to.deep.equal(expected));
});
});
describe('create_category', () => {
let miniflux = miniflux_server();
it('should create category', () => {
let expected: Category = {
id: 1,
user_id: 1,
title: 'Stuff',
};
mock.filteringRequestBody(json_validate).post(`/v1/categories`).reply(200, expected);
return miniflux.create_category('Stuff')
.then(res => expect(res).to.deep.equal(expected));
});
});
describe('update_category', () => {
let miniflux = miniflux_server();
it('should update category', () => {
let expected: Category = {
id: 1,
user_id: 1,
title: 'Stuff',
};
let category_id = 1;
mock.filteringRequestBody(json_validate).put(`/v1/categories/${category_id}`).reply(200, expected);
return miniflux.update_category(category_id, 'Stuff')
.then(res => expect(res).to.deep.equal(expected));
});
});
describe('delete_category', () => {
let miniflux = miniflux_server();
it('should delete category', () => {
let category_id = 1;
mock.filteringRequestBody(json_validate).delete(`/v1/categories/${category_id}`).reply(204);
return miniflux.delete_category(category_id)
.then(res => expect(res).to.equal(null));
});
});
describe('opml_export', () => {
let miniflux = miniflux_server();
it('should export opml', () => {
let expected = "<xml></xml>"
mock.filteringRequestBody(json_validate).get(`/v1/export`).reply(200, expected, {
"Content-Type": "text/xml"
});
return miniflux.ompl_export()
.then(res => expect(res).to.equal(expected));
});
});
describe('create_user', () => {
let miniflux = miniflux_server();
it('should create user', () => {
let expected: User = {
id: 1,
username: 'username',
language: 'en_US',
timezone: 'UTC',
theme: 'default',
entry_sorting_direction: EntryDirection.ASCENDING
}
mock.filteringRequestBody(json_validate).post(`/v1/users`).reply(200, expected);
miniflux.create_user('username', '****', false)
.then(res => expect(res).to.deep.equal(expected));
});
});
describe('update_user', () => {
let miniflux = miniflux_server();
it('should update user', () => {
let user_id = 1;
let expected: User = {
id: user_id,
username: 'username',
language: 'en_US',
timezone: 'UTC',
theme: 'default',
entry_sorting_direction: EntryDirection.ASCENDING
}
mock.filteringRequestBody(json_validate).put(`/v1/users/${user_id}`).reply(200, expected);
return miniflux.update_user(user_id, {
username: 'username',
password: '****',
is_admin: false,
theme: 'default',
language: 'en_US',
timezone: 'UTC',
}).then(res => expect(res).to.deep.equal(expected));
});
});
describe('users', () => {
let miniflux = miniflux_server();
it('should retrieve users', () => {
let expected: User[] = [{
id: 1,
username: 'username',
language: 'en_US',
timezone: 'UTC',
theme: 'default',
entry_sorting_direction: EntryDirection.ASCENDING
}];
mock.filteringRequestBody(json_validate).get(`/v1/users`).reply(200, expected);
return miniflux.users()
.then(res => expect(res).to.deep.equal(expected));
});
});
describe('get_user', () => {
let miniflux = miniflux_server();
it('should retrieve the user', () => {
let user_id = 1;
let expected: User = {
id: user_id,
username: 'username',
language: 'en_US',
timezone: 'UTC',
theme: 'default',
entry_sorting_direction: EntryDirection.ASCENDING
};
mock.filteringRequestBody(json_validate).get(`/v1/users/${user_id}`).reply(200, expected);
return miniflux.get_user(user_id)
.then(res => expect(res).to.deep.equal(expected));
});
});
describe('delete_user', () => {
let miniflux = miniflux_server();
it('should delete user', () => {
let user_id = 1;
mock.filteringRequestBody(json_validate).delete(`/v1/users/${user_id}`).reply(204);
return miniflux.delete_user(user_id)
.then(res => expect(res).to.equal(null));
});
});