This commit is contained in:
Iliyan Angelov
2025-09-14 23:24:25 +03:00
commit c67067a2a4
71311 changed files with 6800714 additions and 0 deletions

37
frontend/node_modules/react-dropzone/src/.eslintrc generated vendored Normal file
View File

@@ -0,0 +1,37 @@
{
"root": true,
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 2017,
"sourceType": "module"
},
"env": {
"es6": true,
"browser": true,
"node": true,
"jest": true
},
"plugins": [
"import",
"jsx-a11y",
"prettier",
"react",
"react-hooks"
],
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:jsx-a11y/recommended",
"plugin:prettier/recommended"
],
"rules": {
"react-hooks/rules-of-hooks": 2,
"react/forbid-prop-types": 0,
"react/require-default-props": 0
},
"settings": {
"react": {
"version": "detect"
}
}
}

View File

@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`useDropzone() hook behavior renders the root and input nodes with the necessary props 1`] = `"<div role=\\"presentation\\" tabindex=\\"0\\"><input multiple=\\"\\" type=\\"file\\" style=\\"border: 0px; clip: rect(0px, 0px, 0px, 0px); clip-path: inset(50%); height: 1px; margin: 0px -1px -1px 0px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap;\\" tabindex=\\"-1\\"></div>"`;

1042
frontend/node_modules/react-dropzone/src/index.js generated vendored Executable file

File diff suppressed because it is too large Load Diff

3640
frontend/node_modules/react-dropzone/src/index.spec.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

336
frontend/node_modules/react-dropzone/src/utils/index.js generated vendored Normal file
View File

