Jsdom: 였λ₯˜: κ΅¬ν˜„λ˜μ§€ μ•ŠμŒ: 탐색

에 λ§Œλ“  2018λ…„ 01μ›” 12일  Β·  49μ½”λ©˜νŠΈ  Β·  좜처: jsdom/jsdom

졜근 버전 21.2.0μ—μ„œ 22.0.6으둜 jest (λ°±κ·ΈλΌμš΄λ“œμ—μ„œ jsdom μ‚¬μš©) μ—…κ·Έλ ˆμ΄λ“œ ν›„ 였λ₯˜κ°€ λ°œμƒν•˜κΈ° μ‹œμž‘ν–ˆμŠ΅λ‹ˆλ‹€. "Error: Not implemented:" navigation

λ‚΄ μ½”λ“œλŠ” window.location 에 μ˜μ‘΄ν•˜κ³  ν…ŒμŠ€νŠΈμ—μ„œ μ‚¬μš©ν•©λ‹ˆλ‹€.

beforeEach(() => {
                window.location.href = `/ms/submission/?mybib`;
                window.location.search = '?mybib';
});

μƒˆ λ²„μ „μ˜ jsdom을 μ‚¬μš©ν•˜μ—¬ window.location.search 값을 μ •μ˜ν•˜λŠ” 방법이 μžˆμŠ΅λ‹ˆκΉŒ?

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

λ‚΄ μžμ‹ μ˜ μ§ˆλ¬Έμ— λŒ€ν•œ 닡변을 κ²Œμ‹œν•  수 μžˆμŠ΅λ‹ˆλ‹€ 😁
λ‚˜λŠ” λ‹¨μˆœνžˆ window.location = url; 및 window.location.href = url; 의 μ‚¬μš©λ²•μ„ λ‹€μŒμœΌλ‘œ λŒ€μ²΄ν•©λ‹ˆλ‹€.

window.location.assign(url);

그런 λ‹€μŒ λ‚΄ ν…ŒμŠ€νŠΈμ—μ„œ λ‹€μŒμ„ μˆ˜ν–‰ν–ˆμŠ΅λ‹ˆλ‹€.

sinon.stub(window.location, 'assign');
expect(window.location.assign).to.have.been.calledWith(url);

맀λ ₯처럼 μž‘λ™ν•©λ‹ˆλ‹€ - λ‹€λ₯Έ μ‚¬λžŒμ—κ²Œ 도움이 되길 λ°”λžλ‹ˆλ‹€ πŸ‘

λͺ¨λ“  49 λŒ“κΈ€

λ‚˜λ„μ΄ 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€

Error: Not implemented: navigation (except hash changes)
    at module.exports (...\node_modules\jsdom\lib\jsdom\browser\not-implemented.js:9:17)
    at navigateFetch (...\node_modules\jsdom\lib\jsdom\living\window\navigation.js:74:3)

jsdom은 탐색을 μ§€μ›ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ window.location.href λ˜λŠ” 이와 μœ μ‚¬ν•œ 섀정은 이 λ©”μ‹œμ§€λ₯Ό ν‘œμ‹œν•©λ‹ˆλ‹€. Jestκ°€ 이전에 μ΄λŸ¬ν•œ λ©”μ‹œμ§€λ₯Ό μ–΅μ œν–ˆλŠ”μ§€, μ•„λ‹ˆλ©΄ 무엇인지 잘 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€.

이것은 μ•„λ§ˆλ„ ν…ŒμŠ€νŠΈμ—μ„œ μˆ˜μ •ν•΄μ•Ό ν•  사항일 κ²ƒμž…λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ λΈŒλΌμš°μ €μ—μ„œ ν•΄λ‹Ή ν…ŒμŠ€νŠΈλ₯Ό μ‹€ν–‰ν•˜λŠ” 경우 νŽ˜μ΄μ§€λ₯Ό μƒˆ URL둜 탐색할 λ•Œ ν…ŒμŠ€νŠΈ μ‹€ν–‰κΈ°κ°€ μ™„μ „νžˆ λ‚ μ•„κ°€κ³  ν…ŒμŠ€νŠΈλ₯Ό λ³Ό 수 μ—†κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. κ²°κ³Ό. λŒ€μ‹  jsdomμ—μ„œλŠ” μ½˜μ†”μ— λ©”μ‹œμ§€λ₯Ό 좜λ ₯ν•©λ‹ˆλ‹€. μ›ν•˜λŠ” 경우 λ¬΄μ‹œν•˜κ±°λ‚˜ 더 λ§Žμ€ ν™˜κ²½μ—μ„œ 더 잘 μž‘λ™ν•˜λ„λ‘ ν…ŒμŠ€νŠΈλ₯Ό μˆ˜μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ–΄μ¨Œλ“ , λ‚˜λŠ” μ‚¬λžŒλ“€μ„ μœ„ν•΄ 이것에 λŒ€ν•œ 더 λ§Žμ€ λ¬Έμ„œλ₯Ό μΆ”κ°€ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ 이 문제λ₯Ό μΆ”μ ν•˜κΈ° μœ„ν•΄ 이 문제λ₯Ό μ—΄μ–΄ λ‘κ² μŠ΅λ‹ˆλ‹€.

당신이 λ§ν•˜λŠ” 것을 μ™„μ „νžˆ μ΄ν•΄ν•˜μ‹­μ‹œμ˜€. 졜근 Jest 22 μ—…λ°μ΄νŠΈλŠ” JSDOM 9μ—μ„œ 11 IIRC둜 μ΄λ™ν–ˆμœΌλ―€λ‘œ 9.xμ—μ„œμ˜ λ™μž‘μ€ μƒλ‹Ήνžˆ λ‹€λ₯Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

