You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
thumbsup/test/steps/actions.spec.js

219 lines
6.3 KiB
JavaScript

const fs = require('node:fs')
const downsize = require('thumbsup-downsize')
const should = require('should/as-function')
const sinon = require('sinon')
const actions = require('../../src/steps/actions')
const ANY_TASK = {
src: 'input/IMG_0001.jpg',
dest: 'output/media/IMG_0001.jpg'
}
describe('actions', () => {
beforeEach(() => {
sinon.stub(fs, 'copyFile').yields(null)
sinon.stub(fs, 'symlink').yields(null)
sinon.stub(downsize, 'image').yields(null)
sinon.stub(downsize, 'video').yields(null)
sinon.stub(downsize, 'still').yields(null)
})
afterEach(() => {
fs.copyFile.restore()
fs.symlink.restore()
downsize.image.restore()
downsize.video.restore()
downsize.still.restore()
})
it('fs:copy = copies the original', testEnd => {
const map = actions.createMap({})
const action = map['fs:copy']
action(ANY_TASK, err => {
should(err).eql(null)
sinon.assert.calledWith(fs.copyFile,
ANY_TASK.src,
ANY_TASK.dest,
sinon.match.func
)
testEnd()
})
})
it('fs:symlink = creates a symbolic link', testEnd => {
const map = actions.createMap({})
const action = map['fs:symlink']
action(ANY_TASK, err => {
should(err).eql(null)
sinon.assert.calledWith(fs.symlink,
ANY_TASK.src,
ANY_TASK.dest,
sinon.match.func
)
testEnd()
})
})
it('fs:link = does nothing', testEnd => {
const map = actions.createMap({})
const action = map['fs:link']
should(action).undefined()
testEnd()
})
it('photo:thumbnail = creates a square thumbnail', testEnd => {
const map = actions.createMap({ thumbSize: 200 })
const action = map['photo:thumbnail']
action(ANY_TASK, err => {
should(err).eql(null)
const downsizeArgs = shouldCallDownsize(downsize.image)
should(downsizeArgs).property('height', 200)
should(downsizeArgs).property('width', 200)
should(downsizeArgs.animated).undefined() // don't animate GIF thumbnails
testEnd()
})
})
it('photo:small = creates a small image', testEnd => {
const map = actions.createMap({ smallSize: 300 })
const action = map['photo:small']
action(ANY_TASK, err => {
should(err).eql(null)
const downsizeArgs = shouldCallDownsize(downsize.image)
should(downsizeArgs).property('height', 300)
testEnd()
})
})
it('photo:large = creates a large image', testEnd => {
const map = actions.createMap({ largeSize: 1000 })
const action = map['photo:large']
action(ANY_TASK, err => {
should(err).eql(null)
const downsizeArgs = shouldCallDownsize(downsize.image)
should(downsizeArgs).property('height', 1000)
should(downsizeArgs).property('animated', true)
testEnd()
})
})
it('video:thumbnail = creates a square video still', testEnd => {
const map = actions.createMap({ thumbSize: 200 })
const action = map['video:thumbnail']
action(ANY_TASK, err => {
should(err).eql(null)
const downsizeArgs = shouldCallDownsize(downsize.still)
should(downsizeArgs).property('height', 200)
should(downsizeArgs).property('width', 200)
testEnd()
})
})
it('video:poster = creates a large video still', testEnd => {
const map = actions.createMap({ largeSize: 1000 })
const action = map['video:poster']
action(ANY_TASK, err => {
should(err).eql(null)
const downsizeArgs = shouldCallDownsize(downsize.still)
should(downsizeArgs).property('height', 1000)
testEnd()
})
})
it('video:poster can seek to a given number of seconds', testEnd => {
const map = actions.createMap({ videoStills: 'seek', videoStillsSeek: 5 })
const action = map['video:poster']
action(ANY_TASK, err => {
should(err).eql(null)
const downsizeArgs = shouldCallDownsize(downsize.still)
should(downsizeArgs).property('seek', 5)
testEnd()
})
})
it('video:poster can seek to the middle', testEnd => {
const map = actions.createMap({ videoStills: 'middle' })
const action = map['video:poster']
action(ANY_TASK, err => {
should(err).eql(null)
const downsizeArgs = shouldCallDownsize(downsize.still)
should(downsizeArgs).property('seek', -1)
testEnd()
})
})
it('video:resized = creates a web-friendly video', testEnd => {
const map = actions.createMap({})
const action = map['video:resized']
action(ANY_TASK, err => {
should(err).eql(null)
const downsizeArgs = shouldCallDownsize(downsize.video)
should(downsizeArgs).eql({
format: undefined,
quality: undefined,
bitrate: undefined,
hwaccel: undefined
})
testEnd()
})
})
it('can specify options for video:resized', testEnd => {
const map = actions.createMap({
// note: some options are mutually exclusive
// but this is OK for testing the mapping
videoFormat: 'mp4',
videoQuality: 75,
videoBitrate: '1200k',
videoHwaccel: 'vaapi'
})
const action = map['video:resized']
action(ANY_TASK, err => {
should(err).eql(null)
const downsizeArgs = shouldCallDownsize(downsize.video)
should(downsizeArgs).eql({
format: 'mp4',
quality: 75,
bitrate: '1200k',
hwaccel: 'vaapi'
})
testEnd()
})
})
describe('watermark', () => {
it('can add a watermark to large images', testEnd => {
const map = actions.createMap({ watermark: 'copyright.jpg' })
const action = map['photo:large']
action(ANY_TASK, err => {
should(err).eql(null)
const downsizeArgs = shouldCallDownsize(downsize.image)
should(downsizeArgs).propertyByPath('watermark', 'file').eql('copyright.jpg')
testEnd()
})
})
it('ignores the watermark for thumbnails', testEnd => {
// it's not supported by <downsize> anyway
const map = actions.createMap({ watermark: 'copyright.jpg' })
const action = map['photo:thumbnail']
action(ANY_TASK, err => {
should(err).eql(null)
const downsizeArgs = shouldCallDownsize(downsize.image)
should(downsizeArgs.watermark).undefined()
testEnd()
})
})
})
})
function shouldCallDownsize (fn) {
sinon.assert.calledWith(fn,
ANY_TASK.src,
ANY_TASK.dest,
sinon.match.object,
sinon.match.func
)
return fn.args[0][2]
}