@@ -0,0 +1,336 @@
import _accepts from "attr-accept";
const accepts = typeof _accepts === "function" ? _accepts : _accepts.default;
// Error codes
export const FILE_INVALID_TYPE = "file-invalid-type";
export const FILE_TOO_LARGE = "file-too-large";
export const FILE_TOO_SMALL = "file-too-small";
export const TOO_MANY_FILES = "too-many-files";
export const ErrorCode = {
FileInvalidType: FILE_INVALID_TYPE,
FileTooLarge: FILE_TOO_LARGE,
FileTooSmall: FILE_TOO_SMALL,
TooManyFiles: TOO_MANY_FILES,
};
/**
*
* @param {string} accept
*/
export const getInvalidTypeRejectionErr = (accept = "") => {
const acceptArr = accept.split(",");
const msg =
acceptArr.length > 1 ? `one of ${acceptArr.join(", ")}` : acceptArr[0];
return {
code: FILE_INVALID_TYPE,
message: `File type must be ${msg}`,
};
};
export const getTooLargeRejectionErr = (maxSize) => {
return {
code: FILE_TOO_LARGE,
message: `File is larger than ${maxSize} ${
maxSize === 1 ? "byte" : "bytes"
}`,
};
};
export const getTooSmallRejectionErr = (minSize) => {
return {
code: FILE_TOO_SMALL,
message: `File is smaller than ${minSize} ${
minSize === 1 ? "byte" : "bytes"
}`,
};
};
export const TOO_MANY_FILES_REJECTION = {
code: TOO_MANY_FILES,
message: "Too many files",
};
/**
* Check if file is accepted.
*
* Firefox versions prior to 53 return a bogus MIME type for every file drag,
* so dragovers with that MIME type will always be accepted.
*
* @param {File} file
* @param {string} accept
* @returns
*/
export function fileAccepted(file, accept) {
const isAcceptable =
file.type === "application/x-moz-file" || accepts(file, accept);
return [
isAcceptable,
isAcceptable ? null : getInvalidTypeRejectionErr(accept),
];
}
export function fileMatchSize(file, minSize, maxSize) {
if (isDefined(file.size)) {
if (isDefined(minSize) && isDefined(maxSize)) {
if (file.size > maxSize) return [false, getTooLargeRejectionErr(maxSize)];
if (file.size < minSize) return [false, getTooSmallRejectionErr(minSize)];
} else if (isDefined(minSize) && file.size < minSize)
return [false, getTooSmallRejectionErr(minSize)];
else if (isDefined(maxSize) && file.size > maxSize)
return [false, getTooLargeRejectionErr(maxSize)];
}
return [true, null];
}
function isDefined(value) {
return value !== undefined && value !== null;
}
/**
*
* @param {object} options
* @param {File[]} options.files
* @param {string} [options.accept]
* @param {number} [options.minSize]
* @param {number} [options.maxSize]
* @param {boolean} [options.multiple]
* @param {number} [options.maxFiles]
* @param {(f: File) => FileError|FileError[]|null} [options.validator]
* @returns
*/
export function allFilesAccepted({
files,
accept,
minSize,
maxSize,
multiple,
maxFiles,
validator,
}) {
if (
(!multiple && files.length > 1) ||
(multiple && maxFiles >= 1 && files.length > maxFiles)
) {
return false;
}
return files.every((file) => {
const [accepted] = fileAccepted(file, accept);
const [sizeMatch] = fileMatchSize(file, minSize, maxSize);
const customErrors = validator ? validator(file) : null;
return accepted && sizeMatch && !customErrors;
});
}
// React's synthetic events has event.isPropagationStopped,
// but to remain compatibility with other libs (Preact) fall back
// to check event.cancelBubble
export function isPropagationStopped(event) {
if (typeof event.isPropagationStopped === "function") {
return event.isPropagationStopped();
} else if (typeof event.cancelBubble !== "undefined") {
return event.cancelBubble;
}
return false;
}
export function isEvtWithFiles(event) {
if (!event.dataTransfer) {
return !!event.target && !!event.target.files;
}
// https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types
// https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types#file
return Array.prototype.some.call(
event.dataTransfer.types,
(type) => type === "Files" || type === "application/x-moz-file"
);
}
export function isKindFile(item) {
return typeof item === "object" && item !== null && item.kind === "file";
}
// allow the entire document to be a drag target
export function onDocumentDragOver(event) {
event.preventDefault();
}
function isIe(userAgent) {
return (
userAgent.indexOf("MSIE") !== -1 || userAgent.indexOf("Trident/") !== -1
);
}
function isEdge(userAgent) {
return userAgent.indexOf("Edge/") !== -1;
}
export function isIeOrEdge(userAgent = window.navigator.userAgent) {
return isIe(userAgent) || isEdge(userAgent);
}
/**
* This is intended to be used to compose event handlers
* They are executed in order until one of them calls `event.isPropagationStopped()`.
* Note that the check is done on the first invoke too,
* meaning that if propagation was stopped before invoking the fns,
* no handlers will be executed.
*
* @param {Function} fns the event hanlder functions
* @return {Function} the event handler to add to an element
*/
export function composeEventHandlers(...fns) {
return (event, ...args) =>
fns.some((fn) => {
if (!isPropagationStopped(event) && fn) {
fn(event, ...args);
}
return isPropagationStopped(event);
});
}
/**
* canUseFileSystemAccessAPI checks if the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API)
* is supported by the browser.
* @returns {boolean}
*/
export function canUseFileSystemAccessAPI() {
return "showOpenFilePicker" in window;
}
/**
* Convert the `{accept}` dropzone prop to the
* `{types}` option for https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker
*
* @param {AcceptProp} accept
* @returns {{accept: string[]}[]}
*/
export function pickerOptionsFromAccept(accept) {
if (isDefined(accept)) {
const acceptForPicker = Object.entries(accept)
.filter(([mimeType, ext]) => {
let ok = true;
if (!isMIMEType(mimeType)) {
console.warn(
`Skipped "${mimeType}" because it is not a valid MIME type. Check https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types for a list of valid MIME types.`
);
ok = false;
}
if (!Array.isArray(ext) || !ext.every(isExt)) {
console.warn(
`Skipped "${mimeType}" because an invalid file extension was provided.`
);
ok = false;
}
return ok;
})
.reduce(
(agg, [mimeType, ext]) => ({
...agg,
[mimeType]: ext,
}),
{}
);
return [
{
// description is required due to https://crbug.com/1264708
description: "Files",
accept: acceptForPicker,
},
];
}
return accept;
}
/**
* Convert the `{accept}` dropzone prop to an array of MIME types/extensions.
* @param {AcceptProp} accept
* @returns {string}
*/
export function acceptPropAsAcceptAttr(accept) {
if (isDefined(accept)) {
return (
Object.entries(accept)
.reduce((a, [mimeType, ext]) => [...a, mimeType, ...ext], [])
// Silently discard invalid entries as pickerOptionsFromAccept warns about these
.filter((v) => isMIMEType(v) || isExt(v))
.join(",")
);
}
return undefined;
}
/**
* Check if v is an exception caused by aborting a request (e.g window.showOpenFilePicker()).
*
* See https://developer.mozilla.org/en-US/docs/Web/API/DOMException.
* @param {any} v
* @returns {boolean} True if v is an abort exception.
*/
export function isAbort(v) {
return (
v instanceof DOMException &&
(v.name === "AbortError" || v.code === v.ABORT_ERR)
);
}
/**
* Check if v is a security error.
*
* See https://developer.mozilla.org/en-US/docs/Web/API/DOMException.
* @param {any} v
* @returns {boolean} True if v is a security error.
*/
export function isSecurityError(v) {
return (
v instanceof DOMException &&
(v.name === "SecurityError" || v.code === v.SECURITY_ERR)
);
}
/**
* Check if v is a MIME type string.
*
* See accepted format: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers.
*
* @param {string} v
*/
export function isMIMEType(v) {
return (
v === "audio/*" ||
v === "video/*" ||
v === "image/*" ||
v === "text/*" ||
v === "application/*" ||
/\w+\/[-+.\w]+/g.test(v)
);
}
/**
* Check if v is a file extension.
* @param {string} v
*/
export function isExt(v) {
return /^.*\.[\w]+$/.test(v);
}
/**
* @typedef {Object.<string, string[]>} AcceptProp
*/
/**
* @typedef {object} FileError
* @property {string} message
* @property {ErrorCode|string} code
*/
/**
* @typedef {"file-invalid-type"|"file-too-large"|"file-too-small"|"too-many-files"} ErrorCode
*/

