Jsdom: Machen Sie eine Methode zum Hinzufügen von Dateien zu einer FileList . verfügbar

Erstellt am 23. Okt. 2015  ·  30Kommentare  ·  Quelle: jsdom/jsdom

FileLists sind in den Spezifikationen nicht schreibbar, aber um input.files testbar zu machen, müssen wir eine util-Methode implementieren, um sie zu modifizieren.

/cc @cpojer

feature

Hilfreichster Kommentar

Ich habe es geschafft, FileList zu erstellen, ohne den Code der jsdom-Bibliothek ändern zu müssen:

const createFile = (size = 44320, name = 'ecp-logo.png', type = 'image/png') =>
  new File([new ArrayBuffer(size)], name , {
    type: type,
  });

const createFileList = (file) => {
  const fileList = new FileList();
  fileList[0] = file;
  return fileList;
}

const fileList = createFileList(createFile());

In diesem Fall erstelle ich ein FileList-Objekt, das den Konstruktor auf FileList aufruft, das von jsdom bereitgestellt wird. Danach füge ich dieser Liste nur eine Datei mit der Array-Notation hinzu. In meinem Fall benötige ich nur 1 Datei im Array, aber dies kann auch in eine for-Schleife geändert werden, um mehrere Dateien zu FileList hinzuzufügen. Ich erstelle eine Datei mit benutzerdefiniertem Namen / Typ / Größe über den Dateikonstruktor, der ebenfalls von jsdom bereitgestellt wird, dessen Funktionalität der Spezifikation folgt.

Dies könnte für jemanden hilfreich sein, der FileList in einer jsdom-Umgebung nachahmt, aber ein Problem besteht immer noch. Das Erstellen von FileList mit einem Array von Dateien mit dieser Methode würde es nicht erlauben, Elemente aus dem Array mit der Methode FileList.item(index) abzurufen. Aber selbst das kann behoben werden, indem die Methode wie folgt überschrieben wird:

const createFileList = (file) => {
  const fileList = new FileList();
  fileList[0] = file;
  fileList.item = index => fileList[index]; // override method functionality
  return fileList;
}

Ich denke immer noch, dass es vielleicht besser wäre, wenn jsdom diese Funktionalitäten zu Testzwecken out of the box anbieten könnte.

Alle 30 Kommentare

input.files = createFileList(file1, file2, ...) wäre nett.

@cpojer Generieren Sie tatsächliche File Objekte, um sie dort einzufügen ?

input.files schreibbar zu machen ist wahrscheinlich schlecht, wir können wahrscheinlich entweder das rohe Array zurückgeben, um sich selbst zu füllen, oder etwas wie fillFileList(input.files, [file]) tun.

Wir verwenden eigentlich nur Scheindaten, also füllen wir .files mit einem Array von Objekten. Aber ich denke, es wäre vernünftig, es als File-Objekt zu verlangen.

Es scheint, als ob defineProperty hier in Ordnung wäre? DOM-Eigenschaften sind aus einem bestimmten Grund rekonfigurierbar...

Ich würde jedoch viel lieber eine echte FileList mit echten Daten erstellen.

Es sollte auch möglich sein, auf FileList-Elemente über ihre Array-Indizes zuzugreifen. .item ist nicht die einzige Möglichkeit, auf ihre Felder zuzugreifen.

OK, es hört sich also so an, als ob es ein paar potenzielle Probleme gibt:

  • FileList funktioniert nicht ordnungsgemäß indizierter Zugriff (Fehler)
  • Es gibt keine Möglichkeit, FileList-Objekte zum Testen zu erstellen (Webplattform-Feature-Lücke).

Aber das Ändern von inputEl.files ist nicht das Problem.

Ja, ich meine, es ist nicht großartig, Ingenieuren zu sagen, dass sie Object.defineProperty über eine normale Aufgabe verwenden sollen, aber ich kann damit leben.

Nun, das müssen sie sowieso in einem echten Browser machen, also scheint es mir vernünftig...