κ·Έ λͺ¨λ“  것을 μ œμ³λ‘κ³ , λ‚˜λŠ” (HTML5 pushstate와 μœ μ‚¬ν•œ μ •μ‹ μœΌλ‘œ) λ‹€λ₯Έ νŽ˜μ΄μ§€λ₯Ό λ‘œλ“œν•˜λŠ” μΈ‘λ©΄μ—μ„œ μž‘λ™ν•˜μ§€ μ•Šλ„λ‘ ν•˜κΈ° μœ„ν•΄ μΌμ’…μ˜ ν”Œλž˜κ·Έλ₯Ό μ‚¬μš©ν•˜μ—¬ JSDOM에 κ΅¬ν˜„λœ 탐색을 보고 μ‹ΆμŠ΅λ‹ˆλ‹€. λΌμ΄λΈŒλŸ¬λ¦¬λŠ” ν…ŒμŠ€νŠΈ λͺ©μ μœΌλ‘œ 맀우 일반적으둜 μ‚¬μš©λ©λ‹ˆλ‹€. κ·Έλž˜μ„œ μ•„λ§ˆλ„ κΈ°λ°œν•œ μš”μ²­μ΄κΈ°λŠ” ν•˜μ§€λ§Œ 자주 μ‚¬μš©λ©λ‹ˆλ‹€.

ν…ŒμŠ€νŠΈλ₯Ό λΈŒλΌμš°μ €μ™€ jsdomμ—μ„œ λ‹€λ₯΄κ²Œ μ‹€ν–‰ν•˜λŠ” ν”Œλž˜κ·Έλ₯Ό μΆ”κ°€ν•΄μ•Ό ν•œλ‹€κ³  μƒκ°ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 그러면 λΈŒλΌμš°μ €μ—μ„œ 물건이 손상될 수 있으며(예: ν…ŒμŠ€νŠΈμ—μ„œ λ°œμƒν•˜λŠ” μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” λŒ€μ‹  μ‚¬μš©μžλ₯Ό λ‹€λ₯Έ νŽ˜μ΄μ§€λ‘œ λ¦¬λ””λ ‰μ…˜ν•  수 있음) λˆˆμΉ˜μ±„μ§€ λͺ»ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€!

이 κ²½μš°μ—λŠ” ν˜„μž¬ νŽ˜μ΄μ§€ μ»¨ν…μŠ€νŠΈλ₯Ό μ–Έλ‘œλ“œν•˜μ§€ μ•ŠλŠ” 것 μ™Έμ—λŠ” 아무 것도 ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ‚˜λŠ” μ—¬μ „νžˆ window.location.href 등이 μ—…λ°μ΄νŠΈλ  κ²ƒμœΌλ‘œ κΈ°λŒ€ν•©λ‹ˆλ‹€.

@domenic 저도 같은 λ¬Έμ œκ°€ 있고 window.location λ₯Ό μ„€μ •ν•˜λŠ” μ•±μœΌλ‘œ JSDOM을 μ„€μ •ν•˜λŠ” λͺ¨λ²” 사둀가 μžˆλŠ”μ§€ κΆκΈˆν•©λ‹ˆλ‹€. λ‚΄κ°€ 말할 μˆ˜μžˆλŠ” κ²ƒμ—μ„œ JSDOM은 window.location λ₯Ό μ„€μ •ν•˜λ €κ³  ν•  λ•Œ 였λ₯˜κ°€ λ°œμƒν•˜κ³  window.location.href λ₯Ό μ„€μ •ν•˜λ €κ³  ν•  λ•Œ 였λ₯˜λ₯Ό κΈ°λ‘ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ mdnμ—μ„œ λ‘˜μ€ λ™μ˜μ–΄μ—¬μ•Ό ν•œλ‹€λŠ” 것을 읽고 μžˆμŠ΅λ‹ˆλ‹€. μŠ€ν…ν•˜κΈ° μ‰¬μš΄ λ‹€λ₯Έ λ°©λ²•μœΌλ‘œ μœ„μΉ˜λ₯Ό μ—…λ°μ΄νŠΈν•΄μ•Ό ν•©λ‹ˆκΉŒ?
λ„μ™€μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€ πŸ˜‚

λ‚΄ μžμ‹ μ˜ μ§ˆλ¬Έμ— λŒ€ν•œ 닡변을 κ²Œμ‹œν•  수 μžˆμŠ΅λ‹ˆλ‹€ 😁
λ‚˜λŠ” λ‹¨μˆœνžˆ window.location = url; 및 window.location.href = url; 의 μ‚¬μš©λ²•μ„ λ‹€μŒμœΌλ‘œ λŒ€μ²΄ν•©λ‹ˆλ‹€.

window.location.assign(url);

그런 λ‹€μŒ λ‚΄ ν…ŒμŠ€νŠΈμ—μ„œ λ‹€μŒμ„ μˆ˜ν–‰ν–ˆμŠ΅λ‹ˆλ‹€.

sinon.stub(window.location, 'assign');
expect(window.location.assign).to.have.been.calledWith(url);

맀λ ₯처럼 μž‘λ™ν•©λ‹ˆλ‹€ - λ‹€λ₯Έ μ‚¬λžŒμ—κ²Œ 도움이 되길 λ°”λžλ‹ˆλ‹€ πŸ‘

기본적으둜 μž‘λ™ν•΄μ•Ό ν•œλ‹€λŠ” 데 λ™μ˜ν•©λ‹ˆλ‹€. μš°λ¦¬λŠ” FBμ—μ„œ window.location λ₯Ό μ‘°λ‘±ν•˜μ§€λ§Œ jsdom의 History κ΅¬ν˜„κ³Ό μΆ©λŒν•©λ‹ˆλ‹€.

μ†Œκ·œλͺ¨ νŒ€μœΌλ‘œμ„œ μš°λ¦¬λŠ” jsdomμ—μ„œ 탐색을 μ μ ˆν•˜κ²Œ κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄ μš°λ¦¬μ—κ²Œ μ˜μ‘΄ν•˜λŠ” 더 큰 ν”„λ‘œμ νŠΈμ˜ 도움에 ν™•μ‹€νžˆ 감사할 κ²ƒμž…λ‹ˆλ‹€.

관심 μžˆλŠ” μ‚¬λžŒμ΄ μžˆλ‹€λ©΄ https://github.com/jsdom/jsdom/pull/1913 μ—μ„œ μ‹œμž‘ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

κ°€λŠ₯ν•œ 해결책은 λ‹¨μœ„ ν…ŒμŠ€νŠΈμ—μ„œ window κ°œμ²΄μ— λŒ€ν•œ 쒅속성 μ£Όμž…/λͺ¨μ˜μ— μ˜μ‘΄ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같은 것:

it('can test', () => {
  const mockWindow = {location: {href: null}};
  fn({window: mockWindow});
  expect(mockWindow.href).toEqual('something');
});

이것은 μ΄μƒμ μ΄μ§€λŠ” μ•Šμ§€λ§Œ @domenic이 λ§ν–ˆλ“―μ΄ :

