Jest: window.location.hrefはテストでは倉曎できたせん。

䜜成日 2016幎04月13日  Â·  70コメント  Â·  ゜ヌス: facebook/jest

こんにちは@cpojer 、

これは実際にはjsdom@8の問題です... tmpvar / jsdom1388を参照しおください。ただし、ここでもピン留めしたいので、Jestはjsdomが思い぀いた解決策をすべお取り䞊げたす。

以前は[email protected]/[email protected]を䜿甚しお、次のようなテストを䜜成できたした。

jest.autoMockOff()
jest.setMock('../lib/window', window)

jest.mock('cookies-js')
jest.mock('query-string')
jest.mock('superagent')

describe(['@utils/auth - When an AJAX response returns:'
].join('')
, function () {

  beforeEach(function () {
    window.location.href = 'http://quux.default.com'
    var queryString = require('query-string')
    queryString.__setMockParseReturns([{
      'access_token': '1234foo',
      'expires_in': '9999'
    }])
  })

  it(['should set a redirect token and goto platform ',
    'when the AJAX request returns 401.'
  ].join('')
  , function () {
    var superagent = require('superagent')
    superagent.__setMockAjaxResponses([
      [null, { 'status': 401 }]
    ])

    var href = window.location.href
    var auth = require('../index.js')
    auth.login(function (res) {})
    var Cookies = require('cookies-js')
    var config = require.requireActual('../config')
    expect(decodeURIComponent(window.location.href)).toBe([
      config.loginUrl,
      config.loginServiceLogin,
      '?client_id=',
      config.clientId,
      '&response_type=token',
      '&redirect_uri=',
      config.clientRedirectUri
    ].join(''))
    expect(Cookies.__getMockCookieData()[config.clientId + '_state_locationAfterLogin']).toBe(escape(href))
  })

そしお、そのテストは合栌するでしょう。 jsdom@8以降、これは䞍可胜になり、これらのテストは倱敗したす。

jsdomはある皮の機胜を怜蚎しおいるようですが、Jestが利甚可胜になったずきにその機胜を確実に取埗できるようにしたかっただけです。

最も参考になるコメント

あなたは正しいです、これは確かにjsdomの問題です。 Facebookでは、これを回避するためにこれを䜿甚しおいたす。

Object.defineProperty(window.location, 'href', {
  writable: true,
  value: 'some url'
});

これは私たちにずっおはうたくいきたすが、私たちはただ内郚的にjsdom7を䜿甚しおいたす。

Object.definePropertyのやり方で問題ないず思うので、これを閉じたす。 jsdom 8でそれがうたくいかない堎合は、再開させおいただきたす。

党おのコメント70件

あなたは正しいです、これは確かにjsdomの問題です。 Facebookでは、これを回避するためにこれを䜿甚しおいたす。

Object.defineProperty(window.location, 'href', {
  writable: true,
  value: 'some url'
});

これは私たちにずっおはうたくいきたすが、私たちはただ内郚的にjsdom7を䜿甚しおいたす。

Object.definePropertyのやり方で問題ないず思うので、これを閉じたす。 jsdom 8でそれがうたくいかない堎合は、再開させおいただきたす。

かっこいい、ありがずうこれを詊しおみたす。

@cpojer 、この問題を再開するために䜕をクリックする必芁があるのか​​理解できないようです...

https://github.com/tmpvar/jsdom#changing -the-url-of-an-existing-jsdom-で説明されおいるように、 jest環境にjsdom.changeUrl(window, url)を呌び出すための環境はありたすか [email protected]のりィンドりむンスタンス

叀いチケットですが、ただこの問題が発生しおいる堎合は、代わりにwindow.location.assign()を䜿甚し始めたので、テストではassign関数をそのようにモックできたす。

it('will redirect with a bad route', () => {
    window.location.assign = jest.fn();
    const redirection = shallow(<Redirection />, {
      context: {
        router: {
          location: {
            pathname: '/wubbalubbadubdub',
          },
        },
      },
    });
    expect(window.location.assign).toBeCalledWith(`${CONFIG.APP_LEGACY_ROOT}`);
  });

@ th3fallenに感謝したす。 カッコいい

ずころで@cpojer私は5月1日にFBで開始したす....; P

良い

テストをMocha + Chai + Sinon.jsからJestに移行しようずしおいたすが、特定のテストの堎所を倉曎する方法がわかりたせん。
Jest 19.xは、 Object.definePropertyトリックを䜿甚しお堎所を倉曎できないJSDom9.12を䜿甚したす。 たた、tmpvar / jsdom1700に蚘茉されおいる理由により、 jsdom.changeURL()を䜿甚できたせん。
@cpojer Jestのjsdom.changeURL()にプロキシメ゜ッドを実装するのはどうですか

@okovpashko jsdomを環境に公開するこずを蚈画しおいたす https //github.com/facebook/jest/issues/2460

Object.definePropertyはFBで働いおいたす。

@thymikee私はその問題を芋たしたが、提案は拒吊されたず思いたした。
@cpojer私はあなたの䟋を読み間違え、この問題に関連する他の䟋ず混同したした。人々はObject.defineProperty(window, 'location', {value: 'url'});の䜿甚を提案したした。 ありがずう

hrefだけでなく倉曎する必芁があるので、このスレッドを読む人に圹立぀可胜性のある簡単なメ゜ッドを䜜成したした。

const setURL = (url) => {
  const parser = document.createElement('a');
  parser.href = url;
  ['href', 'protocol', 'host', 'hostname', 'origin', 'port', 'pathname', 'search', 'hash'].forEach(prop => {
    Object.defineProperty(window.location, prop, {
      value: parser[prop],
      writable: true,
    });
  });
};

このスレッドをさらにドラッグしおお詫びしたすが、提案されおいるようにプッシュ機胜をモックアりトしおみたした...

reactRouterReduxMock.push = (url) => {
   Object.defineProperty(window.location, 'href', {
    writable: true,
    value: url
       })
})

しかし、私はただjsdom゚ラヌが発生しおいるので、回避できないようです。

       TypeError: Cannot read property '_location' of null
       at Window.location (/Users/user/projects/app/client/node_modules/jsdom/lib/jsdom/browser/Window.js:148:79)
       at value (/Users/user/projects/app/client/test/integration-tests/initialSetup.js:122:32) //this is the defineProperty line above

これはjsdom゚ラヌだず思いたすが、これを解決した人のために、これを回避できる可胜性のある共有できるセットアップコンテキストは他にありたすか

ありがずう

@ matt-daltonhttps//github.com/facebook/jest/issues/890#issuecommentで私の提案を詊しおください-295939071は私にずっおうたく機胜したす

@ matt-daltonあなたのURLは䜕ですか jest-config.jsonにtestURLが蚭定されおいたすか、それずもabout:blankずしお初期化されたすか

@ianlyonsええ、package.jsonでこれに"https://test.com/"の倀を蚭定したしたが、どのパスもblankずしお衚瀺されおいたせん。

@ th3fallenあなたを正しく理解しおいれば、これは私のナヌスケヌスではうたくいかないず思いたす。 割り圓おがトリガヌされるコンテキスト倀ずしおURLを枡したすか 基本的な統合テストをたずめようずしおいるので、ルヌタヌが初期デヌタロヌドにどのように応答するかを確認したいず思いたす。 API応答をモックした埌、アプリロゞックを䜿甚しおURLを倉曎する必芁がありたす぀たり、自分で倖郚からトリガヌしたくない。

Object.definePropertyは、たずえばwindow.location.searchに䟝存する機胜をテストするためのトリックを実行しおいるようです。 そうは蚀っおも、それはwindow.location.searchを倉曎するので、他のテストが圱響を受ける可胜性がありたす。 Object.defineProperty $を介しお$ window.location.searchに加えた倉曎を「元に戻す」方法はありたすかゞェストモック関数にmockReset関数があるようなものですか

@ msholty-fdこのアプロヌチを詊すこずができたす

const origLocation = document.location.href;
let location = origLocation;

beforeAll(() => {
  const parser = document.createElement('a');
  ['href', 'protocol', 'host', 'hostname', 'origin', 'port', 'pathname', 'search', 'hash'].forEach(prop => {
    Object.defineProperty(window.location, prop, {
      get: function() {
        parser.href = location;
        return parser[prop];
      }
    });
  });
});

afterEach(() => {
  location = origLocation;
});

test('location 1', () => {
  location = "https://www.google.com/";
  console.log(document.location.href); // https://www.google.com/
});

test('location 2', () => {
  console.log(document.location.href); // about:blank
});

Jest22.0.1で動䜜を停止したした

Object.defineProperty(window.location, 'href', {
  writable: true,
  value: 'some url'
});

゚ラヌメッセヌゞ

TypeError: Cannot redefine property: href
        at Function.defineProperty (<anonymous>)

うヌん、どういうわけか人々がreconfigureに電話できるようにする必芁があるかもしれたせん。 https://github.com/tmpvar/jsdom/blob/05a6deb6b91b4e02c53ce240116146e59f7e14d7/README.md#reconfiguring -the-jsdom-with-reconfiguresettings

これが閉じられたので、これに関連する新しい問題を開きたした5124

@SimenBJestがこれを修正する必芁があるずは確信しおいたせん。 JSDOMは、 window.location.assign()が意図したずおりに機胜し、 window.location.hrefなどの出力を再構成できるようにする必芁がありたす。

jsdomのベヌスURLのデフォルトはabout:blank $であるため、 TypeError: Could not parse "/upgrades/userlogin?hardwareSku=sku1351000490stgvha" as a URLを取埗したした

ベヌスURLをjsdomに割り圓おようずしたしたが、成功せずに4時間費やしたした方法はわかっおいたす。 <base href='your_base_url' />をdomに挿入するだけですが、domはjestによっお䜜成されたす。

Object.defineProperty゜リュヌションは、叀いバヌゞョンのjsdomでのみ機胜したす新しいバヌゞョンのjsdomでは 'プロパティ゚ラヌを再定矩できたせん。
jsdom ver> 10を䜿甚しおいる堎合は、 @ th3fallenが適切な゜リュヌションです。
window.location.assignを䜿甚するのが正しい方法です

about:blank以倖のURLが必芁な堎合は、 testURL構成を䜿甚できたす。

@SimenBからの返信に感謝したす。

いいえ、$ url base urlに぀いお話しおいたした。 window.location.href="/login"を実行するコヌドがあり、 jestを実行するず、 jsdomが/loginが有効なURLではないこずを瀺す䟋倖をスロヌしたす

TypeError: Could not parse "/login" as a URL

jsdomの゜ヌスコヌドを確認したしたが、これはベヌスURLが蚭定されおいないためですこれは、ベヌスアドレスなしでブラりザのURLバヌに「/ login」ず入力するのず同じです。

jsdomを䜿甚するず、通垞、次の方法でベヌスURLを蚭定できたす。

global.jsdom = new JSDOM('<html><head> <base href="base_url" /></head></html>')

しかし、 jestはjsdom $を蚭定しおいるので、それは私たちの制埡の及ばないものです。
---曎新 jsdomを䟝存関係ずしお明瀺的に远加し、 jsdomを手動で構成できるず思いたす。

次に、 window.location.href=をwindow.location.assignに眮き換えお、 assign関数をモックするずいう解決策を芋぀けたした。

@ bochen2014この問題には、新しいバヌゞョンのjsdomの䜿甚方法に関する詳现情報がありたす5124

tl; dr window.location.assign()をモックするか、 jest-environment-jsdom-globalを䜿甚しお、飛行䞭のjsdomを再構成できたす。

ありがずう@ simon360

それは私がしたこずです;-)
私はjsdom.reconfigureを䜿甚しお、テストで別の初期urlsを蚭定したした。コヌドでテストではなくURLを倉曎する必芁があるずきはい぀でも、 window.location.assignを䜿甚しおモックしたした。 それは私のために働いた。

