Fixed a search bug and added simple unit tests for the chapters API
This commit is contained in:
parent
b8ce6ee29c
commit
3c5b93b3c2
7
.babelrc
7
.babelrc
|
@ -1,3 +1,8 @@
|
||||||
{
|
{
|
||||||
"presets": ["env", "react", "stage-3"]
|
"presets": ["env", "react", "stage-3"],
|
||||||
|
"env": {
|
||||||
|
"test": {
|
||||||
|
"plugins": ["transform-es2015-modules-commonjs"]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
1
TODO.txt
1
TODO.txt
|
@ -15,6 +15,7 @@ UX:
|
||||||
|
|
||||||
SHORT LIST:
|
SHORT LIST:
|
||||||
- More Responsive CSS
|
- More Responsive CSS
|
||||||
|
- Does Get Document List Action Need State?
|
||||||
- Add Date Created / Updated Stamps, Introduce Sort Options
|
- Add Date Created / Updated Stamps, Introduce Sort Options
|
||||||
- Testing
|
- Testing
|
||||||
- Python Unit Tests
|
- Python Unit Tests
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from flask import Blueprint, render_template, abort, jsonify, request
|
from flask import Blueprint, render_template, abort, jsonify, request
|
||||||
from elasticsearch import Elasticsearch
|
from elasticsearch import Elasticsearch
|
||||||
|
import json
|
||||||
|
|
||||||
# Elasticsearch local connection
|
# Elasticsearch local connection
|
||||||
# TODO: Extract to config
|
# TODO: Extract to config
|
||||||
|
@ -239,4 +240,6 @@ def delete_tag(id):
|
||||||
''' Basic Text Search '''
|
''' Basic Text Search '''
|
||||||
@api.route('/search/', methods=['POST'])
|
@api.route('/search/', methods=['POST'])
|
||||||
def search_text():
|
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)
|
||||||
|
|
|
@ -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'
|
||||||
|
}
|
||||||
|
};
|
|
@ -6,7 +6,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack-cli --config webpack.prod.js --mode=production",
|
"build": "webpack-cli --config webpack.prod.js --mode=production",
|
||||||
"watch": "webpack-cli --config webpack.dev.js --watch --mode=development",
|
"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",
|
"author": "Alex Hunt",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
@ -29,6 +29,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-core": "^6.26.0",
|
"babel-core": "^6.26.0",
|
||||||
|
"babel-jest": "^22.4.3",
|
||||||
"babel-loader": "^7.1.2",
|
"babel-loader": "^7.1.2",
|
||||||
"babel-preset-env": "^1.6.1",
|
"babel-preset-env": "^1.6.1",
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-preset-react": "^6.24.1",
|
||||||
|
@ -37,6 +38,7 @@
|
||||||
"css-loader": "^0.28.7",
|
"css-loader": "^0.28.7",
|
||||||
"extract-text-webpack-plugin": "^3.0.2",
|
"extract-text-webpack-plugin": "^3.0.2",
|
||||||
"file-loader": "^1.1.11",
|
"file-loader": "^1.1.11",
|
||||||
|
"jest": "^22.4.3",
|
||||||
"manifest-revision-webpack-plugin": "^0.4.1",
|
"manifest-revision-webpack-plugin": "^0.4.1",
|
||||||
"node-sass": "^4.6.0",
|
"node-sass": "^4.6.0",
|
||||||
"postcss-loader": "^2.0.8",
|
"postcss-loader": "^2.0.8",
|
||||||
|
|
40
setup.py
40
setup.py
|
@ -68,120 +68,120 @@ print 'Elasticsearch index created!'
|
||||||
|
|
||||||
# Sample data
|
# Sample data
|
||||||
SAMPLE_DATA = [
|
SAMPLE_DATA = [
|
||||||
{'_op_type': 'index','_type': 'chapter', '_source': {
|
{'_op_type': 'index','_type': 'chapter', '_id': 'AWNM3N3mxgFi4og697un', '_source': {
|
||||||
'number': 1,
|
'number': 1,
|
||||||
'title': 'Telemachus',
|
'title': 'Telemachus',
|
||||||
'html_source': get_chapter_text_from_seed_data('telem')
|
'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,
|
'number': 2,
|
||||||
'title': 'Nestor',
|
'title': 'Nestor',
|
||||||
'html_source': get_chapter_text_from_seed_data('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,
|
'number': 3,
|
||||||
'title': 'Proteus',
|
'title': 'Proteus',
|
||||||
'html_source': get_chapter_text_from_seed_data('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,
|
'number': 4,
|
||||||
'title': 'Calyspo',
|
'title': 'Calyspo',
|
||||||
'html_source': get_chapter_text_from_seed_data('calypso')
|
'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,
|
'number': 5,
|
||||||
'title': 'Lotus Eaters',
|
'title': 'Lotus Eaters',
|
||||||
'html_source': get_chapter_text_from_seed_data('lotus')
|
'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,
|
'number': 6,
|
||||||
'title': 'Hades',
|
'title': 'Hades',
|
||||||
'html_source': get_chapter_text_from_seed_data('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,
|
'number': 7,
|
||||||
'title': 'Aeolus',
|
'title': 'Aeolus',
|
||||||
'html_source': get_chapter_text_from_seed_data('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,
|
'number': 8,
|
||||||
'title': 'Lestrygonians',
|
'title': 'Lestrygonians',
|
||||||
'html_source': get_chapter_text_from_seed_data('lestry')
|
'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,
|
'number': 9,
|
||||||
'title': 'Scylla and Charybdis',
|
'title': 'Scylla and Charybdis',
|
||||||
'html_source': get_chapter_text_from_seed_data('scylla')
|
'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,
|
'number': 10,
|
||||||
'title': 'Wandering Rocks',
|
'title': 'Wandering Rocks',
|
||||||
'html_source': get_chapter_text_from_seed_data('wrocks')
|
'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,
|
'number': 11,
|
||||||
'title': 'Sirens',
|
'title': 'Sirens',
|
||||||
'html_source': get_chapter_text_from_seed_data('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,
|
'number': 12,
|
||||||
'title': 'Cyclops',
|
'title': 'Cyclops',
|
||||||
'html_source': get_chapter_text_from_seed_data('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,
|
'number': 13,
|
||||||
'title': 'Nausicaa',
|
'title': 'Nausicaa',
|
||||||
'html_source': get_chapter_text_from_seed_data('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,
|
'number': 14,
|
||||||
'title': 'Oxen of the Sun',
|
'title': 'Oxen of the Sun',
|
||||||
'html_source': get_chapter_text_from_seed_data('oxen')
|
'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,
|
'number': 15,
|
||||||
'title': 'Circe',
|
'title': 'Circe',
|
||||||
'html_source': get_chapter_text_from_seed_data('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,
|
'number': 16,
|
||||||
'title': 'Eumaeus',
|
'title': 'Eumaeus',
|
||||||
'html_source': get_chapter_text_from_seed_data('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,
|
'number': 17,
|
||||||
'title': 'Ithaca',
|
'title': 'Ithaca',
|
||||||
'html_source': get_chapter_text_from_seed_data('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,
|
'number': 18,
|
||||||
'title': 'Penelope',
|
'title': 'Penelope',
|
||||||
'html_source': get_chapter_text_from_seed_data('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',
|
'title': 'Kinch',
|
||||||
'html_source': 'A knife'
|
'html_source': 'A knife'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{'_op_type': 'index', '_type': 'note', '_source': {
|
{'_op_type': 'index', '_type': 'note','_id': 'AWNmqpdHxgFi4og697vS', '_source': {
|
||||||
'title': 'Lighthouse',
|
'title': 'Lighthouse',
|
||||||
'html_source': 'A lighthouse'
|
'html_source': 'A lighthouse'
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,7 +8,7 @@ const joyceAPI = store => next => action => {
|
||||||
switch(action.type) {
|
switch(action.type) {
|
||||||
case 'GET_DOCUMENT_LIST':
|
case 'GET_DOCUMENT_LIST':
|
||||||
if (action.status === 'request') {
|
if (action.status === 'request') {
|
||||||
api.HTTPGetDocumentList(action.docType, action.state).then(response =>
|
api.HTTPGetDocumentList(action.docType).then(response =>
|
||||||
store.dispatch(actions.getDocumentList(response))
|
store.dispatch(actions.getDocumentList(response))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,12 @@ import axios from 'axios'
|
||||||
|
|
||||||
const apiRoute = '/api/'
|
const apiRoute = '/api/'
|
||||||
const api = {
|
const api = {
|
||||||
HTTPGetDocumentList: (docType, state) =>
|
HTTPGetDocumentList: (docType) =>
|
||||||
axios.get(apiRoute + docType).then(res => {
|
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 => {
|
}).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) =>
|
HTTPGetDocumentText: (id, docType, state) =>
|
||||||
axios.get(apiRoute + docType + '/' + id).then(res => {
|
axios.get(apiRoute + docType + '/' + id).then(res => {
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
.chapter_button > button {
|
.chapter_button > button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0.25% 0;
|
margin: 0.25% 0;
|
||||||
padding: 0.2rem 1rem;
|
padding: 0.2rem 0;
|
||||||
font-size: 1rem;
|
font-size: 1.5vw;
|
||||||
box-shadow: 2px 5px 10px 1px rgba(0, 0, 0, 0.3);
|
box-shadow: 2px 5px 10px 1px rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
module.exports = 'test-file-stub';
|
|
@ -0,0 +1 @@
|
||||||
|
module.exports = {};
|
|
@ -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')
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue