

JESTフレームワークでテストを実施したいです。  
[JESTドキュメント](https://jestjs.io/docs/ja/tutorial-
jquery)では下のように`document.body.innerHTML`によってHTMLを書き込んでいます。  
`document.body.innerHTML`を使わずに、外部のHTMLファイルをそのまま参照する方法はないのでしょうか。

[code]

    // Set up our document body
    document.body.innerHTML =
      '<div>' +
      '  <span id="username" />' +
      '  <button id="button" />' +
      '</div>';
    
[/code]

* * *

I'd like to find the way to read HTML file in JavaScript file.  
For example, in <https://jestjs.io/docs/ja/tutorial-jquery>, we directly write
some HTML contents like above.

But I'd like to read one HTML file, instead of `document.body.innerHTML`.


CC BY-SA 4.0
2020-03-16T14:36:11.877
63905
2020-05-26T15:50:20.507
2020-05-26T15:50:20.507
7997
38239
question
javascript html jestjs
外部のHTMLファイルをjestで読み込む方法


存在します。

## 構造

ディレクトリ構成を次のようにします。

[code]

    .
    ├── src/__tests__
    │   ├── index.test.ts
    │   └── index.html
    └── jest.config.js
    
[/code]

### パッケージ類

[code]

    yarn add -D jest jsdom jquery
    
[/code]

### jest.config.js

[code]

    module.exports = {
      "automock": false,
      "unmockedModulePathPatterns": ["<rootDir>/node_modules/*"],
      "moduleDirectories": ["node_modules"],
      "moduleFileExtensions": ["js", "jsx", "node"],
      "testMatch": ["**/__tests__/*.test.+(js|jsx)"],
      "collectCoverage": true
    };
    
[/code]

### index.html

[code]

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>jest document</title>
    </head>
    <body>
      <h1 class="title">hello world</h1>
    </body>
    </html>
    
[/code]

## 方法1

1つ目の方法は、`fs`ライブラリを利用することです。

[code]

    // index.test.ts
    const fs = require("fs");
    
    // もしbody要素だけであれば
    document.body.innerHTML = fs.readFileSync(__dirname + "/index.html", { encoding: "utf-8" }); 
    
    // <head>タグ内の要素も変更したい場合
    document.querySelector("html").innerHTML = fs.readFileSync(__dirname + "/index.html", { encoding: "utf-8" });
    
[/code]

とやればよいでしょう。ただし、今回の質問は明確に `document.body.innerHTML` を使わずにとあるので、方法2を紹介します。

## 方法2

[ドキュメント](https://jestjs.io/docs/ja/tutorial-
jquery)の下部にあるように、Jest内部では[JSDOM](https://github.com/jsdom/jsdom)を利用してDOMをManupulationしています。  
つまり、JSDOMのAPIを利用すれば今回の質問に対する答えが見つかります。

### `fromeFile`を利用する

例えば、`fromFile`というAPIを利用する場合次のように書けます。

[code]

    // index.test.ts
    const { JSDOM } = require("jsdom");
    const { fromFile } = JSDOM;
    
    describe("test suite", () => {
      beforeAll(async () => {
        console.log(__dirname + "/index.html");
        const jsdom = await fromFile(__dirname + "/index.html");
        // jestがglobalに定義してあるwindowのdocumentをoverrideする
        Object.defineProperty(window, "document", {
          writable: true,
          value: jsdom.window.document,
        });
      });
    
      it("test with fromFile", async () => {
        const $ = require("jquery"); // jQueryはdocumentがセットされた後に読み込む
        expect(document.querySelector(".title").textContent).toEqual("hello world");
        expect($("h1").text()).toEqual("hello world");
      });
    });
    
[/code]

内部的には方法1で紹介したような`fs.writeFile`が走っていますが、fromFileの第2引数で[vm](https://nodejs.org/api/vm.html)の実行をある程度制御することが出来ます。

### `fromURL`を利用する

HTMLをURLから取得することも出来ます。ただし、HTTP Requestが走ってしまうので叩き過ぎには気をつけましょう。

[code]

    const { JSDOM } = require("jsdom");
    const { fromURL } = JSDOM;
    
    describe("test suite", () => {
      beforeAll(async () => {
        const jsdom = await fromURL("https://example.com/");
        // jestがglobalに定義してあるwindowのdocumentをoverrideする
        Object.defineProperty(window, "document", {
          writable: true,
          value: jsdom.window.document,
        });
      });
      it("test with fromURL", async () => {
        const $ = require("jquery"); // jQueryはdocumentがセットされた後に読み込む
        expect($("h1").text()).toEqual("Example Domain");
      });
    });
    
[/code]

## 参考

  * <https://github.com/jsdom/jsdom#fromfile>
  * <https://github.com/jsdom/jsdom#fromurl>


CC BY-SA 4.0
2020-05-26T02:20:20.917
66991
2020-05-26T02:29:34.243
2020-05-26T02:29:34.243
7997
7997
63905
answer