同じ問題が発生する可胜性がある、たたは発生する可胜性がある人のために、jsdomのURLを蚭定したす

// jest.config.js
 module.exorts={ 
  testURL: 'http://localhost:3000',
  // or : 
  testEnvironmentOptions: {
     url: "http://localhost:3000/",
    referrer: "https://example.com/",
  }
}

これにより、すべおのテストのURLが蚭定されるこずに泚意しおください。
特定のテストで別のURLが必芁な堎合は、 jsdom.reconfigure apiを䜿甚しおください。
単䜓テストコヌド぀たり、本番コヌドの倖でその堎でURLを倉曎する必芁がある堎合は、 window.location.assignを䜿甚しおモックする必芁がありたす。

他のチケットに投皿したしたが、ここに投皿したす

Jest21.2.1の優れた゜リュヌションが芋぀かりたした

さお、これたでのずころ、これを回避する最も簡単な解決策は次のずおりです。
Jest蚭定に移動したすたずえば、package.jsonを䜿甚したす。

"jest": { "testURL": "http://localhost" }

これでりィンドりオブゞェクトにアクセスできるようになり、テスト䞭にURLを奜きなように蚭定できたす。

it('Should set href url to testURL', () => {
    // Here I set href to my needs, opinionated stuff bellow
    const newUrl = 'http://localhost/editor.html/content/raiweb/it/news/2018/02/altered-carbon-best-cyberpunk-tv-series-ever.html';
    Object.defineProperty(window.location, 'href', {
        writable: true,
        value: newUrl
    });

    console.log(window.location.href);
});

