Jest: window.location.href рдХреЛ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рдирд╣реАрдВ рдмрджрд▓рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдХреЛ рдирд┐рд░реНрдорд┐рдд 13 рдЕрдкреНрд░реИрд▓ 2016  ┬╖  70рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: facebook/jest

рд╣рд╛рдп @cpojer ,

рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдПрдХ jsdom@8 рдореБрджреНрджреЗ рд╕реЗ рдЕрдзрд┐рдХ рд╣реИ ... tmpvar/jsdom#1388 рджреЗрдЦреЗрдВ, рд▓реЗрдХрд┐рди рдореИрдВ рдпрд╣рд╛рдВ рднреА рдкрд┐рди рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдЗрд╕рд▓рд┐рдП рдЬреЗрд╕реНрдЯ рдЬреЛ рднреА рд╕рдорд╛рдзрд╛рди 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 рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХреА рдХреНрд╖рдорддрд╛ рдХреЛ рджреЗрдЦ рд░рд╣рд╛ рд╣реИ, рдмрд╕ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ рдХрд┐ рдЬреЗрд╕реНрдЯ рдЙрдкрд▓рдмреНрдз рд╣реЛрдиреЗ рдкрд░ рдЙрд╕ рдХреНрд╖рдорддрд╛ рдХреЛ рдЙрдард╛рдПрдЧрд╛ред

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдЖрдк рд╕рд╣реА рд╣реИрдВ, рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдПрдХ jsdom рдореБрджреНрджрд╛ рд╣реИред рдлреЗрд╕рдмреБрдХ рдкрд░, рд╣рдордиреЗ рдЗрд╕рдХреЗ рдЖрд╕рдкрд╛рд╕ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬреЛ рдХрд┐рдпрд╛ рд╣реИ, рд╡рд╣ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣реИ:

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

рдпрд╣ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдБрдХрд┐ рд╣рдо рдЕрднреА рднреА рдЖрдВрддрд░рд┐рдХ рд░реВрдк рд╕реЗ jsdom 7 рдкрд░ рд╣реИрдВред

рдореИрдВ рдЗрд╕реЗ рдмрдВрдж рдХрд░ рджреВрдВрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ рдХрд┐ Object.defineProperty рдЪреАрдЬреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХрд╛ рддрд░реАрдХрд╛ рдареАрдХ рд╣реИред рдЕрдЧрд░ рд╡рд╣ рдЖрдкрдХреЗ рд▓рд┐рдП jsdom 8 рдореЗрдВ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдореБрдЭреЗ рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рдЦреЛрд▓рдиреЗ рдореЗрдВ рдЦреБрд╢реА рд╣реЛ рд░рд╣реА рд╣реИред

рд╕рднреА 70 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдЖрдк рд╕рд╣реА рд╣реИрдВ, рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдПрдХ jsdom рдореБрджреНрджрд╛ рд╣реИред рдлреЗрд╕рдмреБрдХ рдкрд░, рд╣рдордиреЗ рдЗрд╕рдХреЗ рдЖрд╕рдкрд╛рд╕ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬреЛ рдХрд┐рдпрд╛ рд╣реИ, рд╡рд╣ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣реИ:

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

рдпрд╣ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдБрдХрд┐ рд╣рдо рдЕрднреА рднреА рдЖрдВрддрд░рд┐рдХ рд░реВрдк рд╕реЗ jsdom 7 рдкрд░ рд╣реИрдВред

рдореИрдВ рдЗрд╕реЗ рдмрдВрдж рдХрд░ рджреВрдВрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ рдХрд┐ Object.defineProperty рдЪреАрдЬреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХрд╛ рддрд░реАрдХрд╛ рдареАрдХ рд╣реИред рдЕрдЧрд░ рд╡рд╣ рдЖрдкрдХреЗ рд▓рд┐рдП jsdom 8 рдореЗрдВ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдореБрдЭреЗ рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рдЦреЛрд▓рдиреЗ рдореЗрдВ рдЦреБрд╢реА рд╣реЛ рд░рд╣реА рд╣реИред

рдмрдврд╝рд┐рдпрд╛, рдзрдиреНрдпрд╡рд╛рдж рдореИрдВ рдЗрд╕реЗ рдЖрдЬрдорд╛рдЙрдВрдЧрд╛ред

@cpojer , рдореБрдЭреЗ рдпрд╣ рдкрддрд╛ рдирд╣реАрдВ рд▓рдЧ рд░рд╣рд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдлрд┐рд░ рд╕реЗ рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдХреНрдпрд╛ рдХреНрд▓рд┐рдХ рдХрд░рдирд╛ рд╣реИ ...

