web-dev-qa-db-fra.com

Se moquer de `document` en plaisanterie

J'essaie d'écrire des tests pour mes projets de composants Web en plaisantant. J'utilise déjà babel avec es2015 preset. Je suis confronté à un problème lors du chargement du fichier js. J'ai suivi un morceau de code où l'objet document a un objet currentScript. Mais dans le contexte du test, il est null. Alors je pensais me moquer de la même chose. Mais jest.fn() ne vous aide pas vraiment. Comment puis-je gérer ce problème?

Morceau de code où la plaisanterie échoue.

var currentScriptElement = document._currentScript || document.currentScript;
var importDoc = currentScriptElement.ownerDocument;

Cas de test que j'ai écrit. component.test.js

import * as Component from './sample-component.js';

describe('component test', function() {
  it('check instance', function() {
    console.log(Component);
    expect(Component).toBeDefined();
  });
});

Voici l'erreur lancée par la plaisanterie

Test suite failed to run

    TypeError: Cannot read property 'ownerDocument' of null

      at src/components/sample-component/sample-component.js:4:39

Mise à jour: Comme suggéré par Andreas Köberle, j’ai ajouté quelques vars globaux et essayé de me moquer comme suit

__DEV__.document.currentScript = document._currentScript = {
  ownerDocument: ''
};
__DEV__.window = {
  document: __DEV__.document
}
__DEV__.document.registerElement = jest.fn();

import * as Component from './arc-sample-component.js';

describe('component test', function() {
  it('check instance', function() {
    console.log(Component);
    expect(Component).toBeDefined();
  });
});

Mais pas de chance

Mise à jour: J'ai essayé le code ci-dessus sans __dev__. Également en définissant le document comme global.

18
thecodejack

J'ai résolu ceci en utilisant la propriété setUpFiles en plaisanterie. Cela fonctionnera après jsdom et avant chaque test, ce qui est parfait pour moi.

Définissez setupFiles, dans Jest config, par exemple:

"setupFiles": ["<rootDir>/browserMock.js"]


// browserMock.js
Object.defineProperty(document, 'currentScript', {
  value: document.createElement('script'),
});

La situation idéale serait de charger webcomponents.js pour polyfill le jsdom.

10
thecodejack

Semblable à ce que d'autres ont dit, mais au lieu d'essayer de vous moquer du DOM vous-même, utilisez simplement JSDOM:

__mocks __/client.js

import { JSDOM } from "jsdom"
const dom = new JSDOM()
global.document = dom.window.document
global.window = dom.window

Puis dans votre config de plaisanterie:

"setupFiles": [
  "./__mocks__/client.js"
],
5

Je pouvais résoudre ce même problème en utilisant le module global scope sur nodejs, en mettant un document avec un modèle de document, dans mon cas, getElementsByClassName

// My simple mock file
export default {
    getElementsByClassName: () => {
        return [{
            className: 'welcome'
        }]
    }
};

// Your test file
import document from './name.component.mock.js';
global.document = {
    getElementsByClassName: document.getElementsByClassName
};
2
Renato B.

Si, comme moi, vous cherchez à transformer un document en document non défini (par exemple, pour les tests côté serveur/côté client), j'ai été en mesure d'utiliser object.defineProperty dans mes suites de tests sans devoir utiliser setupFiles

Exemple:

beforeAll(() => {
  Object.defineProperty(global, 'document', {});
})
1
tctc91

Si vous devez définir des valeurs de test pour les propriétés, il existe une approche légèrement plus granulaire. Chaque propriété doit être définie individuellement et il est également nécessaire de rendre les propriétés writeable:

Object.defineProperty(window.document, 'URL', {
  writable: true,
  value: 'someurl'
});

Voir: https://github.com/facebook/jest/issues/890

Cela a fonctionné pour moi en utilisant Jest 21.2.1 et Node v8.11.1

0
theUtherSide

Je me suis battu avec le document moqueur pour un projet sur lequel je suis. J'appelle document.querySelector() dans un composant React et je dois m'assurer qu'il fonctionne correctement. En fin de compte, c’est ce qui a fonctionné pour moi:

it('should test something', () => {
    const spyFunc = jest.fn();
    Object.defineProperty(global.document, 'querySelector', { value: spyFunc });
    <run some test>
    expect(spyFunc).toHaveBeenCalled()
});
0
strausd