-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into mkeating/ENT-9742
- Loading branch information
Showing
17 changed files
with
723 additions
and
352 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
NODE_ENV='production' | ||
USE_API_CACHE=true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
9. Deprecation of `useCache` option | ||
=================================== | ||
|
||
Status | ||
****** | ||
|
||
Accepted | ||
|
||
Context | ||
******* | ||
|
||
Frontend platform offers a variety of helpers to facilitate API calls to our backend services. Part of their suite of | ||
helper functions are `getAuthenticatedHttpClient` which allows a `useCache` option. The inclusion of the `useCache` option | ||
treats the original `getAuthenticatedHttpClient` as a | ||
`cachedAuthenticatedHttpClient` `method <https://github.com/openedx/frontend-platform/blob/15ef507e41127b4fd4ace5d31f7e527381678572/src/auth/AxiosJwtAuthService.js#L111-L117>`_. | ||
This has the effect of modifying the headers of the API request to our backend service. Within the the | ||
`Access-Control-Request-Headers` preflight request or OPTIONS call, the inclusion of `useCache` resulted in the | ||
`Cache-Control` header also being sent resulting in an unresolved API response and breaking usability for certain | ||
components that depended on the upstream data. | ||
|
||
Decision | ||
******** | ||
|
||
Deprecate the usage of `useCache` within `getAuthenticatedHttpClient` to avoid inadvertently modifying the expected | ||
request headers to our backend services. For instances where client side caching of API calls is necessary, use | ||
`React Query <https://tanstack.com/query/v4/docs/framework/react/overview>`_ when constructing the API call. There are | ||
several examples that currently reside in our enterprise MFEs that | ||
`effectively leverage <https://github.com/openedx/frontend-app-learner-portal-enterprise/blob/master/src/components/app/data/hooks/useBFF.js>`_ React Query, and the | ||
usage of `query keys <https://github.com/openedx/frontend-app-learner-portal-enterprise/blob/master/src/components/app/data/queries/queryKeyFactory.js>`_ and | ||
`helpers <https://github.com/openedx/frontend-app-learner-portal-enterprise/tree/master/src/components/app/data/queries>`_. | ||
|
||
|
||
Consequences | ||
************ | ||
|
||
This will in the intermediary remove any client side caching facilitated by the `useCache` option. But should intentionally | ||
be updated with a React Query implementation to maintain the benefits of client side caching. In the meantime, the backend | ||
services cache will suffice | ||
|
||
Alternatives Considered | ||
*********************** | ||
The underlying package, `frontend-platform`, which depended on the breaking package upgrade, `Axios`, was downgraded as part of resolving | ||
issues related to the `useCache` field. It was determined that the `useCache` field was primarily used in enterprise, so | ||
it made the most sense to remove the `useCache` field in favor of introducing tools like `React Query` for client side | ||
caching. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -348,6 +348,40 @@ describe('<CreateGroupModal />', () => { | |
expect(screen.getAllByText('[email protected]')).toHaveLength(2); | ||
}, { timeout: EMAIL_ADDRESSES_INPUT_VALUE_DEBOUNCE_DELAY + 1000 }); | ||
}); | ||
it('should clear errors from bad csv file after uploading good csv file', async () => { | ||
render(<CreateGroupModalWrapper />); | ||
const fakeFile = new File(['iamnotanemail'], 'bademails.csv', { type: 'text/csv' }); | ||
const dropzone = screen.getByText('Drag and drop your file here or click to upload.'); | ||
Object.defineProperty(dropzone, 'files', { | ||
value: [fakeFile], | ||
writable: true, | ||
}); | ||
fireEvent.drop(dropzone); | ||
|
||
await waitFor(() => { | ||
expect(screen.getByText('bademails.csv')).toBeInTheDocument(); | ||
expect(screen.getByText("Members can't be invited as entered.")).toBeInTheDocument(); | ||
expect(screen.getByText('iamnotanemail is not a valid email.')).toBeInTheDocument(); | ||
}, { timeout: EMAIL_ADDRESSES_INPUT_VALUE_DEBOUNCE_DELAY + 1000 }); | ||
|
||
const dropzone2 = screen.getByText('bademails.csv'); | ||
const fakeFile2 = new File(['[email protected]'], 'goodemails.csv', { type: 'text/csv' }); | ||
Object.defineProperty(dropzone2, 'files', { | ||
value: [fakeFile2], | ||
}); | ||
fireEvent.drop(dropzone2); | ||
|
||
const groupNameInput = screen.getByTestId('group-name'); | ||
userEvent.type(groupNameInput, 'test group name'); | ||
|
||
await waitFor(() => { | ||
expect(screen.getByText('goodemails.csv')).toBeInTheDocument(); | ||
expect(screen.getByText('Summary (1)')).toBeInTheDocument(); | ||
expect(screen.getAllByText('[email protected]')).toHaveLength(2); | ||
}, { timeout: EMAIL_ADDRESSES_INPUT_VALUE_DEBOUNCE_DELAY + 1000 }); | ||
expect(screen.queryByText("Members can't be invited as entered.")).not.toBeInTheDocument(); | ||
expect(screen.queryByText('iamnotanemail is not a valid email.')).not.toBeInTheDocument(); | ||
}); | ||
it('displays error for email not belonging in an org', async () => { | ||
const mockGroupData = { uuid: 'test-uuid' }; | ||
LmsApiService.createEnterpriseGroup.mockResolvedValue({ status: 201, data: mockGroupData }); | ||
|
@@ -405,4 +439,22 @@ describe('<CreateGroupModal />', () => { | |
)).toBeInTheDocument(); | ||
}); | ||
}); | ||
it('does not show duplicate error when members are bulk added multiple times', async () => { | ||
render(<CreateGroupModalWrapper />); | ||
// testing interaction with adding members from the datatable | ||
const membersCheckboxes = screen.getAllByRole('checkbox'); | ||
// skipping first one because its the select all checkbox | ||
userEvent.click(membersCheckboxes[1]); | ||
const addMembersButton = screen.getByText('Add'); | ||
userEvent.click(addMembersButton); | ||
// Select a second member while keeping first selected, and add again | ||
userEvent.click(membersCheckboxes[2]); | ||
userEvent.click(addMembersButton); | ||
|
||
await waitFor(() => { | ||
expect(screen.getAllByText('[email protected]')).toHaveLength(2); | ||
expect(screen.getAllByText('[email protected]')).toHaveLength(2); | ||
}); | ||
expect(screen.queryByText('Only 1 invite per email address will be sent.')).not.toBeInTheDocument(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.