рдХреНрдпрд╛ jest рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рдХреЛрдИ рднреА рд╡реНрдпрдХреНрддрд┐ jsdom.changeUrl(window, url) рдкрд░ рдХреЙрд▓ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдЬреИрд╕рд╛ рдХрд┐ рдпрд╣рд╛рдВ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ https://github.com/tmpvar/jsdom#change -the-url-of-an- рдореМрдЬреВрджрд╛-jsdom- [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 рдореИрдВ 1 рдордИ рдХреЛ рдПрдлрдмреА рд╕реЗ рд╢реБрд░реВ рдХрд░рддрд╛ рд╣реВрдВ ....; рдкреА

рдЕрдЪреНрдЫрд╛!

рдореИрдВ рдЕрдкрдиреЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЛ рдореЛрдЪрд╛+рдЪрд╛рдИ+рд╕рд┐рдиреЙрди.рдЬреЗрдПрд╕ рд╕реЗ рдЬреЗрд╕реНрдЯ рдореЗрдВ рдорд╛рдЗрдЧреНрд░реЗрдЯ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдпрд╣ рдкрддрд╛ рдирд╣реАрдВ рд▓рдЧрд╛ рд╕рдХрддрд╛ рдХрд┐ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рд╕реНрдерд╛рди рдХреИрд╕реЗ рдмрджрд▓рд╛ рдЬрд╛рдПред
рдЬреЗрд╕реНрдЯ 19.x JSDom 9.12 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ рдЬреЛ Object.defineProperty рдЯреНрд░рд┐рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реНрдерд╛рди рдмрджрд▓рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИред рд╕рд╛рде рд╣реА, рдореИрдВ tmpvar/jsdom#1700 рдореЗрдВ рд╡рд░реНрдгрд┐рдд рдХрд╛рд░рдгреЛрдВ рдХреЗ рдХрд╛рд░рдг jsdom.changeURL() рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ред
@cpojer рдЬреЗрд╕реНрдЯ рдореЗрдВ 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 рддреНрд░реБрдЯрд┐ рд╣реИ, рд▓реЗрдХрд┐рди рдЬрд┐рди рд▓реЛрдЧреЛрдВ рдиреЗ рдЗрд╕реЗ рд╣рд▓ рдХрд┐рдпрд╛ рд╣реИ рдЙрдирдХреЗ рд▓рд┐рдП рдХреНрдпрд╛ рдХреЛрдИ рдФрд░ рд╕реЗрдЯрдЕрдк рд╕рдВрджрд░реНрдн рд╣реИ рдЬрд┐рд╕реЗ рдЖрдк рд╕рд╛рдЭрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдореБрдЭреЗ рдЗрд╕рдХреЗ рдЖрд╕рдкрд╛рд╕ рдЬрд╛рдиреЗ рджреЗ рд╕рдХрддрд╛ рд╣реИ?

рдзрдиреНрдпрд╡рд╛рдж

@ рдореИрдЯ-рдбрд╛рд▓реНрдЯрди https://github.com/facebook/jest/issues/890#issuecomment -295939071 рдореЗрдВ рдореЗрд░реЗ рд╕реБрдЭрд╛рд╡ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВ рдореЗрд░реЗ рд▓рд┐рдП рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ

@ рдореИрдЯ-рдбрд╛рд▓реНрдЯрди рдЖрдкрдХрд╛ рдпреВрдЖрд░рдПрд▓ рдХреНрдпрд╛ рд╣реИ? рдХреНрдпрд╛ рдЖрдкрдХреЗ рдкрд╛рд╕ рдЕрдкрдиреЗ jest-config.json рдореЗрдВ testURL рд╕реЗрдЯ рд╣реИ рдпрд╛ рдпрд╣ about:blank рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рд╛рд░рдВрдн рд╣реЛрддрд╛ рд╣реИ?

@ianlyons рд╣рд╛рдБ рдореИрдВрдиреЗ package.json рдореЗрдВ рдЗрд╕рдХреЗ рд▓рд┐рдП "https://test.com/" рдХрд╛ рдорд╛рди рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рд╣реИ, рдФрд░ рдХреЛрдИ рднреА рдкрде blank рдХреЗ рд░реВрдк рдореЗрдВ рджрд┐рдЦрд╛рдИ рдирд╣реАрдВ рджреЗ рд░рд╣рд╛ рд╣реИред

