test:Applist test cases added (#113)
Co-authored-by: MehakNasir <mehaknasir@A006-00194.local>
This commit is contained in:
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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`;
|
||||
|
||||
@@ -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
6
src/utils.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const executeThunk = async (thunk, dispatch, getState) => {
|
||||
await thunk(dispatch, getState);
|
||||
await new Promise(setImmediate);
|
||||
};
|
||||
|
||||
export default executeThunk;
|
||||
Reference in New Issue
Block a user