Fixed a search bug and added simple unit tests for the chapters API

This commit is contained in:
Alex Hunt 2018-05-18 19:37:03 -04:00
parent b8ce6ee29c
commit 3c5b93b3c2
12 changed files with 117 additions and 29 deletions

View File

@ -1,3 +1,8 @@
{
"presets": ["env", "react", "stage-3"]
"presets": ["env", "react", "stage-3"],
"env": {
"test": {
"plugins": ["transform-es2015-modules-commonjs"]
}
}
}

View File

@ -15,6 +15,7 @@ UX:
SHORT LIST:
- More Responsive CSS
- Does Get Document List Action Need State?
- Add Date Created / Updated Stamps, Introduce Sort Options
- Testing
- Python Unit Tests

View File

@ -1,5 +1,6 @@
from flask import Blueprint, render_template, abort, jsonify, request
from elasticsearch import Elasticsearch
import json
# Elasticsearch local connection
# TODO: Extract to config
@ -239,4 +240,6 @@ def delete_tag(id):
''' Basic Text Search '''
@api.route('/search/', methods=['POST'])
def search_text():
return jsonify(es_search_text(request.data['data']))
data = json.loads(request.data)
results = es_search_text(data.get('data'))
return jsonify(results)

9
jest.config.js Normal file
View File

@ -0,0 +1,9 @@
module.exports = {
verbose: true,
testURL: 'http://localhost:5000',
testEnvironment: 'jsdom',
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)$': '<rootDir>/tests/__mocks__/fileMock.js',
'\\.(css|less)$': '<rootDir>/tests/__mocks__/styleMock.js'
}
};

View File

@ -6,7 +6,7 @@
"scripts": {
"build": "webpack-cli --config webpack.prod.js --mode=production",
"watch": "webpack-cli --config webpack.dev.js --watch --mode=development",
"test": "echo \"Error: no test specified\" && exit 1"
"test": "python setup.py && jest --config jest.config.js --no-cache && python setup.py"
},
"author": "Alex Hunt",
"license": "ISC",
@ -29,6 +29,7 @@
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-jest": "^22.4.3",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1",
@ -37,6 +38,7 @@
"css-loader": "^0.28.7",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.11",
"jest": "^22.4.3",
"manifest-revision-webpack-plugin": "^0.4.1",
"node-sass": "^4.6.0",
"postcss-loader": "^2.0.8",

View File

