diff --git a/.eslintrc.js b/.eslintrc.js index 155dd23..4e15650 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -53,10 +53,16 @@ module.exports = { allowedNames: ['self', '_self'], // Allow `const self = this`; `[]` by default }, ], + 'import/no-unresolved': [ + 'error', + { + ignore: [`^@/.*`], + }, + ], }, overrides: [ { - files: ['*.test.*'], + files: ['*.test.*', `*${puppeteerRollupConfig.js.input}.*`], rules: { 'no-restricted-syntax': 'off', '@typescript-eslint/ban-ts-comment': 'off', @@ -70,7 +76,12 @@ module.exports = { 'no-void': 'off', 'no-empty-function': 'off', 'no-new-func': 'off', - 'import/no-unresolved': ['error', { ignore: [`./${puppeteerRollupConfig.build}/${puppeteerRollupConfig.html.output}$`] }], + 'import/no-unresolved': [ + 'error', + { + ignore: [`\\./${puppeteerRollupConfig.build}/${puppeteerRollupConfig.html.output}$`, `^@/.*`], + }, + ], }, globals: { page: true, diff --git a/config/jest-puppeteer.rollup.config.js b/config/jest-puppeteer.rollup.config.js index fca937a..b036eab 100644 --- a/config/jest-puppeteer.rollup.config.js +++ b/config/jest-puppeteer.rollup.config.js @@ -5,7 +5,7 @@ module.exports = { output: 'build.html', }, js: { - input: 'index', + input: 'index.browser', output: 'build', }, }; diff --git a/config/jest-puppeteer.rollup.js b/config/jest-puppeteer.rollup.js index c5944e3..73cbf83 100644 --- a/config/jest-puppeteer.rollup.js +++ b/config/jest-puppeteer.rollup.js @@ -11,45 +11,6 @@ const rollupConfigName = 'rollup.config.js'; const cacheFilePrefix = 'jest-puppeteer-overlayscrollbars-cache-'; const cacheEncoding = 'utf8'; const cacheHash = 'md5'; -const legacyBabelConfigAssign = { - exclude: [/\/core-js\//], - presets: [ - [ - '@babel/preset-env', - { - useBuiltIns: 'usage', - corejs: { version: 3, proposals: true }, - }, - ], - ], -}; - -const mergeBabelConfigs = (currentConfig, mergeConfig) => { - const { presets: assignPresets, exclude: assignExclude } = mergeConfig; - const { presets: configPresets, exclude: configExclude } = currentConfig; - - assignPresets.forEach((assignPreset) => { - if (Array.isArray(assignPreset)) { - const [assignName, assignConfig] = assignPreset; - - configPresets.forEach((configPreset) => { - if (Array.isArray(configPreset)) { - const [configName, configConfig] = configPreset; - - if (configName === assignName && typeof configConfig === 'object' && typeof assignConfig === 'object') { - Object.assign(configConfig, { - ...assignConfig, - }); - } - } - }); - } - }); - - const finalAssignExclude = Array.isArray(assignExclude) ? assignExclude : [assignExclude]; - const finalConfigExclude = Array.isArray(configExclude) ? configExclude : [configExclude, ...finalAssignExclude]; - currentConfig.exclude = finalConfigExclude.filter((exc) => !!exc); -}; const makeHtmlAttributes = (attributes) => { if (!attributes) { @@ -204,8 +165,7 @@ const setupRollupTest = async (rootDir, testPath, cacheDir) => { let rollupConfigObj = rollupConfig(undefined, { project: rootDir, - overwrite: ({ defaultConfig, legacyBabelConfig }) => { - mergeBabelConfigs(legacyBabelConfig, legacyBabelConfigAssign); + overwrite: ({ defaultConfig }) => { return { input: path.resolve(testDir, deploymentConfig.js.input), dist: path.resolve(testDir, deploymentConfig.build), diff --git a/packages/Select.ts b/packages/Select.ts new file mode 100644 index 0000000..a913b1b --- /dev/null +++ b/packages/Select.ts @@ -0,0 +1,73 @@ +// eslint-disable-next-line +const noop = (): T => { + return {} as T; +}; +const getSelectOptions = (selectElement: HTMLSelectElement) => Array.from(selectElement.options).map((option) => option.value); + +export const generateSelectCallback = (targetElm: HTMLElement | null) => (event: Event) => { + const target = event.target as HTMLSelectElement; + const selectedOption = target.value; + const selectOptions = getSelectOptions(target); + + if (targetElm) { + targetElm.classList.remove(...selectOptions); + targetElm.classList.add(selectedOption); + } +}; + +export const selectOption = (select: HTMLSelectElement | null, selectedOption: string | number): boolean => { + if (!select) { + return false; + } + + const options = getSelectOptions(select); + const currValue = select.value; + + if (selectedOption === currValue) { + return false; + } + + if (typeof selectedOption === 'string' && options.includes(selectedOption)) { + select.value = selectedOption; + } else if (typeof selectedOption === 'number' && options.length < selectedOption && selectedOption > -1) { + select.selectedIndex = selectedOption; + } + + let event; + if (typeof Event === 'function') { + event = new Event('change'); + } else { + event = document.createEvent('Event'); + event.initEvent('change', true, true); + } + select.dispatchEvent(event); + + return true; +}; + +export const iterateSelect = async ( + select: HTMLSelectElement | null, + options?: { + beforeEach?: () => T | Promise; + check?: (input: T) => void | Promise; + afterEach?: () => void | Promise; + } +) => { + if (select) { + const { beforeEach = noop, check = noop, afterEach = noop } = options || {}; + const selectOptions = getSelectOptions(select); + const selectOptionsReversed = getSelectOptions(select).reverse(); + const iterateOptions = [...selectOptions, ...selectOptionsReversed]; + for (let i = 0; i < iterateOptions.length; i++) { + const option = iterateOptions[i]; + // eslint-disable-next-line + const beforeEachObj: T = await beforeEach(); + if (selectOption(select, option)) { + // eslint-disable-next-line + await check(beforeEachObj); + // eslint-disable-next-line + await afterEach(); + } + } + } +}; diff --git a/packages/overlayscrollbars/package-lock.json b/packages/overlayscrollbars/package-lock.json deleted file mode 100644 index 34c6e11..0000000 --- a/packages/overlayscrollbars/package-lock.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "version": "0.0.1", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/jquery": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.0.tgz", - "integrity": "sha512-C7qQUjpMWDUNYQRTXsP5nbYYwCwwgy84yPgoTT7fPN69NH92wLeCtFaMsWeolJD1AF/6uQw3pYt62rzv83sMmw==", - "dev": true, - "requires": { - "@types/sizzle": "*" - } - }, - "@types/sizzle": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz", - "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==", - "dev": true - } - } -} diff --git a/packages/overlayscrollbars/tests/puppeteer/Environment/index.ts b/packages/overlayscrollbars/tests/puppeteer/Environment/index.browser.ts similarity index 100% rename from packages/overlayscrollbars/tests/puppeteer/Environment/index.ts rename to packages/overlayscrollbars/tests/puppeteer/Environment/index.browser.ts diff --git a/packages/overlayscrollbars/tests/puppeteer/Environment/index.test.ts b/packages/overlayscrollbars/tests/puppeteer/Environment/index.test.ts index c156c16..e17754d 100644 --- a/packages/overlayscrollbars/tests/puppeteer/Environment/index.test.ts +++ b/packages/overlayscrollbars/tests/puppeteer/Environment/index.test.ts @@ -7,11 +7,6 @@ describe('Environment', () => { }); it('should be titled "Environment"', async () => { - //await expect(page).toMatchElement('#a'); - //await expect(page).toMatchElement('#b'); - //await expect(page).toMatchElement('#c'); - //await expect(page).toMatchElement('#d'); - const a: Environment = await page.evaluate(() => window.envInstance); console.log(a); await expect(page.title()).resolves.toMatch('Environment'); diff --git a/packages/overlayscrollbars/tests/puppeteer/SizeObserver/index.ts b/packages/overlayscrollbars/tests/puppeteer/SizeObserver/index.browser.ts similarity index 54% rename from packages/overlayscrollbars/tests/puppeteer/SizeObserver/index.ts rename to packages/overlayscrollbars/tests/puppeteer/SizeObserver/index.browser.ts index 91041ad..f5e553f 100644 --- a/packages/overlayscrollbars/tests/puppeteer/SizeObserver/index.ts +++ b/packages/overlayscrollbars/tests/puppeteer/SizeObserver/index.browser.ts @@ -1,9 +1,10 @@ import 'overlayscrollbars.scss'; import './index.scss'; import { createSizeObserver } from 'overlayscrollbars/observers/createSizeObserver'; -import { from, removeClass, addClass, hasDimensions, isString, isNumber, offsetSize } from 'support'; +import { hasDimensions, offsetSize, WH } from 'support'; import { waitFor } from '@testing-library/dom'; import should from 'should'; +import { generateSelectCallback, iterateSelect } from '@/testing-browser/Select'; const targetElm = document.querySelector('#target'); const heightSelect: HTMLSelectElement | null = document.querySelector('#height'); @@ -25,80 +26,35 @@ const observerElm = createSizeObserver(() => { }); }); -const getSelectOptions = (selectElement: HTMLSelectElement) => { - const arr = from(selectElement.options).map((option) => option.value); - return arr; -}; +const selectCallback = generateSelectCallback(targetElm as HTMLElement); -const selectCallback = (event: Event) => { - const target = event.target as HTMLSelectElement; - const selectedOption = target.value; - const selectOptions = getSelectOptions(target); - - removeClass(targetElm, selectOptions.join(' ')); - addClass(targetElm, selectedOption); -}; - -const selectOption = (select: HTMLSelectElement | null, selectedOption: string | number): boolean => { - if (!select) { - return false; - } - - const options = getSelectOptions(select); - const currValue = select.value; - - if (selectedOption === currValue) { - return false; - } - - if (isString(selectedOption) && options.includes(selectedOption)) { - select.value = selectedOption; - } else if (isNumber(selectedOption) && options.length < selectedOption && selectedOption > -1) { - select.selectedIndex = selectedOption; - } - - let event; - if (typeof Event === 'function') { - event = new Event('change'); - } else { - event = document.createEvent('Event'); - event.initEvent('change', true, true); - } - select.dispatchEvent(event); - - return true; -}; - -const iterateSelect = async (select: HTMLSelectElement | null, afterEach?: () => any) => { - if (select) { - const selectOptions = getSelectOptions(select); - const selectOptionsReversed = getSelectOptions(select).reverse(); - const iterateOptions = [...selectOptions, ...selectOptionsReversed]; - for (let i = 0; i < iterateOptions.length; i++) { - const option = iterateOptions[i]; +const iterate = async (select: HTMLSelectElement | null, afterEach?: () => any) => { + await iterateSelect<{ currIterations: number; currOffsetSize: WH }>(select, { + beforeEach() { const currIterations = iterations; const currOffsetSize = offsetSize(targetElm as HTMLElement); - if (selectOption(select, option)) { - const newOffsetSize = offsetSize(targetElm as HTMLElement); - const offsetSizeChanged = currOffsetSize.w !== newOffsetSize.w || currOffsetSize.h !== newOffsetSize.h; - if (hasDimensions(targetElm as HTMLElement) && offsetSizeChanged) { - // eslint-disable-next-line - await waitFor(() => should.equal(iterations, currIterations + 1), { - onTimeout(error): Error { - window.setTestResult(false); - return error; - }, - }); - } + return { + currIterations, + currOffsetSize, + }; + }, + async check({ currIterations, currOffsetSize }) { + const newOffsetSize = offsetSize(targetElm as HTMLElement); + const offsetSizeChanged = currOffsetSize.w !== newOffsetSize.w || currOffsetSize.h !== newOffsetSize.h; - if (typeof afterEach === 'function') { - // eslint-disable-next-line - await afterEach(); - } + if (hasDimensions(targetElm as HTMLElement) && offsetSizeChanged) { + // eslint-disable-next-line + await waitFor(() => should.equal(iterations, currIterations + 1), { + onTimeout(error): Error { + window.setTestResult(false); + return error; + }, + }); } - } - } + }, + afterEach, + }); }; heightSelect?.addEventListener('change', selectCallback); @@ -128,22 +84,22 @@ selectCallback({ target: boxSizingSelect }); selectCallback({ target: displaySelect }); const iteratePadding = async (afterEach?: () => any) => { - await iterateSelect(paddingSelect, afterEach); + await iterate(paddingSelect, afterEach); }; const iterateBorder = async (afterEach?: () => any) => { - await iterateSelect(borderSelect, afterEach); + await iterate(borderSelect, afterEach); }; const iterateHeight = async (afterEach?: () => any) => { - await iterateSelect(heightSelect, afterEach); + await iterate(heightSelect, afterEach); }; const iterateWidth = async (afterEach?: () => any) => { - await iterateSelect(widthSelect, afterEach); + await iterate(widthSelect, afterEach); }; const iterateBoxSizing = async (afterEach?: () => any) => { - await iterateSelect(boxSizingSelect, afterEach); + await iterate(boxSizingSelect, afterEach); }; const iterateDisplay = async (afterEach?: () => any) => { - await iterateSelect(displaySelect, afterEach); + await iterate(displaySelect, afterEach); }; const start = async () => { diff --git a/packages/overlayscrollbars/tsconfig.json b/packages/overlayscrollbars/tsconfig.json index 27c2657..f3a0465 100644 --- a/packages/overlayscrollbars/tsconfig.json +++ b/packages/overlayscrollbars/tsconfig.json @@ -1,6 +1,9 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { - "baseUrl": "./src/" + "baseUrl": "./src/", + "paths": { + "@/testing-browser/*": ["../../testing-browser/src/*"] + } } } diff --git a/packages/testing-browser/package.json b/packages/testing-browser/package.json new file mode 100644 index 0000000..a6b056e --- /dev/null +++ b/packages/testing-browser/package.json @@ -0,0 +1,5 @@ +{ + "private": true, + "name": "testing", + "version": "0.0.0" +} diff --git a/packages/testing-browser/src/Select.ts b/packages/testing-browser/src/Select.ts new file mode 100644 index 0000000..a913b1b --- /dev/null +++ b/packages/testing-browser/src/Select.ts @@ -0,0 +1,73 @@ +// eslint-disable-next-line +const noop = (): T => { + return {} as T; +}; +const getSelectOptions = (selectElement: HTMLSelectElement) => Array.from(selectElement.options).map((option) => option.value); + +export const generateSelectCallback = (targetElm: HTMLElement | null) => (event: Event) => { + const target = event.target as HTMLSelectElement; + const selectedOption = target.value; + const selectOptions = getSelectOptions(target); + + if (targetElm) { + targetElm.classList.remove(...selectOptions); + targetElm.classList.add(selectedOption); + } +}; + +export const selectOption = (select: HTMLSelectElement | null, selectedOption: string | number): boolean => { + if (!select) { + return false; + } + + const options = getSelectOptions(select); + const currValue = select.value; + + if (selectedOption === currValue) { + return false; + } + + if (typeof selectedOption === 'string' && options.includes(selectedOption)) { + select.value = selectedOption; + } else if (typeof selectedOption === 'number' && options.length < selectedOption && selectedOption > -1) { + select.selectedIndex = selectedOption; + } + + let event; + if (typeof Event === 'function') { + event = new Event('change'); + } else { + event = document.createEvent('Event'); + event.initEvent('change', true, true); + } + select.dispatchEvent(event); + + return true; +}; + +export const iterateSelect = async ( + select: HTMLSelectElement | null, + options?: { + beforeEach?: () => T | Promise; + check?: (input: T) => void | Promise; + afterEach?: () => void | Promise; + } +) => { + if (select) { + const { beforeEach = noop, check = noop, afterEach = noop } = options || {}; + const selectOptions = getSelectOptions(select); + const selectOptionsReversed = getSelectOptions(select).reverse(); + const iterateOptions = [...selectOptions, ...selectOptionsReversed]; + for (let i = 0; i < iterateOptions.length; i++) { + const option = iterateOptions[i]; + // eslint-disable-next-line + const beforeEachObj: T = await beforeEach(); + if (selectOption(select, option)) { + // eslint-disable-next-line + await check(beforeEachObj); + // eslint-disable-next-line + await afterEach(); + } + } + } +}; diff --git a/packages/testing-browser/tsconfig.json b/packages/testing-browser/tsconfig.json new file mode 100644 index 0000000..27c2657 --- /dev/null +++ b/packages/testing-browser/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": "./src/" + } +} diff --git a/rollup.config.base.js b/rollup.config.base.js index cac0aef..e722b1f 100644 --- a/rollup.config.base.js +++ b/rollup.config.base.js @@ -10,6 +10,8 @@ const fs = require('fs'); const path = require('path'); const resolve = require('./resolve.config.json'); +const isTestEnv = process.env.NODE_ENV === 'test'; + const rollupConfigDefaults = { input: './src/index', src: './src', @@ -25,10 +27,12 @@ const rollupConfigDefaults = { }; const legacyBabelConfig = { + exclude: isTestEnv ? [/\/core-js\//] : [], presets: [ [ '@babel/preset-env', { + ...(isTestEnv ? { useBuiltIns: 'usage', corejs: { version: 3, proposals: true } } : {}), loose: true, targets: { ie: '11', @@ -53,6 +57,8 @@ const esmBabelConfig = { ], }; +const normalizePath = (pathName) => (pathName ? pathName.split(path.sep).join(path.posix.sep) : pathName); + const appendExtension = (file) => { if (path.extname(file) === '') { return file + resolve.extensions.find((ext) => fs.existsSync(path.resolve(`${file}${ext}`))); @@ -81,6 +87,7 @@ const resolveConfig = (config, userConfig) => { const rollupConfig = (config = {}, { project = process.cwd(), overwrite = {}, silent, fast } = {}) => { const projectPath = resolvePath(__dirname, project); + const relativeBackPath = path.relative(projectPath, __dirname); const projectName = path.basename(project); const packageJSONPath = resolvePath(projectPath, 'package.json'); @@ -122,6 +129,7 @@ const rollupConfig = (config = {}, { project = process.cwd(), overwrite = {}, si const testsPath = resolvePath(projectPath, tests); const inputPath = resolvePath(projectPath, input, true); + const prependBackPath = (value) => normalizePath(`${relativeBackPath}${path.sep}`) + value; const genOutputConfig = (esm) => ({ format: esm ? 'esm' : 'umd', file: path.resolve(distPath, `${file}${esm ? '.esm' : ''}.js`), @@ -167,6 +175,8 @@ const rollupConfig = (config = {}, { project = process.cwd(), overwrite = {}, si }, exclude: (require(tsconfigJSONPath).exclude || []).concat(testsPath), }, + include: ['*.ts+(|x)', '**/*.ts+(|x)'].map(prependBackPath), + exclude: ['*.d.ts', '**/*.d.ts'].map(prependBackPath), }) : {}, inject: rollupInject({ diff --git a/yarn.lock b/yarn.lock index 9662b2b..454c56f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1312,6 +1312,14 @@ estree-walker "^1.0.1" picomatch "^2.2.2" +"@rollup/pluginutils@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.1.0.tgz#0dcc61c780e39257554feb7f77207dceca13c838" + integrity sha512-TrBhfJkFxA+ER+ew2U2/fHbebhLT/l/2pRk0hfj9KusXUuRXd2v0R58AfaZK9VXDQ4TogOSEmICVrQAA3zFnHQ== + dependencies: + estree-walker "^2.0.1" + picomatch "^2.2.2" + "@sinonjs/commons@^1.7.0": version "1.8.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" @@ -3492,6 +3500,11 @@ estree-walker@^1.0.1: resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== +estree-walker@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.1.tgz#f8e030fb21cefa183b44b7ad516b747434e7a3e0" + integrity sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"