이것은 μ•„λ§ˆλ„ ν…ŒμŠ€νŠΈμ—μ„œ μˆ˜μ •ν•΄μ•Ό ν•  사항일 κ²ƒμž…λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ λΈŒλΌμš°μ €μ—μ„œ ν•΄λ‹Ή ν…ŒμŠ€νŠΈλ₯Ό μ‹€ν–‰ν•˜λŠ” 경우 νŽ˜μ΄μ§€λ₯Ό μƒˆ URL둜 탐색할 λ•Œ ν…ŒμŠ€νŠΈ μ‹€ν–‰κΈ°κ°€ μ™„μ „νžˆ λ‚ μ•„κ°ˆ 것이기 λ•Œλ¬Έμž…λ‹ˆλ‹€.

μ§€κΈˆ μš°λ¦¬λŠ” 이것과 ν•¨κ»˜ μ‚΄κ³  μžˆμŠ΅λ‹ˆλ‹€. 예, μš°λ¦¬λŠ” λ‚˜μœ μŠ΅κ΄€μœΌλ‘œ κ°„μ£Όλ˜λŠ” ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•΄ κ΅¬ν˜„ μ½”λ“œλ₯Ό λ³€κ²½ν•˜μ§€λ§Œ 밀에도 잘 자고 μžˆμŠ΅λ‹ˆλ‹€!

ν–‰λ³΅ν•œ ν…ŒμŠ€νŠΈ

@hontas 의 μ†”λ£¨μ…˜μ΄ 도움이 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

λ‚΄ μ½”λ“œμ—μ„œ window.location.assign(Config.BASE_URL); ν–ˆμŠ΅λ‹ˆλ‹€.

ν…ŒμŠ€νŠΈλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

jest.spyOn(window.location, 'assign').mockImplementation( l => {
   expect(l).toEqual(Config.BASE_URL);
})

window.location.assign.mockClear();

같은 문제, λ‚΄ μ½”λ“œμ—μ„œ window.location.search = foo; λ₯Ό μ‚¬μš©ν•˜κ³  있으며 jsdom(및 jest)을 μ‚¬μš©ν•˜μ—¬ ν…ŒμŠ€νŠΈν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€. πŸ€”

μΆ”μ‹ : https://github.com/facebook/jest/issues/5266 κ΄€λ ¨

jsdom 12.2.0으둜 μ—…λ°μ΄νŠΈν•œ ν›„ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.
TypeError: 속성을 μž¬μ •μ˜ν•  수 μ—†μŒ: ν• λ‹Ή
const assign = sinon.stub(document.location, 'assign')
그것을 κ³ μΉ˜λŠ” 방법?

@yuri-sakharov

jsdom 12.2.0으둜 μ—…λ°μ΄νŠΈν•œ ν›„ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.
TypeError: 속성을 μž¬μ •μ˜ν•  수 μ—†μŒ: ν• λ‹Ή
const assign = sinon.stub(document.location, 'assign')
그것을 κ³ μΉ˜λŠ” 방법?

sinon.stub(document.location, 'assign')

될 ν•„μš”κ°€μžˆλ‹€:

sinon.stub(window.location, 'assign')

document λ₯Ό window 둜 λ°”κΏ”μ•Ό ν•©λ‹ˆλ‹€.

λ‚˜λŠ” λ‹€μŒκ³Ό 같은 κΈ°λŠ₯을 κ°€μ§€κ³ μžˆλ‹€

export const isLocalHost = () => Boolean(
  window.location.hostname === 'localhost' ||
  // [::1] is the IPv6 localhost address.
  window.location.hostname === '[::1]' ||
  // 127.0.0.1/8 is considered localhost for IPv4.
  window.location.hostname.match(
    /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
  )
);

μž‘λ™ν•˜λŠ”μ§€ ν…ŒμŠ€νŠΈν•  수 μžˆλ„λ‘ 직접 hostname μ£Όμž…ν•©λ‹ˆλ‹€.

it('#isLocalHost should return true for all the cases of localhost', () => {
    window.location.hostname = 'localhost';
    expect(isLocalHost()).toBeTruthy();

    window.location.hostname = '[::1]';
    expect(isLocalHost()).toBeTruthy();

    window.location.hostname = '127.0.0.1';
    expect(isLocalHost()).toBeTruthy();

    // Reset back the hostname to avoid issues with it
    window.location.hostname = '';
  });

ν•˜μ§€λ§Œ 이 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.

jsdom κ°€ 탐색을 μ™„μ „νžˆ κ΅¬ν˜„ν•˜κΈ°λ₯Ό κΈ°λŒ€ν•˜μ§€λŠ” μ•Šμ§€λ§Œ μ΅œμ†Œν•œ ν‚€λ₯Ό μΆ”κ°€ν•˜κ³  κΈ°λŠ₯을 μ‘°λ‘±ν•©λ‹ˆλ‹€.

μ™œ 이 였λ₯˜κ°€ 계속 λ°œμƒν•˜λŠ”μ§€ ν˜Όλž€μŠ€λŸ¬μ›Œμ„œ 값을 μ„€μ •ν•  수 있기λ₯Ό μ›ν•©λ‹ˆλ‹€.

@nickhallph
λ‚˜λŠ” 당신이 μ“΄λŒ€λ‘œ 그것을 window.location 둜 λ°”κΎΈμ—ˆμ§€λ§Œ κ²°κ³ΌλŠ” λ™μΌν•©λ‹ˆλ‹€.
TypeError: Cannot redefine property: assign
μ–΄λ–€ 아이디어?

@yuri-sakharov μ‹€ν–‰ λͺ¨μΉ΄μ™€ λ™μΌν•œ λ¬Έμ œμž…λ‹ˆλ‹€.

κ²°μ½” window.location.* 둜 λŒ€μ²΄/μ—…λ°μ΄νŠΈ/λͺ¨μ˜ν•˜κ±°λ‚˜ 무엇이든 ν•  수 μžˆλŠ” 것 같지 μ•ŠμŠ΅λ‹ˆλ‹€. 이 문제λ₯Ό ν•΄κ²°ν•˜λŠ” μœ μΌν•œ 방법은 μ‚¬μš©μž μ •μ˜ window.location λͺ¨μ˜λ₯Ό λ§Œλ“€κ³  이에 따라 전체 μ½”λ“œλ² μ΄μŠ€λ₯Ό λ³€κ²½ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