@ -68,120 +68,120 @@ print 'Elasticsearch index created!'
# Sample data
SAMPLE_DATA = [
{'_op_type': 'index','_type': 'chapter', '_source': {
{'_op_type': 'index','_type': 'chapter', '_id': 'AWNM3N3mxgFi4og697un', '_source': {
'number': 1,
'title': 'Telemachus',
'html_source': get_chapter_text_from_seed_data('telem')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vA', '_source': {
'number': 2,
'title': 'Nestor',
'html_source': get_chapter_text_from_seed_data('nestor')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vB', '_source': {
'number': 3,
'title': 'Proteus',
'html_source': get_chapter_text_from_seed_data('proteus')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vC', '_source': {
'number': 4,
'title': 'Calyspo',
'html_source': get_chapter_text_from_seed_data('calypso')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vD', '_source': {
'number': 5,
'title': 'Lotus Eaters',
'html_source': get_chapter_text_from_seed_data('lotus')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vE', '_source': {
'number': 6,
'title': 'Hades',
'html_source': get_chapter_text_from_seed_data('hades')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vF', '_source': {
'number': 7,
'title': 'Aeolus',
'html_source': get_chapter_text_from_seed_data('aeolus')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vG', '_source': {
'number': 8,
'title': 'Lestrygonians',
'html_source': get_chapter_text_from_seed_data('lestry')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vH', '_source': {
'number': 9,
'title': 'Scylla and Charybdis',
'html_source': get_chapter_text_from_seed_data('scylla')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vI', '_source': {
'number': 10,
'title': 'Wandering Rocks',
'html_source': get_chapter_text_from_seed_data('wrocks')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vJ', '_source': {
'number': 11,
'title': 'Sirens',
'html_source': get_chapter_text_from_seed_data('sirens')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vK', '_source': {
'number': 12,
'title': 'Cyclops',
'html_source': get_chapter_text_from_seed_data('cyclops')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vL', '_source': {
'number': 13,
'title': 'Nausicaa',
'html_source': get_chapter_text_from_seed_data('nausicaa')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vM', '_source': {
'number': 14,
'title': 'Oxen of the Sun',
'html_source': get_chapter_text_from_seed_data('oxen')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vN', '_source': {
'number': 15,
'title': 'Circe',
'html_source': get_chapter_text_from_seed_data('circe')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vO', '_source': {
'number': 16,
'title': 'Eumaeus',
'html_source': get_chapter_text_from_seed_data('eumaeus')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vP', '_source': {
'number': 17,
'title': 'Ithaca',
'html_source': get_chapter_text_from_seed_data('ithaca')
},
},
{'_op_type': 'index', '_type': 'chapter', '_source': {
{'_op_type': 'index', '_type': 'chapter','_id': 'AWNmqpdHxgFi4og697vQ', '_source': {
'number': 18,
'title': 'Penelope',
'html_source': get_chapter_text_from_seed_data('penelope')
},
},
{'_op_type': 'index', '_type': 'note', '_source': {
{'_op_type': 'index', '_type': 'note','_id': 'AWNmqpdHxgFi4og697vR', '_source': {
'title': 'Kinch',
'html_source': 'A knife'
},
},
{'_op_type': 'index', '_type': 'note', '_source': {
{'_op_type': 'index', '_type': 'note','_id': 'AWNmqpdHxgFi4og697vS', '_source': {
'title': 'Lighthouse',
'html_source': 'A lighthouse'
},

View File

@ -8,7 +8,7 @@ const joyceAPI = store => next => action => {
switch(action.type) {
case 'GET_DOCUMENT_LIST':
if (action.status === 'request') {
api.HTTPGetDocumentList(action.docType, action.state).then(response =>
api.HTTPGetDocumentList(action.docType).then(response =>
store.dispatch(actions.getDocumentList(response))
)
}

View File

@ -2,11 +2,12 @@ import axios from 'axios'
const apiRoute = '/api/'
const api = {
HTTPGetDocumentList: (docType, state) =>
HTTPGetDocumentList: (docType) =>
axios.get(apiRoute + docType).then(res => {
return {status: 'success', docType: docType, state: state, data: res.data}
return {status: 'success', docType: docType, data: res.data}
}).catch(error => {
return {status: 'error', docType: docType, state: state, data: error}
console.log(error)
return {status: 'error', docType: docType, data: error}
}),
HTTPGetDocumentText: (id, docType, state) =>
axios.get(apiRoute + docType + '/' + id).then(res => {

View File

@ -23,8 +23,8 @@
.chapter_button > button {
width: 100%;
margin: 0.25% 0;
padding: 0.2rem 1rem;
font-size: 1rem;
padding: 0.2rem 0;
font-size: 1.5vw;
box-shadow: 2px 5px 10px 1px rgba(0, 0, 0, 0.3);
}

View File

@ -0,0 +1 @@
module.exports = 'test-file-stub';

View File

@ -0,0 +1 @@
module.exports = {};

65
tests/api.test.js Normal file
View File

@ -0,0 +1,65 @@
const api = require('../src/modules/api')
// beforeEach(() => {
// })
// Chapters
test('API returned chapter list', () => {
expect.assertions(3)
return api.default.HTTPGetDocumentList('chapters').then(response => {
expect(response.status).toBe('success')
expect(response.docType).toBe('chapters')
expect(response.data.length).toBe(18)
})
})
test('API returned chapter document', () => {
expect.assertions(5)
return api.default.HTTPGetDocumentText('AWNM3N3mxgFi4og697un', 'chapters').then(response => {
expect(response.status).toBe('success')
expect(response.docType).toBe('chapters')
expect(response.data.title).toBe('Telemachus')
expect(response.data.number).toBe(1)
expect(response.data.html_source).toBeDefined()
})
})
test('API successfully edited document', () => {
expect.assertions(3)
const updatedChapter = {
number: 1,
title: 'Odyssey',
html_source: 'No more text.'
}
return api.default.HTTPPostWriteDocument('AWNM3N3mxgFi4og697un', 'chapters', updatedChapter).then(response => {
console.log(response.data)
expect(response.status).toBe('success')
expect(response.data.length).toBe(18)
expect(response.data[0].title).toBe('Odyssey')
})
})
test('API successfully created document', () => {
expect.assertions(3)
const newChapter = {
title: 'Test',
number: 19,
html_source: '<p>Ithaca!</p>'
}
return api.default.HTTPPutCreateDocument('chapters', newChapter).then(response => {
expect(response.status).toBe('success')
expect(response.data.length).toBe(19)
expect(response.data.slice(-1)[0].title).toBe('Test')
})
})
test('API successfully deleted document', () => {
expect.assertions(3)
return api.default.HTTPDeleteDocument('AWNM3N3mxgFi4og697un', 'chapters').then(response => {
expect(response.status).toBe('success')
expect(response.data.length).toBe(18)
expect(response.data[0].title).toBe('Nestor')
})
})