@ th3fallen рдЕрдЧрд░ рдореИрдВ рдЖрдкрдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рд╕рдордЭрддрд╛ рд╣реВрдВ, рддреЛ рдореБрдЭреЗ рдирд╣реАрдВ рд▓рдЧрддрд╛ рдХрд┐ рдпрд╣ рдореЗрд░реЗ рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдХреНрдпрд╛ рдЖрдк рдпреВрдЖрд░рдПрд▓ рдХреЛ рд╕рдВрджрд░реНрдн рдорд╛рди рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд╕ рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЬреЛ рдЕрд╕рд╛рдЗрди рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░рдг рдмрдирддрд╛ рд╣реИ? рдореИрдВ рдПрдХ рдкреНрд░рд╛рдердорд┐рдХ рдПрдХреАрдХрд░рдг рдкрд░реАрдХреНрд╖рдг рдХреЛ рдПрдХ рд╕рд╛рде рд░рдЦрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдпрд╣ рдЬрд╛рдВрдЪрдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рд░рд╛рдЙрдЯрд░ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдбреЗрдЯрд╛ рд▓реЛрдб рдкрд░ рдХреИрд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд░рддрд╛ рд╣реИред рдореИрдВрдиреЗ рдПрдкреАрдЖрдИ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд╛ рдордЬрд╝рд╛рдХ рдЙрдбрд╝рд╛рдпрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ рдРрдк рддрд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдпреВрдЖрд░рдПрд▓ рдкрд░рд┐рд╡рд░реНрддрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рдпрд╛рдиреА рдореИрдВ рдЗрд╕реЗ рдмрд╛рд╣рд░реА рд░реВрдк рд╕реЗ рдЯреНрд░рд┐рдЧрд░ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛)ред

Object.defineProperty рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, window.location.search рдкрд░ рдирд┐рд░реНрднрд░ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЪрд╛рд▓ рдЪрд▓ рд░рд╣рд╛ рд╣реИред рдХрд╣рд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИ рдХрд┐ рдпрд╣ window.location.search рдмрджрд▓ рджреЗрддрд╛ рд╣реИ рдЗрд╕рд▓рд┐рдП рдЕрдиреНрдп рдкрд░реАрдХреНрд╖рдг рдкреНрд░рднрд╛рд╡рд┐рдд рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рдХреНрдпрд╛ рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ window.location.search рдкрд░ Object.defineProperty #$ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрд┐рдП рдЧрдП рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ "рдкреВрд░реНрд╡рд╡рдд" рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рд╣реИ, рдЬреИрд╕реЗ рдХрд┐ рдЬреЗрд╕реНрдЯ рдореЙрдХ рдлрд╝рдВрдХреНрд╢рдВрд╕ рдореЗрдВ 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
});

рдЗрд╕рдиреЗ рдЬреЗрд╕реНрдЯ 22.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#reconfigure -the-jsdom-with-reconfiguresettings

рдЗрд╕рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдПрдХ рдирдпрд╛ рдореБрджреНрджрд╛ рдЦреЛрд▓рд╛, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдмрдВрдж рдерд╛: #5124

@SimenB рдореБрдЭреЗ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЬреЗрд╕реНрдЯ рдХреЛ рдЗрд╕реЗ рдареАрдХ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред JSDOM рдХреЛ window.location.assign() рдХреЛ рдЗрдЪреНрдЫрд┐рдд рдХрд╛рд░реНрдп рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдиреА рдЪрд╛рд╣рд┐рдП рдФрд░ window.location.href рдЖрджрд┐ рдХреЗ рдЖрдЙрдЯрдкреБрдЯ рдХреЛ рдкреБрди: рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдореБрдЭреЗ TypeError: Could not parse "/upgrades/userlogin?hardwareSku=sku1351000490stgvha" as a URL рдорд┐рд▓рд╛ рдХреНрдпреЛрдВрдХрд┐ jsdom рдХрд╛ рдЖрдзрд╛рд░ url рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ about:blank рд╣реИ