@hontas 의 μ†”λ£¨μ…˜μ΄ 도움이 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

λ‚΄ μ½”λ“œμ—μ„œ window.location.assign(Config.BASE_URL); ν–ˆμŠ΅λ‹ˆλ‹€.

ν…ŒμŠ€νŠΈλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

jest.spyOn(window.location, 'assign').mockImplementation( l => {
   expect(l).toEqual(Config.BASE_URL);
})

window.location.assign.mockClear();

@zxest 의 @hontas ' μ†”λ£¨μ…˜μ˜ Jest 버전은 μ €μ—κ²Œ νš¨κ³Όκ°€ μ—†μ—ˆμ§€λ§Œ λ‹€μŒκ³Ό 같이 ν–ˆμŠ΅λ‹ˆλ‹€.

window.location.assign = jest.fn();
expect(window.location.assign).toHaveBeenCalledWith('https://correct-uri.com');
window.location.assign.mockRestore();

location.assign λ₯Ό μ‚¬μš©ν•˜λ„λ‘ μ½”λ“œλ₯Ό λ³€κ²½ν•˜κ³  싢지 μ•Šμ€ 경우 - 이것은 JSDom 11 및 13μ—μ„œ μž‘λ™ν•˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

delete window.location;
window.location = {}; // or stub/spy etc.

λ§ˆμ§€λ§‰ λŒ€λ‹΅μ€ μ €μ—κ²Œ νš¨κ³Όμ μ΄μ—ˆμ§€λ§Œ replace λ₯Ό μ •μ˜ν•΄μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€.

delete window.location
window.location = { replace: jest.fn() }

도움이 되기λ₯Ό λ°”λžλ‹ˆλ‹€.

TypeError: Cannot redefine property: assign with sinon 7.2.3 및 jsdom 13.2.0이 ν‘œμ‹œλ©λ‹ˆλ‹€. 이것이 일뢀 μ‚¬λžŒλ“€μ—κ²ŒλŠ” νš¨κ³Όκ°€ 있고 λ‹€λ₯Έ μ‚¬λžŒλ“€μ—κ²ŒλŠ” νš¨κ³Όκ°€ μ—†λŠ” 이유λ₯Ό λͺ¨λ₯΄μ‹­λ‹ˆκΉŒ?

이것이 λ‚˜λ₯Ό μœ„ν•΄ μΌν•œ κ²ƒμž…λ‹ˆλ‹€.

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

μš°λ¦¬λŠ” 이것을 μž‘λ™μ‹œν‚€κΈ° μœ„ν•΄ pushState λ₯Ό μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€.

 window.history.pushState(
        {},
        '',
        'http://localhost/something/123?order=asc'
      );

이것은 μ–΄λ €μš΄ μƒν™©μž…λ‹ˆλ‹€. JSDOM은 탐색(λΈŒλ ˆλ“œν¬λŸΌ μ œμ™Έ)을 μ™„λ²½ν•˜κ²Œ μ§€μ›ν•˜μ§€ μ•ŠμœΌλ©° JSDOM은 탐색을 λͺ¨μ˜(mock-out) ν—ˆμš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ΅œμ’… κ²°κ³ΌλŠ” ꢁ극적으둜 탐색을 νŠΈλ¦¬κ±°ν•˜λ €κ³  μ‹œλ„ν•˜λŠ” ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•  수 μ—†λ‹€λŠ” 것 μž…λ‹ˆλ‹€.

JSDOM이 νƒμƒ‰ν•˜λŠ” 법을 λ°°μ› λ‹€λ©΄(그것이 무엇을 μ˜λ―Έν•˜λŠ”μ§€ 저도 잘 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€), μ•„λ§ˆλ„ μ μ ˆν•œ νŽ˜μ΄μ§€μ— μžˆλ‹€κ³  μ£Όμž₯ν•  수 μžˆμ„ κ²ƒμž…λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λ‚΄ ν…ŒμŠ€νŠΈ μ‚¬μš© μ‚¬λ‘€μ˜ 경우 μ‹€μ œλ‘œ μˆ˜ν–‰λœ 것이 μ•„λ‹ˆλΌ 탐색이 νŠΈλ¦¬κ±°λ˜μ—ˆλ‹€κ³  μ£Όμž₯ν•˜λŠ” 것이 훨씬 더 κΉ¨λ—ν•˜κ³  λΉ λ¦…λ‹ˆλ‹€. jsdom을 μ‚¬μš©ν•˜μ—¬ ν…ŒμŠ€νŠΈν•  λ•Œ μ—­μ‚¬μ μœΌλ‘œ μˆ˜ν–‰ν•œ μž‘μ—…μ΄λ©° μ΄μ œλŠ” μ†μƒλ˜μ—ˆμŠ΅λ‹ˆλ‹€.

λ‚΄ μ§ˆλ¬Έμ— λŒ€ν•œ 닡변을 κ²Œμ‹œν•˜λ„λ‘ ν—ˆμš©
λ‚˜λŠ” λ‹¨μˆœνžˆ window.location = url; 및 window.location.href = url; 의 μ‚¬μš©λ²•μ„ λ‹€μŒμœΌλ‘œ λŒ€μ²΄ν•©λ‹ˆλ‹€.

window.location.assign(url);

그런 λ‹€μŒ λ‚΄ ν…ŒμŠ€νŠΈμ—μ„œ λ‹€μŒμ„ μˆ˜ν–‰ν–ˆμŠ΅λ‹ˆλ‹€.

sinon.stub(window.location, 'assign');
expect(window.location.assign).to.have.been.calledWith(url);

맀λ ₯처럼 μž‘λ™ν•©λ‹ˆλ‹€ - λ‹€λ₯Έ μ‚¬λžŒμ—κ²Œ 도움이 되기λ₯Ό λ°”λžλ‹ˆλ‹€.

λŒ€μƒ URL에 λŒ€ν•œ μ œμ–΄ κΆŒν•œμ΄ μžˆμ§€λ§Œ Google λ˜λŠ” Instagram μ›Ή μ‚¬μ΄νŠΈλ₯Ό λ‘œλ“œν•˜λŠ” κ²½μš°μ—λŠ” μ–΄λ–»κ²Œ λ κΉŒμš”? λ˜λŠ” μ–΄λ–€ μ›Ήμ‚¬μ΄νŠΈ? 이 문제λ₯Ό μ–΄λ–»κ²Œ ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

