Change spec file to Jest

refs MAT-1152
flag=none

Test plan
- Specs pass (and we're sure this file ran)

Change-Id: I69c26c8c2a7a277ee865b0491bb13ff0f71591db
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/310185
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Ed Schiebel <eschiebel@instructure.com>
QA-Review: Jake Oeding <jake.oeding@instructure.com>
Product-Review: Mysti Lilla <mysti@instructure.com>
This commit is contained in:
Mysti Lilla 2023-02-01 18:05:14 -07:00
parent 5b0b557027
commit 1547e8dbe0
3 changed files with 282 additions and 322 deletions

View File

@ -23,7 +23,7 @@ module.exports = {
'\\.svg$': '<rootDir>/jest/imageMock.js',
'node_modules-version-of-backbone': require.resolve('backbone'),
'node_modules-version-of-react-modal': require.resolve('react-modal'),
'underscore$': require.resolve('lodash-underscore'),
underscore$: require.resolve('lodash-underscore'),
'^Backbone$': '<rootDir>/public/javascripts/Backbone.js',
// jest can't import the icons
'@instructure/ui-icons/es/svg': '<rootDir>/packages/canvas-rce/src/rce/__tests__/_mockIcons.js',
@ -36,9 +36,9 @@ module.exports = {
'@tinymce/tinymce-react': '<rootDir>/packages/canvas-rce/src/rce/__mocks__/tinymceReact.js',
'decimal.js/decimal.mjs': 'decimal.js/decimal.js',
// https://github.com/ai/nanoid/issues/363
"^nanoid(/(.*)|$)": "nanoid$1",
'^nanoid(/(.*)|$)': 'nanoid$1',
},
roots: ['<rootDir>/ui', 'gems/plugins', 'public/javascripts'],
roots: ['<rootDir>/ui', 'gems/plugins', 'public/javascripts', 'packages/mathml'],
moduleDirectories: ['ui/shims', 'public/javascripts', 'node_modules'],
reporters: [
'default',
@ -48,16 +48,16 @@ module.exports = {
suiteName: 'Jest Tests',
outputDirectory: process.env.TEST_RESULT_OUTPUT_DIR || './coverage-js/junit-reports',
outputName: 'jest.xml',
addFileAttribute: 'true'
}
]
addFileAttribute: 'true',
},
],
],
snapshotSerializers: ['enzyme-to-json/serializer'],
setupFiles: ['jest-localstorage-mock', 'jest-canvas-mock', '<rootDir>/jest/jest-setup.js'],
setupFilesAfterEnv: [
'@testing-library/jest-dom/extend-expect',
'./packages/validated-apollo/src/ValidatedApolloCleanup.js',
'<rootDir>/jest/stubInstUi.js'
'<rootDir>/jest/stubInstUi.js',
],
testMatch: ['**/__tests__/**/?(*.)(spec|test).[jt]s?(x)'],
@ -68,7 +68,7 @@ module.exports = {
// k5_dashboard: LS-2243
collectCoverageFrom: [
'**/__tests__/**/?(*.)(spec|test).[jt]s?(x)',
'!<rootDir>/ui/features/k5_dashboard/react/__tests__/k5DashboardPlanner.test.js'
'!<rootDir>/ui/features/k5_dashboard/react/__tests__/k5DashboardPlanner.test.js',
],
moduleFileExtensions: [...defaults.moduleFileExtensions, 'coffee', 'handlebars'],
@ -90,16 +90,16 @@ module.exports = {
{
// until we're on Jest 27 and can look into loading ESMs natively;
// https://jestjs.io/docs/ecmascript-modules
modules: 'commonjs'
}
modules: 'commonjs',
},
],
['@babel/preset-react', {useBuiltIns: true}],
['@babel/preset-typescript', {}]
['@babel/preset-typescript', {}],
],
targets: {
node: 'current'
}
}
]
}
node: 'current',
},
},
],
},
}

View File