рдореИрдВрдиреЗ jsdom рдХреЛ рдЖрдзрд╛рд░ рдпреВрдЖрд░рдПрд▓ рдЕрд╕рд╛рдЗрди рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд┐рдпрд╛, рдмрд┐рдирд╛ рд╕рдлрд▓рддрд╛ рдХреЗ 4 рдШрдВрдЯреЗ рдмрд┐рддрд╛рдП (рдореБрдЭреЗ рдкрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕реЗ рдХреИрд╕реЗ рдХрд░рдирд╛ рд╣реИ, рдмрд╕ рдбреЛрдо рдореЗрдВ <base href='your_base_url' /> рдбрд╛рд▓реЗрдВ; рд▓реЗрдХрд┐рди , рдбреЛрдо jest рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ

Object.defineProperty рд╕рдорд╛рдзрд╛рди рдХреЗрд╡рд▓ jsdom рдХреЗ рдкреБрд░рд╛рдиреЗ рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ (рдЖрдкрдХреЛ ' jsdom рдХреЗ рдмрд╛рдж рдХреЗ рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд╕рд╛рде рд╕рдВрдкрддреНрддрд┐ рддреНрд░реБрдЯрд┐ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ);
рдпрджрд┐ рдЖрдк jsdom ver > 10 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЬреИрд╕рд╛ рдХрд┐ @th3fallen рдиреЗ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рд╣реИ рддреЛ рдпрд╣ рд╕рд╣реА рд╕рдорд╛рдзрд╛рди рд╣реИред
рдЙрдкрдпреЛрдЧ window.location.assign рдЬрд╛рдиреЗ рдХрд╛ рд╕рд╣реА рддрд░реАрдХрд╛ рд╣реИ

рдпрджрд┐ рдЖрдк about:blank рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдХреБрдЫ рдЕрдиреНрдп url рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк testURL config рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдЖрдкрдХреЗ рдЙрддреНрддрд░ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж @SimenB ред

рдирд╣реАрдВ, рдореИрдВ рдмрд╛рдд рдХрд░ рд░рд╣рд╛ рдерд╛ base url рдирд╣реАрдВ url ред рдореЗрд░реЗ рдкрд╛рд╕ рдХреЛрдб рд╣реИ рдЬреЛ window.location.href="/login" рдХрд░реЗрдЧрд╛ рдФрд░ jest рдЪрд▓рд╛рддреЗ рд╕рдордп, jsdom рд╢рд┐рдХрд╛рдпрдд рдлреЗрдВрдХ рдЕрдкрд╡рд╛рдж /login рд╡реИрдз рдпреВрдЖрд░рдПрд▓ рдирд╣реАрдВ рд╣реИ

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

рдореИрдВрдиреЗ jsdom рдХреЗ рд╕реНрд░реЛрдд рдХреЛрдб рдХреА рдЬрд╛рдВрдЪ рдХреА рдФрд░ рдорд╣рд╕реВрд╕ рдХрд┐рдпрд╛ рдХрд┐ рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдореЗрд░реЗ рдкрд╛рд╕ рдЖрдзрд╛рд░ рдпреВрдЖрд░рдПрд▓ рд╕реЗрдЯрдЕрдк рдирд╣реАрдВ рд╣реИ (рдпрд╣ рдЖрдзрд╛рд░ рдкрддреЗ рдХреЗ рдмрд┐рдирд╛ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдпреВрдЖрд░рдПрд▓ рдмрд╛рд░ рдореЗрдВ "/ рд▓реЙрдЧрд┐рди" рдЯрд╛рдЗрдк рдХрд░рдиреЗ рдХреЗ рдмрд░рд╛рдмрд░ рд╣реИ)ред

рдХреЗ рд╕рд╛рде jsdom , рдЖрдо рддреМрд░ рдкрд░ рд╣рдо рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЖрдзрд╛рд░ рдпреВрдЖрд░рдПрд▓ рд╕реЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ

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

рдЯреАрдПрд▓; рдбреЙ: рдЖрдк window.location.assign() рдХрд╛ рдордЬрд╛рдХ рдЙрдбрд╝рд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рдЖрдк jest-environment-jsdom-global рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ рдЖрдкрдХреЛ рдЙрдбрд╝рд╛рди рдореЗрдВ jsdom рдХреЛ рдлрд┐рд░ рд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ред

рдзрдиреНрдпрд╡рд╛рдж @ рд╕рд╛рдЗрдорди360

рд╡рд╣реА рдореИрдВрдиреЗ рдХрд┐рдпрд╛ ;-)
рдореИрдВрдиреЗ рдЕрдкрдиреЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкреНрд░рд╛рд░рдВрднрд┐рдХ urls рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП jsdom.reconfigure рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛, рдФрд░ рдЬрдм рднреА рдореБрдЭреЗ рдХреЛрдб рдореЗрдВ рдпреВрдЖрд░рдПрд▓ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ (рдкрд░реАрдХреНрд╖рдг рдирд╣реАрдВ), рддреЛ рдореИрдВ window.location.assign рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ рдЗрд╕рдХрд╛ рдордЬрд╛рдХ рдЙрдбрд╝рд╛рддрд╛ рд╣реВрдВред рдЬреЛ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛ред

рд╕рд┐рд░реНрдл рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬреЛ рдЖрдкрдХреЗ jsdom рдХреЗ рд▓рд┐рдП рдпреВрдЖрд░рдПрд▓ рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╣реА рдореБрджреНрджреЗ рдореЗрдВ рднрд╛рдЧ рд╕рдХрддреЗ рд╣реИрдВ/рдЪрд▓реЗрдВрдЧреЗ

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

рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпрд╣ рдЖрдкрдХреЗ рд╕рднреА рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд▓рд┐рдП url рд╕реЗрдЯ рдХрд░реЗрдЧрд╛;
рдпрджрд┐ рдЖрдк рдХреБрдЫ рд╡рд┐рд╢реЗрд╖ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рдПрдХ рдЕрд▓рдЧ рдпреВрдЖрд░рдПрд▓ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ jsdom.reconfigure рдПрдкреАрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ;
рдЕрдЧрд░ рдЖрдкрдХреЛ рдпреВрдирд┐рдЯ рдЯреЗрд╕реНрдЯ рдХреЛрдб (рдпрд╛рдиреА рдкреНрд░реЛрдбрдХреНрд╢рди рдХреЛрдб) рдХреЗ рдмрд╛рд╣рд░ рдлреНрд▓рд╛рдИ рдкрд░ рдпреВрдЖрд░рдПрд▓ рдмрджрд▓рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ, рддреЛ рдЖрдкрдХреЛ window.location.assign рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдЗрд╕реЗ рдирдХрд▓реА рдмрдирд╛рдирд╛ рд╣реЛрдЧрд╛ред

рдЗрд╕реЗ рдЕрдиреНрдп рдЯрд┐рдХрдЯ рдкрд░ рдкреЛрд╕реНрдЯ рдХрд┐рдпрд╛, рд▓реЗрдХрд┐рди рдореИрдВ рдЗрд╕реЗ рдпрд╣рд╛рдВ рдкреЛрд╕реНрдЯ рдХрд░реВрдВрдЧрд╛:

рдЬреЗрд╕реНрдЯ 21.2.1 рдХреЗ рд▓рд┐рдП рдЕрдЪреНрдЫрд╛ рд╕рдорд╛рдзрд╛рди рдорд┐рд▓рд╛

рдареАрдХ рд╣реИ, рдЕрдм рддрдХ рдЗрд╕рдХрд╛ рд╕рдмрд╕реЗ рдЖрд╕рд╛рди рд╕рдорд╛рдзрд╛рди рд╣реИ:
рдЕрдкрдиреА рдЬреЗрд╕реНрдЯ рд╕реЗрдЯрд┐рдВрдЧ рдореЗрдВ рдЬрд╛рдПрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдореИрдВ 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 рдиреЛрдЯрд┐рд╕ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдЕрджреНрдпрддрди рдЯрд┐рдкреНрдкрдгреАред

рдЗрд╕реЗ рдкреЛрд╕реНрдЯ рдХрд░рдирд╛ рдмрдВрдж рдХрд░реЛ, рдпрд╣ рдордЬрд╛рдХ рдкрд░ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛": "^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 рдореЗрдВ, рдпрд╣ url рднрд╛рдЧ рдХреЛ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП jsdom.reconfigure 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;

рдореЗрд░реЗ рдкрд╛рд╕ рдпрд╣ рдореЗрд░реА рдЬреЗрдПрд╕рдбреАрдУрдПрдо рд╕реЗрдЯрдЕрдк рдлрд╝рд╛рдЗрд▓ рдХреЗ рд╢реАрд░реНрд╖ рдкрд░ рд╣реИ:

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;

рдЬреЗрд╕реНрдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ "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

"рдЕрдкрдиреЗ рдЬреЗрд╕реНрдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ, рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕реЗрдЯ рдХрд░рдирд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ:

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

рдлрд┐рд░ рдЕрдкрдиреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рдкрд╣рд▓реЗ () рдЕрдиреБрднрд╛рдЧ рдореЗрдВ, рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЖрд╡рд╢реНрдпрдХрддрд╛рдиреБрд╕рд╛рд░ рдкрде рдмрджрд▓реЗрдВ
рдЗрддрд┐рд╣рд╛рд╕ред рдкреБрд╢рд╕реНрдЯреЗрдЯ ()ред

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

рд╡реЛрдЗрд▓рд╛! рдЕрдм рдЖрдк рдХрд┐рд╕реА рднреА рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ рд░рд╛рд╕реНрддрд╛ рдмрджрд▓рддреЗ рд╣реИрдВ, рдмрд┐рдирд╛ рдХрд┐рд╕реА jsdom рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд┐рдП, рдЬреИрд╕рд╛ рдХрд┐ рдКрдкрд░ рд╡рд░реНрдгрд┐рдд рдзрд╛рдЧреЗ рдореЗрдВ рдЕрдиреНрдп рд╕реБрдЭрд╛рд╡ рджреЗрддреЗ рд╣реИрдВред рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдореБрдЭреЗ рдпрд╣ рд╕рдорд╛рдзрд╛рди рдХрд┐рд╕ рдзрд╛рдЧреЗ рдкрд░ рдорд┐рд▓рд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЙрд╕ рджреЗрд╡ рдХреЛ рдмрдзрд╛рдИ рдЬрд┐рд╕рдиреЗ рдЗрд╕реЗ рдкреЛрд╕реНрдЯ рдХрд┐рдпрд╛ рд╣реИ!"

@ рдорд╛рдЗрдХ-рдЯреНрд░рд╛рди рдпреВ рд░реЙрдХ! рдпрд╣ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд┐рдпрд╛, рдЗрддрдирд╛ рдЖрд╕рд╛рдиред рдореБрдЭреЗ testURL рд╕реЗрдЯрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рднреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рдереАред

@ рдорд╛рдЗрдХ-рдЯреНрд░рд╛рди рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ! рдзрдиреНрдпрд╡рд╛рдж! рд╣рд╛рд▓рд╛рдВрдХрд┐, рдореБрдЭреЗ 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';
}

