test:Applist test cases added (#113)

Co-authored-by: MehakNasir <mehaknasir@A006-00194.local>
This commit is contained in:
Mehak Nasir
2021-05-11 16:10:20 +05:00
committed by GitHub
parent 6caf6aeefb
commit a3219225db
6 changed files with 123 additions and 22 deletions

View File

@@ -2,8 +2,9 @@ import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import Responsive from 'react-responsive';
import {
Card, CheckboxControl, ExtraSmall,
Card, CheckboxControl, breakpoints,
} from '@edx/paragon';
import messages from './messages';
import FeaturesList from './FeaturesList';
@@ -51,12 +52,12 @@ function AppCard({
</div>
<Card.Subtitle className="mb-3 text-muted">{supportText}</Card.Subtitle>
<Card.Text>{intl.formatMessage(messages[`appDescription-${app.id}`])}</Card.Text>
<ExtraSmall>
<Responsive maxWidth={breakpoints.extraSmall.maxWidth}>
<FeaturesList
features={features}
app={app}
/>
</ExtraSmall>
</Responsive>
</Card.Body>
</Card>
);

View File

@@ -1,11 +1,10 @@
import React, { useCallback, useEffect } from 'react';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { CardGrid, Container, LargerThanExtraSmall } from '@edx/paragon';
import { CardGrid, Container, breakpoints } from '@edx/paragon';
import { useDispatch, useSelector } from 'react-redux';
import Responsive from 'react-responsive';
import { useModels } from '../../../generic/model-store';
import { selectApp, LOADED, LOADING } from '../data/slice';
import AppCard from './AppCard';
import messages from './messages';
import FeaturesTable from './FeaturesTable';
@@ -73,7 +72,7 @@ function AppList({ intl }) {
/>
))}
</CardGrid>
<LargerThanExtraSmall>
<Responsive minWidth={breakpoints.small.minWidth}>
<h3 className="my-sm-5 my-4">
{intl.formatMessage(messages.supportedFeatures)}
</h3>
@@ -83,7 +82,7 @@ function AppList({ intl }) {
features={features}
/>
</div>
</LargerThanExtraSmall>
</Responsive>
</div>
);
}

View File

@@ -1,21 +1,107 @@
import React from 'react';
import { initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { AppProvider } from '@edx/frontend-platform/react';
import { breakpoints } from '@edx/paragon';
import {
queryByText, render, queryAllByRole, queryByRole, getByRole, queryByLabelText, getByLabelText, queryAllByText,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MockAdapter from 'axios-mock-adapter';
import { Context as ResponsiveContext } from 'react-responsive';
import initializeStore from '../../../store';
import executeThunk from '../../../utils';
import { getAppsUrl } from '../data/api';
import { fetchApps } from '../data/thunks';
import { emptyAppApiResponse, legacyApiResponse, piazzaApiResponse } from '../factories/mockApiResponses';
import AppList from './AppList';
import messages from './messages';
const courseId = 'course-v1:edX+TestX+Test_Course';
describe('AppList', () => {
test('displays a message when there are no apps available', () => {
let axiosMock;
let store;
let container;
function createComponent(screenWidth = breakpoints.extraLarge.minWidth) {
return (
<AppProvider store={store}>
<ResponsiveContext.Provider value={{ width: screenWidth }}>
<IntlProvider locale="en" messages={{}}>
<AppList />
</IntlProvider>
</ResponsiveContext.Provider>
</AppProvider>
);
}
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});
store = await initializeStore();
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
});
test('display a card for each available app', () => {
const mockStore = async (mockResponse, screenWidth = breakpoints.extraLarge.minWidth) => {
axiosMock.onGet(getAppsUrl(courseId)).reply(200, mockResponse);
await executeThunk(fetchApps(courseId), store.dispatch);
const component = createComponent(screenWidth);
const wrapper = render(component);
container = wrapper.container;
};
test('displays a message when there are no apps available', async () => {
await mockStore(emptyAppApiResponse);
expect(queryByText(container, `${messages.noApps.defaultMessage}`)).toBeInTheDocument();
});
test('displays the FeaturesTable at desktop sizes', () => {
test('displays loading state when there is no active App', async () => {
await mockStore({});
expect(queryByRole(container, 'status')).toBeInTheDocument();
});
test('hides the FeaturesTable at mobile sizes', () => {
test('display a card for each available app', async () => {
await mockStore(piazzaApiResponse);
const appCount = store.getState().discussions.appIds.length;
expect(queryAllByRole(container, 'radio')).toHaveLength(appCount);
});
test('onSelectApp is called when an app is clicked', () => {
test('displays the FeaturesTable at desktop sizes', async () => {
await mockStore(piazzaApiResponse);
expect(queryByRole(container, 'table')).toBeInTheDocument();
});
test('hides the FeaturesTable at mobile sizes', async () => {
await mockStore(piazzaApiResponse, breakpoints.extraSmall.maxWidth);
expect(queryByRole(container, 'table')).not.toBeInTheDocument();
});
test('hides the FeaturesList at desktop sizes', async () => {
await mockStore(piazzaApiResponse);
expect(queryByText(container, messages['supportedFeatureList-mobile-show'].defaultMessage)).not.toBeInTheDocument();
});
test('displays the FeaturesList at mobile sizes', async () => {
await mockStore(piazzaApiResponse, breakpoints.extraSmall.maxWidth);
const appCount = store.getState().discussions.appIds.length;
expect(queryAllByText(container, messages['supportedFeatureList-mobile-show'].defaultMessage)).toHaveLength(appCount);
});
test('selectApp is called when an app is clicked', async () => {
await mockStore(legacyApiResponse);
userEvent.click(getByLabelText(container, 'Select Piazza'));
const clickedCard = getByRole(container, 'radio', { checked: true });
expect(queryByLabelText(clickedCard, 'Select Piazza')).toBeInTheDocument();
});
});

View File

@@ -10,13 +10,7 @@ import {
import { fetchApps, saveAppConfig } from './thunks';
import { LOADED } from '../../../data/slice';
import { legacyApiResponse, piazzaApiResponse } from '../factories/mockApiResponses';
// Helper, that is used to forcibly finalize all promises
// in thunk before running matcher against state.
const executeThunk = async (thunk, dispatch, getState) => {
await thunk(dispatch, getState);
await new Promise(setImmediate);
};
import executeThunk from '../../../utils';
const courseId = 'course-v1:edX+TestX+Test_Course';
const pagesAndResourcesPath = `/course/${courseId}/pages-and-resources`;

View File

@@ -70,3 +70,18 @@ export const legacyApiResponse = {
},
},
};
export const emptyAppApiResponse = {
context_key: '',
enabled: null,
provider_type: '',
features: [],
lti_configuration: {},
plugin_configuration: {},
providers: {
active: 'legacy',
available: {
},
},
};

6
src/utils.js Normal file
View File

@@ -0,0 +1,6 @@
const executeThunk = async (thunk, dispatch, getState) => {
await thunk(dispatch, getState);
await new Promise(setImmediate);
};
export default executeThunk;