@ -0,0 +1,266 @@
/*
* Copyright (C) 2017 - 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 $ from 'jquery'
import mathml, {mathImageHelper} from '..'
let stub = null
describe('MathML and MathJax it', () => {
beforeEach(() => {
const mathElem = document.createElement('math')
mathElem.innerHTML = '<mi>&#x3C0;</mi> <msup> <mi>r</mi> <mn>2</mn> </msup>'
document.body.innerHTML = mathElem.outerHTML
window.ENV.locale = 'en'
})
afterEach(() => {
jest.clearAllMocks()
stub = null
delete window.MathJax
delete window.MathJaxIsLoading
document.body.innerHTML = ''
})
it('loadMathJax loads mathJax', () => {
stub = jest.spyOn($, 'ajax')
mathml.loadMathJax('bogus')
expect(stub).toHaveBeenCalledTimes(1)
})
it('loadMathJax does not load mathJax', () => {
stub = jest.spyOn($, 'ajax')
window.MathJax = {
Hub: {
Queue: () => {},
},
}
mathml.loadMathJax('bogus')
expect(stub).not.toHaveBeenCalled()
})
it("loadMathJax doesn't download mathjax if in-flight", () => {
stub = jest.spyOn($, 'ajax')
mathml.loadMathJax('bogus')
mathml.loadMathJax('bogus')
expect(stub).toHaveBeenCalledTimes(1)
})
it('isMathJaxLoaded return true', () => {
window.MathJax = {Hub: {}}
expect(mathml.isMathJaxLoaded()).toBeTruthy()
})
it('reloadElement reloads the element', () => {
window.MathJax = {
Hub: {
Queue: jest.fn(),
},
}
mathml.reloadElement('content')
expect(window.MathJax.Hub.Queue).toHaveBeenCalledTimes(1)
})
})
describe('isMathInElement', () => {
beforeEach(() => {
window.ENV = {
FEATURES: {},
}
})
it('returns true if there is mathml', () => {
const mathElem = document.createElement('div')
mathElem.innerHTML = '<math><mi>&#x3C0;</mi> <msup> <mi>r</mi> <mn>2</mn> </msup></math>'
document.body.innerHTML = mathElem.outerHTML
expect(mathml.isMathInElement(mathElem)).toBeTruthy()
})
it('returns false if there is a .math_equation_latex element', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '<span class="math_equation_latex">2 + 2</span>'
document.body.innerHTML = mathElem.outerHTML
expect(mathml.isMathInElement(mathElem)).toBeFalsy()
})
})
describe('isMathInElement, with new_math_equation_handling on', () => {
beforeEach(() => {
window.ENV = {
FEATURES: {
new_math_equation_handling: true,
},
}
})
it('returns true if there is mathml', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '<math><mi>&#x3C0;</mi> <msup> <mi>r</mi> <mn>2</mn> </msup>></math>'
document.body.innerHTML = mathElem.outerHTML
expect(mathml.isMathInElement(mathElem)).toBeTruthy()
})
it('returns true if there is a .math_equation_latex element', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '<span class="math_equation_latex">2 + 2</span>'
document.body.innerHTML = mathElem.outerHTML
expect(mathml.isMathInElement(mathElem)).toBeTruthy()
})
it('returns true if there is block-delmited math', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '$$y = mx + b$$'
document.body.innerHTML = mathElem.outerHTML
expect(mathml.isMathInElement(mathElem)).toBeTruthy()
})
it('returns true if there is inline-delmited math', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '\\(ax^2 + by + c = 0\\)'
document.body.innerHTML = mathElem.outerHTML
expect(mathml.isMathInElement(mathElem)).toBeTruthy()
})
it('handles "process-new-math" event', () => {
stub = jest.spyOn(mathml, 'processNewMathInElem')
const elem = document.createElement('span')
window.dispatchEvent(new CustomEvent('process-new-math', {detail: {target: elem}}))
expect(stub).toHaveBeenCalledWith(elem)
})
})
describe('mathEquationHelper', () => {
beforeEach(() => {
window.ENV = {
FEATURES: {
new_math_equation_handling: true,
inline_math_everywhere: true,
},
}
document.body.innerHTML = ''
})
afterEach(() => {
document.body.innerHTML = ''
})
it('getImageEquationText does not use data-equation-content', () => {
const img = document.createElement('img')
const txt = encodeURIComponent(encodeURIComponent('y = sqrt{x}'))
img.setAttribute('src', `http://host/equation_images/${txt}`)
img.setAttribute('data-equation-content', 'never use me')
expect(mathImageHelper.getImageEquationText(img)).toEqual('y = sqrt{x}')
})
it('getImageEquationText uses img src as the source of truth', () => {
const img = document.createElement('img')
const txt = encodeURIComponent(encodeURIComponent('y = sqrt{x}'))
img.setAttribute('src', `http://host/equation_images/${txt}`)
img.setAttribute('data-equation-content', 'never use me')
expect(mathImageHelper.getImageEquationText(img)).toEqual('y = sqrt{x}')
})
it('getImageEquationText returns undefined if there is no src', () => {
const img = document.createElement('img')
const txt = encodeURIComponent(encodeURIComponent('y = sqrt{x}'))
img.setAttribute('alt', `http://host/not_equation_images/${txt}`)
expect(mathImageHelper.getImageEquationText(img)).toBeUndefined()
})
it('getImageEquationText returns undefined if it is not an equation image', () => {
const img = document.createElement('img')
const txt = encodeURIComponent(encodeURIComponent('y = sqrt{x}'))
img.setAttribute('src', `http://host/not_equation_images/${txt}`)
expect(mathImageHelper.getImageEquationText(img)).toBeUndefined()
})
it('catchEquationImages processes equation images', () => {
const root = document.body
root.innerHTML = `
<img id="i2"
class="equation_image"
src="data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw=="
>
<img id="i2"
class="equation_image"
src="http://localhost:3000/equation_images/17?scale=1.5"
>
`
mathImageHelper.catchEquationImages(root)
expect(document.querySelectorAll('img[mathjaxified]').length).toEqual(1)
expect(document.querySelector('.math_equation_latex').textContent).toEqual('\\(17\\)')
})
it('removeStrayEquationImages only removes tagged images', () => {
const root = document.body
root.innerHTML = `
<img id="i1" class="equation_image">
<img id="i2" class="equation_image" mathjaxified>
`
mathImageHelper.removeStrayEquationImages(root)
expect(document.getElementById('i1')).toBeTruthy()
expect(document.getElementById('i2')).toBeNull()
})
})
describe('isMathJaxIgnored', () => {
beforeEach(() => {
window.ENV = {
FEATURES: {
new_math_equation_handling: true,
inline_math_everywhere: true,
},
}
document.body.innerHTML = ''
})
afterEach(() => {
document.body.innerHTML = ''
})
it('ignores elements in the ignore list', () => {
const root = document.body
const elem = document.createElement('span')
elem.setAttribute('id', 'quiz-elapsed-time')
root.appendChild(elem)
expect(mathml.isMathJaxIgnored(elem)).toBeTruthy()
})
it('ignores descendents of .mathjax_ignore', () => {
const root = document.body
const ignored = document.createElement('span')
ignored.setAttribute('class', 'mathjax_ignore')
root.appendChild(ignored)
const elem = document.createElement('span')
elem.textContent = 'ignore me'
ignored.appendChild(elem)
expect(mathml.isMathJaxIgnored(elem)).toBeTruthy()
})
it('deals with disconnected elements', () => {
// even though they should never get here
const elem = document.createElement('span')
expect(mathml.isMathJaxIgnored(elem)).toBeTruthy()
})
it('handles missing element', () => {
expect(mathml.isMathJaxIgnored()).toBeTruthy()
})
})

View File

@ -1,306 +0,0 @@
/*
* Copyright (C) 2017 - 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 $ from 'jquery'
import mathml, {mathImageHelper} from 'mathml'
let stub = null
QUnit.module('MathML and MathJax test', {
beforeEach: () => {
const mathElem = document.createElement('math')
mathElem.innerHTML = '<mi>&#x3C0;</mi> <msup> <mi>r</mi> <mn>2</mn> </msup>'
document.getElementById('fixtures').innerHTML = mathElem.outerHTML
window.ENV.locale = 'en'
},
afterEach: () => {
stub && stub.restore()
stub = null
delete window.MathJax
delete window.MathJaxIsLoading
},
after: () => {
document.getElementById('fixtures').innerHTML = ''
},
})
test('loadMathJax loads mathJax', () => {
stub = sinon.stub($, 'ajax')
mathml.loadMathJax('bogus')
ok($.ajax.calledOnce)
})
test('loadMathJax does not load mathJax', () => {
stub = sinon.stub($, 'ajax')
window.MathJax = {
Hub: {
Queue: () => {},
},
}
mathml.loadMathJax('bogus')
ok(!$.ajax.called)
})
test("loadMathJax doesn't download mathjax if in-flight", () => {
stub = sinon.stub($, 'ajax')
mathml.loadMathJax('bogus')
mathml.loadMathJax('bogus')
sinon.assert.calledOnce($.ajax)
})
test('isMathJaxLoaded return true', () => {
window.MathJax = {Hub: {}}
ok(mathml.isMathJaxLoaded())
})
test('reloadElement reloads the element', () => {
window.MathJax = {
Hub: {
Queue: () => {},
},
}
stub = sinon.stub(window.MathJax.Hub, 'Queue')
mathml.reloadElement('content')
ok(window.MathJax.Hub.Queue.called)
})
QUnit.module('isMathInElement', {
beforeEach: () => {
window.ENV = {
FEATURES: {},
}
},
})
test('returns true if there is mathml', () => {
const mathElem = document.createElement('div')
mathElem.innerHTML = '<math><mi>&#x3C0;</mi> <msup> <mi>r</mi> <mn>2</mn> </msup></math>'
document.getElementById('fixtures').innerHTML = mathElem.outerHTML
equal(mathml.isMathInElement(mathElem), true)
})
test('returns false if there is a .math_equation_latex element', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '<span class="math_equation_latex">2 + 2</span>'
document.getElementById('fixtures').innerHTML = mathElem.outerHTML
equal(mathml.isMathInElement(mathElem), false)
})
QUnit.module('isMathInElement, with new_math_equation_handling on', {
beforeEach: () => {
window.ENV = {
FEATURES: {
new_math_equation_handling: true,
inline_math_everywhere: true,
},
}
},
})
test('returns true if there is mathml', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '<math><mi>&#x3C0;</mi> <msup> <mi>r</mi> <mn>2</mn> </msup>></math>'
document.getElementById('fixtures').innerHTML = mathElem.outerHTML
equal(mathml.isMathInElement(mathElem), true)
})
test('returns true if there is a .math_equation_latex element', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '<span class="math_equation_latex">2 + 2</span>'
document.getElementById('fixtures').innerHTML = mathElem.outerHTML
equal(mathml.isMathInElement(mathElem), true)
})
test('returns true if there is block-delmited math', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '$$y = mx + b$$'
document.getElementById('fixtures').innerHTML = mathElem.outerHTML
equal(mathml.isMathInElement(mathElem), true)
})
test('returns true if there is inline-delmited math', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '\\(ax^2 + by + c = 0\\)'
document.getElementById('fixtures').innerHTML = mathElem.outerHTML
equal(mathml.isMathInElement(mathElem), true)
})
QUnit.module('isMathInElement, including inline LaTex', {
beforeEach: () => {
window.ENV = {
FEATURES: {
new_math_equation_handling: true,
inline_math_everywhere: true,
},
}
},
})
test('returns true if there is mathml', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '<math><mi>&#x3C0;</mi> <msup> <mi>r</mi> <mn>2</mn> </msup></math>'
document.getElementById('fixtures').innerHTML = mathElem.outerHTML
equal(mathml.isMathInElement(mathElem), true)
})
test('returns true if there is a .math_equation_latex element', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '<span class="math_equation_latex">2 + 2</span>'
document.getElementById('fixtures').innerHTML = mathElem.outerHTML
equal(mathml.isMathInElement(mathElem), true)
})
test('returns true if there is block-delmited math', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '$$y = mx + b$$'
document.getElementById('fixtures').innerHTML = mathElem.outerHTML
equal(mathml.isMathInElement(mathElem), true)
})
test('returns true if there is inline-delmited math', () => {
const mathElem = document.createElement('span')
mathElem.innerHTML = '\\(ax^2 + by + c = 0\\)'
document.getElementById('fixtures').innerHTML = mathElem.outerHTML
equal(mathml.isMathInElement(mathElem), true)
})
test('handles "process-new-math" event', () => {
const spy = sinon.spy(mathml, 'processNewMathInElem')
const elem = document.createElement('span')
window.dispatchEvent(new CustomEvent('process-new-math', {detail: {target: elem}}))
ok(spy.calledWith(elem))
})
QUnit.module('mathEquationHelper', {
beforeEach: () => {
window.ENV = {
FEATURES: {
new_math_equation_handling: true,
inline_math_everywhere: true,
},
}
document.getElementById('fixtures').innerHTML = ''
},
afterEach: () => {
document.getElementById('fixtures').innerHTML = ''
},
})
test('getImageEquationText does not use data-equation-content', () => {
const img = document.createElement('img')
const txt = encodeURIComponent(encodeURIComponent('y = sqrt{x}'))
img.setAttribute('src', `http://host/equation_images/${txt}`)
img.setAttribute('data-equation-content', 'never use me')
equal(mathImageHelper.getImageEquationText(img), 'y = sqrt{x}')
})
test('getImageEquationText uses img src as the source of truth', () => {
const img = document.createElement('img')
const txt = encodeURIComponent(encodeURIComponent('y = sqrt{x}'))
img.setAttribute('src', `http://host/equation_images/${txt}`)
img.setAttribute('data-equation-content', 'never use me')
equal(mathImageHelper.getImageEquationText(img), 'y = sqrt{x}')
})
test('getImageEquationText returns undefined if there is no src', () => {
const img = document.createElement('img')
const txt = encodeURIComponent(encodeURIComponent('y = sqrt{x}'))
img.setAttribute('alt', `http://host/not_equation_images/${txt}`)
equal(mathImageHelper.getImageEquationText(img), undefined)
})
test('getImageEquationText returns undefined if it is not an equation image', () => {
const img = document.createElement('img')
const txt = encodeURIComponent(encodeURIComponent('y = sqrt{x}'))
img.setAttribute('src', `http://host/not_equation_images/${txt}`)
equal(mathImageHelper.getImageEquationText(img), undefined)
})
test('catchEquationImages processes equation images', () => {
const root = document.getElementById('fixtures')
root.innerHTML = `
<img id="i2"
class="equation_image"
src="data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw=="
>
<img id="i2"
class="equation_image"
src="http://localhost:3000/equation_images/17?scale=1.5"
>
`
mathImageHelper.catchEquationImages(root)
equal(document.querySelectorAll('img[mathjaxified]').length, 1)
equal(document.querySelector('.math_equation_latex').textContent, '\\(17\\)')
})
test('removeStrayEquationImages only removes tagged images', () => {
const root = document.getElementById('fixtures')
root.innerHTML = `
<img id="i1" class="equation_image">
<img id="i2" class="equation_image" mathjaxified>
`
mathImageHelper.removeStrayEquationImages(root)
ok(document.getElementById('i1'))
equal(document.getElementById('i2'), null)
})
QUnit.module('isMathJaxIgnored', {
beforeEach: () => {
window.ENV = {
FEATURES: {
new_math_equation_handling: true,
inline_math_everywhere: true,
},
}
document.getElementById('fixtures').innerHTML = ''
},
afterEach: () => {
document.getElementById('fixtures').innerHTML = ''
},
})
test('ignores elements in the ignore list', () => {
const root = document.getElementById('fixtures')
const elem = document.createElement('span')
elem.setAttribute('id', 'quiz-elapsed-time')
root.appendChild(elem)
ok(mathml.isMathJaxIgnored(elem))
})
test('ignores descendents of .mathjax_ignore', () => {
const root = document.getElementById('fixtures')
const ignored = document.createElement('span')
ignored.setAttribute('class', 'mathjax_ignore')
root.appendChild(ignored)
const elem = document.createElement('span')
elem.textContent = 'ignore me'
ignored.appendChild(elem)
ok(mathml.isMathJaxIgnored(elem))
})
test('deals with disconnected elements', () => {
// even though they should never get here
const elem = document.createElement('span')
ok(mathml.isMathJaxIgnored(elem))
})
test('handles missing element', () => {
ok(mathml.isMathJaxIgnored())
})