@vimeo/vimeo
Version:
A Node.js library for the new Vimeo API.
967 lines (757 loc) • 34.8 kB
JavaScript
/* eslint-env mocha */
'use strict'
const Vimeo = require('../../lib/vimeo').Vimeo
const requestDefaults = require('../../lib/vimeo').request_defaults
const authEndpoints = require('../../lib/vimeo').authEndpoints
const http = require('http') // Needed for mocking
const https = require('https') // Needed for mocking
const fs = require('fs') // Needed for mocking
const events = require('events')
const expect = require('chai').expect
const sinon = require('sinon')
afterEach(() => {
sinon.restore()
})
describe('Vimeo.buildAuthorizationEndpoint', () => {
const REDIRECT_URL = 'https://myapp.com/login'
const vimeo = new Vimeo('id', 'secret', 'token')
it('uses `public` scope by default', () => {
const url = vimeo.buildAuthorizationEndpoint(REDIRECT_URL)
expect(url).to.contain('scope=public')
})
it('uses a space-separated list for scopes', () => {
const url = vimeo.buildAuthorizationEndpoint(REDIRECT_URL, ['scope1', 'scope2'])
expect(url).to.contain('scope=scope1%20scope2')
})
it('uses a space-separated list for scopes', () => {
const url = vimeo.buildAuthorizationEndpoint(REDIRECT_URL, 'scope1 scope2')
expect(url).to.contain('scope=scope1%20scope2')
})
it('uses state if present', () => {
const url = vimeo.buildAuthorizationEndpoint(REDIRECT_URL, 'scope', 'state')
expect(url).to.contain('state=state')
})
it('uses request_defaults to build the URL', () => {
const url = vimeo.buildAuthorizationEndpoint(REDIRECT_URL, 'scope', 'state')
expect(url).to.contain(requestDefaults.protocol)
expect(url).to.contain(requestDefaults.hostname)
})
})
describe('Vimeo.generateClientCredentials', () => {
const vimeo = new Vimeo('id', 'secret', 'token')
describe('request is called with the expected parameters', () => {
let mockRequest
beforeEach(() => {
mockRequest = sinon.fake()
sinon.replace(vimeo, 'request', mockRequest)
})
it('with `public` scope by default', () => {
vimeo.generateClientCredentials(null, () => {})
sinon.assert.calledOnce(mockRequest)
sinon.assert.calledWith(mockRequest, sinon.match({ query: sinon.match.has('scope', 'public') }))
})
it('with a space-separated list for scopes', () => {
vimeo.generateClientCredentials(['scope1', 'scope2'], () => {})
sinon.assert.calledOnce(mockRequest)
sinon.assert.calledWith(mockRequest, sinon.match({ query: sinon.match.has('scope', 'scope1 scope2') }))
})
it('with a space-separated list for scopes', () => {
vimeo.generateClientCredentials('scope1 scope2', () => {})
sinon.assert.calledOnce(mockRequest)
sinon.assert.calledWith(mockRequest, sinon.match({ query: sinon.match.has('scope', 'scope1 scope2') }))
})
it('with all defaults', () => {
vimeo.generateClientCredentials(null, () => {})
const expectedPayload = {
method: 'POST',
hostname: requestDefaults.hostname,
path: authEndpoints.clientCredentials,
query: {
grant_type: 'client_credentials'
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
sinon.assert.calledOnce(mockRequest)
sinon.assert.calledWith(mockRequest, sinon.match(expectedPayload))
})
})
describe('request is called with the expected parameters for the promise implementation', () => {
let requestStub
beforeEach(() => {
requestStub = sinon.stub(vimeo, 'request').resolves('Success.')
})
it('with `public` scope by default', async () => {
await vimeo.generateClientCredentials()
sinon.assert.calledOnce(requestStub)
sinon.assert.calledWith(requestStub, sinon.match({ query: sinon.match.has('scope', 'public') }))
})
it('with a space-separated list for scopes', async () => {
await vimeo.generateClientCredentials(['scope1', 'scope2'])
sinon.assert.calledOnce(requestStub)
sinon.assert.calledWith(requestStub, sinon.match({ query: sinon.match.has('scope', 'scope1 scope2') }))
})
it('with a space-separated list for scopes', async () => {
await vimeo.generateClientCredentials('scope1 scope2')
sinon.assert.calledOnce(requestStub)
sinon.assert.calledWith(requestStub, sinon.match({ query: sinon.match.has('scope', 'scope1 scope2') }))
})
it('with all defaults', async () => {
await vimeo.generateClientCredentials()
const expectedPayload = {
method: 'POST',
hostname: requestDefaults.hostname,
path: authEndpoints.clientCredentials,
query: {
grant_type: 'client_credentials'
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
sinon.assert.calledOnce(requestStub)
sinon.assert.calledWith(requestStub, sinon.match(expectedPayload))
})
})
describe('callback is called with the expected parameters', () => {
it('request returns an error', () => {
const error = 'Request Error'
const body = { body: 'body' }
const status = { status: 'status' }
const headers = { headers: 'headers' }
const mockRequest = sinon.fake.yields(error, body, status, headers)
sinon.replace(vimeo, 'request', mockRequest)
const mockCallback = sinon.fake()
vimeo.generateClientCredentials('scope', mockCallback)
sinon.assert.calledOnce(mockCallback)
sinon.assert.calledWith(mockCallback, error, null, status, headers)
})
it('request is successful', () => {
const body = { body: 'body' }
const status = { status: 'status' }
const headers = { headers: 'headers' }
const mockRequest = sinon.fake.yields(null, body, status, headers)
sinon.replace(vimeo, 'request', mockRequest)
const mockCallback = sinon.fake()
vimeo.generateClientCredentials('scope', mockCallback)
sinon.assert.calledOnce(mockCallback)
sinon.assert.calledWith(mockCallback, null, body, status, headers)
})
})
describe('a Promise is returned with the expected response or error when the callback is not passed in', () => {
it('request returns an error', async () => {
const error = new Error('Request Error')
sinon.stub(vimeo, 'request').rejects(error)
await vimeo.generateClientCredentials('scope').catch(err => sinon.assert.match(err, error))
})
it('request is successful', async () => {
const body = 'body'
sinon.stub(vimeo, 'request').resolves(body)
await vimeo.generateClientCredentials('scope').then(res => sinon.assert.match(res, body))
})
})
})
describe('Vimeo.accessToken', () => {
const vimeo = new Vimeo('id', 'secret', 'token')
const CODE = 'code'
const REDIRECT_URI = 'redirectURI'
it('request is called with the expected parameters', () => {
const mockRequest = sinon.fake()
sinon.replace(vimeo, 'request', mockRequest)
vimeo.accessToken(CODE, REDIRECT_URI, () => {})
const expectedPayload = {
method: 'POST',
hostname: requestDefaults.hostname,
path: authEndpoints.accessToken,
query: {
grant_type: 'authorization_code',
code: CODE,
redirect_uri: REDIRECT_URI
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
sinon.assert.calledOnce(mockRequest)
sinon.assert.calledWith(mockRequest, sinon.match(expectedPayload))
})
describe('callback is called with the expected parameters', () => {
it('request returns an error', () => {
const error = 'Request Error'
const body = { body: 'body' }
const status = { status: 'status' }
const headers = { headers: 'headers' }
const mockRequest = sinon.fake.yields(error, body, status, headers)
sinon.replace(vimeo, 'request', mockRequest)
const mockCallback = sinon.fake()
vimeo.accessToken(CODE, REDIRECT_URI, mockCallback)
sinon.assert.calledOnce(mockCallback)
sinon.assert.calledWith(mockCallback, error, null, status, headers)
})
it('request is successful', () => {
const body = { body: 'body' }
const status = { status: 'status' }
const headers = { headers: 'headers' }
const mockRequest = sinon.fake.yields(null, body, status, headers)
sinon.replace(vimeo, 'request', mockRequest)
const mockCallback = sinon.fake()
vimeo.accessToken(CODE, REDIRECT_URI, mockCallback)
sinon.assert.calledOnce(mockCallback)
sinon.assert.calledWith(mockCallback, null, body, status, headers)
})
})
describe('request and response are expected for the Promise implementation', () => {
it('vimeo.request is called with the expected parameters', async () => {
const requestStub = sinon.stub(vimeo, 'request').resolves('Success.')
await vimeo.accessToken(CODE, REDIRECT_URI)
const expectedPayload = {
method: 'POST',
hostname: requestDefaults.hostname,
path: authEndpoints.accessToken,
query: {
grant_type: 'authorization_code',
code: CODE,
redirect_uri: REDIRECT_URI
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
sinon.assert.calledOnce(requestStub)
sinon.assert.calledWith(requestStub, sinon.match(expectedPayload))
})
it('returns expected error response when the request fails', async () => {
const err = new Error('Request Error')
sinon.stub(vimeo, 'request').rejects(err)
await vimeo.accessToken(CODE, REDIRECT_URI).catch((error) => {
sinon.assert.match(error, err)
})
})
it('returns the expected response when the request is successful', async () => {
const body = 'body'
sinon.stub(vimeo, 'request').resolves(body)
await vimeo.accessToken(CODE, REDIRECT_URI).then((res) => {
sinon.assert.match(res, body)
})
})
})
})
describe('Vimeo.setAccessToken', () => {
const vimeo = new Vimeo('id', 'secret', 'token')
it('changes the access token', () => {
vimeo.setAccessToken('token2')
expect(vimeo._accessToken).to.equal('token2')
})
})
describe('Vimeo._applyQuerystringParams', () => {
const vimeo = new Vimeo('id', 'secret', 'token')
const PATH = '/path'
const PATH_QS = '/path?a=b'
const QS = { c: 'd' }
it('returns the path if no query is passed', () => {
const newPath = vimeo._applyQuerystringParams({ path: PATH }, {})
expect(newPath).to.equal(PATH)
})
it('returns the path if no query is passed', () => {
const newPath = vimeo._applyQuerystringParams({ path: PATH_QS }, {})
expect(newPath).to.equal(PATH_QS)
})
it('adds the query string after the ?', () => {
const newPath = vimeo._applyQuerystringParams({ path: PATH }, { query: QS })
expect(newPath).to.equal(PATH + '?c=d')
})
it('appens the query string after the &', () => {
const newPath = vimeo._applyQuerystringParams({ path: PATH_QS }, { query: QS })
expect(newPath).to.equal(PATH_QS + '&c=d')
})
})
describe('Vimeo.request', () => {
const vimeo = new Vimeo('id', 'secret', 'token')
let mockHttpRequest, mockHttpsRequest, mockReq, handleRequestStub
beforeEach(() => {
mockReq = new events.EventEmitter()
mockReq.on = sinon.fake(mockReq.on)
mockReq.end = sinon.fake()
mockReq.write = sinon.fake()
mockHttpRequest = sinon.fake.returns(mockReq)
sinon.replace(http, 'request', mockHttpRequest)
mockHttpsRequest = sinon.fake.returns(mockReq)
sinon.replace(https, 'request', mockHttpsRequest)
})
describe('callback function is used when passed in', () => {
it('calls callback with an error if options has no path', () => {
const mockCallback = sinon.fake()
vimeo.request({}, mockCallback)
sinon.assert.calledOnce(mockCallback)
sinon.assert.calledWith(mockCallback, sinon.match.instanceOf(Error))
})
it('parses options if passed as a string', () => {
vimeo.request('https://example.com:1234/path', () => { })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ method: 'GET', path: '/path', host: 'example.com', port: '1234' }))
})
it('adds a leading slash if missing', () => {
vimeo.request({ path: 'path' }, () => { })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ path: '/path' }))
})
it('uses https client when requested', () => {
vimeo.request({ protocol: 'https:', path: '/path' }, () => { })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.notCalled(mockHttpRequest)
})
it('uses http client by default', () => {
vimeo.request({ protocol: 'proto:', path: '/path' }, () => { })
sinon.assert.calledOnce(mockHttpRequest)
sinon.assert.notCalled(mockHttpsRequest)
})
it('sends body as JSON if content type is application/json', () => {
vimeo.request({ method: 'POST', path: '/path', query: { a: 'b' }, headers: { 'Content-Type': 'application/json' } }, () => { })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ body: '{"a":"b"}' }))
})
it('sends form data as string if content type is application/x-www-form-urlencoded', () => {
vimeo.request({ method: 'POST', path: '/path', query: { a: 'b', c: 'd' }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }, () => { })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ body: 'a=b&c=d' }))
})
it('sends body as it is if content type is not application/x-www-form-urlencoded nor application/json', () => {
vimeo.request({ method: 'POST', path: '/path', body: 'text', headers: { 'Content-Type': 'text/plain' } }, () => { })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ body: 'text' }))
})
it('sets the correct body Content-Length', () => {
vimeo.request({ method: 'POST', path: '/path', query: { a: 'b' }, headers: { 'Content-Type': 'application/json' } }, () => { })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ headers: sinon.match.has('Content-Length', 9) }))
})
it('sets the correct body Content-Length', () => {
vimeo.request({ method: 'POST', path: '/path' }, () => { })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ headers: sinon.match.has('Content-Length', 0) }))
})
it('calls req.write with the body', () => {
vimeo.request({ method: 'POST', path: '/path', query: { a: 'b' } }, () => { })
sinon.assert.calledOnce(mockReq.write)
sinon.assert.calledWith(mockReq.write, '{"a":"b"}')
})
it('doesn\'t call req.write if there is no body', () => {
vimeo.request({ method: 'POST', path: '/path' }, () => { })
sinon.assert.notCalled(mockReq.write)
})
it('sets on error listener', () => {
const mockCallback = sinon.fake()
vimeo.request({ path: '/path' }, mockCallback)
sinon.assert.calledOnce(mockReq.on)
sinon.assert.calledWith(mockReq.on, 'error', sinon.match.func)
mockReq.emit('error', 'Error Emitted')
sinon.assert.calledOnce(mockCallback)
sinon.assert.calledWith(mockCallback, 'Error Emitted')
})
it('calls req.end()', () => {
vimeo.request({ path: '/path' }, () => { })
sinon.assert.calledOnce(mockReq.end)
})
})
describe('a Promise is returned when the callback function is not passed in', () => {
beforeEach(() => {
handleRequestStub = sinon.stub(vimeo, '_handleRequest').callsFake((resolve) => { resolve('Success.') })
})
it('returns an error if options has no path', async () => {
const error = sinon.match.instanceOf(Error).and(sinon.match.has('message', 'You must provide an API path.'))
await vimeo.request({}).catch((e) => sinon.assert.match(e, error))
})
it('parses options if passed as a string', async () => {
await vimeo.request('https://example.com:1234/path')
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ method: 'GET', path: '/path', host: 'example.com', port: '1234' }))
sinon.assert.calledOnce(handleRequestStub)
})
it('adds a leading slash if missing', async () => {
await vimeo.request({ path: 'path' })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ path: '/path' }))
})
it('uses https client when requested', async () => {
await vimeo.request({ protocol: 'https:', path: '/path' })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.notCalled(mockHttpRequest)
})
it('uses http client by default', async () => {
await vimeo.request({ protocol: 'proto:', path: '/path' })
sinon.assert.calledOnce(mockHttpRequest)
sinon.assert.notCalled(mockHttpsRequest)
})
it('sends body as JSON if content type is application/json', async () => {
await vimeo.request({ method: 'POST', path: '/path', query: { a: 'b' }, headers: { 'Content-Type': 'application/json' } })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ body: '{"a":"b"}' }))
})
it('sends form data as string if content type is application/x-www-form-urlencoded', async () => {
await vimeo.request({ method: 'POST', path: '/path', query: { a: 'b', c: 'd' }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ body: 'a=b&c=d' }))
})
it('sends body as it is if content type is not application/x-www-form-urlencoded nor application/json', async () => {
await vimeo.request({ method: 'POST', path: '/path', body: 'text', headers: { 'Content-Type': 'text/plain' } })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ body: 'text' }))
})
it('sets the correct body Content-Length', async () => {
await vimeo.request({ method: 'POST', path: '/path', query: { a: 'b' }, headers: { 'Content-Type': 'application/json' } })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ headers: sinon.match.has('Content-Length', 9) }))
})
it('sets the correct body Content-Length', async () => {
await vimeo.request({ method: 'POST', path: '/path' })
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ headers: sinon.match.has('Content-Length', 0) }))
})
it('calls req.write with the body', async () => {
await vimeo.request({ method: 'POST', path: '/path', query: { a: 'b' } })
sinon.assert.calledOnce(mockReq.write)
sinon.assert.calledWith(mockReq.write, '{"a":"b"}')
})
it('doesn\'t call req.write if there is no body', async () => {
await vimeo.request({ method: 'POST', path: '/path' })
sinon.assert.notCalled(mockReq.write)
})
it('calls req.end()', async () => {
await vimeo.request({ path: '/path' })
sinon.assert.calledOnce(mockReq.end)
})
it('returns the correct response when the Promise is fullfilled', async () => {
const req = await vimeo.request({ method: 'POST', path: '/path' })
expect(req).to.equal('Success.')
})
it('returns the error object when the Promise is rejected', async () => {
handleRequestStub.resetBehavior()
const err = new Error('Request Error')
handleRequestStub.callsFake((resolve, reject) => {
reject(err)
})
await vimeo.request({ method: 'POST', path: '/path' }).catch((e) => {
expect(e).to.equal(err)
})
})
it('sets on error listener', async () => {
handleRequestStub.resetBehavior()
const req = vimeo.request({ path: '/path' }).catch((error) => {
sinon.assert.match(error, sinon.match.instanceOf(Error).and(sinon.match.has('message', 'Error Emitted')))
})
mockReq.emit('error', new Error('Error Emitted'))
sinon.assert.calledOnce(mockReq.on)
sinon.assert.calledWith(mockReq.on, 'error', sinon.match.func)
return req
})
it('throws an error when the Promise rejects', async () => {
handleRequestStub.resetBehavior()
handleRequestStub.callsFake((resolve, reject) => { reject(new Error('Failure.')) })
const error = sinon.match.instanceOf(Error).and(sinon.match.has('message', 'Failure.'))
await vimeo.request('https://example.com:1234/path').catch((e) => {
sinon.assert.match(e, error)
})
sinon.assert.calledOnce(mockHttpsRequest)
sinon.assert.calledWith(mockHttpsRequest, sinon.match({ method: 'GET', path: '/path', host: 'example.com', port: '1234' }))
sinon.assert.calledOnce(handleRequestStub)
})
})
})
describe('Vimeo._handleRequest', () => {
const vimeo = new Vimeo('id', 'secret', 'token')
let mockRes
beforeEach(() => {
mockRes = new events.EventEmitter()
mockRes.on = sinon.fake(mockRes.on)
mockRes.setEncoding = sinon.fake()
mockRes.headers = { headers: 'value' }
})
it('sets the encoding to utf8', () => {
const handler = vimeo._handleRequest(() => { })
handler(mockRes)
sinon.assert.calledOnce(mockRes.setEncoding)
sinon.assert.calledWith(mockRes.setEncoding, 'utf8')
})
it('calls callback with an error if status code >= 400', () => {
const mockCallback = sinon.fake()
const handler = vimeo._handleRequest(mockCallback)
mockRes.statusCode = 404
handler(mockRes)
mockRes.emit('end')
sinon.assert.calledOnce(mockCallback)
sinon.assert.calledWith(mockCallback, sinon.match.instanceOf(Error), '', mockRes.statusCode, mockRes.headers)
})
it('calls callback no error if status code < 400', () => {
const mockCallback = sinon.fake()
const handler = vimeo._handleRequest(mockCallback)
mockRes.statusCode = 200
handler(mockRes)
mockRes.emit('end')
sinon.assert.calledOnce(mockCallback)
sinon.assert.calledWith(mockCallback, null, {}, mockRes.statusCode, mockRes.headers)
})
it('calls callback with an error if the body is not valid JSON', () => {
const mockCallback = sinon.fake()
const handler = vimeo._handleRequest(mockCallback)
mockRes.read = sinon.fake.returns('{"bad": "json"')
mockRes.statusCode = 200
handler(mockRes)
mockRes.emit('readable')
mockRes.emit('end')
sinon.assert.calledOnce(mockCallback)
sinon.assert.calledWith(mockCallback, sinon.match.instanceOf(Error).and(sinon.match.has('message', 'Unexpected end of JSON input')))
})
it('calls callback the body parsed as JSON', () => {
const mockCallback = sinon.fake()
const handler = vimeo._handleRequest(mockCallback)
mockRes.read = sinon.fake.returns('{"good": "json"}')
mockRes.statusCode = 200
handler(mockRes)
mockRes.emit('readable')
mockRes.emit('end')
sinon.assert.calledOnce(mockCallback)
sinon.assert.calledWith(mockCallback, null, { good: 'json' }, mockRes.statusCode, mockRes.headers)
})
describe('when there is a second fn passed in, calls the second fn on error', () => {
let mockResolve, mockReject, handler
beforeEach(() => {
mockResolve = sinon.fake()
mockReject = sinon.fake()
handler = vimeo._handleRequest(mockResolve, mockReject)
})
it('sets the encoding to utf8', () => {
const handler = vimeo._handleRequest(() => { }, () => { })
handler(mockRes)
sinon.assert.calledOnce(mockRes.setEncoding)
sinon.assert.calledWith(mockRes.setEncoding, 'utf8')
})
it('calls the second fn with an error if status code >= 400', () => {
mockRes.statusCode = 404
handler(mockRes)
mockRes.emit('end')
sinon.assert.calledOnce(mockReject)
sinon.assert.calledWith(mockReject, sinon.match.instanceOf(Error))
})
it('calls the first fn with no error if status code < 400', () => {
mockRes.statusCode = 200
handler(mockRes)
mockRes.emit('end')
sinon.assert.calledOnce(mockResolve)
sinon.assert.calledWith(mockResolve, { body: {}, headers: mockRes.headers, statusCode: mockRes.statusCode })
})
it('calls the second fn with an error if the body is not valid JSON', () => {
mockRes.read = sinon.fake.returns('{"bad": "json"')
mockRes.statusCode = 200
handler(mockRes)
mockRes.emit('readable')
mockRes.emit('end')
sinon.assert.calledOnce(mockReject)
sinon.assert.calledWith(mockReject,
sinon.match.instanceOf(Error).and(sinon.match.has('message', 'Unexpected end of JSON input')),
'{"bad": "json"',
mockRes.statusCode,
mockRes.headers)
})
it('calls the first fn if the body parsed as JSON', () => {
mockRes.read = sinon.fake.returns('{"good": "json"}')
mockRes.statusCode = 200
handler(mockRes)
mockRes.emit('readable')
mockRes.emit('end')
sinon.assert.calledOnce(mockResolve)
sinon.assert.calledWith(mockResolve, { body: { good: 'json' }, headers: mockRes.headers, statusCode: mockRes.statusCode })
})
})
})
describe('Vimeo.upload', () => {
const FILE_NAME = '/real/file'
const FILE_SIZE = 24601
const vimeo = new Vimeo('id', 'secret', 'token')
let mockCompleteCallback
let mockProgressCallback
let mockErrorCallback
beforeEach(() => {
mockCompleteCallback = sinon.fake()
mockProgressCallback = sinon.fake()
mockErrorCallback = sinon.fake()
})
it('calls the errorCallback if the file is inexistant', () => {
const errFs = sinon.fake.throws('File Error')
sinon.replace(fs, 'statSync', errFs)
const vimeo = new Vimeo('id', 'secret', 'token')
vimeo.upload(FILE_NAME, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockErrorCallback)
sinon.assert.calledWith(mockErrorCallback, 'Unable to locate file to upload.')
})
it('calls the errorCallback if the file parameter is an object', () => {
const fileObject = {
size: FILE_SIZE
}
vimeo.upload(fileObject, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockErrorCallback)
sinon.assert.calledWith(mockErrorCallback, sinon.match.instanceOf(Error).and(sinon.match.has('message', 'Please pass in a valid file path.')))
})
describe('file exists', () => {
beforeEach(() => {
const mockFs = sinon.fake.returns({ size: FILE_SIZE })
sinon.replace(fs, 'statSync', mockFs)
})
describe('always uses `tus` to upload', () => {
let mockRequest
beforeEach(() => {
mockRequest = sinon.fake()
sinon.replace(vimeo, 'request', mockRequest)
})
it('if upload.approach is not specified', () => {
vimeo.upload(FILE_NAME, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockRequest)
const expectedPayload = {
query: { upload: { approach: 'tus' } }
}
sinon.assert.calledWith(mockRequest, sinon.match(expectedPayload))
})
it('if upload.approach is not tus', () => {
vimeo.upload(FILE_NAME, { upload: { approach: 'not-tus' } }, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockRequest)
const expectedPayload = {
query: { upload: { approach: 'tus' } }
}
sinon.assert.calledWith(mockRequest, sinon.match(expectedPayload))
})
})
it('request is called with the expected parameters', () => {
const mockRequest = sinon.fake()
sinon.replace(vimeo, 'request', mockRequest)
vimeo.upload(FILE_NAME, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockRequest)
const expectedPayload = {
method: 'POST',
path: '/me/videos?fields=uri,name,upload',
query: { upload: { approach: 'tus', size: FILE_SIZE } }
}
sinon.assert.calledWith(mockRequest, expectedPayload)
})
it('calls the errorCallback if request returned an error', () => {
const mockRequest = sinon.fake.yields('Request Error')
sinon.replace(vimeo, 'request', mockRequest)
vimeo.upload(FILE_NAME, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockErrorCallback)
sinon.assert.calledWith(mockErrorCallback, sinon.match('Request Error'))
})
it('calls _performTusUpload with the expected parameters', () => {
const mockRequest = sinon.fake.yields(null, {})
sinon.replace(vimeo, 'request', mockRequest)
const mockTusUpload = sinon.fake()
sinon.replace(vimeo, '_performTusUpload', mockTusUpload)
vimeo.upload(FILE_NAME, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockTusUpload)
sinon.assert.calledWith(mockTusUpload, FILE_NAME, FILE_SIZE, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
})
it('shifts callbacks if param is not passed to the function', () => {
const mockRequest = sinon.fake.yields(null, {})
sinon.replace(vimeo, 'request', mockRequest)
const mockTusUpload = sinon.fake()
sinon.replace(vimeo, '_performTusUpload', mockTusUpload)
vimeo.upload(FILE_NAME, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockTusUpload)
sinon.assert.calledWith(mockTusUpload, FILE_NAME, FILE_SIZE, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
})
})
})
describe('Vimeo.replace', () => {
const FILE_NAME = '/real/file/name'
const FILE_SIZE = 24601
const VIDEO_URI = '/videos/123456789'
const vimeo = new Vimeo('id', 'secret', 'token')
let mockCompleteCallback
let mockProgressCallback
let mockErrorCallback
beforeEach(() => {
mockCompleteCallback = sinon.fake()
mockProgressCallback = sinon.fake()
mockErrorCallback = sinon.fake()
})
it('calls the errorCallback if the file is inexistant', () => {
const errFs = sinon.fake.throws('File Error')
sinon.replace(fs, 'statSync', errFs)
const vimeo = new Vimeo('id', 'secret', 'token')
vimeo.replace(FILE_NAME, VIDEO_URI, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockErrorCallback)
sinon.assert.calledWith(mockErrorCallback, 'Unable to locate file to upload.')
})
it('calls the errorCallback if the file parameter is an object', () => {
const fileObject = {
size: FILE_SIZE
}
vimeo.replace(fileObject, VIDEO_URI, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockErrorCallback)
sinon.assert.calledWith(mockErrorCallback, sinon.match.instanceOf(Error).and(sinon.match.has('message', 'Please pass in a valid file path.')))
})
describe('file exists', () => {
beforeEach(() => {
const mockFs = sinon.fake.returns({ size: FILE_SIZE })
sinon.replace(fs, 'statSync', mockFs)
})
describe('always uses `tus` to upload', () => {
let mockRequest
beforeEach(() => {
mockRequest = sinon.fake()
sinon.replace(vimeo, 'request', mockRequest)
})
it('if upload.approach is not specified', () => {
vimeo.replace(FILE_NAME, VIDEO_URI, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockRequest)
const expectedPayload = {
query: { upload: { approach: 'tus' } }
}
sinon.assert.calledWith(mockRequest, sinon.match(expectedPayload))
})
it('if upload.approach is not tus', () => {
vimeo.replace(FILE_NAME, VIDEO_URI, { upload: { approach: 'not-tus' } }, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockRequest)
const expectedPayload = {
query: { upload: { approach: 'tus' } }
}
sinon.assert.calledWith(mockRequest, sinon.match(expectedPayload))
})
})
it('request is called with the expected parameters', () => {
const mockRequest = sinon.fake()
sinon.replace(vimeo, 'request', mockRequest)
vimeo.replace(FILE_NAME, VIDEO_URI, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockRequest)
const expectedPayload = {
method: 'POST',
path: VIDEO_URI + '/versions?fields=upload',
query: { file_name: 'name', upload: { approach: 'tus', size: FILE_SIZE } }
}
sinon.assert.calledWith(mockRequest, expectedPayload)
})
it('calls the errorCallback if request returned an error', () => {
const mockRequest = sinon.fake.yields('Request Error')
sinon.replace(vimeo, 'request', mockRequest)
vimeo.replace(FILE_NAME, VIDEO_URI, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockErrorCallback)
sinon.assert.calledWith(mockErrorCallback, sinon.match('Request Error'))
})
it('calls _performTusUpload with the expected parameters', () => {
const mockRequest = sinon.fake.yields(null, {})
sinon.replace(vimeo, 'request', mockRequest)
const mockTusUpload = sinon.fake()
sinon.replace(vimeo, '_performTusUpload', mockTusUpload)
vimeo.replace(FILE_NAME, VIDEO_URI, {}, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockTusUpload)
sinon.assert.calledWith(mockTusUpload, FILE_NAME, FILE_SIZE, { uri: VIDEO_URI }, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
})
it('shifts callbacks if param is not passed to the function', () => {
const mockRequest = sinon.fake.yields(null, {})
sinon.replace(vimeo, 'request', mockRequest)
const mockTusUpload = sinon.fake()
sinon.replace(vimeo, '_performTusUpload', mockTusUpload)
vimeo.replace(FILE_NAME, VIDEO_URI, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
sinon.assert.calledOnce(mockTusUpload)
sinon.assert.calledWith(mockTusUpload, FILE_NAME, FILE_SIZE, { uri: VIDEO_URI }, mockCompleteCallback, mockProgressCallback, mockErrorCallback)
})
})
})