Hallo, wie ich sehe, ist dies über ein Jahr alt, ich würde gerne fragen, ob es bezüglich dieses Problems Fortschritte gibt? Ich verwende das Jest-Framework, um meine React/Redux-App zu testen, die intern jsdom verwendet. Ich habe ein Problem, bei dem ich FileList mit einem oder mehreren File-Objekten dynamisch erstellen muss.

Wenn ich mir lib/jsdom/living/filelist.js ansehe, kann ich sehen, dass es einen Konstruktor für FileList gibt, aber es gibt keine Möglichkeit, Dateien an ihn zu übergeben. Ich verstehe, dass FileList und File aus Sicherheitsgründen keinen Konstruktor gemäß den Spezifikationen haben, aber gibt es die Absicht, dem Konstruktor zu erlauben, ein Array von File-Objekten oder zumindest eine zusätzliche Methode (sagen wir _setItem_) zu akzeptieren, die es uns ermöglichen würde, Datei hinzuzufügen? Objekte speziell zu Testzwecken in die Liste aufnehmen?

Ich sehe auch ein anderes Problem mit FileList. Wenn ich mich nicht irre, sollte es sich um ein Array-ähnliches Objekt handeln, genau wie NodeList (lib/jsdom/living/node-list.js), was bedeutet, dass es eine Möglichkeit geben sollte, auf Dateiobjekte auf zwei Arten zuzugreifen:

var fileList = document.getElementById("myfileinput").files;

fileList[0];
fileList.item(0);

Derzeit ist der Zugriff nur über die Methode möglich. Dies bedeutet, dass hier dieselbe Logik wie in NodeList angewendet werden sollte:

FileList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

und Dateien sollten in etwa wie folgt gespeichert werden, wenn wir ein Array von Dateien an den Konstruktor übergeben würden:

for (let i = 0; i < files.length; ++i) {
  this[i] = files[i];
}

Ich habe keine starke Meinung dazu, wie dies gemacht werden sollte, dies sind nur Beispiele, die ich verwende, um besser zu erklären, was ich versuche, darauf hinzuweisen.

Zusätzliche Fragen (ich möchte keine unnötigen Fragen öffnen, bevor ich hier frage):

1.) Wäre es von Vorteil, den Dateikonstruktor zu Testzwecken hinzuzufügen, der ein Dateiobjekt aus einer tatsächlichen Datei erstellt, wobei der Pfad als Zeichenfolge bereitgestellt wird? Ich habe eine Bibliothek gefunden (Entschuldigung, ich kann keinen Link mehr finden), die dies erlaubt:

const file = new File('../fixtures/files/test-image.png');

Diese hat für mich eine Datei mit Eigenschaften (Größe, LastModified, Typ ...) erstellt, ohne dass ich sie manuell erstellen muss:

const file = new File([''], 'test-image.png', {
  lastModified: 1449505890000,
  lastModifiedDate: new Date(1449505890000),
  name: "ecp-logo.png",
  size: 44320,
  type: "image/png",
});

Ich weiß nicht, wie diese Bibliothek funktioniert hat, ich weiß nur, dass sie über ein Jahr lang nicht gepflegt wurde und wir sie nicht mehr verwenden. Ich kann es anscheinend nicht mehr finden.

2.) window.URL.createObjectURL wird von jsdom nicht unterstützt. Nicht sicher, ob es gemeldet werden soll.

Ich habe es geschafft, FileList zu erstellen, ohne den Code der jsdom-Bibliothek ändern zu müssen:

const createFile = (size = 44320, name = 'ecp-logo.png', type = 'image/png') =>
  new File([new ArrayBuffer(size)], name , {
    type: type,
  });

const createFileList = (file) => {
  const fileList = new FileList();
  fileList[0] = file;
  return fileList;
}

const fileList = createFileList(createFile());

In diesem Fall erstelle ich ein FileList-Objekt, das den Konstruktor auf FileList aufruft, das von jsdom bereitgestellt wird. Danach füge ich dieser Liste nur eine Datei mit der Array-Notation hinzu. In meinem Fall benötige ich nur 1 Datei im Array, aber dies kann auch in eine for-Schleife geändert werden, um mehrere Dateien zu FileList hinzuzufügen. Ich erstelle eine Datei mit benutzerdefiniertem Namen / Typ / Größe über den Dateikonstruktor, der ebenfalls von jsdom bereitgestellt wird, dessen Funktionalität der Spezifikation folgt.

