Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions common/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["es2015", "react"]
}
1 change: 1 addition & 0 deletions common/actionTypes/todos.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export const setVisibilityFilter = buildTodosActionType('setVisibilityFilter');
export const getTodos = buildTodosActionType('getTodos');
export const getTodosSuccess = buildTodosActionType('getTodosSuccess');
export const getTodosError = buildTodosActionType('getTodosError');
export const timeoutTodo = buildTodosActionType('timeoutTodo');
1 change: 1 addition & 0 deletions common/actions/todos.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export const setVisibilityFilter = createAction(todos.setVisibilityFilter);
export const getTodos = createAction(todos.getTodos);
export const getTodosSuccess = createAction(todos.getTodosSuccess);
export const getTodosError = createAction(todos.getTodosError);
export const timeoutTodo = createAction(todos.timeoutTodo);
71 changes: 51 additions & 20 deletions common/api/todos.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,77 @@ import type { descriptionAndId, toggle } from 'todosIndex/types';

// TODO: Add an environment variable management setup that allows env vars
// to be used with both React and React Native

const apiConfig = { remoteEndpoint: 'http://localhost:3000' };

export const todosScope = (path: ?string) => {
return `${apiConfig.remoteEndpoint}/api/v1/todos${path || ''}`;
}

export const addRemoteEndpoint = (remoteEndpoint: string) => {
export const addRemoteEndpoint = async (remoteEndpoint: string) => {
apiConfig.remoteEndpoint = remoteEndpoint; //TODO: Check if the slash exists and remove it
}

export const timeoutDelay = (time: number) => {
return new Promise(resolve => {
setTimeout(resolve(false), time);
});
}

// /api/v1/todos
export const addTodo = (description: string, completed: boolean = false) => {
const url = todosScope();
const todoParams = { todo: { description, completed } };
return apiCall.post({ url, data: todoParams });
export const addTodo = async (description: string, completed: boolean = false) => {
try {
const url = todosScope();
const todoParams = { todo: { description, completed } };
const result = await apiCall.post({ url, data: todoParams });
return ({ result });
} catch (error) {
return ({ error });
}
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return either a result or error key depending on the API call outcome.,

};

// /api/v1/todos
export const editTodo = (todo: descriptionAndId) => {
const url = todosScope(`/${todo.id}`);
const todoParams = { todo: { description: todo.description } };
return apiCall.put({ url, data: todoParams });
export const editTodo = async (todo: descriptionAndId) => {
try {
const url = todosScope(`/${todo.id}`);
const todoParams = { todo: { description: todo.description } };
const result = await apiCall.put({ url, data: todoParams });
return ({ result });
} catch (error) {
return ({ error });
}
};

// /api/v1/todos/:todo_id
export const removeTodo = (todoId: number) => {
const url = todosScope(`/${todoId}`);
return apiCall.delete({ url });
export const removeTodo = async (todoId: number) => {
try {
const url = todosScope(`/${todoId}`);
const result = await apiCall.delete({ url });
retrun ({ result });
} catch (error) {
return ({ error });
}
};

// /api/v1/todos
export const toggleTodo = (todo: toggle) => {
const url = todosScope(`/${todo.id}`);
const todoParams = { todo: { completed: todo.completed } };
return apiCall.put({ url, data: todoParams });
export const toggleTodo = async (todo: toggle) => {
try {
const url = todosScope(`/${todo.id}`);
const todoParams = { todo: { completed: todo.completed } };
const result = await apiCall.put({ url, data: todoParams });
return ({ result });
} catch (error) {
return ({ error });
}
};

// /api/v1/todos
export const getTodos = () => {
const url = todosScope('/');
return apiCall.get({ url });
export const getTodos = async () => {
try {
const url = todosScope('/');
const result = await apiCall.get({ url });
return ({ result });
} catch (error) {
return ({ error });
}
}
74 changes: 36 additions & 38 deletions common/junit.xml
Original file line number Diff line number Diff line change
@@ -1,28 +1,12 @@
<testsuites name="jest tests">
<testsuite name="libs/utils/api" tests="5" errors="0" failures="0" skipped="0" timestamp="2017-04-25T10:48:35" time="0.749">
<testcase classname="libs/utils/api { buildUrl } combines a path and an object of key values into a url with a query" name="libs/utils/api { buildUrl } combines a path and an object of key values into a url with a query" time="0.004">
<testsuite name="raceCallApi Generator Function" tests="2" errors="0" failures="0" skipped="0" timestamp="2017-05-14T10:07:48" time="0.466">
<testcase classname="raceCallApi Generator Function handles async responses" name="raceCallApi Generator Function handles async responses" time="0.005">
</testcase>
<testcase classname="libs/utils/api { buildUrl } removes keys that have null values" name="libs/utils/api { buildUrl } removes keys that have null values" time="0.001">
</testcase>
<testcase classname="libs/utils/api { parseRawParams } accepts todo params" name="libs/utils/api { parseRawParams } accepts todo params" time="0.001">
</testcase>
<testcase classname="libs/utils/api { parseRawParams } accepts remote URLs" name="libs/utils/api { parseRawParams } accepts remote URLs" time="0.001">
</testcase>
<testcase classname="libs/utils/api { buildReqUrl } accepts a full URL" name="libs/utils/api { buildReqUrl } accepts a full URL" time="0">
</testcase>
</testsuite>
<testsuite name="addTodo Saga" tests="4" errors="0" failures="0" skipped="0" timestamp="2017-04-25T10:48:36" time="0.178">
<testcase classname="addTodo Saga handles async responses" name="addTodo Saga handles async responses" time="0.007">
</testcase>
<testcase classname="editTodo Saga handles async responses" name="editTodo Saga handles async responses" time="0.002">
</testcase>
<testcase classname="removeTodo Saga handles async responses" name="removeTodo Saga handles async responses" time="0.001">
</testcase>
<testcase classname="toggleTodo Saga handles async responses" name="toggleTodo Saga handles async responses" time="0.001">
<testcase classname="raceCallApi Generator Function handles timed out responses (over 6000 ms)" name="raceCallApi Generator Function handles timed out responses (over 6000 ms)" time="0.001">
</testcase>
</testsuite>
<testsuite name="addTodoSuccess" tests="5" errors="0" failures="0" skipped="0" timestamp="2017-04-25T10:48:36" time="0.114">
<testcase classname="addTodoSuccess adds todo to state" name="addTodoSuccess adds todo to state" time="0.003">
<testsuite name="addTodoSuccess" tests="5" errors="0" failures="0" skipped="0" timestamp="2017-05-14T10:07:49" time="0.119">
<testcase classname="addTodoSuccess adds todo to state" name="addTodoSuccess adds todo to state" time="0.005">
</testcase>
<testcase classname="editTodoDescription edits the description of selected Todo" name="editTodoDescription edits the description of selected Todo" time="0.002">
</testcase>
Expand All @@ -33,19 +17,7 @@
<testcase classname="toggleTodoSuccess merges toggled todo into state" name="toggleTodoSuccess merges toggled todo into state" time="0.001">
</testcase>
</testsuite>
<testsuite name="undefined" tests="1" errors="0" failures="0" skipped="0" timestamp="2017-04-25T10:48:36" time="0.093">
<testcase classname=" normalizeTodos" name=" normalizeTodos" time="0.006">
</testcase>
</testsuite>
<testsuite name="libs/utils/normalizr" tests="3" errors="0" failures="0" skipped="0" timestamp="2017-04-25T10:48:37" time="0.083">
<testcase classname="libs/utils/normalizr normalizeArray creates an object with numeric ids as the keys" name="libs/utils/normalizr normalizeArray creates an object with numeric ids as the keys" time="0.002">
</testcase>
<testcase classname="libs/utils/normalizr normalizeArrayToMap creates a map with numeric ids as the keys" name="libs/utils/normalizr normalizeArrayToMap creates a map with numeric ids as the keys" time="0.001">
</testcase>
<testcase classname="libs/utils/normalizr normalizeObjectToMap creates a map with numeric ids as the keys" name="libs/utils/normalizr normalizeObjectToMap creates a map with numeric ids as the keys" time="0.001">
</testcase>
</testsuite>
<testsuite name="utils/immutable" tests="9" errors="0" failures="0" skipped="0" timestamp="2017-04-25T10:48:37" time="0.094">
<testsuite name="utils/immutable" tests="9" errors="0" failures="0" skipped="0" timestamp="2017-05-14T10:07:49" time="0.101">
<testcase classname="utils/immutable { toJS } does nothing if the object is not an Immutable" name="utils/immutable { toJS } does nothing if the object is not an Immutable" time="0.001">
</testcase>
<testcase classname="utils/immutable { toJS } invokes `toJS` on the object if it is Immutable" name="utils/immutable { toJS } invokes `toJS` on the object if it is Immutable" time="0.001">
Expand All @@ -56,16 +28,42 @@
</testcase>
<testcase classname="utils/immutable { subtractIn } subtracts many items from a $Set nested in an immutable and returns the immutable" name="utils/immutable { subtractIn } subtracts many items from a $Set nested in an immutable and returns the immutable" time="0.001">
</testcase>
<testcase classname="utils/immutable { pushIn } pushes an item to a $List nested in an immutable and returns the immutable" name="utils/immutable { pushIn } pushes an item to a $List nested in an immutable and returns the immutable" time="0.001">
<testcase classname="utils/immutable { pushIn } pushes an item to a $List nested in an immutable and returns the immutable" name="utils/immutable { pushIn } pushes an item to a $List nested in an immutable and returns the immutable" time="0.002">
</testcase>
<testcase classname="utils/immutable { deleteIn } deletes item at the given index inside a nested $List and returns the immutable" name="utils/immutable { deleteIn } deletes item at the given index inside a nested $List and returns the immutable" time="0.001">
<testcase classname="utils/immutable { deleteIn } deletes item at the given index inside a nested $List and returns the immutable" name="utils/immutable { deleteIn } deletes item at the given index inside a nested $List and returns the immutable" time="0">
</testcase>
<testcase classname="utils/immutable { rejectIn } removes items in nested $List for which predicate returns true" name="utils/immutable { rejectIn } removes items in nested $List for which predicate returns true" time="0.001">
<testcase classname="utils/immutable { rejectIn } removes items in nested $List for which predicate returns true" name="utils/immutable { rejectIn } removes items in nested $List for which predicate returns true" time="0.002">
</testcase>
<testcase classname="utils/immutable { filterIn } removes items in nested $List for which predicate returns false" name="utils/immutable { filterIn } removes items in nested $List for which predicate returns false" time="0.001">
</testcase>
</testsuite>
<testsuite name="utils/redux" tests="1" errors="0" failures="0" skipped="0" timestamp="2017-04-25T10:48:37" time="0.088">
<testsuite name="undefined" tests="1" errors="0" failures="0" skipped="0" timestamp="2017-05-14T10:07:49" time="0.091">
<testcase classname=" normalizeTodos" name=" normalizeTodos" time="0.004">
</testcase>
</testsuite>
<testsuite name="libs/utils/api" tests="6" errors="0" failures="0" skipped="0" timestamp="2017-05-14T10:07:49" time="0.093">
<testcase classname="libs/utils/api { buildUrl } combines a path and an object of key values into a url with a query" name="libs/utils/api { buildUrl } combines a path and an object of key values into a url with a query" time="0.002">
</testcase>
<testcase classname="libs/utils/api { buildUrl } removes keys that have null values" name="libs/utils/api { buildUrl } removes keys that have null values" time="0">
</testcase>
<testcase classname="libs/utils/api { parseRawParams } accepts todo params" name="libs/utils/api { parseRawParams } accepts todo params" time="0.001">
</testcase>
<testcase classname="libs/utils/api { parseRawParams } accepts remote URLs" name="libs/utils/api { parseRawParams } accepts remote URLs" time="0.001">
</testcase>
<testcase classname="libs/utils/api callApi handles 400 error with an exception" name="libs/utils/api callApi handles 400 error with an exception" time="0.002">
</testcase>
<testcase classname="libs/utils/api callApi handles 500 error with an exception" name="libs/utils/api callApi handles 500 error with an exception" time="0">
</testcase>
</testsuite>
<testsuite name="libs/utils/normalizr" tests="3" errors="0" failures="0" skipped="0" timestamp="2017-05-14T10:07:49" time="0.094">
<testcase classname="libs/utils/normalizr normalizeArray creates an object with numeric ids as the keys" name="libs/utils/normalizr normalizeArray creates an object with numeric ids as the keys" time="0.003">
</testcase>
<testcase classname="libs/utils/normalizr normalizeArrayToMap creates a map with numeric ids as the keys" name="libs/utils/normalizr normalizeArrayToMap creates a map with numeric ids as the keys" time="0.002">
</testcase>
<testcase classname="libs/utils/normalizr normalizeObjectToMap creates a map with numeric ids as the keys" name="libs/utils/normalizr normalizeObjectToMap creates a map with numeric ids as the keys" time="0">
</testcase>
</testsuite>
<testsuite name="utils/redux" tests="1" errors="0" failures="0" skipped="0" timestamp="2017-05-14T10:07:49" time="0.08">
<testcase classname="utils/redux buildActionType creates an action type string" name="utils/redux buildActionType creates an action type string" time="0.001">
</testcase>
</testsuite>
Expand Down
14 changes: 7 additions & 7 deletions common/libs/utils/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ function parseImmutableData(data: any) {

function checkResponseStatus(response: Response) {
if (response.ok) return response;

return response.json().then(errData => {
const isBadCsrfToken = response.status === 401 && errData.message === 'Bad Authenticity Token';
if (isBadCsrfToken && IS_BROWSER) window.location.reload();
const error = new ApiError(response.statusText, errData, response.status);
throw error;
});
return response.json()
.then(errData => {
const isBadCsrfToken = response.status === 401 && errData.message === 'Bad Authenticity Token';
if (isBadCsrfToken && IS_BROWSER) window.location.reload();
const error = new ApiError(response.statusText, errData, response.status);
throw error;
});
}

function parseResponse(response: Response) {
Expand Down
23 changes: 23 additions & 0 deletions common/libs/utils/api/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
buildUrl,
parseRawParams,
buildReqUrl,
callApi
} from './index';

const todoParams = { todo: { description: 'this is a todo.' } };
Expand Down Expand Up @@ -56,4 +57,26 @@ describe('libs/utils/api', () => {
expect(actual).toMatchObject(expected);
});
});

describe('callApi', () => {
it('handles 400 error with an exception', async () => {
const url = 'http://fakeurl';
fetch.mockResponseOnce(JSON.stringify([{description: "add a todo"}]), {status: 400});
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added fetch-mock to test the API stuff.

try {
const resp = await callApi('GET', { url });
} catch (error) {
expect.anything();
}
});

it('handles 500 error with an exception', async () => {
const url = 'http://fakeurl';
fetch.mockResponseOnce(JSON.stringify([{description: "add a todo"}]), {status: 500});
try {
const resp = await callApi('GET', { url });
} catch (error) {
expect.anything();
}
});
});
});
16 changes: 12 additions & 4 deletions common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@
"react-redux": "^5.0.3",
"redux": "^3.6.0",
"redux-actions": "^2.0.2",
"redux-saga": "^0.14.6",
"webpack": "^2.4.1"
"redux-saga": "^0.14.6"
},
"devDependencies": {
"babel-jest": "19.0.0",
"babel-plugin-flow-react-proptypes": "^0.21.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babylon": "^6.16.1",
"eslint": "^3.17.1",
"eslint-config-shakacode": "^14.1.1",
"eslint-import-resolver-webpack": "^0.8.0",
"eslint-plugin-flowtype": "^2.30.3",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-jest": "^19.0.1",
Expand All @@ -37,10 +40,15 @@
"flow-bin": "^0.41.0",
"flow-typed": "2.0.0",
"jest": "^19.0.2",
"jest-fetch-mock": "^1.1.1",
"jest-junit": "^1.3.0"
},
"jest": {
"verbose": true,
"testResultsProcessor": "./node_modules/jest-junit"
"automock": false,
"testResultsProcessor": "./node_modules/jest-junit",
"setupFiles": [
"./test/setupJest.js"
]
}
}
Loading