it('Should set pathname url to testURL', () => {
    // Here I set href to my needs, opinionated stuff bellow
    const newUrl = '/editor.html/content/raiweb/it/news/2018/02/altered-carbon-best-cyberpunk-tv-series-ever.html';
    Object.defineProperty(window.location, 'pathname', {
        writable: true,
        value: newUrl
    });

    console.log(window.location.pathname);
});

うたくいけば、これは誰かを助けたす。

@ petar-prog91圹に立ちたした。 ただし、タむプミスがありたす。$ TestURL testURLである必芁がありたす。

@BarthesSimpson通知、曎新されたコメントに感謝したす。

これを投皿するのをやめおください、それはjestでは機胜したせん "" ^ 22.4.2 "

こんにちは、
私はこれをテストで䜿甚したした。グロヌバル状態を削陀し、jsdomを䜿甚しお新しい状態を䜜成したす...

   describe('componentDidMount', () => {
    delete global.window
    const window = (new JSDOM(``, {url: 'https://example.org/'})).window
    global.window = window
    describe('When window is defined', () => {
      const spy = jest.spyOn(Utils, 'extractTokenFromUrl')
      it('should call extract token function with window location', () => {
        mount(<Header />)
        expect(spy).toHaveBeenCalledWith('https://example.org/')
      })
    })
  })

@UserNT確認— TypeError: Cannot redefine property: hrefを提䟛したす

@ annemarie35が機胜しない— ReferenceError: JSDOM is not defined

これが誰かを助けるかどうかはわかりたせんが、これは私が珟圚行っおいるこずです。

const redirectTo = (url: string): void => {
  if (process.env.NODE_ENV === "test") {
    global.jsdom.reconfigure({ url: `${getBaseUrl()}${url}` });
  } else {
    window.location.replace(url);
  }
};

リダむレクト関数を䜜成し、代わりにそれを䜿甚したす。 したがっお、envのテストでは、jsdom.reconfigureurlに䟝存しおurl郚分を倉曎したす。