@chrisbateman의 닡변을 기반으둜 Jest ν™˜κ²½μ—μ„œ 이 μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. Jestλ₯Ό μ‚¬μš©ν•˜λŠ” μ‚¬λžŒμ„ μœ„ν•œ ν•΄κ²° 방법은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

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

    beforeEach(() => {
        delete window.location;

        window.location = {
            href: '',
        };
    });

    afterEach(() => {
        window.location = originalLocation;
    });

    it('', () => {
        // test here
    });
});

이 ꡬ성을 μ‚¬μš©ν•˜μ—¬ 이 문제λ₯Ό ν•΄κ²°ν–ˆμŠ΅λ‹ˆλ‹€. ν•΄μ‹œ URL에 λŒ€ν•œ λ¦¬λ””λ ‰μ…˜μ„ ν…ŒμŠ€νŠΈν•˜κ³  μ‹Άμ—ˆμŠ΅λ‹ˆλ‹€.

    beforeEach(() => {
      delete global.window;
      global.window = {
        location: { replace: jest.fn(url => ({ href: url })) },
      };
    });
    it('should redirect hash url', () => {
      window.location.hash = '#/contrat?id=8171675304';
      global.window.location.href =
        'http://localhost:3000/#/contrat?id=8171675304';
      redirectHashUrl();

      expect(window.location.replace).toHaveBeenCalled();
    });

@chrisbateman @hamzahamidi κ°μ‚¬ν•©λ‹ˆλ‹€. μ†”λ£¨μ…˜μ΄ 잘 μž‘λ™ν–ˆμŠ΅λ‹ˆλ‹€.

쒋은 방법은 μ•„λ‹ˆμ§€λ§Œ μœ„μΉ˜/호슀트/호슀트 이름 및 기타 μœ„μΉ˜ 속성에 μ˜μ‘΄ν•˜λŠ” λͺ‡ 가지 ν…ŒμŠ€νŠΈκ°€ μžˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ μš°λ¦¬κ°€ μ›ν•˜λŠ”λŒ€λ‘œ μœ„μΉ˜λ₯Ό μ‘°λ‘±ν•˜κ³  λ‚˜μ€‘μ— λ³΅μ›ν•˜λŠ” 것이 μ €μ—κ²Œ νš¨κ³Όμ μ΄μ—ˆμŠ΅λ‹ˆλ‹€.

const realLocation = window.location;

describe('bla bla', () => {
  afterEach(() => {
    window.location = realLocation;
  });

  it('test where I want to use hostname', () => {
    delete window.location;
    window.location = { 
      hostname: 'my-url-i-expect.com'
    };
    // check my function that uses hostname
  });
});

이것이 λ‚˜λ₯Ό μœ„ν•΄ μΌν•œ κ²ƒμž…λ‹ˆλ‹€.

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

circleci와 같은 CI μ—μ„œλŠ” μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

@hontas 의 μ†”λ£¨μ…˜μ΄ 도움이 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

λ‚΄ μ½”λ“œμ—μ„œ window.location.assign(Config.BASE_URL); ν–ˆμŠ΅λ‹ˆλ‹€.

ν…ŒμŠ€νŠΈλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

jest.spyOn(window.location, 'assign').mockImplementation( l => {
   expect(l).toEqual(Config.BASE_URL);
})

window.location.assign.mockClear();

κ³ λ§ˆμ›Œ 친ꡬ, 당신은 λ‚˜μ—κ²Œ ν•˜λ£¨λ₯Ό κ΅¬ν–ˆμŠ΅λ‹ˆλ‹€! :)

λ‚΄ κ²½μš°μ—λŠ” λ‚΄κ°€ 쿼리 λ¬Έμžμ—΄μ„ ν…ŒμŠ€νŠΈν•˜κ³ μžˆμ–΄, λ‚΄ μ‚¬μ–‘μ˜ μ£Όμ œλŠ” 쿼리 λ¬Έμžμ—΄ 자체이기 λ•Œλ¬Έμ—, λ‚˜λŠ” 그것을 우회 싢지 μ•Šμ•„,ν•˜μ§€λ§Œ λ‚œ 그것을 λ°–μœΌλ‘œ μŠ€ν… λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€. 제 κ²½μš°μ—λŠ” 이것이 잘 μž‘λ™ν–ˆμŠ΅λ‹ˆλ‹€.

    let name = "utm_content"
    window.history.pushState({}, 'Test Title', '/test.html?utm_content=abc');
    expect(ParseUrlUtils.getParam(name)).toBe("abc")

μ—¬κΈ°μ„œ 창의 제λͺ©μ΄ λ¬΄μ—‡μΈμ§€λŠ” μ€‘μš”ν•˜μ§€ μ•ŠμœΌλ©° /test.html (μ‹€μ œκ°€ μ•„λ‹˜)인 것도 μ€‘μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ€‘μš”ν•œ 것은 쿼리 λ¬Έμžμ—΄μ„ μ˜¬λ°”λ₯΄κ²Œ κ°€μ Έμ˜€λŠ” κ²ƒμž…λ‹ˆλ‹€( 이것은 톡과)

예제의 λ¬Έμ œλŠ” λ©”μ„œλ“œμ™€ κ²Œν„°κ°€ μ‚¬μš©λ˜μ§€ μ•ŠλŠ”λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. λ‚΄κ°€ν•˜λŠ” 일은 기본적으둜 Location 객체λ₯Ό URL 객체둜 λ°”κΎΈλŠ” κ²ƒμž…λ‹ˆλ‹€. URLμ—λŠ” Location의 λͺ¨λ“  속성(검색, 호슀트, ν•΄μ‹œ λ“±)이 μžˆμŠ΅λ‹ˆλ‹€.

const realLocation = window.location;

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

    afterEach(() => {
        window.location = realLocation;
    });

    test('My test func', () => {

        // @ts-ignore
        delete window.location;

        // @ts-ignore
        window.location = new URL('http://google.com');

        // ...
    });
});

λ‚˜λ„μ΄ 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€

Error: Not implemented: navigation (except hash changes)
    at module.exports (...\node_modules\jsdom\lib\jsdom\browser\not-implemented.js:9:17)
    at navigateFetch (...\node_modules\jsdom\lib\jsdom\living\window\navigation.js:74:3)