View File

@@ -0,0 +1,600 @@
beforeEach(() => {
jest.resetModules();
});
describe("fileMatchSize()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("should return true if the file object doesn't have a {size} property", () => {
expect(utils.fileMatchSize({})).toEqual([true, null]);
expect(utils.fileMatchSize({ size: null })).toEqual([true, null]);
});
it("should return true if the minSize and maxSize were not provided", () => {
expect(utils.fileMatchSize({ size: 100 })).toEqual([true, null]);
expect(utils.fileMatchSize({ size: 100 }, undefined, undefined)).toEqual([
true,
null,
]);
expect(utils.fileMatchSize({ size: 100 }, null, null)).toEqual([
true,
null,
]);
});
it("should return true if the file {size} is within the [minSize, maxSize] range", () => {
expect(utils.fileMatchSize({ size: 100 }, 10, 200)).toEqual([true, null]);
expect(utils.fileMatchSize({ size: 100 }, 10, 99)).toEqual([
false,
{ code: "file-too-large", message: "File is larger than 99 bytes" },
]);
expect(utils.fileMatchSize({ size: 100 }, 101, 200)).toEqual([
false,
{ code: "file-too-small", message: "File is smaller than 101 bytes" },
]);
});
it("should return true if the file {size} is more than minSize", () => {
expect(utils.fileMatchSize({ size: 100 }, 100)).toEqual([true, null]);
expect(utils.fileMatchSize({ size: 100 }, 101)).toEqual([
false,
{ code: "file-too-small", message: "File is smaller than 101 bytes" },
]);
});
it("should return true if the file {size} is less than maxSize", () => {
expect(utils.fileMatchSize({ size: 100 }, undefined, 100)).toEqual([
true,
null,
]);
expect(utils.fileMatchSize({ size: 100 }, null, 100)).toEqual([true, null]);
expect(utils.fileMatchSize({ size: 100 }, undefined, 99)).toEqual([
false,
{ code: "file-too-large", message: "File is larger than 99 bytes" },
]);
expect(utils.fileMatchSize({ size: 100 }, null, 99)).toEqual([
false,
{ code: "file-too-large", message: "File is larger than 99 bytes" },
]);
});
});
describe("isIeOrEdge", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("should return true for IE10", () => {
const userAgent =
"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729)";
expect(utils.isIeOrEdge(userAgent)).toBe(true);
});
it("should return true for IE11", () => {
const userAgent =
"Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; rv:11.0) like Gecko";
expect(utils.isIeOrEdge(userAgent)).toBe(true);
});
it("should return true for Edge", () => {
const userAgent =
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16258";
expect(utils.isIeOrEdge(userAgent)).toBe(true);
});
it("should return false for Chrome", () => {
const userAgent =
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36";
expect(utils.isIeOrEdge(userAgent)).toBe(false);
});
});
describe("isKindFile()", () => {
it('should return true for DataTransferItem of kind "file"', async () => {
/**
* @constant
* @type {import('./index')}
*/
const utils = await import("./index");
expect(utils.isKindFile({ kind: "file" })).toBe(true);
expect(utils.isKindFile({ kind: "text/html" })).toBe(false);
expect(utils.isKindFile({})).toBe(false);
expect(utils.isKindFile(null)).toBe(false);
});
});
describe("isPropagationStopped()", () => {
const trueFn = jest.fn(() => true);
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("should return result of isPropagationStopped() if isPropagationStopped exists", () => {
expect(utils.isPropagationStopped({ isPropagationStopped: trueFn })).toBe(
true
);
});
it("should return value of cancelBubble if isPropagationStopped doesnt exist and cancelBubble exists", () => {
expect(utils.isPropagationStopped({ cancelBubble: true })).toBe(true);
});
it("should return false if isPropagationStopped and cancelBubble are missing", () => {
expect(utils.isPropagationStopped({})).toBe(false);
});
});
describe("isEvtWithFiles()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("should return true if some dragged types are files", () => {
expect(utils.isEvtWithFiles({ dataTransfer: { types: ["Files"] } })).toBe(
true
);
expect(
utils.isEvtWithFiles({
dataTransfer: { types: ["application/x-moz-file"] },
})
).toBe(true);
expect(
utils.isEvtWithFiles({
dataTransfer: { types: ["Files", "application/x-moz-file"] },
})
).toBe(true);
expect(
utils.isEvtWithFiles({ dataTransfer: { types: ["text/plain"] } })
).toBe(false);
expect(
utils.isEvtWithFiles({ dataTransfer: { types: ["text/html"] } })
).toBe(false);
expect(
utils.isEvtWithFiles({
dataTransfer: { types: ["Files", "application/test"] },
})
).toBe(true);
expect(
utils.isEvtWithFiles({
dataTransfer: { types: ["application/x-moz-file", "application/test"] },
})
).toBe(true);
});
it("should return true if the event has a target with files", () => {
expect(utils.isEvtWithFiles({ target: { files: [] } })).toBe(true);
});
it("should return false otherwise", () => {
expect(utils.isEvtWithFiles({})).toBe(false);
});
});
describe("composeEventHandlers()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("returns a fn", () => {
const fn = utils.composeEventHandlers(() => {});
expect(typeof fn).toBe("function");
});
it("runs every passed fn in order", () => {
const fn1 = jest.fn();
const fn2 = jest.fn();
const fn = utils.composeEventHandlers(fn1, fn2);
const event = { type: "click" };
const data = { ping: true };
fn(event, data);
expect(fn1).toHaveBeenCalledWith(event, data);
expect(fn2).toHaveBeenCalledWith(event, data);
});
it("stops after first fn that calls stopPropagation()", () => {
const fn1 = jest.fn().mockImplementation((event) => {
Object.defineProperty(event, "cancelBubble", { value: true });
return event;
});
const fn2 = jest.fn();
const fn = utils.composeEventHandlers(fn1, fn2);
const event = new MouseEvent("click");
fn(event);
expect(fn1).toHaveBeenCalledWith(event);
expect(fn2).not.toHaveBeenCalled();
});
it("stops before first fn if bubble is already canceled", () => {
const fn1 = jest.fn();
const fn2 = jest.fn();
const fn = utils.composeEventHandlers(fn1, fn2);
const event = new MouseEvent("click");
Object.defineProperty(event, "cancelBubble", { value: true });
fn(event);
expect(fn1).not.toHaveBeenCalled();
expect(fn2).not.toHaveBeenCalled();
});
});
describe("fileAccepted()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("accepts bogus firefox file", () => {
const file = createFile("bogus.png", 100, "application/x-moz-file");
expect(utils.fileAccepted(file, ".pdf")).toEqual([true, null]);
});
it("accepts file when single accept criteria", () => {
const file = createFile("hamster.pdf", 100, "application/pdf");
expect(utils.fileAccepted(file, ".pdf")).toEqual([true, null]);
});
it("accepts file when multiple accept criteria", () => {
const file = createFile("hamster.pdf", 100, "application/pdf");
expect(utils.fileAccepted(file, ".pdf,.png")).toEqual([true, null]);
});
it("rejects file when single accept criteria", () => {
const file = createFile("hamster.pdf", 100, "application/pdf");
expect(utils.fileAccepted(file, ".png")).toEqual([
false,
{ code: "file-invalid-type", message: "File type must be .png" },
]);
});
it("rejects file when multiple accept criteria", () => {
const file = createFile("hamster.pdf", 100, "application/pdf");
expect(utils.fileAccepted(file, ".gif,.png")).toEqual([
false,
{
code: "file-invalid-type",
message: "File type must be one of .gif, .png",
},
]);
});
});
describe("getTooLargeRejectionErr()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("prints byte when maxSize is 1", () => {
expect(utils.getTooLargeRejectionErr(1).message).toEqual(
"File is larger than 1 byte"
);
});
it("prints bytes when maxSize > 1", () => {
expect(utils.getTooLargeRejectionErr(100).message).toEqual(
"File is larger than 100 bytes"
);
});
});
describe("getTooSmallRejectionErr()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("prints byte when minSize is 1", () => {
expect(utils.getTooSmallRejectionErr(1).message).toEqual(
"File is smaller than 1 byte"
);
});
it("prints bytes when minSize > 1", () => {
expect(utils.getTooSmallRejectionErr(100).message).toEqual(
"File is smaller than 100 bytes"
);
});
});
describe("allFilesAccepted()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("rejects file when multiple accept criteria", () => {
const files = [
createFile("hamster.pdf", 100, "application/pdf"),
createFile("fish.pdf", 100, "application/pdf"),
];
const images = [
createFile("cats.gif", 1234, "image/gif"),
createFile("dogs.gif", 2345, "image/jpeg"),
];
expect(utils.allFilesAccepted({ files, multiple: true })).toEqual(true);
expect(
utils.allFilesAccepted({ files, multiple: true, maxFiles: 10 })
).toEqual(true);
expect(
utils.allFilesAccepted({ files, multiple: false, maxFiles: 10 })
).toEqual(false);
expect(
utils.allFilesAccepted({ files, multiple: true, accept: "image/jpeg" })
).toEqual(false);
expect(
utils.allFilesAccepted({
files: images,
multiple: true,
accept: "image/*",
})
).toEqual(true);
expect(
utils.allFilesAccepted({ files, multiple: true, minSize: 110 })
).toEqual(false);
expect(
utils.allFilesAccepted({ files, multiple: true, maxSize: 99 })
).toEqual(false);
expect(
utils.allFilesAccepted({ files, multiple: true, maxFiles: 1 })
).toEqual(false);
expect(
utils.allFilesAccepted({
files,
validator: () => ({ code: "not-allowed", message: "Cannot do this!" }),
})
).toEqual(false);
});
});
describe("ErrorCode", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("should exist and have known error code properties", () => {
expect(utils.ErrorCode.FileInvalidType).toEqual(utils.FILE_INVALID_TYPE);
expect(utils.ErrorCode.FileTooLarge).toEqual(utils.FILE_TOO_LARGE);
expect(utils.ErrorCode.FileTooSmall).toEqual(utils.FILE_TOO_SMALL);
expect(utils.ErrorCode.TooManyFiles).toEqual(utils.TOO_MANY_FILES);
});
});
describe("canUseFileSystemAccessAPI()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("should return false if not", () => {
expect(utils.canUseFileSystemAccessAPI()).toBe(false);
});
it("should return true if yes", () => {
// TODO: If we use these in other tests, restore once test is done
window.showOpenFilePicker = jest.fn();
expect(utils.canUseFileSystemAccessAPI()).toBe(true);
});
});
describe("pickerOptionsFromAccept()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("converts the {accept} prop to file picker options", () => {
expect(
utils.pickerOptionsFromAccept({
"image/*": [".png", ".jpg"], // ok
"text/*": [".txt", ".pdf"], // ok
"audio/*": ["mp3"], // not ok
"*": [".p12"], // not ok
})
).toEqual([
{
description: "Files",
accept: {
"image/*": [".png", ".jpg"],
"text/*": [".txt", ".pdf"],
},
},
]);
});
});
describe("acceptPropAsAcceptAttr()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("converts {accept} to an array of strings", () => {
expect(
utils.acceptPropAsAcceptAttr({
"image/*": [".png", ".jpg"],
"text/*": [".txt", ".pdf"],
"audio/*": ["mp3"], // `mp3` not ok
"*": [".p12"], // `*` not ok
})
).toEqual("image/*,.png,.jpg,text/*,.txt,.pdf,audio/*,.p12");
});
});
describe("isMIMEType()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("checks that the value is a valid MIME type string", () => {
expect(utils.isMIMEType("text/html")).toBe(true);
expect(utils.isMIMEType("text/*")).toBe(true);
expect(utils.isMIMEType("image/*")).toBe(true);
expect(utils.isMIMEType("video/*")).toBe(true);
expect(utils.isMIMEType("audio/*")).toBe(true);
expect(utils.isMIMEType("application/*")).toBe(true);
expect(utils.isMIMEType("test/*")).toBe(false);
expect(utils.isMIMEType("text")).toBe(false);
expect(utils.isMIMEType("")).toBe(false);
expect(utils.isMIMEType(undefined)).toBe(false);
});
});
describe("isExt()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("checks that the value is a valid file extension", () => {
expect(utils.isExt(".jpg")).toBe(true);
expect(utils.isExt("me.jpg")).toBe(true);
expect(utils.isExt("me.prev.png")).toBe(true);
expect(utils.isExt("")).toBe(false);
expect(utils.isExt("text")).toBe(false);
expect(utils.isExt(undefined)).toBe(false);
});
});
describe("isAbort()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("should work as expected", () => {
expect(utils.isAbort(new DOMException())).toBe(false);
expect(utils.isAbort(new DOMException("some err"))).toBe(false);
expect(utils.isAbort(new DOMException("some err", "Noop"))).toBe(false);
expect(utils.isAbort(new DOMException("some err", "AbortError"))).toBe(
true
);
const err = new DOMException("some err");
const e = new Proxy(err, {
get(t, p) {
if (p === "code") {
return 20;
}
return t[p];
},
});
expect(utils.isAbort(e)).toBe(true);
});
});
describe("isSecurityError()", () => {
/**
* @constant
* @type {import('./index')}
*/
let utils;
beforeEach(async () => {
utils = await import("./index");
});
it("should work as expected", () => {
expect(utils.isSecurityError(new DOMException())).toBe(false);
expect(utils.isSecurityError(new DOMException("some err"))).toBe(false);
expect(utils.isSecurityError(new DOMException("some err", "Noop"))).toBe(
false
);
expect(
utils.isSecurityError(new DOMException("some err", "SecurityError"))
).toBe(true);
const err = new DOMException("some err");
const e = new Proxy(err, {
get(t, p) {
if (p === "code") {
return 18;
}
return t[p];
},
});
expect(utils.isSecurityError(e)).toBe(true);
});
});
function createFile(name, size, type) {
const file = new File([], name, { type });
Object.defineProperty(file, "size", {
get() {
return size;
},
});
return file;
}