upgrade jest to v28

refs DE-1284

Change-Id: I6f91f5d986d51d73a809cba9fd93355a6f8de7a4
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/296476
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Andrea Cirulli <andrea.cirulli@instructure.com>
QA-Review: Aaron Ogata <aogata@instructure.com>
Product-Review: Aaron Ogata <aogata@instructure.com>
This commit is contained in:
Aaron Ogata 2022-07-18 15:07:53 -07:00
parent 4bdbe477cf
commit 6afa51a0ef
19 changed files with 724 additions and 495 deletions

View File

@ -23,6 +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'),
'^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',
@ -33,7 +34,9 @@ module.exports = {
'<rootDir>/packages/canvas-rce/lib/rce/plugins/shared/Upload/CategoryProcessor',
// mock the tinymce-react Editor react component
'@tinymce/tinymce-react': '<rootDir>/packages/canvas-rce/src/rce/__mocks__/tinymceReact.js',
'decimal.js/decimal.mjs': 'decimal.js/decimal.js'
'decimal.js/decimal.mjs': 'decimal.js/decimal.js',
// https://github.com/ai/nanoid/issues/363
"^nanoid(/(.*)|$)": "nanoid$1",
},
roots: ['<rootDir>/ui', 'gems/plugins', 'public/javascripts'],
moduleDirectories: ['ui/shims', 'public/javascripts', 'node_modules'],
@ -78,7 +81,7 @@ module.exports = {
transform: {
'\\.coffee$': '<rootDir>/jest/coffeeTransformer.js',
'\\.handlebars$': '<rootDir>/jest/handlebarsTransformer.js',
'\\.graphql$': 'jest-raw-loader',
'\\.graphql$': '<rootDir>/jest/rawLoader.js',
'\\.[jt]sx?$': [
'babel-jest',
{

View File

@ -21,9 +21,9 @@ const {transform} = require('@babel/core')
exports.process = (coffee, path) => {
const esm = compile(coffee, {bare: true})
const cjs = transform(esm, {
return transform(esm, {
filename: path,
plugins: ['@babel/plugin-transform-modules-commonjs']
}).code
return cjs
})
}

View File

@ -24,9 +24,9 @@ exports.process = (source, path) => {
// brandable_css assets are not available in test
injectBrandableStylesheet: false
})
const cjs = transform(amd, {
return transform(amd, {
filename: path,
plugins: ['@babel/plugin-transform-modules-commonjs']
}).code
return cjs
})
}

25
jest/rawLoader.js Normal file
View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2022 - 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/>.
*/
module.exports = {
process: (data) => {
return {
code: `module.exports = ${JSON.stringify(data)}`
}
}
}

View File

@ -231,7 +231,7 @@
"array-flat-polyfill": "^1.0.1",
"axe-core": "~2.1.7",
"babel-eslint": "^10",
"babel-jest": "^26",
"babel-jest": "^28",
"babel-loader": "^8",
"babel-plugin-transform-react-remove-prop-types": "^0.4",
"babel-plugin-typescript-to-proptypes": "^1.4.2",
@ -282,15 +282,15 @@
"imports-loader": "^0.8",
"istanbul-instrumenter-loader": "^3",
"istanbul-merge": "^1.1.1",
"jest": "^27",
"jest": "^28",
"jest-canvas-mock": "^2",
"jest-config": "^27",
"jest-config": "^28",
"jest-environment-jsdom": "^28",
"jest-fetch-mock": "^3.0.3",
"jest-html-reporter": "^3",
"jest-junit": "^7",
"jest-localstorage-mock": "^2",
"jest-moxios-utils": "^1",
"jest-raw-loader": "^1",
"jsdom-global": "^3.0.2",
"json-loader": "^0.5.7",
"karma": "^3",

View File

@ -119,7 +119,7 @@
"esm": "^3.2.25",
"format-message-cli": "^6",
"identity-obj-proxy": "^3.0.0",
"jest": "^27",
"jest": "^28",
"jest-canvas-mock": "^2",
"jest-junit": "^7",
"jest-moxios-utils": "^1",

View File

@ -13,6 +13,6 @@
"author": "Ahmad Amireh <ahmad@instructure.com>",
"license": "MIT",
"devDependencies": {
"jest": "^27"
"jest": "^28"
}
}

View File

@ -20,6 +20,6 @@
"timezone": "https://registry.npmjs.org/@brentburgoyne/timezone/-/timezone-1.0.24.tgz"
},
"devDependencies": {
"jest": "^27"
"jest": "^28"
}
}

