Skip to content

Commit 79eab16

Browse files
committed
Sketchlist and projects action creator tests
1 parent 4826969 commit 79eab16

File tree

10 files changed

+671
-107
lines changed

10 files changed

+671
-107
lines changed

client/__mocks__/axios.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const mockAxios = jest.genMockFromModule('axios');
2+
3+
// this is the key to fix the axios.create() undefined error!
4+
mockAxios.create = jest.fn(() => mockAxios);
5+
6+
export default mockAxios;

client/__mocks__/i18n.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { enUS, es, ja, hi } from 'date-fns/locale';
2+
import i18n from '../i18n-test';
3+
4+
export function languageKeyToLabel(lang) {
5+
const languageMap = {
6+
'en-US': 'English',
7+
'es-419': 'Español',
8+
ja: '日本語',
9+
hi: 'हिन्दी'
10+
};
11+
return languageMap[lang];
12+
}
13+
14+
export function languageKeyToDateLocale(lang) {
15+
const languageMap = {
16+
'en-US': enUS,
17+
'es-419': es,
18+
ja,
19+
hi
20+
};
21+
return languageMap[lang];
22+
}
23+
24+
export function currentDateLocale() {
25+
return languageKeyToDateLocale(i18n.language);
26+
}
27+
28+
export default i18n;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import * as ActionTypes from '../../../../constants';
2+
import { startLoader, stopLoader } from '../loader';
3+
import { mockProjects } from '../../../../redux_test_stores/test_store';
4+
5+
// eslint-disable-next-line
6+
export function getProjects(username) {
7+
console.log(`mocked getProjects call with ${username}`);
8+
return (dispatch) => {
9+
dispatch(startLoader());
10+
dispatch({
11+
type: ActionTypes.SET_PROJECTS,
12+
projects: mockProjects
13+
});
14+
dispatch(stopLoader());
15+
};
16+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import configureStore from 'redux-mock-store';
2+
import thunk from 'redux-thunk';
3+
import axios from 'axios';
4+
import { unmountComponentAtNode } from 'react-dom';
5+
import { act } from 'react-dom/test-utils';
6+
import * as ProjectActions from '../projects';
7+
import * as ActionTypes from '../../../../constants';
8+
import {
9+
initialTestState,
10+
mockProjects
11+
} from '../../../../redux_test_stores/test_store';
12+
13+
// look into this
14+
// https://willowtreeapps.com/ideas/best-practices-for-unit-testing-with-a-react-redux-approach
15+
16+
const mockStore = configureStore([thunk]);
17+
18+
describe('projects action creator tests', () => {
19+
let store;
20+
21+
afterEach(() => {
22+
store.clearActions();
23+
});
24+
25+
it('creates GET_PROJECTS after successfuly fetching projects', () => {
26+
store = mockStore(initialTestState);
27+
28+
axios.get.mockImplementationOnce((x) => {
29+
console.log('get was called with ', x);
30+
return Promise.resolve({ data: mockProjects });
31+
});
32+
33+
const expectedActions = [
34+
{ type: ActionTypes.START_LOADING },
35+
{ type: ActionTypes.SET_PROJECTS, projects: mockProjects },
36+
{ type: ActionTypes.STOP_LOADING }
37+
];
38+
39+
return store
40+
.dispatch(ProjectActions.getProjects('happydog'))
41+
.then(() => expect(store.getActions()).toEqual(expectedActions));
42+
});
43+
});

client/modules/IDE/actions/projects.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export function getProjects(username) {
1212
} else {
1313
url = '/projects';
1414
}
15-
apiClient
15+
return apiClient
1616
.get(url)
1717
.then((response) => {
1818
dispatch({

client/modules/IDE/components/SketchList.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,6 @@ class SketchListRowBase extends React.Component {
179179
renderDropdown = () => {
180180
const { optionsOpen } = this.state;
181181
const userIsOwner = this.props.user.username === this.props.username;
182-
183182
return (
184183
<td className="sketch-list__dropdown-column">
185184
<button
@@ -188,6 +187,7 @@ class SketchListRowBase extends React.Component {
188187
onBlur={this.onBlurComponent}
189188
onFocus={this.onFocusComponent}
190189
aria-label={this.props.t('SketchList.ToggleLabelARIA')}
190+
data-testid="sketch-list-toggle-options-arrow"
191191
>
192192
<DownFilledTriangleIcon focusable="false" aria-hidden="true" />
193193
</button>
Lines changed: 87 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,39 @@
11
import React from 'react';
22
import configureStore from 'redux-mock-store';
33
import thunk from 'redux-thunk';
4+
import axios from 'axios';
45
import { unmountComponentAtNode } from 'react-dom';
56
import { act } from 'react-dom/test-utils';
6-
import moxios from 'moxios';
7-
import * as ProjectActions from '../actions/projects';
8-
import * as ActionTypes from '../../../constants';
97
import SketchList from './SketchList';
108
import { reduxRender, fireEvent, screen } from '../../../test-utils';
9+
import {
10+
initialTestState,
11+
mockProjects
12+
} from '../../../redux_test_stores/test_store';
1113

12-
const mockStore = configureStore([thunk]);
14+
jest.mock('../../../i18n');
1315

14-
const mockProjects = [
15-
{
16-
name: 'testsketch1',
17-
_id: 'testid1',
18-
updatedAt: '2021-02-26T04:58:29.390Z',
19-
files: [],
20-
createdAt: '2021-02-26T04:58:14.136Z',
21-
id: 'testid1'
22-
},
23-
{
24-
name: 'testsketch2',
25-
_id: 'testid2',
26-
updatedAt: '2021-02-23T17:40:43.789Z',
27-
files: [],
28-
createdAt: '2021-02-23T17:40:43.789Z',
29-
id: 'testid2'
30-
}
31-
];
32-
33-
const initialTestState = {
34-
ide: null,
35-
files: [],
36-
preferences: {},
37-
user: {
38-
39-
username: 'happydog',
40-
preferences: {},
41-
apiKeys: [],
42-
verified: 'sent',
43-
id: '123456789',
44-
totalSize: 0,
45-
authenticated: true
46-
},
47-
project: null,
48-
sketches: mockProjects,
49-
search: {
50-
collectionSearchTerm: '',
51-
sketchSearchTerm: ''
52-
},
53-
sorting: {
54-
field: 'createdAt',
55-
direction: 'DESCENDING'
56-
},
57-
editorAccessibility: {},
58-
toast: {},
59-
console: [],
60-
assets: {},
61-
loading: false,
62-
collections: []
63-
};
16+
/*
17+
* there seem to be polarizing opinions about whether or not
18+
* we should test the unconnected component or the
19+
* connected one. For the sake of not editing the original SketchList file
20+
* with an unneccessary export statement, I'm testing
21+
* the connected component with redux-mock-store.
22+
* this approach is outlined here -
23+
* https://www.robinwieruch.de/react-connected-component-test
24+
*/
6425

6526
describe('<Sketchlist />', () => {
66-
let container = null;
6727
let store;
28+
let container;
29+
const mockStore = configureStore([thunk]);
30+
6831
beforeEach(() => {
6932
// setup a DOM element as a render target
7033
container = document.createElement('div');
7134
document.body.appendChild(container);
35+
axios.get.mockImplementationOnce((x) => Promise.resolve({ data: 'foo' }));
36+
store = mockStore(initialTestState);
7237
});
7338

7439
afterEach(() => {
@@ -79,71 +44,88 @@ describe('<Sketchlist />', () => {
7944
store.clearActions();
8045
});
8146

82-
// it('creates GET_PROJECTS after successfuly fetching projects', async () => {
83-
// moxios.install();
84-
// function resolveAfter2Seconds() {
85-
// console.log("called resolve");
86-
// return new Promise(resolve => {
87-
// setTimeout(() => {
88-
// resolve('resolved');
89-
// }, 5000);
90-
// });
91-
// }
92-
// console.log("moxios", moxios);
93-
// moxios.wait(() => {
94-
95-
// const request = moxios.requests.mostRecent();
96-
// console.log(moxios.requests, request)
97-
// console.log("recieved request for get projects")
98-
// request.respondWith({
99-
// status: 200,
100-
// response: mockProjects,
101-
// }).then(() => done());
102-
// });
103-
104-
// const expectedActions = [
105-
// {type: ActionTypes.START_LOADING},
106-
// { type: ActionTypes.SET_PROJECTS,
107-
// projects: mockProjects }
108-
// ];
109-
110-
// store = mockStore(initialTestState);
111-
// console.log("dispatching action");
112-
// //store.dispatch(ProjectActions.getProjects("happydog"))
113-
// act(() => {
114-
// reduxRender(<SketchList />, { store, container });
115-
// });
116-
117-
// const hasSetProjectKey = (currActions) => {
118-
// return currActions.filter(ac => ac.type === ActionTypes.SET_PROJECTS).length > 0;
119-
// }
120-
121-
// await waitFor(() => expect(hasSetProjectKey(store.getActions())).toEqual(true));
122-
// moxios.uninstall();
123-
// //expect(store.getActions()).toEqual(expectedActions);
124-
// //return resolveAfter2Seconds().then(res => console.log("resolved"))
125-
// });
126-
127-
it('has both of the sample projects', () => {
128-
store = mockStore(initialTestState);
47+
it('has sample projects', () => {
12948
let component;
13049
act(() => {
131-
component = reduxRender(<SketchList />, { store, container });
50+
component = reduxRender(<SketchList username="happydog1" />, {
51+
store,
52+
container
53+
});
13254
});
13355
expect(screen.getByText('testsketch1')).toBeInTheDocument();
13456
expect(screen.getByText('testsketch2')).toBeInTheDocument();
13557
});
13658

13759
it('clicking on date created row header dispatches a reordering action', () => {
138-
store = mockStore(initialTestState);
13960
let component;
14061
act(() => {
141-
component = reduxRender(<SketchList />, { store, container });
62+
component = reduxRender(<SketchList username="happydog2" />, {
63+
store,
64+
container
65+
});
14266
});
14367
act(() => {
14468
fireEvent.click(screen.getByTestId('toggle-direction-createdAt'));
14569
});
14670
const expectedAction = [{ type: 'TOGGLE_DIRECTION', field: 'createdAt' }];
14771
expect(store.getActions()).toEqual(expect.arrayContaining(expectedAction));
14872
});
73+
74+
it('clicking on dropdown arrow opens sketch options', () => {
75+
let component;
76+
act(() => {
77+
component = reduxRender(<SketchList username="happydog2" />, {
78+
store,
79+
container
80+
});
81+
});
82+
const dropdown = screen.queryAllByTestId(
83+
'sketch-list-toggle-options-arrow'
84+
);
85+
86+
if (dropdown.length > 0) {
87+
act(() => {
88+
fireEvent.click(dropdown[0]);
89+
});
90+
91+
expect(screen.queryByText('Rename')).not.toBeInTheDocument();
92+
expect(screen.queryByText('Duplicate')).toBeInTheDocument();
93+
expect(screen.queryByText('Download')).toBeInTheDocument();
94+
expect(screen.queryByText('Add to collection')).toBeInTheDocument();
95+
expect(screen.queryByText('Delete')).not.toBeInTheDocument();
96+
}
97+
});
98+
99+
it('clicking on dropdown arrow opens sketch options - sketches belong to user', () => {
100+
let component;
101+
act(() => {
102+
component = reduxRender(<SketchList username="happydog" />, {
103+
store,
104+
container
105+
});
106+
});
107+
const dropdown = screen.queryAllByTestId(
108+
'sketch-list-toggle-options-arrow'
109+
);
110+
111+
if (dropdown.length > 0) {
112+
act(() => {
113+
fireEvent.click(dropdown[0]);
114+
});
115+
116+
expect(screen.queryByText('Rename')).toBeInTheDocument();
117+
expect(screen.queryByText('Duplicate')).toBeInTheDocument();
118+
expect(screen.queryByText('Download')).toBeInTheDocument();
119+
expect(screen.queryByText('Add to collection')).toBeInTheDocument();
120+
expect(screen.queryByText('Delete')).toBeInTheDocument();
121+
}
122+
});
123+
124+
it('snapshot testing', () => {
125+
const { asFragment } = reduxRender(<SketchList username="happydog2" />, {
126+
store,
127+
container
128+
});
129+
expect(asFragment()).toMatchSnapshot();
130+
});
149131
});

0 commit comments

Comments
 (0)