Compare commits

..

23 Commits

Author SHA1 Message Date
Ben Warzeski
8e19b5774c fix: merge cruft leftover file 2023-05-15 11:32:42 -04:00
Ben Warzeski
f7a4309888 fix: table tests 2023-05-15 11:16:48 -04:00
Omar Al-Ithawi
3e3a73e2bb feat: use atlas in make pull_translations (#325)
Changes
-------
 - Bump frontend-platform to bring `intl-imports.js` script
 - Move all i18n imports into `src/i18n/index.js` so `intl-imports.js` can
   override it with latest translations
 - Add `atlas` into `make pull_translations` when `OPENEDX_ATLAS_PULL`
   environment variable is set.
 - Refactored i18n utils into own file to avoid overwriting them by
   atlas

Refs: [FC-0012 project](https://openedx.atlassian.net/l/cp/XGS0iCcQ) implementing Translation Infrastructure OEP-58.
2023-05-15 10:58:11 -04:00
Ben Warzeski
af8d7182ef fix: date test 2023-05-15 10:57:48 -04:00
Ben Warzeski
d898a9cc2f fix: null renders 2023-05-15 10:57:25 -04:00
Ben Warzeski
f4b839f4d8 fix: lint 2023-05-15 10:57:24 -04:00
Ben Warzeski
f41b237d08 fix: redux transform tests 2023-05-15 10:57:24 -04:00
Ben Warzeski
6dd2fb3dd6 refactor: GradebookFilters component modernization 2023-05-15 10:57:23 -04:00
Ben Warzeski
b173681edb refactor: GradesView component modernization 2023-05-15 10:57:23 -04:00
Ben Warzeski
5fcde3b9e8 refactor: ImportSuccessToast component modernization 2023-05-15 10:57:22 -04:00
Ben Warzeski
35ee68ea9d refactor: SearchControls component modernization 2023-05-15 10:57:22 -04:00
Ben Warzeski
dde8e759b6 refactor: ScoreViewInput component modernization 2023-05-15 10:57:22 -04:00
Ben Warzeski
6b149e9ce0 refactor: PageButtons component modernization 2023-05-15 10:57:21 -04:00
Ben Warzeski
4cf5ba7a07 refactor: FilteredUsersLabel component modernization 2023-05-15 10:57:21 -04:00
Ben Warzeski
7a506324a8 refactor: FilterMenuToggle component modernization 2023-05-15 10:57:20 -04:00
Ben Warzeski
7f54cc4917 refactor: FilterBadges component modernization 2023-05-15 10:57:20 -04:00
Ben Warzeski
134ace9483 refactor: GradebookTable component modernization 2023-05-15 10:57:18 -04:00
Ben Warzeski
0e6f52fca9 refactor: EditModal component updates 2023-05-15 10:50:31 -04:00
Ben Warzeski
ca64cc614a feat: redux hooks 2023-05-15 10:50:19 -04:00
Ben Warzeski
1ad297c46c refactor: testing architecture updates 2023-05-15 10:50:17 -04:00
Ben Warzeski
f2bb0d7c2a refactor: interventsions report component 2023-05-15 10:49:45 -04:00
Ben Warzeski
f76f3d64c9 refactor: bulk management controls component 2023-05-15 10:49:45 -04:00
Ben Warzeski
db56d76d37 refactor: gradebook header component refactor 2023-05-15 10:49:44 -04:00
72 changed files with 26428 additions and 6642 deletions

1
.env
View File

@@ -10,7 +10,6 @@ DATA_API_BASE_URL=''
SEGMENT_KEY=''
FEATURE_FLAGS={}
ACCESS_TOKEN_COOKIE_NAME=''
LANGUAGE_PREFERENCE_COOKIE_NAME=''
NEW_RELIC_APP_ID=''
NEW_RELIC_LICENSE_KEY=''
SITE_NAME=''

View File

@@ -12,7 +12,6 @@ FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'
ACCESS_TOKEN_COOKIE_NAME='edx-jwt-cookie-header-payload'
LANGUAGE_PREFERENCE_COOKIE_NAME='openedx-language-preference'
USER_INFO_COOKIE_NAME='edx-user-info'
SITE_NAME=localhost
DATA_API_BASE_URL='http://localhost:8000'

View File

@@ -11,18 +11,22 @@ on:
jobs:
test:
runs-on: ubuntu-20.04
strategy:
matrix:
node: [16]
npm: [8.5.x]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Nodejs Env
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
uses: actions/checkout@v2
- name: Setup Nodejs
uses: actions/setup-node@v3
uses: actions/setup-node@v1
with:
node-version: ${{ env.NODE_VER }}
node-version: ${{ matrix.node }}
- name: Install npm 8.5.x
run: npm install -g npm@${{ matrix.npm }}
- name: Install dependencies
run: npm ci

View File

@@ -10,4 +10,4 @@ on:
jobs:
version-check:
uses: openedx/.github/.github/workflows/lockfile-check.yml@master
uses: openedx/.github/.github/workflows/lockfileversion-check.yml@master

View File

@@ -15,13 +15,10 @@ jobs:
with:
fetch-depth: 0
- name: Setup Nodejs Env
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: ${{ env.NODE_VER }}
node-version: 12
- name: Install dependencies
run: npm ci

1
.nvmrc
View File

@@ -1 +0,0 @@
18.15

View File

@@ -1,5 +1,5 @@
npm-install-%: ## install specified % npm package
npm ci $* --save-dev
npm install $* --save-dev
git add package.json
export TRANSIFEX_RESOURCE = frontend-app-gradebook
transifex_langs = "ar,de,es_419,fa_IR,fr,fr_CA,hi,it,pt,ru,uk,zh_CN"
@@ -12,7 +12,7 @@ tx_url1 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transi
tx_url2 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/source/
# This directory must match .babelrc .
transifex_temp = ./temp/babel-plugin-formatjs
transifex_temp = ./temp/babel-plugin-react-intl
NPM_TESTS=build i18n_extract lint test is-es5
@@ -65,14 +65,12 @@ pull_translations:
rm -rf src/i18n/messages
mkdir src/i18n/messages
cd src/i18n/messages \
&& atlas pull $(ATLAS_OPTIONS) \
&& atlas pull --filter=$(transifex_langs) \
translations/frontend-component-footer/src/i18n/messages:frontend-component-footer \
translations/frontend-component-header/src/i18n/messages:frontend-component-header \
translations/frontend-platform/src/i18n/messages:frontend-platform \
translations/paragon/src/i18n/messages:paragon \
translations/frontend-app-gradebook/src/i18n/messages:frontend-app-gradebook
$(intl_imports) frontend-platform paragon frontend-component-header frontend-component-footer frontend-app-gradebook
$(intl_imports) frontend-component-header frontend-component-footer frontend-app-gradebook
endif
# This target is used by CI.

View File

@@ -1,5 +1,3 @@
# frontend-app-gradebook
[![Build Status](https://api.travis-ci.com/edx/frontend-app-gradebook.svg?branch=master)](https://travis-ci.com/edx/frontend-app-gradebook)
[![Codecov](https://img.shields.io/codecov/c/gh/openedx/frontend-app-gradebook)](https://app.codecov.io/gh/openedx/frontend-app-gradebook)
[![npm_version](https://img.shields.io/npm/v/@edx/frontend-app-gradebook.svg)](@edx/frontend-app-gradebook)
@@ -7,7 +5,7 @@
[![license](https://img.shields.io/npm/l/@edx/frontend-app-gradebook.svg)](@edx/frontend-app-gradebook)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
# Purpose
# Gradebook
Gradebook allows course staff to view, filter, and override subsection grades for a course. Additionally for Masters courses, Gradebook enables bulk management of subsection grades.
@@ -49,8 +47,7 @@ depending on their needs. Instructors that expect to review grades infrequently
to the problem in question will have a worse UX than the legacy gradebook provides. Instructors that rely on the graphs
generated by the current gradebook might find the lack of autogenerated graphs to be frustrating.
## Getting Started
## Quickstart
### Installation
@@ -58,20 +55,6 @@ To install gradebook into your project:
```
npm i --save @edx/frontend-app-gradebook
```
Cloning and Startup
===================
1. Clone your new repo:
``git clone https://github.com/openedx/frontend-app-gradebook.git``
2. Install npm dependencies:
``cd frontend-app-gradebook && npm install``
3. Start the dev server:
``npm start``
## Running the UI Standalone
@@ -136,57 +119,3 @@ running gradebook container.
## Authentication with backend API services
See the [`@edx/frontend-auth`](https://github.com/edx-unsupported/frontend-auth) repo for information about securing routes in your application that require user authentication.
License
=======
The code in this repository is licensed under the AGPLv3 unless otherwise
noted.
Contributing
============
Contributions are very welcome. Please read `How To Contribute`_ for details.
.. _How To Contribute: https://openedx.org/r/how-to-contribute
This project is currently accepting all types of contributions, bug fixes,
security fixes, maintenance work, or new features. However, please make sure
to have a discussion about your new feature idea with the maintainers prior to
beginning development to maximize the chances of your change being accepted.
You can start a conversation by creating a new issue on this repo summarizing
your idea.
Getting Help
===========
If you're having trouble, we have discussion forums at
https://discuss.openedx.org where you can connect with others in the community.
Our real-time conversations are on Slack. You can request a `Slack
invitation`_, then join our `community Slack workspace`_. Because this is a
frontend repository, the best place to discuss it would be in the `#wg-frontend
channel`_.
For anything non-trivial, the best path is to open an issue in this repository
with as many details about the issue you are facing as you can provide.
https://github.com/openedx/frontend-app-gradebook/issues
For more information about these options, see the `Getting Help`_ page.
.. _Slack invitation: https://openedx.org/slack
.. _community Slack workspace: https://openedx.slack.com/
.. _#wg-frontend channel: https://openedx.slack.com/archives/C04BM6YC7A6
.. _Getting Help: https://openedx.org/community/connect
The Open edX Code of Conduct
============================
All community members are expected to follow the `Open edX Code of Conduct`_.
.. _Open edX Code of Conduct: https://openedx.org/code-of-conduct/
Reporting Security Issues
=========================
Please do not report security issues in public. Please email security@openedx.org.

View File

@@ -5,6 +5,9 @@ module.exports = createConfig('jest', {
'<rootDir>/src/setupTest.js',
],
modulePaths: ['<rootDir>/src/'],
snapshotSerializers: [
'enzyme-to-json/serializer',
],
coveragePathIgnorePatterns: [
'src/segment.js',
'src/postcss.config.js',

31989
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@
"scripts": {
"build": "fedx-scripts webpack",
"is-es5": "es-check es5 ./dist/*.js",
"i18n_extract": "fedx-scripts formatjs extract",
"i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null",
"lint": "fedx-scripts eslint --ext .jsx,.js src/",
"lint-fix": "fedx-scripts eslint --fix --ext .jsx,.js src/",
"prepush": "npm run lint",
@@ -28,13 +28,11 @@
"extends @edx/browserslist-config"
],
"dependencies": {
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
"@edx/frontend-component-footer": "12.2.0",
"@edx/frontend-component-header": "4.6.0",
"@edx/frontend-platform": "5.5.4",
"@edx/openedx-atlas": "^0.6.0",
"@edx/paragon": "20.45.0",
"@edx/react-unit-test-utils": "1.7.1",
"@edx/brand": "npm:@edx/brand-openedx@^1.2.0",
"@edx/frontend-component-footer": "^12.0.0",
"@edx/frontend-component-header": "^4.0.0",
"@edx/frontend-platform": "^4.2.0",
"@edx/paragon": "^19.25.4",
"@edx/reactifex": "^2.1.1",
"@fortawesome/fontawesome-svg-core": "^1.2.25",
"@fortawesome/free-brands-svg-icons": "^5.11.2",
@@ -45,16 +43,18 @@
"classnames": "^2.2.6",
"core-js": "3.6.5",
"email-prop-type": "^1.1.7",
"enzyme": "^3.10.0",
"enzyme-to-json": "^3.6.2",
"font-awesome": "4.7.0",
"history": "4.10.1",
"prop-types": "15.8.1",
"query-string": "6.13.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"react": "16.14.0",
"react-dom": "16.14.0",
"react-helmet": "^6.1.0",
"react-redux": "^7.2.9",
"react-router": "6.15.0",
"react-router-dom": "6.15.0",
"react-redux": "^7.1.1",
"react-router": "5.2.0",
"react-router-dom": "5.2.0",
"react-router-redux": "^5.0.0-alpha.9",
"redux": "4.0.5",
"redux-beacon": "^2.1.0",
@@ -67,17 +67,18 @@
},
"devDependencies": {
"@edx/browserslist-config": "^1.1.1",
"@edx/frontend-build": "13.0.1",
"@testing-library/react": "12.1.5",
"@edx/frontend-build": "^12.4.15",
"@testing-library/react": "^12.1.0",
"axios": "0.21.2",
"axios-mock-adapter": "^1.17.0",
"enzyme-adapter-react-16": "^1.14.0",
"es-check": "^2.3.0",
"fetch-mock": "^6.5.2",
"husky": "2.7.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^26.6.3",
"react-dev-utils": "^12.0.1",
"react-test-renderer": "17.0.2",
"react-test-renderer": "^16.10.1",
"reactifex": "1.1.1",
"redux-mock-store": "^1.5.3",
"semantic-release": "^19.0.3"

View File

@@ -1,11 +1,12 @@
import React from 'react';
import { Route, Routes } from 'react-router-dom';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { AppProvider } from '@edx/frontend-platform/react';
import Footer from '@edx/frontend-component-footer';
import Header from '@edx/frontend-component-header';
import { routePath } from 'data/constants/app';
import store from 'data/store';
import GradebookPage from 'containers/GradebookPage';
import './App.scss';
@@ -14,18 +15,21 @@ import Head from './head/Head';
const App = () => (
<AppProvider store={store}>
<Head />
<div>
<Header />
<main>
<Routes>
<Route
path="/:courseId"
element={<GradebookPage />}
/>
</Routes>
</main>
<Footer logo={process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG} />
</div>
<Router>
<div>
<Header />
<main>
<Switch>
<Route
exact
path={routePath}
component={GradebookPage}
/>
</Switch>
</main>
<Footer logo={process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG} />
</div>
</Router>
</AppProvider>
);

View File

@@ -1,70 +1,80 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { Route } from 'react-router-dom';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { AppProvider } from '@edx/frontend-platform/react';
import Footer from '@edx/frontend-component-footer';
import Header from '@edx/frontend-component-header';
import { routePath } from 'data/constants/app';
import store from 'data/store';
import GradebookPage from 'containers/GradebookPage';
import App from './App';
import Head from './head/Head';
jest.mock('react-router-dom', () => ({
BrowserRouter: () => 'BrowserRouter',
Route: () => 'Route',
Routes: () => 'Routes',
Switch: () => 'Switch',
}));
jest.mock('@edx/frontend-platform/react', () => ({
AppProvider: () => 'AppProvider',
}));
jest.mock('data/constants/app', () => ({
routePath: '/:courseId',
}));
jest.mock('@edx/frontend-component-footer', () => 'Footer');
jest.mock('data/store', () => 'testStore');
jest.mock('containers/GradebookPage', () => 'GradebookPage');
jest.mock('@edx/frontend-component-header', () => 'Header');
jest.mock('./head/Head', () => 'Head');
const logo = 'fakeLogo.png';
let el;
let secondChild;
let router;
describe('App router component', () => {
test('snapshot', () => {
expect(shallow(<App />).snapshot).toMatchSnapshot();
expect(shallow(<App />)).toMatchSnapshot();
});
describe('component', () => {
beforeEach(() => {
process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG = logo;
el = shallow(<App />);
secondChild = el.instance.children;
router = el.childAt(1);
});
describe('AppProvider', () => {
test('AppProvider is the parent component, passed the redux store props', () => {
expect(el.instance.type).toBe('AppProvider');
expect(el.instance.props.store).toEqual(store);
expect(el.type()).toBe(AppProvider);
expect(el.props().store).toEqual(store);
});
});
describe('Head', () => {
test('first child of AppProvider', () => {
expect(el.instance.children[0].type).toBe('Head');
expect(el.childAt(0).type()).toBe(Head);
});
});
describe('Router', () => {
test('second child of AppProvider', () => {
expect(secondChild[1].type).toBe('div');
expect(router.type()).toBe(Router);
});
test('Header is above/outside-of the routing', () => {
expect(secondChild[1].children[0].type).toBe('Header');
expect(secondChild[1].children[1].type).toBe('main');
expect(router.childAt(0).childAt(0).type()).toBe(Header);
expect(router.childAt(0).childAt(1).type()).toBe('main');
});
test('Routing - GradebookPage is only route', () => {
expect(secondChild[1].findByType(Route)).toHaveLength(1);
expect(secondChild[1].findByType(Route)[0].props.path).toEqual('/:courseId');
expect(secondChild[1].findByType(Route)[0].props.element.type).toEqual(GradebookPage);
expect(router.find('main')).toEqual(shallow(
<main>
<Switch>
<Route exact path={routePath} component={GradebookPage} />
</Switch>
</main>,
));
});
});
test('Footer logo drawn from env variable', () => {
expect(secondChild[1].findByType(Footer)[0].props.logo).toEqual(logo);
expect(router.find(Footer).props().logo).toEqual(logo);
});
});
});

View File

@@ -5,17 +5,20 @@ exports[`App router component snapshot 1`] = `
store="testStore"
>
<Head />
<div>
<Header />
<main>
<Routes>
<Route
element={<GradebookPage />}
path="/:courseId"
/>
</Routes>
</main>
<Footer />
</div>
<BrowserRouter>
<div>
<Header />
<main>
<Switch>
<Route
component="GradebookPage"
exact={true}
path="/:courseId"
/>
</Switch>
</main>
<Footer />
</div>
</BrowserRouter>
</AppProvider>
`;

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { Alert } from '@edx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
@@ -35,17 +35,17 @@ describe('BulkManagementAlerts', () => {
el = shallow(<BulkManagementAlerts />);
});
test('snapshot - bulkImportError closed, success closed', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('closed danger alert', () => {
expect(el.instance.children[0].type).toBe('Alert');
expect(el.instance.findByType(Alert)[0].props.show).toEqual(false);
expect(el.instance.findByType(Alert)[0].props.variant).toEqual('danger');
expect(el.childAt(0).is(Alert)).toEqual(true);
expect(el.childAt(0).props().show).toEqual(false);
expect(el.childAt(0).props().variant).toEqual('danger');
});
test('closed success alert', () => {
expect(el.instance.children[1].type).toBe('Alert');
expect(el.instance.findByType(Alert)[1].props.show).toEqual(false);
expect(el.instance.findByType(Alert)[1].props.variant).toEqual('success');
expect(el.childAt(1).is(Alert)).toEqual(true);
expect(el.childAt(1).props().show).toEqual(false);
expect(el.childAt(1).props().variant).toEqual('success');
});
});
describe('no errer, no upload success', () => {
@@ -57,19 +57,19 @@ describe('BulkManagementAlerts', () => {
'success alert open with messages.successDialog',
];
test(`snapshot - ${assertions.join(', ')}`, () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('open danger alert with bulkImportError content', () => {
expect(el.instance.children[0].type).toBe('Alert');
expect(el.instance.findByType(Alert)[0].children[0].el).toEqual(errorMessage);
expect(el.instance.findByType(Alert)[0].props.show).toEqual(true);
expect(el.childAt(0).is(Alert)).toEqual(true);
expect(el.childAt(0).children().text()).toEqual(errorMessage);
expect(el.childAt(0).props().show).toEqual(true);
});
test('open success alert with messages.successDialog content', () => {
expect(el.instance.children[1].type).toBe('Alert');
expect(el.shallowWrapper.props.children[1].props.children).toEqual(
expect(el.childAt(1).is(Alert)).toEqual(true);
expect(el.childAt(1).children().getElement()).toEqual(
<FormattedMessage {...messages.successDialog} />,
);
expect(el.instance.children[1].props.show).toEqual(true);
expect(el.childAt(1).props().show).toEqual(true);
});
});
});

View File

@@ -1,6 +1,6 @@
/* eslint-disable import/no-named-as-default */
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { DataTable } from '@edx/paragon';
import selectors from 'data/selectors';
@@ -56,12 +56,12 @@ describe('HistoryTable', () => {
el = shallow(<HistoryTable {...props} />);
});
test('snapshot - loads formatted table', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
describe('history table', () => {
let table;
beforeEach(() => {
table = el.instance.findByType(DataTable);
table = el.find(DataTable);
});
describe('data (from bulkManagementHistory.map(this.formatHistoryRow)', () => {
const fieldAssertions = [
@@ -70,10 +70,10 @@ describe('HistoryTable', () => {
'forwards the rest',
];
test(`snapshot: ${fieldAssertions.join(', ')}`, () => {
expect(table[0].props.data).toMatchSnapshot();
expect(table.props().data).toMatchSnapshot();
});
test(fieldAssertions.join(', '), () => {
const rows = table[0].props.data;
const rows = table.props().data;
expect(rows[0].resultsSummary).toEqual(<ResultsSummary {...entry1.resultsSummary} />);
expect(rows[0].user).toEqual(<span className="wrap-text-in-cell">{entry1.user}</span>);
expect(
@@ -87,7 +87,7 @@ describe('HistoryTable', () => {
});
});
test('columns from bulkManagementColumns', () => {
expect(table[0].props.columns).toEqual(bulkManagementColumns);
expect(table.props().columns).toEqual(bulkManagementColumns);
});
});
});

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { Icon } from '@edx/paragon';
import { Download } from '@edx/paragon/icons';
import lms from 'data/services/lms';
@@ -34,19 +35,19 @@ describe('ResultsSummary component', () => {
el = shallow(<ResultsSummary {...props} />);
});
test(`snapshot - ${assertions.join(', ')}`, () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('Hyperlink has target="_blank" and rel="noopener noreferrer"', () => {
expect(el.instance.props.target).toEqual('_blank');
expect(el.instance.props.rel).toEqual('noopener noreferrer');
expect(el.props().target).toEqual('_blank');
expect(el.props().rel).toEqual('noopener noreferrer');
});
test('Hyperlink has href to bulkGradesUrl', () => {
expect(el.instance.props.href).toEqual(lms.urls.bulkGradesUrlByRow(props.rowId));
expect(el.props().href).toEqual(lms.urls.bulkGradesUrlByRow(props.rowId));
});
test('displays Download Icon and text', () => {
const icon = el.instance.children[0];
expect(icon.type).toEqual('Icon');
expect(icon.props.src).toEqual(Download);
expect(el.instance.children[1].el).toEqual(props.text);
const icon = el.childAt(0);
expect(icon.is(Icon)).toEqual(true);
expect(icon.props().src).toEqual(Download);
expect(el.childAt(1).text()).toEqual(props.text);
});
});

View File

@@ -1,6 +1,6 @@
/* eslint-disable import/no-named-as-default */
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { BulkManagementHistoryView } from '.';
@@ -24,23 +24,20 @@ describe('BulkManagementHistoryView', () => {
'<HistoryTable />',
];
test(`snapshot - loads ${snapshotSegments.join(', ')}`, () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('heading - h4 loaded from messages', () => {
const heading = el.instance.findByType('h4')[0];
const expectedHeading = shallow(
const heading = el.find('h4');
expect(heading.getElement()).toEqual((
<h4>
<FormattedMessage {...messages.heading} />
</h4>,
);
expect(heading.el.type).toEqual(expectedHeading.type);
expect(heading.el.props).toEqual(expectedHeading.props);
</h4>
));
});
test('heading, then alerts, then upload form, then table', () => {
expect(el.instance.children[0].type).toEqual('h4');
expect(el.instance.children[2].type).toEqual(BulkManagementAlerts);
expect(el.instance.children[3].type).toEqual(HistoryTable);
expect(el.childAt(0).is('h4')).toEqual(true);
expect(el.childAt(2).is(BulkManagementAlerts)).toEqual(true);
expect(el.childAt(3).is(HistoryTable)).toEqual(true);
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { getConfig } from '@edx/frontend-platform';
@@ -16,6 +16,6 @@ describe('Header', () => {
test('snapshot - has edx link with logo url', () => {
const url = 'www.ourLogo.url';
getConfig.mockReturnValue({ LOGO_URL: url });
expect(shallow(<Header />).snapshot).toMatchSnapshot();
expect(shallow(<Header />)).toMatchSnapshot();
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
import SelectGroup from '../SelectGroup';
@@ -38,10 +38,10 @@ describe('AssignmentFilter component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('filter options', () => {
const { options } = el.instance.findByType(SelectGroup)[0].props;
const { options } = el.find(SelectGroup).props();
expect(options.length).toEqual(5);
const testOption = assignmentFilterOptions[0];
const optionProps = options[1].props;

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Button } from '@edx/paragon';
@@ -37,20 +37,20 @@ describe('AssignmentFilter component', () => {
describe('render', () => {
describe('with selected assignment', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
it('renders a PercentGroup for both Max and Min filters', () => {
let { props } = el.instance.findByType(PercentGroup)[0];
let props = el.find(PercentGroup).at(0).props();
expect(props.value).toEqual(hookData.assignmentGradeMin);
expect(props.disabled).toEqual(false);
expect(props.onChange).toEqual(hookData.handleSetMin);
props = el.instance.findByType(PercentGroup)[1].props;
props = el.find(PercentGroup).at(1).props();
expect(props.value).toEqual(hookData.assignmentGradeMax);
expect(props.disabled).toEqual(false);
expect(props.onChange).toEqual(hookData.handleSetMax);
});
it('renders a submit button', () => {
const { props } = el.instance.findByType(Button)[0];
const props = el.find(Button).props();
expect(props.disabled).toEqual(false);
expect(props.onClick).toEqual(hookData.handleSubmit);
});
@@ -64,12 +64,12 @@ describe('AssignmentFilter component', () => {
el = shallow(<AssignmentFilter updateQueryParams={updateQueryParams} />);
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
it('disables controls', () => {
let { props } = el.instance.findByType(PercentGroup)[0];
let props = el.find(PercentGroup).at(0).props();
expect(props.disabled).toEqual(true);
props = el.instance.findByType(PercentGroup)[1].props;
props = el.find(PercentGroup).at(1).props();
expect(props.disabled).toEqual(true);
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
import SelectGroup from '../SelectGroup';
@@ -34,10 +34,10 @@ describe('AssignmentFilterType component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('filter options', () => {
const { options } = el.instance.findByType(SelectGroup)[0].props;
const { options } = el.find(SelectGroup).props();
expect(options.length).toEqual(5);
const optionProps = options[1].props;
expect(optionProps.value).toEqual(assignmentTypes[0]);

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Button } from '@edx/paragon';
@@ -42,18 +42,18 @@ describe('CourseFilter component', () => {
describe('render', () => {
describe('with selected assignment', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
it('renders a PercentGroup for both Max and Min filters', () => {
let { props } = el.instance.findByType(PercentGroup)[0];
let props = el.find(PercentGroup).at(0).props();
expect(props.value).toEqual(hookData.min.value);
expect(props.onChange).toEqual(hookData.min.onChange);
props = el.instance.findByType(PercentGroup)[1].props;
props = el.find(PercentGroup).at(1).props();
expect(props.value).toEqual(hookData.max.value);
expect(props.onChange).toEqual(hookData.max.onChange);
});
it('renders a submit button', () => {
const { props } = el.instance.findByType(Button)[0];
const props = el.find(Button).props();
expect(props.disabled).toEqual(false);
expect(props.onClick).toEqual(hookData.handleApplyClick);
});
@@ -64,10 +64,10 @@ describe('CourseFilter component', () => {
el = shallow(<CourseFilter updateQueryParams={updateQueryParams} />);
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
it('disables submit', () => {
const { props } = el.instance.findByType(Button)[0];
const props = el.find(Button).props();
expect(props.disabled).toEqual(true);
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import PercentGroup from './PercentGroup';
@@ -22,11 +22,11 @@ describe('PercentGroup', () => {
describe('snapshots', () => {
test('basic snapshot', () => {
const el = shallow(<PercentGroup {...props} />);
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('disabled', () => {
const el = shallow(<PercentGroup {...props} disabled />);
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import SelectGroup from './SelectGroup';
@@ -27,11 +27,11 @@ describe('SelectGroup', () => {
describe('snapshots', () => {
test('basic snapshot', () => {
const el = shallow(<SelectGroup {...props} />);
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('disabled', () => {
const el = shallow(<SelectGroup {...props} disabled />);
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
import SelectGroup from '../SelectGroup';
@@ -48,14 +48,14 @@ describe('StudentGroupsFilter component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('track options', () => {
const {
options,
onChange,
value,
} = el.instance.findByType(SelectGroup)[0].props;
} = el.find(SelectGroup).at(0).props();
expect(value).toEqual(props.tracks.value);
expect(onChange).toEqual(props.tracks.handleChange);
expect(options.length).toEqual(5);
@@ -70,7 +70,7 @@ describe('StudentGroupsFilter component', () => {
onChange,
disabled,
value,
} = el.instance.findByType(SelectGroup)[1].props;
} = el.find(SelectGroup).at(1).props();
expect(value).toEqual(props.cohorts.value);
expect(disabled).toEqual(false);
expect(onChange).toEqual(props.cohorts.handleChange);

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Collapsible } from '@edx/paragon';
@@ -49,10 +49,10 @@ describe('GradebookFilters', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('Assignment filters', () => {
expect(el.instance.findByType(Collapsible)[0].children[0]).toMatchObject(shallow(
expect(el.find(Collapsible).at(0).children()).toMatchObject(shallow(
<div>
<AssignmentTypeFilter updateQueryParams={updateQueryParams} />
<AssignmentFilter updateQueryParams={updateQueryParams} />
@@ -61,22 +61,22 @@ describe('GradebookFilters', () => {
));
});
test('CourseGrade filters', () => {
expect(el.instance.findByType(Collapsible)[1].children[0]).toMatchObject(shallow(
expect(el.find(Collapsible).at(1).children()).toMatchObject(shallow(
<CourseGradeFilter updateQueryParams={updateQueryParams} />,
));
});
test('StudentGroups filters', () => {
expect(el.instance.findByType(Collapsible)[2].children[0]).toMatchObject(shallow(
expect(el.find(Collapsible).at(2).children()).toMatchObject(shallow(
<StudentGroupsFilter updateQueryParams={updateQueryParams} />,
));
});
test('includeCourseTeamMembers', () => {
const checkbox = el.instance.findByType(Collapsible)[3].children[0];
expect(checkbox.props).toEqual({
const checkbox = el.find(Collapsible).at(3).children();
expect(checkbox.props()).toEqual({
checked: true,
onChange: hookProps.includeCourseTeamMembers.handleChange,
children: formatMessage(messages.includeCourseTeamMembers),
});
expect(checkbox.children[0].el).toEqual(formatMessage(messages.includeCourseTeamMembers));
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Button } from '@edx/paragon';
@@ -40,7 +40,7 @@ describe('GradebookHeader component', () => {
describe('render', () => {
describe('default view', () => {
test('shapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
});
describe('show bulk management', () => {
@@ -49,10 +49,10 @@ describe('GradebookHeader component', () => {
el = shallow(<GradebookHeader />);
});
test('snapshot: show toggle view message button with handleToggleViewClick method', () => {
expect(el.snapshot).toMatchSnapshot();
const { onClick } = el.instance.findByType(Button)[0].props;
expect(el).toMatchSnapshot();
const { onClick, children } = el.find(Button).props();
expect(onClick).toEqual(hookProps.handleToggleViewClick);
expect(el.instance.findByType(Button)[0].children[0].el).toEqual(formatMessage(hookProps.toggleViewMessage));
expect(children).toEqual(formatMessage(hookProps.toggleViewMessage));
});
});
describe('frozen grades', () => {
@@ -61,7 +61,7 @@ describe('GradebookHeader component', () => {
el = shallow(<GradebookHeader />);
});
test('snapshot: show frozen warning', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
});
describe('user cannot view gradebook', () => {
@@ -70,7 +70,7 @@ describe('GradebookHeader component', () => {
el = shallow(<GradebookHeader />);
});
test('snapshot: show unauthorized warning', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import useBulkManagementControlsData from './hooks';
import BulkManagementControls from '.';
@@ -22,7 +22,7 @@ describe('BulkManagementControls', () => {
});
describe('render', () => {
test('snapshot - show - network and import buttons', () => {
expect(shallow(<BulkManagementControls />).snapshot).toMatchSnapshot();
expect(shallow(<BulkManagementControls />)).toMatchSnapshot();
});
test('snapshot - empty if show is not truthy', () => {
useBulkManagementControlsData.mockReturnValueOnce({ ...hookProps, show: false });

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import HistoryHeader from './HistoryHeader';
@@ -11,7 +11,7 @@ describe('HistoryHeader', () => {
};
describe('Component', () => {
test('snapshot', () => {
expect(shallow(<HistoryHeader {...props} />).snapshot).toMatchSnapshot();
expect(shallow(<HistoryHeader {...props} />)).toMatchSnapshot();
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
import { selectors } from 'data/redux/hooks';
@@ -47,10 +47,10 @@ describe('ModalHeaders', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('assignment header', () => {
const headerProps = el.instance.findByType(HistoryHeader)[0].props;
const headerProps = el.find(HistoryHeader).at(0).props();
expect(headerProps).toMatchObject({
id: HistoryKeys.assignment,
label: formatMessage(messages.assignmentHeader),
@@ -58,7 +58,7 @@ describe('ModalHeaders', () => {
});
});
test('student header', () => {
const headerProps = el.instance.findByType(HistoryHeader)[1].props;
const headerProps = el.find(HistoryHeader).at(1).props();
expect(headerProps).toMatchObject({
id: HistoryKeys.student,
label: formatMessage(messages.studentHeader),
@@ -66,7 +66,7 @@ describe('ModalHeaders', () => {
});
});
test('originalGrade header', () => {
const headerProps = el.instance.findByType(HistoryHeader)[2].props;
const headerProps = el.find(HistoryHeader).at(2).props();
expect(headerProps).toMatchObject({
id: HistoryKeys.originalGrade,
label: formatMessage(messages.originalGradeHeader),
@@ -74,7 +74,7 @@ describe('ModalHeaders', () => {
});
});
test('currentGrade header', () => {
const headerProps = el.instance.findByType(HistoryHeader)[3].props;
const headerProps = el.find(HistoryHeader).at(3).props();
expect(headerProps).toMatchObject({
id: HistoryKeys.currentGrade,
label: formatMessage(messages.currentGradeHeader),

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { Form } from '@edx/paragon';
@@ -28,11 +28,11 @@ describe('AdjustedGradeInput component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
const control = el.instance.findByType(Form.Control)[0];
expect(control.props.value).toEqual(hookProps.value);
expect(control.props.onChange).toEqual(hookProps.onChange);
expect(el.instance.children[1].el).toContain(hookProps.hintText);
expect(el).toMatchSnapshot();
const control = el.find(Form.Control);
expect(control.props().value).toEqual(hookProps.value);
expect(control.props().onChange).toEqual(hookProps.onChange);
expect(el.contains(hookProps.hintText)).toEqual(true);
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { Form } from '@edx/paragon';
@@ -28,10 +28,10 @@ describe('ReasonInput component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
const control = el.instance.findByType(Form.Control)[0];
expect(control.props.value).toEqual(hookProps.value);
expect(control.props.onChange).toEqual(hookProps.onChange);
expect(el).toMatchSnapshot();
const control = el.find(Form.Control);
expect(control.props().value).toEqual(hookProps.value);
expect(control.props().onChange).toEqual(hookProps.onChange);
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { DataTable } from '@edx/paragon';
@@ -48,10 +48,10 @@ describe('OverrideTable component', () => {
expect(el.isEmptyRender()).toEqual(true);
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
const table = el.instance.findByType(DataTable)[0];
expect(table.props.columns).toEqual(hookProps.columns);
const data = [...table.props.data];
expect(el).toMatchSnapshot();
const table = el.find(DataTable);
expect(table.props().columns).toEqual(hookProps.columns);
const data = [...table.props().data];
const inputRow = data.pop();
const formattedDate = formatDateForDisplay(new Date());
expect(data).toEqual(hookProps.data);

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import {
ActionRow,
@@ -43,56 +43,60 @@ describe('EditModal component', () => {
});
describe('render', () => {
test('modal props', () => {
const modalProps = el.instance.findByType(ModalDialog)[0].props;
const modalProps = el.find(ModalDialog).props();
expect(modalProps.title).toEqual(formatMessage(messages.title));
expect(modalProps.isOpen).toEqual(hookProps.isOpen);
expect(modalProps.onClose).toEqual(hookProps.onClose);
});
const loadBody = () => {
const body = el.instance.findByType(ModalDialog)[0].children[0];
const { children } = body.children[0];
const body = el.find(ModalDialog).children().at(0);
const children = body.find('div').children();
return { body, children };
};
const testBody = () => {
test('type', () => {
const { body } = loadBody();
expect(body.type).toEqual('ModalDialog.Body');
expect(body.type()).toEqual('ModalDialog.Body');
});
test('headers row', () => {
const { children } = loadBody();
expect(children[0]).toMatchObject(shallow(<ModalHeaders />));
expect(children.at(0)).toMatchObject(shallow(<ModalHeaders />));
});
test('table row', () => {
const { children } = loadBody();
expect(children[2]).toMatchObject(shallow(<OverrideTable />));
expect(children.at(2)).toMatchObject(shallow(<OverrideTable />));
});
test('messages', () => {
const { children } = loadBody();
expect(children[3].children[0].el).toEqual(formatMessage(messages.visibility));
expect(children[4].children[0].el).toEqual(formatMessage(messages.saveVisibility));
expect(
children.at(3).contains(formatMessage(messages.visibility)),
).toEqual(true);
expect(
children.at(4).contains(formatMessage(messages.saveVisibility)),
).toEqual(true);
});
};
const testFooter = () => {
let footer;
beforeEach(() => {
footer = el.instance.findByType(ModalDialog)[0].children;
footer = el.find(ModalDialog).children().at(1);
});
test('type', () => {
expect(footer[1].type).toEqual('ModalDialog.Footer');
expect(footer.type()).toEqual('ModalDialog.Footer');
});
test('contains action row', () => {
expect(footer[1].children[0].type).toEqual('ActionRow');
expect(footer.children().at(0).type()).toEqual('ActionRow');
});
test('close button', () => {
const button = footer[1].findByType(ActionRow)[0].children[0];
expect(button.children[0].el).toEqual(formatMessage(messages.closeText));
expect(button.type).toEqual('ModalDialog.CloseButton');
const button = footer.find(ActionRow).children().at(0);
expect(button.contains(formatMessage(messages.closeText))).toEqual(true);
expect(button.type()).toEqual('ModalDialog.CloseButton');
});
test('adjusted grade button', () => {
const button = footer[1].findByType(ActionRow)[0].children[1];
expect(button.children[0].el).toEqual(formatMessage(messages.saveGrade));
expect(button.type).toEqual('Button');
expect(button.props.onClick).toEqual(hookProps.handleAdjustedGradeClick);
const button = footer.find(ActionRow).children().at(1);
expect(button.contains(formatMessage(messages.saveGrade))).toEqual(true);
expect(button.type()).toEqual('Button');
expect(button.props().onClick).toEqual(hookProps.handleAdjustedGradeClick);
});
};
describe('without error', () => {
@@ -101,26 +105,26 @@ describe('EditModal component', () => {
el = shallow(<EditModal />);
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
testBody();
testFooter();
test('alert row', () => {
const alert = loadBody().children[1];
expect(alert.type).toEqual('Alert');
expect(alert.props.show).toEqual(false);
const alert = loadBody().children.at(1);
expect(alert.type()).toEqual('Alert');
expect(alert.props().show).toEqual(false);
});
});
describe('with error', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
testBody();
test('alert row', () => {
const alert = loadBody().children[1];
expect(alert.type).toEqual('Alert');
expect(alert.props.show).toEqual(true);
expect(alert.children[0].el).toEqual(hookProps.error);
const alert = loadBody().children.at(1);
expect(alert.type()).toEqual('Alert');
expect(alert.props().show).toEqual(true);
expect(alert.contains(hookProps.error)).toEqual(true);
});
testFooter();
});

View File

@@ -32,8 +32,8 @@ export const FilterBadge = ({
return (
<div>
<span className="badge badge-info">
<span data-testid="display-name">{formatMessage(displayName)}</span>
<span data-testid="filter-value">
<span>{formatMessage(displayName)}</span>
<span>
{!hideValue ? `: ${value}` : ''}
</span>
<Button

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
import { formatMessage } from 'testUtils';
@@ -48,12 +48,12 @@ describe('FilterBadge', () => {
describe('render', () => {
const testDisplayName = () => {
test('formatted display name appears on badge', () => {
expect(el.instance.findByTestId('display-name')[0].children[0].el).toEqual(formatMessage(hookProps.displayName));
expect(el.contains(formatMessage(hookProps.displayName))).toEqual(true);
});
};
const testCloseButton = () => {
test('close button forwards close method', () => {
expect(el.instance.findByType(Button)[0].props.onClick).toEqual(handleClose(hookProps.connectedFilters));
expect(el.find(Button).props().onClick).toEqual(handleClose(hookProps.connectedFilters));
});
};
test('empty render if isDefault', () => {
@@ -75,20 +75,20 @@ describe('FilterBadge', () => {
testDisplayName();
testCloseButton();
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('value is note present in the badge', () => {
expect(el.instance.findByTestId('filter-value')[0].children).toHaveLength(0);
expect(el.contains(hookProps.value)).toEqual(false);
});
});
describe('do not hide value', () => {
testDisplayName();
testCloseButton();
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('value is present in the badge', () => {
expect(el.instance.findByTestId('filter-value')[0].children[0].el).toBe(`: ${hookProps.value}`);
test('value is note present in the badge', () => {
expect(el.text().includes(hookProps.value)).toEqual(true);
});
});
});

View File

@@ -5,14 +5,10 @@ exports[`FilterBadge render do not hide value snapshot 1`] = `
<span
className="badge badge-info"
>
<span
data-testid="display-name"
>
<span>
a common name
</span>
<span
data-testid="filter-value"
>
<span>
: a common value
</span>
<Button
@@ -43,14 +39,10 @@ exports[`FilterBadge render hide Value snapshot 1`] = `
<span
className="badge badge-info"
>
<span
data-testid="display-name"
>
<span>
a common name
</span>
<span
data-testid="filter-value"
/>
<span />
<Button
aria-label="close"
className="btn-info"

View File

@@ -1,6 +1,6 @@
/* eslint-disable import/no-named-as-default */
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import FilterBadges from '.';
import FilterBadge from './FilterBadge';
@@ -22,14 +22,14 @@ describe('FilterBadges', () => {
el = shallow(<FilterBadges handleClose={handleClose} />);
});
test('snapshot - has a filterbadge with handleClose for each filter in badgeOrder', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('has a filterbadge with handleClose for each filter in badgeOrder', () => {
const badgeProps = el.instance.findByType(FilterBadge).map(badgeEl => badgeEl.props);
const badgeProps = el.find(FilterBadge).map(badgeEl => badgeEl.props());
// key prop is not rendered by react
expect(badgeProps[0]).toMatchObject({ filterName: order[0], handleClose });
expect(badgeProps[1]).toMatchObject({ filterName: order[1], handleClose });
expect(badgeProps[2]).toMatchObject({ filterName: order[2], handleClose });
expect(badgeProps[0]).toEqual({ filterName: order[0], handleClose });
expect(badgeProps[1]).toEqual({ filterName: order[1], handleClose });
expect(badgeProps[2]).toEqual({ filterName: order[2], handleClose });
expect(badgeProps.length).toEqual(3);
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
@@ -38,10 +38,10 @@ describe('FilterMenuToggle component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el.instance.type).toEqual('Button');
expect(el.instance.props.onClick).toEqual(toggleFilterMenu);
expect(el.instance.children[2].el).toContain(formatMessage(messages.editFilters));
expect(el).toMatchSnapshot();
expect(el.type()).toEqual('Button');
expect(el.props().onClick).toEqual(toggleFilterMenu);
expect(el.text().includes(formatMessage(messages.editFilters)));
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
@@ -46,8 +46,8 @@ describe('FilteredUsersLabel component', () => {
expect(shallow(<FilteredUsersLabel />).isEmptyRender()).toEqual(true);
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el.instance).toMatchObject(shallow(formatMessage(messages.visibilityLabel, {
expect(el).toMatchSnapshot();
expect(el).toMatchObject(shallow(formatMessage(messages.visibilityLabel, {
filteredUsers: <BoldText text={userCounts.filteredUsersCount} />,
totalUsers: <BoldText text={userCounts.totalUsersCount} />,
})));

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import Fields from './Fields';
@@ -16,13 +16,14 @@ describe('Gradebook Table Fields', () => {
el = shallow(<Fields.Username {...props} />);
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('wraps external user key and username', () => {
expect(el.instance.findByType('span')[0].el).toMatchSnapshot();
const content = el.instance.findByType('span')[0].children[0];
expect(content.children[0].children[0].el).toEqual(username);
expect(content.children[1].children[0].el).toEqual(props.userKey);
expect(el.find('span').childAt(0)).toMatchSnapshot();
expect(el.find('span').childAt(0)).toMatchSnapshot();
const content = el.find('span').childAt(0);
expect(content.childAt(0).text()).toEqual(username);
expect(content.childAt(1).text()).toEqual(props.userKey);
});
});
describe('without external_user_key', () => {
@@ -30,12 +31,12 @@ describe('Gradebook Table Fields', () => {
el = shallow(<Fields.Username username={username} />);
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('wraps username only', () => {
const content = el.instance.findByType('span')[0].children[0];
expect(content.children[0].children[0].el).toEqual(username);
expect(content.children).toHaveLength(1);
const content = el.find('span').childAt(0);
expect(content.childAt(0).text()).toEqual(username);
expect(content.children()).toHaveLength(1);
});
});
});
@@ -43,10 +44,10 @@ describe('Gradebook Table Fields', () => {
describe('Text', () => {
const value = 'myTag@place.com';
test('snapshot', () => {
expect(shallow(<Fields.Text value={value} />).snapshot).toMatchSnapshot();
expect(shallow(<Fields.Text value={value} />)).toMatchSnapshot();
});
test('wraps entry value', () => {
expect(shallow(<Fields.Text value={value} />).instance.children[0].el).toEqual(value);
expect(shallow(<Fields.Text value={value} />).text()).toEqual(value);
});
});
});

View File

@@ -11,7 +11,7 @@ export const useGradeButtonData = ({ entry, subsection }) => {
const areGradesFrozen = selectors.assignmentTypes.useAreGradesFrozen();
const { gradeFormat } = selectors.grades.useGradeData();
const setModalState = thunkActions.app.useSetModalStateFromTable();
const label = transforms.grades.subsectionGrade({ gradeFormat, subsection })();
const label = transforms.grades.subsectionGrade({ gradeFormat, subsection });
const onClick = () => {
setModalState({

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { selectors, thunkActions } from 'data/redux/hooks';
import transforms from 'data/redux/transforms';
@@ -41,7 +41,7 @@ const props = {
};
const gradeFormat = 'percent';
const setModalState = jest.fn();
const subsectionGrade = () => 'test-subsection-grade';
const subsectionGrade = 'test-subsection-grade';
selectors.assignmentTypes.useAreGradesFrozen.mockReturnValue(false);
selectors.grades.useGradeData.mockReturnValue({ gradeFormat });
thunkActions.app.useSetModalStateFromTable.mockReturnValue(setModalState);
@@ -73,7 +73,7 @@ describe('GradeButton', () => {
expect(out.areGradesFrozen).toEqual(false);
});
test('label passed from subsection grade redux hook', () => {
expect(out.label).toEqual(subsectionGrade());
expect(out.label).toEqual(subsectionGrade);
});
test('onClick sets modal state with user entry and subsection', () => {
out.onClick();
@@ -101,8 +101,8 @@ describe('GradeButton', () => {
el = shallow(<GradeButton {...props} />);
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el.instance.el).toEqual(hookProps.label);
expect(el).toMatchSnapshot();
expect(el.text()).toEqual(hookProps.label);
});
});
describe('not frozen grades', () => {
@@ -111,10 +111,10 @@ describe('GradeButton', () => {
el = shallow(<GradeButton {...props} />);
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el.instance.type).toEqual('Button');
expect(el.instance.props.onClick).toEqual(hookProps.onClick);
expect(el.instance.children[0].el).toEqual(hookProps.label);
expect(el).toMatchSnapshot();
expect(el.type()).toEqual('Button');
expect(el.props().onClick).toEqual(hookProps.onClick);
expect(el.contains(hookProps.label)).toEqual(true);
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { getLocale } from '@edx/frontend-platform/i18n';
import { OverlayTrigger } from '@edx/paragon';
@@ -25,15 +25,15 @@ describe('LabelReplacements', () => {
el = shallow(<TotalGradeLabelReplacement />);
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('displays overlay tooltip', () => {
expect(el.instance.findByType(OverlayTrigger)[0].props.overlay).toMatchSnapshot();
expect(el.find(OverlayTrigger).props().overlay).toMatchSnapshot();
});
});
describe('UsernameLabelReplacement', () => {
test('snapshot', () => {
expect(shallow(<UsernameLabelReplacement />).snapshot).toMatchSnapshot();
expect(shallow(<UsernameLabelReplacement />)).toMatchSnapshot();
});
});
describe('MastersOnlyLabelReplacement', () => {
@@ -43,7 +43,7 @@ describe('LabelReplacements', () => {
defaultMessage: 'defaultMessAge',
description: 'desCripTion',
};
expect(shallow(<MastersOnlyLabelReplacement {...message} />).snapshot).toMatchSnapshot();
expect(shallow(<MastersOnlyLabelReplacement {...message} />)).toMatchSnapshot();
});
});
});
@@ -53,11 +53,11 @@ describe('snapshot', () => {
test('right to left overlay placement', () => {
getLocale.mockImplementation(() => 'en');
el = shallow(<TotalGradeLabelReplacement />);
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('left to right overlay placement', () => {
getLocale.mockImplementation(() => 'ar');
el = shallow(<TotalGradeLabelReplacement />);
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
});

View File

@@ -28,36 +28,29 @@ exports[`Gradebook Table Fields Username with external_user_key snapshot 1`] = `
`;
exports[`Gradebook Table Fields Username with external_user_key wraps external user key and username 1`] = `
Object {
"children": Array [
Object {
"children": Array [
Object {
"children": Array [
"MyNameFromHere",
],
"props": Object {},
"type": "div",
},
Object {
"children": Array [
"My name from another land",
],
"props": Object {
"className": "student-key",
},
"type": "div",
},
],
"props": Object {},
"type": "div",
},
],
"props": Object {
"className": "wrap-text-in-cell",
},
"type": "span",
}
<div>
<div>
MyNameFromHere
</div>
<div
className="student-key"
>
My name from another land
</div>
</div>
`;
exports[`Gradebook Table Fields Username with external_user_key wraps external user key and username 2`] = `
<div>
<div>
MyNameFromHere
</div>
<div
className="student-key"
>
My name from another land
</div>
</div>
`;
exports[`Gradebook Table Fields Username without external_user_key snapshot 1`] = `

View File

@@ -39,7 +39,7 @@ export const useGradebookTableData = () => {
[Headings.username]: (
<Fields.Username username={entry.username} userKey={entry.external_user_key} />
),
[Headings.email]: (<Fields.Text value={entry.email} />),
[Headings.email]: (<Fields.Email email={entry.email} />),
[Headings.totalGrade]: `${roundGrade(entry.percent * 100)}${getLocalizedPercentSign()}`,
...entry.section_breakdown.reduce((acc, subsection) => ({
...acc,

View File

@@ -1,4 +1,4 @@
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
@@ -22,7 +22,7 @@ jest.mock('i18n/utils', () => ({
jest.mock('./GradeButton', () => 'GradeButton');
jest.mock('./Fields', () => jest.requireActual('testUtils').mockNestedComponents({
Username: 'Fields.Username',
Text: 'Fields.Text',
Email: 'Fields.Email',
}));
jest.mock('./LabelReplacements', () => jest.requireActual('testUtils').mockNestedComponents({
TotalGradeLabelReplacement: 'LabelReplacements.TotalGradeLabelReplacement',
@@ -158,7 +158,7 @@ describe('useGradebookTableData', () => {
test('email field', () => {
allGrades.forEach((entry, index) => {
expect(out.data[index][Headings.email]).toMatchObject(
<Fields.Text value={entry.email} />,
<Fields.Email email={entry.email} />,
);
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { DataTable } from '@edx/paragon';
@@ -24,16 +24,16 @@ describe('GradebookTable', () => {
el = shallow(<GradebookTable />);
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('Datatable props', () => {
const datatable = el.instance.findByType(DataTable)[0];
const { props } = datatable;
const datatable = el.find(DataTable);
const props = datatable.props();
expect(props.columns).toEqual(hookProps.columns);
expect(props.data).toEqual(hookProps.data);
expect(props.itemCount).toEqual(hookProps.grades.length);
expect(props.RowStatusComponent).toEqual(hookProps.nullMethod);
expect(datatable.children[2].type).toEqual('DataTable.EmptyTable');
expect(datatable.children[2].props.content).toEqual(hookProps.emptyContent);
expect(datatable.children().at(2).type()).toEqual('DataTable.EmptyTable');
expect(datatable.children().at(2).props().content).toEqual(hookProps.emptyContent);
});
});

View File

@@ -1,24 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ImportGradesButton component render Form 1`] = `
<Form
action="test-grade-export-url"
method="post"
>
<Form.Group
controlId="csv"
>
<Form.Control
className="d-none"
data-testid="file-control"
label="Upload Grade CSV"
onChange={[MockFunction props.handleFileInputChange]}
type="file"
/>
</Form.Group>
</Form>
`;
exports[`ImportGradesButton component render snapshot 1`] = `
<Fragment>
<Form
@@ -32,7 +13,7 @@ exports[`ImportGradesButton component render snapshot 1`] = `
className="d-none"
data-testid="file-control"
label="Upload Grade CSV"
onChange={[MockFunction props.handleFileInputChange]}
onChange={[MockFunction]}
type="file"
/>
</Form.Group>
@@ -47,7 +28,7 @@ exports[`ImportGradesButton component render snapshot 1`] = `
"id": "gradebook.GradesView.importGradesBtnText",
}
}
onClick={[MockFunction props.handleClickImportGrades]}
onClick={[MockFunction]}
/>
</Fragment>
`;

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Form } from '@edx/paragon';
@@ -18,8 +18,8 @@ describe('ImportGradesButton component', () => {
props = {
fileInputRef: { current: null },
gradeExportUrl: 'test-grade-export-url',
handleClickImportGrades: jest.fn().mockName('props.handleClickImportGrades'),
handleFileInputChange: jest.fn().mockName('props.handleFileInputChange'),
handleClickImportGrades: jest.fn(),
handleFileInputChange: jest.fn(),
};
useImportGradesButtonData.mockReturnValue(props);
el = shallow(<ImportGradesButton />);
@@ -32,15 +32,14 @@ describe('ImportGradesButton component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('Form', () => {
expect(el.instance.findByType(Form)[0].snapshot).toMatchSnapshot();
expect(el.instance.findByType(Form)[0].props.action).toEqual(props.gradeExportUrl);
expect(el.instance.findByType(Form.Control)[0].props.onChange).toEqual(props.handleFileInputChange);
expect(el.find(Form).props().action).toEqual(props.gradeExportUrl);
expect(el.find(Form.Control).props().onChange).toEqual(props.handleFileInputChange);
});
test('import button', () => {
expect(el.instance.findByType(NetworkButton)[0].props.onClick).toEqual(props.handleClickImportGrades);
expect(el.find(NetworkButton).props().onClick).toEqual(props.handleClickImportGrades);
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import useImportSuccessToastData from './hooks';
import ImportSuccessToast from '.';
@@ -26,14 +26,14 @@ describe('ImportSuccessToast component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('Toast', () => {
expect(el.instance.type).toEqual('Toast');
expect(el.instance.props.action).toEqual(hookProps.action);
expect(el.instance.props.onClose).toEqual(hookProps.onClose);
expect(el.instance.props.show).toEqual(hookProps.show);
expect(el.instance.children[0].el).toEqual(hookProps.description);
expect(el.type()).toEqual('Toast');
expect(el.props().action).toEqual(hookProps.action);
expect(el.props().onClose).toEqual(hookProps.onClose);
expect(el.props().show).toEqual(hookProps.show);
expect(el.text()).toEqual(hookProps.description);
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
@@ -33,8 +33,8 @@ describe('InterventionsReport component', () => {
expect(el.isEmptyRender()).toEqual(true);
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
const btnProps = el.instance.findByType(NetworkButton)[0].props;
expect(el).toMatchSnapshot();
const btnProps = el.find(NetworkButton).props();
expect(btnProps.label).toEqual(messages.downloadBtn);
expect(btnProps.onClick).toEqual(hookProps.handleClick);
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { Button } from '@edx/paragon';
@@ -35,19 +35,19 @@ describe('PageButtons component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('prev button', () => {
const button = el.instance.findByType(Button)[0];
expect(button.props.disabled).toEqual(hookProps.prev.disabled);
expect(button.props.onClick).toEqual(hookProps.prev.onClick);
expect(button.children[0].el).toEqual(hookProps.prev.text);
const button = el.find(Button).at(0);
expect(button.props().disabled).toEqual(hookProps.prev.disabled);
expect(button.props().onClick).toEqual(hookProps.prev.onClick);
expect(button.text()).toEqual(hookProps.prev.text);
});
test('next button', () => {
const button = el.instance.findByType(Button)[1];
expect(button.props.disabled).toEqual(hookProps.next.disabled);
expect(button.props.onClick).toEqual(hookProps.next.onClick);
expect(button.children[0].el).toEqual(hookProps.next.text);
const button = el.find(Button).at(1);
expect(button.props().disabled).toEqual(hookProps.next.disabled);
expect(button.props().onClick).toEqual(hookProps.next.onClick);
expect(button.text()).toEqual(hookProps.next.text);
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { useIntl } from '@edx/frontend-platform/i18n';
import { GradeFormats } from 'data/constants/grades';
@@ -40,27 +40,27 @@ describe('ScoreViewInput component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('label', () => {
const label = el.instance.children[0];
expect(label.children[0].el).toEqual(`${formatMessage(messages.scoreView)}`);
const label = el.children().at(0);
expect(label.text()).toEqual(`${formatMessage(messages.scoreView)}:`);
});
describe('form control', () => {
let control;
beforeEach(() => {
control = el.instance.children;
control = el.children().at(1);
});
test('value and onChange from redux hooks', () => {
expect(control[1].props.value).toEqual(gradeFormat);
expect(control[1].props.onChange).toEqual(toggleGradeFormat);
expect(control.props().value).toEqual(gradeFormat);
expect(control.props().onChange).toEqual(toggleGradeFormat);
});
test('absolute and percent options', () => {
const { children } = control[1];
expect(children[0].props.value).toEqual(GradeFormats.percent);
expect(children[0].children[0].el).toEqual(formatMessage(messages.percent));
expect(children[1].props.value).toEqual(GradeFormats.absolute);
expect(children[1].children[0].el).toEqual(formatMessage(messages.absolute));
const children = control.children();
expect(children.at(0).props().value).toEqual(GradeFormats.percent);
expect(children.at(0).text()).toEqual(formatMessage(messages.percent));
expect(children.at(1).props().value).toEqual(GradeFormats.absolute);
expect(children.at(1).text()).toEqual(formatMessage(messages.absolute));
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { SearchField } from '@edx/paragon';
@@ -31,10 +31,10 @@ describe('SearchControls component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('search field', () => {
const { props } = el.instance.findByType(SearchField)[0];
const props = el.find(SearchField).props();
expect(props.onSubmit).toEqual(hookProps.onSubmit);
expect(props.onBlur).toEqual(hookProps.onBlur);
expect(props.onClear).toEqual(hookProps.onClear);
@@ -42,7 +42,7 @@ describe('SearchControls component', () => {
expect(props.value).toEqual(hookProps.searchValue);
});
test('hint text', () => {
expect(el.instance.findByType('small')[0].children[0].el).toEqual(hookProps.hintText);
expect(el.find('small').text()).toEqual(hookProps.hintText);
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { selectors } from 'data/redux/hooks';
import SpinnerIcon from './SpinnerIcon';
@@ -29,7 +29,7 @@ describe('SpinnerIcon', () => {
expect(el.isEmptyRender()).toEqual(true);
});
test('snapshot - displays spinner overlay with spinner icon', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { Alert } from '@edx/paragon';
@@ -34,20 +34,20 @@ describe('StatusAlerts component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('success banner', () => {
const alert = el.instance.findByType(Alert)[0];
const { props } = alert;
const alert = el.find(Alert).at(0);
const props = alert.props();
expect(props.onClose).toEqual(hookProps.successBanner.onClose);
expect(props.show).toEqual(hookProps.successBanner.show);
expect(alert.children[0].el).toEqual(hookProps.successBanner.text);
expect(alert.text()).toEqual(hookProps.successBanner.text);
});
test('grade filter banner', () => {
const alert = el.instance.findByType(Alert)[1];
const { props } = alert;
const alert = el.find(Alert).at(1);
const props = alert.props();
expect(props.show).toEqual(hookProps.gradeFilter.show);
expect(alert.children[0].el).toEqual(hookProps.gradeFilter.text);
expect(alert.text()).toEqual(hookProps.gradeFilter.text);
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import FilterBadges from './FilterBadges';
@@ -46,10 +46,10 @@ describe('GradesView component', () => {
});
describe('render', () => {
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
test('filterBadges load close behavior from hook', () => {
expect(el.instance.findByType(FilterBadges)[0].props.handleClose).toEqual(
expect(el.find(FilterBadges).props().handleClose).toEqual(
hookProps.handleFilterBadgeClose,
);
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { Icon, StatefulButton } from '@edx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
@@ -37,10 +37,10 @@ describe('NetworkButton component', () => {
beforeEach(() => {
props.onClick = jest.fn();
el = shallow(<NetworkButton {...props} />);
btnProps = el.instance.findByType(StatefulButton)[0].props;
btnProps = el.find(StatefulButton).props();
});
test('snapshot', () => {
expect(el.snapshot).toMatchSnapshot();
expect(el).toMatchSnapshot();
});
it('sets labels to translated label prop', () => {
expect(btnProps.labels).toEqual({
@@ -58,8 +58,8 @@ describe('NetworkButton component', () => {
});
describe('import icons', () => {
it('sets icons with spinner pending icon and upload default', () => {
el = shallow(<NetworkButton {...props} import />);
expect(el.instance.findByType(StatefulButton)[0].props.icons).toEqual({
el.setProps({ import: true });
expect(el.find(StatefulButton).props().icons).toEqual({
pending: (<Icon className="fa mr-2 fa-spinner fa-spin" />),
default: (<Icon className="fa mr-2 fa-upload" />),
});
@@ -70,8 +70,8 @@ describe('NetworkButton component', () => {
expect(btnProps.state).toEqual(buttonStates.default);
});
it('is set to pending state if props.showSpinner', () => {
el = shallow(<NetworkButton {...props} showSpinner />);
expect(el.instance.findByType(StatefulButton)[0].props.state).toEqual(buttonStates.pending);
el.setProps({ showSpinner: true });
expect(el.find(StatefulButton).props().state).toEqual(buttonStates.pending);
expect(btnProps.state).toEqual(buttonStates.default);
});
});

View File

@@ -5,7 +5,7 @@ exports[`WithSidebar Component snapshots basic snapshot 1`] = `
className="d-flex sidebar-container page-gradebook"
>
<aside
className="sidebar d-none"
className="sidebar-class-names"
onTransitionEnd={[MockFunction handleSlideDone]}
>
<div>
@@ -13,7 +13,7 @@ exports[`WithSidebar Component snapshots basic snapshot 1`] = `
</div>
</aside>
<div
className="sidebar-contents position-relative"
className="content-class-names"
>
<b>
aby in a bi

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import selectors from 'data/selectors';
import thunkActions from 'data/thunkActions';
@@ -56,34 +56,30 @@ describe('WithSidebar', () => {
el = shallow(<WithSidebar {...props} />);
});
describe('sidebarClassNames', () => {
const getVal = () => [
...el.instance.props.className.split(' '),
...el.instance.children[0].props.className.split(' '),
...el.instance.children[1].props.className.split(' '),
];
const getVal = () => el.instance().sidebarClassNames.split(' ');
it('returns a "sidebar" classname', () => {
expect(getVal()).toContain('sidebar');
});
it('includes an open className iff props.open', () => {
expect(getVal()).not.toContain('open');
el = shallow(<WithSidebar {...props} open />);
el.setProps({ open: true });
expect(getVal()).toContain('open');
});
it('includes a d-none className iff props.isClosed', () => {
expect(getVal()).toContain('d-none');
el = shallow(<WithSidebar {...props} isClosed={false} />);
el.setProps({ isClosed: false });
expect(getVal()).not.toContain('d-none');
});
});
describe('contentClassNames', () => {
const getVal = () => el.instance.children[1].props.className.split(' ');
const getVal = () => el.instance().contentClassNames.split(' ');
it('includes sidebar-contents and position-relative classNames', () => {
expect(getVal()).toContain('sidebar-contents');
expect(getVal()).toContain('position-relative');
});
it('includes an opening class iff props.isOpening', () => {
expect(getVal()).not.toContain('opening');
el = shallow(<WithSidebar {...props} isOpening />);
el.setProps({ isOpening: true });
expect(getVal()).toContain('opening');
});
});
@@ -91,7 +87,11 @@ describe('WithSidebar', () => {
describe('snapshots', () => {
test('basic snapshot', () => {
const el = shallow(<WithSidebar {...props} />);
expect(el.snapshot).toMatchSnapshot();
const sidebarClassNames = 'sidebar-class-names';
const contentClassNames = 'content-class-names';
jest.spyOn(el.instance(), 'sidebarClassNames', 'get').mockReturnValue(sidebarClassNames);
jest.spyOn(el.instance(), 'contentClassNames', 'get').mockReturnValue(contentClassNames);
expect(el.instance().render()).toMatchSnapshot();
});
});
});

View File

@@ -4,7 +4,7 @@ exports[`GradebookPage component snapshot - shows BulkManagementHistoryView if a
<WithSidebar
sidebar={
<GradebookFilters
updateQueryParams={[Function]}
updateQueryParams={[MockFunction updateQueryParams]}
/>
}
>
@@ -21,7 +21,7 @@ exports[`GradebookPage component snapshot - shows GradesView if aciveView === vi
<WithSidebar
sidebar={
<GradebookFilters
updateQueryParams={[Function]}
updateQueryParams={[MockFunction updateQueryParams]}
/>
}
>
@@ -30,7 +30,7 @@ exports[`GradebookPage component snapshot - shows GradesView if aciveView === vi
>
<GradebookHeader />
<GradesView
updateQueryParams={[Function]}
updateQueryParams={[MockFunction updateQueryParams]}
/>
</div>
</WithSidebar>

View File

@@ -14,8 +14,6 @@ import GradesView from 'components/GradesView';
import GradebookFilters from 'components/GradebookFilters';
import BulkManagementHistoryView from 'components/BulkManagementHistoryView';
import { withParams, withNavigate, withLocation } from '../../utils/hoc';
/**
* <GradebookPage />
* Top-level view for the Gradebook MFE.
@@ -30,11 +28,10 @@ export class GradebookPage extends React.Component {
componentDidMount() {
const urlQuery = queryString.parse(this.props.location.search);
this.props.initializeApp(this.props.courseId, urlQuery);
this.props.initializeApp(this.props.match.params.courseId, urlQuery);
}
updateQueryParams(queryParams) {
const { pathname } = this.props.location;
const parsed = queryString.parse(this.props.location.search);
Object.keys(queryParams).forEach((key) => {
if (queryParams[key]) {
@@ -43,7 +40,7 @@ export class GradebookPage extends React.Component {
delete parsed[key];
}
});
this.props.navigate({ pathname, search: `?${queryString.stringify(parsed)}` });
this.props.history.push(`?${queryString.stringify(parsed)}`);
}
render() {
@@ -63,12 +60,18 @@ export class GradebookPage extends React.Component {
}
}
GradebookPage.defaultProps = {
location: { pathname: '/', search: '' },
location: { search: '' },
};
GradebookPage.propTypes = {
navigate: PropTypes.func.isRequired,
location: PropTypes.shape({ pathname: PropTypes.string, search: PropTypes.string }),
courseId: PropTypes.string.isRequired,
history: PropTypes.shape({
push: PropTypes.func,
}).isRequired,
location: PropTypes.shape({ search: PropTypes.string }),
match: PropTypes.shape({
params: PropTypes.shape({
courseId: PropTypes.string,
}),
}).isRequired,
// redux
activeView: PropTypes.string.isRequired,
initializeApp: PropTypes.func.isRequired,
@@ -82,4 +85,4 @@ export const mapDispatchToProps = {
initializeApp: thunkActions.app.initialize,
};
export default connect(mapStateToProps, mapDispatchToProps)(withParams(withNavigate(withLocation(GradebookPage))));
export default connect(mapStateToProps, mapDispatchToProps)(GradebookPage);

View File

@@ -1,7 +1,6 @@
/* eslint-disable import/no-named-as-default */
import React from 'react';
import { render } from '@testing-library/react'; // eslint-disable-line import/no-extraneous-dependencies
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import queryString from 'query-string';
import selectors from 'data/selectors';
@@ -51,23 +50,24 @@ describe('GradebookPage', () => {
let el;
const props = {
location: {
pathname: '/',
search: 'searchString',
},
courseId,
match: { params: { courseId } },
activeView: views.grades,
};
beforeEach(() => {
props.initializeApp = jest.fn();
props.navigate = jest.fn();
props.history = { push: jest.fn() };
});
test('snapshot - shows BulkManagementHistoryView if activeView === views.bulkManagementHistory', () => {
el = shallow(<GradebookPage {...props} activeView={views.bulkManagementHistory} />);
expect(el.snapshot).toMatchSnapshot();
el.instance().updateQueryParams = jest.fn().mockName('updateQueryParams');
expect(el.instance().render()).toMatchSnapshot();
});
test('snapshot - shows GradesView if aciveView === views.grades', () => {
el = shallow(<GradebookPage {...props} />);
expect(el.snapshot).toMatchSnapshot();
el.instance().updateQueryParams = jest.fn().mockName('updateQueryParams');
expect(el.instance().render()).toMatchSnapshot();
});
describe('render', () => {
beforeEach(() => {
@@ -75,9 +75,9 @@ describe('GradebookPage', () => {
});
describe('top-level WithSidebar', () => {
test('sidebar from GradebookFilters, with updateQueryParams', () => {
const { sidebar } = el.instance.props;
expect(sidebar).toMatchObject(
<GradebookFilters updateQueryParams={el.shallowWrapper.props.sidebar.props.updateQueryParams} />,
const { sidebar } = el.props();
expect(sidebar).toEqual(
<GradebookFilters updateQueryParams={el.instance().updateQueryParams} />,
);
});
});
@@ -85,37 +85,37 @@ describe('GradebookPage', () => {
let content;
let children;
beforeEach(() => {
content = el.instance.children;
children = content[0].children;
content = el.props().children;
children = content.props.children;
});
it('is wrapped in a div w/ px-3 gradebook-content classNames', () => {
expect(content[0].type).toEqual('div');
expect(content[0].props.className).toEqual('px-3 gradebook-content');
expect(content.type).toEqual('div');
expect(content.props.className).toEqual('px-3 gradebook-content');
});
it('displays Gradebook header and then tabs', () => {
expect(shallow(children[0])).toEqual(shallow(<GradebookHeader />));
expect(children[0]).toEqual(<GradebookHeader />);
});
it('displays GradesView if activeView === views.grades', () => {
expect(shallow(children[1])).toEqual(shallow((
<GradesView updateQueryParams={el.shallowWrapper.props.sidebar.props.updateQueryParams} />
<GradesView updateQueryParams={el.instance().updateQueryParams} />
)));
});
it('displays Bulk Management History View if activeView === views.bulkManagementHistory', () => {
el = shallow(<GradebookPage {...props} activeView={views.bulkManagementHistory} />);
const mainView = el.instance.children[0].children[1];
expect(shallow(mainView)).toEqual(shallow(
<BulkManagementHistoryView />,
const mainView = el.props().children.props.children[1];
expect(mainView).toEqual((
<BulkManagementHistoryView />
));
});
});
});
describe('behavior', () => {
beforeEach(() => {
el = shallow(<GradebookPage {...props} />);
el = shallow(<GradebookPage {...props} />, { disableLifecucleMethods: true });
});
describe('componentDidMount', () => {
test('initializes app with courseId and urlQuery', () => {
render(<GradebookPage {...props} />);
el.instance().componentDidMount();
expect(props.initializeApp).toHaveBeenCalledWith(
courseId,
queryString.parse(props.location.search),
@@ -129,8 +129,8 @@ describe('GradebookPage', () => {
const val1 = 'VALUE';
const val2 = 'VALTWO!!';
const args = { [newKey]: val1, [props.location.search]: val2 };
el.shallowWrapper.props.sidebar.props.updateQueryParams(args);
expect(props.navigate).toHaveBeenCalledWith({ pathname: '/', search: `?${queryString.stringify(args)}` });
el.instance().updateQueryParams(args);
expect(props.history.push).toHaveBeenCalledWith(`?${queryString.stringify(args)}`);
});
it('clears values for non-truthy values', () => {
queryString.parse.mockImplementation(key => ({ [key]: key }));
@@ -138,9 +138,9 @@ describe('GradebookPage', () => {
const val1 = 'VALUE';
const val2 = false;
const args = { [newKey]: val1, [props.location.search]: val2 };
el.shallowWrapper.props.sidebar.props.updateQueryParams(args);
expect(props.navigate).toHaveBeenCalledWith(
{ pathname: '/', search: `?${queryString.stringify({ [newKey]: val1 })}` },
el.instance().updateQueryParams(args);
expect(props.history.push).toHaveBeenCalledWith(
`?${queryString.stringify({ [newKey]: val1 })}`,
);
});
});

View File

@@ -1,4 +1,7 @@
import { StrictDict } from 'utils';
import { getConfig } from '@edx/frontend-platform';
export const routePath = `${getConfig().PUBLIC_PATH}:courseId`;
export const views = StrictDict({
grades: 'grades',

View File

@@ -10,7 +10,7 @@ import { fetchGrades } from './grades';
import { fetchTracks } from './tracks';
import { fetchAssignmentTypes } from './assignmentTypes';
export const allowedRoles = ['staff', 'limited_staff', 'instructor', 'support'];
export const allowedRoles = ['staff', 'instructor', 'support'];
export const fetchRoles = () => (
(dispatch, getState) => {

View File

@@ -1,5 +1,6 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { shallow } from 'enzyme';
import { Helmet } from 'react-helmet';
import { getConfig } from '@edx/frontend-platform';
import Head from './Head';
@@ -20,10 +21,11 @@ getConfig.mockReturnValue(config);
describe('Head', () => {
it('should match render title tag and favicon with the site configuration values', () => {
const el = shallow(<Head />);
const title = el.instance.findByType('title')[0];
const link = el.instance.findByType('link')[0];
expect(title.children[0].el).toEqual(`Gradebook | ${config.SITE_NAME}`);
expect(link.props.rel).toEqual('shortcut icon');
expect(link.props.href).toEqual(config.FAVICON_URL);
const helmet = el.find(Helmet);
const title = helmet.find('title');
const link = el.find('link');
expect(title.props().children).toEqual(`Gradebook | ${config.SITE_NAME}`);
expect(link.props().rel).toEqual('shortcut icon');
expect(link.props().href).toEqual(config.FAVICON_URL);
});
});

View File

@@ -1,6 +1,5 @@
import { messages as footerMessages } from '@edx/frontend-component-footer';
import { messages as headerMessages } from '@edx/frontend-component-header';
import { messages as paragonMessages } from '@edx/paragon';
import arMessages from './messages/ar.json';
import deMessages from './messages/de.json';
@@ -32,7 +31,6 @@ const appMessages = {
};
export default [
paragonMessages,
footerMessages,
headerMessages,
appMessages,

View File

@@ -1,3 +1,10 @@
/* eslint-disable import/no-extraneous-dependencies */
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
// These configuration values are usually set in webpack's EnvironmentPlugin however
// Jest does not use webpack so we need to set these so for testing
process.env.LMS_BASE_URL = 'http://localhost:18000';

View File

@@ -1,24 +0,0 @@
import React from 'react';
import { useLocation, useNavigate, useParams } from 'react-router-dom';
export const withParams = WrappedComponent => {
const WithParamsComponent = props => <WrappedComponent {...useParams()} {...props} />;
return WithParamsComponent;
};
export const withNavigate = WrappedComponent => {
const WithNavigateComponent = props => {
const navigate = useNavigate();
return <WrappedComponent navigate={navigate} {...props} />;
};
return WithNavigateComponent;
};
export const withLocation = WrappedComponent => {
const WithLocationComponent = props => {
const location = useLocation();
return <WrappedComponent location={location} {...props} />;
};
return WithLocationComponent;
};

View File

@@ -1,38 +0,0 @@
import React from 'react';
import { fireEvent, render } from '@testing-library/react';
import { withLocation, withNavigate } from './hoc';
const mockedNavigator = jest.fn();
jest.mock('react-router-dom', () => ({
useNavigate: () => mockedNavigator,
useLocation: () => ({
pathname: '/current-location',
}),
}));
// eslint-disable-next-line react/prop-types
const MockComponent = ({ navigate, location }) => (
// eslint-disable-next-line react/button-has-type, react/prop-types
<button id="btn" onClick={() => navigate('/some-route')}>{location.pathname}</button>
);
const WrappedComponent = withNavigate(withLocation(MockComponent));
test('Provide Navigation to Component', () => {
const wrapper = render(
<WrappedComponent />,
);
const btn = wrapper.container.querySelector('#btn');
fireEvent.click(btn);
expect(mockedNavigator).toHaveBeenCalledWith('/some-route');
});
test('Provide Location object to Component', () => {
const wrapper = render(
<WrappedComponent />,
);
expect(wrapper.container.querySelector('#btn').textContent).toContain('/current-location');
});