Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,10 @@ async function send(control, action = '', method = 'GET', body = null, enctype =
if (method === 'GET') {
action.search = formDataToParams(body).toString()
body = null
} else if (enctype !== 'multipart/form-data') {
} else if (enctype !== 'multipart/form-data' && (body instanceof FormData)) {
body = formDataToParams(body)
} else {
enctype = null
}
}

Expand All @@ -331,6 +333,8 @@ async function send(control, action = '', method = 'GET', body = null, enctype =
}, settings.headers, control.headers),
}

if (!request.enctype) { delete request.enctype } // Let browser set the correct multipart boundary

dispatch(control.el, 'ajax:send', request)

let pending
Expand Down Expand Up @@ -465,6 +469,13 @@ async function send(control, action = '', method = 'GET', body = null, enctype =
function parseFormData(data) {
if (data instanceof FormData) return data
if (data instanceof HTMLFormElement) return new FormData(data)
if (typeof data === 'string') return data
if (data instanceof ArrayBuffer) return data
if (data instanceof DataView) return data
if (data instanceof Blob) return data
if (data instanceof File) return data
if (data instanceof URLSearchParams) return data
if (data instanceof ReadableStream) return data

const formData = new FormData()
for (let key in data) {
Expand Down
62 changes: 62 additions & 0 deletions tests/ajax.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,65 @@ test('follows redirects by default',
})
}
)

test('can upload files with $ajax method',
html`<button type="button" id="replace" x-init @click="
const file = new File(['test content'], 'test.txt', { type: 'text/plain' });
$ajax('/tests', {
method: 'POST',
body: file
})
"></button>`,
({ intercept, get, wait }) => {
intercept('POST', '/tests', {
statusCode: 200,
body: '<h1 id="title">Success</h1><div id="replace">File uploaded</div>'
}).as('response')
get('button').click()
wait('@response').then((interception) => {
// Verify the request body is a File
expect(interception.request.body).to.be.equal('test content')
})
})

test('can upload string with $ajax method',
html`<button type="button" id="replace" x-init @click="
const text = 'test content';
$ajax('/tests', {
method: 'POST',
body: text
})
"></button>`,
({ intercept, get, wait }) => {
intercept('POST', '/tests', {
statusCode: 200,
body: '<h1 id="title">Success</h1><div id="replace">File uploaded</div>'
}).as('response')
get('button').click()
wait('@response').then((interception) => {
// Verify the request body is a File
expect(interception.request.body).to.be.equal('test content')
})
})

test('can transform object to FormData with $ajax method',
html`<button type="button" id="replace" x-init @click="
const obj = { key: 'value', arr: [1,2], nested: { a: 'b' } };
$ajax('/tests', {
method: 'POST',
body: obj
})
"></button>`,
({ intercept, get, wait }) => {
intercept('POST', '/tests', {
statusCode: 200,
body: '<h1 id="title">Success</h1><div id="replace">File uploaded</div>'
}).as('response')
get('button').click()
wait('@response').then((interception) => {
// Verify the request body is a FormData with the correct entries
expect(interception.request.body).to.include('key=value')
expect(interception.request.body).to.include('arr='+encodeURIComponent(JSON.stringify([1,2]))) // arr=[1,2]
expect(interception.request.body).to.include('nested='+encodeURIComponent(JSON.stringify({ a: 'b' }))) // nested={"a":"b"}
})
})