Skip to content

Commit a344ad4

Browse files
authored
fix(upload): apply accept filter more leniently (#1064)
1 parent bf8111c commit a344ad4

File tree

2 files changed

+72
-20
lines changed

2 files changed

+72
-20
lines changed

src/utility/upload.ts

+16-8
Original file line numberDiff line numberDiff line change
@@ -54,20 +54,28 @@ export async function upload(
5454
input.removeEventListener('fileDialog', fileDialog)
5555
}
5656

57+
// When matching files, browsers ignore case and consider jpeg/jpg interchangeable.
58+
function normalize(nameOrType: string) {
59+
return nameOrType.toLowerCase().replace(/(\.|\/)jpg\b/g, '$1jpeg')
60+
}
61+
5762
function isAcceptableFile(file: File, accept: string) {
5863
if (!accept) {
5964
return true
6065
}
6166

6267
const wildcards = ['audio/*', 'image/*', 'video/*']
6368

64-
return accept.split(',').some(acceptToken => {
65-
if (acceptToken.startsWith('.')) {
69+
return normalize(accept)
70+
.trim()
71+
.split(/\s*,\s*/)
72+
.some(acceptToken => {
6673
// tokens starting with a dot represent a file extension
67-
return file.name.endsWith(acceptToken)
68-
} else if (wildcards.includes(acceptToken)) {
69-
return file.type.startsWith(acceptToken.substr(0, acceptToken.length - 1))
70-
}
71-
return file.type === acceptToken
72-
})
74+
if (acceptToken.startsWith('.')) {
75+
return normalize(file.name).endsWith(acceptToken)
76+
} else if (wildcards.includes(acceptToken)) {
77+
return normalize(file.type).startsWith(acceptToken.replace('*', ''))
78+
}
79+
return normalize(file.type) === acceptToken
80+
})
7381
}

tests/utility/upload.ts

+56-12
Original file line numberDiff line numberDiff line change
@@ -154,19 +154,62 @@ test('do nothing when element is disabled', async () => {
154154
})
155155

156156
test.each([
157-
[true, 'video/*,audio/*', 2],
158-
[true, '.png', 1],
159-
[true, 'text/csv', 1],
160-
[true, '', 4],
161-
[false, 'video/*', 4],
157+
[true, 'video/*,audio/*', ['audio.mp3', 'mp3.jpg', 'video.mp4']],
158+
[
159+
true,
160+
'image/png, image/gif, image/jpeg',
161+
['image.png', 'image2.PNG', 'image.jpeg', 'image.jpg'],
162+
],
163+
[
164+
true,
165+
`image/jpeg,
166+
image/png, image/gif`,
167+
['image.png', 'image2.PNG', 'image.jpeg', 'image.jpg'],
168+
],
169+
[true, 'image/JPG', ['image.jpeg', 'image.jpg']],
170+
[true, '.JPEG', ['image.jpeg', 'image.jpg', 'mp3.jpg']],
171+
[true, '.png', ['image.png', 'image2.PNG']],
172+
[true, 'text/csv', ['file.csv']],
173+
[
174+
true,
175+
'',
176+
[
177+
'image.png',
178+
'image2.PNG',
179+
'image.jpeg',
180+
'image.jpg',
181+
'audio.mp3',
182+
'mp3.jpg',
183+
'file.csv',
184+
'video.mp4',
185+
],
186+
],
187+
[
188+
false,
189+
'video/*',
190+
[
191+
'image.png',
192+
'image2.PNG',
193+
'image.jpeg',
194+
'image.jpg',
195+
'audio.mp3',
196+
'mp3.jpg',
197+
'file.csv',
198+
'video.mp4',
199+
],
200+
],
162201
])(
163202
'filter according to accept attribute applyAccept=%s, acceptAttribute=%s',
164-
async (applyAccept, acceptAttribute, expectedLength) => {
203+
async (applyAccept, acceptAttribute, expectedFileNames) => {
165204
const files = [
166-
new File(['hello'], 'hello.png', {type: 'image/png'}),
167-
new File(['there'], 'there.jpg', {type: 'audio/mp3'}),
168-
new File(['there'], 'there.csv', {type: 'text/csv'}),
169-
new File(['there'], 'there.jpg', {type: 'video/mp4'}),
205+
new File(['hello'], 'image.png', {type: 'image/png'}),
206+
new File(['hello'], 'image2.PNG', {type: 'image/png'}),
207+
new File(['hello'], 'image.jpeg', {type: 'image/jpeg'}),
208+
new File(['hello'], 'image.jpg', {type: 'image/jpeg'}),
209+
new File(['hello'], 'audio.mp3', {type: 'audio/mp3'}),
210+
new File(['hello'], 'mp3.jpg', {type: 'audio/mp3'}),
211+
new File(['hello'], 'file.csv', {type: 'text/csv'}),
212+
new File(['hello'], 'video.mp4', {type: 'video/mp4'}),
170213
]
171214
const {element, user} = setup<HTMLInputElement>(
172215
`
@@ -179,8 +222,9 @@ test.each([
179222
)
180223

181224
await user.upload(element, files)
182-
183-
expect(element.files).toHaveLength(expectedLength)
225+
expect(
226+
Array.from(element.files as FileList).map(item => item.name),
227+
).toEqual(expectedFileNames)
184228
},
185229
)
186230

0 commit comments

Comments
 (0)