mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-12 06:26:16 -08:00
refactor(thumbnail): [PKG-TOOL-THUMB-04] preserve approved published defaults
This commit is contained in:
1 parent
490e157717
commit
b5f8b5e28e
37 files changed
+11172
-136
No files matched your search
@@ -22,7 +22,9 @@ test('Monaco consumes Thumbnail global declarations and runs the actual typed co
|
||||
}))
|
||||
const model = api.editor.createModel(`
|
||||
const input = document.createElement('input'); input.type = 'file'; document.body.appendChild(input);
|
||||
const options: ArtplayerToolThumbnail.Option = { fileInput: input, number: 10 };
|
||||
const mode: ArtplayerToolThumbnail.Compatibility = 'workspace-4.4';
|
||||
const defaults: ArtplayerToolThumbnail.DefaultOptions = ArtplayerToolThumbnail.DEFAULTS;
|
||||
const options: ArtplayerToolThumbnail.Option = { fileInput: input, number: 10, compatibility: mode, delay: defaults.delay };
|
||||
const tool: ArtplayerToolThumbnail = new ArtplayerToolThumbnail(options);
|
||||
let last = 0;
|
||||
tool.on('custom', (value: number) => { last = value; });
|
||||
@@ -32,7 +34,7 @@ const video: HTMLVideoElement = tool.video;
|
||||
tool.destroy(); tool.destroy(); input.remove();
|
||||
function mediaTypes(player: artplayerProxyMediabunny.MediaBunnyPlayer): number | undefined { return player.mediabunny?.currentTime; }
|
||||
`, 'typescript', api.Uri.parse('file:///thumbnail-consumer.ts'))
|
||||
const invalid = api.editor.createModel("new ArtplayerToolThumbnail({ fileInput: '#input' });", 'typescript', api.Uri.parse('file:///thumbnail-invalid.ts'))
|
||||
const invalid = api.editor.createModel('new ArtplayerToolThumbnail({ fileInput: \'#input\' });', 'typescript', api.Uri.parse('file:///thumbnail-invalid.ts'))
|
||||
try {
|
||||
const worker = await (await types.getTypeScriptWorker())(model.uri, invalid.uri)
|
||||
const syntax = await worker.getSyntacticDiagnostics(model.uri.toString())
|
||||
|
||||
@@ -12,7 +12,7 @@ test('Thumbnail input ownership replaces real DOM listeners and generated inputs
|
||||
await page.addScriptTag({ content: implementation.code })
|
||||
await page.evaluate(() => {
|
||||
window.inputEvents = []
|
||||
window.inputTool = new window.ArtplayerToolThumbnail({ fileInput: document.querySelector('#first') })
|
||||
window.inputTool = new window.ArtplayerToolThumbnail({ fileInput: document.querySelector('#first'), compatibility: 'workspace-4.4' })
|
||||
window.firstInput = window.inputTool.option.fileInput
|
||||
window.inputTool.on('file', file => window.inputEvents.push(file.name))
|
||||
window.inputTool.setup({ fileInput: document.querySelector('#first') })
|
||||
|
||||
@@ -27,7 +27,12 @@ async function capabilityControl(page, testInfo, lifecycle) {
|
||||
return true
|
||||
}
|
||||
|
||||
const implementations = [...thumbnailHistorical(), { ...await thumbnailCandidate(), inputOwnership: true, lifecycle: true }]
|
||||
const candidate = await thumbnailCandidate()
|
||||
const implementations = [
|
||||
...thumbnailHistorical(),
|
||||
{ ...candidate, inputOwnership: true, lifecycle: true, publishedPolicy: true },
|
||||
{ ...candidate, name: `${candidate.name}-workspace-policy`, inputOwnership: true, lifecycle: true, compatibility: 'workspace-4.4' },
|
||||
]
|
||||
for (const implementation of implementations) {
|
||||
test.describe(`Thumbnail tool ${implementation.name}`, () => {
|
||||
test.beforeEach(async ({ page }, testInfo) => {
|
||||
@@ -61,7 +66,7 @@ for (const implementation of implementations) {
|
||||
}
|
||||
URL.revokeObjectURL(blobUrl)
|
||||
})
|
||||
await page.evaluate(() => {
|
||||
await page.evaluate((compatibility) => {
|
||||
window.created = []
|
||||
window.revoked = []
|
||||
const create = URL.createObjectURL.bind(URL)
|
||||
@@ -75,11 +80,11 @@ for (const implementation of implementations) {
|
||||
revoked.push(url)
|
||||
revoke(url)
|
||||
}
|
||||
window.tool = new ArtplayerToolThumbnail({ fileInput: document.querySelector('#input'), number: 10, width: 80, height: 30, column: 3, begin: 0, end: 20 })
|
||||
window.tool = new ArtplayerToolThumbnail({ fileInput: document.querySelector('#input'), number: 10, width: 80, height: 30, column: 3, begin: 0, end: 20, compatibility })
|
||||
window.observed = []
|
||||
for (const event of ['file', 'video', 'canvas', 'update', 'done', 'error', 'destroy'])
|
||||
tool.on(event, (...args) => observed.push({ event, progress: event === 'update' ? args[1] : null, processing: tool.processing }))
|
||||
})
|
||||
tool.on(event, (...args) => observed.push({ event, at: performance.now(), progress: event === 'update' ? args[1] : null, processing: tool.processing }))
|
||||
}, implementation.compatibility)
|
||||
await testInfo.attach('thumbnail-runtime', { contentType: 'application/json', body: JSON.stringify({ name: implementation.name, sha256: hash(implementation.code), recoveredIndividualFile: implementation.legacy, originalNpmArchive: false, media: path.relative(process.cwd(), sample) }) })
|
||||
})
|
||||
|
||||
@@ -117,12 +122,20 @@ for (const implementation of implementations) {
|
||||
return { width: image.width, height: image.height, sourceWidth, sourceHeight, cellHeight: tool.option.height, mime: blob.type, bytes: blob.size, nonBlack, initialEvents, events: observed, first, second, created, revoked, connected: tool.video.isConnected, retiredReadyState: tool.video.readyState, retiredSrc: tool.video.getAttribute('src') }
|
||||
})
|
||||
expect(result.width).toBe(240)
|
||||
expect(result.cellHeight).toBe(implementation.legacy ? 30 : result.sourceHeight / result.sourceWidth * 80)
|
||||
expect(result.cellHeight).toBe(implementation.legacy || implementation.publishedPolicy ? 30 : result.sourceHeight / result.sourceWidth * 80)
|
||||
expect(result.height).toBe(Math.trunc(result.cellHeight * 4 + 30))
|
||||
expect(result.mime).toBe('image/png')
|
||||
expect(result.bytes).toBeGreaterThan(100)
|
||||
expect(result.nonBlack).toBeGreaterThan(100)
|
||||
expect(result.initialEvents.filter(item => item.event === 'update').map(item => item.progress)).toEqual(Array.from({ length: 10 }, (_, i) => (i + 1) / 10))
|
||||
if (implementation.publishedPolicy) {
|
||||
const events = result.initialEvents
|
||||
expect(events.find(item => item.event === 'video').at - events.find(item => item.event === 'file').at).toBeGreaterThanOrEqual(298)
|
||||
const frames = events.filter(item => item.event === 'canvas' || item.event === 'update')
|
||||
for (let index = 1; index < frames.length; index++)
|
||||
expect(frames[index].at - frames[index - 1].at).toBeGreaterThanOrEqual(298)
|
||||
expect(events.find(item => item.event === 'done').at - frames.at(-1).at).toBeGreaterThanOrEqual(598)
|
||||
}
|
||||
expect(result.events.filter(item => item.event === 'done')).toHaveLength(2)
|
||||
expect(result.first).not.toBe(result.second)
|
||||
expect([...result.created].sort()).toEqual([...result.revoked].sort())
|
||||
@@ -177,7 +190,7 @@ for (const implementation of implementations) {
|
||||
expect(result.revoked).toEqual(implementation.lifecycle ? result.created : [result.created[1]])
|
||||
expect(result.revoked.includes(failed.first)).toBe(!!implementation.lifecycle)
|
||||
expect(result.repeated).toBe(implementation.inputOwnership ? undefined : 'NotFoundError')
|
||||
expect(result.value === '').toBe(!implementation.legacy)
|
||||
expect(result.value === '').toBe(!(implementation.legacy || implementation.publishedPolicy))
|
||||
await testInfo.attach('thumbnail-media-failure', { contentType: 'application/json', body: JSON.stringify({ failed, result }) })
|
||||
})
|
||||
|
||||
@@ -255,6 +268,8 @@ for (const implementation of implementations) {
|
||||
})
|
||||
})
|
||||
await expect.poll(() => page.evaluate(() => typeof window.releaseFirst)).toBe('function')
|
||||
// Published policy retains the value; selecting the same file need not fire change.
|
||||
await page.locator('#input').setInputFiles([])
|
||||
await page.locator('#input').setInputFiles(sample)
|
||||
const result = await page.evaluate(async () => {
|
||||
const source = tool.videoUrl
|
||||
|
||||
@@ -7,7 +7,7 @@ const implementation = await thumbnailCandidate()
|
||||
function setup(wrapper = false) {
|
||||
const env = thumbnailEnvironment(implementation)
|
||||
const target = new env.Element(wrapper ? 'div' : 'input')
|
||||
const instance = new env.Factory({ fileInput: target, number: 10, width: 20, height: 30, column: 3 })
|
||||
const instance = new env.Factory({ fileInput: target, number: 10, width: 20, height: 30, column: 3, compatibility: 'workspace-4.4' })
|
||||
return { ...env, target, instance }
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ test('Thumbnail input ownership preserves class methods, constructor fields and
|
||||
assert.equal(exported.default, undefined)
|
||||
assert.deepEqual(Object.keys(instance), ['processing', 'option', 'video', 'duration', 'inputChange', 'ondrop'])
|
||||
assert.deepEqual(Object.getOwnPropertyNames(Factory.prototype), ['constructor', 'ondrop', 'setup', 'inputChange', 'loadVideo', 'start', 'creatScreenshotDate', 'creatCanvas', 'download', 'errorHandle', 'destroy'])
|
||||
assert.deepEqual(Object.keys(Factory.DEFAULTS), ['number', 'width', 'height', 'column', 'begin', 'end'])
|
||||
assert.deepEqual(Object.keys(Factory.DEFAULTS), ['delay', 'number', 'width', 'height', 'column', 'begin', 'end'])
|
||||
assert.equal(instance.setup({ custom: 7 }), instance)
|
||||
assert.equal(instance.option.custom, 7)
|
||||
instance.destroy()
|
||||
|
||||
@@ -16,7 +16,8 @@ function observe(promise) {
|
||||
}
|
||||
function setup(ready = true) {
|
||||
const env = thumbnailEnvironment(implementation)
|
||||
env.instance = new env.Factory({ fileInput: new env.Element('input'), number: 10, width: 40, column: 3 })
|
||||
// These lifecycle fixtures retain the explicitly selected workspace timing.
|
||||
env.instance = new env.Factory({ fileInput: new env.Element('input'), number: 10, width: 40, column: 3, compatibility: 'workspace-4.4' })
|
||||
env.instance.loadVideo({ name: 'first.mp4', type: 'video/mp4' })
|
||||
if (ready) {
|
||||
env.instance.video.duration = 100
|
||||
@@ -409,7 +410,7 @@ test('Thumbnail URL creation reentrant load preserves the newer source and revok
|
||||
|
||||
test('Thumbnail start before the first file retains its legacy wait-for-selection behavior', async () => {
|
||||
const env = thumbnailEnvironment(implementation)
|
||||
env.instance = new env.Factory({ fileInput: new env.Element('input'), number: 10 })
|
||||
env.instance = new env.Factory({ fileInput: new env.Element('input'), number: 10, compatibility: 'workspace-4.4' })
|
||||
const state = observe(env.instance.start())
|
||||
env.instance.loadVideo({ name: 'first.mp4', type: 'video/mp4' })
|
||||
env.instance.video.duration = 100
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
import assert from 'node:assert/strict'
|
||||
// eslint-disable-next-line test/no-import-node-test -- Approved runtime policy compatibility.
|
||||
import test from 'node:test'
|
||||
import { thumbnailCandidate, thumbnailEnvironment, thumbnailHistorical } from './helpers/thumbnail.js'
|
||||
|
||||
const candidate = await thumbnailCandidate()
|
||||
const flush = () => new Promise(resolve => setImmediate(resolve))
|
||||
function create(option = {}) {
|
||||
const env = thumbnailEnvironment(candidate)
|
||||
env.input = new env.Element('input')
|
||||
env.tool = new env.Factory({ fileInput: env.input, number: 10, width: 40, height: 25, ...option })
|
||||
return env
|
||||
}
|
||||
function tick(env, delay) {
|
||||
const selected = [...env.timers].find(([, timer]) => Object.is(timer.delay, delay))
|
||||
assert(selected, `Expected owned timer for ${delay} ms`)
|
||||
env.timers.delete(selected[0])
|
||||
selected[1].callback()
|
||||
}
|
||||
function ready(env) {
|
||||
env.tool.video.duration = 100
|
||||
env.tool.video.readyState = 2
|
||||
env.tool.video.videoWidth = 160
|
||||
env.tool.video.videoHeight = 90
|
||||
env.tool.loadVideo({ name: 'sample.mp4', type: 'video/mp4' })
|
||||
for (const fn of env.tool.video.handlers.get('loadedmetadata'))
|
||||
fn()
|
||||
}
|
||||
|
||||
test('Thumbnail root defaults match the recovered published profile, including key order', () => {
|
||||
const actual = create()
|
||||
const old = thumbnailEnvironment(thumbnailHistorical().find(item => item.legacy))
|
||||
assert.deepEqual(Object.keys(actual.Factory.DEFAULTS), Object.keys(old.Factory.DEFAULTS))
|
||||
for (const key of Object.keys(old.Factory.DEFAULTS))
|
||||
assert.equal(actual.Factory.DEFAULTS[key], old.Factory.DEFAULTS[key])
|
||||
actual.tool.destroy()
|
||||
})
|
||||
|
||||
test('Thumbnail published policy validates and clamps delay/height while workspace preserves its inputs', () => {
|
||||
const published = create({ height: 2, delay: 4000 })
|
||||
assert.equal(published.tool.option.height, 10)
|
||||
assert.equal(published.tool.option.delay, 1000)
|
||||
assert.throws(() => published.tool.setup({ delay: 'bad' }), /delay.*number/)
|
||||
assert.throws(() => published.tool.setup({ height: 'bad' }), /height.*number/)
|
||||
assert.throws(() => published.tool.setup({ compatibility: 'unknown' }), /compatibility/)
|
||||
const workspace = create({ compatibility: 'workspace-4.4', height: 2, delay: 4000 })
|
||||
assert.equal(workspace.tool.option.height, 2)
|
||||
assert.equal(workspace.tool.option.delay, 4000)
|
||||
published.tool.destroy()
|
||||
workspace.tool.destroy()
|
||||
})
|
||||
|
||||
for (const compatibility of [undefined, 'published-3.5', 'workspace-4.4']) {
|
||||
test(`Thumbnail ${compatibility || 'default'} preserves file/video timing and input reset policy`, () => {
|
||||
const env = create({ compatibility, delay: 25 })
|
||||
const seen = []
|
||||
env.input.files = [{ name: 'sample.mp4', type: 'video/mp4' }]
|
||||
env.input.value = 'selected'
|
||||
env.tool.on('file', () => seen.push(['file', env.tool.video.src]))
|
||||
env.tool.on('video', video => seen.push(['video', video.src]))
|
||||
env.tool.inputChange({ target: env.input })
|
||||
const workspace = compatibility === 'workspace-4.4'
|
||||
assert.deepEqual(seen, workspace ? [['file', undefined], ['video', env.tool.videoUrl]] : [['file', undefined]])
|
||||
assert.equal(env.input.value, workspace ? '' : 'selected')
|
||||
if (!workspace) {
|
||||
tick(env, 25)
|
||||
assert.deepEqual(seen[1], ['video', env.tool.videoUrl])
|
||||
}
|
||||
env.tool.destroy()
|
||||
assert.equal(env.timers.size, 0)
|
||||
})
|
||||
}
|
||||
|
||||
test('Thumbnail default extraction keeps configured height and requires delay plus frame readiness', async () => {
|
||||
const env = create({ delay: 25 })
|
||||
ready(env)
|
||||
tick(env, 25)
|
||||
env.tool.video.seeking = true
|
||||
const work = env.tool.start()
|
||||
await flush()
|
||||
assert.equal(env.tool.option.height, 25)
|
||||
tick(env, 25)
|
||||
assert.equal(env.operations.filter(op => op.name === 'drawImage').length, 0)
|
||||
env.tool.video.seeking = false
|
||||
env.tool.video.oncanplay()
|
||||
await flush()
|
||||
assert.equal(env.operations.filter(op => op.name === 'drawImage').length, 1)
|
||||
env.tool.destroy()
|
||||
await assert.rejects(work, { name: 'AbortError' })
|
||||
assert.equal(env.timers.size, 0)
|
||||
})
|
||||
|
||||
test('Thumbnail delayed video notifications are cancelled by replacement, failure and destroy', () => {
|
||||
for (const action of ['replace', 'error', 'destroy']) {
|
||||
const env = create({ delay: 25 })
|
||||
const seen = []
|
||||
env.tool.on('video', () => seen.push(env.tool.file.name)).on('error', () => {})
|
||||
env.tool.loadVideo({ name: 'old.mp4', type: 'video/mp4' })
|
||||
const stale = [...env.timers.values()].find(timer => timer.delay === 25)
|
||||
assert(stale)
|
||||
if (action === 'replace') {
|
||||
env.tool.loadVideo({ name: 'new.mp4', type: 'video/mp4' })
|
||||
}
|
||||
else if (action === 'error') {
|
||||
for (const fn of env.tool.video.handlers.get('error'))
|
||||
fn()
|
||||
}
|
||||
else {
|
||||
env.tool.destroy()
|
||||
}
|
||||
stale.callback()
|
||||
assert.deepEqual(seen, [])
|
||||
if (action === 'replace') {
|
||||
tick(env, 25)
|
||||
assert.deepEqual(seen, ['new.mp4'])
|
||||
}
|
||||
env.tool.destroy()
|
||||
assert.equal(env.timers.size, 0)
|
||||
}
|
||||
})
|
||||
|
||||
test('Thumbnail numeric NaN delay keeps the historical asynchronous timer boundary', () => {
|
||||
const env = create({ delay: Number.NaN })
|
||||
let events = 0
|
||||
env.tool.on('video', () => events++)
|
||||
env.tool.loadVideo({ name: 'sample.mp4', type: 'video/mp4' })
|
||||
assert.equal(events, 0)
|
||||
tick(env, Number.NaN)
|
||||
assert.equal(events, 1)
|
||||
env.tool.destroy()
|
||||
})
|
||||
|
||||
for (const finish of ['complete', 'destroy', 'replace', 'error']) {
|
||||
test(`Thumbnail default final delay owns completion and ${finish} settlement`, async () => {
|
||||
const env = create({ delay: 25 })
|
||||
ready(env)
|
||||
tick(env, 25)
|
||||
let done = 0
|
||||
const updates = []
|
||||
env.tool.on('done', () => done++).on('update', (_, progress) => updates.push(progress))
|
||||
const work = env.tool.start()
|
||||
await flush()
|
||||
for (let frame = 0; frame < 10; frame++) {
|
||||
tick(env, 25)
|
||||
await flush()
|
||||
}
|
||||
assert.deepEqual(updates, Array.from({ length: 10 }, (_, index) => (index + 1) / 10))
|
||||
assert.equal(done, 0)
|
||||
assert.equal(env.tool.processing, true)
|
||||
const final = [...env.timers.values()].find(timer => timer.delay === 50)
|
||||
assert(final)
|
||||
if (finish === 'complete') {
|
||||
tick(env, 50)
|
||||
await work
|
||||
assert.equal(done, 1)
|
||||
}
|
||||
else {
|
||||
if (finish === 'destroy') {
|
||||
env.tool.destroy()
|
||||
}
|
||||
else if (finish === 'replace') {
|
||||
env.tool.loadVideo({ name: 'next.mp4', type: 'video/mp4' })
|
||||
}
|
||||
else {
|
||||
env.tool.on('error', () => {})
|
||||
for (const fn of [...env.tool.video.handlers.get('error')])
|
||||
fn()
|
||||
}
|
||||
await assert.rejects(work, finish === 'error' ? /Unable to load video/ : { name: 'AbortError' })
|
||||
final.callback()
|
||||
assert.equal(done, 0)
|
||||
}
|
||||
assert.equal(env.tool.processing, false)
|
||||
env.tool.destroy()
|
||||
assert.equal(env.timers.size, 0)
|
||||
})
|
||||
}
|
||||
|
||||
test('Thumbnail explicit workspace extraction retains aspect height with no policy timers', async () => {
|
||||
const env = create({ compatibility: 'workspace-4.4', delay: 25 })
|
||||
ready(env)
|
||||
const work = env.tool.start()
|
||||
await work
|
||||
assert.equal(env.tool.option.height, 22.5)
|
||||
assert.equal(env.operations.filter(op => op.name === 'drawImage').length, 10)
|
||||
assert.equal(env.timers.size, 0)
|
||||
env.tool.destroy()
|
||||
})
|
||||
@@ -6,9 +6,9 @@ import vm from 'node:vm'
|
||||
import { thumbnailCandidate, thumbnailEnvironment, thumbnailHistorical } from './helpers/thumbnail.js'
|
||||
|
||||
const candidate = await thumbnailCandidate()
|
||||
function create(implementation) {
|
||||
function create(implementation, option = {}) {
|
||||
const env = thumbnailEnvironment(implementation)
|
||||
return { ...env, tool: new env.Factory({ fileInput: new env.Element('input') }) }
|
||||
return { ...env, tool: new env.Factory({ fileInput: new env.Element('input'), ...option }) }
|
||||
}
|
||||
const referenceModule = { exports: {} }
|
||||
vm.runInNewContext(fs.readFileSync(new URL('../refactor/baselines/thumbnail-vendor/tiny-emitter-2.1.0.txt', import.meta.url), 'utf8'), { module: referenceModule })
|
||||
@@ -39,7 +39,8 @@ test('Thumbnail typed facade preserves descriptors, lazy fields, default class a
|
||||
assert.equal(tool.option.custom, metadata)
|
||||
assert.equal(tool.option.width, 21.5)
|
||||
assert.notEqual(Factory.DEFAULTS, Factory.DEFAULTS)
|
||||
assert.deepEqual(Object.keys(Factory.DEFAULTS), Object.keys(baseline.Factory.DEFAULTS))
|
||||
const published = thumbnailEnvironment(thumbnailHistorical().find(item => item.legacy))
|
||||
assert.deepEqual(Object.keys(Factory.DEFAULTS), Object.keys(published.Factory.DEFAULTS))
|
||||
assert(Number.isNaN(Factory.DEFAULTS.end))
|
||||
tool.destroy()
|
||||
})
|
||||
@@ -132,7 +133,7 @@ test('Thumbnail typed facade retains synchronous validation, option mutation and
|
||||
|
||||
test('Thumbnail error event preserves arbitrary thrown message values and Promise rejection identity', async () => {
|
||||
for (const failure of [{ message: 7 }, { message: { detail: 'failure' } }, 3, null]) {
|
||||
const { tool } = create(candidate)
|
||||
const { tool } = create(candidate, { compatibility: 'workspace-4.4' })
|
||||
tool.setup({ number: 10 })
|
||||
tool.file = { name: 'sample.mp4' }
|
||||
tool.video.duration = 100
|
||||
|
||||
+12
-2
@@ -1,4 +1,4 @@
|
||||
import type { EventArgs, Option, ScreenshotPoint } from 'artplayer-tool-thumbnail'
|
||||
import type { Compatibility, DefaultOptions, EventArgs, Option, ScreenshotPoint } from 'artplayer-tool-thumbnail'
|
||||
import Thumbnail from 'artplayer-tool-thumbnail'
|
||||
import Legacy from 'artplayer-tool-thumbnail/legacy'
|
||||
|
||||
@@ -32,8 +32,14 @@ tool.off('file').setup({ width: 100 }).download()
|
||||
tool.loadVideo(input.files?.[0])
|
||||
tool.loadVideo(null)
|
||||
const defaults: Thumbnail.SheetOptions = Thumbnail.DEFAULTS
|
||||
const publishedDefaults: DefaultOptions = Thumbnail.DEFAULTS
|
||||
const delay: number = publishedDefaults.delay
|
||||
const mode: Compatibility = 'workspace-4.4'
|
||||
tool.setup({ compatibility: mode, delay: undefined })
|
||||
legacy.setup({ compatibility: 'published-3.5', delay: 300, height: 25 })
|
||||
const sheet: Thumbnail.SheetOptions = { number: 10, width: 80, height: 25, column: 3, begin: 0, end: 20 }
|
||||
const end: void = tool.destroy()
|
||||
void [legacy, duration, file, url, pending, canvas, points, extension, defaults, end]
|
||||
void [legacy, duration, file, url, pending, canvas, points, extension, defaults, delay, sheet, end]
|
||||
|
||||
// @ts-expect-error Numeric width is required.
|
||||
tool.setup({ width: '80' })
|
||||
@@ -55,4 +61,8 @@ const earlyDensity: number = tool.density
|
||||
tool.on('error', (message: string) => message.length)
|
||||
// @ts-expect-error Built-in done does not carry a file.
|
||||
tool.emit('done', input.files?.[0])
|
||||
// @ts-expect-error Compatibility accepts only the two supported policies.
|
||||
tool.setup({ compatibility: 'latest' })
|
||||
// @ts-expect-error Published delay is a numeric option.
|
||||
tool.setup({ delay: '300' })
|
||||
void [wrongInput, wrongResult, WrongAlias, earlyDensity]
|
||||
Reference in new issue
Block a user