Skip to content

Commit

Permalink
feat(Delete): User should be able to delete an article
Browse files Browse the repository at this point in the history
- Add button to delete an article
- Add Component for delete article.
- Add tests for the detete article feature

[#162696281]
  • Loading branch information
ATUHAIRE JUDE INNOCENT committed Dec 21, 2018
1 parent cbf6795 commit c8622d0
Show file tree
Hide file tree
Showing 21 changed files with 385 additions and 12 deletions.
2 changes: 2 additions & 0 deletions src/actions/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ const ACTION_TYPE = {
EDIT_ARTICLE_DATA: 'EDIT_ARTICLE_DATA',
UPDATE_IMAGE: 'UPDATE_IMAGE',
LOAD_EDIT_DATA: 'LOAD_EDIT_DATA',
DELETE_ARTICLE_SUCCESS: 'DELETE_ARTICLE_SUCCESS',
DELETE_ARTICLE_FAILED: 'DELETE_ARTICLE_FAILED',
};

export default ACTION_TYPE;
29 changes: 29 additions & 0 deletions src/actions/deleteArticleActions/deleteArticleAction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import axios from 'axios';
import ACTION_TYPE from '../actionTypes';
import APP_URL from '../../utils/constants';

export const deleteArticleSuccess = response => ({
type: ACTION_TYPE.DELETE_ARTICLE_SUCCESS,
payload: response,
});

export const deleteArticleFailure = errorMessage => ({
type: ACTION_TYPE.DELETE_ARTICLE_FAILED,
payload: errorMessage,
});

const tok = localStorage.getItem('token');
export const deleteArticleThunk = articleId => (dispatch) => {
const url = `${APP_URL}/articles/${articleId}`;
const token = `Token ${tok}`;
const headers = {
headers: { Authorization: token },
};
return axios.delete(url, headers)
.then((response) => {
dispatch(deleteArticleSuccess(response.data.results));
})
.catch((error) => {
dispatch(deleteArticleFailure(error.response));
});
};
58 changes: 58 additions & 0 deletions src/actions/deleteArticleActions/deleteArticleAction.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import moxios from 'moxios';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import {
deleteArticleSuccess, deleteArticleThunk,
} from './deleteArticleAction';
import ACTION_TYPE from '../actionTypes';
import APP_URL from '../../utils/constants';


describe('Create article Actions tests', () => {
let store;
let actionTypesData;
let response;
beforeEach(() => {
response = { delete: 'Article deleted successfully' };
const mockStore = configureMockStore([thunk]);
store = mockStore({});
actionTypesData = actionType => ({
type: actionType,
});
// import and pass your custom axios instance to this method
moxios.install();
});
afterEach(() => {
// import and pass your custom axios instance to this method
moxios.uninstall();
});
test('Successful delete article action', () => {
expect(deleteArticleSuccess(response)).toEqual(expect.objectContaining(
actionTypesData(ACTION_TYPE.DELETE_ARTICLE_SUCCESS),
));
});
test('Delete article successfull', () => {
moxios.stubRequest(`${APP_URL}/articles/7`, {
status: 200,
});
store.dispatch(deleteArticleThunk(7)).then(() => {
expect(store.getActions()).toEqual(expect.objectContaining(
{
type: ACTION_TYPE.CREATE_ARTICLE_SUCCESS,
},
));
});
});
test('Delete article failed', () => {
moxios.stubRequest(`${APP_URL}/articles/7`, {
status: 400,
});
store.dispatch(deleteArticleThunk(7)).catch(() => {
expect(store.getActions()).toEqual(expect.objectContaining(
[{
type: ACTION_TYPE.DELETE_ARTICLE_FAILED,
}],
));
});
});
});
12 changes: 12 additions & 0 deletions src/actions/swalAlerts.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ const swalMessages = {
type: 'success',
confirmButtonText: 'continue',
},
ARTICLE_DELETED_SUCCESSFUL: {
title: 'Article deleted',
text: 'Your article was deleted successfully',
type: 'success',
showConfirmButton: false,
timer: 3000,
},
REGISTRATION_ERROR: {
title: 'Unable to complete registration',
text: '',
Expand Down Expand Up @@ -51,6 +58,11 @@ const swalMessages = {
type: 'error',
confirmButtonText: 'continue',
},
DELETE_ERROR: {
title: 'Delete failed',
text: 'You can only delete an article you created',
type: 'error',
},
};

export default swalMessages;
1 change: 1 addition & 0 deletions src/commons/initialStates.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const initialState = {
articles: [],
errorMessage: '',
},
deleteArticleReducer: {},
socialLoginReducer: { isLoggedIn: false },
loginReducer: { errorMessage: '', successMessage: '', user_details: '' },
createArticleReducer: {},
Expand Down
2 changes: 1 addition & 1 deletion src/components/Article/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ exports[`<Article /> should render correctly 1`] = `
</div>
</div>
<div
className="share"
className="share container"
>
<ShareRow
article={
Expand Down
6 changes: 5 additions & 1 deletion src/components/Article/article.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ $primaryDarker: #345F5B;
font-family: $headingFontFamily;
color: $primaryDarker;
}
#edit-del-bt{
display: flex;
}
#edit-bt {
padding: 10px;
font-size: 12px
font-size: 12px;
margin-right: 5px;
}
.article-image {
padding: 30px 0;
Expand Down
22 changes: 13 additions & 9 deletions src/components/Article/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import './article.scss';
import LikeDislike from '../LikeDislike';
import RatingPage from '../../containers/RatingPage';
import ShareRow from './shareRow';
import DeleteArticlePage from '../../containers/deleteArticle';

library.add(
faUser,
Expand Down Expand Up @@ -95,18 +96,21 @@ const Article = ({ onLikeDislike, article, onClick }) => {
</div>
</div>
</div>
<div className="share">
<div className="share container">
<ShareRow article={article} />
<div>
{article.author.username === loggedinUser ? (
<button
type="button"
onClick={onClick}
id="edit-bt"
className="btn btn-success"
>
Edit Article
</button>
<div id="edit-del-bt">
<button
type="button"
onClick={onClick}
id="edit-bt"
className="btn btn-success"
>
EDIT ARTICLE
</button>
<DeleteArticlePage articleId={article.id} />
</div>
) : (
<span />
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<DeleteArticle /> renders the component 1`] = `
<div>
<button
className="btn btn-danger"
id="delete-bt"
onClick={[MockFunction]}
type="submit"
>
DELETE ARTICLE
</button>
</div>
`;
4 changes: 4 additions & 0 deletions src/components/deleteArticle/deleteArticle.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#delete-bt {
padding: 10px;
font-size: 12px
}
14 changes: 14 additions & 0 deletions src/components/deleteArticle/deleteArticle.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { shallow } from 'enzyme';
import DeleteArticle from './index';

