76 lines
3.2 KiB
JavaScript
76 lines
3.2 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { readFile } from 'node:fs/promises'
|
|
|
|
// The live client uses Axios. This isolated test checks its request construction
|
|
// without needing a browser or an installed dependency tree.
|
|
const clientSource = await readFile(new URL('../src/api/client.js', import.meta.url), 'utf8')
|
|
const calls = []
|
|
const clients = []
|
|
|
|
globalThis.window ??= { location: { hostname: 'localhost' } }
|
|
globalThis.__goodDriveTestAxios = {
|
|
create(defaults) {
|
|
const instance = {
|
|
defaults,
|
|
interceptors: { request: { use() {} }, response: { use() {} } },
|
|
async post(url, body, config) {
|
|
calls.push({ url, body, config, defaults })
|
|
if (url.endsWith('/uploads/start/')) return { data: { id: 'test-upload-id', offset: 0 } }
|
|
if (url.endsWith('/chunk/')) {
|
|
return { data: { offset: Number(body.get('offset')) + body.get('part').size } }
|
|
}
|
|
return { data: { items: [] } }
|
|
},
|
|
}
|
|
clients.push(instance)
|
|
return instance
|
|
},
|
|
}
|
|
|
|
assert.match(clientSource, /import axios from ['"]axios['"]/, 'Unexpected Axios import')
|
|
const sourceWithMock = clientSource.replace(/import axios from ['"]axios['"]/, 'const axios = globalThis.__goodDriveTestAxios')
|
|
const { drive } = await import(`data:text/javascript;base64,${Buffer.from(sourceWithMock).toString('base64')}`)
|
|
|
|
function assertMultipartRequest(call) {
|
|
assert.ok(call.body instanceof FormData, `${call.url} must send FormData`)
|
|
assert.ok(
|
|
!Object.keys(call.defaults.headers ?? {}).some(key => key.toLowerCase() === 'content-type'),
|
|
'Do not force application/json globally; let Axios/browser set multipart boundary',
|
|
)
|
|
assert.ok(
|
|
!Object.keys(call.config?.headers ?? {}).some(key => key.toLowerCase() === 'content-type' && call.config.headers[key] === 'application/json'),
|
|
'Do not override multipart with application/json on this request',
|
|
)
|
|
}
|
|
|
|
test('small-file upload sends FormData, with no global JSON content type', async () => {
|
|
calls.length = 0
|
|
const file = new File(['abc'], 'demo.txt', { type: 'text/plain' })
|
|
await drive.upload([file], 12, 7)
|
|
const upload = calls.find(call => call.url === '/drive/uploads/')
|
|
assert.ok(upload)
|
|
assertMultipartRequest(upload)
|
|
assert.equal(upload.body.get('files').name, 'demo.txt')
|
|
assert.equal(upload.body.get('parent'), '12')
|
|
assert.equal(upload.body.get('space'), '7')
|
|
})
|
|
|
|
test('resumable upload sends JSON metadata and multipart binary chunks', async () => {
|
|
calls.length = 0
|
|
const file = new File([new Uint8Array(8 * 1024 * 1024 + 3)], 'video.bin')
|
|
await drive.uploadResumable(file, null, 7)
|
|
const start = calls.find(call => call.url === '/drive/uploads/start/')
|
|
const parts = calls.filter(call => call.url.endsWith('/chunk/'))
|
|
const finish = calls.find(call => call.url.endsWith('/finish/'))
|
|
assert.ok(start)
|
|
assert.equal(start.body.name, 'video.bin')
|
|
assert.equal(start.body.size, file.size)
|
|
assert.ok(!(start.body instanceof FormData))
|
|
assert.equal(parts.length, 2)
|
|
for (const part of parts) assertMultipartRequest(part)
|
|
assert.equal(parts[0].body.get('part').size, 8 * 1024 * 1024)
|
|
assert.equal(parts[1].body.get('part').size, 3)
|
|
assert.ok(finish)
|
|
})
|