_๊ธฐ๋ฅ_์ ์์ฒญํ์๊ฒ ์ต๋๊น? ์๋๋ฉด _๋ฒ๊ทธ_๋ฅผ ๋ณด๊ณ ํ์๊ฒ ์ต๋๊น? ๋ฒ๊ทธ ์ ๊ณ
ํ์ฌ ํ๋์ ๋ฌด์์ ๋๊น?
ํ ์คํธ ์ค์ํธ ๋ด๋ถ์์ ๋ค์์ ํธ์ถํฉ๋๋ค.
Object.defineProperty(location, "hostname", {
value: "example.com",
writable: true
});
๋ค์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
TypeError: Cannot redefine property: hostname
at Function.defineProperty (<anonymous>)
์์๋๋ ๋์์ ๋ฌด์์ ๋๊น?
์ฝ๋๋ ์์ธ๋ฅผ throwํด์๋ ์ ๋๋ฉฐ window.location.hostname === "example.com"
๋ true๋ก ํ๊ฐ๋์ด์ผ ํฉ๋๋ค.
๋ณด๊ธฐ์ jsdom
์ด์ window.location์ ์์กฐํ ์ ์๋๋ก ์ค์ ํฉ๋๋ค . window.location
๋ด์์ ๊ฐ์ ๋ณ๊ฒฝํ๋ ์ ์ผํ ๋ฐฉ๋ฒ์ reconfigure
๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด์ง๋ง (#2460์ ๋ฐ๋ผ) Jest๋ ํ
์คํธ๋ฅผ ์ํด jsdom
๋ฅผ ๋
ธ์ถํ์ง ์์ต๋๋ค.
์ ํํ Jest ๊ตฌ์ฑ์ ์ ๊ณตํ๊ณ Jest, ๋ ธ๋,yarn/npm ๋ฒ์ ๋ฐ ์ด์ ์ฒด์ .
๋๋ด ๋ฒ์ : 22.0.1
๋
ธ๋ ๋ฒ์ : 8.6.0
์์ฌ ๋ฒ์ : 1.2.0
OS : macOS ํ์ด ์์๋ผ 10.13.2
๋น์ทํ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ์์ ๋ง์ JSDOMEnvironment๋ฅผ ๋ง๋ค๊ณ jsdom ๊ฐ์ฒด๋ฅผ ์ด์ ๊ฐ์ด ์ ์ญ์ ๋ ธ์ถํ ์ ์์ต๋๋ค.
const JSDOMEnvironment = require('jest-environment-jsdom');
module.exports = class CustomizedJSDomEnvironment extends JSDOMEnvironment {
constructor(config) {
super(config);
this.global.jsdom = this.dom;
}
teardown() {
this.global.jsdom = null;
return super.teardown();
}
};
๊ทธ๋ฐ ๋ค์ ์ํ๋ ๋๋ก ํ ์คํธ ์ผ์ด์ค์์ jsdom.reconfigure๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค.
์ข์ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋๋ค. ๊ณต์ ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค!
์ฝ์์ด๋ฏ๋ก super.teardown();
๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค. btw
์๋ฒฝํฉ๋๋ค. @oliverzy - ์๋ํด ๋ณด๊ฒ ์ต๋๋ค. ๊ฐ์ฌ ํด์!
์ด๋ฅผ ๋ฌธ์ํํ ์ ์ ํ ์ฅ์๊ฐ ์์ต๋๊น? ๊ฝค ์์ฃผ ๋์ค๋ ์ง๋ฌธ์ธ ๊ฒ ๊ฐ์ต๋๋ค. ๋ฐ๋ผ๊ฑด๋, ์ด๊ฒ์ด ๋ฌธ์์ ํตํฉ๋๋ค๋ฉด ๋ฏธ๋์ ๋ฌธ์ ๋ฅผ ์ค์ผ ์ ์์ต๋๊น?
์ด ์๋ฃจ์ ์ ๋งค์ฐ ์๋ํ์ง ์์๋ค.
ํ
์คํธ ํ์ผ ๋ด์์ global
๊ฐ JSDom์ window
๊ฐ์ฒด๋ก ์ค์ ๋ ๊ฒ ๊ฐ์ต๋๋ค.
์ฆ, ํ
์คํธ ์ค์ํธ ๋ด์์ global
๋ window
์ ๋์ผํ์ง๋ง JSDOMEnvironment
๋ฅผ ํ์ฅํ๋ ํด๋์ค ๋ด์์ global
๋ Node ํ๊ฒฝ์์ ๊ฐ์ ธ์ต๋๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
describe("test suite", () => {
it("should not fail", () => {
global.jsdom.reconfigure({
url: "https://www.example.com/"
});
});
});
global.jsdom
์ด ์ ์๋์ง ์์๊ธฐ ๋๋ฌธ์ ์คํจํฉ๋๋ค.
๋๋ ์ด๊ฒ์ ํจ์ผ๋ก์จ ๊ทธ๊ฒ์ ํด๊ฒฐํ์ง๋ง ๊ทธ๊ฒ์ ๋ํด ๋ณ๋ก ์๋์ค๋ฝ์ง๋ ์๋ค.
const JSDOMEnvironment = require("jest-environment-jsdom");
module.exports = class JSDOMEnvironmentGlobal extends JSDOMEnvironment {
constructor(config) {
super(config);
this.dom.window.jsdom = this.dom;
}
};
์ด ํ๊ฒฝ์์ ํ
์คํธ ์ค์ํธ ๋ด์ global.jsdom
๋ this.dom
์ ๊ฐ๊ณ ์์ ํ
์คํธ ์ค์ํธ๊ฐ ์๋ํฉ๋๋ค.
๋์๊ฒ jsdom
๋ฅผ ์์ฒด window
๊ฐ์ฒด์ ์์ฑ์ผ๋ก ์ค์ ํ๋ ๊ฒ์ ๊ฒฐ๊ตญ ๋ฌด๋์ง ์๋ฐ์ ์๋ ๊ฒ์ฒ๋ผ ๋๊ปด์ง๋๋ค. ๋ ๊นจ๋ํ ๋ฐฉ๋ฒ์ด ์์ต๋๊น?
ํ
์คํธ์์ global.jsdom
๊ฐ ์๋ jsdom
๋ฅผ ์จ์ผ ํฉ๋๋ค.
@oliverzy ์ด๋ ๊ฒ?
describe("test suite", () => {
it("should not fail", () => {
jsdom.reconfigure({
url: "https://www.example.com/"
});
});
});
๊ทธ๋ฌ๋ฉด jsdom is not defined
๊ฐ ๋ฐ์ํ์ง๋ง ์ ๊ฐ ์๋ชป ํด์ํ๊ณ ์์ ์ ์์ต๋๋ค.
@ simon360 ๊ตฌ์ฑํ์ญ์์ค testEnvironment
@oliverzy์ ์ฝ๋๋ฅผ ์ฐธ์กฐ https://facebook.github.io/jest/docs/en/configuration.html#testenvironment -String
@danielbayerlein ๋ด Jest ๊ตฌ์ฑ์๋ ๋ค์์ด ์์ต๋๋ค.
"testEnvironment": "@wel-ui/jest-environment-jsdom-global"
์ฌ๊ธฐ์ @wel-ui/jest-environment-jsdom-global
๋ ๋ชจ๋
ธ๋ ํฌ์ ์๋ ํจํค์ง์ ์ด๋ฆ์
๋๋ค. ๊ทธ๋ฌ๋ jsdom
์ window
jsdom
๋ฅผ ์ค์ ํ๋ ์๋ฃจ์
์ด ์์๋๋ก ์๋ํ๊ธฐ ๋๋ฌธ์ ํ๊ฒฝ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉ๋๊ณ ์์ต๋๋ค.
BTW, ์๋ ์๋ฃจ์
์ด ์ ๋ฒ์ ์์ ์๋ํ์ง ์๋ ์ด์ ๋ฅผ ์๋ ์ฌ๋์ด ์์ต๋๊น?
์ด ํ๋:
Object.defineProperty(location, "hostname", {
value: "example.com",
writable: true
});
@SimenB ์๊ฒ ์ต๋๋ค. jsdom reconfigure
๋ฉ์๋์ ๋ํ ์ค๋ช
์ ์ฐพ์์ต๋๋ค.
์ฐฝ์ ๋งจ ์ ์์ฑ์ ์ฌ์์์ [์์กฐ ๋ถ๊ฐ๋ฅ]์ผ๋ก ํ์๋์ด ์์ต๋๋ค. ์ฆ, ๊ตฌ์ฑํ ์ ์๋ ์์ฒด ์์ฑ์ด๋ฏ๋ก Object.defineProperty๋ฅผ ์ฌ์ฉํ๋๋ผ๋ jsdom ๋ด๋ถ์์ ์คํ๋๋ ์ผ๋ฐ ์ฝ๋๋ก ๋ฎ์ด์ฐ๊ฑฐ๋ ์จ๊ธธ ์ ์์ต๋๋ค.
์ด ๋์์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ์ ์ ์ฅ์๋ฅผ ์ถ๊ฐํ์ต๋๋ค. ๋ก์ปฌ์์ ๋ณต์ ํ์ฌ ๋ณต์ ํ ์ ์๋ ์ฌ๋์ด ์์ต๋๊น?
@simon360 ์ฌํ
@ simon360 ์ฐพ์์ต๋๋ค. global.jsdom
์ ์ํ ๋ this
ํค์๋๋ฅผ ๋์ณค์ต๋๋ค.
const JSDOMEnvironment = require("jest-environment-jsdom");
module.exports = class JSDOMEnvironmentGlobal extends JSDOMEnvironment {
constructor(config) {
super(config);
this.global.jsdom = this.dom;
}
teardown() {
this.global.jsdom = null;
return super.teardown();
}
};
location.search
์ด๋ป์ต๋๊น? ๊ทธ๊ฒ์ ๋ํ ์ธ๊ธ์ ์ฐพ์ง ๋ชปํ์ต๋๋ค. https://github.com/tmpvar/jsdom/blob/05a6deb6b91b4e02c53ce240116146e59f7e14d7/README.md#reconfiguring -the-jsdom-with-reconfiguresettings
@andrewBalekha ์ด๊ฑด ์ด๋?
jsdom.reconfigure({
url: 'https://www.example.com/endpoint?queryparam1=15&queryparam2=test'
});
@modestfake ๊ฐ์ฌ
์๊ฒ ์ต๋๋ค. ์ด์ Jest ํ๊ฒฝ ๊ฐ์ฒด์ this.global
๊ฐ Jest ํ
์คํธ ํ์ผ์์ global
๋ก ์ค์ ๋ฉ๋๋ค. ์ดํด๊ฐ ๋ฉ๋๋ค. ๋์์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค! ๊ด์ฌ์ด ์ถฉ๋ถํ๋ค๋ฉด ํด๋น ๋ฆฌํฌ์งํ ๋ฆฌ์ ๋ณต๊ตฌ๋ ๋ฒ์ ์ ํจํค์งํ๊ณ npm
๋ก jest-environment-jsdom-global
npm
์ ๋ฃ์ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ ์์ผ๋ก Jest์์ ์ด๋ฅผ ์ํํ ์ ์๋ ๋ ๊นจ๋ํ ๋ฐฉ๋ฒ์ด ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ์ด๊ฒ์ window.location
๋ฅผ ๋ณ๊ฒฝํ๋ ๋ง์ฐฐ์ด ์ ์ ๋ฐฉ๋ฒ์ด ์๋๋๋ค.
@jest-environment
์ ๊ฐ์ ์ docblock ์ด ์์ ์ ์์ต๋๊น? ์๋ฅผ ๋ค์ด...
/**
* @jest-url https://www.example.com/
*/
๋๋ JSDom์ด jest
๊ฐ์ฒด์ ํน์ ๋ถ๋ถ์ ๋
ธ์ถ๋ ์ ์์ต๋๋ค.
jest.environment.jsdom.reconfigure({
url: "https://www.example.com/"
});
( window.top
๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค๋ ์ถ๊ฐ ์ด์ ์ด ์์)
์ด์ #5003์ ๋ณํฉํ์ต๋๋ค. ๊ทธ๊ฒ์ docblock์ผ๋ก ์ถ๊ฐํ ์ ์๋ค๋ ๊ฒ์ด ์๋ฏธ๊ฐ ์์์ง ๋ชจ๋ฅด์ง๋ง ํ์คํ์ง ์์ต๋๋ค. @cpojer? ์๋ก์ด ์ต์
์ ํตํด ์ ๊ณต๋ ์ ์์ผ๋ฏ๋ก testUrl
๋ ๋ ์ด์ ์ฌ์ฉํ์ง ์์ ์ ์์ต๋๋ค.
๊ด์ฌ์ด ์ถฉ๋ถํ๋ค๋ฉด ํด๋น ๋ฆฌํฌ์งํ ๋ฆฌ์ ๋ณต๊ตฌ๋ ๋ฒ์ ์ ํจํค์งํ๊ณ
npm
๋กjest-environment-jsdom-global
npm
์ ๋ฃ์ ์ ์์ต๋๋ค.
URL์ ์ค์ ํ๋ ๊ฒ ์ด์์ ์ํํ๋ฏ๋ก ์ด๋ค ๊ฒฝ์ฐ์๋ ์ด๊ฒ์ด ์๋ฏธ๊ฐ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ ์ฒด JSDOM์ ํ๊ฒฝ์ ๋ ธ์ถํฉ๋๋ค.
@andrewBalekha Object.defineProperty(location, 'search', { ...options });
window.location
์ ๋์ผํ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค. ๊ทธ๋๋ ์ ์ํด ์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค.
Object.defineProperty(window.location, 'href', {
์ค์ : newValue => { currentUrl = newValue; },
});
์ด์ ๋ฒ์ ์์ ์ด๊ฒ์ ๊ฐ์ง๊ณ ์์๊ณ ์ด์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
์ฐ๊ธฐ ๊ฐ๋ฅ์ ์ถ๊ฐํ๋ฉด true
์ ๊ทผ์์ ์ฐ๊ธฐ ๊ฐ๋ฅ์ ๋ชจ๋ ์ง์ ํ ์ ์๋ค๋ ๋ ๋ค๋ฅธ ์์ธ๊ฐ ๋ฐ์ํฉ๋๋ค.
๋๋๋ผ๋ NPM์ ์ ํจํค์ง๋ฅผ ๋ฐํํ๋ค jest-environment-jsdom-global
์ด๋ค ์ฌ๋๋ค์ ํจ๊ป ๋ฐ์ํ๋ ๋ฌธ์ ์ ๋์์ด ๋ ์์๋, Object.defineProperty
.
๋๊ตฌ๋ ์ง { writable: true }
๋ํ ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ์์ต๋๊น?
์๋ฅผ ๋ค์ด:
Object.defineProperty(window.location, 'href', { writable: true })
...
Object.defineProperty(window.location, 'hash', { writable: true })
...
Object.defineProperty(window.location, 'search', { writable: true })
@danielbayerlein ์ด ์ด ์ค๋ ๋๋ฅผ ์ฝ์์ต๋๋ค. ์ฌ์ฉ์ ์ง์ ํ๊ฒฝ์ ๋ง๋ค์ด์ผ ํฉ๋๋ค. ์ด์ ๋ฉ์์ง์ ์์ ๊ฐ ํฌํจ๋ url์ด ํฌํจ๋์ด ์์ต๋๋ค.
@modestfake ์ด๋ฏธ ์ด ์ค๋ ๋๋ฅผ ์ฝ์์ผ๋ฉฐ https://github.com/facebook/jest/issues/5124#issuecomment -352749005๊ฐ ์ ๋๋ก ์๋ํฉ๋๋ค. ํ์ง๋ง ๋ค๋ฅธ ์ฌ์ฉ ์ฌ๋ก๊ฐ ์์ต๋๋ค. Jest 21.xx๋ฅผ ์ฌ์ฉํ์ฌ URL ์์ด Object.defineProperty(window.location, 'href', { writable: true })
๋ฅผ ์ค์ ํ์ต๋๋ค. { writable: true }
์์ต๋๋ค. URL์ ์ค์ ํ๋ฉด ํ
์คํธ๊ฐ ์๋ฏธ๊ฐ ์์ต๋๋ค.
@danielbayerlein ์ฐ๊ธฐ ๊ฐ๋ฅํ์ง๋ง ์ค์ ๋ก ์ฌ์ ์ํ์ง ์๋ ์ฌ์ฉ ์ฌ๋ก๋ ๋ฌด์์ ๋๊น? ์ด๊ฒ์ ์ดํดํ๋ฉด ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ฐพ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
URL์ ๋ณ๊ฒฝํ๋ ๊ธฐ๋ฅ์ด ์์ต๋๋ค.
๋ผ์ฐํ .js
...
export function redirectToErrorPage () {
window.location.href = '/error.html'
}
...
๋ผ์ฐํ .test.js
test('redirect to the error page', () => {
...
expect(window.location.href).toBe('/error.html')
...
})
Jest 21.xx๋ฅผ ์ฌ์ฉํ์ฌ Object.defineProperty(window.location, 'href', { writable: true })
window.location.assign
์ ํํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๊ทธ๋ ๊ฒ ํ๋ฉด ํจ์๋ฅผ ๋ชจ์ํ ์ ์์ต๋๋ค.
@simon360 ๋งค๋ ฅ์ฒ๋ผ ์๋ํฉ๋๋ค! ๊ฐ์ฌํฉ๋๋ค. ๐ค
๋๋ ์ฌ์ฉํ๋ค
history.pushState({}, "page 2", "/bar.html");
jest ๊ตฌ์ฑ์์ testURL
์ ํจ๊ป
์์น ๋ถ๋ถ๋ง์ด ๋ฌธ์ ๊ฐ ์๋๋๋ค. jsdom.reconfigureWindow
๋ฅผ ํธ์ถํ๊ธฐ ์ํด jsdom
๋ณ๋๋ก ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค(์ต์ ๋ฒ์ ์ jsdom์๋ ํด๋น ๊ธฐ๋ฅ์ด ๋ ์ด์ ์กด์ฌํ์ง ์๊ธฐ ๋๋ฌธ์
๋๋ค). window !== top
๊ฒฝ์ฐ ๋ค๋ฅด๊ฒ ์คํ๋๋ ์ฝ๋๋ฅผ ํ
์คํธํ๊ธฐ ์ํด ์ด ์์
์ ์ํํ์ต๋๋ค. ์ต์ ๋ฒ์ ์ jsdom์ ์ฌ์ฉํ๋ ์ต์ ๋ฒ์ ์ jest์์๋ ๋ ์ด์ ์ด๋ฅผ ๋ฌ์ฑํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
@andyearnshaw jsdom.reconfigure
๋ฉ์๋์๋ ๊ฐ์ฒด์ windowTop
๋ฉค๋ฒ๊ฐ ์์ต๋๋ค.
์์์ ๋งํฌํ JSDOM ํ๊ฒฝ( jest-environment-jsdom-global
)์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ๋ค์์ ์ํํ ์ ์์ต๋๋ค.
jsdom.reconfigure({
windowTop: YOUR_VALUE
});
ํ ์คํธ์์ ์ต๊ณ ์ ๊ฐ์น๋ฅผ ์กฐ๋กฑํฉ๋๋ค.
๋๋ ๊ทธ๊ฒ์ ์ฌ์ฉํ๊ณ ์ ์๋ํฉ๋๋ค, ๊ฐ์ฌํฉ๋๋ค!
2018๋ 1์ 30์ผ ํ, 13:40 simon360, ์๋ฆผ @github.com ์์ฑ:
@andyearnshaw https://github.com/andyearnshaw jsdom.reconfigure
๋ฉ์๋์ ๊ฐ์ฒด์ windowTop ๋ฉค๋ฒ๊ฐ ์์ต๋๋ค.JSDOM ํ๊ฒฝ(jest-environment-jsdom-global)์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ I
์์ ๋งํฌ์์ ๋ค์์ ์ํํ ์ ์์ต๋๋ค.jsdom.reconfigure({
windowTop: YOUR_VALUE
});ํ ์คํธ์์ ์ต๊ณ ์ ๊ฐ์น๋ฅผ ์กฐ๋กฑํฉ๋๋ค.
โ
๋น์ ์ด ์ธ๊ธ๋์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
https://github.com/facebook/jest/issues/5124#issuecomment-361595999 ๋๋ ์์๊ฑฐ
์ค๋ ๋
https://github.com/notifications/unsubscribe-auth/ABvdEzCLlWtzr0udscL0C6KUxpgXHZRhks5tPxvJgaJpZM4RGN7C
.
window.history.pushState
๋ฐ testUrl
์ด ์ ์๊ฒ ํจ๊ณผ์ ์ด์์ต๋๋ค.
https://github.com/facebook/jest/issues/5124#issuecomment -359411593
Jest ์ธก์์ ํ ์ผ์ด ์๊ณ ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ์์ผ๋ฏ๋ก ์ด๊ฒ์ ๋ซ์ ๊ฒ์ ๋๋ค(์์ ๋กญ๊ฒ ํ ๋ก ์ ๊ณ์ํ์ญ์์ค!)
jsdom v8.5.0์์ v11.6.2๋ก ์
๊ทธ๋ ์ด๋ํ๋ฉด ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์์ต๋๋ค. ๋ฐ๋ผ์ ๋ด package.json
์๋ ๋ค์์ด ํฌํจ๋ฉ๋๋ค.
"jest": "^21.2.1",
"jest-cli": "^21.2.1",
"jsdom": "^11.6.2",
jest ๋ฐ jest-cli๋ฅผ v22.2.2๋ก ์ ๊ทธ๋ ์ด๋ํ๋ฉด ์ค๋จ๋ฉ๋๋ค.
@andr-3-w package.json์ jsdom์ด ์๋ ํน๋ณํ ์ด์ ๊ฐ ์์ต๋๊น? Jest์ ํจ๊ป ์ ๊ณต๋ฉ๋๋ค.
@SimenB๋ ์ง๋ฌธ ์ข์์ ๋ํ ํ์๊ฐ ์์ต๋๋ค jsdom
์ฐ๋ฆฌ์ package.json
. ๊ฐ์ฌ ํด์!
๋ฐ๋ผ์ jsdom์ ์ง์ ์ฌ์ฉํ์ง ์๊ณ ๋ด ๋ฌผ๊ฑด์ ๋ํด ์๊ฐํด๋ธ ์๋ฃจ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
Jest 21.2.1์์ ์๋ํฉ๋๋ค(์ ๋ ํด๋น ๋ฒ์ ์์ ํ ์คํธํ์ต๋๋ค).
Jest ์ค์ ์ผ๋ก ์ด๋ํฉ๋๋ค(์: package.json ์ฌ์ฉ).
"jest": {
"testURL": "http://localhost"
}
์ด์ window.location ๊ฐ์ฒด๋ฅผ ๋ณ๊ฒฝํ ์ ์์ผ๋ฉฐ ํ ์คํธ ์ค์ 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);
});
์ด๊ฒ์ด ๋๊ตฐ๊ฐ๋ฅผ ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
๊ฒ์๋ฅผ ์ค์งํ์ญ์์ค. ๋๋ด์ผ๋ก๋ ์๋ํ์ง ์์ต๋๋ค.": "^22.4.2"
@UserNT ์ฌ๊ธฐ์์ ์๋ํ๋ ๋ฒ์ ์ ์ธ๊ธํ์ผ๋ฉฐ ํ๋ก๋์ ํ ์คํธ ์ํธ์ ๊ด๋ฒ์ํ๊ฒ ์ฌ์ฉํฉ๋๋ค. ์ต์ ๋ฒ์ ์์ ์๋ํ์ง ์์ผ๋ฉด ์ฃ์กํฉ๋๋ค. ๋ฌด์์ ๊ณต๊ฒฉ ๋์ ์์ ์ ์๋ฃจ์ ์ ์๊ฐํด ๋ณด์ธ์.
์์ ์ฑ์ ์ํด ์๋ฃจ์ ์ด ์ด ์ค๋ ๋์ ์ค๊ฐ์ ์ข์ด๋์ด ์๊ธฐ ๋๋ฌธ์...
@petar-prog91์ ์๋ฃจ์
์ Jest 21์์ ์๋ํ์ง๋ง ์
๋ฐ์ดํธ๋ jsdom
๊ฐ ์๋ Jest 22์์๋ ์๋ํ์ง ์์ต๋๋ค.
๊ฐ์ ์ต์ ๋๋ด์์ ์คํํ๊ธฐ ์ํด, ์ฌ์ฉ ๋ญ๊ฐ jest-environment-jsdom-global
(์ ์ฒด ๊ณต๊ฐ, ์ด๊ฒ์ ๋ด ํจํค์ง)์ ๋
ธ์ถ jsdom
๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ jsdom.reconfigure
์์ ๊ฒ์ด๋ค, ๋์ผํ (๋๋ ์ ์ด๋ ์ ์ฌํ) ํจ๊ณผ.
https://github.com/facebook/jest/issues/5124#issuecomment -359411593์ jest 22์์๋ ์๋ํฉ๋๋ค.
@simon360 ์๋
ํ์ธ์, location.href
์ setter๋ฅผ ํดํนํด์ผ ํ๋ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ํด์ผ ํ๋์?
๋ด ์ด์ ํ
์คํธ์๋ ์ด์ ๊ฐ์ ํ
์คํธ๊ฐ ๋ง์๊ณ ์ง๊ธ์ ๋ชจ๋ ์คํจํ์ต๋๋ค...
const setHrefMockFn = jest.fn();
beforeAll(() => {
Object.defineProperty(location, "href", {
get: () => "https://xxxxx",
set: setHrefMockFn
});
});
it("xxx", () => {
//...
expect(setHrefMockFn.mock.calls[0][0]).toBe(xxx);
});
@simon360 ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์๋์ ๊ฐ์ด ํ ์คํธ๋ฅผ ์ ๋ฐ์ดํธํ๋ ๋ฐฉ๋ฒ์ ์๋ฅผ ๋ค์ด
beforeAll(() => {
=======
Object.defineProperty(window.location, 'href', {
writable: true
});
});
@abhijeetNmishra ๋ฌธ์ ๋ฅผ ๋ณด์์ต๋๊น? ๋๋ ๊ทธ๊ฒ์ด ๋น์ ์ ์ง๋ฌธ์ ๋ตํ ๊ฒ์ด๋ผ๊ณ ๋ฏฟ์ต๋๋ค.
@ simon360 ์, ๋ฌธ์์ ๋ํ ์ดํด๋ฅผ ๋ฐํ์ผ๋ก ์ฝ
jsdom.reconfigure({
url: "https://www.example.com/"
});
ํ ์คํธ๋ณ๋ก๊ฐ ์๋๋ผ ์ ์ญ์ ์ผ๋ก URL์ ์ฌ์ ์ํฉ๋๋ค. ๋์์ฃผ์ธ์!
@abhijeetNmishra ์ด ๋ฌธ์ ๊ฐ ํ ๋ก ํ๊ธฐ์ ๊ฐ์ฅ ์ข์ ์ฅ์์ธ์ง ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. jest-environment-jsdom-global
๋ฆฌํฌ์งํ ๋ฆฌ์์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ ๋ฌธ์ ๋ฅผ ์ด์ด์ฃผ์๊ฒ ์ต๋๊น? ๊ฐ์ฌ ํด์!
@SimenB ๋ช
์๋ ํด๊ฒฐ ๋ฐฉ๋ฒ("use jest-environment-jsdom-global
")์ ๋ถ๋ช
ํ ๋งค์ฐ ์ผ๋ฐ์ ์ธ ๋ฌธ์ ์ ๋ํ ๊ทน๋๋ก ์ฐจ์ ์ฑ
์ฒ๋ผ ๋๊ปด์ง๋๋ค. Jest 22๋ก ์
๊ทธ๋ ์ด๋ํ๋ ์ฌ๋์ ์ด์ ํด๋น ํ์ฌ ํจํค์ง์ ์ข
์์ฑ์ ์ถ๊ฐํ๊ณ (์ฌ์ฉ์์ ๊ด์ ์์) ํ
์คํธ ์ค ์ผ๋ถ๋ฅผ ๋ค์ ์์ฑํด์ผ ํฉ๋๋ค. ์ด๊ฒ์ Jest์ ํ๋์ด ํดํํ๋ ๊ฒ์
๋๋ค.
๊ธฐ๋ณธ jest-environment-jsdom
๊ตฌ์ถํ ์ ์๋ ์ด์ ๋ํ ์๋ฃจ์
์ด ์์ต๋๊น? ๋น์ ์ ์ง๋์ ํจ๊ป PR์ ํ๊ฒ ๋์ด ๊ธฐ์ฉ๋๋ค.
๋๊ตฐ๊ฐ๊ฐ window.location.href๋ฅผ ๋ณ๊ฒฝํ๊ธฐ ์ํด ์ด ๋ง์ ๊ณ ๋ฆฌ๋ฅผ ๊ฑด๋๋ฐ์ด์ผ ํ๋ ๊ฒ์ ๋งค์ฐ ๋ถํํ ์ผ์ ๋๋ค. ๋ฐฉ๊ธ Jest๋ฅผ ์ฌ์ฉํ๊ธฐ ์์ํ์ผ๋ฉฐ ์ด ๋ฌธ์ ๋ฅผ ๊ณ ๋ คํ ๋ ํ ์คํธ ํ๋ ์์ํฌ ์ ํ์ ์ฌ๊ณ ํ๋ ค๊ณ ํฉ๋๋ค. ์์์ ์ ์ํ ๋ชป์๊ธด ํดํน๋ณด๋ค ๋ ๋์ ์๋ฃจ์ ์ด ์ ๋ง ์์๊น์?
@ydogandjiev ๋ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ํ๋ก์ ํธ์ ์์ ๋กญ๊ฒ ๊ธฐ์ฌํ ์ ์์ต๋๋ค. ์ด๊ฒ์ ์คํ ์์ค์ด๋ฏ๋ก "๋ฐ์๋ค์ผ ์ ์๋ค", "์ด๋ฆฌ์๋ค"์ ๊ฐ์ ๋๊ธ๋ก ๋ ๋ฐ๋ ๊ฒ์ ๋๊ตฌ์๊ฒ๋ ๋์์ด ๋์ง ์๋๋ค๋ ์ ์ ๊ธฐ์ตํ์ญ์์ค.
@msholty-fd ํ ์๋ง ์๋ค๋ฉด ๋๊ณ ์ถ์ต๋๋ค. ์ ๋ jest์ jsdom์ ๋ง ์์ํ๊ธฐ ๋๋ฌธ์ ์ด ๊ฒฝํ์ ๊ฐ์ ํ๊ธฐ ์ํ ์ต์ ์ ๋ฐฉ๋ฒ์ด ๋ฌด์์ธ์ง ์ ํํ ์๊ธฐ ์ํด ์ด๋ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํด ์ถฉ๋ถํ ๊น์ด ์ดํดํ๊ณ ์๋์ง ํ์ ํ ์ ์์ต๋๋ค. ์ด๊ฒ์ ๋๋ด์ด๋ jsdom์์ ๊ฐ์ฅ ์ ํด๊ฒฐ๋๋ ๊ฒ์ ๋๊น? ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ํ๋๊ฐ Object.defineProperty ์ ๊ทผ ๋ฐฉ์์ ๊นจ๋ ๋ณ๊ฒฝ ์ฌํญ์ ์ ์ฉํ ๊ฒ ๊ฐ์ต๋๋ค. ๋๋ด์ด๋ jsdom์์ ๋ณ๊ฒฝ๋ ์ฌํญ์ ๋๊น?
๋ค์์ window.location์ ๋ณ๊ฒฝํ๋ ๋ฐ ํ์ํ ์ค ์์ ๋ฐ๋ผ ์ ํธํ๋ ๋ชจ๋ ์ต์ ์ ๋๋ค. ์ด๋ค ์ค ์ด๋ ๊ฒ๋ ํ์ฌ ์๋ํ์ง ์์ต๋๋ค:
window.location.href = "https://www.example.com";
JSDOM์ด ์ฐฝ์ ์์น ์์ฑ์ [Unforgeable] ๋ก ๋ง๋ค์๊ธฐ ๋๋ฌธ์ Object.defineProperty๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ํ์ง ์์ต๋๋ค.
Object.defineProperty(window.location, "href", {
value: "https://www.example.com",
configurable: true
});
jest๋ ์ฌ์ด ์ก์ธ์ค๋ฅผ ์ํด ๋ ธ์ถ๋์ง ์์ ์์ฒด ์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ๊ฐ๊ธฐ ๋๋ฌธ์ jsdom์ ์ธ์คํด์ค๋ฅผ ๋ง๋ค๊ณ ๊ตฌ์ฑํ๋ ๊ฒ์ ์๋ํ์ง ์์ต๋๋ค.
import { JSDOM } from "jsdom";
...
const dom = new JSDOM();
dom.reconfigure({ url: "https://www.example.com" });
์ต์ 1 ๋๋ 2๋ฅผ ์๋์ํค๋ ค๋ฉด jsdom์ด ์ค์ ๋ธ๋ผ์ฐ์ ์ฒ๋ผ ํ๋ํ๋ ค๋ ํ์ฌ ๋ชฉํ๋ฅผ ์ญ์ถ์ ํด์ผ ํฉ๋๋ค. ๋ฐ๋ผ์ ์ฐ๋ฆฌ๊ฐ ํ ์ ์๋ ์ ์ผํ ์ต์ ์ jest๊ฐ ์ฌ์ฉํ๋ jsdom์ ์ธ์คํด์ค๋ฅผ ์ฝ๊ฒ ์ฌ๊ตฌ์ฑํ ์ ์๋๋ก ํ๋ ๊ฒ์ ๋๋ค. ํด๋น ์ธ์คํด์ค๋ฅผ ์ ์ญ jest ๊ฐ์ฒด์ ์ง์ ๋ ธ์ถํ๋ ๊ฒ์ด ์๋ฏธ๊ฐ ์์ต๋๊น? ์ฆ, ๋ค์๊ณผ ๊ฐ์ ๊ฒ์ ํ์ฉํฉ๋๋ค.
jest.dom.reconfigure({ url: "https://www.example.com" });
๋๋ ์ฌ์ ํ location.assign('some-url')
๊ฒ์ด location.href = 'some-url'
๋ณด๋ค ๋ซ๋ค๊ณ ์๊ฐํฉ๋๋ค. ํ ๋น๋ณด๋ค ํจ์ ํธ์ถ์ด ๋ ๋ช
์์ ์ด๋ฉฐ ํจ์๋ฅผ ์กฐ๋กฑํ ์ ์์ต๋๋ค.
์ฝ๋ _set_๋ฅผ ์๋ํ๋ ๊ฒฝ์ฐ์ @SimenB location.href
, ์ location.assign()
๋ ์ข๋ค. ๊ทธ๋ฌ๋ location.href
_reads_ location.assign()
๊ฐ ์ค์ ๋ก ์๋ฌด ๊ฒ๋ ํ์ง ์๊ธฐ ๋๋ฌธ์ location.assign()
๊ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ง ๋ชปํฉ๋๋ค.
reconfigure
์ฌ์ฉํ๋ ์์ด๋์ด๋ location.href
๊ฐ ํน์ ๋ฐฉ์์ผ๋ก ํ์ฑ๋ ๋๋ง ํ์ฑํ๋๋ ์ฝ๋ ๊ฒฝ๋ก๋ฅผ ํ์ฑํํ๋ ๊ฒ์
๋๋ค. ์ฐ๋ฆฌ์ ๊ฒฝ์ฐ ํ์ฌ ๋๋ฉ์ธ์ ๋ฐ๋ผ ๋ณ๊ฒฝ๋ ์ผ๋ถ ์ฝ๋๊ฐ ์์ต๋๋ค. ์ฝ๋๋ ๋์๊ฐ ๋์ง๋ง ๋ํ ํ์ํฉ๋๋ค. ๋์ ๋๋ ์ฝ๋๋ฅผ ์ํํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ๋์์ ์บก์ฒํ๊ณ ์ ์ง๋๋๋ก ํ๋ ํ
์คํธ ์ฅ์น๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค. ์ ์๋ฆฌ์.
๋ฆฌ๋๋ ์ ์ ํ ์คํธํ๊ธฐ ์ํด Enzyme ๋ฐ ํ์ฌ๋ ๊ตฌ์ฑ ์์์ ํจ๊ป ์ด๊ฒ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๊น?
Jest๋ฅผ ์ ๊ทธ๋ ์ด๋ํ๊ธฐ ์ ์ ์๋ ํ ์คํธ๋ฅผ ํต๊ณผํ์ต๋๋ค.
```
it('๊ฒฝ๋ก๋ฅผ ์์ ํ๋ ๊ฒฝ๋ก', () => {
Object.defineProperty(window.location, 'href', {
writable: true,
value: 'https://mysuperawesomesite.com/',
});
const component = mount(
<App {...props} />
);
const link = component.find('.class');
link.simulate('click');
expect(window.location.href).toEqual('https://mysuperawesomesite.com/new');
});
After upgrading Jest and implementing [jest-environment-jsdom-global](https://www.npmjs.com/package/jest-environment-jsdom-global), I tried the following to no avail:
```
it('routes to correct route', () => {
jsdom.reconfigure({
url: 'https://mysuperawesomesite.com/',
});
const component = mount(
<App {...props} />
);
const link = component.find('.class');
link.simulate('click');
expect(window.location.href).toEqual('https://mysuperawesomesite.com/new');
});
(window.location.href๋ ์ฌ์ ํ ' https://mysuperawesomesite.com/ '๊ณผ ๊ฐ์ผ๋ฉฐ ('https://mysuperawesomesite.com/new')๋ก ๋ณ๊ฒฝ๋์ง ์์์ต๋๋ค.
์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ๋ ์์์ ํด๋ฆญ ์ด๋ฒคํธ๋ ๋ฆฌ๋๋ ์ ๋์ง ์์ผ๋ฉฐ ๋ฆฌ๋๋ ์ ์ window.location.href๋ฅผ ์ค์ ํ์ฌ ๋ฐ์ํฉ๋๋ค.
์ด๊ฒ์ ์ ์ ํ๊ฒ ํ ์คํธํ๋ ๋ฐฉ๋ฒ ๋๋ ์ด์ ์ Object.defineProperty๋ฅผ ์ฌ์ฉํ ํ ์คํธ๊ฐ ์ฒ์๋ถํฐ ์ ๋๋ก ๊ตฌ์ฑ๋์ง ์์๋์ง ๋ถ๋ช ํํฉ๋๋ค. ๋์์ ์ฃผ์ ์ ๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
ํธ์ง: ํด๊ฒฐ
window.location.href = href ๋์ window.location.assign(url)์ ์ฌ์ฉํ์ฌ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์์ต๋๋ค. ์ด๋ฅผ ํตํด assign ๋ฉ์๋๋ฅผ ์ ๊ฑฐํ๊ณ ์ ๋๋ก ํธ์ถ๋์๋์ง ํ ์คํธํ ์ ์์์ต๋๋ค. ์๋ ์ฐธ์กฐ:
it('routes to correct route', () => {
window.location.assign = jest.fn();
const component = mount(
<App {...props} />
);
const link = component.find('.class');
link.simulate('click');
expect(window.location.assign).toBeCalledWith('https://mysuperawesomesite.com/new');
window.location.assign.mockRestore();
});
@SimenB .assign
์ .href
์ฌ์ด์๋ ํฐ ์ฐจ์ด๊ฐ ์์ต๋๋ค. MDN์์ ์ฝ์ ์ ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ๋ ์ฃผ์ ๊ต์ฐจ ๋๋ฉ์ธ ์ ํ ์ฌํญ์ด ์์ต๋๋ค. ๋ด ์ฝ๋์์ ๋ด ์ฝ๋๊ฐ ์คํ ์ค์ธ iframe์์ ์์ ํ์ด์ง๋ฅผ ๋ฆฌ๋๋ ์
ํ๊ณ ์ถ์ต๋๋ค. ๊ทธ๊ฒ๋ค์ ๊ต์ฐจ ๋๋ฉ์ธ์
๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ด๊ฐ ํ ์ ์๋ ์ ์ผํ ๋ฐฉ๋ฒ์ href
๋ฅผ ๋ณ๊ฒฝํ๋ ๊ฒ์
๋๋ค.
ํ์ฌ ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ํ์๋์ง ์๊ณ ์ด ๊ธฐ๋ฅ์ ๋ํ ํ
์คํธ๋ฅผ ์ํํ์ง ์์์ผ ํ๊ธฐ ๋๋ฌธ์ ์ด ๋ฌธ์ ๊ฐ ๋ค์ ์ด๋ฆฌ๋ฉด ์ข๊ฒ ์ต๋๋ค. ๋ถ๋ช
ํ ์ง์ฆ๋ฉ๋๋ค.
@soswow์ ๊ฐ์ ๋ฐฐ์ ์์ต๋๋ค. ์ด ๊ธฐ๋ฅ์ด ๋ณต์๋ ๋๊น์ง ์ฌ๋ฌ ๋จ์ ํ ์คํธ๋ ์ ๊ฑฐํ๋ฏ๋ก URL์ ์ฌ์ ์ํ๋ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ ์ ์๋ค๋ฉด ์ข์ ๊ฒ์ ๋๋ค.
ํ์ฌ ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ํ์๋์ง ์๊ณ ์ด ๊ธฐ๋ฅ์ ๋ํ ํ ์คํธ๋ฅผ ์ํํ์ง ์์์ผ ํ๊ธฐ ๋๋ฌธ์ ์ด ๋ฌธ์ ๊ฐ ๋ค์ ์ด๋ฆฌ๋ฉด ์ข๊ฒ ์ต๋๋ค. ๋ถ๋ช ํ ์ง์ฆ๋ฉ๋๋ค.
์ฐ๋ฆฌ๊ฐ ๋๋ด์ ํธ์์ ํ ์ ์๋ ์ผ์ ์๋ฌด๊ฒ๋ ์์ต๋๋ค. ๋๋ jsdom์ด ๊ทธ๊ฒ์ ์ง์ํ๋ PR์ ์ข์ํ ๊ฒ์ด๋ผ๊ณ ํ์ ํฉ๋๋ค. https://github.com/jsdom/jsdom/issues/2112
๋ค์์ ์๋ํ๋ ๊ฐ๋จํ ์๋ฃจ์ ์ ๋๋ค.
describe('changing location', () => {
const testURL = location.href;
beforeEach(() => history.replaceState({}, 'Login', '/login'));
afterEach(() => history.replaceState({}, 'Home', '/'));
it('works', () => {
expect(location.pathname).toBe('/login');
});
});
@vastus ๋ด๊ฐ ๋ช ์์ ์ผ๋ก ์ง์ ํ๋ฏ์ด ๋ฌธ์ ๋ ๊ต์ฐจ ๋๋ฉ์ธ์ ์์ต๋๋ค. ๋ด๊ฐ ๊ธฐ์ตํ๋ ํ history API๋ ๋ค๋ฅธ ๋๋ฉ์ธ์ผ๋ก์ ์ ํ์ ํ์ฉํ์ง ์์ต๋๋ค.
location
๋ jsdom window
๊ฐ์ฒด์์ ์ง์ ์ฌ์ ์ํ ์ ์์ผ๋ฏ๋ก ํ ๊ฐ์ง ๊ฐ๋ฅํ ์ ๊ทผ ๋ฐฉ์์ ํ์ ๊ฐ์ฒด์์ ์ฌ์ ์ํ๋ ๊ฒ์
๋๋ค.
global.window = Object.create(window);
Object.defineProperty(window, 'location', {
value: {
href: 'http://example.org/'
}
});
๋๋ ์ด๊ฒ์ ์ฌ์ฉํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค.
const windowLocation = JSON.stringify(window.location);
delete window.location;
Object.defineProperty(window, 'location', {
value: JSON.parse(windowLocation)
});
@RubenVerborgh ๋ฐ ์ป์์ต๋๋ค .
@vastus ์๋ฃจ์
์ ๊ธฐ๋ฐ์ผ๋ก location.search
ํ
์คํธ ์์ ์ถ๊ฐ:
test('gets passed query param and returns it as a string if it exists', () => {
history.replaceState({}, 'Test', '/test?customer=123');
const customerId = getQueryParam('customer');
expect(customerId).toBe('123');
});
@RubenVerborgh ๋งค๋ ฅ์ฒ๋ผ ์๋ํฉ๋๋ค.
๋ ธ๋ ฅํ๋ค:
window.history.pushState({}, null, '/pathname?k=v');
@sahalsaad ์ ์ ์ฌํ ์๋ฃจ์
:
```์๋ฐ์คํฌ๋ฆฝํธ
const oldWindow = window.location;
window.location ์ญ์ ;
์ฐฝ ์์น = {
... ์ค๋๋ ์ฐฝ,
// ๋ค์ sinon ์คํ
๊ณผ ๊ฐ์ ์ฌ์ฉ์ ์ ์ ๋ฎ์ด์ฐ๊ธฐ๋ฅผ ํฌํจํฉ๋๋ค.
๊ต์ฒด: sinon.stub(),
};
// ๋ง๋ฒ์ ๊ฑธ์ด๋ผ
window.location = ์ค๋๋ ์ฐฝ;
````
@sahalsaad ๊ฐ์ฌํฉ๋๋ค! ๋๋ window.location.search๋ฅผ ์กฐ๋กฑํ๊ธฐ ์ํด ์๋ฃจ์ ์ ๋ณํ์ ์ฌ์ฉํ์ต๋๋ค.
const location = {
...window.location,
search: queryString,
};
Object.defineProperty(window, 'location', {
writable: true,
value: location,
});
์๋ง๋ ๋ ๋์ ์๋ฃจ์ :
import { URL } from 'whatwg-url';
const location = new URL(window.location.href);
location.assign = jest.fn()
location.replace = jest.fn()
location.reload = jest.fn()
delete window.location
window.location = location
@kdelmonte๊ฐ ์ ๊ณตํ ์๋ฃจ์
์ ์ฌ์ฉํ์ฌ ๋ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค. window.location.search
๋ณ์๋ฅผ ์กฐ๋กฑํด์ผ ํ์ต๋๋ค. ๊ทธ๋์ ๋๋ ์ฌ์ฉํ๋ค
window.history.pushState({}, null, '?skuId=1234')
location
๋ jsdomwindow
๊ฐ์ฒด์์ ์ง์ ์ฌ์ ์ํ ์ ์์ผ๋ฏ๋ก ํ ๊ฐ์ง ๊ฐ๋ฅํ ์ ๊ทผ ๋ฐฉ์์ ํ์ ๊ฐ์ฒด์์ ์ฌ์ ์ํ๋ ๊ฒ์ ๋๋ค.global.window = Object.create(window); Object.defineProperty(window, 'location', { value: { href: 'http://example.org/' } });
๊ทํ์ ๋ต๋ณ์ ๋ด ์ํฉ์ ๋ง๋ ์ ์ผํ ๋ต๋ณ์ ๋๋ค. ๊ฐ์ฌํฉ๋๋ค!
location
๋ jsdomwindow
๊ฐ์ฒด์์ ์ง์ ์ฌ์ ์ํ ์ ์์ผ๋ฏ๋ก ํ ๊ฐ์ง ๊ฐ๋ฅํ ์ ๊ทผ ๋ฐฉ์์ ํ์ ๊ฐ์ฒด์์ ์ฌ์ ์ํ๋ ๊ฒ์ ๋๋ค.global.window = Object.create(window); Object.defineProperty(window, 'location', { value: { href: 'http://example.org/' } });
๊ทํ์ ๋ต๋ณ์ ๋ด ์ํฉ์ ๋ง๋ ์ ์ผํ ๋ต๋ณ์ ๋๋ค. ๊ฐ์ฌํฉ๋๋ค!
์ด๊ฒ์ ๋ ์ด์ ์๋ํ์ง ์์ต๋๋ค ๐ข
location
๋ jsdomwindow
๊ฐ์ฒด์์ ์ง์ ์ฌ์ ์ํ ์ ์์ผ๋ฏ๋ก ํ ๊ฐ์ง ๊ฐ๋ฅํ ์ ๊ทผ ๋ฐฉ์์ ํ์ ๊ฐ์ฒด์์ ์ฌ์ ์ํ๋ ๊ฒ์ ๋๋ค.global.window = Object.create(window); Object.defineProperty(window, 'location', { value: { href: 'http://example.org/' } });
๊ทํ์ ๋ต๋ณ์ ๋ด ์ํฉ์ ๋ง๋ ์ ์ผํ ๋ต๋ณ์ ๋๋ค. ๊ฐ์ฌํฉ๋๋ค!
์ด๊ฒ์ ๋ ์ด์ ์๋ํ์ง ์์ต๋๋ค ๐ข
๋์๊ฒ๋ ํจ๊ณผ๊ฐ ์๋ค
๋๋ ์ด๊ฒ์ ํด๊ฒฐํ๋ค :
delete window.location
window.location = {
href: 'http://example.org/,
}
Location
์์
์ ์ํ ์ ํธ๋ฆฌํฐ๋ก ๋ค์ ๋ชจ์๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
export class MockLocation extends URL implements Location {
ancestorOrigins: any = []
toString = jest.fn().mockImplementation(() => this.toString())
assign = jest.fn(href => this.href = href)
replace = jest.fn(href => this.href = href)
reload = jest.fn()
constructor(
url: string = 'http://mock.localhost',
) {
super(url)
}
onWindow(window: Window) {
Object.defineProperty(window, 'location', {
writable: true,
value: this
});
return this
}
}
๊ทธ๋ฐ ๋ค์ ๋ด ํ ์คํธ์์
let location: MockLocation
beforeEach(() => {
location = new MockLocation(MOCK_PARTNER_URL).onWindow(window)
})
๋๋ ํญ์ ์ด์ ๊ฐ์ ๊น๋ค๋ก์ด ๊ฐ์ฒด๋ฅผ ์คํฐ๋นํ๊ณ ์ ์ฐํ ๋์ฐ๋ฏธ ํจ์๋ฅผ ๋ง๋ค์์ต๋๋ค.
export const safelyStubAndThenCleanup = (target, method, value) => {
const original = target[method]
beforeEach(() => {
Object.defineProperty(target, method, { configurable: true, value })
})
afterEach(() => {
Object.defineProperty(target, method, { configurable: true, value: original })
})
}
๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ๋ฒ:
describe('when on /pages', () => {
safelyStubAndThenCleanup(window, 'location', { pathname: '/pages' })
it('should do something neat', () => { /* ... */ })
})
๊ทธ๋ฆฌ๊ณ ์ํ๋ ๊ฒ์ ์คํ
ํ ์ ์์ต๋๋ค. pathname
, href
๋ฑ... ์ด๋ ๊ฒ ํ๋ฉด ์ ๋ฆฌ์ ์ถ๊ฐ ์ด์ ์ ์ป์ ์ ์์ต๋๋ค.
ํต์ฌ์ location
์์ฒด๋ฅผ ์๋ง์ผ๋ก ๋ง๋ค ์ ์์ผ๋ฏ๋ก location
๋ฅผ ๊ฐ์ง๋ก ๋ฐ๊พธ๊ณ ํ
์คํธ๊ฐ ์๋ฃ๋๋ฉด ๋ค์ ๋ฃ์ผ์ญ์์ค.
๋๋ฒ๊น
์ธ์
์์ ๋ณผ ์ ์๋ฏ์ด global.location
๋ getter๋ฅผ ํตํด ๊ตฌํ๋์ง๋ง ๋จ์ ์์ฑ์ ์๋๋๋ค. ์ด๋ ๊ฒ ์ฌ์ ์ํ๋ ๊ฒ์ด ๋ ์์ ํ์ง ์์๊น์?
let originalLocationDescriptor;
beforeAll(() => {
originalLocationDescriptor = Object.getOwnPropertyDescriptor(global, 'location');
delete global.location;
global.location = {};
});
afterAll(() => {
Object.defineProperty(global, 'location', originalLocationDescriptor);
}):
์๋ global.location
๋ฅผ ์ฌ์ฉํ๋ ค๋ ์ด์ ๋ฅผ ์์ํ๊ธฐ ์ด๋ ต์ง๋ง ์กฐ๊ธ ๋ ์ ํํด ๋ณด์
๋๋ค.
๋ฌผ๋ก ์ด ์ฝ๋๋ ์ ์๊ฒ ์ ๋ง์ต๋๋ค. ๋๋ ๋จ์ง location.pathname
์ ์ ๊ทผํ์ง๋ง ์ด ๊ฐ์ฒด๋ ํ์ํ ๊ฒฝ์ฐ jest.fn()
๋ก ์ฝ๊ฒ ํ์ฅ๋ ์ ์์ต๋๋ค.
์ด๊ฒ์ jest 26.5๋ฅผ ์ฌ์ฉํ์ฌ ์ ์๊ฒ ํจ๊ณผ์ ์ด์์ต๋๋ค.
function stubLocation(location) {
beforeEach(() => {
jest.spyOn(window, "location", "get").mockReturnValue({
...window.location,
...location,
});
});
}
stubLocation({ pathname: "/facebook/jest/issues/5124" });
test("mocks location prop", () => {
expect(window.location.pathname).toEqual("/facebook/jest/issues/5124");
});
@vastus ์๋ฃจ์ ์ ๊ธฐ๋ฐ์ผ๋ก
location.search
ํ ์คํธ ์์ ์ถ๊ฐ:test('gets passed query param and returns it as a string if it exists', () => { history.replaceState({}, 'Test', '/test?customer=123'); const customerId = getQueryParam('customer'); expect(customerId).toBe('123'); });
์ด๊ฒ์ ๋ด๊ฐ ๊ฒช๊ณ ์๋ ๋ฌธ์ ์ ์ ํํ ์ ๋ง์์ต๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
๋๋๋ผ๋ NPM์ ์ ํจํค์ง๋ฅผ ๋ฐํํ๋ค
jest-environment-jsdom-global
์ด๋ค ์ฌ๋๋ค์ ํจ๊ป ๋ฐ์ํ๋ ๋ฌธ์ ์ ๋์์ด ๋ ์์๋,Object.defineProperty
.