Skip to content

Commit

Permalink
fix: adding query size check (#997)
Browse files Browse the repository at this point in the history
* fix: adding query size check

* fix: more test converage
  • Loading branch information
kiram15 committed Jun 13, 2023
1 parent 3dc6e8b commit 10bb6f0
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 13 deletions.
1 change: 0 additions & 1 deletion src/components/forms/data/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ export const FormReducer: FormReducerType = (
...oldStateMap,
[setStateArgs.name]: setStateArgs.state,
};
console.log('setting state to ', newStateMap);
return { ...state, stateMap: newStateMap };
} default:
return state;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import React from 'react';
import {
cleanup, screen, waitFor, waitForElementToBeRemoved,
} from '@testing-library/react';
import '@testing-library/jest-dom';
import configureMockStore from 'redux-mock-store';

import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { features } from '../../../../../config';

import { renderWithRouter } from '../../../../test/testUtils';
import SettingsLMSTab from '../..';
import LmsApiService from '../../../../../data/services/LmsApiService';
import { getChannelMap } from '../../../../../utils';

const mockFetch = jest.fn();
mockFetch.mockResolvedValue({ data: { refresh_token: 'foobar' } });

const channelMapReturn = {
BLACKBOARD: {
fetch: mockFetch,
},
};

jest.mock('../../../../../utils', () => ({
...jest.requireActual('../../../../../utils'),
getChannelMap: jest.fn(),
}));

getChannelMap.mockReturnValue(channelMapReturn);

const enterpriseId = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee';
const enterpriseSlug = 'test-slug';
const enableSamlConfigurationScreen = false;
const identityProvider = '';

const initialState = {
portalConfiguration: {
enterpriseId, enterpriseSlug, enableSamlConfigurationScreen, identityProvider,
},
};

const existingConfigData = {
data: [{
channelCode: 'BLACKBOARD',
id: 1,
isValid: [{ missing: [] }, { incorrect: [] }],
active: true,
displayName: 'squish',
enterpriseCustomer: enterpriseId,
lastSyncAttemptedAt: '2022-11-22T20:59:56Z',
lastContentSyncAttemptedAt: '2022-11-22T20:59:56Z',
lastLearnerSyncAttemptedAt: null,
lastSyncErroredAt: null,
lastContentSyncErroredAt: null,
lastLearnerSyncErroredAt: null,
lastModifiedAt: '2023-05-05T14:51:53.473144Z',
}],
};

const configData = {
data: {
channelCode: 'BLACKBOARD',
id: 1,
isValid: [{ missing: [] }, { incorrect: [] }],
active: true,
displayName: 'foobar',
enterpriseCustomer: enterpriseId,
lastSyncAttemptedAt: '2022-11-22T20:59:56Z',
lastContentSyncAttemptedAt: '2022-11-22T20:59:56Z',
lastLearnerSyncAttemptedAt: null,
lastSyncErroredAt: null,
lastContentSyncErroredAt: null,
lastLearnerSyncErroredAt: null,
lastModifiedAt: '2023-05-05T14:51:53.473144Z',
},
};

const mockStore = configureMockStore([thunk]);
window.open = jest.fn();

