server: tests: add tests for feed-monitor endpoints

This commit is contained in:
Jesse Chan
2020-10-24 19:48:41 +08:00
parent 265032d3d5
commit d4a8b03928
5 changed files with 348 additions and 12 deletions

View File

@@ -0,0 +1,334 @@
import fs from 'fs';
import supertest from 'supertest';
import app from '../../app';
import {getAuthToken} from './auth';
import {getTempPath} from '../../models/TemporaryStorage';
import type {AddFeedOptions, AddRuleOptions, ModifyFeedOptions} from '../../../shared/types/api/feed-monitor';
import type {Feed, Rule} from '../../../shared/types/Feed';
const request = supertest(app);
const authToken = `jwt=${getAuthToken('_config')}`;
const feed: AddFeedOptions = {
label: 'NYTimes',
url: 'https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml',
interval: 1,
};
let addedFeed: Feed | null = null;
describe('GET /api/feed-monitor', () => {
it('Expects nothing, yet. Verifies data structure.', (done) => {
request
.get('/api/feed-monitor')
.send()
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, res) => {
if (err) done(err);
const expectedResponse = {
feeds: [],
rules: [],
};
expect(res.body).toStrictEqual(expectedResponse);
done();
});
});
});
describe('PUT /api/feed-monitor/feeds', () => {
it('Subscribes to a feed', (done) => {
request
.put('/api/feed-monitor/feeds')
.send(feed)
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, res) => {
if (err) done(err);
const response: Feed = res.body;
expect(response).toMatchObject(feed);
expect(response._id).not.toBeNull();
expect(typeof response._id).toBe('string');
addedFeed = response;
done();
});
});
it('GET /api/feed-monitor to verify added feed', (done) => {
request
.get('/api/feed-monitor')
.send()
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, res) => {
if (err) done(err);
const expectedResponse = {
feeds: [addedFeed],
rules: [],
};
expect(res.body).toStrictEqual(expectedResponse);
done();
});
});
it('GET /api/feed-monitor/feeds to verify added feed', (done) => {
request
.get('/api/feed-monitor/feeds')
.send()
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, res) => {
if (err) done(err);
expect(res.body).toStrictEqual([addedFeed]);
done();
});
});
});
describe('PATCH /api/feed-monitor/feeds/{id}', () => {
const modifyFeedOptions: ModifyFeedOptions = {
label: 'Modified Feed',
};
it('Modifies the added feed', (done) => {
expect(addedFeed).not.toBe(null);
if (addedFeed == null) return;
request
.patch(`/api/feed-monitor/feeds/${addedFeed._id}`)
.send(modifyFeedOptions)
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, _res) => {
if (err) done(err);
done();
});
});
it('GET /api/feed-monitor/feeds/{id} to verify modified feed', (done) => {
expect(addedFeed).not.toBe(null);
if (addedFeed == null) return;
request
.get(`/api/feed-monitor/feeds/${addedFeed._id}`)
.send()
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, res) => {
if (err) done(err);
addedFeed = {...(addedFeed as Feed), ...modifyFeedOptions};
expect(res.body).toStrictEqual([addedFeed]);
done();
});
});
});
describe('GET /api/feed-monitor/feeds/{id}/items', () => {
it('Requests items of the feed', (done) => {
expect(addedFeed).not.toBe(null);
if (addedFeed == null) return;
request
.get(`/api/feed-monitor/feeds/${addedFeed._id}/items`)
.send()
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, res) => {
if (err) done(err);
expect(Array.isArray(res.body)).toBe(true);
done();
});
});
});
const tempDirectory = getTempPath('download');
fs.mkdirSync(tempDirectory, {recursive: true});
let addedRule: Rule;
describe('GET /api/feed-monitor/rules', () => {
it('Expects nothing, verifies the response is an array', (done) => {
request
.get(`/api/feed-monitor/rules`)
.send()
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, res) => {
if (err) done(err);
expect(Array.isArray(res.body)).toBe(true);
done();
});
});
});
describe('PUT /api/feed-monitor/rules', () => {
const rule: AddRuleOptions = {
label: 'Test rule',
feedIDs: [''],
match: '',
exclude: '.*',
destination: tempDirectory,
tags: ['FeedItem'],
startOnLoad: false,
};
it('Adds an automation rule', (done) => {
expect(addedFeed).not.toBe(null);
if (addedFeed == null) return;
rule.feedIDs = [addedFeed._id];
request
.put('/api/feed-monitor/rules')
.send(rule)
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, res) => {
if (err) done(err);
const response: Rule = res.body;
expect(response).toMatchObject(rule);
expect(response._id).not.toBeNull();
expect(typeof response._id).toBe('string');
addedRule = response;
done();
});
});
it('GET /api/feed-monitor to verify added rule', (done) => {
request
.get('/api/feed-monitor')
.send()
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, res) => {
if (err) done(err);
expect(res.body.rules).toStrictEqual([addedRule]);
done();
});
});
it('GET /api/feed-monitor/rules to verify added rule', (done) => {
request
.get('/api/feed-monitor/rules')
.send()
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, res) => {
if (err) done(err);
expect(res.body).toStrictEqual([addedRule]);
done();
});
});
});
describe('DELETE /api/feed-monitor/{id}', () => {
it('Deletes the added feed', (done) => {
expect(addedFeed).not.toBe(null);
if (addedFeed == null) return;
request
.delete(`/api/feed-monitor/${addedFeed._id}`)
.send()
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, _res) => {
if (err) done(err);
done();
});
});
it('Deletes the added rule', (done) => {
request
.delete(`/api/feed-monitor/${addedRule._id}`)
.send()
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, _res) => {
if (err) done(err);
done();
});
});
it('GET /api/feed-monitor to verify feed and rule are deleted', (done) => {
request
.get('/api/feed-monitor')
.send()
.set('Cookie', [authToken])
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
.end((err, res) => {
if (err) done(err);
const expectedResponse = {
feeds: [],
rules: [],
};
expect(res.body).toStrictEqual(expectedResponse);
done();
});
});
});

