Set up comprehensive frontend testing infrastructure
- Install Jest for unit testing with React Testing Library - Install Playwright for end-to-end testing - Configure Jest with proper TypeScript support and module mapping - Create test setup files and utilities for both unit and e2e tests Components: * Jest configuration with coverage thresholds * Playwright configuration with browser automation * Unit tests for LoginForm, AuthContext, and useSocketIO hook * E2E tests for authentication, dashboard, and agents workflows * GitHub Actions workflow for automated testing * Mock data and API utilities for consistent testing * Test documentation with best practices Testing features: - Unit tests with 70% coverage threshold - E2E tests with API mocking and user journey testing - CI/CD integration for automated test runs - Cross-browser testing support with Playwright - Authentication system testing end-to-end 🚀 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
20
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/click/isClickableInput.js
generated
vendored
Normal file
20
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/click/isClickableInput.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
var isElementType = require('../misc/isElementType.js');
|
||||
|
||||
var clickableInputTypes = /*#__PURE__*/ function(clickableInputTypes) {
|
||||
clickableInputTypes["button"] = "button";
|
||||
clickableInputTypes["color"] = "color";
|
||||
clickableInputTypes["file"] = "file";
|
||||
clickableInputTypes["image"] = "image";
|
||||
clickableInputTypes["reset"] = "reset";
|
||||
clickableInputTypes["submit"] = "submit";
|
||||
clickableInputTypes["checkbox"] = "checkbox";
|
||||
clickableInputTypes["radio"] = "radio";
|
||||
return clickableInputTypes;
|
||||
}(clickableInputTypes || {});
|
||||
function isClickableInput(element) {
|
||||
return isElementType.isElementType(element, 'button') || isElementType.isElementType(element, 'input') && element.type in clickableInputTypes;
|
||||
}
|
||||
|
||||
exports.isClickableInput = isClickableInput;
|
||||
16
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/dataTransfer/Blob.js
generated
vendored
Normal file
16
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/dataTransfer/Blob.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
// jsdom does not implement Blob.text()
|
||||
function readBlobText(blob, FileReader) {
|
||||
return new Promise((res, rej)=>{
|
||||
const fr = new FileReader();
|
||||
fr.onerror = rej;
|
||||
fr.onabort = rej;
|
||||
fr.onload = ()=>{
|
||||
res(String(fr.result));
|
||||
};
|
||||
fr.readAsText(blob);
|
||||
});
|
||||
}
|
||||
|
||||
exports.readBlobText = readBlobText;
|
||||
169
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/dataTransfer/Clipboard.js
generated
vendored
Normal file
169
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/dataTransfer/Clipboard.js
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
'use strict';
|
||||
|
||||
var getWindow = require('../misc/getWindow.js');
|
||||
var Blob = require('./Blob.js');
|
||||
var DataTransfer = require('./DataTransfer.js');
|
||||
|
||||
// Clipboard is not available in jsdom
|
||||
function _define_property(obj, key, value) {
|
||||
if (key in obj) {
|
||||
Object.defineProperty(obj, key, {
|
||||
value: value,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true
|
||||
});
|
||||
} else {
|
||||
obj[key] = value;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
// MDN lists string|Blob|Promise<Blob|string> as possible types in ClipboardItemData
|
||||
// lib.dom.d.ts lists only Promise<Blob|string>
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem/ClipboardItem#syntax
|
||||
function createClipboardItem(window, ...blobs) {
|
||||
const dataMap = Object.fromEntries(blobs.map((b)=>[
|
||||
typeof b === 'string' ? 'text/plain' : b.type,
|
||||
Promise.resolve(b)
|
||||
]));
|
||||
// use real ClipboardItem if available
|
||||
/* istanbul ignore if */ if (typeof window.ClipboardItem !== 'undefined') {
|
||||
return new window.ClipboardItem(dataMap);
|
||||
}
|
||||
return new class ClipboardItem {
|
||||
get types() {
|
||||
return Array.from(Object.keys(this.data));
|
||||
}
|
||||
async getType(type) {
|
||||
const value = await this.data[type];
|
||||
if (!value) {
|
||||
throw new Error(`${type} is not one of the available MIME types on this item.`);
|
||||
}
|
||||
return value instanceof window.Blob ? value : new window.Blob([
|
||||
value
|
||||
], {
|
||||
type
|
||||
});
|
||||
}
|
||||
constructor(d){
|
||||
_define_property(this, "data", undefined);
|
||||
this.data = d;
|
||||
}
|
||||
}(dataMap);
|
||||
}
|
||||
const ClipboardStubControl = Symbol('Manage ClipboardSub');
|
||||
function createClipboardStub(window, control) {
|
||||
return Object.assign(new class Clipboard extends window.EventTarget {
|
||||
async read() {
|
||||
return Array.from(this.items);
|
||||
}
|
||||
async readText() {
|
||||
let text = '';
|
||||
for (const item of this.items){
|
||||
const type = item.types.includes('text/plain') ? 'text/plain' : item.types.find((t)=>t.startsWith('text/'));
|
||||
if (type) {
|
||||
text += await item.getType(type).then((b)=>Blob.readBlobText(b, window.FileReader));
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
async write(data) {
|
||||
this.items = data;
|
||||
}
|
||||
async writeText(text) {
|
||||
this.items = [
|
||||
createClipboardItem(window, text)
|
||||
];
|
||||
}
|
||||
constructor(...args){
|
||||
super(...args), _define_property(this, "items", []);
|
||||
}
|
||||
}(), {
|
||||
[ClipboardStubControl]: control
|
||||
});
|
||||
}
|
||||
function isClipboardStub(clipboard) {
|
||||
return !!(clipboard === null || clipboard === undefined ? undefined : clipboard[ClipboardStubControl]);
|
||||
}
|
||||
function attachClipboardStubToView(window) {
|
||||
if (isClipboardStub(window.navigator.clipboard)) {
|
||||
return window.navigator.clipboard[ClipboardStubControl];
|
||||
}
|
||||
const realClipboard = Object.getOwnPropertyDescriptor(window.navigator, 'clipboard');
|
||||
let stub;
|
||||
const control = {
|
||||
resetClipboardStub: ()=>{
|
||||
stub = createClipboardStub(window, control);
|
||||
},
|
||||
detachClipboardStub: ()=>{
|
||||
/* istanbul ignore if */ if (realClipboard) {
|
||||
Object.defineProperty(window.navigator, 'clipboard', realClipboard);
|
||||
} else {
|
||||
Object.defineProperty(window.navigator, 'clipboard', {
|
||||
value: undefined,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
stub = createClipboardStub(window, control);
|
||||
Object.defineProperty(window.navigator, 'clipboard', {
|
||||
get: ()=>stub,
|
||||
configurable: true
|
||||
});
|
||||
return stub[ClipboardStubControl];
|
||||
}
|
||||
function resetClipboardStubOnView(window) {
|
||||
if (isClipboardStub(window.navigator.clipboard)) {
|
||||
window.navigator.clipboard[ClipboardStubControl].resetClipboardStub();
|
||||
}
|
||||
}
|
||||
function detachClipboardStubFromView(window) {
|
||||
if (isClipboardStub(window.navigator.clipboard)) {
|
||||
window.navigator.clipboard[ClipboardStubControl].detachClipboardStub();
|
||||
}
|
||||
}
|
||||
async function readDataTransferFromClipboard(document) {
|
||||
const window = document.defaultView;
|
||||
const clipboard = window === null || window === undefined ? undefined : window.navigator.clipboard;
|
||||
const items = clipboard && await clipboard.read();
|
||||
if (!items) {
|
||||
throw new Error('The Clipboard API is unavailable.');
|
||||
}
|
||||
const dt = DataTransfer.createDataTransfer(window);
|
||||
for (const item of items){
|
||||
for (const type of item.types){
|
||||
dt.setData(type, await item.getType(type).then((b)=>Blob.readBlobText(b, window.FileReader)));
|
||||
}
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
async function writeDataTransferToClipboard(document, clipboardData) {
|
||||
const window = getWindow.getWindow(document);
|
||||
const clipboard = window.navigator.clipboard;
|
||||
const items = [];
|
||||
for(let i = 0; i < clipboardData.items.length; i++){
|
||||
const dtItem = clipboardData.items[i];
|
||||
const blob = await DataTransfer.getBlobFromDataTransferItem(window, dtItem);
|
||||
items.push(createClipboardItem(window, blob));
|
||||
}
|
||||
const written = clipboard && await clipboard.write(items).then(()=>true, // Can happen with other implementations that e.g. require permissions
|
||||
/* istanbul ignore next */ ()=>false);
|
||||
if (!written) {
|
||||
throw new Error('The Clipboard API is unavailable.');
|
||||
}
|
||||
}
|
||||
const g = globalThis;
|
||||
/* istanbul ignore else */ if (typeof g.afterEach === 'function') {
|
||||
g.afterEach(()=>resetClipboardStubOnView(globalThis.window));
|
||||
}
|
||||
/* istanbul ignore else */ if (typeof g.afterAll === 'function') {
|
||||
g.afterAll(()=>detachClipboardStubFromView(globalThis.window));
|
||||
}
|
||||
|
||||
exports.attachClipboardStubToView = attachClipboardStubToView;
|
||||
exports.createClipboardItem = createClipboardItem;
|
||||
exports.detachClipboardStubFromView = detachClipboardStubFromView;
|
||||
exports.readDataTransferFromClipboard = readDataTransferFromClipboard;
|
||||
exports.resetClipboardStubOnView = resetClipboardStubOnView;
|
||||
exports.writeDataTransferToClipboard = writeDataTransferToClipboard;
|
||||
136
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/dataTransfer/DataTransfer.js
generated
vendored
Normal file
136
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/dataTransfer/DataTransfer.js
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
'use strict';
|
||||
|
||||
var FileList = require('./FileList.js');
|
||||
|
||||
function _define_property(obj, key, value) {
|
||||
if (key in obj) {
|
||||
Object.defineProperty(obj, key, {
|
||||
value: value,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true
|
||||
});
|
||||
} else {
|
||||
obj[key] = value;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
// DataTransfer is not implemented in jsdom.
|
||||
// DataTransfer with FileList is being created by the browser on certain events.
|
||||
class DataTransferItemStub {
|
||||
getAsFile() {
|
||||
return this.file;
|
||||
}
|
||||
getAsString(callback) {
|
||||
if (typeof this.data === 'string') {
|
||||
callback(this.data);
|
||||
}
|
||||
}
|
||||
/* istanbul ignore next */ webkitGetAsEntry() {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
constructor(dataOrFile, type){
|
||||
_define_property(this, "kind", undefined);
|
||||
_define_property(this, "type", undefined);
|
||||
_define_property(this, "file", null);
|
||||
_define_property(this, "data", undefined);
|
||||
if (typeof dataOrFile === 'string') {
|
||||
this.kind = 'string';
|
||||
this.type = String(type);
|
||||
this.data = dataOrFile;
|
||||
} else {
|
||||
this.kind = 'file';
|
||||
this.type = dataOrFile.type;
|
||||
this.file = dataOrFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
class DataTransferItemListStub extends Array {
|
||||
add(...args) {
|
||||
const item = new DataTransferItemStub(args[0], args[1]);
|
||||
this.push(item);
|
||||
return item;
|
||||
}
|
||||
clear() {
|
||||
this.splice(0, this.length);
|
||||
}
|
||||
remove(index) {
|
||||
this.splice(index, 1);
|
||||
}
|
||||
}
|
||||
function getTypeMatcher(type, exact) {
|
||||
const [group, sub] = type.split('/');
|
||||
const isGroup = !sub || sub === '*';
|
||||
return (item)=>{
|
||||
return exact ? item.type === (isGroup ? group : type) : isGroup ? item.type.startsWith(`${group}/`) : item.type === group;
|
||||
};
|
||||
}
|
||||
function createDataTransferStub(window) {
|
||||
return new class DataTransferStub {
|
||||
getData(format) {
|
||||
var _this_items_find;
|
||||
const match = (_this_items_find = this.items.find(getTypeMatcher(format, true))) !== null && _this_items_find !== undefined ? _this_items_find : this.items.find(getTypeMatcher(format, false));
|
||||
let text = '';
|
||||
match === null || match === undefined ? undefined : match.getAsString((t)=>{
|
||||
text = t;
|
||||
});
|
||||
return text;
|
||||
}
|
||||
setData(format, data) {
|
||||
const matchIndex = this.items.findIndex(getTypeMatcher(format, true));
|
||||
const item = new DataTransferItemStub(data, format);
|
||||
if (matchIndex >= 0) {
|
||||
this.items.splice(matchIndex, 1, item);
|
||||
} else {
|
||||
this.items.push(item);
|
||||
}
|
||||
}
|
||||
clearData(format) {
|
||||
if (format) {
|
||||
const matchIndex = this.items.findIndex(getTypeMatcher(format, true));
|
||||
if (matchIndex >= 0) {
|
||||
this.items.remove(matchIndex);
|
||||
}
|
||||
} else {
|
||||
this.items.clear();
|
||||
}
|
||||
}
|
||||
get types() {
|
||||
const t = [];
|
||||
if (this.files.length) {
|
||||
t.push('Files');
|
||||
}
|
||||
this.items.forEach((i)=>t.push(i.type));
|
||||
Object.freeze(t);
|
||||
return t;
|
||||
}
|
||||
/* istanbul ignore next */ setDragImage() {}
|
||||
constructor(){
|
||||
_define_property(this, "dropEffect", 'none');
|
||||
_define_property(this, "effectAllowed", 'uninitialized');
|
||||
_define_property(this, "items", new DataTransferItemListStub());
|
||||
_define_property(this, "files", FileList.createFileList(window, []));
|
||||
}
|
||||
}();
|
||||
}
|
||||
function createDataTransfer(window, files = []) {
|
||||
// Use real DataTransfer if available
|
||||
const dt = typeof window.DataTransfer === 'undefined' ? createDataTransferStub(window) : /* istanbul ignore next */ new window.DataTransfer();
|
||||
Object.defineProperty(dt, 'files', {
|
||||
get: ()=>FileList.createFileList(window, files)
|
||||
});
|
||||
return dt;
|
||||
}
|
||||
async function getBlobFromDataTransferItem(window, item) {
|
||||
if (item.kind === 'file') {
|
||||
return item.getAsFile();
|
||||
}
|
||||
return new window.Blob([
|
||||
await new Promise((r)=>item.getAsString(r))
|
||||
], {
|
||||
type: item.type
|
||||
});
|
||||
}
|
||||
|
||||
exports.createDataTransfer = createDataTransfer;
|
||||
exports.getBlobFromDataTransferItem = getBlobFromDataTransferItem;
|
||||
24
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/dataTransfer/FileList.js
generated
vendored
Normal file
24
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/dataTransfer/FileList.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
// FileList can not be created per constructor.
|
||||
function createFileList(window, files) {
|
||||
const list = {
|
||||
...files,
|
||||
length: files.length,
|
||||
item: (index)=>list[index],
|
||||
[Symbol.iterator]: function* nextFile() {
|
||||
for(let i = 0; i < list.length; i++){
|
||||
yield list[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
list.constructor = window.FileList;
|
||||
// guard for environments without FileList
|
||||
/* istanbul ignore else */ if (window.FileList) {
|
||||
Object.setPrototypeOf(list, window.FileList.prototype);
|
||||
}
|
||||
Object.freeze(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
exports.createFileList = createFileList;
|
||||
18
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/edit/isContentEditable.js
generated
vendored
Normal file
18
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/edit/isContentEditable.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
//jsdom is not supporting isContentEditable
|
||||
function isContentEditable(element) {
|
||||
return element.hasAttribute('contenteditable') && (element.getAttribute('contenteditable') == 'true' || element.getAttribute('contenteditable') == '');
|
||||
}
|
||||
/**
|
||||
* If a node is a contenteditable or inside one, return that element.
|
||||
*/ function getContentEditable(node) {
|
||||
const element = getElement(node);
|
||||
return element && (element.closest('[contenteditable=""]') || element.closest('[contenteditable="true"]'));
|
||||
}
|
||||
function getElement(node) {
|
||||
return node.nodeType === 1 ? node : node.parentElement;
|
||||
}
|
||||
|
||||
exports.getContentEditable = getContentEditable;
|
||||
exports.isContentEditable = isContentEditable;
|
||||
29
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/edit/isEditable.js
generated
vendored
Normal file
29
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/edit/isEditable.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
var isElementType = require('../misc/isElementType.js');
|
||||
var isContentEditable = require('./isContentEditable.js');
|
||||
|
||||
function isEditable(element) {
|
||||
return isEditableInputOrTextArea(element) && !element.readOnly || isContentEditable.isContentEditable(element);
|
||||
}
|
||||
var editableInputTypes = /*#__PURE__*/ function(editableInputTypes) {
|
||||
editableInputTypes["text"] = "text";
|
||||
editableInputTypes["date"] = "date";
|
||||
editableInputTypes["datetime-local"] = "datetime-local";
|
||||
editableInputTypes["email"] = "email";
|
||||
editableInputTypes["month"] = "month";
|
||||
editableInputTypes["number"] = "number";
|
||||
editableInputTypes["password"] = "password";
|
||||
editableInputTypes["search"] = "search";
|
||||
editableInputTypes["tel"] = "tel";
|
||||
editableInputTypes["time"] = "time";
|
||||
editableInputTypes["url"] = "url";
|
||||
editableInputTypes["week"] = "week";
|
||||
return editableInputTypes;
|
||||
}(editableInputTypes || {});
|
||||
function isEditableInputOrTextArea(element) {
|
||||
return isElementType.isElementType(element, 'textarea') || isElementType.isElementType(element, 'input') && element.type in editableInputTypes;
|
||||
}
|
||||
|
||||
exports.isEditable = isEditable;
|
||||
exports.isEditableInputOrTextArea = isEditableInputOrTextArea;
|
||||
26
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/edit/maxLength.js
generated
vendored
Normal file
26
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/edit/maxLength.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
var isElementType = require('../misc/isElementType.js');
|
||||
|
||||
var maxLengthSupportedTypes = /*#__PURE__*/ function(maxLengthSupportedTypes) {
|
||||
maxLengthSupportedTypes["email"] = "email";
|
||||
maxLengthSupportedTypes["password"] = "password";
|
||||
maxLengthSupportedTypes["search"] = "search";
|
||||
maxLengthSupportedTypes["telephone"] = "telephone";
|
||||
maxLengthSupportedTypes["text"] = "text";
|
||||
maxLengthSupportedTypes["url"] = "url";
|
||||
return maxLengthSupportedTypes;
|
||||
}(maxLengthSupportedTypes || {});
|
||||
// can't use .maxLength property because of a jsdom bug:
|
||||
// https://github.com/jsdom/jsdom/issues/2927
|
||||
function getMaxLength(element) {
|
||||
var _element_getAttribute;
|
||||
const attr = (_element_getAttribute = element.getAttribute('maxlength')) !== null && _element_getAttribute !== undefined ? _element_getAttribute : '';
|
||||
return /^\d+$/.test(attr) && Number(attr) >= 0 ? Number(attr) : undefined;
|
||||
}
|
||||
function supportsMaxLength(element) {
|
||||
return isElementType.isElementType(element, 'textarea') || isElementType.isElementType(element, 'input') && element.type in maxLengthSupportedTypes;
|
||||
}
|
||||
|
||||
exports.getMaxLength = getMaxLength;
|
||||
exports.supportsMaxLength = supportsMaxLength;
|
||||
59
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/edit/setFiles.js
generated
vendored
Normal file
59
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/edit/setFiles.js
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
'use strict';
|
||||
|
||||
// It is not possible to create a real FileList programmatically.
|
||||
// Therefore assigning `files` property with a programmatically created FileList results in an error.
|
||||
// Just assigning the property (as per fireEvent) breaks the interweaving with the `value` property.
|
||||
const fakeFiles = Symbol('files and value properties are mocked');
|
||||
function restoreProperty(obj, prop, descriptor) {
|
||||
if (descriptor) {
|
||||
Object.defineProperty(obj, prop, descriptor);
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete obj[prop];
|
||||
}
|
||||
}
|
||||
function setFiles(el, files) {
|
||||
var _el_fakeFiles;
|
||||
(_el_fakeFiles = el[fakeFiles]) === null || _el_fakeFiles === undefined ? undefined : _el_fakeFiles.restore();
|
||||
const typeDescr = Object.getOwnPropertyDescriptor(el, 'type');
|
||||
const valueDescr = Object.getOwnPropertyDescriptor(el, 'value');
|
||||
const filesDescr = Object.getOwnPropertyDescriptor(el, 'files');
|
||||
function restore() {
|
||||
restoreProperty(el, 'type', typeDescr);
|
||||
restoreProperty(el, 'value', valueDescr);
|
||||
restoreProperty(el, 'files', filesDescr);
|
||||
}
|
||||
el[fakeFiles] = {
|
||||
restore
|
||||
};
|
||||
Object.defineProperties(el, {
|
||||
files: {
|
||||
configurable: true,
|
||||
get: ()=>files
|
||||
},
|
||||
value: {
|
||||
configurable: true,
|
||||
get: ()=>files.length ? `C:\\fakepath\\${files[0].name}` : '',
|
||||
set (v) {
|
||||
if (v === '') {
|
||||
restore();
|
||||
} else {
|
||||
var _valueDescr_set;
|
||||
valueDescr === null || valueDescr === undefined ? undefined : (_valueDescr_set = valueDescr.set) === null || _valueDescr_set === undefined ? undefined : _valueDescr_set.call(el, v);
|
||||
}
|
||||
}
|
||||
},
|
||||
type: {
|
||||
configurable: true,
|
||||
get: ()=>'file',
|
||||
set (v) {
|
||||
if (v !== 'file') {
|
||||
restore();
|
||||
el.type = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
exports.setFiles = setFiles;
|
||||
40
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/edit/timeValue.js
generated
vendored
Normal file
40
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/edit/timeValue.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
'use strict';
|
||||
|
||||
const parseInt = globalThis.parseInt;
|
||||
function buildTimeValue(value) {
|
||||
const onlyDigitsValue = value.replace(/\D/g, '');
|
||||
if (onlyDigitsValue.length < 2) {
|
||||
return value;
|
||||
}
|
||||
const firstDigit = parseInt(onlyDigitsValue[0], 10);
|
||||
const secondDigit = parseInt(onlyDigitsValue[1], 10);
|
||||
if (firstDigit >= 3 || firstDigit === 2 && secondDigit >= 4) {
|
||||
let index;
|
||||
if (firstDigit >= 3) {
|
||||
index = 1;
|
||||
} else {
|
||||
index = 2;
|
||||
}
|
||||
return build(onlyDigitsValue, index);
|
||||
}
|
||||
if (value.length === 2) {
|
||||
return value;
|
||||
}
|
||||
return build(onlyDigitsValue, 2);
|
||||
}
|
||||
function build(onlyDigitsValue, index) {
|
||||
const hours = onlyDigitsValue.slice(0, index);
|
||||
const validHours = Math.min(parseInt(hours, 10), 23);
|
||||
const minuteCharacters = onlyDigitsValue.slice(index);
|
||||
const parsedMinutes = parseInt(minuteCharacters, 10);
|
||||
const validMinutes = Math.min(parsedMinutes, 59);
|
||||
return `${validHours.toString().padStart(2, '0')}:${validMinutes.toString().padStart(2, '0')}`;
|
||||
}
|
||||
function isValidDateOrTimeValue(element, value) {
|
||||
const clone = element.cloneNode();
|
||||
clone.value = value;
|
||||
return clone.value === value;
|
||||
}
|
||||
|
||||
exports.buildTimeValue = buildTimeValue;
|
||||
exports.isValidDateOrTimeValue = isValidDateOrTimeValue;
|
||||
126
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/focus/cursor.js
generated
vendored
Normal file
126
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/focus/cursor.js
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
'use strict';
|
||||
|
||||
var isContentEditable = require('../edit/isContentEditable.js');
|
||||
var isElementType = require('../misc/isElementType.js');
|
||||
|
||||
function getNextCursorPosition(node, offset, direction, inputType) {
|
||||
// The behavior at text node zero offset is inconsistent.
|
||||
// When walking backwards:
|
||||
// Firefox always moves to zero offset and jumps over last offset.
|
||||
// Chrome jumps over zero offset per default but over last offset when Shift is pressed.
|
||||
// The cursor always moves to zero offset if the focus area (contenteditable or body) ends there.
|
||||
// When walking forward both ignore zero offset.
|
||||
// When walking over input elements the cursor moves before or after that element.
|
||||
// When walking over line breaks the cursor moves inside any following text node.
|
||||
if (isTextNode(node) && offset + direction >= 0 && offset + direction <= node.nodeValue.length) {
|
||||
return {
|
||||
node,
|
||||
offset: offset + direction
|
||||
};
|
||||
}
|
||||
const nextNode = getNextCharacterContentNode(node, offset, direction);
|
||||
if (nextNode) {
|
||||
if (isTextNode(nextNode)) {
|
||||
return {
|
||||
node: nextNode,
|
||||
offset: direction > 0 ? Math.min(1, nextNode.nodeValue.length) : Math.max(nextNode.nodeValue.length - 1, 0)
|
||||
};
|
||||
} else if (isElementType.isElementType(nextNode, 'br')) {
|
||||
const nextPlusOne = getNextCharacterContentNode(nextNode, undefined, direction);
|
||||
if (!nextPlusOne) {
|
||||
// The behavior when there is no possible cursor position beyond the line break is inconsistent.
|
||||
// In Chrome outside of contenteditable moving before a leading line break is possible.
|
||||
// A leading line break can still be removed per deleteContentBackward.
|
||||
// A trailing line break on the other hand is not removed by deleteContentForward.
|
||||
if (direction < 0 && inputType === 'deleteContentBackward') {
|
||||
return {
|
||||
node: nextNode.parentNode,
|
||||
offset: getOffset(nextNode)
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
} else if (isTextNode(nextPlusOne)) {
|
||||
return {
|
||||
node: nextPlusOne,
|
||||
offset: direction > 0 ? 0 : nextPlusOne.nodeValue.length
|
||||
};
|
||||
} else if (direction < 0 && isElementType.isElementType(nextPlusOne, 'br')) {
|
||||
return {
|
||||
node: nextNode.parentNode,
|
||||
offset: getOffset(nextNode)
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
node: nextPlusOne.parentNode,
|
||||
offset: getOffset(nextPlusOne) + (direction > 0 ? 0 : 1)
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
node: nextNode.parentNode,
|
||||
offset: getOffset(nextNode) + (direction > 0 ? 1 : 0)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
function getNextCharacterContentNode(node, offset, direction) {
|
||||
const nextOffset = Number(offset) + (direction < 0 ? -1 : 0);
|
||||
if (offset !== undefined && isElement(node) && nextOffset >= 0 && nextOffset < node.children.length) {
|
||||
node = node.children[nextOffset];
|
||||
}
|
||||
return walkNodes(node, direction === 1 ? 'next' : 'previous', isTreatedAsCharacterContent);
|
||||
}
|
||||
function isTreatedAsCharacterContent(node) {
|
||||
if (isTextNode(node)) {
|
||||
return true;
|
||||
}
|
||||
if (isElement(node)) {
|
||||
if (isElementType.isElementType(node, [
|
||||
'input',
|
||||
'textarea'
|
||||
])) {
|
||||
return node.type !== 'hidden';
|
||||
} else if (isElementType.isElementType(node, 'br')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function getOffset(node) {
|
||||
let i = 0;
|
||||
while(node.previousSibling){
|
||||
i++;
|
||||
node = node.previousSibling;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
function isElement(node) {
|
||||
return node.nodeType === 1;
|
||||
}
|
||||
function isTextNode(node) {
|
||||
return node.nodeType === 3;
|
||||
}
|
||||
function walkNodes(node, direction, callback) {
|
||||
for(;;){
|
||||
var _node_ownerDocument;
|
||||
const sibling = node[`${direction}Sibling`];
|
||||
if (sibling) {
|
||||
node = getDescendant(sibling, direction === 'next' ? 'first' : 'last');
|
||||
if (callback(node)) {
|
||||
return node;
|
||||
}
|
||||
} else if (node.parentNode && (!isElement(node.parentNode) || !isContentEditable.isContentEditable(node.parentNode) && node.parentNode !== ((_node_ownerDocument = node.ownerDocument) === null || _node_ownerDocument === undefined ? undefined : _node_ownerDocument.body))) {
|
||||
node = node.parentNode;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
function getDescendant(node, direction) {
|
||||
while(node.hasChildNodes()){
|
||||
node = node[`${direction}Child`];
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
exports.getNextCursorPosition = getNextCursorPosition;
|
||||
23
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/focus/getActiveElement.js
generated
vendored
Normal file
23
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/focus/getActiveElement.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
var isDisabled = require('../misc/isDisabled.js');
|
||||
|
||||
function getActiveElement(document) {
|
||||
const activeElement = document.activeElement;
|
||||
if (activeElement === null || activeElement === undefined ? undefined : activeElement.shadowRoot) {
|
||||
return getActiveElement(activeElement.shadowRoot);
|
||||
} else {
|
||||
// Browser does not yield disabled elements as document.activeElement - jsdom does
|
||||
if (isDisabled.isDisabled(activeElement)) {
|
||||
return document.ownerDocument ? /* istanbul ignore next */ document.ownerDocument.body : document.body;
|
||||
}
|
||||
return activeElement;
|
||||
}
|
||||
}
|
||||
function getActiveElementOrBody(document) {
|
||||
var _getActiveElement;
|
||||
return (_getActiveElement = getActiveElement(document)) !== null && _getActiveElement !== undefined ? _getActiveElement : /* istanbul ignore next */ document.body;
|
||||
}
|
||||
|
||||
exports.getActiveElement = getActiveElement;
|
||||
exports.getActiveElementOrBody = getActiveElementOrBody;
|
||||
80
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/focus/getTabDestination.js
generated
vendored
Normal file
80
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/focus/getTabDestination.js
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
'use strict';
|
||||
|
||||
var isDisabled = require('../misc/isDisabled.js');
|
||||
var isElementType = require('../misc/isElementType.js');
|
||||
var isVisible = require('../misc/isVisible.js');
|
||||
var selector = require('./selector.js');
|
||||
|
||||
function getTabDestination(activeElement, shift) {
|
||||
const document = activeElement.ownerDocument;
|
||||
const focusableElements = document.querySelectorAll(selector.FOCUSABLE_SELECTOR);
|
||||
const enabledElements = Array.from(focusableElements).filter((el)=>el === activeElement || !(Number(el.getAttribute('tabindex')) < 0 || isDisabled.isDisabled(el)));
|
||||
// tabindex has no effect if the active element has negative tabindex
|
||||
if (Number(activeElement.getAttribute('tabindex')) >= 0) {
|
||||
enabledElements.sort((a, b)=>{
|
||||
const i = Number(a.getAttribute('tabindex'));
|
||||
const j = Number(b.getAttribute('tabindex'));
|
||||
if (i === j) {
|
||||
return 0;
|
||||
} else if (i === 0) {
|
||||
return 1;
|
||||
} else if (j === 0) {
|
||||
return -1;
|
||||
}
|
||||
return i - j;
|
||||
});
|
||||
}
|
||||
const checkedRadio = {};
|
||||
let prunedElements = [
|
||||
document.body
|
||||
];
|
||||
const activeRadioGroup = isElementType.isElementType(activeElement, 'input', {
|
||||
type: 'radio'
|
||||
}) ? activeElement.name : undefined;
|
||||
enabledElements.forEach((currentElement)=>{
|
||||
const el = currentElement;
|
||||
// For radio groups keep only the active radio
|
||||
// If there is no active radio, keep only the checked radio
|
||||
// If there is no checked radio, treat like everything else
|
||||
if (isElementType.isElementType(el, 'input', {
|
||||
type: 'radio'
|
||||
}) && el.name) {
|
||||
// If the active element is part of the group, add only that
|
||||
if (el === activeElement) {
|
||||
prunedElements.push(el);
|
||||
return;
|
||||
} else if (el.name === activeRadioGroup) {
|
||||
return;
|
||||
}
|
||||
// If we stumble upon a checked radio, remove the others
|
||||
if (el.checked) {
|
||||
prunedElements = prunedElements.filter((e)=>!isElementType.isElementType(e, 'input', {
|
||||
type: 'radio',
|
||||
name: el.name
|
||||
}));
|
||||
prunedElements.push(el);
|
||||
checkedRadio[el.name] = el;
|
||||
return;
|
||||
}
|
||||
// If we already found the checked one, skip
|
||||
if (typeof checkedRadio[el.name] !== 'undefined') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
prunedElements.push(el);
|
||||
});
|
||||
for(let index = prunedElements.findIndex((el)=>el === activeElement);;){
|
||||
index += shift ? -1 : 1;
|
||||
// loop at overflow
|
||||
if (index === prunedElements.length) {
|
||||
index = 0;
|
||||
} else if (index === -1) {
|
||||
index = prunedElements.length - 1;
|
||||
}
|
||||
if (prunedElements[index] === activeElement || prunedElements[index] === document.body || isVisible.isVisible(prunedElements[index])) {
|
||||
return prunedElements[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.getTabDestination = getTabDestination;
|
||||
9
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/focus/isFocusable.js
generated
vendored
Normal file
9
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/focus/isFocusable.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
var selector = require('./selector.js');
|
||||
|
||||
function isFocusable(element) {
|
||||
return element.matches(selector.FOCUSABLE_SELECTOR);
|
||||
}
|
||||
|
||||
exports.isFocusable = isFocusable;
|
||||
20
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/focus/selection.js
generated
vendored
Normal file
20
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/focus/selection.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
var isClickableInput = require('../click/isClickableInput.js');
|
||||
var isEditable = require('../edit/isEditable.js');
|
||||
|
||||
/**
|
||||
* Determine if the element has its own selection implementation
|
||||
* and does not interact with the Document Selection API.
|
||||
*/ function hasOwnSelection(node) {
|
||||
return isElement(node) && isEditable.isEditableInputOrTextArea(node);
|
||||
}
|
||||
function hasNoSelection(node) {
|
||||
return isElement(node) && isClickableInput.isClickableInput(node);
|
||||
}
|
||||
function isElement(node) {
|
||||
return node.nodeType === 1;
|
||||
}
|
||||
|
||||
exports.hasNoSelection = hasNoSelection;
|
||||
exports.hasOwnSelection = hasOwnSelection;
|
||||
14
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/focus/selector.js
generated
vendored
Normal file
14
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/focus/selector.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
const FOCUSABLE_SELECTOR = [
|
||||
'input:not([type=hidden]):not([disabled])',
|
||||
'button:not([disabled])',
|
||||
'select:not([disabled])',
|
||||
'textarea:not([disabled])',
|
||||
'[contenteditable=""]',
|
||||
'[contenteditable="true"]',
|
||||
'a[href]',
|
||||
'[tabindex]:not([disabled])'
|
||||
].join(', ');
|
||||
|
||||
exports.FOCUSABLE_SELECTOR = FOCUSABLE_SELECTOR;
|
||||
78
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/index.js
generated
vendored
Normal file
78
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/index.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
'use strict';
|
||||
|
||||
var isClickableInput = require('./click/isClickableInput.js');
|
||||
var Blob = require('./dataTransfer/Blob.js');
|
||||
var DataTransfer = require('./dataTransfer/DataTransfer.js');
|
||||
var FileList = require('./dataTransfer/FileList.js');
|
||||
var Clipboard = require('./dataTransfer/Clipboard.js');
|
||||
var timeValue = require('./edit/timeValue.js');
|
||||
var isContentEditable = require('./edit/isContentEditable.js');
|
||||
var isEditable = require('./edit/isEditable.js');
|
||||
var maxLength = require('./edit/maxLength.js');
|
||||
var setFiles = require('./edit/setFiles.js');
|
||||
var cursor = require('./focus/cursor.js');
|
||||
var getActiveElement = require('./focus/getActiveElement.js');
|
||||
var getTabDestination = require('./focus/getTabDestination.js');
|
||||
var isFocusable = require('./focus/isFocusable.js');
|
||||
var selection = require('./focus/selection.js');
|
||||
var selector = require('./focus/selector.js');
|
||||
var readNextDescriptor = require('./keyDef/readNextDescriptor.js');
|
||||
var cloneEvent = require('./misc/cloneEvent.js');
|
||||
var findClosest = require('./misc/findClosest.js');
|
||||
var getDocumentFromNode = require('./misc/getDocumentFromNode.js');
|
||||
var getTreeDiff = require('./misc/getTreeDiff.js');
|
||||
var getWindow = require('./misc/getWindow.js');
|
||||
var isDescendantOrSelf = require('./misc/isDescendantOrSelf.js');
|
||||
var isElementType = require('./misc/isElementType.js');
|
||||
var isVisible = require('./misc/isVisible.js');
|
||||
var isDisabled = require('./misc/isDisabled.js');
|
||||
var level = require('./misc/level.js');
|
||||
var wait = require('./misc/wait.js');
|
||||
var cssPointerEvents = require('./pointer/cssPointerEvents.js');
|
||||
|
||||
|
||||
|
||||
exports.isClickableInput = isClickableInput.isClickableInput;
|
||||
exports.readBlobText = Blob.readBlobText;
|
||||
exports.createDataTransfer = DataTransfer.createDataTransfer;
|
||||
exports.getBlobFromDataTransferItem = DataTransfer.getBlobFromDataTransferItem;
|
||||
exports.createFileList = FileList.createFileList;
|
||||
exports.attachClipboardStubToView = Clipboard.attachClipboardStubToView;
|
||||
exports.createClipboardItem = Clipboard.createClipboardItem;
|
||||
exports.detachClipboardStubFromView = Clipboard.detachClipboardStubFromView;
|
||||
exports.readDataTransferFromClipboard = Clipboard.readDataTransferFromClipboard;
|
||||
exports.resetClipboardStubOnView = Clipboard.resetClipboardStubOnView;
|
||||
exports.writeDataTransferToClipboard = Clipboard.writeDataTransferToClipboard;
|
||||
exports.buildTimeValue = timeValue.buildTimeValue;
|
||||
exports.isValidDateOrTimeValue = timeValue.isValidDateOrTimeValue;
|
||||
exports.getContentEditable = isContentEditable.getContentEditable;
|
||||
exports.isContentEditable = isContentEditable.isContentEditable;
|
||||
exports.isEditable = isEditable.isEditable;
|
||||
exports.isEditableInputOrTextArea = isEditable.isEditableInputOrTextArea;
|
||||
exports.getMaxLength = maxLength.getMaxLength;
|
||||
exports.supportsMaxLength = maxLength.supportsMaxLength;
|
||||
exports.setFiles = setFiles.setFiles;
|
||||
exports.getNextCursorPosition = cursor.getNextCursorPosition;
|
||||
exports.getActiveElement = getActiveElement.getActiveElement;
|
||||
exports.getActiveElementOrBody = getActiveElement.getActiveElementOrBody;
|
||||
exports.getTabDestination = getTabDestination.getTabDestination;
|
||||
exports.isFocusable = isFocusable.isFocusable;
|
||||
exports.hasNoSelection = selection.hasNoSelection;
|
||||
exports.hasOwnSelection = selection.hasOwnSelection;
|
||||
exports.FOCUSABLE_SELECTOR = selector.FOCUSABLE_SELECTOR;
|
||||
exports.readNextDescriptor = readNextDescriptor.readNextDescriptor;
|
||||
exports.cloneEvent = cloneEvent.cloneEvent;
|
||||
exports.findClosest = findClosest.findClosest;
|
||||
exports.getDocumentFromNode = getDocumentFromNode.getDocumentFromNode;
|
||||
exports.getTreeDiff = getTreeDiff.getTreeDiff;
|
||||
exports.getWindow = getWindow.getWindow;
|
||||
exports.isDescendantOrSelf = isDescendantOrSelf.isDescendantOrSelf;
|
||||
exports.isElementType = isElementType.isElementType;
|
||||
exports.isVisible = isVisible.isVisible;
|
||||
exports.isDisabled = isDisabled.isDisabled;
|
||||
exports.ApiLevel = level.ApiLevel;
|
||||
exports.getLevelRef = level.getLevelRef;
|
||||
exports.setLevelRef = level.setLevelRef;
|
||||
exports.wait = wait.wait;
|
||||
exports.assertPointerEvents = cssPointerEvents.assertPointerEvents;
|
||||
exports.hasPointerEvents = cssPointerEvents.hasPointerEvents;
|
||||
92
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/keyDef/readNextDescriptor.js
generated
vendored
Normal file
92
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/keyDef/readNextDescriptor.js
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
'use strict';
|
||||
|
||||
var bracketDict = /*#__PURE__*/ function(bracketDict) {
|
||||
bracketDict["{"] = "}";
|
||||
bracketDict["["] = "]";
|
||||
return bracketDict;
|
||||
}(bracketDict || {});
|
||||
/**
|
||||
* Read the next key definition from user input
|
||||
*
|
||||
* Describe key per `{descriptor}` or `[descriptor]`.
|
||||
* Everything else will be interpreted as a single character as descriptor - e.g. `a`.
|
||||
* Brackets `{` and `[` can be escaped by doubling - e.g. `foo[[bar` translates to `foo[bar`.
|
||||
* A previously pressed key can be released per `{/descriptor}`.
|
||||
* Keeping the key pressed can be written as `{descriptor>}`.
|
||||
* When keeping the key pressed you can choose how long the key is pressed `{descriptor>3}`.
|
||||
* You can then release the key per `{descriptor>3/}` or keep it pressed and continue with the next key.
|
||||
*/ function readNextDescriptor(text, context) {
|
||||
let pos = 0;
|
||||
const startBracket = text[pos] in bracketDict ? text[pos] : '';
|
||||
pos += startBracket.length;
|
||||
const isEscapedChar = new RegExp(`^\\${startBracket}{2}`).test(text);
|
||||
const type = isEscapedChar ? '' : startBracket;
|
||||
return {
|
||||
type,
|
||||
...type === '' ? readPrintableChar(text, pos, context) : readTag(text, pos, type, context)
|
||||
};
|
||||
}
|
||||
function readPrintableChar(text, pos, context) {
|
||||
const descriptor = text[pos];
|
||||
assertDescriptor(descriptor, text, pos, context);
|
||||
pos += descriptor.length;
|
||||
return {
|
||||
consumedLength: pos,
|
||||
descriptor,
|
||||
releasePrevious: false,
|
||||
releaseSelf: true,
|
||||
repeat: 1
|
||||
};
|
||||
}
|
||||
function readTag(text, pos, startBracket, context) {
|
||||
var _text_slice_match, _text_slice_match1;
|
||||
const releasePreviousModifier = text[pos] === '/' ? '/' : '';
|
||||
pos += releasePreviousModifier.length;
|
||||
const escapedDescriptor = startBracket === '{' && text[pos] === '\\';
|
||||
pos += Number(escapedDescriptor);
|
||||
const descriptor = escapedDescriptor ? text[pos] : (_text_slice_match = text.slice(pos).match(startBracket === '{' ? /^\w+|^[^}>/]/ : /^\w+/)) === null || _text_slice_match === undefined ? undefined : _text_slice_match[0];
|
||||
assertDescriptor(descriptor, text, pos, context);
|
||||
pos += descriptor.length;
|
||||
var _text_slice_match_;
|
||||
const repeatModifier = (_text_slice_match_ = (_text_slice_match1 = text.slice(pos).match(/^>\d+/)) === null || _text_slice_match1 === undefined ? undefined : _text_slice_match1[0]) !== null && _text_slice_match_ !== undefined ? _text_slice_match_ : '';
|
||||
pos += repeatModifier.length;
|
||||
const releaseSelfModifier = text[pos] === '/' || !repeatModifier && text[pos] === '>' ? text[pos] : '';
|
||||
pos += releaseSelfModifier.length;
|
||||
const expectedEndBracket = bracketDict[startBracket];
|
||||
const endBracket = text[pos] === expectedEndBracket ? expectedEndBracket : '';
|
||||
if (!endBracket) {
|
||||
throw new Error(getErrorMessage([
|
||||
!repeatModifier && 'repeat modifier',
|
||||
!releaseSelfModifier && 'release modifier',
|
||||
`"${expectedEndBracket}"`
|
||||
].filter(Boolean).join(' or '), text[pos], text, context));
|
||||
}
|
||||
pos += endBracket.length;
|
||||
return {
|
||||
consumedLength: pos,
|
||||
descriptor,
|
||||
releasePrevious: !!releasePreviousModifier,
|
||||
repeat: repeatModifier ? Math.max(Number(repeatModifier.substr(1)), 1) : 1,
|
||||
releaseSelf: hasReleaseSelf(releaseSelfModifier, repeatModifier)
|
||||
};
|
||||
}
|
||||
function assertDescriptor(descriptor, text, pos, context) {
|
||||
if (!descriptor) {
|
||||
throw new Error(getErrorMessage('key descriptor', text[pos], text, context));
|
||||
}
|
||||
}
|
||||
function hasReleaseSelf(releaseSelfModifier, repeatModifier) {
|
||||
if (releaseSelfModifier) {
|
||||
return releaseSelfModifier === '/';
|
||||
}
|
||||
if (repeatModifier) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function getErrorMessage(expected, found, text, context) {
|
||||
return `Expected ${expected} but found "${found !== null && found !== undefined ? found : ''}" in "${text}"
|
||||
See ${context === 'pointer' ? `https://testing-library.com/docs/user-event/pointer#pressing-a-button-or-touching-the-screen` : `https://testing-library.com/docs/user-event/keyboard`}
|
||||
for more information about how userEvent parses your input.`;
|
||||
}
|
||||
|
||||
exports.readNextDescriptor = readNextDescriptor;
|
||||
7
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/cloneEvent.js
generated
vendored
Normal file
7
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/cloneEvent.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
function cloneEvent(event) {
|
||||
return new event.constructor(event.type, event);
|
||||
}
|
||||
|
||||
exports.cloneEvent = cloneEvent;
|
||||
14
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/findClosest.js
generated
vendored
Normal file
14
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/findClosest.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
function findClosest(element, callback) {
|
||||
let el = element;
|
||||
do {
|
||||
if (callback(el)) {
|
||||
return el;
|
||||
}
|
||||
el = el.parentElement;
|
||||
}while (el && el !== element.ownerDocument.body)
|
||||
return undefined;
|
||||
}
|
||||
|
||||
exports.findClosest = findClosest;
|
||||
10
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/getDocumentFromNode.js
generated
vendored
Normal file
10
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/getDocumentFromNode.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
function getDocumentFromNode(el) {
|
||||
return isDocument(el) ? el : el.ownerDocument;
|
||||
}
|
||||
function isDocument(node) {
|
||||
return node.nodeType === 9;
|
||||
}
|
||||
|
||||
exports.getDocumentFromNode = getDocumentFromNode;
|
||||
25
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/getTreeDiff.js
generated
vendored
Normal file
25
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/getTreeDiff.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
function getTreeDiff(a, b) {
|
||||
const treeA = [];
|
||||
for(let el = a; el; el = el.parentElement){
|
||||
treeA.push(el);
|
||||
}
|
||||
const treeB = [];
|
||||
for(let el = b; el; el = el.parentElement){
|
||||
treeB.push(el);
|
||||
}
|
||||
let i = 0;
|
||||
for(;; i++){
|
||||
if (i >= treeA.length || i >= treeB.length || treeA[treeA.length - 1 - i] !== treeB[treeB.length - 1 - i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return [
|
||||
treeA.slice(0, treeA.length - i),
|
||||
treeB.slice(0, treeB.length - i),
|
||||
treeB.slice(treeB.length - i)
|
||||
];
|
||||
}
|
||||
|
||||
exports.getTreeDiff = getTreeDiff;
|
||||
19
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/getWindow.js
generated
vendored
Normal file
19
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/getWindow.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
function getWindow(node) {
|
||||
var _node_ownerDocument;
|
||||
if (isDocument(node) && node.defaultView) {
|
||||
return node.defaultView;
|
||||
} else if ((_node_ownerDocument = node.ownerDocument) === null || _node_ownerDocument === undefined ? undefined : _node_ownerDocument.defaultView) {
|
||||
return node.ownerDocument.defaultView;
|
||||
}
|
||||
throw new Error(`Could not determine window of node. Node was ${describe(node)}`);
|
||||
}
|
||||
function isDocument(node) {
|
||||
return node.nodeType === 9;
|
||||
}
|
||||
function describe(val) {
|
||||
return typeof val === 'function' ? `function ${val.name}` : val === null ? 'null' : String(val);
|
||||
}
|
||||
|
||||
exports.getWindow = getWindow;
|
||||
14
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/isDescendantOrSelf.js
generated
vendored
Normal file
14
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/isDescendantOrSelf.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
function isDescendantOrSelf(potentialDescendant, potentialAncestor) {
|
||||
let el = potentialDescendant;
|
||||
do {
|
||||
if (el === potentialAncestor) {
|
||||
return true;
|
||||
}
|
||||
el = el.parentElement;
|
||||
}while (el)
|
||||
return false;
|
||||
}
|
||||
|
||||
exports.isDescendantOrSelf = isDescendantOrSelf;
|
||||
33
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/isDisabled.js
generated
vendored
Normal file
33
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/isDisabled.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
var isElementType = require('./isElementType.js');
|
||||
|
||||
// This should probably just rely on the :disabled pseudo-class, but JSDOM doesn't implement it properly.
|
||||
function isDisabled(element) {
|
||||
for(let el = element; el; el = el.parentElement){
|
||||
if (isElementType.isElementType(el, [
|
||||
'button',
|
||||
'input',
|
||||
'select',
|
||||
'textarea',
|
||||
'optgroup',
|
||||
'option'
|
||||
])) {
|
||||
if (el.hasAttribute('disabled')) {
|
||||
return true;
|
||||
}
|
||||
} else if (isElementType.isElementType(el, 'fieldset')) {
|
||||
var _el_querySelector;
|
||||
if (el.hasAttribute('disabled') && !((_el_querySelector = el.querySelector(':scope > legend')) === null || _el_querySelector === undefined ? undefined : _el_querySelector.contains(element))) {
|
||||
return true;
|
||||
}
|
||||
} else if (el.tagName.includes('-')) {
|
||||
if (el.constructor.formAssociated && el.hasAttribute('disabled')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
exports.isDisabled = isDisabled;
|
||||
20
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/isElementType.js
generated
vendored
Normal file
20
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/isElementType.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
function isElementType(element, tag, props) {
|
||||
if (element.namespaceURI && element.namespaceURI !== 'http://www.w3.org/1999/xhtml') {
|
||||
return false;
|
||||
}
|
||||
tag = Array.isArray(tag) ? tag : [
|
||||
tag
|
||||
];
|
||||
// tagName is uppercase in HTMLDocument and lowercase in XMLDocument
|
||||
if (!tag.includes(element.tagName.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
if (props) {
|
||||
return Object.entries(props).every(([k, v])=>element[k] === v);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
exports.isElementType = isElementType;
|
||||
19
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/isVisible.js
generated
vendored
Normal file
19
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/isVisible.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
var getWindow = require('./getWindow.js');
|
||||
|
||||
function isVisible(element) {
|
||||
const window = getWindow.getWindow(element);
|
||||
for(let el = element; el === null || el === undefined ? undefined : el.ownerDocument; el = el.parentElement){
|
||||
const { display, visibility } = window.getComputedStyle(el);
|
||||
if (display === 'none') {
|
||||
return false;
|
||||
}
|
||||
if (visibility === 'hidden') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
exports.isVisible = isVisible;
|
||||
17
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/level.js
generated
vendored
Normal file
17
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/level.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
var ApiLevel = /*#__PURE__*/ function(ApiLevel) {
|
||||
ApiLevel[ApiLevel["Trigger"] = 2] = "Trigger";
|
||||
ApiLevel[ApiLevel["Call"] = 1] = "Call";
|
||||
return ApiLevel;
|
||||
}({});
|
||||
function setLevelRef(instance, level) {
|
||||
instance.levelRefs[level] = {};
|
||||
}
|
||||
function getLevelRef(instance, level) {
|
||||
return instance.levelRefs[level];
|
||||
}
|
||||
|
||||
exports.ApiLevel = ApiLevel;
|
||||
exports.getLevelRef = getLevelRef;
|
||||
exports.setLevelRef = setLevelRef;
|
||||
14
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/wait.js
generated
vendored
Normal file
14
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/misc/wait.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
function wait(config) {
|
||||
const delay = config.delay;
|
||||
if (typeof delay !== 'number') {
|
||||
return;
|
||||
}
|
||||
return Promise.all([
|
||||
new Promise((resolve)=>globalThis.setTimeout(()=>resolve(), delay)),
|
||||
config.advanceTimers(delay)
|
||||
]);
|
||||
}
|
||||
|
||||
exports.wait = wait;
|
||||
103
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/pointer/cssPointerEvents.js
generated
vendored
Normal file
103
frontend/node_modules/@testing-library/user-event/dist/cjs/utils/pointer/cssPointerEvents.js
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
'use strict';
|
||||
|
||||
var options = require('../../options.js');
|
||||
var getWindow = require('../misc/getWindow.js');
|
||||
var isElementType = require('../misc/isElementType.js');
|
||||
var level = require('../misc/level.js');
|
||||
|
||||
function hasPointerEvents(instance, element) {
|
||||
var _checkPointerEvents;
|
||||
return ((_checkPointerEvents = checkPointerEvents(instance, element)) === null || _checkPointerEvents === undefined ? undefined : _checkPointerEvents.pointerEvents) !== 'none';
|
||||
}
|
||||
function closestPointerEventsDeclaration(element) {
|
||||
const window = getWindow.getWindow(element);
|
||||
for(let el = element, tree = []; el === null || el === undefined ? undefined : el.ownerDocument; el = el.parentElement){
|
||||
tree.push(el);
|
||||
const pointerEvents = window.getComputedStyle(el).pointerEvents;
|
||||
if (pointerEvents && ![
|
||||
'inherit',
|
||||
'unset'
|
||||
].includes(pointerEvents)) {
|
||||
return {
|
||||
pointerEvents,
|
||||
tree
|
||||
};
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
const PointerEventsCheck = Symbol('Last check for pointer-events');
|
||||
function checkPointerEvents(instance, element) {
|
||||
const lastCheck = element[PointerEventsCheck];
|
||||
const needsCheck = instance.config.pointerEventsCheck !== options.PointerEventsCheckLevel.Never && (!lastCheck || hasBitFlag(instance.config.pointerEventsCheck, options.PointerEventsCheckLevel.EachApiCall) && lastCheck[level.ApiLevel.Call] !== level.getLevelRef(instance, level.ApiLevel.Call) || hasBitFlag(instance.config.pointerEventsCheck, options.PointerEventsCheckLevel.EachTrigger) && lastCheck[level.ApiLevel.Trigger] !== level.getLevelRef(instance, level.ApiLevel.Trigger));
|
||||
if (!needsCheck) {
|
||||
return lastCheck === null || lastCheck === undefined ? undefined : lastCheck.result;
|
||||
}
|
||||
const declaration = closestPointerEventsDeclaration(element);
|
||||
element[PointerEventsCheck] = {
|
||||
[level.ApiLevel.Call]: level.getLevelRef(instance, level.ApiLevel.Call),
|
||||
[level.ApiLevel.Trigger]: level.getLevelRef(instance, level.ApiLevel.Trigger),
|
||||
result: declaration
|
||||
};
|
||||
return declaration;
|
||||
}
|
||||
function assertPointerEvents(instance, element) {
|
||||
const declaration = checkPointerEvents(instance, element);
|
||||
if ((declaration === null || declaration === undefined ? undefined : declaration.pointerEvents) === 'none') {
|
||||
throw new Error([
|
||||
`Unable to perform pointer interaction as the element ${declaration.tree.length > 1 ? 'inherits' : 'has'} \`pointer-events: none\`:`,
|
||||
'',
|
||||
printTree(declaration.tree)
|
||||
].join('\n'));
|
||||
}
|
||||
}
|
||||
function printTree(tree) {
|
||||
return tree.reverse().map((el, i)=>[
|
||||
''.padEnd(i),
|
||||
el.tagName,
|
||||
el.id && `#${el.id}`,
|
||||
el.hasAttribute('data-testid') && `(testId=${el.getAttribute('data-testid')})`,
|
||||
getLabelDescr(el),
|
||||
tree.length > 1 && i === 0 && ' <-- This element declared `pointer-events: none`',
|
||||
tree.length > 1 && i === tree.length - 1 && ' <-- Asserted pointer events here'
|
||||
].filter(Boolean).join('')).join('\n');
|
||||
}
|
||||
function getLabelDescr(element) {
|
||||
var _element_labels;
|
||||
let label;
|
||||
if (element.hasAttribute('aria-label')) {
|
||||
label = element.getAttribute('aria-label');
|
||||
} else if (element.hasAttribute('aria-labelledby')) {
|
||||
var _element_ownerDocument_getElementById_textContent, _element_ownerDocument_getElementById;
|
||||
label = (_element_ownerDocument_getElementById = element.ownerDocument.getElementById(element.getAttribute('aria-labelledby'))) === null || _element_ownerDocument_getElementById === undefined ? undefined : (_element_ownerDocument_getElementById_textContent = _element_ownerDocument_getElementById.textContent) === null || _element_ownerDocument_getElementById_textContent === undefined ? undefined : _element_ownerDocument_getElementById_textContent.trim();
|
||||
} else if (isElementType.isElementType(element, [
|
||||
'button',
|
||||
'input',
|
||||
'meter',
|
||||
'output',
|
||||
'progress',
|
||||
'select',
|
||||
'textarea'
|
||||
]) && ((_element_labels = element.labels) === null || _element_labels === undefined ? undefined : _element_labels.length)) {
|
||||
label = Array.from(element.labels).map((el)=>{
|
||||
var _el_textContent;
|
||||
return (_el_textContent = el.textContent) === null || _el_textContent === undefined ? undefined : _el_textContent.trim();
|
||||
}).join('|');
|
||||
} else if (isElementType.isElementType(element, 'button')) {
|
||||
var _element_textContent;
|
||||
label = (_element_textContent = element.textContent) === null || _element_textContent === undefined ? undefined : _element_textContent.trim();
|
||||
}
|
||||
label = label === null || label === undefined ? undefined : label.replace(/\n/g, ' ');
|
||||
if (Number(label === null || label === undefined ? undefined : label.length) > 30) {
|
||||
label = `${label === null || label === undefined ? undefined : label.substring(0, 29)}…`;
|
||||
}
|
||||
return label ? `(label=${label})` : '';
|
||||
}
|
||||
// With the eslint rule and prettier the bitwise operation isn't nice to read
|
||||
function hasBitFlag(conf, flag) {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return (conf & flag) > 0;
|
||||
}
|
||||
|
||||
exports.assertPointerEvents = assertPointerEvents;
|
||||
exports.hasPointerEvents = hasPointerEvents;
|
||||
Reference in New Issue
Block a user