View File

@ -12,6 +12,6 @@
},
"devDependencies": {
"axios": "^0.21.1",
"jest": "^27"
"jest": "^28"
}
}

View File

@ -25,9 +25,7 @@
"license": "MIT",
"devDependencies": {
"@babel/preset-typescript": "^7.15.0",
"@jest/globals": "^27.1.0",
"babel-jest": "^27.1.0",
"jest": "^27",
"jest": "^28",
"jest-localstorage-mock": "^2.4.17"
}
}

View File

@ -14,7 +14,7 @@
"lint": "prettier bin/**/*.js lib/**/*.json --write"
},
"devDependencies": {
"jest": "^27",
"jest": "^28",
"prettier": "^2"
}
}

View File

@ -39,7 +39,7 @@ describe('WebcamCapture', () => {
})
afterEach(async () => {
await act(async() => { jest.runOnlyPendingTimers() })
await act(async() => { jest.runAllTimers() })
delete navigator.mediaDevices
})

View File

@ -26,7 +26,7 @@ import {render, waitFor} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import '@testing-library/jest-dom/extend-expect'
jest.setTimeout(20000)
jest.setTimeout(25000)
const originalState = store.getState()

View File

@ -40,7 +40,7 @@ import * as useGroupDetail from '@canvas/outcomes/react/hooks/useGroupDetail'
jest.setTimeout(15000)
jest.mock('@canvas/rce/RichContentEditor')
jest.useFakeTimers('legacy')
jest.useFakeTimers({ legacyFakeTimers: true })
describe('OutcomeManagementPanel', () => {
let cache

View File

@ -38,7 +38,7 @@ import {clickEl} from '@canvas/outcomes/react/helpers/testHelpers'
import resolveProgress from '@canvas/progress/resolve_progress'
jest.mock('@canvas/progress/resolve_progress')
jest.useFakeTimers('legacy')
jest.useFakeTimers({ legacyFakeTimers: true })
const delayImportOutcomesProgress = () => {
let realResolve

View File

@ -24,6 +24,12 @@ import DirectShareUserModal from '../DirectShareUserModal'
jest.mock('../../effects/useContentShareUserSearchApi')
const flushAllTimersAndPromises = async () => {
while(jest.getTimerCount() > 0) {
await act(async () => { jest.runAllTimers() })
}
}
describe('DirectShareUserModal', () => {
let ariaLive
@ -51,13 +57,14 @@ describe('DirectShareUserModal', () => {
})
})
afterEach(() => {
afterEach(async () => {
await flushAllTimersAndPromises()
fetchMock.restore()
})
function selectUser(getByText, getByLabelText, name = 'abc') {
fireEvent.change(getByLabelText(/send to:/i), {target: {value: name}})
act(() => jest.runAllTimers()) // let the debounce happen
async function selectUser(getByText, findByLabelText, name = 'abc') {
fireEvent.change(await findByLabelText(/send to:/i), {target: {value: name}})
await act(async () => jest.runAllTimers()) // let the debounce happen
fireEvent.click(getByText(name))
}
@ -66,30 +73,30 @@ describe('DirectShareUserModal', () => {
expect(getByText('Send').closest('button').getAttribute('disabled')).toBe('')
})
it('enables the send button only when a user is selected', () => {
const {getByText, getAllByText, getByLabelText} = render(
it('enables the send button only when a user is selected UNDER TEST', async () => {
const {getByText, getAllByText, findByLabelText} = render(
<DirectShareUserModal open courseId="1" />
)
selectUser(getByText, getByLabelText)
await selectUser(getByText, findByLabelText)
expect(getByText('Send').closest('button').getAttribute('disabled')).toBe(null)
// remove the selected user from the list
fireEvent.click(getAllByText('abc')[1]) // first one is SR alert
expect(getByText('Send').closest('button').getAttribute('disabled')).toBe('')
})
it('disables the send button when a search has started', () => {
const {getByText, getByLabelText} = render(
it('disables the send button when a search has started UNDER TEST', async () => {
const {getByText, findByLabelText} = render(
<DirectShareUserModal open courseId="1" onDismiss={Function.prototype} />
)
selectUser(getByText, getByLabelText)
await selectUser(getByText, findByLabelText)
fireEvent.click(getByText('Send'))
expect(getByText('Send').closest('button').getAttribute('disabled')).toBe('')
})
it('starts a share operation and reports status', async () => {
it('starts a share operation and reports status UNDER TEST', async () => {
fetchMock.postOnce('path:/api/v1/users/self/content_shares', 200)
const onDismiss = jest.fn()
const {getByText, getAllByText, getByLabelText} = render(
const {getByText, getAllByText, findByLabelText} = render(
<DirectShareUserModal
open
courseId="1"
@ -97,7 +104,7 @@ describe('DirectShareUserModal', () => {
onDismiss={onDismiss}
/>
)
selectUser(getByText, getByLabelText)
await selectUser(getByText, findByLabelText)
fireEvent.click(getByText('Send'))
const [, fetchOptions] = fetchMock.lastCall()
expect(fetchOptions.method).toBe('POST')
@ -114,10 +121,10 @@ describe('DirectShareUserModal', () => {
it('clears user selection when the modal is closed', async () => {
fetchMock.get('*', [{id: 'abc', name: 'abc'}])
const {queryByText, getByText, getByLabelText, rerender} = render(
const {queryByText, getByText, findByLabelText, rerender} = render(
<DirectShareUserModal open courseId="1" />
)
selectUser(getByText, getByLabelText)
await selectUser(getByText, findByLabelText)
rerender(<DirectShareUserModal open={false} courseId="1" />)
rerender(<DirectShareUserModal open courseId="1" />)
expect(queryByText('abc')).toBeNull()
@ -134,14 +141,14 @@ describe('DirectShareUserModal', () => {
it('reports an error if the fetch fails', async () => {
fetchMock.postOnce('path:/api/v1/users/self/content_shares', 400)
const {getByText, getByLabelText} = render(
const {getByText, findByLabelText} = render(
<DirectShareUserModal
open
courseId="1"
contentShare={{content_type: 'discussion_topic', content_id: '42'}}
/>
)
selectUser(getByText, getByLabelText)
await selectUser(getByText, findByLabelText)
fireEvent.click(getByText('Send'))
await act(() => fetchMock.flush(true))
expect(getByText(/error/i)).toBeInTheDocument()

View File

@ -29,7 +29,7 @@ import * as apiClient from '../apiClient'
jest.mock('@canvas/alerts/react/FlashAlert')
jest.mock('../apiClient')
jest.useFakeTimers('legacy')
jest.useFakeTimers({ legacyFakeTimers: true })
const file = sinon.createStubInstance(File)
const defaultProps = (props = {}) =>

View File

@ -28,6 +28,12 @@ import {FIND_GROUP_OUTCOMES} from '@canvas/outcomes/graphql/Management'
jest.mock('@canvas/alerts/react/FlashAlert')
const flushAllTimersAndPromises = async () => {
while(jest.getTimerCount() > 0) {
await act(async () => { jest.runAllTimers() })
}
}
const outcomeTitles = result => result.current.group.outcomes.edges.map(edge => edge.node.title)
const outcomeFriendlyDescriptions = result =>
result.current.group.outcomes.edges.map(edge => edge.node.friendlyDescription?.description || '')
@ -176,7 +182,7 @@ describe('groupDetailHook', () => {
expect(outcomeTitles(result)).toEqual(['Outcome 1 - Group 1', 'Outcome 2 - Group 1'])
expect(outcomeFriendlyDescriptions(result)).toEqual(['', ''])
act(() => rerender('200'))
await act(async () => jest.runAllTimers())
await flushAllTimersAndPromises()
expect(result.current.group.title).toBe('Refetched Group 200')
expect(outcomeTitles(result)).toEqual([
'Refetched Outcome 1 - Group 200',

1094
yarn.lock

File diff suppressed because it is too large Load Diff