View File

@@ -50,18 +50,19 @@ router.delete<{id: string}>('/:id', (req, res) => {
});
/**
* GET /api/feed-monitor/feeds
* GET /api/feed-monitor/feeds/{id?}
* @summary Gets subscribed feeds
* @tags Feeds
* @security User
* @param id.path.optional - Unique ID of the feed subscription
* @return {Array<Feed>}} 200 - success response - application/json
* @return {Error} 500 - failure response - application/json
*/
router.get('/feeds', (req, res) => {
router.get<{id?: string}>('/feeds/:id?', (req, res) => {
const callback = ajaxUtil.getResponseFn(res);
req.services?.feedService
.getFeeds()
.getFeeds(req.params.id)
.then((feeds) => {
callback(feeds);
})
@@ -173,8 +174,8 @@ router.put<unknown, unknown, AddRuleOptions>('/rules', (req, res) => {
req.services?.feedService
.addRule(req.body)
.then(() => {
callback(null);
.then((rule) => {
callback(rule);
})
.catch((error) => {
callback(null, error);

View File

@@ -84,11 +84,13 @@ class FeedService extends BaseService {
throw new Error();
}
// JSON.parse(JSON.stringify()) to remove undefined properties
modifiedFeedReader.stopReader();
modifiedFeedReader.modify({feedLabel: label, url, interval});
modifiedFeedReader.modify(JSON.parse(JSON.stringify({feedLabel: label, url, interval})));
return new Promise<void>((resolve, reject) => {
this.db.update({_id: id}, {$set: {url, label, interval}}, {}, (err) => {
this.db.update({_id: id}, {$set: JSON.parse(JSON.stringify({label, url, interval}))}, {}, (err) => {
if (err) {
reject(err);
return;
@@ -160,9 +162,9 @@ class FeedService extends BaseService {
});
}
async getFeeds(): Promise<Array<Feed>> {
async getFeeds(id?: string): Promise<Array<Feed>> {
return new Promise<Array<Feed>>((resolve, reject) => {
this.db.find({type: 'feed'}, (err: Error | null, feeds: Array<Feed>) => {
this.db.find(id ? {_id: id} : {type: 'feed'}, (err: Error | null, feeds: Array<Feed>) => {
if (err) {
reject(err);
return;

View File

@@ -14,6 +14,5 @@
},
"outDir": "../dist"
},
"include": ["./**/*.ts", "../shared/**/*.ts", "../config.js", "../config.ts"],
"exclude": ["node_modules", "**/*.spec.ts", "**/*.test.ts"]
"include": ["./**/*.ts", "../shared/**/*.ts", "../config.js", "../config.ts"]
}

View File

@@ -6,7 +6,7 @@ export interface Feed {
label: string;
// URL of the feed.
url: string;
// Interval between checking the feed for new items.
// Interval between checking the feed for new items. (in minutes)
interval: number;
// How many times rules have matched items of the feed.
count?: number;