describe('<DeleteArticle /> ', () => {
const DeleteArticleComponent = shallow(
<DeleteArticle
onClick={jest.fn()}
/>,
);
test('renders the component', () => {
expect(DeleteArticleComponent).toMatchSnapshot();
});
});
15 changes: 15 additions & 0 deletions src/components/deleteArticle/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import * as PropTypes from 'prop-types';
import './deleteArticle.scss';

const DeleteArticle = ({ onClick }) => (
<div>
<button type="submit" onClick={onClick} className="btn btn-danger" id="delete-bt">DELETE ARTICLE</button>
</div>
);

DeleteArticle.propTypes = {
onClick: PropTypes.func.isRequired,
};

export default DeleteArticle;
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,7 @@ exports[`<ArticlePage /> renders the container 1`] = `
</div>
</div>
<div
className="share"
className="share container"
>
<ShareRow
article={
Expand Down
1 change: 1 addition & 0 deletions src/containers/ArticlePage/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ describe('<ArticlePage />', () => {
getCommentData: { results: [] },
},
ratingReducer: { rating: 1 },
deleteArticleReducer: {},
};
mockStore = configureStore([thunk]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe('handle Invoke email for password reset', () => {
const evt = { target: { id: 12, value: 'Likes' } };
expect(wrapper.instance().handleChange(evt));
});

it('should submit user email for passwordreset', () => {
component
.find('input#email')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<CreateArticlePage /> should render the component 1`] = `
<Connect(DeleteArticlePage)
article={[MockFunction]}
articleId={1}
store={
Object {
"clearActions": [Function],
"dispatch": [Function],
"getActions": [Function],
"getState": [Function],
"replaceReducer": [Function],
"subscribe": [Function],
}
}
>
<DeleteArticlePage
article={[MockFunction]}
articleDelete={[Function]}
articleId={1}
deleteArticleReducer={
Object {
"articleDelete": Object {
"message": "Article deleted succesfully",
},
}
}
store={
Object {
"clearActions": [Function],
"dispatch": [Function],
"getActions": [Function],
"getState": [Function],
"replaceReducer": [Function],
"subscribe": [Function],
}
}
storeSubscription={
Subscription {
"listeners": Object {
"clear": [Function],
"get": [Function],
"notify": [Function],
"subscribe": [Function],
},
"onStateChange": [Function],
"parentSub": undefined,
"store": Object {
"clearActions": [Function],
"dispatch": [Function],
"getActions": [Function],
"getState": [Function],
"replaceReducer": [Function],
"subscribe": [Function],
},
"unsubscribe": [Function],
}
}
>
<div>
<DeleteArticle
onClick={[Function]}
>
<div>
<button
className="btn btn-danger"
id="delete-bt"
onClick={[Function]}
type="submit"
>
DELETE ARTICLE
</button>
</div>
</DeleteArticle>
</div>
</DeleteArticlePage>
</Connect(DeleteArticlePage)>
`;
47 changes: 47 additions & 0 deletions src/containers/deleteArticle/deleteArticle.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import DeleteArticlePage, { mapDispatchToProps } from './index';

describe('<CreateArticlePage />', () => {
let DeleteArticlePageComponent;
let wrapper;
beforeEach(() => {
jest.resetModules();
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
const initialState = { deleteArticleReducer: { articleDelete: { message: 'Article deleted succesfully' } } };
const store = mockStore(initialState);
const props = { articleId: 1 };
DeleteArticlePageComponent = mount(
<DeleteArticlePage article={jest.fn()} store={store} articleId={props.articleId} />,
);
wrapper = shallow(
<DeleteArticlePage store={store} articleId={props.articleId} />,
);
});

it('should render the component', () => {
expect(DeleteArticlePageComponent).toMatchSnapshot();
});

it('should dispatch a method to get user input', () => {
const dispatch = jest.fn();
mapDispatchToProps(dispatch).articleDelete({});
});

test('Test function', () => {
const event = { preventDefault: jest.fn() };
expect(wrapper.dive().instance().handleSubmit(event));
});

it('should test user data without fail', () => {
DeleteArticlePageComponent
.find('button')
.simulate('submit');
DeleteArticlePageComponent
.find('#delete-bt')
.simulate('click');
});
});
Loading

0 comments on commit c8622d0

Please sign in to comment.