describe('Test sync history page full flow', () => {
afterEach(() => {
cleanup();
jest.clearAllMocks();
});

test('Test opening sync history page', async () => {
getAuthenticatedUser.mockReturnValue({
administrator: true,
});
features.FEATURE_INTEGRATION_REPORTING = true;

const mockFetchSingleConfig = jest.spyOn(LmsApiService, 'fetchSingleBlackboardConfig');
const mockFetchExistingConfigs = jest.spyOn(LmsApiService, 'fetchEnterpriseCustomerIntegrationConfigs');
mockFetchSingleConfig.mockResolvedValue(configData);
mockFetchExistingConfigs.mockResolvedValue(existingConfigData);

const SettingsLMSWrapper = () => (
<IntlProvider locale="en">
<Provider store={mockStore({ ...initialState })}>
<SettingsLMSTab
enterpriseId={enterpriseId}
enterpriseSlug={enterpriseSlug}
enableSamlConfigurationScreen={enableSamlConfigurationScreen}
identityProvider={identityProvider}
hasSSOConfig
/>
</Provider>
</IntlProvider>
);

renderWithRouter(<SettingsLMSWrapper />);
const skeleton = screen.getAllByTestId('skeleton');
await waitForElementToBeRemoved(skeleton);
await (expect(screen.getByText('squish')));

const syncHistoryButton = screen.getByText('View sync history');
expect(syncHistoryButton.getAttribute('href')).toBe(`/${configData.data.channelCode}/${configData.data.id}`);
});
test('Test configure action from sync history', async () => {
const mockFetchSingleConfig = jest.spyOn(LmsApiService, 'fetchSingleBlackboardConfig');
mockFetchSingleConfig.mockResolvedValue(configData);

const location = {
...window.location,
search: `?lms=${configData.data.channelCode}&id=${configData.data.id}`,
};
Object.defineProperty(window, 'location', {
writable: true,
value: location,
});

const SettingsLMSWrapper = () => (
<IntlProvider locale="en">
<Provider store={mockStore({ ...initialState })}>
<SettingsLMSTab
enterpriseId={enterpriseId}
enterpriseSlug={enterpriseSlug}
enableSamlConfigurationScreen={enableSamlConfigurationScreen}
identityProvider={identityProvider}
hasSSOConfig
/>
</Provider>
</IntlProvider>
);

renderWithRouter(<SettingsLMSWrapper />);
expect(window.location.search).toEqual(`?lms=${configData.data.channelCode}&id=${configData.data.id}`);
await waitFor(() => expect(mockFetch).toHaveBeenCalledWith('1'));
// opens stepper
await waitFor(() => expect(screen.getByText('New learning platform integration')));
screen.debug(undefined, 100000);
});
});
29 changes: 17 additions & 12 deletions src/components/settings/SettingsLMSTab/index.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import _ from 'lodash';
import React, { useCallback, useEffect, useState } from 'react';
import React, {
useCallback, useEffect, useMemo, useState,
} from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';

Expand All @@ -10,7 +12,7 @@ import {
import { Add, Info } from '@edx/paragon/icons';
import { logError } from '@edx/frontend-platform/logging';

import { camelCaseDictArray, channelMapping } from '../../../utils';
import { camelCaseDictArray, getChannelMap } from '../../../utils';
import LMSConfigPage from './LMSConfigPage';
import ExistingLMSCardDeck from './ExistingLMSCardDeck';
import NoConfigCard from './NoConfigCard';
Expand Down Expand Up @@ -44,6 +46,7 @@ const SettingsLMSTab = ({
const [isLmsStepperOpen, openLmsStepper, closeLmsStepper] = useToggle(false);
const toastMessages = [ACTIVATE_TOAST_MESSAGE, DELETE_TOAST_MESSAGE, INACTIVATE_TOAST_MESSAGE, SUBMIT_TOAST_MESSAGE];
const { dispatch } = useFormContext();
const channelMap = useMemo(() => getChannelMap(), []);

// onClick function for existing config cards' edit action
const editExistingConfig = useCallback((configData, configType) => {
Expand All @@ -62,18 +65,20 @@ const SettingsLMSTab = ({
openLmsStepper();
}, [dispatch, openLmsStepper]);

// we pass in params (configId and lmsType) from SyncHistory when user wants to edit that config
useEffect(() => {
const query = new URLSearchParams(window.location.search);
const fetchData = async () => channelMapping[query.get('lms')].fetch(query.get('id'));
fetchData()
.then((response) => {
editExistingConfig(camelCaseObject(response.data), query.get('id'));
})
.catch((err) => {
logError(err);
});
}, [editExistingConfig]);
// if we have passed in params (lmsType and configId) from SyncHistory, user wants to edit that config
if (query.has('lms') && query.has('id')) {
const fetchData = async () => channelMap[query.get('lms')].fetch(query.get('id'));
fetchData()
.then((response) => {
editExistingConfig(camelCaseObject(response.data), query.get('id'));
})
.catch((err) => {
logError(err);
});
}
}, [channelMap, editExistingConfig]);

const fetchExistingConfigs = useCallback(() => {
const options = { enterprise_customer: enterpriseId };
Expand Down

0 comments on commit 10bb6f0

Please sign in to comment.