рдлрд┐рд░, рдЕрдкрдиреЗ рдордЬрд╝рд╛рдХ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ, рдЖрдк рдмрд╕ рдЙрдирдХрд╛ рдордЬрд╝рд╛рдХ рдЙрдбрд╝рд╛рддреЗ рд╣реИрдВ рддрд╛рдХрд┐ 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');
});

@ рдорд╛рдЗрдХ-рдЯреНрд░рд╛рди, @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 />);
}

}

рдореЙрдбреНрдпреВрд▓.рдПрдХреНрд╕рдкреЛрд░реНрдЯреНрд╕ = рдПрд╕рдПрд╕рдУрдЯреЗрд╕реНрдЯ рдХреЙрдореНрдкреЛрдиреЗрдВрдЯ;

рдореИрдВ enjyme рдФрд░ рдЬреЗрд╕реНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдпреВрдирд┐рдЯ рдЯреЗрд╕реНрдЯ рдХреЗрд╕ рд▓рд┐рдЦ рд░рд╣рд╛ рд╣реВрдВ, рд╕реНрдерд┐рддрд┐ рд╡рд┐рдВрдбреЛ рдХреИрд╕реЗ рд▓рд┐рдЦреЗрдВрдЧреЗред рд╕реНрдерд╛рди ... рдХреГрдкрдпрд╛ рдЙрддреНрддрд░ рджреЗрдВ

рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛

    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
    });

рдЬрд╕реНрдЯ рд╕рдВрд╕реНрдХрд░рдг 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+ рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ ( рдпреВрдЖрд░рдПрд▓ рдХреНрд▓рд╛рд╕ рдбреЙрдХреНрд╕ рджреЗрдЦреЗрдВ) рдФрд░ рдореИрдВ рдЬреЗрд╕реНрдЯ 24 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рдерд╛ред

рдпрд╣ рднреА рдзреНрдпрд╛рди рджреЗрдВ, рдпрд╣ рд╕рд╛рдкреЗрдХреНрд╖ URL рдХреЗ рд╕рд╛рде рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, https://url.spec.whatwg.org/#example -url-parsing рджреЗрдЦреЗрдВред

рдпрд╣ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрд░реЗ рд▓рд┐рдП рдЬреЗрд╕реНрдЯ 24.0.0 рдФрд░ рдиреЛрдб 10.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

рдЕрд░реЗ, рдпрд╛рд░) рдмрдврд╝рд┐рдпрд╛ рдЙрдкрдпреЛрдЧ!

рдореЗрд░реЗ рд▓рд┐рдП src/setupTests.test.ts рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рдереЛрдбрд╝рд╛ рдмреЗрдорд╛рдиреА рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЖрдкрдиреЗ src/testUtils.test.ts рдореЗрдВ mockWindow рдЙрдкрдпреЛрдЧ рдХрд╛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рд╣реИред рддреЛ, src/setupTests.ts рдХреЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рдпрд╣ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ, рдХрд┐ рдЖрдк рд╕рд╣реА рддрд░реНрдХреЛрдВ рдХреЗ рд╕рд╛рде mockWindow рдХрд╣рддреЗ рд╣реИрдВред

рдЖрдкрдХреЛ рдзрдиреНрдпрд╡рд╛рдж)

@tzvipm @jup-iter рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред рдореИрдВрдиреЗ рдЕрднреА рдЬрд╛рд░реА рдХрд┐рдпрд╛ @jedmao/storage рдФрд░ @jedmao/location , рдЬреЛ рджреЛрдиреЛрдВ рдЬреЗрд╕реНрдЯ рдХреЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрдЬреНрдЮреЗрдпрд╡рд╛рджреА рд╣реИрдВред рдЖрдкрдХреЛ spyOn рдмрд┐рдирд╛ рдХреЛрдИ рдЕрддрд┐рд░рд┐рдХреНрдд рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦреЗ рдЙрдкрдпреБрдХреНрдд рддрд░реАрдХреЛрдВ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдХреНрдпреЛрдВрдХрд┐ npm рдкреИрдХреЗрдЬ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред

