Fix AppFilters spec on master build

Test Plan:
 n/a

Change-Id: I210c97d4e24ccbf5e7827103a3ca211b9ca27bee
Reviewed-on: https://gerrit.instructure.com/167771
Tested-by: Jenkins
Reviewed-by: Weston Dransfield <wdransfield@instructure.com>
QA-Review: Weston Dransfield <wdransfield@instructure.com>
Product-Review: Marc Phillips <mphillips@instructure.com>
This commit is contained in:
Marc Phillips 2018-10-10 13:06:00 -06:00
parent 7fb2a50d1a
commit 91fe52ff86
8 changed files with 236 additions and 157 deletions

View File

@ -18,7 +18,7 @@
import I18n from 'i18n!external_tools'
import React from 'react'
import store from '../../external_apps/lib/AppCenterStore'
import store from '../lib/AppCenterStore'
import $ from 'jquery'
import 'compiled/jquery.rails_flash_notifications'
@ -64,7 +64,7 @@ export default class AppFilters extends React.Component {
<ul className="nav nav-pills" role="tablist">
<li className={activeFilter === 'all' ? 'active' : ''}>
<a
ref="tabAll"
ref={c => (this.tabAll = c)}
onClick={this.handleFilterClick.bind(this, 'all')}
href="#"
role="tab"
@ -75,7 +75,7 @@ export default class AppFilters extends React.Component {
</li>
<li className={activeFilter === 'not_installed' ? 'active' : ''}>
<a
ref="tabNotInstalled"
ref={c => (this.tabNotInstalled = c)}
onClick={this.handleFilterClick.bind(this, 'not_installed')}
href="#"
role="tab"
@ -86,7 +86,7 @@ export default class AppFilters extends React.Component {
</li>
<li className={activeFilter === 'installed' ? 'active' : ''}>
<a
ref="tabInstalled"
ref={c => (this.tabInstalled = c)}
onClick={this.handleFilterClick.bind(this, 'installed')}
href="#"
role="tab"
@ -99,7 +99,7 @@ export default class AppFilters extends React.Component {
window.ENV.LTI_13_TOOLS_FEATURE_FLAG_ENABLED &&
<li className={activeFilter === 'lti_1_3_tools' ? 'active' : ''}>
<a
ref="tabLti13Tools"
ref={c => (this.tabLti13Tools = c)}
onClick={this.handleFilterClick.bind(this, 'lti_1_3_tools')}
href="#"
role="tab"

View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2018 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
import {mount} from 'enzyme'
import store from '../../lib/AppCenterStore'
import AppFilters from '../AppFilters'
const defaultApps = () => [
{
app_type: null,
average_rating: 0,
banner_image_url:
'https://edu-app-center.s3.amazonaws.com/uploads/production/lti_app/banner_image/acclaim_app.png',
config_options: [],
config_xml_url: 'https://www.eduappcenter.com/configurations/g7lthtepu68qhchz.xml',
custom_tags: [
'Assessment',
'Community',
'Content',
'Media',
'7th-12th Grade',
'Postsecondary',
'Open Content',
'Web 2.0'
],
description:
'\n<p>Acclaim is the easiest way to organize and annotate videos for class.</p>\n\n<p>Instructors and students set up folders, upload recordings or embed relevant web videos, and then securely share access among each other. Moments in each video can then be highlighted and discussed using time-specific comments!</p>\n\n<p>To learn more about how to use Acclaim in your class(es), email Melinda at <a href="mailto:melinda@getacclaim.com">melinda@getacclaim.com</a>.</p>\n\n<p>For general information, please visit <a href="https://getacclaim.com">Acclaim</a>.</p>\n',
icon_image_url: null,
id: 289,
is_certified: false,
is_installed: true,
logo_image_url: null,
name: 'Acclaim',
preview_url: '',
requires_secret: true,
short_description: 'Acclaim is the easiest way to organize and annotate videos.',
short_name: 'acclaim_app',
status: 'active',
total_ratings: 0
},
{
app_type: null,
average_rating: 5,
banner_image_url:
'https://edu-app-center.s3.amazonaws.com/uploads/production/lti_app/banner_image/aleks.png',
config_options: [],
config_xml_url: 'https://www.eduappcenter.com/configurations/fn4dnjhl0ot1ka4j.xml',
custom_tags: ['Community', 'Content', 'K-6th Grade', '7th-12th Grade', 'Postsecondary'],
description:
'\n<p>ALEKS is an artificial intelligent assessment and learning system which uses adaptive questioning to quickly and accurately determine exactly what a student knows and doesn\u2019t know in a course.</p>\n\n<p>ALEKS\u2019s LTI support included external assignments that pass grades back to the LMS.</p>\n\n<p>Visit the <a href="http://www.aleks.com/highered/math/training_center">ALEKS Training Center</a> for directions on configuring your ALEKS Higher Education school account. Look for the \u2018LTI Integration\u2019 section.</p>\n',
icon_image_url: null,
id: 66,
is_certified: true,
is_installed: true,
logo_image_url: 'http://www.edu-apps.org/tools/aleks/logo.png',
name: 'ALEKS',
preview_url: '',
requires_secret: true,
short_description:
'ALEKS is an artificial intelligent assessment and learning system which uses adaptive questioning to quickly and accurately determine exactly what a student kno...',
short_name: 'aleks',
status: 'active',
total_ratings: 2
},
{
app_type: 'custom',
average_rating: 4,
banner_image_url:
'https://edu-app-center.s3.amazonaws.com/uploads/production/lti_app/banner_image/apprennet.png',
config_options: [],
config_xml_url: 'https://www.apprennet.com/lti-config.xml',
custom_tags: ['Community', 'Postsecondary'],
description:
'\n<p>Integrate hands-on learning exercises into your course. With ApprenNet\u2019s LTI APP, you can add exercises to your course in which participants 1) submit video responses, 2) review their peers, 3) receive feedback and 4) engage with experts. Make e-learning interactive and social.</p>\n\n<p><a href="https://www.apprennet.com/users/sign_up_guide">Start a free trial!</a> and then, if you like what you see, request a key and secret by emailing contact@apprennet.com.</p>\n',
icon_image_url: null,
id: 127,
is_certified: false,
logo_image_url:
'https://s3.amazonaws.com/assets01.apprennet.com/lti-bounty/apprennet-logo-2-72x72.png',
name: 'ApprenNet',
preview_url: 'https://www.youtube.com/embed/sJ81INPRNa0',
requires_secret: true,
short_description:
"Integrate hands-on learning exercises into your course. With ApprenNet's LTI APP, you can add exercises to your course in which participants 1) submit video res...",
short_name: 'apprennet',
status: 'active',
total_ratings: 1
}
]
let wrapper = 'empty wrapper'
beforeEach(() => {
window.ENV = {LTI_13_TOOLS_FEATURE_FLAG_ENABLED: true}
store.setState({apps: defaultApps()})
})
afterEach(() => {
wrapper.unmount()
store.reset()
})
it('changes the filter to not_installed on Not Installed tab click', () => {
wrapper = mount(<AppFilters />)
wrapper.find('a[children="Not Installed"]').simulate('click')
expect(store.getState().filter).toEqual('not_installed')
})
it('changes the filter to installed on Installed tab click', () => {
wrapper = mount(<AppFilters />)
wrapper.find('a[children="Installed"]').simulate('click')
expect(store.getState().filter).toEqual('installed')
})
it('changes the filter to lti_1_3_tools on LTI 1.3 tab click', () => {
wrapper = mount(<AppFilters />)
wrapper.find('a[children="LTI 1.3"]').simulate('click')
expect(store.getState().filter).toEqual('lti_1_3_tools')
})

View File

@ -19,8 +19,8 @@
import $ from 'jquery'
import I18n from 'i18n!external_tools'
import _ from 'underscore'
import createStore from '../../shared/helpers/createStore'
import ExternalAppsStore from '../../external_apps/lib/ExternalAppsStore'
import createStore from '../../shared/helpers/createStoreJestCompatible'
import ExternalAppsStore from './ExternalAppsStore'
import parseLinkHeader from 'compiled/fn/parseLinkHeader'
import 'compiled/jquery.rails_flash_notifications'

View File

@ -19,7 +19,7 @@
import I18n from 'i18n!external_tools'
import $ from 'jquery'
import _ from 'underscore'
import createStore from '../../shared/helpers/createStore'
import createStore from '../../shared/helpers/createStoreJestCompatible'
import parseLinkHeader from 'compiled/fn/parseLinkHeader'
import 'compiled/jquery.rails_flash_notifications'

View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2014 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Creates a data store with some initial state.
*
* ```js
* var UserStore = createStore({loaded: false, users: []});
*
* UserStore.load = function() {
* $.getJSON('/users', function(users) {
* UserStore.setState({loaded: true, users});
* });
* };
* ```
*
* Then in a component:
*
* ```js
* var UsersView = React.createClass({
* getInitialState () {
* return UserStore.getState();
* },
*
* componentDidMount () {
* UserStore.addChangeListener(this.handleStoreChange);
* UserStore.load();
* },
*
* handleStoreChange () {
* this.setState(UserStore.getState());
* }
* });
* ```
*/
function createStore(initialState = {}) {
let state = initialState
const listeners = {}
return {
setState (newState) {
state = Object.assign({}, state, newState)
this.emitChange()
},
getState () {
return state
},
clearState () {
state = {}
this.emitChange()
},
addChangeListener (listener) {
listeners[listener] = listener
},
removeChangeListener (listener) {
delete listeners[listener]
},
emitChange () {
Object.values(listeners).forEach(listener => listener())
}
}
}
export default createStore

View File

@ -35,6 +35,8 @@ it('sums numbers', () => {
All `expect()` matchers supported by Jest are [extensively documented here](http://facebook.github.io/jest/docs/api.html#expect-value).<br>
You can also use [`jest.fn()` and `expect(fn).toBeCalled()`](http://facebook.github.io/jest/docs/api.html#tobecalled) to create “spies” or mock functions and in jest tests you should probably use that instead of sinon mocks/spies/stubs like we use in our QUnit tests.
*NOTE: You cannot run jest if there is anything with AMD, CoffeeScript, or some of the Webpack aliases (which lead to AMD or CoffeeScript).
### Testing Components
There is a broad spectrum of component testing techniques. They range from a “smoke test” using a jest snapshot, to shallow rendering and testing some of the output, to full rendering and testing component lifecycle and state changes.

View File

@ -1,148 +0,0 @@
/*
* Copyright (C) 2014 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
import ReactDOM from 'react-dom'
import TestUtils from 'react-dom/test-utils'
import store from 'jsx/external_apps/lib/AppCenterStore'
import AppFilters from 'jsx/external_apps/components/AppFilters'
const {Simulate} = TestUtils
const wrapper = document.getElementById('fixtures')
const createElement = () => <AppFilters />
const renderComponent = () => ReactDOM.render(createElement(), wrapper)
const getDOMNodes = function() {
const component = renderComponent()
const tabAll = component.refs.tabAll
const tabNotInstalled = component.refs.tabNotInstalled
const tabInstalled = component.refs.tabInstalled
const filterText = component.refs.filterText
const lti13tools = component.refs.tabLti13Tools
return [component, tabAll, tabNotInstalled, tabInstalled, lti13tools, filterText]
}
QUnit.module('ExternalApps.AppFilters', {
setup() {
this.apps = [
{
app_type: null,
average_rating: 0,
banner_image_url:
'https://edu-app-center.s3.amazonaws.com/uploads/production/lti_app/banner_image/acclaim_app.png',
config_options: [],
config_xml_url: 'https://www.eduappcenter.com/configurations/g7lthtepu68qhchz.xml',
custom_tags: [
'Assessment',
'Community',
'Content',
'Media',
'7th-12th Grade',
'Postsecondary',
'Open Content',
'Web 2.0'
],
description:
'\n<p>Acclaim is the easiest way to organize and annotate videos for class.</p>\n\n<p>Instructors and students set up folders, upload recordings or embed relevant web videos, and then securely share access among each other. Moments in each video can then be highlighted and discussed using time-specific comments!</p>\n\n<p>To learn more about how to use Acclaim in your class(es), email Melinda at <a href="mailto:melinda@getacclaim.com">melinda@getacclaim.com</a>.</p>\n\n<p>For general information, please visit <a href="https://getacclaim.com">Acclaim</a>.</p>\n',
icon_image_url: null,
id: 289,
is_certified: false,
is_installed: true,
logo_image_url: null,
name: 'Acclaim',
preview_url: '',
requires_secret: true,
short_description: 'Acclaim is the easiest way to organize and annotate videos.',
short_name: 'acclaim_app',
status: 'active',
total_ratings: 0
},
{
app_type: null,
average_rating: 5,
banner_image_url:
'https://edu-app-center.s3.amazonaws.com/uploads/production/lti_app/banner_image/aleks.png',
config_options: [],
config_xml_url: 'https://www.eduappcenter.com/configurations/fn4dnjhl0ot1ka4j.xml',
custom_tags: ['Community', 'Content', 'K-6th Grade', '7th-12th Grade', 'Postsecondary'],
description:
'\n<p>ALEKS is an artificial intelligent assessment and learning system which uses adaptive questioning to quickly and accurately determine exactly what a student knows and doesn\u2019t know in a course.</p>\n\n<p>ALEKS\u2019s LTI support included external assignments that pass grades back to the LMS.</p>\n\n<p>Visit the <a href="http://www.aleks.com/highered/math/training_center">ALEKS Training Center</a> for directions on configuring your ALEKS Higher Education school account. Look for the \u2018LTI Integration\u2019 section.</p>\n',
icon_image_url: null,
id: 66,
is_certified: true,
is_installed: true,
logo_image_url: 'http://www.edu-apps.org/tools/aleks/logo.png',
name: 'ALEKS',
preview_url: '',
requires_secret: true,
short_description:
'ALEKS is an artificial intelligent assessment and learning system which uses adaptive questioning to quickly and accurately determine exactly what a student kno...',
short_name: 'aleks',
status: 'active',
total_ratings: 2
},
{
app_type: 'custom',
average_rating: 4,
banner_image_url:
'https://edu-app-center.s3.amazonaws.com/uploads/production/lti_app/banner_image/apprennet.png',
config_options: [],
config_xml_url: 'https://www.apprennet.com/lti-config.xml',
custom_tags: ['Community', 'Postsecondary'],
description:
'\n<p>Integrate hands-on learning exercises into your course. With ApprenNet\u2019s LTI APP, you can add exercises to your course in which participants 1) submit video responses, 2) review their peers, 3) receive feedback and 4) engage with experts. Make e-learning interactive and social.</p>\n\n<p><a href="https://www.apprennet.com/users/sign_up_guide">Start a free trial!</a> and then, if you like what you see, request a key and secret by emailing contact@apprennet.com.</p>\n',
icon_image_url: null,
id: 127,
is_certified: false,
logo_image_url:
'https://s3.amazonaws.com/assets01.apprennet.com/lti-bounty/apprennet-logo-2-72x72.png',
name: 'ApprenNet',
preview_url: 'https://www.youtube.com/embed/sJ81INPRNa0',
requires_secret: true,
short_description:
"Integrate hands-on learning exercises into your course. With ApprenNet's LTI APP, you can add exercises to your course in which participants 1) submit video res...",
short_name: 'apprennet',
status: 'active',
total_ratings: 1
}
]
store.reset()
window.ENV.LTI_13_TOOLS_FEATURE_FLAG_ENABLED = true
return store.setState({apps: this.apps})
},
teardown() {
store.reset()
ReactDOM.unmountComponentAtNode(wrapper)
}
})
test('renders', () => {
const [component, tabAll, tabNotInstalled, tabInstalled, lti13tools, filterText] = Array.from(getDOMNodes())
ok(component)
ok(TestUtils.isCompositeComponentWithType(component, AppFilters))
})
test('sets filter on click', () => {
const [component, tabAll, tabNotInstalled, tabInstalled, lti13tools, filterText] = Array.from(getDOMNodes())
equal(store.getState().filter, 'all')
Simulate.click(tabNotInstalled)
equal(store.getState().filter, 'not_installed')
Simulate.click(tabInstalled)
equal(store.getState().filter, 'installed')
Simulate.click(lti13tools)
equal(store.getState().filter, 'lti_1_3_tools')
})

View File

@ -143,7 +143,7 @@ test('filteredApps', function() {
})
test('filteredApps of lti 1.3 tools', function() {
store.setState({filterText: 'e'})
store.setState({filterText: 'tool', lti13Tools: this})
equal(store.filteredApps(this.lti13Tools).length, 1)
})
@ -172,6 +172,7 @@ test('fetch13Tools', function() {
})
test('installTool', function() {
store.setState({lti13Tools: this.lti13Tools})
notOk(store.getState().lti13Tools.find(tool => tool.app_id === '1').enabled)
notOk(store.getState().lti13Tools.find(tool => tool.app_id === '1').installed_locally)
this.server.respondWith('POST', /\/create_tool/, [
@ -186,6 +187,7 @@ test('installTool', function() {
})
test('removeTool', function() {
store.setState({lti13Tools: this.lti13Tools})
store._toggle_lti_1_3_tool_enabled('1')(true)
ok(store.getState().lti13Tools.find(tool => tool.app_id === '1').enabled)
ok(store.getState().lti13Tools.find(tool => tool.app_id === '1').installed_locally)