diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index bf7c8f1c..e3212a40 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,16 +15,19 @@ merge of your pull request! --> **What**: + **Why**: + **How**: - + **Checklist**: + diff --git a/jest.config.js b/jest.config.js index 077f1872..3594a492 100644 --- a/jest.config.js +++ b/jest.config.js @@ -10,9 +10,7 @@ config.moduleNameMapper = { config.testEnvironment = 'jsdom' -config.setupFilesAfterEnv = [ - '/testenv/jest.js', -] +config.setupFilesAfterEnv = ['/testenv/jest.js'] config.testMatch.push('/tests/**/*.+(js|jsx|ts|tsx)') diff --git a/scripts/package.json b/scripts/package.json index 6990891f..3dbc1ca5 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -1 +1,3 @@ -{"type": "module"} +{ + "type": "module" +} diff --git a/scripts/setup.js b/scripts/setup.js index 39148d26..ca1dec7a 100644 --- a/scripts/setup.js +++ b/scripts/setup.js @@ -1,7 +1,7 @@ import fs from 'fs/promises' import path from 'path' -import { createBundleBuilder } from '@ph.fritsche/toolbox/dist/builder/index.js' -import { spawn } from 'child_process' +import {createBundleBuilder} from '@ph.fritsche/toolbox/dist/builder/index.js' +import {spawn} from 'child_process' const dirname = path.dirname(new URL(import.meta.url).pathname) const indexDirLib = path.join(dirname, '../testenv/libs') @@ -13,124 +13,140 @@ const cmd = process.argv[2] const names = process.argv.length > 3 ? process.argv.slice(3) : undefined if (cmd === 'install-lib') { - await Promise.all( - (await getLibDirs(names)) - .map(([name, dir]) => installLib(name, dir)) - ) + await Promise.all( + (await getLibDirs(names)).map(([name, dir]) => installLib(name, dir)), + ) } else if (cmd === 'bundle-lib') { - await Promise.all( - (await getLibDirs(names)) - .map(([name, dir]) => buildLib(name, dir)) - ) + await Promise.all( + (await getLibDirs(names)).map(([name, dir]) => buildLib(name, dir)), + ) } else if (cmd === 'bundle-env') { - await Promise.all( - (await getEnvFiles(names)) - .map(([name, file]) => buildEnv(name, file)) - ) + await Promise.all( + (await getEnvFiles(names)).map(([name, file]) => buildEnv(name, file)), + ) } else if (!cmd) { - await Promise.all([ - ...(await getLibDirs()).map(([name, dir]) => installLib(name, dir).then(() => buildLib(name, dir))), - ...(await getEnvFiles()).map(([name, file]) => buildEnv(name, file)), - ]) + await Promise.all([ + ...( + await getLibDirs() + ).map(([name, dir]) => + installLib(name, dir).then(() => buildLib(name, dir)), + ), + ...(await getEnvFiles()).map(([name, file]) => buildEnv(name, file)), + ]) } async function getLibDirs(names) { - names ??= (await fs.readdir(indexDirLib)).filter(n => !n.startsWith('.')) - - return await Promise.all(names.map(name => { - const dir = `${indexDirLib}/${name}` - - return fs.stat(`${dir}/index.js`).then( - () => [name, dir], - () => {throw new Error(`${dir}/index.js could not be found.`)} - ) - })) + names ??= (await fs.readdir(indexDirLib)).filter(n => !n.startsWith('.')) + + return await Promise.all( + names.map(name => { + const dir = `${indexDirLib}/${name}` + + return fs.stat(`${dir}/index.js`).then( + () => [name, dir], + () => { + throw new Error(`${dir}/index.js could not be found.`) + }, + ) + }), + ) } async function getEnvFiles(names) { - names ??= (await fs.readdir(indexDirEnv)) - .filter(n => /^\w+\.js$/.test(n)) - .filter(n => !ignoreEnv.includes(n)) - .map(f => f.slice(0, f.length - 3)) - - return await Promise.all(names.map(async name => { - const file = `${indexDirEnv}/${name}.js` - - return fs.stat(file).then( - () => [name, file], - () => { throw new Error(`${file} could not be found.`)} - ) - })) + names ??= (await fs.readdir(indexDirEnv)) + .filter(n => /^\w+\.js$/.test(n)) + .filter(n => !ignoreEnv.includes(n)) + .map(f => f.slice(0, f.length - 3)) + + return await Promise.all( + names.map(async name => { + const file = `${indexDirEnv}/${name}.js` + + return fs.stat(file).then( + () => [name, file], + () => { + throw new Error(`${file} could not be found.`) + }, + ) + }), + ) } async function installLib(name, dir) { - return new Promise((res, rej) => { - const child = spawn('npm', ['i'], {cwd: dir}) + return new Promise((res, rej) => { + const child = spawn('npm', ['i'], {cwd: dir}) - process.stdout.write(`Installing library "${name}" at ${dir}\n`) + process.stdout.write(`Installing library "${name}" at ${dir}\n`) - child.on('error', e => { - process.stdout.write(`${e.stack ?? String(e)}\n`) - }) - child.on('exit', (code, signal) => { - (code || signal ? rej(code) : res()) - }) + child.on('error', e => { + process.stdout.write(`${e.stack ?? String(e)}\n`) + }) + child.on('exit', (code, signal) => { + code || signal ? rej(code) : res() }) + }) } async function buildLib(name, dir) { - const { globals } = JSON.parse(await fs.readFile(`${dir}/package.json`)) - - process.stdout.write(`Bundling library "${name}" at ${dir}/index.js\n`) - - const builder = createBundleBuilder({ - basePath: `${dir}/`, - globals, - }) - builder.inputFiles.set(`${dir}/index.js`, undefined) - - builder.emitter.addListener('complete', e => { - const content = String(e.outputFiles.get('index.js')?.content) - fs.writeFile(`${dir}/index.bundle.js`, content) - .then(() => process.stdout.write([ - '<<<', - `Wrote ${dir}/index.bundle.js`, - `[${content.length} bytes]`, - ...((globals && Object.keys(globals).length) - ? [ - ` Depending on:`, - ...Object.entries(globals).map(([module, name]) => ` ${name} => ${module}`), - ] - : []), - '>>>', - '', - ].join('\n'))) - }) + const {globals} = JSON.parse(await fs.readFile(`${dir}/package.json`)) + + process.stdout.write(`Bundling library "${name}" at ${dir}/index.js\n`) + + const builder = createBundleBuilder({ + basePath: `${dir}/`, + globals, + }) + builder.inputFiles.set(`${dir}/index.js`, undefined) + + builder.emitter.addListener('complete', e => { + const content = String(e.outputFiles.get('index.js')?.content) + fs.writeFile(`${dir}/index.bundle.js`, content).then(() => + process.stdout.write( + [ + '<<<', + `Wrote ${dir}/index.bundle.js`, + `[${content.length} bytes]`, + ...(globals && Object.keys(globals).length + ? [ + ` Depending on:`, + ...Object.entries(globals).map( + ([module, name]) => ` ${name} => ${module}`, + ), + ] + : []), + '>>>', + '', + ].join('\n'), + ), + ) + }) - builder.build() + builder.build() } async function buildEnv(name, file) { - process.stdout.write(`Bundling environment "${name}" at ${file}\n`) - - const builder = createBundleBuilder({ - basePath: `${indexDirEnv}/`, - }) - const basename = path.basename(file, '.js') - builder.inputFiles.set(file, undefined) - - builder.emitter.addListener('complete', e => { - const content = String(e.outputFiles.get(`${basename}.js`)?.content) - fs.writeFile(`${indexDirEnv}/${basename}.bundle.js`, content) - .then(() => process.stdout.write([ - '<<<', - `Wrote ${indexDirEnv}/${basename}.bundle.js`, - `[${content.length} bytes]`, - '>>>', - '', - ].join('\n'))) - }) + process.stdout.write(`Bundling environment "${name}" at ${file}\n`) + + const builder = createBundleBuilder({ + basePath: `${indexDirEnv}/`, + }) + const basename = path.basename(file, '.js') + builder.inputFiles.set(file, undefined) + + builder.emitter.addListener('complete', e => { + const content = String(e.outputFiles.get(`${basename}.js`)?.content) + fs.writeFile(`${indexDirEnv}/${basename}.bundle.js`, content).then(() => + process.stdout.write( + [ + '<<<', + `Wrote ${indexDirEnv}/${basename}.bundle.js`, + `[${content.length} bytes]`, + '>>>', + '', + ].join('\n'), + ), + ) + }) - builder.build() + builder.build() } - diff --git a/scripts/test.js b/scripts/test.js index 7052ffd6..7ddc3569 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -1,9 +1,13 @@ -import { createProjectBuildProvider, serveDir, serveToolboxRunner } from '@ph.fritsche/toolbox' -import { NodeTestConductor } from '@ph.fritsche/toolbox/dist/conductor/NodeTestConductor.js' -import { ChromeTestConductor } from '@ph.fritsche/toolbox/dist/conductor/ChromeTestConductor.js' -import { ConsoleReporter } from '@ph.fritsche/toolbox/dist/reporter/ConsoleReporter.js' -import { ReporterServer } from '@ph.fritsche/toolbox/dist/reporter/ReporterServer.js' -import { TestRunStack } from '@ph.fritsche/toolbox/dist/reporter/TestRunStack.js' +import { + createProjectBuildProvider, + serveDir, + serveToolboxRunner, +} from '@ph.fritsche/toolbox' +import {NodeTestConductor} from '@ph.fritsche/toolbox/dist/conductor/NodeTestConductor.js' +import {ChromeTestConductor} from '@ph.fritsche/toolbox/dist/conductor/ChromeTestConductor.js' +import {ConsoleReporter} from '@ph.fritsche/toolbox/dist/reporter/ConsoleReporter.js' +import {ReporterServer} from '@ph.fritsche/toolbox/dist/reporter/ReporterServer.js' +import {TestRunStack} from '@ph.fritsche/toolbox/dist/reporter/TestRunStack.js' import IstanbulLibCoverage from 'istanbul-lib-coverage' import IstanbulLibReport from 'istanbul-lib-report' @@ -15,30 +19,48 @@ const tsConfigFile = './tests/tsconfig.json' const toolbox = await serveToolboxRunner() const env = await serveDir('testenv') -const { buildProvider, fileProvider, fileServer, onBuildDone } = createProjectBuildProvider([ - 'src', - 'tests', -], { +const {buildProvider, fileProvider, fileServer, onBuildDone} = + createProjectBuildProvider(['src', 'tests'], { tsConfigFile, globals: { - '@testing-library/dom': 'DomTestingLibrary', - '@testing-library/react': 'ReactTestingLibrary', - 'react': 'React', - 'react-dom': 'ReactDom', - } -}) - -for (const { builder } of buildProvider.builders) { - builder.emitter.addListener('start', ({ type, buildId, inputFiles }) => console.log(builder.id, { type, buildId, inputFiles: inputFiles.size })) - builder.emitter.addListener('complete', ({ type, buildId, inputFiles, outputFiles }) => console.log(builder.id, { type, buildId, inputFiles: inputFiles.size, outputFiles: outputFiles.size })) - builder.emitter.addListener('error', ({ type, buildId, error }) => console.log(builder.id, { type, buildId, error })) - builder.emitter.addListener('done', ({ type, buildId }) => console.log(builder.id, { type, buildId })) + '@testing-library/dom': 'DomTestingLibrary', + '@testing-library/react': 'ReactTestingLibrary', + react: 'React', + 'react-dom': 'ReactDom', + }, + }) + +for (const {builder} of buildProvider.builders) { + builder.emitter.addListener('start', ({type, buildId, inputFiles}) => + console.log(builder.id, {type, buildId, inputFiles: inputFiles.size}), + ) + builder.emitter.addListener( + 'complete', + ({type, buildId, inputFiles, outputFiles}) => + console.log(builder.id, { + type, + buildId, + inputFiles: inputFiles.size, + outputFiles: outputFiles.size, + }), + ) + builder.emitter.addListener('error', ({type, buildId, error}) => + console.log(builder.id, {type, buildId, error}), + ) + builder.emitter.addListener('done', ({type, buildId}) => + console.log(builder.id, {type, buildId}), + ) } -buildProvider.getBuilder('dependencies').builder.emitter.addListener('start', ({inputFiles}) => console.log('dependencies', inputFiles.keys())) +buildProvider + .getBuilder('dependencies') + .builder.emitter.addListener('start', ({inputFiles}) => + console.log('dependencies', inputFiles.keys()), + ) -const filter = (f) => f.startsWith('tests') - && /(? + f.startsWith('tests') && + /(? { - const files = { - server: await fileServer.url, - paths: Array.from(fileProvider.files.keys()).filter(filter), - } - const runs = conductors.map(c => c.createTestRun(files)) - const stack = new TestRunStack(runs.map(r => r.run)) - - for (const r of runs) { - await r.exec() - } - - await stack.then() - - const coverageMap = IstanbulLibCoverage.createCoverageMap() - for (const run of stack.runs) { - for (const coverage of run.coverage.values()) { - coverageMap.merge(coverage) - } - } - - const sourceStore = IstanbulLibSourceMaps.createSourceMapStore() - const reportContext = IstanbulLibReport.createContext({ - coverageMap: await sourceStore.transformCoverage(coverageMap), - dir: fileProvider.origin, - sourceFinder: sourceStore.sourceFinder, - defaultSummarizer: 'nested', - watermarks: { - branches: [80, 100], - functions: [80, 100], - lines: [80, 100], - statements: [80, 100], - }, - }) - - IstanbulReports.create('text').execute(reportContext) - - if (process.env.CI) { - toolbox.server.close() - env.server.close() - fileServer.close() - buildProvider.close() - reporterServer.close() - conductors.forEach(c => c.close()) + const files = { + server: await fileServer.url, + paths: Array.from(fileProvider.files.keys()).filter(filter), + } + const runs = conductors.map(c => c.createTestRun(files)) + const stack = new TestRunStack(runs.map(r => r.run)) + + for (const r of runs) { + await r.exec() + } + + await stack.then() + + const coverageMap = IstanbulLibCoverage.createCoverageMap() + for (const run of stack.runs) { + for (const coverage of run.coverage.values()) { + coverageMap.merge(coverage) } + } + + const sourceStore = IstanbulLibSourceMaps.createSourceMapStore() + const reportContext = IstanbulLibReport.createContext({ + coverageMap: await sourceStore.transformCoverage(coverageMap), + dir: fileProvider.origin, + sourceFinder: sourceStore.sourceFinder, + defaultSummarizer: 'nested', + watermarks: { + branches: [80, 100], + functions: [80, 100], + lines: [80, 100], + statements: [80, 100], + }, + }) + + IstanbulReports.create('text').execute(reportContext) + + if (process.env.CI) { + toolbox.server.close() + env.server.close() + fileServer.close() + buildProvider.close() + reporterServer.close() + conductors.forEach(c => c.close()) + } }) diff --git a/src/clipboard/copy.ts b/src/clipboard/copy.ts index dc4c5fe1..fac54bb9 100644 --- a/src/clipboard/copy.ts +++ b/src/clipboard/copy.ts @@ -1,5 +1,5 @@ import {copySelection} from '../document' -import type {Instance} from '../setup' +import {type Instance} from '../setup' import {writeDataTransferToClipboard} from '../utils' export async function copy(this: Instance) { diff --git a/src/clipboard/cut.ts b/src/clipboard/cut.ts index f267cfd9..7e75e2ee 100644 --- a/src/clipboard/cut.ts +++ b/src/clipboard/cut.ts @@ -1,5 +1,5 @@ import {copySelection} from '../document' -import type {Instance} from '../setup' +import {type Instance} from '../setup' import {writeDataTransferToClipboard} from '../utils' export async function cut(this: Instance) { diff --git a/src/clipboard/paste.ts b/src/clipboard/paste.ts index ab2e98d5..18c70cab 100644 --- a/src/clipboard/paste.ts +++ b/src/clipboard/paste.ts @@ -1,4 +1,4 @@ -import type {Instance} from '../setup' +import {type Instance} from '../setup' import { createDataTransfer, getWindow, diff --git a/src/convenience/click.ts b/src/convenience/click.ts index 789db166..ae18a622 100644 --- a/src/convenience/click.ts +++ b/src/convenience/click.ts @@ -1,5 +1,5 @@ -import type {PointerInput} from '../pointer' -import type {Instance} from '../setup' +import {type PointerInput} from '../pointer' +import {type Instance} from '../setup' export async function click(this: Instance, element: Element): Promise { const pointerIn: PointerInput = [] diff --git a/src/convenience/hover.ts b/src/convenience/hover.ts index a342e45a..345f9ea7 100644 --- a/src/convenience/hover.ts +++ b/src/convenience/hover.ts @@ -1,4 +1,4 @@ -import type {Instance} from '../setup' +import {type Instance} from '../setup' import {assertPointerEvents} from '../utils' export async function hover(this: Instance, element: Element) { diff --git a/src/convenience/tab.ts b/src/convenience/tab.ts index 7ec7991f..c544743e 100644 --- a/src/convenience/tab.ts +++ b/src/convenience/tab.ts @@ -1,4 +1,4 @@ -import type {Instance} from '../setup' +import {type Instance} from '../setup' export async function tab( this: Instance, diff --git a/src/event/behavior/registry.ts b/src/event/behavior/registry.ts index 586d0231..6b80f794 100644 --- a/src/event/behavior/registry.ts +++ b/src/event/behavior/registry.ts @@ -1,4 +1,4 @@ -import type {Instance} from '../../setup' +import {type Instance} from '../../setup' import {EventType} from '../types' export interface BehaviorPlugin { diff --git a/src/event/createEvent.ts b/src/event/createEvent.ts index 3b46731c..5b163059 100644 --- a/src/event/createEvent.ts +++ b/src/event/createEvent.ts @@ -1,6 +1,10 @@ import {getWindow} from '../utils' import {eventMap, eventMapKeys} from './eventMap' -import type {EventType, EventTypeInit, FixedDocumentEventMap} from './types' +import { + type EventType, + type EventTypeInit, + type FixedDocumentEventMap, +} from './types' const eventInitializer = { ClipboardEvent: [initClipboardEvent], diff --git a/src/event/dispatchEvent.ts b/src/event/dispatchEvent.ts index c3ea6fc1..4627296d 100644 --- a/src/event/dispatchEvent.ts +++ b/src/event/dispatchEvent.ts @@ -1,4 +1,4 @@ -import type {Instance} from '../setup' +import {type Instance} from '../setup' import {EventType, EventTypeInit} from './types' import {behavior, BehaviorPlugin} from './behavior' import {wrapEvent} from './wrapEvent' diff --git a/src/event/input.ts b/src/event/input.ts index b1d501ae..356eeba3 100644 --- a/src/event/input.ts +++ b/src/event/input.ts @@ -5,7 +5,7 @@ import { setUIValue, UISelectionRange, } from '../document' -import type {Instance} from '../setup' +import {type Instance} from '../setup' import { buildTimeValue, EditableInputOrTextarea, diff --git a/src/event/radio.ts b/src/event/radio.ts index 9c31098a..7c374af9 100644 --- a/src/event/radio.ts +++ b/src/event/radio.ts @@ -1,4 +1,4 @@ -import type {Instance} from '../setup' +import {type Instance} from '../setup' import {getWindow, isDisabled} from '../utils' import {focusElement} from './focus' diff --git a/src/event/selection/index.ts b/src/event/selection/index.ts index e0a9460d..f22dbb21 100644 --- a/src/event/selection/index.ts +++ b/src/event/selection/index.ts @@ -1,4 +1,4 @@ -import type {EditableInputOrTextarea} from '../../utils' +import {type EditableInputOrTextarea} from '../../utils' export {getInputRange} from './getInputRange' export {modifySelection} from './modifySelection' diff --git a/src/event/selection/modifySelectionPerMouse.ts b/src/event/selection/modifySelectionPerMouse.ts index 999458e0..edc4fff0 100644 --- a/src/event/selection/modifySelectionPerMouse.ts +++ b/src/event/selection/modifySelectionPerMouse.ts @@ -1,5 +1,5 @@ import {setUISelection} from '../../document' -import type {SelectionRange} from '.' +import {type SelectionRange} from '.' import {resolveCaretPosition} from './resolveCaretPosition' export function modifySelectionPerMouseMove( diff --git a/src/event/selection/setSelectionPerMouse.ts b/src/event/selection/setSelectionPerMouse.ts index 95a184c9..5078655e 100644 --- a/src/event/selection/setSelectionPerMouse.ts +++ b/src/event/selection/setSelectionPerMouse.ts @@ -1,6 +1,6 @@ import {getUIValue, setUISelection} from '../../document' import {hasNoSelection, hasOwnSelection} from '../../utils' -import type {SelectionRange} from '.' +import {type SelectionRange} from '.' import {resolveCaretPosition} from './resolveCaretPosition' export function setSelectionPerMouseDown({ diff --git a/src/event/wrapEvent.ts b/src/event/wrapEvent.ts index 15254b56..33ebf9bc 100644 --- a/src/event/wrapEvent.ts +++ b/src/event/wrapEvent.ts @@ -1,6 +1,6 @@ import dtl from '../_interop/dtl' -const { getConfig } = dtl +const {getConfig} = dtl export function wrapEvent(cb: () => R, _element: Element) { return getConfig().eventWrapper(cb) as unknown as R diff --git a/src/keyboard/index.ts b/src/keyboard/index.ts index 124508ba..d4687c0f 100644 --- a/src/keyboard/index.ts +++ b/src/keyboard/index.ts @@ -1,5 +1,5 @@ -import type {Instance} from '../setup' -import type {keyboardKey} from '../system/keyboard' +import {type Instance} from '../setup' +import {type keyboardKey} from '../system/keyboard' import {wait} from '../utils' import {parseKeyDef} from './parseKeyDef' diff --git a/src/options.ts b/src/options.ts index a1ba67a4..ad0ae94b 100644 --- a/src/options.ts +++ b/src/options.ts @@ -1,5 +1,5 @@ -import type {keyboardKey} from './system/keyboard' -import type {pointerKey} from './system/pointer' +import {type keyboardKey} from './system/keyboard' +import {type pointerKey} from './system/pointer' export enum PointerEventsCheckLevel { /** diff --git a/src/pointer/index.ts b/src/pointer/index.ts index 9d67d813..5a9c6a0e 100644 --- a/src/pointer/index.ts +++ b/src/pointer/index.ts @@ -1,6 +1,6 @@ -import type {PointerCoords} from '../event' -import type {Instance} from '../setup' -import type {pointerKey, PointerPosition} from '../system/pointer' +import {type PointerCoords} from '../event' +import {type Instance} from '../setup' +import {type pointerKey, type PointerPosition} from '../system/pointer' import {ApiLevel, setLevelRef, wait} from '../utils' import {parseKeyDef} from './parseKeyDef' diff --git a/src/setup/api.ts b/src/setup/api.ts index 4180ce64..a25bbc21 100644 --- a/src/setup/api.ts +++ b/src/setup/api.ts @@ -5,20 +5,20 @@ import {pointer} from '../pointer' import {clear, deselectOptions, selectOptions, type, upload} from '../utility' export const userEventApi = { - click, - dblClick, - tripleClick, - hover, - unhover, - tab, - keyboard, - copy, - cut, - paste, - pointer, - clear, - deselectOptions, - selectOptions, - type, - upload, + click, + dblClick, + tripleClick, + hover, + unhover, + tab, + keyboard, + copy, + cut, + paste, + pointer, + clear, + deselectOptions, + selectOptions, + type, + upload, } diff --git a/src/setup/directApi.ts b/src/setup/directApi.ts index 58b876bc..c27066c7 100644 --- a/src/setup/directApi.ts +++ b/src/setup/directApi.ts @@ -1,8 +1,7 @@ -import type {Options} from '../options' -import type {PointerInput} from '../pointer' -import type {System} from '../system' -import type {UserEventApi} from './setup' -import {setupDirect} from './setup' +import {type Options} from '../options' +import {type PointerInput} from '../pointer' +import {type System} from '../system' +import {setupDirect, type UserEventApi} from './setup' export type DirectOptions = Options & { keyboardState?: System diff --git a/src/setup/wrapAsync.ts b/src/setup/wrapAsync.ts index e18efcf8..6f496653 100644 --- a/src/setup/wrapAsync.ts +++ b/src/setup/wrapAsync.ts @@ -1,6 +1,6 @@ import dtl from '../_interop/dtl' -const { getConfig } = dtl +const {getConfig} = dtl /** * Wrap an internal Promise diff --git a/src/system/keyboard.ts b/src/system/keyboard.ts index d379685d..a70fbb80 100644 --- a/src/system/keyboard.ts +++ b/src/system/keyboard.ts @@ -1,6 +1,6 @@ -import type {Instance} from '../setup' +import {type Instance} from '../setup' import {getActiveElementOrBody} from '../utils' -import type {System} from '.' +import {type System} from '.' export enum DOM_KEY_LOCATION { STANDARD = 0, @@ -97,6 +97,7 @@ export class KeyboardHost { const target = getActiveElementOrBody(instance.config.document) this.setKeydownTarget(target) + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition this.pressed[code] ??= { keyDef, unpreventedDefault: false, diff --git a/src/system/pointer/buttons.ts b/src/system/pointer/buttons.ts index 38303a02..e078ea03 100644 --- a/src/system/pointer/buttons.ts +++ b/src/system/pointer/buttons.ts @@ -1,4 +1,4 @@ -import type {pointerKey} from './shared' +import {type pointerKey} from './shared' export class Buttons { private readonly pressed: Record = {} diff --git a/src/system/pointer/device.ts b/src/system/pointer/device.ts index e9fe7091..0d9cde40 100644 --- a/src/system/pointer/device.ts +++ b/src/system/pointer/device.ts @@ -1,4 +1,4 @@ -import type {pointerKey} from '.' +import {type pointerKey} from '.' export class Device { private pressedKeys = new Set() diff --git a/src/system/pointer/index.ts b/src/system/pointer/index.ts index f0691f3a..a574e8a1 100644 --- a/src/system/pointer/index.ts +++ b/src/system/pointer/index.ts @@ -23,6 +23,7 @@ export class PointerHost { private registry = {} as Record get(k: string) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition this.registry[k] ??= new Device() return this.registry[k] } diff --git a/src/system/pointer/mouse.ts b/src/system/pointer/mouse.ts index 7a1ea0a9..516a447e 100644 --- a/src/system/pointer/mouse.ts +++ b/src/system/pointer/mouse.ts @@ -5,10 +5,10 @@ import { SelectionRange, setSelectionPerMouseDown, } from '../../event' -import type {Instance} from '../../setup' +import {type Instance} from '../../setup' import {getTreeDiff, isDisabled} from '../../utils' import {Buttons, getMouseEventButton, MouseButton} from './buttons' -import type {Pointer} from './pointer' +import {type Pointer} from './pointer' import {isDifferentPointerPosition, pointerKey, PointerPosition} from './shared' /** diff --git a/src/system/pointer/pointer.ts b/src/system/pointer/pointer.ts index d622ca6b..fc149c70 100644 --- a/src/system/pointer/pointer.ts +++ b/src/system/pointer/pointer.ts @@ -1,4 +1,4 @@ -import type {Instance} from '../../setup' +import {type Instance} from '../../setup' import {assertPointerEvents, getTreeDiff, hasPointerEvents} from '../../utils' import {isDifferentPointerPosition, pointerKey, PointerPosition} from './shared' diff --git a/src/utility/clear.ts b/src/utility/clear.ts index 4e563edb..a383d10c 100644 --- a/src/utility/clear.ts +++ b/src/utility/clear.ts @@ -1,5 +1,5 @@ import {focusElement, input, isAllSelected, selectAll} from '../event' -import type {Instance} from '../setup' +import {type Instance} from '../setup' import {isDisabled, isEditable} from '../utils' export async function clear(this: Instance, element: Element) { diff --git a/src/utility/selectOptions.ts b/src/utility/selectOptions.ts index 03766a62..730b4616 100644 --- a/src/utility/selectOptions.ts +++ b/src/utility/selectOptions.ts @@ -1,9 +1,9 @@ import dtl from '../_interop/dtl' import {hasPointerEvents, isDisabled, isElementType, wait} from '../utils' -import type {Instance} from '../setup' +import {type Instance} from '../setup' import {focusElement} from '../event' -const { getConfig } = dtl +const {getConfig} = dtl export async function selectOptions( this: Instance, diff --git a/src/utility/type.ts b/src/utility/type.ts index 2f2da12b..d58b84eb 100644 --- a/src/utility/type.ts +++ b/src/utility/type.ts @@ -1,7 +1,7 @@ -import type {Instance} from '../setup' +import {type Instance} from '../setup' import {releaseAllKeys} from '../keyboard' import {setSelectionRange} from '../event/selection' -import type {Options} from '../options' +import {type Options} from '../options' export interface typeOptions { skipClick?: Options['skipClick'] diff --git a/src/utility/upload.ts b/src/utility/upload.ts index 3165aa17..df92e21d 100644 --- a/src/utility/upload.ts +++ b/src/utility/upload.ts @@ -5,7 +5,7 @@ import { isElementType, setFiles, } from '../utils' -import type {Instance} from '../setup' +import {type Instance} from '../setup' export interface uploadInit { changeInit?: EventInit diff --git a/src/utils/misc/isElementType.ts b/src/utils/misc/isElementType.ts index 8106a6ab..c67fbb0f 100644 --- a/src/utils/misc/isElementType.ts +++ b/src/utils/misc/isElementType.ts @@ -2,7 +2,7 @@ type tag = keyof HTMLElementTagNameMap export function isElementType< T extends tag, - P extends {[k: string]: unknown} | undefined = undefined + P extends {[k: string]: unknown} | undefined = undefined, >( element: Element, tag: T | T[], diff --git a/src/utils/misc/level.ts b/src/utils/misc/level.ts index d30114da..bd00b3cf 100644 --- a/src/utils/misc/level.ts +++ b/src/utils/misc/level.ts @@ -1,4 +1,4 @@ -import type {Instance} from '../../setup' +import {type Instance} from '../../setup' export enum ApiLevel { Trigger = 2, diff --git a/src/utils/misc/wait.ts b/src/utils/misc/wait.ts index edd13a6f..7a8ffa91 100644 --- a/src/utils/misc/wait.ts +++ b/src/utils/misc/wait.ts @@ -1,4 +1,4 @@ -import type {Instance} from '../../setup' +import {type Instance} from '../../setup' export function wait(config: Instance['config']) { const delay = config.delay diff --git a/src/utils/pointer/cssPointerEvents.ts b/src/utils/pointer/cssPointerEvents.ts index 7be9498f..b4055181 100644 --- a/src/utils/pointer/cssPointerEvents.ts +++ b/src/utils/pointer/cssPointerEvents.ts @@ -1,5 +1,5 @@ import {PointerEventsCheckLevel} from '../../options' -import type {Instance} from '../../setup' +import {type Instance} from '../../setup' import {getWindow} from '../misc/getWindow' import {isElementType} from '../misc/isElementType' import {ApiLevel, getLevelRef} from '../misc/level' diff --git a/testenv/jest.js b/testenv/jest.js index 49d18467..9b7df274 100644 --- a/testenv/jest.js +++ b/testenv/jest.js @@ -3,10 +3,10 @@ import './modules/timers.js' import './modules/testinglibrary.js' import './modules/console.js' -import { toMatchInlineSnapshot } from 'jest-snapshot' +import {toMatchInlineSnapshot} from 'jest-snapshot' expect.extend({ - toMatchInlineSnapshot: function(actual, ...args) { - return toMatchInlineSnapshot.call(this, actual?.snapshot ?? actual, ...args) - } + toMatchInlineSnapshot: function (actual, ...args) { + return toMatchInlineSnapshot.call(this, actual?.snapshot ?? actual, ...args) + }, }) diff --git a/testenv/libs/dom8/package.json b/testenv/libs/dom8/package.json index 1e7f7c83..a348f4db 100644 --- a/testenv/libs/dom8/package.json +++ b/testenv/libs/dom8/package.json @@ -1,6 +1,6 @@ { - "type": "module", - "dependencies": { - "@testing-library/dom": "^8" - } -} \ No newline at end of file + "type": "module", + "dependencies": { + "@testing-library/dom": "^8" + } +} diff --git a/testenv/libs/react17/package.json b/testenv/libs/react17/package.json index ee7a1398..f083fbbc 100644 --- a/testenv/libs/react17/package.json +++ b/testenv/libs/react17/package.json @@ -1,11 +1,11 @@ { - "type": "module", - "dependencies": { - "@testing-library/react": "^12", - "react": "^17", - "react-dom": "^17" - }, - "globals": { - "@testing-library/dom": "DomTestingLibrary" - } + "type": "module", + "dependencies": { + "@testing-library/react": "^12", + "react": "^17", + "react-dom": "^17" + }, + "globals": { + "@testing-library/dom": "DomTestingLibrary" + } } diff --git a/testenv/libs/react18/package.json b/testenv/libs/react18/package.json index 85e226f6..cac9fdb0 100644 --- a/testenv/libs/react18/package.json +++ b/testenv/libs/react18/package.json @@ -1,11 +1,11 @@ { - "type": "module", - "dependencies": { - "@testing-library/react": "^13", - "react": "^18", - "react-dom": "^18" - }, - "globals": { - "@testing-library/dom": "DomTestingLibrary" - } + "type": "module", + "dependencies": { + "@testing-library/react": "^13", + "react": "^18", + "react-dom": "^18" + }, + "globals": { + "@testing-library/dom": "DomTestingLibrary" + } } diff --git a/testenv/modules/console.js b/testenv/modules/console.js index d8468502..2691548d 100644 --- a/testenv/modules/console.js +++ b/testenv/modules/console.js @@ -1,30 +1,30 @@ const isCI = !!process.env.CI beforeEach(() => { - mocks.spyOn(console, 'error') - mocks.spyOn(console, 'log') - mocks.spyOn(console, 'warn') - mocks.spyOn(console, 'info') + mocks.spyOn(console, 'error') + mocks.spyOn(console, 'log') + mocks.spyOn(console, 'warn') + mocks.spyOn(console, 'info') }) afterEach(() => { - if (isCI && console.error.mock.calls.length) { - throw new Error(`console.error should not be called in tests`) - } - console.error.mockRestore() + if (isCI && console.error.mock.calls.length) { + throw new Error(`console.error should not be called in tests`) + } + console.error.mockRestore() - if (isCI && console.log.mock.calls.length) { - throw new Error(`console.log should not be called in tests`) - } - console.log.mockRestore() + if (isCI && console.log.mock.calls.length) { + throw new Error(`console.log should not be called in tests`) + } + console.log.mockRestore() - if (isCI && console.warn.mock.calls.length) { - throw new Error(`console.warn should not be called in tests`) - } - console.warn.mockRestore() + if (isCI && console.warn.mock.calls.length) { + throw new Error(`console.warn should not be called in tests`) + } + console.warn.mockRestore() - if (isCI && console.info.mock.calls.length) { - throw new Error(`console.info should not be called in tests`) - } - console.info.mockRestore() + if (isCI && console.info.mock.calls.length) { + throw new Error(`console.info should not be called in tests`) + } + console.info.mockRestore() }) diff --git a/testenv/modules/expect.js b/testenv/modules/expect.js index 3c0ddf04..e5df03c8 100644 --- a/testenv/modules/expect.js +++ b/testenv/modules/expect.js @@ -1,3 +1,3 @@ -import { expect } from 'expect' +import {expect} from 'expect' globalThis.expect = expect diff --git a/testenv/modules/fakeTimers.js b/testenv/modules/fakeTimers.js index 91502abc..963d41d1 100644 --- a/testenv/modules/fakeTimers.js +++ b/testenv/modules/fakeTimers.js @@ -19,86 +19,96 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -import { withGlobal, } from '@sinonjs/fake-timers'; +import {withGlobal} from '@sinonjs/fake-timers' var FakeTimers = /** @class */ (function () { - function FakeTimers(context) { - if (context === void 0) { context = globalThis; } - this.fakeTimers = withGlobal(context); + function FakeTimers(context) { + if (context === void 0) { + context = globalThis } - FakeTimers.prototype.clearAllTimers = function () { - var _a; - (_a = this.clock) === null || _a === void 0 ? void 0 : _a.reset(); - }; - FakeTimers.prototype.dispose = function () { - this.useRealTimers(); - }; - FakeTimers.prototype.runAllTimers = function () { - var _a; - (_a = this.clock) === null || _a === void 0 ? void 0 : _a.runAll(); - }; - FakeTimers.prototype.runOnlyPendingTimers = function () { - var _a; - (_a = this.clock) === null || _a === void 0 ? void 0 : _a.runToLast(); - }; - FakeTimers.prototype.advanceTimersToNextTimer = function (steps) { - if (steps === void 0) { steps = 1; } - this.assertFakeTimers(); - for (var i = steps; i > 0; i--) { - this.clock.next(); - // Fire all timers at this point: https://github.com/sinonjs/fake-timers/issues/250 - this.clock.tick(0); - if (this.clock.countTimers() === 0) { - break; - } - } - }; - FakeTimers.prototype.advanceTimersByTime = function (msToRun) { - this.assertFakeTimers(); - this.clock.tick(msToRun); - }; - FakeTimers.prototype.runAllTicks = function () { - this.assertFakeTimers(); - // @ts-expect-error - doesn't exist? - this.clock.runMicrotasks(); - }; - FakeTimers.prototype.useRealTimers = function () { - var _a; - (_a = this.clock) === null || _a === void 0 ? void 0 : _a.uninstall(); - delete this.clock; - }; - FakeTimers.prototype.useFakeTimers = function (fakeTimersConfig) { - if (this.clock) { - this.clock.uninstall(); - delete this.clock; - } - this.clock = this.fakeTimers.install(fakeTimersConfig); - }; - FakeTimers.prototype.reset = function () { - this.assertFakeTimers(); - var now = this.clock.now; - this.clock.reset(); - this.clock.setSystemTime(now); - }; - FakeTimers.prototype.setSystemTime = function (now) { - this.assertFakeTimers(); - this.clock.setSystemTime(now); - }; - FakeTimers.prototype.getRealSystemTime = function () { - return Date.now(); - }; - FakeTimers.prototype.now = function () { - var _a, _b; - return (_b = (_a = this.clock) === null || _a === void 0 ? void 0 : _a.now) !== null && _b !== void 0 ? _b : Date.now(); - }; - FakeTimers.prototype.getTimerCount = function () { - this.assertFakeTimers(); - return this.clock.countTimers(); - }; - FakeTimers.prototype.assertFakeTimers = function () { - if (!this.clock) { - throw new Error('A function that relies on fake timers was called, but the timers APIs are not replaced with fake timers.'); - } - }; - return FakeTimers; -}()); -export { FakeTimers }; + this.fakeTimers = withGlobal(context) + } + FakeTimers.prototype.clearAllTimers = function () { + var _a + ;(_a = this.clock) === null || _a === void 0 ? void 0 : _a.reset() + } + FakeTimers.prototype.dispose = function () { + this.useRealTimers() + } + FakeTimers.prototype.runAllTimers = function () { + var _a + ;(_a = this.clock) === null || _a === void 0 ? void 0 : _a.runAll() + } + FakeTimers.prototype.runOnlyPendingTimers = function () { + var _a + ;(_a = this.clock) === null || _a === void 0 ? void 0 : _a.runToLast() + } + FakeTimers.prototype.advanceTimersToNextTimer = function (steps) { + if (steps === void 0) { + steps = 1 + } + this.assertFakeTimers() + for (var i = steps; i > 0; i--) { + this.clock.next() + // Fire all timers at this point: https://github.com/sinonjs/fake-timers/issues/250 + this.clock.tick(0) + if (this.clock.countTimers() === 0) { + break + } + } + } + FakeTimers.prototype.advanceTimersByTime = function (msToRun) { + this.assertFakeTimers() + this.clock.tick(msToRun) + } + FakeTimers.prototype.runAllTicks = function () { + this.assertFakeTimers() + // @ts-expect-error - doesn't exist? + this.clock.runMicrotasks() + } + FakeTimers.prototype.useRealTimers = function () { + var _a + ;(_a = this.clock) === null || _a === void 0 ? void 0 : _a.uninstall() + delete this.clock + } + FakeTimers.prototype.useFakeTimers = function (fakeTimersConfig) { + if (this.clock) { + this.clock.uninstall() + delete this.clock + } + this.clock = this.fakeTimers.install(fakeTimersConfig) + } + FakeTimers.prototype.reset = function () { + this.assertFakeTimers() + var now = this.clock.now + this.clock.reset() + this.clock.setSystemTime(now) + } + FakeTimers.prototype.setSystemTime = function (now) { + this.assertFakeTimers() + this.clock.setSystemTime(now) + } + FakeTimers.prototype.getRealSystemTime = function () { + return Date.now() + } + FakeTimers.prototype.now = function () { + var _a, _b + return (_b = + (_a = this.clock) === null || _a === void 0 ? void 0 : _a.now) !== null && + _b !== void 0 + ? _b + : Date.now() + } + FakeTimers.prototype.getTimerCount = function () { + this.assertFakeTimers() + return this.clock.countTimers() + } + FakeTimers.prototype.assertFakeTimers = function () { + if (!this.clock) { + throw new Error( + 'A function that relies on fake timers was called, but the timers APIs are not replaced with fake timers.', + ) + } + } + return FakeTimers +})() +export {FakeTimers} diff --git a/testenv/modules/fakeTimers.ts b/testenv/modules/fakeTimers.ts index 0f2cf961..b7efbd96 100644 --- a/testenv/modules/fakeTimers.ts +++ b/testenv/modules/fakeTimers.ts @@ -1,16 +1,16 @@ /** * Copyright (c) Facebook, Inc. and its affiliates. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -21,104 +21,104 @@ */ import { - FakeTimerWithContext, - InstalledClock, - FakeTimerInstallOpts, - withGlobal, + FakeTimerWithContext, + InstalledClock, + FakeTimerInstallOpts, + withGlobal, } from '@sinonjs/fake-timers' export class FakeTimers { - protected readonly fakeTimers: FakeTimerWithContext - protected clock?: InstalledClock - - constructor( - context: typeof globalThis = globalThis, - ) { - this.fakeTimers = withGlobal(context) - } - - clearAllTimers(): void { - this.clock?.reset() - } - - dispose(): void { - this.useRealTimers() - } - - runAllTimers(): void { - this.clock?.runAll() - } - - runOnlyPendingTimers(): void { - this.clock?.runToLast() - } - - advanceTimersToNextTimer(steps = 1): void { - this.assertFakeTimers() - for (let i = steps; i > 0; i--) { - this.clock!.next() - // Fire all timers at this point: https://github.com/sinonjs/fake-timers/issues/250 - this.clock!.tick(0) - - if (this.clock!.countTimers() === 0) { - break - } - } - } - - advanceTimersByTime(msToRun: number): void { - this.assertFakeTimers() - this.clock!.tick(msToRun) - } - - runAllTicks(): void { - this.assertFakeTimers() - // @ts-expect-error - doesn't exist? - this.clock!.runMicrotasks() - } - - useRealTimers(): void { - this.clock?.uninstall() - delete this.clock - } - - useFakeTimers(fakeTimersConfig?: FakeTimerInstallOpts): void { - if (this.clock) { - this.clock.uninstall() - delete this.clock - } - - this.clock = this.fakeTimers.install(fakeTimersConfig) - } - - reset(): void { - this.assertFakeTimers() - const now = this.clock!.now - this.clock!.reset() - this.clock!.setSystemTime(now) - } - - setSystemTime(now?: number | Date): void { - this.assertFakeTimers() - this.clock!.setSystemTime(now) - } - - getRealSystemTime(): number { - return Date.now() - } - - now(): number { - return this.clock?.now ?? Date.now() - } - - getTimerCount(): number { - this.assertFakeTimers() - return this.clock!.countTimers() - } - - protected assertFakeTimers() { - if (!this.clock) { - throw new Error('A function that relies on fake timers was called, but the timers APIs are not replaced with fake timers.') - } - } + protected readonly fakeTimers: FakeTimerWithContext + protected clock?: InstalledClock + + constructor(context: typeof globalThis = globalThis) { + this.fakeTimers = withGlobal(context) + } + + clearAllTimers(): void { + this.clock?.reset() + } + + dispose(): void { + this.useRealTimers() + } + + runAllTimers(): void { + this.clock?.runAll() + } + + runOnlyPendingTimers(): void { + this.clock?.runToLast() + } + + advanceTimersToNextTimer(steps = 1): void { + this.assertFakeTimers() + for (let i = steps; i > 0; i--) { + this.clock!.next() + // Fire all timers at this point: https://github.com/sinonjs/fake-timers/issues/250 + this.clock!.tick(0) + + if (this.clock!.countTimers() === 0) { + break + } + } + } + + advanceTimersByTime(msToRun: number): void { + this.assertFakeTimers() + this.clock!.tick(msToRun) + } + + runAllTicks(): void { + this.assertFakeTimers() + // @ts-expect-error - doesn't exist? + this.clock!.runMicrotasks() + } + + useRealTimers(): void { + this.clock?.uninstall() + delete this.clock + } + + useFakeTimers(fakeTimersConfig?: FakeTimerInstallOpts): void { + if (this.clock) { + this.clock.uninstall() + delete this.clock + } + + this.clock = this.fakeTimers.install(fakeTimersConfig) + } + + reset(): void { + this.assertFakeTimers() + const now = this.clock!.now + this.clock!.reset() + this.clock!.setSystemTime(now) + } + + setSystemTime(now?: number | Date): void { + this.assertFakeTimers() + this.clock!.setSystemTime(now) + } + + getRealSystemTime(): number { + return Date.now() + } + + now(): number { + return this.clock?.now ?? Date.now() + } + + getTimerCount(): number { + this.assertFakeTimers() + return this.clock!.countTimers() + } + + protected assertFakeTimers() { + if (!this.clock) { + throw new Error( + 'A function that relies on fake timers was called, but the timers APIs are not replaced with fake timers.', + ) + } + } } diff --git a/testenv/modules/inlineSnapshot.js b/testenv/modules/inlineSnapshot.js index a884dd39..86169f36 100644 --- a/testenv/modules/inlineSnapshot.js +++ b/testenv/modules/inlineSnapshot.js @@ -1,120 +1,141 @@ expect.extend({ - toMatchInlineSnapshot, - toThrowErrorMatchingInlineSnapshot, + toMatchInlineSnapshot, + toThrowErrorMatchingInlineSnapshot, }) -export function toMatchInlineSnapshot( - actual, - expected, -) { - const normalizedActual = stripAddedLinebreaks(stripAddedIndentation(String(actual?.snapshot ?? actual))) - const normalizedExpected = stripAddedLinebreaks(stripAddedIndentation(expected)) +export function toMatchInlineSnapshot(actual, expected) { + const normalizedActual = stripAddedLinebreaks( + stripAddedIndentation(String(actual?.snapshot ?? actual)), + ) + const normalizedExpected = stripAddedLinebreaks( + stripAddedIndentation(expected), + ) - return { - pass: normalizedActual === normalizedExpected, - message: () => [ - this.utils.matcherHint('toMatchInlineSnapshot', undefined, undefined, { - isNot: this.isNot, - promise: this.promise, - }), - '', - this.utils.diff(normalizedExpected, normalizedActual, {expand: this.expand}), - ].join('\n'), - } + return { + pass: normalizedActual === normalizedExpected, + message: () => + [ + this.utils.matcherHint('toMatchInlineSnapshot', undefined, undefined, { + isNot: this.isNot, + promise: this.promise, + }), + '', + this.utils.diff(normalizedExpected, normalizedActual, { + expand: this.expand, + }), + ].join('\n'), + } } -export function toThrowErrorMatchingInlineSnapshot( - callback, - expected, -) { - if (typeof callback === 'function') { - try { - const promise = callback() - if (typeof promise === 'object' && 'then' in promise) { - return promise - .then(() => ({ didThrow: false }), r => ({ didThrow: true, actual: r })) - .then(({ didThrow, actual }) => matchError.call(this, didThrow, actual, expected)) - } - } catch (e) { - return matchError.call(this, true, e, expected) - } - return matchError.call(this, false, undefined, expected) - } else if (this.promise === 'rejects') { - return matchError.call(this, true, callback, expected) +export function toThrowErrorMatchingInlineSnapshot(callback, expected) { + if (typeof callback === 'function') { + try { + const promise = callback() + if (typeof promise === 'object' && 'then' in promise) { + return promise + .then( + () => ({didThrow: false}), + r => ({didThrow: true, actual: r}), + ) + .then(({didThrow, actual}) => + matchError.call(this, didThrow, actual, expected), + ) + } + } catch (e) { + return matchError.call(this, true, e, expected) } + return matchError.call(this, false, undefined, expected) + } else if (this.promise === 'rejects') { + return matchError.call(this, true, callback, expected) + } - throw new Error('Invalid argument') + throw new Error('Invalid argument') } -function matchError( - didThrow, - actual, - expected, -) { - const normalizedActual = didThrow && stripAddedLinebreaks(stripAddedIndentation(typeof actual === 'object' && 'message' in actual ? actual.message : String(actual))) - const normalizedExpected = stripAddedLinebreaks(stripAddedIndentation(expected)) +function matchError(didThrow, actual, expected) { + const normalizedActual = + didThrow && + stripAddedLinebreaks( + stripAddedIndentation( + typeof actual === 'object' && 'message' in actual + ? actual.message + : String(actual), + ), + ) + const normalizedExpected = stripAddedLinebreaks( + stripAddedIndentation(expected), + ) - return { - pass: this.isNot === !didThrow && normalizedActual === normalizedExpected, - message: () => [ - this.utils.matcherHint('toThrowErrorMatchingInlineSnapshot', undefined, undefined, { - isNot: this.isNot, - promise: this.promise, - }), - '', - didThrow - ? this.utils.diff(normalizedExpected, normalizedActual, { expand: this.expand }) - : '[Did not throw]', - ].join('\n'), - } + return { + pass: this.isNot === !didThrow && normalizedActual === normalizedExpected, + message: () => + [ + this.utils.matcherHint( + 'toThrowErrorMatchingInlineSnapshot', + undefined, + undefined, + { + isNot: this.isNot, + promise: this.promise, + }, + ), + '', + didThrow + ? this.utils.diff(normalizedExpected, normalizedActual, { + expand: this.expand, + }) + : '[Did not throw]', + ].join('\n'), + } } function stripAddedLinebreaks(normalizedSnapshot) { - return normalizedSnapshot.startsWith('\n') && normalizedSnapshot.endsWith('\n') - ? normalizedSnapshot.substring(1, normalizedSnapshot.length - 1) - : normalizedSnapshot + return normalizedSnapshot.startsWith('\n') && + normalizedSnapshot.endsWith('\n') + ? normalizedSnapshot.substring(1, normalizedSnapshot.length - 1) + : normalizedSnapshot } -const INDENTATION_REGEX = /^([^\S\n]*)\S/m; +const INDENTATION_REGEX = /^([^\S\n]*)\S/m function stripAddedIndentation(inlineSnapshot) { - // Find indentation if exists. - const match = inlineSnapshot.match(INDENTATION_REGEX) - if (!match || !match[1]) { - // No indentation. - return inlineSnapshot - } + // Find indentation if exists. + const match = inlineSnapshot.match(INDENTATION_REGEX) + if (!match || !match[1]) { + // No indentation. + return inlineSnapshot + } - const indentation = match[1] - const lines = inlineSnapshot.split('\n') - if (lines.length <= 2) { - // Must be at least 3 lines. - return inlineSnapshot - } + const indentation = match[1] + const lines = inlineSnapshot.split('\n') + if (lines.length <= 2) { + // Must be at least 3 lines. + return inlineSnapshot + } - if (lines[0].trim() !== '' || lines[lines.length - 1].trim() !== '') { - // If not blank first and last lines, abort. - return inlineSnapshot - } + if (lines[0].trim() !== '' || lines[lines.length - 1].trim() !== '') { + // If not blank first and last lines, abort. + return inlineSnapshot + } - for (let i = 1; i < lines.length - 1; i++) { - if (lines[i] !== '') { - if (lines[i].indexOf(indentation) !== 0) { - // All lines except first and last should either be blank or have the same - // indent as the first line (or more). If this isn't the case we don't - // want to touch the snapshot at all. - return inlineSnapshot - } + for (let i = 1; i < lines.length - 1; i++) { + if (lines[i] !== '') { + if (lines[i].indexOf(indentation) !== 0) { + // All lines except first and last should either be blank or have the same + // indent as the first line (or more). If this isn't the case we don't + // want to touch the snapshot at all. + return inlineSnapshot + } - lines[i] = lines[i].substring(indentation.length) - } + lines[i] = lines[i].substring(indentation.length) } + } - // Last line is a special case because it won't have the same indent as others - // but may still have been given some indent to line up. - lines[lines.length - 1] = '' + // Last line is a special case because it won't have the same indent as others + // but may still have been given some indent to line up. + lines[lines.length - 1] = '' - // Return inline snapshot, now at indent 0. - inlineSnapshot = lines.join('\n') - return inlineSnapshot + // Return inline snapshot, now at indent 0. + inlineSnapshot = lines.join('\n') + return inlineSnapshot } diff --git a/testenv/modules/mocks.js b/testenv/modules/mocks.js index 5449ce55..e6a0fcd6 100644 --- a/testenv/modules/mocks.js +++ b/testenv/modules/mocks.js @@ -1,4 +1,4 @@ -import { ModuleMocker } from 'jest-mock' +import {ModuleMocker} from 'jest-mock' const mocks = new ModuleMocker(globalThis) globalThis.mocks = mocks diff --git a/testenv/modules/timers.js b/testenv/modules/timers.js index 808da59b..468ca195 100644 --- a/testenv/modules/timers.js +++ b/testenv/modules/timers.js @@ -1,4 +1,4 @@ -import { FakeTimers } from './fakeTimers.js' +import {FakeTimers} from './fakeTimers.js' const timers = new FakeTimers() globalThis.timers = timers diff --git a/testenv/node.js b/testenv/node.js index c4655b21..6c54ce22 100644 --- a/testenv/node.js +++ b/testenv/node.js @@ -14,7 +14,7 @@ globalThis.window = jsdom.window globalThis.document = jsdom.window.document globalThis.window.CSS = { - escape: global.CSS.escape, + escape: global.CSS.escape, } globalThis.XPathResult = jsdom.window.XPathResult diff --git a/testenv/package.json b/testenv/package.json index 6990891f..3dbc1ca5 100644 --- a/testenv/package.json +++ b/testenv/package.json @@ -1 +1,3 @@ -{"type": "module"} +{ + "type": "module" +} diff --git a/testenv/types/index.d.ts b/testenv/types/index.d.ts index ac4e3942..d8a9b3b5 100644 --- a/testenv/types/index.d.ts +++ b/testenv/types/index.d.ts @@ -1,29 +1,29 @@ -import type { Expect } from 'expect' -import type { ModuleMocker } from 'jest-mock' -import type { SnapshotMatchers } from 'jest-snapshot' -import type { FakeTimers } from '../modules/fakeTimers' -import type { TestContext } from '@ph.fritsche/toolbox' +import type {Expect} from 'expect' +import type {ModuleMocker} from 'jest-mock' +import type {SnapshotMatchers} from 'jest-snapshot' +import type {FakeTimers} from '../modules/fakeTimers' +import type {TestContext} from '@ph.fritsche/toolbox' -type M = import('@testing-library/jest-dom/matchers').TestingLibraryMatchers +type M = + import('@testing-library/jest-dom/matchers').TestingLibraryMatchers declare module 'expect' { - export interface Matchers extends - M, - SnapshotMatchers - {} + export interface Matchers + extends M, + SnapshotMatchers {} } declare global { - declare var expect: Expect - - declare var mocks: ModuleMocker - - declare var timers: FakeTimers - - declare var describe: TestContext['describe'] - declare var test: TestContext['test'] - declare var beforeAll: TestContext['beforeAll'] - declare var beforeEach: TestContext['beforeEach'] - declare var afterAll: TestContext['afterAll'] - declare var afterEach: TestContext['afterEach'] + declare var expect: Expect + + declare var mocks: ModuleMocker + + declare var timers: FakeTimers + + declare var describe: TestContext['describe'] + declare var test: TestContext['test'] + declare var beforeAll: TestContext['beforeAll'] + declare var beforeEach: TestContext['beforeEach'] + declare var afterAll: TestContext['afterAll'] + declare var afterEach: TestContext['afterEach'] } diff --git a/tests/event/dispatchEvent.ts b/tests/event/dispatchEvent.ts index b76662ce..d468d3a3 100644 --- a/tests/event/dispatchEvent.ts +++ b/tests/event/dispatchEvent.ts @@ -2,7 +2,9 @@ import {behavior} from '#src/event/behavior' import {createConfig, createInstance} from '#src/setup/setup' import {render} from '#testHelpers' -const mockPlugin = mocks.spyOn(behavior as Required, 'click').mockImplementation(() => void 0) +const mockPlugin = mocks + .spyOn(behavior as Required, 'click') + .mockImplementation(() => void 0) afterEach(() => { mockPlugin.mockClear() diff --git a/tests/pointer/index.ts b/tests/pointer/index.ts index de6afb6f..b512fc16 100644 --- a/tests/pointer/index.ts +++ b/tests/pointer/index.ts @@ -1,4 +1,4 @@ -import type { SpyInstance } from 'jest-mock' +import {type SpyInstance} from 'jest-mock' import {PointerEventsCheckLevel} from '#src' import {setup} from '#testHelpers' @@ -126,7 +126,8 @@ test('no mousedown/mouseup on disabled elements', async () => { describe('check for pointer-events', () => { let getComputedStyle: SpyInstance beforeAll(() => { - getComputedStyle = mocks.spyOn(window, 'getComputedStyle') + getComputedStyle = mocks + .spyOn(window, 'getComputedStyle') .mockImplementation( () => ({ diff --git a/tests/setup/_mockApis.ts b/tests/setup/_mockApis.ts index a7c60428..a0652815 100644 --- a/tests/setup/_mockApis.ts +++ b/tests/setup/_mockApis.ts @@ -1,6 +1,6 @@ -import type {MockedFunction, MockInstance} from 'jest-mock' -import type {Instance, UserEventApi} from '#src/setup/setup' -import { userEventApi } from '#src/setup/api' +import {type MockedFunction, type MockInstance} from 'jest-mock' +import {type Instance, type UserEventApi} from '#src/setup/setup' +import {userEventApi} from '#src/setup/api' // `const` are not initialized when mocking is executed, but `function` are when prefixed with `mock` const mockApis = {} as { @@ -17,18 +17,19 @@ export function getReal(k: K) { return mockApis[k].real } -type APIMock = UserEventApi[name] & MockInstance & { - originalMockImplementation: ( - this: Instance, - ...args: Parameters - ) => ReturnType - mock: { - lastCall?: { - this: Instance +type APIMock = UserEventApi[name] & + MockInstance & { + originalMockImplementation: ( + this: Instance, + ...args: Parameters + ) => ReturnType + mock: { + lastCall?: { + this: Instance + } + calls: {this: Instance}[] } - calls: {this: Instance}[] } -} const real = { ...userEventApi, diff --git a/tests/setup/index.ts b/tests/setup/index.ts index f498e8a2..4f51b7f1 100644 --- a/tests/setup/index.ts +++ b/tests/setup/index.ts @@ -1,10 +1,10 @@ import {getSpy} from './_mockApis' import DOMTestingLibrary from '#src/_interop/dtl' import userEvent from '#src' -import type {Instance, UserEventApi} from '#src/setup/setup' +import {type Instance, type UserEventApi} from '#src/setup/setup' import {render} from '#testHelpers' -const { getConfig } = DOMTestingLibrary +const {getConfig} = DOMTestingLibrary type ApiDeclarations = { [api in keyof UserEventApi]: { @@ -68,8 +68,12 @@ const apiDeclarations: ApiDeclarations = { }, } -type ApiDeclarationsEntry = [k, ApiDeclarations[k]] -const apiDeclarationsEntries = Object.entries(apiDeclarations) as ApiDeclarationsEntry[] +type ApiDeclarationsEntry< + k extends keyof ApiDeclarations = keyof ApiDeclarations, +> = [k, ApiDeclarations[k]] +const apiDeclarationsEntries = Object.entries( + apiDeclarations, +) as ApiDeclarationsEntry[] const opt = Symbol('testOption') declare module '#src/setup' { @@ -139,9 +143,7 @@ test.each(apiDeclarationsEntries)( expect(spy).toBeCalledTimes(2) expect(spy.mock.lastCall?.this.config[opt]).toBe(true) - expect(spy.mock.calls[1].this.system).toBe( - spy.mock.calls[0].this.system, - ) + expect(spy.mock.calls[1].this.system).toBe(spy.mock.calls[0].this.system) }, ) diff --git a/tests/tsconfig.json b/tests/tsconfig.json index d9659fb1..9aa9f8a6 100644 --- a/tests/tsconfig.json +++ b/tests/tsconfig.json @@ -7,12 +7,8 @@ "#src/*": ["./src/*"], "#testHelpers": ["./tests/_helpers/index"] }, - "typeRoots": [ - "../testenv", - ], - "types": [ - "types", - ], + "typeRoots": ["../testenv"], + "types": ["types"] }, - "include": [".", "../testenv"], + "include": [".", "../testenv"] } diff --git a/tests/utils/misc/isVisible.ts b/tests/utils/misc/isVisible.ts index d603ae55..61ca89e5 100644 --- a/tests/utils/misc/isVisible.ts +++ b/tests/utils/misc/isVisible.ts @@ -2,7 +2,7 @@ import DOMTestingLibrary from '#src/_interop/dtl' import {isVisible} from '#src/utils' import {setup} from '#testHelpers' -const { screen } = DOMTestingLibrary +const {screen} = DOMTestingLibrary test('check if element is visible', async () => { setup(` diff --git a/tsconfig.json b/tsconfig.json index ccfd108b..046b11ae 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,16 +2,13 @@ "extends": "./node_modules/kcd-scripts/shared-tsconfig.json", "compilerOptions": { "esModuleInterop": true, - "lib": [ - "ESNext", - "DOM", - ], + "lib": ["ESNext", "DOM"], "target": "ES5", "baseUrl": "/dev/null", "paths": {}, "noEmit": true, "typeRoots": [], - "types": [], + "types": [] }, "include": ["./src"] }