Dies könnte für jemanden hilfreich sein, der FileList in einer jsdom-Umgebung nachahmt, aber ein Problem besteht immer noch. Das Erstellen von FileList mit einem Array von Dateien mit dieser Methode würde es nicht erlauben, Elemente aus dem Array mit der Methode FileList.item(index) abzurufen. Aber selbst das kann behoben werden, indem die Methode wie folgt überschrieben wird:

const createFileList = (file) => {
  const fileList = new FileList();
  fileList[0] = file;
  fileList.item = index => fileList[index]; // override method functionality
  return fileList;
}

Ich denke immer noch, dass es vielleicht besser wäre, wenn jsdom diese Funktionalitäten zu Testzwecken out of the box anbieten könnte.

Hallo Leute ,
Ich habe ein Problem beim Verspotten des $("#selectorID of Upload file")[0].files[0]-Objekts, das FileList zurückgibt.
Kann mir jemand helfen, ein FileList-Objekt zu erstellen? Weil ich nirgendwo im WWW einen Referenzlink finden kann

Es ist derzeit nicht möglich.

Danke Domenik,

Ich muss einen Testfall für das Änderungsereignis Datei-Upload schreiben. jede andere Möglichkeit, dieses Testszenario auszuführen.

Gibt es diesbezüglich Fortschritte?

@niksajanjic Haben Sie es geschafft, die beste Lösung in diesem Thread zu implementieren?
Ref: const file = new File('../fixtures/files/test-image.png');
Oder so ähnlich?
Am besten

@domenic Scheint in diesem Twitter-Post zu diesem Thema ein wenig abweichend zu sein

@domenic Ok, ich habe den grundlegenden Start dafür eingerichtet. Es sind nicht alle Schecks vorhanden, aber im Wesentlichen hat @niksajanjic davon gesprochen.

erstelle Datei

function createFile(file_path) {
  const { mtimeMs: lastModified, size } = fs.statSync(file_path)

  return new File(
    [new fs.readFileSync(file_path)],
    path.basename(file_path),
    {
      lastModified,
      type: mime.lookup(file_path) || '',
    }
  )
}

Dateiliste hinzufügen

function addFileList(input, file_paths) {
  if (typeof file_paths === 'string')
    file_paths = [file_paths]
  else if (!Array.isArray(file_paths)) {
    throw new Error('file_paths needs to be a file path string or an Array of file path strings')
  }

  const file_list = file_paths.map(fp => createFile(fp))
  file_list.__proto__ = Object.create(FileList.prototype)

  Object.defineProperty(input, 'files', {
    value: file_list,
    writeable: false,
  })

  return input
}

Demo-Datei

/*eslint-disable no-console, no-unused-vars */

/*
https://github.com/jsdom/jsdom/issues/1272
*/

const fs = require('fs')
const path = require('path')
const mime = require('mime-types')

const { JSDOM } = require('jsdom')
const dom = new JSDOM(`
<!DOCTYPE html>
<body>
  <input type="file">
</body>
`)

const { window } = dom
const { document, File, FileList } = window


const file_paths = [
  '/Users/williamrusnack/Documents/form_database/test/try-input-file.html',
  '/Users/williamrusnack/Documents/form_database/test/try-jsdom-input-file.js',
]

function createFile(file_path) {
  const { mtimeMs: lastModified, size } = fs.statSync(file_path)

  return new File(
    [new fs.readFileSync(file_path)],
    path.basename(file_path),
    {
      lastModified,
      type: mime.lookup(file_path) || '',
    }
  )
}

function addFileList(input, file_paths) {
  if (typeof file_paths === 'string')
    file_paths = [file_paths]
  else if (!Array.isArray(file_paths)) {
    throw new Error('file_paths needs to be a file path string or an Array of file path strings')
  }

  const file_list = file_paths.map(fp => createFile(fp))
  file_list.__proto__ = Object.create(FileList.prototype)

  Object.defineProperty(input, 'files', {
    value: file_list,
    writeable: false,
  })

  return input
}