рдпрджрд┐ рдЖрдкрдХреЛ Vue рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рдпрд╣ рддреНрд░реБрдЯрд┐ рд╣реЛ рд░рд╣реА рд╣реИ, рддреЛ рдмрд╕ this.$router.go({...}) рдХреЗ рдмрдЬрд╛рдп this.$router.go({...}) this.$router.push({...}) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ

image

рдиреАрдЪреЗ рджрд┐рдП рдЧрдП рдХреЛрдб рдХреЛ рд▓рд╛рдЗрди 1 рдкрд░ рд░рдЦреЗрдВ:
delete global.window.location;
global.window.location = "";

рдПрдХ рдХреНрд▓рд┐рдХ рдИрд╡реЗрдВрдЯ рдЬреЛ рд╡рд┐рдВрдбреЛ рдХреЛ рдмрджрд▓ рд░рд╣рд╛ рд╣реИред рд╕реНрдерд╛рди рдЕрдм рдХреИрдкреНрдЪрд░ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

"рдЬрд╕реНрдЯ": "^ 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 рдореБрджреНрджрд╛ рд╣реИред рдлреЗрд╕рдмреБрдХ рдкрд░, рд╣рдордиреЗ рдЗрд╕рдХреЗ рдЖрд╕рдкрд╛рд╕ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬреЛ рдХрд┐рдпрд╛ рд╣реИ, рд╡рд╣ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣реИ:

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

рдпрд╣ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдБрдХрд┐ рд╣рдо рдЕрднреА рднреА рдЖрдВрддрд░рд┐рдХ рд░реВрдк рд╕реЗ jsdom 7 рдкрд░ рд╣реИрдВред

рдореИрдВ рдЗрд╕реЗ рдмрдВрдж рдХрд░ рджреВрдВрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ рдХрд┐ 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 рдореБрджреНрджрд╛ рд╣реИред рдлреЗрд╕рдмреБрдХ рдкрд░, рд╣рдордиреЗ рдЗрд╕рдХреЗ рдЖрд╕рдкрд╛рд╕ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬреЛ рдХрд┐рдпрд╛ рд╣реИ, рд╡рд╣ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣реИ:

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

рдпрд╣ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдБрдХрд┐ рд╣рдо рдЕрднреА рднреА рдЖрдВрддрд░рд┐рдХ рд░реВрдк рд╕реЗ jsdom 7 рдкрд░ рд╣реИрдВред
рдореИрдВ рдЗрд╕реЗ рдмрдВрдж рдХрд░ рджреВрдВрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ рдХрд┐ 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

рдФрд░ рдореЗрд░реА рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдПрдХ рдлрд╝реАрд▓реНрдб рд╣реИ testURL рдореЗрдВ jest.config.js рдлрд╝рд╛рдЗрд▓ рдХрд╛рдо рдХрд░ рд╕рдХрддреА рд╣реИред рд▓реЗрдХрд┐рди рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рдореИрдВ рдкреНрд░рддреНрдпреЗрдХ рдкрд░реАрдХреНрд╖рдг рд╕реЗ рдкрд╣рд▓реЗ testURL рдмрджрд▓рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред

рдореБрдЭреЗ рдпрд╣ рдкреЛрд╕реНрдЯ рдмрд╣реБрдд рдорджрджрдЧрд╛рд░ рд▓рдЧреА: https://www.ryandoll.com/post/2018/3/29/jest-and-url-mocking

"рдЕрдкрдиреЗ рдЬреЗрд╕реНрдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ, рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕реЗрдЯ рдХрд░рдирд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ:

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

рдлрд┐рд░ рдЕрдкрдиреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рдкрд╣рд▓реЗ () рдЕрдиреБрднрд╛рдЧ рдореЗрдВ, рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЖрд╡рд╢реНрдпрдХрддрд╛рдиреБрд╕рд╛рд░ рдкрде рдмрджрд▓реЗрдВ
рдЗрддрд┐рд╣рд╛рд╕ред рдкреБрд╢рд╕реНрдЯреЗрдЯ ()ред

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

