Skip to content

Commit

Permalink
Merge pull request #1 from nhsuk/save-current-url
Browse files Browse the repository at this point in the history
Save current url
  • Loading branch information
prembonsall authored Mar 30, 2020
2 parents c3d340a + b4e8493 commit d87b600
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 12 deletions.
2 changes: 2 additions & 0 deletions lib/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
12 changes: 10 additions & 2 deletions lib/database.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
22 changes: 20 additions & 2 deletions lib/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 };
};

/**
Expand Down
22 changes: 18 additions & 4 deletions lib/validation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
46 changes: 42 additions & 4 deletions tests/integration/api.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -40,22 +43,29 @@ 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);
expect(data[0]).toEqual(
expect.objectContaining({
isSatisfied: true,
token: expect.stringMatching(UUID_REGEX),
url: 'https://example.com/my-test-page/',
})
);
});
});

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;
};
Expand Down Expand Up @@ -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 = {
Expand All @@ -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/',
})
);
});
Expand Down

0 comments on commit d87b600

Please sign in to comment.