const input = document.querySelector('input')

addFileList(input, file_paths)

for (let i = 0; i < input.files.length; ++i) {
  const file = input.files[i]
  console.log('file', file)
  console.log('file.name', file.name)
  console.log('file.size', file.size)
  console.log('file.type', file.type)
  console.log('file.lastModified', file.lastModified)
  console.log()
}

@BebeSparkelSparkel Ich habe den Test so gemacht, wie ich es in meinem späteren Beitrag dort oben erklärt habe. Leider funktionierte es einige Monate später nicht mehr mit neueren Versionen von jsdom, als einer meiner Kollegen versuchte, diesen Code zu kopieren. Also mussten wir die Tests für FileList zu diesem Zeitpunkt auskommentieren. Von da an fanden wir keinen Weg, diese Tests zu schreiben und in den letzten Monaten hatte niemand die Zeit, sich das noch einmal anzusehen und zu versuchen, einen Weg zu finden.

@niksajanjic Danke für dein Update. Ich arbeite an der Lösung, die Sie vorgeschlagen haben, und sie scheint zu funktionieren (siehe Code oben), aber ich halte es für unwahrscheinlich, dass sie zu jsdom hinzugefügt wird, da es sehr schwierig wäre, herauszufinden, wie sie hinzugefügt wird.
Schaut doch gerne mal rein und nutzt es wenn ihr wollt

Erstellt ein einfaches Hilfsskript, das dieses Problem löst, bis das jsdom-Projekt eine Lösung findet.
https://bitbucket.org/william_rusnack/addfilelist/src/master/

Fügen Sie eine Datei hinzu:

const input = document.querySelector('input[type=file]')
addFileList(input, 'path/to/file')

Mehrere Dateien hinzufügen:

const input = document.querySelector('input[type=file]')
addFileList(input, [
  'path/to/file',
  'path/to/another/file',
  // add as many as you want
])

Installieren und benötigen

npm install https://github.com/BebeSparkelSparkel/addFileList.git

```javascript
const { addFileList } = require('addFileList')

## Functions
**addFileList**(input, file_paths)  
Effects: puts the file_paths as File object into input.files as a FileList  
Returns: input  
Arguments:  
- input: HTML input element  
- file_paths: String or Array of string file paths to put in input.files  
`const { addFileList } = require('addFileList')`  

## Example
Extract from example.js
```javascript
// add a single file
addFileList(input, 'example.js')

// log input's FileList
console.log(input.files)

// log file properties
const [ file ] = input.files
console.log(file)
console.log(
  '\nlastModified', file.lastModified,
  '\nname', file.name,
  '\nsize', file.size,
  '\ntype', file.type,
  '\n'
)

Ergebnis

$ node example.js 
FileList [ File {} ]
File {}

lastModified 1518523506000 
name example.js 
size 647 
type application/javascript 

@BebeSparkelSparkel Ihr Repo scheint gelöscht worden zu sein?

Ich hatte ein ähnliches Problem – ich habe eine Funktion geschrieben, die FileList als Eingabe akzeptiert, und wollte mit jest einen Komponententest dafür schreiben. Ich war in der Lage, die folgende Hilfsfunktion zu verwenden, um ein FileList Objekt genug zu fälschen, um mit meiner Funktion zu arbeiten. Syntax ist ES6 mit Flow-Anmerkungen. Keine Versprechungen, dass es in allen Situationen funktioniert, da es nur die Funktionalität der echten FileList Klasse vortäuscht…

const createFileList = (files: Array<File>): FileList => {
  return {
    length: files.length,
    item: (index: number) => files[index],
    * [Symbol.iterator]() {
      for (let i = 0; i < files.length; i++) {
        yield files[i];
      }
    },
    ...files,
  };
};

Im Frontend kann ich Folgendes tun, um (umgangssprachlich) ein 'echtes' FileList konstruieren:

export const makeFileList = files => {
  const reducer = (dataTransfer, file) => {
    dataTransfer.items.add(file)
    return dataTransfer
  }

  return files.reduce(reducer, new DataTransfer()).files
}