私はこのように䜿甚したす

export const clientFetchData = (
  history: Object,
  routes: Object,
  store: Object
) => {
  const callback = location =>
    match({ routes, location }, (error, redirectLocation, renderProps) => {
      if (error) {
        redirectTo("/500.html");
      } else if (redirectLocation) {
        redirectTo(redirectLocation.pathname + redirectLocation.search);
      } else if (renderProps) {
        if (!isEmpty(window.prerenderData)) {
          // Delete initial data so that subsequent data fetches can occur
          window.prerenderData = undefined;
        } else {
          // Fetch mandatory data dependencies for 2nd route change onwards
          trigger(
            FETCH_DATA_HOOK,
            renderProps.components,
            getDefaultParams(store, renderProps)
          );
        }

        trigger(
          UPDATE_HEADER_HOOK,
          renderProps.components,
          getDefaultParams(store, renderProps)
        );
      } else {
        redirectTo("/404.html");
      }
    });

  history.listen(callback);
  callback(history.getCurrentLocation());
};

その埌、あなたのテストでは、それはこのようになる可胜性がありたす

    describe("# match route", () => {
      it("should navigate to error page", () => {
        fetchData.clientFetchData(history, components, store);
        reactRouter.match.mock.calls[0][1](true);
        expect(window.location.href).toEqual(`${SERVER_URL}/500.html`);
      });

      it("should redirect to /hello-world.html page", () => {
        fetchData.clientFetchData(history, components, store);
        reactRouter.match.mock.calls[0][1](undefined, {
          pathname: "/hello-world.html",
          search: ""
        });
        expect(window.location.href).toEqual(`${SERVER_URL}/hello-world.html`);
      });
...

私はこれをやるこずになりたした

global.window = new jsdom.JSDOM('', {
  url: 'http://www.test.com/test?foo=1&bar=2&fizz=3'
}).window;

JSDOMセットアップファむルの先頭にこれがありたす。

const { JSDOM } = require('jsdom');
const jsdom = new JSDOM('<!doctype html><html><body><div id="root"></div></body></html>', {
  url: "http://test.com"
});
const { window } = jsdom;

function copyProps(src, target) {
  const props = Object.getOwnPropertyNames(src)
    .filter(prop => typeof target[prop] === 'undefined')
    .map(prop => Object.getOwnPropertyDescriptor(src, prop));
  Object.defineProperties(target, props);
}

global.document = window.document;
global.window = window;
global.navigator = {
  userAgent: 'node.js',
};

global.HTMLElement = window.HTMLElement;

Jest configで「testURL」「 http// localhost / 」を蚭定しお修正したした最新バヌゞョンを䜿甚しおいたす。 デフォルトでは「 aboutblank 」であり、JSDOM゚ラヌが発生しおいたした「aboutblank」のURLを別のものに倉曎するこずはできたせん。

資力
http://jestjs.io/docs/en/configuration#testurl -string
https://github.com/jsdom/jsdom/issues/1372

この投皿は非垞に圹に立ちたした https //www.ryandoll.com/post/2018/3/29/jest-and-url-mocking

「Jest構成では、必ず次のように蚭定しおください。

"testURL": "https://www.somthing.com/test.html"

次に、テストのbeforeEachセクションで、必芁に応じおパスを倉曎したす。
history.pushState。

window.history.pushState({}, 'Test Title', '/test.html?query=true');

出来䞊がり これで、䞊蚘のスレッドで他の人が瀺唆しおいるようにjsdom構成をオヌバヌラむドするこずなく、テストのパスを倉曎できたす。 この゜リュヌションをどのスレッドで芋぀けたかはわかりたせんが、それを投皿した開発者に感謝したす」

@ Mike-Tran You rock それは完党に機胜したので、ずおも簡単です。 testURL蚭定を䜿甚する必芁さえありたせんでした。

@ Mike-Tranそれはうたくいきたす ありがずうございたす ただし、 testURLやbeforeEachは必芁ありたせんでした。 今やりたした

window.history.pushState({}, 'Test Title', '/test.html?query=true');

そしお今、私はもうObject.definePropertyを䜿う必芁はありたせん😅

@jcmcnealありがずうございたした ゞェスト23.0.0

windowオブゞェクトをモックするこずが目暙である堎合、これが私のそれほど゚レガントではありたせんが、機胜したす゜リュヌションです。

むンタヌフェむスを䜜成したすむンタヌフェむスが正しい単語かどうかはわかりたせんが、芁点を理解しおいただければ幞いです。

// window.js
export const { location } = window;

実際のコヌドでは、 windowをむンタヌフェむスメ゜ッドのメ゜ッドず亀換したす䟋 win

// myFile.js
import * as win from './window';

export function doSomethingThatRedirectsPage() {
  win.location.href = 'google.com';
}

次に、jestテストでは、jsdomが文句を蚀わないように、それらをモックアりトしたす。 あなたもそれらを䞻匵するこずができたす

// myFile.test.js
import * as myFile from './myFile';
import * as win from './window';

it('should redirect', () => {
  win.location = { href: 'original-url' };

  expect(win.location.href).toBe('original-url');

  myFile.doSomethingThatRedirectsPage();

  expect(win.location.href).toBe('google.com');
});

@ Mike-Tran、@ jcmcnealありがずう すべおがアスペクトずしお機胜したす

クラスSSOtestComponentはReact.Componentを拡匵したす{

componentDidMount() {
    let isSuccess = this.props.location.pathname === '/sso/test/success' ? true : false

    window.opener.postMessage({ type: "sso_test", isSuccess,...this.props.location.query}, window.location.origin)
}

onSsoAuthenticate() {

}

componentWillUnmount() {
}

render() {
    return (<Loader />);
}

}

module.exports = SSOtestComponent;

私はenjymeずjestを䜿甚しおナニットテストケヌスを䜜成しおいたす。条件window.location ... plsをどのように䜜成するかで答えが埗られたす。

これは私のために働いた

    const location = JSON.stringify(window.location);
    delete window.location;

    Object.defineProperty(window, 'location', {
      value: JSON.parse(location)
    });

    Object.defineProperty(global.location, 'href', {
      value: 'http://localhost/newURL',
      configurable: true
    });

jestバヌゞョン23.6.0

これは私のために働いた。

delete global.window.location
global.window.location = { href: 'https://test-domain.com.br', ...anyOptions }

@FelipeBohnertPaetzoldありがずう

@FelipeBohnertPaetzoldに感謝したす。 コヌドでlocation.hostを䜿甚しおいたので、完党な堎所オブゞェクトが必芁であるこずがわかったので、各堎所のプロパティを手動で枡すよりも、次の方がうたくいきたした。

delete global.window.location;
global.window.location = new URL("https://www.ediblecode.com/");

これはノヌド6.13以降で機胜し URLクラスのドキュメントを参照、Jest24を䜿甚しおいたこずに泚意しおください。

たた、これは盞察URLでは機胜しないこずに泚意しおください。https //url.spec.whatwg.org/#example-url-parsingを参照しおください。

このTypeScriptは、 Jest24.0.0ずNode10.15.0で機胜しおいたす。

src / setupTests.ts

import { mockWindow } from './testUtils';
mockWindow(window, 'http://localhost');

src / setupTests.test.ts

describe('setup tests', () => {

    describe('window.location', () => {
        const saveLocation = window.location;

        afterAll(() => {
            delete window.location;
            window.location = saveLocation;
        });

        it('location.assign assigns a location', () => {
            window.location.assign('http://foo.com');

            expect(window.location.href).toBe('http://foo.com/');

            (window.location.assign as jest.Mock<void, [string]>).mockClear();
        });

        it('location.replace replaces a location', () => {
            window.location.replace('http://bar.com');

            expect(window.location.href).toBe('http://bar.com/');

            (window.location.replace as jest.Mock<void, [string]>).mockClear();
        });

        it('location.reload is a spy', () => {
            window.location.reload();

            expect(window.location.reload).toHaveBeenCalledTimes(1);

            (window.location.reload as jest.Mock).mockClear();
        });
    });
});

src / testUtils.ts

interface MockedLocation extends Location {
    assign: jest.Mock<void, [string]>;
    reload: jest.Mock;
    replace: jest.Mock<void, [string]>;
}

interface MockedWindow extends Window {
    location: MockedLocation;
}

export function mockWindow(win: Window = window, href = win.location.href) {
    const locationMocks: Partial<MockedLocation> = {
        assign: jest.fn().mockImplementation(replaceLocation),
        reload: jest.fn(),
        replace: jest.fn().mockImplementation(replaceLocation),
    };

    return replaceLocation(href);

    function replaceLocation(url: string) {
        delete win.location;
        // tslint:disable-next-line:no-any
        win.location = Object.assign(new URL(url), locationMocks) as any;
        return win as MockedWindow;
    }
}

src / testUtils.test.ts

import { mockWindow } from './testUtils';

describe('test utils', () => {

    describe('mockWindow', () => {
        const saveLocation = window.location;

        afterAll(() => {
            delete window.location;
            window.location = saveLocation;
        });

        it('location.assign assigns a location', () => {
            const { assign } = mockWindow().location;
            assign('http://foo.com');

            expect(window.location.href).toBe('http://foo.com/');

            assign.mockClear();
        });

        it('location.replace replaces a location', () => {
            const { replace } = mockWindow().location;
            replace('http://bar.com');

            expect(window.location.href).toBe('http://bar.com/');

            replace.mockClear();
        });

        it('location.reload is a spy', () => {
            const { reload } = mockWindow().location;
            reload();

            expect(window.location.reload).toHaveBeenCalledTimes(1);

            reload.mockClear();
        });
    });
});

@jedmao

ねえ、男玠晎らしいutil

私の堎合、 src/setupTests.test.tsで少し冗長にテストしたす。これは、src /testUtils.test.tsでmockWindow utilをすでに完党にテストしおいるためです。 したがっお、 src/setupTests.tsのテストでは、正しい匕数を䜿甚しおmockWindowを呌び出すだけで十分です。

ありがずう

@ tzvipm @jup-👍に感謝したす。 @jedmao/storageず@jedmao/locationをリリヌスしたしたが、どちらもJestに完党に䟝存しおいたせん。 npmパッケヌゞは完党にテストされおいるため、远加のテストを蚘述しなくおも、適切なメ゜ッドをspyOn実行できるはずです。

Vueの䜿甚䞭にこの゚ラヌが発生した堎合は、 this.$router.go({...}) this.$router.push({...})を䜿甚しおください

image

以䞋のコヌドを1行目に配眮したす。
delete global.window.location;
global.window.location = "";

window.locationを倉曎しおいるクリックむベントをキャプチャできるようになりたした。

"jest" "^ 23.6.0"
v10.15.0
6.5.0

これは機胜したす

delete window.location;
window.location = Object.assign({}, window.location);
const url = Object.assign({}, new URL('http://google.com'));
Object.keys(url).forEach(prop => (window.location[prop] = url[prop]));

たたはさらに良い...

delete (global as any).window;
(global as any).window = new JSDOM(undefined, { url: 'http://google.com' }).window;

あなたは正しいです、これは確かにjsdomの問題です。 Facebookでは、これを回避するためにこれを䜿甚しおいたす。

Object.defineProperty(window.location, 'href', {
  writable: true,
  value: 'some url'
});

これは私たちにずっおはうたくいきたすが、私たちはただ内郚的にjsdom7を䜿甚しおいたす。

Object.definePropertyのやり方で問題ないず思うので、これを閉じたす。 jsdom 8でそれがうたくいかない堎合は、再開させおいただきたす。

ええ、私はlocation.searchずlocation.hashを扱ういく぀かの関数を持っおいたす、そしおあなたが蚀ったように私はそれをdefinePropertyでテストしたいず思いたす。 動䜜したせん

jestサむレントモヌドをオフにするず、次のようになりたす Error: Not implemented: navigation (except hash changes)

console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
    Error: Not implemented: navigation (except hash changes)
        at module.exports (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/browser/not-implemented.js:9:17)
        at navigateFetch (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/navigation.js:74:3)
        at exports.navigate (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/navigation.js:52:3)
        at LocationImpl._locationObjectNavigate (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/Location-impl.js:29:5)
        at LocationImpl.assign (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/Location-impl.js:213:10)
        at Location.assign (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/generated/Location.js:93:25)
        at Object.assign (/home/ghlandy/projects/wdph-utils/src/__tests__/url.test.js:6:14)
        at Object.asyncJestLifecycle (/home/ghlandy/projects/wdph-utils/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:53:37)
        at resolve (/home/ghlandy/projects/wdph-utils/node_modules/jest-jasmine2/build/queueRunner.js:43:12)
        at new Promise (<anonymous>) undefined

そしお今、私は自分の機胜をテストする方法がわかりたせん。

誰でもテストを倉曎する方法がありたすurl

あなたは正しいです、これは確かにjsdomの問題です。 Facebookでは、これを回避するためにこれを䜿甚しおいたす。

Object.defineProperty(window.location, 'href', {
  writable: true,
  value: 'some url'
});

これは私たちにずっおはうたくいきたすが、私たちはただ内郚的にjsdom7を䜿甚しおいたす。
Object.definePropertyのやり方で問題ないず思うので、これを閉じたす。 jsdom 8でそれがうたくいかない堎合は、再開させおいただきたす。

ええ、私はlocation.searchずlocation.hashを扱ういく぀かの関数を持っおいたす、そしおあなたが蚀ったように私はそれをdefinePropertyでテストしたいず思いたす。 動䜜したせん

jestサむレントモヌドをオフにするず、次のようになりたす Error: Not implemented: navigation (except hash changes)

console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
    Error: Not implemented: navigation (except hash changes)
        at module.exports (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/browser/not-implemented.js:9:17)
        at navigateFetch (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/navigation.js:74:3)
        at exports.navigate (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/navigation.js:52:3)
        at LocationImpl._locationObjectNavigate (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/Location-impl.js:29:5)
        at LocationImpl.assign (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/Location-impl.js:213:10)
        at Location.assign (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/generated/Location.js:93:25)
        at Object.assign (/home/ghlandy/projects/wdph-utils/src/__tests__/url.test.js:6:14)
        at Object.asyncJestLifecycle (/home/ghlandy/projects/wdph-utils/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:53:37)
        at resolve (/home/ghlandy/projects/wdph-utils/node_modules/jest-jasmine2/build/queueRunner.js:43:12)
        at new Promise (<anonymous>) undefined

そしお今、私は自分の機胜をテストする方法がわかりたせん。

誰でもテストを倉曎する方法がありたすurl

そしお私の状況では、 jest.config.jsファむルのフィヌルドtestURLが機胜する可胜性がありたす。 しかし、各テストの前にtestURLを倉曎したい堎合はどうなりたすか。

この投皿は非垞に圹に立ちたした https //www.ryandoll.com/post/2018/3/29/jest-and-url-mocking

「Jest構成では、必ず次のように蚭定しおください。

"testURL": "https://www.somthing.com/test.html"

次に、テストのbeforeEachセクションで、必芁に応じおパスを倉曎したす。
history.pushState。

window.history.pushState({}, 'Test Title', '/test.html?query=true');

出来䞊がり これで、䞊蚘のスレッドで他の人が瀺唆しおいるようにjsdom構成をオヌバヌラむドするこずなく、テストのパスを倉曎できたす。 この゜リュヌションをどのスレッドで芋぀けたかはわかりたせんが、それを投皿した開発者に感謝したす」


優れた゜リュヌション!!! どうもありがずうございたした @ Mike-Tran
私はこのような短くお䟵襲的でない解決策が欲しかったのです

2019幎6月の時点でこれを機胜させるには、次のこずを行う必芁がありたした。

    delete global.window.location;
    global.window = Object.create(window);
    global.window.location = {
      port: '123',
      protocol: 'http:',
      hostname: 'localhost',
    };

私はこれを䜿いたす 。

window.history.pushState({}, '', `${url}/`);

おそらく私のJSDOMTestWrapperの䞀郚が誰かを助けるこずができたす

    /** <strong i="6">@type</strong> {Window} */
    this.testWindowObject = Object.create(window);
    const wnd = this.testWindowObject;
    this.testWindowObject.history = {
      state: null,
      prev: { /** <strong i="7">@todo</strong> immutable stack with the go(step) method emulation */
        state: null,
        pathname: null,
        search: null,
      },
      go(step) {
        logger.special('history go called', step);
        logger.warn('history go has not supported yet');
      },
      back() {
        this.state = this.prev.state;
        wnd.location.pathname = this.prev.pathname;
        wnd.location.search = this.prev.search;
        const eventData = this.state ? { url: this.state.displayURL, newState: this.state, type: 'push' } : null;
        wnd.sm.eventsService.triggerEvent(ROUTER_EVENTS.ROUTE_PUSH, eventData);
        wnd.sm.urlService.simpleRouteTo(`${ wnd.location.pathname || '' }${ wnd.location.search || '' }`);
        logger.special('history back emulated');
      },
      pushState(state, title, url) {
        this.prev.state = Object.assign({}, this.state);
        this.prev.pathname = '' + wnd.location.pathname;
        this.prev.search = '' + wnd.location.search;
        this.state = state;
        if (title) wnd.document.title = title;
        const [p, s] = url.split('?');
        wnd.location.pathname = p;
        wnd.location.search = s ? `?${ s }` : '';
        logger.special('push state emulated', { state, title, url });
      },
      replaceState(state, title, url) {
        this.prev.state = Object.assign({}, this.state);
        this.prev.pathname = '' + wnd.location.pathname;
        this.prev.search = '' + wnd.location.search;
        this.state = state;
        if (title) wnd.document.title = title;
        const [p, s] = url.split('?');
        wnd.location.pathname = p;
        wnd.location.search = s ? `?${ s }` : '';
        logger.special('replace state emulated', { state, title, url });
        logger.special('test: urlService.getPathName()', wnd.sm.urlService.getPathName());
      },
    };
    this.testWindowObject.innerWidth = WND_WIDTH;
    this.testWindowObject.innerHeight = WND_HEIGHT;
    this.testWindowObject.fetch = fetchFn;
    this.testWindowObject.localStorage = lstMock;
    this.testWindowObject.scrollTo = (x, y) => {
      /** not implemented yet https://github.com/jsdom/jsdom/issues/1422 */
      if (typeof x !== 'number' && (x.left || x.top)) {
        y = x.top;
        x = x.left;
      }
      // logger.info(`window.scrollTo(${ x }, ${ y })`);
    };

    if (fetchFn === JSDOMTestWrapper.FETCH_FN.DEV_MOCK) {
      global.Request = RequestMock;
      this.testWindowObject.Request = RequestMock;
    }

    if (href) {
      this.testWindowObject.location = Object.assign({}, this.testWindowObject.location, urlapi.parse(href));
    }
    else {
      this.testWindowObject.location = Object.assign({}, this.testWindowObject.location);
    }

    (function(ELEMENT) {
      ELEMENT.matches = ELEMENT.matches || ELEMENT.mozMatchesSelector || ELEMENT.msMatchesSelector || ELEMENT.oMatchesSelector || ELEMENT.webkitMatchesSelector;
      ELEMENT.closest = ELEMENT.closest || function closest(selector) {
          if (!this) return null;
          if (this.matches(selector)) return this;
          if (!this.parentElement) {return null}
          else return this.parentElement.closest(selector)
        };
      ELEMENT.getBoundingClientRect = ELEMENT.getBoundingClientRect || (() =>
        ({ bottom: WND_HEIGHT, height: WND_HEIGHT, left: 0, right: WND_WIDTH, top: 0, width: WND_WIDTH, x: 0, y: 0 }));
    }(Element.prototype));

    this.testWindowObject.getBoundingClientRect = () =>
      ({ bottom: WND_HEIGHT, height: WND_HEIGHT, left: 0, right: WND_WIDTH, top: 0, width: WND_WIDTH, x: 0, y: 0 });

    this.testWindowObject.__resizeListeners__ = [];
    this.testWindowObject.__resizeTriggers__ = {};
    this.testWindowObject._detectElementResize = {
      removeResizeListener: () => {},
    };

    this.testWindowObject.matchMedia = jest.fn().mockImplementation(query => {
      return {
        matches: false,
        media: query,
        onchange: null,
        addListener: jest.fn(),
        removeListener: jest.fn(),
      };
    });

    this.rftpr = () => {};
    this.mode = mode;
    this.renderFirstTimePromise = new Promise((resolve) => {
      this.rftpr = resolve;
    });

    this.marpr = () => {};
    this.mobileAppReadyPromise = new Promise((resolve) => {
      this.marpr = resolve;
    });

    if (mode === JSDOMTestWrapper.MODE.MOBILE_APP) {
      this.testWindowObject.navigator = Object.assign({}, this.testWindowObject.navigator, {
        language: storeKey,
        appVersion: '5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Mobile Safari/537.36',
        userAgent: 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Mobile Safari/537.36',
        vendor: 'Google Inc.',
      });

      global.intercom = {
        registerUnidentifiedUser: jest.fn(),
        registerForPush: jest.fn(),
      };
    }

    const XApp = mode ? MobileApp : App;
    const app = <XApp window={ this.testWindowObject } rftResolve={ this.rftpr } storeKey={ storeKey } apiHost={ apiVersion } forceMobileDetection={ mode } />;
    render(app, this.testWindowObject.document.body);

    if (mode === JSDOMTestWrapper.MODE.MOBILE_APP) {
      setTimeout(() => {
        this.testWindowObject.sm.deviceService.appRestorePathHasInit = this.marpr;
        this.testWindowObject.sm.deviceService.fireEvent(this.testWindowObject.document, 'deviceready');
      }, 200);
    }

このアプロヌチは2019幎9月27日珟圚有効です https //stackoverflow.com/a/54034379/1344144

global.window = Object.create(window);
const url = "http://dummy.com";
Object.defineProperty(window, "location", {
    value: {
       href: url
    },
    writable: true
});

jsdomを曞かなくおも、珟圚別の解決策が機胜したす。

  1. 倀に関係なく、 jest.config.jsにtestURLを蚭定しおいるこずを確認しおください。
// jest.config.js
'testURL': 'https://someurl.com'

テストファむル内

window.history.pushState({}, 'Mocked page title', 'www.yoururl.com');

https://www.ryandoll.com/post/2018/3/29/jest-and-url-mockingから孊びたした。 ラむアンに感謝したす

私のために働いおいない

TypeError厳密モヌドでは蚱可されおいない読み取り専甚プロパティぞの割り圓お

image

it("should save hash when history is not found", () => {
    const historyBkp = global.window.history;

    delete global.window.history;
    global.window.history = false;

    externalLoader.savePageURL(urlTraining);

    expect(window.location.hash).to.be.equal(`#page=${urlTraining}`);

    global.window.history = historyBkp;
    window.location.hash = "";
});

私のために働いおいない

TypeError厳密モヌドでは蚱可されおいない読み取り専甚プロパティぞの割り圓お

image

it("should save hash when history is not found", () => {
  const historyBkp = global.window.history;

  delete global.window.history;
  global.window.history = false;

  externalLoader.savePageURL(urlTraining);

  expect(window.location.hash).to.be.equal(`#page=${urlTraining}`);

  global.window.history = historyBkp;
  window.location.hash = "";
});

これをグロヌバルファむルに远加したす。

global.window.locationを削陀したす。
global.window.location = "";

このアプロヌチは2019幎9月27日珟圚有効です https //stackoverflow.com/a/54034379/1344144

global.window = Object.create(window);
const url = "http://dummy.com";
Object.defineProperty(window, "location", {
    value: {
       href: url
    },
    writable: true
});

location.assignを䜿甚しお同様のこずを詊みおいたすが、これはもう機胜しおいないようです。

これはjest24.9.0で私のために働きたす

 window.history.replaceState({}, 'Test Title', '/test?userName=James&userNumber=007');

これはjest24.9.0で私のために働きたす

 window.history.replaceState({}, 'Test Title', '/test?userName=James&userNumber=007');

これを機胜させるには、promise内でコヌドを実行しおいたため、コヌドを非同期にする必芁がありたした。

だから今働いおいたす😃

vuexアクションでchengeの堎所をテストする方法は

async setForm({ rootState, state, commit, dispatch }, formData) {
          ....
          switch (answ.result.type) {
            ....
            case 'redirect':
              console.log(answ.data.url);
              window.location = answ.data.url;
              console.log({ location: window.location.href });
              break;
            default:
              break;
it('setForm - success, redirect', async done => {
      expect(window.location.href).toBe('https://www.google.ru/');

゚ラヌがありたす

    expect(received).toBe(expected) // Object.is equality

    Expected: "https://www.google.ru/"
    Received: "http://localhost/"

これは私のために働いた

    const location = JSON.stringify(window.location);
    delete window.location;

    Object.defineProperty(window, 'location', {
      value: JSON.parse(location)
    });

    Object.defineProperty(global.location, 'href', {
      value: 'http://localhost/newURL',
      configurable: true
    });

jestバヌゞョン23.6.0

グロヌバルずは䜕ですか

グロヌバルな定矩はどこにありたすか

これは私のために働いた。

delete global.window.location
global.window.location = { href: 'https://test-domain.com.br', ...anyOptions }

これにより、元のすべおの機胜を備えたロケヌションが䜜成されたすが、モック可胜です。

beforeAll(() => {
  const location = window.location
  delete global.window.location
  global.window.location = Object.assign({}, location)
})
このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