@hontas 의 μ†”λ£¨μ…˜μ΄ 도움이 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

λ‚΄ μ½”λ“œμ—μ„œ window.location.assign(Config.BASE_URL); ν–ˆμŠ΅λ‹ˆλ‹€.

ν…ŒμŠ€νŠΈλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

jest.spyOn(window.location, 'assign').mockImplementation( l => {
   expect(l).toEqual(Config.BASE_URL);
})

window.location.assign.mockClear();

이것은 λ‚˜λ₯Ό μœ„ν•΄ μΌν–ˆμŠ΅λ‹ˆλ‹€. κ°μ‚¬ν•©λ‹ˆλ‹€! κ·ΈλŸ¬λ‚˜ jest test()μ—μ„œ done 인수λ₯Ό μ‚¬μš©ν•΄μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€. 그렇지 μ•ŠμœΌλ©΄ μ˜ˆμƒμ΄ ν‰κ°€λ˜κ³  ν…ŒμŠ€νŠΈκ°€ μ–΄μ¨Œλ“  μ„±κ³΅μ μœΌλ‘œ μ’…λ£Œλ˜μ—ˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

it('should', (done) => {
jest.spyOn(window.location, 'assign').mockImplementation( l => {
   expect(l).toEqual(Config.BASE_URL);
   done();
})

window.location.assign.mockClear();
}

@hontas λŠ” λ‚˜λ₯Ό μœ„ν•΄ μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€ :( ν• λ‹Ή/ꡐ체 속성을 λ‹€μ‹œ μ“Έ 수 μ—†μŠ΅λ‹ˆλ‹€

"κ΅¬ν˜„λ˜μ§€ μ•ŠμŒ: 탐색" λ©”μ‹œμ§€λ₯Ό νŠΈλ¦¬κ±°ν•˜λŠ” ν…ŒμŠ€νŠΈλ₯Ό 찾을 수 μžˆλŠ” 방법이 μžˆμŠ΅λ‹ˆκΉŒ? 43개의 ν…ŒμŠ€νŠΈ λͺ¨μŒμ΄ μžˆμŠ΅λ‹ˆλ‹€. 였λ₯˜λŠ” ν•œ 번만 ν‘œμ‹œλ˜κ³  계속 νŠ•κΉλ‹ˆλ‹€. μ–΄λ–€ ν…ŒμŠ€νŠΈλ₯Ό 고칠지 말할 수 μ—†μŠ΅λ‹ˆλ‹€!!! μŠ€νƒ 좔적은 λ‚˜μ—κ²Œ λ²”μΈμ˜ ν‘œμ‹œλ₯Ό μ œκ³΅ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€:

console.error
  Error: Not implemented: navigation (except hash changes)
      at module.exports (/Users/naresh/projects/mobx-state-router/node_modules/jsdom/lib/jsdom/browser/not-implemented.js:9:17)
      at navigateFetch (/Users/naresh/projects/mobx-state-router/node_modules/jsdom/lib/jsdom/living/window/navigation.js:76:3)
      at exports.navigate (/Users/naresh/projects/mobx-state-router/node_modules/jsdom/lib/jsdom/living/window/navigation.js:54:3)
      at Timeout._onTimeout (/Users/naresh/projects/mobx-state-router/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils-impl.js:81:7)
      at listOnTimeout (internal/timers.js:531:17)
      at processTimers (internal/timers.js:475:7) undefined

    at VirtualConsole.<anonymous> (node_modules/jsdom/lib/jsdom/virtual-console.js:29:45)
    at module.exports (node_modules/jsdom/lib/jsdom/browser/not-implemented.js:12:26)
    at navigateFetch (node_modules/jsdom/lib/jsdom/living/window/navigation.js:76:3)
    at exports.navigate (node_modules/jsdom/lib/jsdom/living/window/navigation.js:54:3)
    at Timeout._onTimeout (node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils-impl.js:81:7)

@hontas λŠ” λ‚˜λ₯Ό μœ„ν•΄ μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€ :( ν• λ‹Ή/ꡐ체 속성을 λ‹€μ‹œ μ“Έ 수 μ—†μŠ΅λ‹ˆλ‹€

jestκ°€ μƒˆ 버전("jest": "^26.0.1")μ—μ„œ λ³€κ²½ν•œ 것을 μ΄ν•΄ν•˜λ―€λ‘œ μ§€κΈˆ λ°”λ‘œ μž‘λ™ν•©λ‹ˆλ‹€.

// Mock
  Object.defineProperty(window, 'location', {
    value: {
      pathname: '/terminals',
      assign: jest.fn(),
    },
  });

// Then test
expect(window.location.assign).toBeCalledWith('/auth');

"κ΅¬ν˜„λ˜μ§€ μ•ŠμŒ: 탐색" λ©”μ‹œμ§€λ₯Ό νŠΈλ¦¬κ±°ν•˜λŠ” ν…ŒμŠ€νŠΈλ₯Ό 찾을 수 μžˆλŠ” 방법이 μžˆμŠ΅λ‹ˆκΉŒ? 43개의 ν…ŒμŠ€νŠΈ λͺ¨μŒμ΄ μžˆμŠ΅λ‹ˆλ‹€. 였λ₯˜λŠ” ν•œ 번만 ν‘œμ‹œλ˜κ³  계속 νŠ•κΉλ‹ˆλ‹€. μ–΄λ–€ ν…ŒμŠ€νŠΈλ₯Ό 고칠지 말할 수 μ—†μŠ΅λ‹ˆλ‹€!!! μŠ€νƒ 좔적은 λ‚˜μ—κ²Œ λ²”μΈμ˜ ν‘œμ‹œλ₯Ό μ œκ³΅ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€:

console.error
  Error: Not implemented: navigation (except hash changes)
      at module.exports (/Users/naresh/projects/mobx-state-router/node_modules/jsdom/lib/jsdom/browser/not-implemented.js:9:17)
      at navigateFetch (/Users/naresh/projects/mobx-state-router/node_modules/jsdom/lib/jsdom/living/window/navigation.js:76:3)
      at exports.navigate (/Users/naresh/projects/mobx-state-router/node_modules/jsdom/lib/jsdom/living/window/navigation.js:54:3)
      at Timeout._onTimeout (/Users/naresh/projects/mobx-state-router/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils-impl.js:81:7)
      at listOnTimeout (internal/timers.js:531:17)
      at processTimers (internal/timers.js:475:7) undefined

    at VirtualConsole.<anonymous> (node_modules/jsdom/lib/jsdom/virtual-console.js:29:45)
    at module.exports (node_modules/jsdom/lib/jsdom/browser/not-implemented.js:12:26)
    at navigateFetch (node_modules/jsdom/lib/jsdom/living/window/navigation.js:76:3)
    at exports.navigate (node_modules/jsdom/lib/jsdom/living/window/navigation.js:54:3)
    at Timeout._onTimeout (node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils-impl.js:81:7)

μ–΄λ–€ ν…ŒμŠ€νŠΈμ—μ„œ κ΅¬ν˜„λ˜μ§€ μ•Šμ€ 였λ₯˜κ°€ λ°œμƒν–ˆλŠ”μ§€ λ§ν•˜κΈ°λŠ” μ–΄λ ΅μŠ΅λ‹ˆλ‹€.

node_modules/jsdom/lib/jsdom/browser/not-implemented.js:12 쀑단점을 μΆ”κ°€ν•˜κ³  디버그 μ„Έμ…˜μ„ μ‹€ν–‰ν•˜κ³  쀑단점에 도달할 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦½λ‹ˆλ‹€. κ·Έλž˜μ•Όλ§Œ 이 λ©”μ‹œμ§€λ₯Ό μ—†μ• κΈ° μœ„ν•΄ μ–΄λ–€ ν…ŒμŠ€νŠΈλ₯Ό κ°œμ„ ν•΄μ•Ό ν•˜λŠ”μ§€ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.
image

λ•Œλ•Œλ‘œ λŸ¬λ„ˆκ°€ λ¬Έμ œκ°€ μžˆλŠ” ν…ŒμŠ€νŠΈμ— 도달할 λ•ŒκΉŒμ§€ 2-3뢄이 κ±Έλ¦½λ‹ˆλ‹€.

μΆ”μ‹ : ν˜„μž¬ ν”„λ‘œμ νŠΈμ—λŠ” 176개의 jsdom κ΄€λ ¨ ν…ŒμŠ€νŠΈκ°€ μžˆμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” ν˜„μž¬ Jest 26.0.1 ν•˜κ³  있으며 λ‹€μŒμ΄ μ €μ—κ²Œ νš¨κ³Όμ μž…λ‹ˆλ‹€.

  1. window.location.assign(url) λ₯Ό μ‚¬μš©ν•˜μ—¬ μ°½ μœ„μΉ˜λ₯Ό λ³€κ²½ν•©λ‹ˆλ‹€.

  2. λ‹€μŒκ³Ό 같이 μœ„μΉ˜ 객체λ₯Ό μ‘°λ‘±ν•©λ‹ˆλ‹€(객체λ₯Ό λ¨Όμ € μ‚­μ œν•˜κ³  λ‹€μ‹œ λΉŒλ“œν•˜μ§€ μ•ŠμœΌλ©΄ Jest 및 이전 λ²„μ „μ—μ„œ μ—¬μ „νžˆ κ΅¬ν˜„λ˜μ§€ μ•Šμ€ 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€. λ˜ν•œ Object.defineProperty 도 μž‘λ™ν•˜μ§€ μ•Šκ³  μ—¬μ „νžˆ κ²°κ³Όκ°€ 였λ₯˜):

delete window.location;
window.location = {
    href: '',
    hostname: '',
    pathname: '',
    protocol: '',
    assign: jest.fn()
};
  1. λ‹€μŒμœΌλ‘œ μ£Όμž₯:
expect(window.location.assign).toBeCalledWith(url);

jestλ₯Ό 톡해 μ΄λŸ¬ν•œ λŠμž„μ—†λŠ” λ¬Έμ œμ™€ λ³€κ²½ 없이 μ‰½κ²Œ μœ„μΉ˜λ₯Ό μ‘°λ‘±ν•  수 μžˆλ‹€λ©΄ 정말 쒋을 κ²ƒμž…λ‹ˆλ‹€. μ˜ˆμ „μ—λŠ” window.location.assign = jest.fn() 만 μ‚¬μš©ν•˜λ‹€κ°€ 문제 없이 v24μ—μ„œ μ—…κ·Έλ ˆμ΄λ“œ ν•΄μ„œ μ§€κΈˆμ€ μ΄λ ‡κ²Œ ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

Windows APIκ°€ μž κΈ°κ±°λ‚˜ κ³ μ •λœ μ΄μœ κ°€ μžˆμŠ΅λ‹ˆκΉŒ?
탐색이 κ΅¬ν˜„λ˜μ§€ μ•Šμ€ ν•΄κ²° 방법을 μ‹œλ„ν•˜λŠ” μ‚¬λžŒλ“€μ˜ μž₯벽인 것 κ°™μŠ΅λ‹ˆλ‹€.

그렇지 μ•Šλ‹€λ©΄ μš°λ¦¬λŠ” 그듀을 얼리지 μ•Šμ„ 수 μžˆμŠ΅λ‹ˆκΉŒ? λ‚˜λŠ” λΈŒλΌμš°μ €μ‘°μ°¨λ„ μ°½ 개체λ₯Ό λ³€κ²½ν•˜λŠ” 것을 λ§‰λŠ” 데 κ·Έλ ‡κ²Œ μ—„κ²©ν•˜λ‹€κ³  μƒκ°ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

jsdom이 λΈŒλΌμš°μ €μ™€ λ‹€λ₯΄κ²Œ λ™μž‘ν•˜λŠ” μ˜ˆκ°€ μžˆλŠ” 경우 문제 ν…œν”Œλ¦Ώ(jsbin λ˜λŠ” λΈŒλΌμš°μ € λ™μž‘μ„ λ³΄μ—¬μ£ΌλŠ” μœ μ‚¬ν•œ ν•­λͺ© 포함)에 따라 문제λ₯Ό μ œμΆœν•˜μ„Έμš”.

λ‹€λ₯Έ μ‚¬λžŒμ΄λ‘œ 싀행쀑인 λ™μΌν•œ Error: Not implemented: navigation (except hash changes) 농담이 ν•¨κ»˜ν•˜λŠ” 액컀 μš”μ†Œμ— ν™”μž¬ 클릭 이벀트λ₯Ό ν…ŒμŠ€νŠΈν•˜λŠ” λ™μ•ˆ href ? λ‚΄ ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•΄ onClick λΌλŠ” ν•¨μˆ˜λ₯Ό κ°μ‹œν•˜κ³  이에 λŒ€ν•œ μ£Όμž₯을 ν•˜κ³  μžˆμœΌλ―€λ‘œ μ‹€μ œλ‘œ 액컀 μš”μ†Œμ—μ„œ 클릭 이벀트λ₯Ό λ°œμƒμ‹œμΌœμ•Ό ν•©λ‹ˆλ‹€.

window.location μ‘°λ‘±κ³Ό κ΄€λ ¨λœ μœ„μ˜ μ†”λ£¨μ…˜μ€ λͺ…μ‹œμ μœΌλ‘œ window.location.replace λ˜λŠ” window.location.assign ν˜ΈμΆœν•˜λŠ” κ³³μ—μ„œ μž‘λ™ν•˜μ§€λ§Œ 탐색이 액컀 μš”μ†Œμ—μ„œ μ‹œμž‘λ˜λŠ” 이 κ²½μš°μ—λŠ” 도움이 λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 클릭 μ€‘μž…λ‹ˆλ‹€.

μ†”λ£¨μ…˜μ— λŒ€ν•œ 아이디어가 μžˆμŠ΅λ‹ˆκΉŒ? 감사 ν•΄μš”!

λΈŒλΌμš°μ €μ—μ„œ ν•΄λ‹Ή μ½”λ“œλ₯Ό μ–΄λ–»κ²Œ ν…ŒμŠ€νŠΈν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ? λΈŒλΌμš°μ €μ—μ„œ 링크λ₯Ό ν΄λ¦­ν•˜λ©΄ 전체 νŽ˜μ΄μ§€κ°€ λ‚ μ•„κ°€κ³  λͺ¨λ“  ν…ŒμŠ€νŠΈ κ²°κ³Όκ°€ μ‚¬λΌμ§‘λ‹ˆλ‹€. λ”°λΌμ„œ 이λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ 무엇을 ν•˜λ“  훨씬 덜 극적인 κ²½κ³  λ©”μ‹œμ§€μΈ jsdom이 μ½˜μ†”μ— 좜λ ₯λ˜λŠ” 것을 방지할 κ²ƒμž…λ‹ˆλ‹€.

λ‚΄ μƒν™©μ—μ„œ ν”„λ‘œμ νŠΈλŠ” Jestλ₯Ό 23μ—μ„œ 26 λ²„μ „μœΌλ‘œ μ—…κ·Έλ ˆμ΄λ“œν–ˆμŠ΅λ‹ˆλ‹€.
location.search λ¬Έμ œκ°€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€. Error: Not implemented: navigation 같은 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.
λ‚΄κ°€ ν…ŒμŠ€νŠΈν•œ λͺ¨λ“ˆμ€ 검색어 λ§€κ°œλ³€μˆ˜μ˜ 값을 κ°€μ Έμ˜΅λ‹ˆλ‹€.
λ‹€μŒ κ΅¬ν˜„μ΄ μ €μ—κ²Œ νš¨κ³Όμ μ΄μ—ˆμŠ΅λ‹ˆλ‹€.

beforeAll(() => {
  delete window.location;
  window.location = new URL('your URL');
})

afterAll(() => {
  window.location.search = '';
})

@mattcphillips 이 문제λ₯Ό ν•΄κ²°ν•˜λŠ” 방법을 μ•Œμ•„λƒˆμŠ΅λ‹ˆκΉŒ? 클릭할 λ•Œλ„ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

@Sabrinovsky μ•„λ‹ˆμš”, 제 setupFiles 에 슀크립트λ₯Ό μΆ”κ°€ν•˜μ—¬ jsdom νƒμƒ‰μ—μ„œ λ°œμƒν•˜λŠ” μ½˜μ†” 였λ₯˜λ₯Ό μ‚ΌμΌœ ν…ŒμŠ€νŠΈλ₯Ό μ–΄μ§€λŸ½νžˆμ§€ μ•Šλ„λ‘ ν–ˆμŠ΅λ‹ˆλ‹€. 무엇보닀 λ°˜μ°½κ³ μ— κ°€κΉμ§€λ§Œ ν…ŒμŠ€νŠΈ μ„€μ •μ—μ„œ μ΄λŸ¬ν•œ 였λ₯˜κ°€ μ˜ˆμƒλ˜λŠ” κ²ƒμ²˜λŸΌ λ“€λ ΈμŠ΅λ‹ˆλ‹€.

λ‹€μŒμ€ ν…ŒμŠ€νŠΈ 전에 μ‹€ν–‰ν•˜λŠ” μŠ€ν¬λ¦½νŠΈμž…λ‹ˆλ‹€.

// There should be a single listener which simply prints to the
// console. We will wrap that listener in our own listener.
const listeners = window._virtualConsole.listeners('jsdomError');
const originalListener = listeners && listeners[0];

window._virtualConsole.removeAllListeners('jsdomError');

// Add a new listener to swallow JSDOM errors that orginate from clicks on anchor tags.
window._virtualConsole.addListener('jsdomError', error => {
  if (
    error.type !== 'not implemented' &&
    error.message !== 'Not implemented: navigation (except hash changes)' &&
    originalListener
  ) {
    originalListener(error);
  }

  // swallow error
});

이것은 λ‚˜λ₯Ό μœ„ν•΄ μΌν–ˆμŠ΅λ‹ˆλ‹€.

delete global.window.location
global.window.location = { href: 'https://test.com' }

이것은 λ‚˜λ₯Ό μœ„ν•΄ μΌν–ˆμŠ΅λ‹ˆλ‹€.

delete window.location
window.location = { assign: jest.fn() }

당신이 얻을 경우 TypeError: Cannot assign to read only property 'assign' of object '[object Location]' , λ‹€μŒμ—μ„œμ΄ 같은 것을 μ‚¬μš©ν•˜μ—¬ jest.setup.ts :

```
global.window = Object.create(μ°½);
Object.defineProperty(μ°½, 'μœ„μΉ˜', {
κ°’: {
...μ°½.μœ„μΉ˜,
},
μ“°κΈ° κ°€λŠ₯: 사싀,
});
````

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