Ref: https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer

Leider scheint jsdom DataTransfer noch nicht wirklich zu unterstützen, daher funktioniert dies in meinen Tests nicht:

Andere Referenzen:


Als ich die Quelle ein wenig durchsuchte, fand ich exports.FileList = require("./generated/FileList").interface;

~Aber es war mir von GitHub nicht klar, wo ich die Quelle finden sollte, die letztendlich ./generated ~

Der Hauptexport des npm-Pakets ist ./lib/api.js und exportiert eine sehr kleine öffentliche API:

exports.JSDOM = JSDOM;
exports.VirtualConsole = VirtualConsole;
exports.CookieJar = CookieJar;
exports.ResourceLoader = ResourceLoader;
exports.toughCookie = toughCookie;

Aber wenn ich in meinem ./node_modules/jsdom/lib/jsdom Verzeichnis schaue, kann ich sehen, dass auch alle internen / Implementierungsdateien vorhanden sind, einschließlich ./node_modules/jsdom/lib/jsdom/living/file-api :

Blob-impl.js  File-impl.js  FileList-impl.js  FileReader-impl.js

FileList-impl.js enthält hier die eigentliche JS-Implementierung, die die exponierte FileList API in jsdom unterstützt.

Wenn wir uns jetzt ./node_modules/jsdom/lib/jsdom/living/generated/FileList.js ansehen, sehen wir die tatsächlich generierte "öffentliche API", die wir bei normaler Nutzung sehen, einschließlich unserer nur allzu vertrauten:

class FileList {
  constructor() {
    throw new TypeError("Illegal constructor");
  }

Diese Datei exportiert module.exports = iface; , das viel mehr Funktionalität enthält als das, was wir durch die 'normale' öffentliche API-Exponierung erhalten, die nur den iface.interface Schlüssel verwendet. Vielleicht könnten wir also etwas Lustiges machen, wenn wir require("./generated/FileList") direkt verwenden. Wenn wir die Implementierungsdetails entfernen, haben wir eine Schnittstelle, die ungefähr so ​​​​aussieht:

const iface = {
  _mixedIntoPredicates: [],
  is(obj) {..snip..},
  isImpl(obj) {..snip..},
  convert(obj, { context = "The provided value" } = {}) {..snip..},
  create(constructorArgs, privateData) {..snip..},
  createImpl(constructorArgs, privateData) {..snip..},
  _internalSetup(obj) {},
  setup(obj, constructorArgs, privateData) {...snip...},
  interface: FileList,
  expose: {
    Window: { FileList },
    Worker: { FileList }
  }
}; // iface

Jetzt, da wir wissen, dass es mehr Macht gibt, sehen wir uns an, wie andere Bereiche von jsdom zugreifen.

Wenn wir uns HTMLInputElement-impl ansehen, scheint es FileList.createImpl() , obwohl es uns leider nicht zeigt, wie die Parameter verwendet werden:

createImpl ist nur ein kleiner Wrapper um setup im exportierten iface :

createImpl(constructorArgs, privateData) {
    let obj = Object.create(FileList.prototype);
    obj = this.setup(obj, constructorArgs, privateData);
    return utils.implForWrapper(obj);
  },

Wenn wir damit in einer Konsole herumspielen, scheint es, als hätten wir die ausdrucksstarke API des Array Elements, von dem FileListImpl unterstützt wird. So können wir Dinge tun wie:

var flist = require('./node_modules/jsdom/lib/jsdom/living/generated/FileList.js')
var myFileListImpl = flist.createImpl()
myFileListImpl.push('aa')

Es hat eine Symbol(wrapper) Eigenschaft, auf die wir mit ./node_modules/jsdom/lib/jsdom/living/generated/utils.js:37 zugreifen müssen:

var utils = require('./node_modules/jsdom/lib/jsdom/living/generated/utils.js')
var wrapper = myFileListImpl[utils.wrapperSymbol]

Das exportierte iface hat eine Funktion convert , die throw new TypeError( ${context} nicht vom Typ 'FileList' ist. ); wenn das bereitgestellte Objekt kein FileList . Wir können dies verwenden, um Dinge zu testen.

Wenn wir es im Rohformat myFileListImpl aufrufen, wird der Fehler ausgegeben:

flist.convert(myFileListImpl)

Während wir das oben extrahierte wrapper , können wir sehen, dass es den Fehler nicht auslöst:

flist.convert(myFileListImpl[utils.wrapperSymbol])

Damit können wir myFileListImpl modifizieren und erhalten ein akzeptables FileList Objekt zurück, um es dorthin zu übergeben, wo wir es brauchen. Ein vollständig funktionierendes Beispiel (mit util.wrapperForImpl() anstelle unseres vorherigen Codes):

var _FileList = require('./node_modules/jsdom/lib/jsdom/living/generated/FileList.js')
var utils = require('./node_modules/jsdom/lib/jsdom/living/generated/utils.js')

var myMutableFileListImpl = _FileList.createImpl()

myMutableFileListImpl.length // 0
myMutableFileListImpl.push(new File([], 'a.jpg'))
myMutableFileListImpl.length // 1

var myFileList = utils.wrapperForImpl(myMutableFileListImpl)
_FileList.convert(myFileList) // no error

myFileList.length // 1
myFileList[0] // the File{} object

Mit diesem Wissen kann ich jetzt die jsdom-Testversion meines ursprünglichen Browser-Workaround-Hack implementieren (der aus Gründen der Faulheit zusätzlich zu ImmutableJS implementiert wurde):

import { Map, Record } from 'immutable'

import jsdomFileList from 'jsdom/lib/jsdom/living/generated/FileList'
import { wrapperForImpl } from 'jsdom/lib/jsdom/living/generated/utils'

// Note: relying on internal API's is super hacky, and will probably break
// As soon as we can, we should use whatever the proper outcome from this issue is:
//   https://github.com/jsdom/jsdom/issues/1272#issuecomment-486088445

export const makeFileList = files => {
  const reducer = (fileListImpl, file) => {
    fileListImpl.push(file)
    return fileListImpl
  }

  const fileListImpl = files.reduce(reducer, jsdomFileList.createImpl())

  return wrapperForImpl(fileListImpl)
}

export class DataTransferStub extends Record({ items: Map() }) {
  get files() {
    return makeFileList(this.items.toList().toArray())
  }
}

export const stubGlobalDataTransfer = () => {
  global.DataTransfer = DataTransferStub
}

export const restoreGlobalDataTransfer = () => {
  global.DataTransfer = undefined
}

Und dann manuell mit meinen globalen Vars verbinden, damit meine Ava- Tests es verwenden können:

import {
  restoreGlobalDataTransfer,
  stubGlobalDataTransfer,
} from ../helpers/jsdom-helpers'

test.before(t => {
  stubGlobalDataTransfer()
})

test.after(t => {
  restoreGlobalDataTransfer()
})

Alle modernen Browser (dh nicht IE <= 11) unterstützen jetzt das Setzen von input.files auf eine FileList https://stackoverflow.com/a/47522812/2744776

Dies scheint sich in einer neueren Version geändert zu haben. Folgendes hat bei mir funktioniert:

const jsdomUtils = require('jsdom/lib/jsdom/living/generated/utils');
const jsdomFileList = require('jsdom/lib/jsdom/living/generated/FileList');
function makeFileList(...files) {
    const impl = jsdomFileList.createImpl(window);
    const ret = Object.assign([...files], {
        item: (ix) => ret[ix],
        [jsdomUtils.implSymbol]: impl,
    });
    impl[jsdomUtils.wrapperSymbol] = ret;
    Object.setPrototypeOf(ret, FileList.prototype);
    return ret;
}

Wenn Sie JSDOM über Jest verwenden, müssen Sie sicherstellen, dass die Interna außerhalb der Test-VM erforderlich sind. Ich habe eine benutzerdefinierte Testumgebung wie folgt erstellt:

const JsdomEnvironment = require('jest-environment-jsdom');

/** See jsdom/jsdom#1272 */
class EnvWithSyntheticFileList extends JsdomEnvironment {
    async setup() {
        await super.setup();
        this.global.jsdomUtils = require('jsdom/lib/jsdom/living/generated/utils');
        this.global.jsdomFileList = require('jsdom/lib/jsdom/living/generated/FileList');
    }
}

module.exports = EnvWithSyntheticFileList;

Damit ich auf die 'äußeren' Importe zugreifen konnte.

Dies scheint sich in einer neueren Version geändert zu haben. Folgendes hat bei mir funktioniert:

const jsdomUtils = require('jsdom/lib/jsdom/living/generated/utils');
const jsdomFileList = require('jsdom/lib/jsdom/living/generated/FileList');
function makeFileList(...files) {
    const impl = jsdomFileList.createImpl(window);
    const ret = Object.assign([...files], {
        item: (ix) => ret[ix],
        [jsdomUtils.implSymbol]: impl,
    });
    impl[jsdomUtils.wrapperSymbol] = ret;
    Object.setPrototypeOf(ret, FileList.prototype);
    return ret;
}

Wenn Sie JSDOM über Jest verwenden, müssen Sie sicherstellen, dass die Interna außerhalb der Test-VM erforderlich sind. Ich habe eine benutzerdefinierte Testumgebung wie folgt erstellt:

const JsdomEnvironment = require('jest-environment-jsdom');

/** See jsdom/jsdom#1272 */
class EnvWithSyntheticFileList extends JsdomEnvironment {
    async setup() {
        await super.setup();
        this.global.jsdomUtils = require('jsdom/lib/jsdom/living/generated/utils');
        this.global.jsdomFileList = require('jsdom/lib/jsdom/living/generated/FileList');
    }
}

module.exports = EnvWithSyntheticFileList;

Damit ich auf die 'äußeren' Importe zugreifen konnte.

Das hat mich nahe gebracht, aber ich komme nicht über die interne Validierung hinaus:

exports.is = Wert => {
return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
};

TypeError: Fehler beim Festlegen der 'files'-Eigenschaft für 'HTMLInputElement': Der bereitgestellte Wert ist nicht vom Typ 'FileList'.

Stunden verbracht. Super frustrierend

Dies scheint sich in einer neueren Version geändert zu haben. Folgendes hat bei mir funktioniert:

const jsdomUtils = require('jsdom/lib/jsdom/living/generated/utils');
const jsdomFileList = require('jsdom/lib/jsdom/living/generated/FileList');
function makeFileList(...files) {
    const impl = jsdomFileList.createImpl(window);
    const ret = Object.assign([...files], {
        item: (ix) => ret[ix],
        [jsdomUtils.implSymbol]: impl,
    });
    impl[jsdomUtils.wrapperSymbol] = ret;
    Object.setPrototypeOf(ret, FileList.prototype);
    return ret;
}

Wenn Sie JSDOM über Jest verwenden, müssen Sie sicherstellen, dass die Interna außerhalb der Test-VM erforderlich sind. Ich habe eine benutzerdefinierte Testumgebung wie folgt erstellt:

const JsdomEnvironment = require('jest-environment-jsdom');

/** See jsdom/jsdom#1272 */
class EnvWithSyntheticFileList extends JsdomEnvironment {
    async setup() {
        await super.setup();
        this.global.jsdomUtils = require('jsdom/lib/jsdom/living/generated/utils');
        this.global.jsdomFileList = require('jsdom/lib/jsdom/living/generated/FileList');
    }
}

module.exports = EnvWithSyntheticFileList;

Damit ich auf die 'äußeren' Importe zugreifen konnte.

Das hat mich nahe gebracht, aber ich komme nicht über die interne Validierung hinaus:

exports.is = Wert => {
return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
};

TypeError: Fehler beim Festlegen der 'files'-Eigenschaft für 'HTMLInputElement': Der bereitgestellte Wert ist nicht vom Typ 'FileList'.

Stunden verbracht. Super frustrierend

Nachdem ich wieder mit einem frischen Gehirn angefangen hatte, fand ich das Problem. Irgendwie hatte ich 2 separate jsdom-Umgebungen am Laufen, die die Verweise auf Symbole verworfen haben.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen