refactor: refactor ResizeObserver code, fix code coverage for RO (#101)

* fix: detect ResizeObserver on-demand, fix code coverage for RO

* fix: fix test

* test: test ro

* fix: avoid recalc
This commit is contained in:
Nolan Lawson 2020-12-27 09:54:37 -08:00 committed by GitHub
parent e0c7245d5c
commit b86b8c6b2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 102 additions and 15 deletions

View File

@ -2,6 +2,7 @@ import '@testing-library/jest-dom/extend-expect'
import FDBFactory from 'fake-indexeddb/build/FDBFactory'
import FDBKeyRange from 'fake-indexeddb/build/FDBKeyRange'
import { Crypto } from '@peculiar/webcrypto'
import { ResizeObserver } from 'd2l-resize-aware/resize-observer-module.js'
jest.mock('node-fetch', () => require('fetch-mock-jest').sandbox())
jest.setTimeout(60000)
@ -9,6 +10,7 @@ jest.setTimeout(60000)
global.fetch = require('node-fetch')
global.Response = fetch.Response
global.crypto = new Crypto()
global.ResizeObserver = ResizeObserver
process.env.NODE_ENV = 'test'

View File

@ -15,7 +15,7 @@ module.exports = {
},
moduleFileExtensions: ['js', 'svelte'],
testPathIgnorePatterns: ['node_modules'],
transformIgnorePatterns: ['<rootDir>/node_modules/(?!lodash-es|if-emoji)'],
transformIgnorePatterns: ['<rootDir>/node_modules/(?!lodash-es|if-emoji|d2l-resize-aware)'],
bail: true,
verbose: true,
silent: false,

View File

@ -81,6 +81,7 @@
"compression": "^1.7.4",
"conventional-changelog-cli": "^2.1.1",
"cssnano": "^4.1.10",
"d2l-resize-aware": "BrightspaceUI/resize-aware#semver:^1.2.2",
"emoji-picker-element-data": "^1.0.0",
"emojibase-data": "^5.1.1",
"express": "^4.17.1",

View File

@ -20,7 +20,7 @@ import {
} from '../../constants'
import { uniqBy } from '../../../shared/uniqBy'
import { summarizeEmojisForUI } from '../../utils/summarizeEmojisForUI'
import { calculateWidth, resizeObserverSupported } from '../../utils/calculateWidth'
import * as widthCalculator from '../../utils/widthCalculator'
import { checkZwjSupport } from '../../utils/checkZwjSupport'
import { requestPostAnimationFrame } from '../../utils/requestPostAnimationFrame'
import { stop } from '../../../shared/marks'
@ -253,7 +253,7 @@ $: {
// eslint-disable-next-line no-unused-vars
function calculateEmojiGridWidth (node) {
return calculateWidth(node, width => {
return widthCalculator.calculateWidth(node, width => {
/* istanbul ignore next */
const newNumColumns = process.env.NODE_ENV === 'test'
? DEFAULT_NUM_COLUMNS
@ -280,7 +280,7 @@ $: currentGroup = groups[currentGroupIndex]
// eslint-disable-next-line no-unused-vars
function calculateIndicatorWidth (node) {
return calculateWidth(node, width => {
return widthCalculator.calculateWidth(node, width => {
computedIndicatorWidth = width
})
}
@ -290,14 +290,12 @@ function calculateIndicatorWidth (node) {
// So we calculate of the indicator and use exact pixel values in the animation instead
// (where ResizeObserver is supported).
$: {
/* istanbul ignore if */
if (resizeObserverSupported) {
// eslint-disable-next-line no-unused-vars
indicatorStyle = `transform: translateX(${currentGroupIndex * computedIndicatorWidth}px);` // exact pixels
} else {
// eslint-disable-next-line no-unused-vars
indicatorStyle = `transform: translateX(${currentGroupIndex * 100}%);`// fallback to percent-based
}
// eslint-disable-next-line no-unused-vars
indicatorStyle = `transform: translateX(${
widthCalculator.resizeObserverSupported
? `${currentGroupIndex * computedIndicatorWidth}px` // exact pixels
: `${currentGroupIndex * 100}%` // fallback to percent-based
})`
}
//

View File

@ -4,11 +4,15 @@
import { requestAnimationFrame } from './requestAnimationFrame'
export const resizeObserverSupported = typeof ResizeObserver === 'function'
export let resizeObserverSupported = typeof ResizeObserver === 'function'
// only used in jest tests
export const resetResizeObserverSupported = () => {
resizeObserverSupported = typeof ResizeObserver === 'function'
}
export function calculateWidth (node, onUpdate) {
let resizeObserver
/* istanbul ignore if */
if (resizeObserverSupported) {
resizeObserver = new ResizeObserver(entries => (
onUpdate(entries[0].contentRect.width)
@ -22,7 +26,6 @@ export function calculateWidth (node, onUpdate) {
return {
destroy () {
/* istanbul ignore if */
if (resizeObserver) {
resizeObserver.disconnect()
}

View File

@ -0,0 +1,65 @@
import { groups } from '../../../src/picker/groups'
import * as testingLibrary from '@testing-library/dom'
import {
waitFor, getAllByRole,
getByRole, fireEvent
} from '@testing-library/dom'
import { ALL_EMOJI, basicAfterEach, basicBeforeEach, tick, truncatedEmoji } from '../shared'
import Picker from '../../../src/picker/PickerElement'
import Database from '../../../src/database/Database'
import { resetResizeObserverSupported } from '../../../src/picker/utils/widthCalculator'
// TODO: we can remove these tests when/if we stop supporting browsers without ResizeObserver
// https://caniuse.com/resizeobserver
describe('ResizeObserver unsupported', () => {
let picker
let container
let oldResizeObserver
beforeEach(async () => {
basicBeforeEach()
oldResizeObserver = global.ResizeObserver
delete global.ResizeObserver
resetResizeObserverSupported()
picker = new Picker({ dataSource: ALL_EMOJI })
document.body.appendChild(picker)
container = picker.shadowRoot.querySelector('.picker')
await tick(40)
})
afterEach(async () => {
await tick(40)
document.body.removeChild(picker)
await tick(40)
await new Database({ dataSource: ALL_EMOJI }).delete()
await tick(40)
basicAfterEach()
global.ResizeObserver = oldResizeObserver
resetResizeObserverSupported()
})
test('basic picker test', async () => {
const numInGroup1 = truncatedEmoji.filter(_ => _.group === 0).length
const numInGroup2 = truncatedEmoji.filter(_ => _.group === 1).length
await waitFor(() => expect(getByRole(container, 'button', { name: 'Choose a skin tone (currently Default)' })).toBeVisible())
expect(getAllByRole(container, 'tab')).toHaveLength(groups.length)
expect(getByRole(container, 'tab', { name: 'Smileys and emoticons', selected: true })).toBeVisible()
await waitFor(() => expect(
testingLibrary.getAllByRole(getByRole(container, 'tabpanel'), 'menuitem')).toHaveLength(numInGroup1)
)
expect(getByRole(container, 'tab', { name: 'People and body' })).toBeVisible()
fireEvent.click(getByRole(container, 'tab', { name: 'People and body' }))
await waitFor(() => expect(
testingLibrary.getAllByRole(getByRole(container, 'tabpanel'), 'menuitem')).toHaveLength(numInGroup2))
expect(getByRole(container, 'tab', { name: 'People and body', selected: true })).toBeVisible()
})
})

View File

@ -1500,6 +1500,13 @@
tslib "^2.0.3"
webcrypto-core "^1.1.8"
"@polymer/polymer@^3.0.0":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-3.4.1.tgz#333bef25711f8411bb5624fb3eba8212ef8bee96"
integrity sha512-KPWnhDZibtqKrUz7enIPOiO4ZQoJNOuLwqrhV2MXzIt3VVnUVJVG5ORz4Z2sgO+UZ+/UZnPD0jqY+jmw/+a9mQ==
dependencies:
"@webcomponents/shadycss" "^1.9.1"
"@rollup/plugin-commonjs@^16.0.0":
version "16.0.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz#169004d56cd0f0a1d0f35915d31a036b0efe281f"
@ -1842,6 +1849,11 @@
dependencies:
"@types/node" "*"
"@webcomponents/shadycss@^1.9.1":
version "1.10.2"
resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.10.2.tgz#40e03cab6dc5e12f199949ba2b79e02f183d1e7b"
integrity sha512-9Iseu8bRtecb0klvv+WXZOVZatsRkbaH7M97Z+f+Pt909R4lDfgUODAnra23DOZTpeMTAkVpf4m/FZztN7Ox1A==
JSONStream@^1.0.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
@ -3419,6 +3431,12 @@ currently-unhandled@^0.4.1:
dependencies:
array-find-index "^1.0.1"
"d2l-resize-aware@BrightspaceUI/resize-aware#semver:^1.2.2":
version "1.2.2"
resolved "https://codeload.github.com/BrightspaceUI/resize-aware/tar.gz/96ba3ac560380abfb753f128ac9a5c0992d7d723"
dependencies:
"@polymer/polymer" "^3.0.0"
dargs@^4.0.1:
version "4.1.0"
resolved "https://registry.yarnpkg.com/dargs/-/dargs-4.1.0.tgz#03a9dbb4b5c2f139bf14ae53f0b8a2a6a86f4e17"