From a19c89a2f85fe6eec327e52d044a38410903615e Mon Sep 17 00:00:00 2001 From: Mike Monteith Date: Mon, 23 Mar 2020 17:14:27 +0000 Subject: [PATCH 1/2] Add url parameter to the tests --- lib/database.test.js | 12 +++++++-- lib/validation.test.js | 22 ++++++++++++++--- tests/integration/api.test.js | 46 ++++++++++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 10 deletions(-) diff --git a/lib/database.test.js b/lib/database.test.js index 333bf34..453094a 100644 --- a/lib/database.test.js +++ b/lib/database.test.js @@ -27,17 +27,25 @@ describe('database', () => { }); it('inserts true answer into database', async () => { - await database.saveInitialResponse({ isSatisfied: true }); + await database.saveInitialResponse({ + isSatisfied: true, + url: 'https://example.com/my-test-page/', + }); const data = await db.collection('feedback').find({}).toArray(); expect(data.length).toBe(1); expect(data[0].isSatisfied).toBe(true); + expect(data[0].url).toBe('https://example.com/my-test-page/'); }); it('inserts false answer into database', async () => { - await database.saveInitialResponse({ isSatisfied: false }); + await database.saveInitialResponse({ + isSatisfied: false, + url: 'https://example.com/my-test-page/', + }); const data = await db.collection('feedback').find({}).toArray(); expect(data.length).toBe(1); expect(data[0].isSatisfied).toBe(false); + expect(data[0].url).toBe('https://example.com/my-test-page/'); }); it('inserts text comment into database', async () => { diff --git a/lib/validation.test.js b/lib/validation.test.js index 38a443e..4188702 100644 --- a/lib/validation.test.js +++ b/lib/validation.test.js @@ -4,30 +4,44 @@ const validation = require('./validation.js'); describe('validate initial response', () => { it('when isSatisfied is true', () => { - const dirtyData = { isSatisfied: true }; + const dirtyData = { isSatisfied: true, url: 'https://example.com/' }; const cleanData = validation.validateInitialResponse(dirtyData); expect(cleanData).toEqual(dirtyData); }); it('when isSatisfied is false', () => { - const dirtyData = { isSatisfied: false }; + const dirtyData = { isSatisfied: false, url: 'https://example.com/' }; const cleanData = validation.validateInitialResponse(dirtyData); expect(cleanData).toEqual(dirtyData); }); it('when isSatisfied is invalid', () => { - const dirtyData = { isSatisfied: null }; + const dirtyData = { isSatisfied: null, url: 'https://example.com/' }; expect(() => { validation.validateInitialResponse(dirtyData); }).toThrow('isSatisfied must be true or false'); }); it('when isSatisfied is missing', () => { - const dirtyData = {}; + const dirtyData = { url: 'https://example.com/' }; expect(() => { validation.validateInitialResponse(dirtyData); }).toThrow('isSatisfied must be true or false'); }); + + it('when url is missing', () => { + const dirtyData = { isSatisfied: true }; + expect(() => { + validation.validateInitialResponse(dirtyData); + }).toThrow('url must be a valid URL'); + }); + + it('when url is not a valid URL', () => { + const dirtyData = { isSatisfied: true, url: 'bobloblawlawblog' }; + expect(() => { + validation.validateInitialResponse(dirtyData); + }).toThrow('url must be a valid URL'); + }); }); describe('validate text comments', () => { diff --git a/tests/integration/api.test.js b/tests/integration/api.test.js index 8cab6e1..3cd0b59 100644 --- a/tests/integration/api.test.js +++ b/tests/integration/api.test.js @@ -28,7 +28,10 @@ const UUID_REGEX = /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}- describe('API endpoint /satisfied/', () => { it('returns status ok response', async () => { - const payload = { isSatisfied: true }; + const payload = { + isSatisfied: true, + url: 'https://example.com/my-test-page/', + }; const response = await axios.post('http://localhost:7071/satisfied/', payload); expect(response.status).toEqual(200); expect(response.data).toEqual( @@ -40,7 +43,10 @@ describe('API endpoint /satisfied/', () => { }); it('saves into the database', async () => { - const payload = { isSatisfied: true }; + const payload = { + isSatisfied: true, + url: 'https://example.com/my-test-page/', + }; await axios.post('http://localhost:7071/satisfied/', payload); const data = await db.collection('feedback').find({}).toArray(); expect(data.length).toBe(1); @@ -48,6 +54,7 @@ describe('API endpoint /satisfied/', () => { expect.objectContaining({ isSatisfied: true, token: expect.stringMatching(UUID_REGEX), + url: 'https://example.com/my-test-page/', }) ); }); @@ -55,7 +62,10 @@ describe('API endpoint /satisfied/', () => { describe('API endpoint /comments/', () => { const getToken = async () => { - const payload = { isSatisfied: true }; + const payload = { + isSatisfied: true, + url: 'https://example.com/my-test-page/', + }; const response = await axios.post('http://localhost:7071/satisfied/', payload); return response.data.token; }; @@ -95,7 +105,34 @@ describe('API endpoint /comments/', () => { }); it('is associated with satisfaction response via token', async () => { - const satisfiedPayload = { isSatisfied: false }; + const satisfiedPayload = { + isSatisfied: false, + url: 'https://example.com/my-test-page/', + }; + const response = await axios.post('http://localhost:7071/satisfied/', satisfiedPayload); + + const payload = { + comments: 'Could do with a bit more cowbell.', + token: response.data.token, + }; + await axios.post('http://localhost:7071/comments/', payload); + const data = await db.collection('feedback').find({}).toArray(); + expect(data.length).toBe(1); + + // comment data should be associated with the earlier "satisfied" API call + expect(data[0]).toEqual( + expect.objectContaining({ + comments: 'Could do with a bit more cowbell.', + isSatisfied: false, + }) + ); + }); + + it('is associated with url from satisfaction request', async () => { + const satisfiedPayload = { + isSatisfied: false, + url: 'https://example.com/my-test-page/', + }; const response = await axios.post('http://localhost:7071/satisfied/', satisfiedPayload); const payload = { @@ -111,6 +148,7 @@ describe('API endpoint /comments/', () => { expect.objectContaining({ comments: 'Could do with a bit more cowbell.', isSatisfied: false, + url: 'https://example.com/my-test-page/', }) ); }); From b4e84933f9d9ab01716159deeb789963aa3b3799 Mon Sep 17 00:00:00 2001 From: Mike Monteith Date: Mon, 23 Mar 2020 17:15:25 +0000 Subject: [PATCH 2/2] Satisfy url parameter tests --- lib/database.js | 2 ++ lib/index.js | 1 + lib/validation.js | 22 ++++++++++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/database.js b/lib/database.js index 3d9740c..0d135e4 100644 --- a/lib/database.js +++ b/lib/database.js @@ -40,6 +40,8 @@ const insertOrUpdate = async (data) => { /** * @param {Object} payload - data to save for the initial response + * @param {boolean} payload.isSatisfied - is the user satisfied? + * @param {string} payload.url - URL that the user is commenting on * @returns {Promise} */ module.exports.saveInitialResponse = (payload) => { diff --git a/lib/index.js b/lib/index.js index c838550..cec25e5 100644 --- a/lib/index.js +++ b/lib/index.js @@ -27,6 +27,7 @@ module.exports.handleRequest = async (context, req, requestType) => { token = await database.saveInitialResponse({ isSatisfied: req.body.isSatisfied, token, + url: req.body.url, }); } if (requestType === requestTypes.COMMENTS) { diff --git a/lib/validation.js b/lib/validation.js index 42a84a2..4097625 100644 --- a/lib/validation.js +++ b/lib/validation.js @@ -26,6 +26,20 @@ class ValidationError extends HttpError { module.exports.ValidationError = ValidationError; +/** + * Validates if a given test string is a valid URL + * @param {string} test - The string to test + * @returns {boolean} - True if the test string is a valid URL, otherwise false. + */ +const isValidUrl = (test) => { + try { + new URL(test); // eslint-disable-line no-new + return true; + } catch (_) { + return false; + } +}; + /** * Validate the incoming data and return clean data for saving to the database * @param {Object} data - Object containing initial response data @@ -34,13 +48,17 @@ module.exports.ValidationError = ValidationError; * @throws {ValidationError} error if data format is invalid */ module.exports.validateInitialResponse = (data) => { - const { isSatisfied, token } = data; + const { isSatisfied, token, url } = data; if (isSatisfied !== true && isSatisfied !== false) { throw new ValidationError('isSatisfied must be true or false'); } - return { isSatisfied, token }; + if (!isValidUrl(url)) { + throw new ValidationError('url must be a valid URL'); + } + + return { isSatisfied, token, url }; }; /**