рд╡реЛрдЗрд▓рд╛! рдЕрдм рдЖрдк рдХрд┐рд╕реА рднреА рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ рд░рд╛рд╕реНрддрд╛ рдмрджрд▓рддреЗ рд╣реИрдВ, рдмрд┐рдирд╛ рдХрд┐рд╕реА jsdom рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд┐рдП, рдЬреИрд╕рд╛ рдХрд┐ рдКрдкрд░ рд╡рд░реНрдгрд┐рдд рдзрд╛рдЧреЗ рдореЗрдВ рдЕрдиреНрдп рд╕реБрдЭрд╛рд╡ рджреЗрддреЗ рд╣реИрдВред рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдореБрдЭреЗ рдпрд╣ рд╕рдорд╛рдзрд╛рди рдХрд┐рд╕ рдзрд╛рдЧреЗ рдкрд░ рдорд┐рд▓рд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЙрд╕ рджреЗрд╡ рдХреЛ рдмрдзрд╛рдИ рдЬрд┐рд╕рдиреЗ рдЗрд╕реЗ рдкреЛрд╕реНрдЯ рдХрд┐рдпрд╛ рд╣реИ!"


рдмреЗрд╣рддрд░реАрди рдЙрдкрд╛рдп!!! рдЖрдкрдХрд╛ рдмрд╣реБрдд рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рдж! @ рдорд╛рдЗрдХ-рдЯреНрд░рд╛рди
рдореИрдВ рдЗрд╕ рддрд░рд╣ рдПрдХ рдЫреЛрдЯрд╛ рдФрд░ рдЖрдХреНрд░рд╛рдордХ рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рдЪрд╛рд╣рддрд╛ рдерд╛!

рдЗрд╕реЗ рдЬреВрди 2019 рддрдХ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдпрд╣ рдХрд░рдирд╛ рдерд╛:

    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);
    }

рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг 27 рд╕рд┐рддрдВрдмрд░, 2019 рддрдХ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ: 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. рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдЖрдкрдиреЗ testURL рдХреЛ jest.config.js рдореЗрдВ рд╕реЗрдЯ рдХрд┐рдпрд╛ рд╣реИ, рдЪрд╛рд╣реЗ рдХреЛрдИ рднреА рдореВрд▓реНрдп рд╣реЛ:
// 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ред рд░рдпрд╛рди рдХреЛ рдзрдиреНрдпрд╡рд╛рдж!

рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛:

рд▓реЗрдЦрди рддреНрд░реБрдЯрд┐: рд╕рдЦреНрдд рдореЛрдб рдореЗрдВ рдХреЗрд╡рд▓ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдЧреБрдгреЛрдВ рдХреЛ рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рд╣реИ

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 = "";
});

рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛:

рд▓реЗрдЦрди рддреНрд░реБрдЯрд┐: рд╕рдЦреНрдд рдореЛрдб рдореЗрдВ рдХреЗрд╡рд▓ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдЧреБрдгреЛрдВ рдХреЛ рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рд╣реИ

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 = "";
});

рдЗрд╕реЗ рд╡реИрд╢реНрд╡рд┐рдХ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред

рд╡реИрд╢реНрд╡рд┐рдХ.рд╡рд┐рдВрдбреЛ.рд╕реНрдерд╛рди рд╣рдЯрд╛рдПрдВ;
рд╡реИрд╢реНрд╡рд┐рдХ.рд╡рд┐рдВрдбреЛ.рд╕реНрдерд╛рди = "";

рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг 27 рд╕рд┐рддрдВрдмрд░, 2019 рддрдХ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ: 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
});

рдореИрдВ рд╕реНрдерд╛рди рдХреЗ рд╕рд╛рде рдХреБрдЫ рдЗрд╕реА рддрд░рд╣ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред рдЕрд╕рд╛рдЗрди рдХрд░реЗрдВ, рд▓реЗрдХрд┐рди рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЕрдм рдФрд░ рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИред

рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдЬреЗрд╕реНрдЯ 24.9.0 . рдкрд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ

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

рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдЬреЗрд╕реНрдЯ 24.9.0 . рдкрд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ

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

рдЗрд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдХреЛрдб async рдмрдирд╛рдирд╛ рдкрдбрд╝рд╛ рдХреНрдпреЛрдВрдХрд┐ рдореИрдВ рдПрдХ рд╡рд╛рджреЗ рдХреЗ рдЕрдВрджрд░ рдХреЛрдб рдЪрд▓рд╛ рд░рд╣рд╛ рдерд╛ред

рддреЛ рдЕрдм рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ

vuex рдПрдХреНрд╢рди рдореЗрдВ рдЪреЗрдВрдЬ рд▓реЛрдХреЗрд╢рди рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХреИрд╕реЗ рдХрд░реЗрдВ?

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
    });

рдЬрд╕реНрдЯ рд╕рдВрд╕реНрдХрд░рдг 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 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

rosiakr picture rosiakr  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

kentor picture kentor  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

StephanBijzitter picture StephanBijzitter  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

stephenlautier picture stephenlautier  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

paularmstrong picture paularmstrong  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