Jest 테스트 실패: TypeError: window.matchMedia가 함수가 아닙니다.
프런트 엔드 테스트는 이번이 처음입니다.했습니다.TypeError: window.matchMedia is not a function
내 컴포넌트 안에.
Jest 문서를 살펴보니 "Manual mocks" 섹션을 찾았는데, 아직 어떻게 해야 할지 모르겠어요.
이제 Jest 문서에는 다음과 같은 "공식" 해결 방법이 있습니다.
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
저는 이 기술을 사용하여 많은 조롱의 문제를 해결했습니다.
describe("Test", () => {
beforeAll(() => {
Object.defineProperty(window, "matchMedia", {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
}))
});
});
});
항상는 안에 요.mocks
에서 package.json
"setupFilesAfterEnv": "<rootDir>/src/tests/mocks.js",
.
레퍼런스: 셋업Test Framework Script 파일
Jest 테스트 파일(테스트 위)에 matchMedia stub을 저장했습니다.이것에 의해, 테스트에 합격할 수 있습니다.
window.matchMedia = window.matchMedia || function() {
return {
matches: false,
addListener: function() {},
removeListener: function() {}
};
};
JEEST 공식 회피책
파일,즉 '모크 파일'을 거예요.matchMedia.js
다음 코드를 추가합니다.
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
다음 시험 안에 ''를 가져오세요.import './matchMedia';
모든 사용 사례에서 Import하기만 하면 문제가 해결될 것입니다.
대체 옵션
저는 이 문제에 계속 부딪혔고, 그저 너무 많은 수입을 하고 있다는 것을 알게 되었고, 다른 해결책을 제시해야겠다고 생각했습니다.
셋업/셋업하다를 만드는 것입니다.before.js
다음과 같이 합니다.
import 'regenerator-runtime';
/** Add any global mocks needed for the test suite here */
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
그런 다음 jeast.config 파일에 다음 내용을 추가합니다.
setupFiles: ['<rootDir>/
이전으로 가는 길입니다.JS 파일'],
Jest는 jsdom을 사용하여 브라우저 환경을 만듭니다.단, JSDom은 지원하지 않습니다.window.matchMedia
직접 작성하셔야 합니다.
Jeest의 수동 모크는 모듈 경계(예: 요구/가져오기 문)와 함께 작동하므로 조롱하기에 적절하지 않습니다.window.matchMedia
이치노
따라서 다음 두 가지 옵션이 있습니다.
window.matchMedia를 내보내는 로컬 matchMedia 모듈을 정의합니다.이것에 의해, 테스트에 사용하는 수동 모크를 정의할 수 있습니다.
글로벌 창에 matchMedia 모크를 추가하는 셋업 파일을 정의합니다.
이러한 옵션 중 하나를 사용하여 match Media polyfill을 모의실험으로 사용할 수 있습니다.최소한 테스트를 실행할 수 있는 경우 또는 다른 상태를 시뮬레이션할 필요가 있는 경우 Jest 수동 모의실험과 유사한 동작을 설정할 수 있는 개인 메서드를 사용하여 match Media polyfill을 직접 작성할 수 있습니다.
API를 조롱할 수 있습니다.
describe("Test", () => {
beforeAll(() => {
Object.defineProperty(window, "matchMedia", {
value: jest.fn(() => {
return {
matches: true,
addListener: jest.fn(),
removeListener: jest.fn()
};
})
});
});
});
저는 방금 이 문제에 직면했고 Global Mocks.ts에서 이것들을 조롱해야 했습니다.
Object.defineProperty(window, 'matchMedia', {
value: () => {
return {
matches: false,
addListener: () => {},
removeListener: () => {}
};
}
});
Object.defineProperty(window, 'getComputedStyle', {
value: () => {
return {
getPropertyValue: () => {}
};
}
});
.jest-matchmedia-mock
미디어 쿼리를 테스트하기 위한 패키지(디바이스 화면 변경, 색상 변경 등)
하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 한 줄씩.setupTest.js
삭제,
global.matchMedia = global.matchMedia || function() {
return {
matches : false,
addListener : function() {},
removeListener: function() {}
}
}
그러면 모든 테스트 케이스에 대한 매치 미디어 쿼리가 추가됩니다.
아래 TL;DR 답변
요.window.matchMedia
false
(오류)true
(변경하면)여러 개의 서로 다른 쿼리를 수신해야 하는 React 후크 및 컴포넌트가 있었습니다.matches
.
내가 시도한 것
개의 .jest-matchmedia-mock
도움이 되었습니다.제가 동안 3시간 동안 전화를 때 알 수 것 요.useMediaQuery
이전 쿼리는 더 이상 작동하지 않습니다., 즉 전달되는 입니다.useMediaQuery
맞아떨어지다true
든지 당신의 window.matchMedia
실제 "표준 폭"에 관계없이 동일한 쿼리를 사용합니다.
정답.
질문 내용을 실제로 테스트할 수 없다는 것을 깨달은 후jest-matchmedia-mock
쿼리의 할 수 matches
에는 「」가 css-mediaquery
packagenpm n n n
import mediaQuery from "css-mediaquery";
// Mock window.matchMedia's impl.
Object.defineProperty(window, "matchMedia", {
writable: true,
value: jest.fn().mockImplementation((query) => {
const instance = {
matches: mediaQuery.match(query, {
width: window.innerWidth,
height: window.innerHeight,
}),
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
};
// Listen to resize events from window.resizeTo and update the instance's match
window.addEventListener("resize", () => {
const change = mediaQuery.match(query, {
width: window.innerWidth,
height: window.innerHeight,
});
if (change != instance.matches) {
instance.matches = change;
instance.dispatchEvent("change");
}
});
return instance;
}),
});
// Mock window.resizeTo's impl.
Object.defineProperty(window, "resizeTo", {
value: (width: number, height: number) => {
Object.defineProperty(window, "innerWidth", {
configurable: true,
writable: true,
value: width,
});
Object.defineProperty(window, "outerWidth", {
configurable: true,
writable: true,
value: width,
});
Object.defineProperty(window, "innerHeight", {
configurable: true,
writable: true,
value: height,
});
Object.defineProperty(window, "outerHeight", {
configurable: true,
writable: true,
value: height,
});
window.dispatchEvent(new Event("resize"));
},
});
it it를 한다.css-mediaquery
window.innerWidth
하드 코딩된 부울 대신 쿼리가 실제로 일치하는지 여부를 확인합니다.또, 에 의해서 발생하는 이벤트의 사이즈 변경도 리슨 합니다.window.resizeTo
「」를 disced .matches
discloss.discloss 。
이제 사용할 수 있습니다.window.resizeTo
에서 창 로 변경"하도록 .window.matchMedia
이 폭을 반영합니다.여기 이 질문만을 위해 작성된 예가 있습니다. 따라서 성능 문제는 무시하십시오.
const bp = { xs: 200, sm: 620, md: 980, lg: 1280, xl: 1920 };
// Component.tsx
const Component = () => {
const isXs = window.matchMedia(`(min-width: ${bp.xs}px)`).matches;
const isSm = window.matchMedia(`(min-width: ${bp.sm}px)`).matches;
const isMd = window.matchMedia(`(min-width: ${bp.md}px)`).matches;
const isLg = window.matchMedia(`(min-width: ${bp.lg}px)`).matches;
const isXl = window.matchMedia(`(min-width: ${bp.xl}px)`).matches;
console.log("matches", { isXs, isSm, isMd, isLg, isXl });
const width =
(isXl && "1000px") ||
(isLg && "800px") ||
(isMd && "600px") ||
(isSm && "500px") ||
(isXs && "300px") ||
"100px";
return <div style={{ width }} />;
};
// Component.test.tsx
it("should use the md width value", () => {
window.resizeTo(bp.md, 1000);
const wrapper = mount(<Component />);
const div = wrapper.find("div").first();
// console.log: matches { isXs: true, isSm: true, isMd: true, isLg: false, isXl: false }
expect(div.prop("style")).toHaveProperty("width", "600px");
});
참고: 구성 요소를 장착한 후 윈도우 크기를 조정할 때 이 동작은 테스트하지 않았습니다.
은 제가 업데이트하기로 .react-scripts
(create-contract-app) 4.4.1에서 4.0.3으로 설정합니다. 후, 했습니다.Cannot read property 'matches' of undefined
.
여기 해결 방법이 있습니다.개발 의존관계로서 mq-polyfill을 인스톨 합니다.
이것을 럼 this로 주세요.src/setupTests.js
:
import matchMediaPolyfill from 'mq-polyfill'
matchMediaPolyfill(window)
// implementation of window.resizeTo for dispatching event
window.resizeTo = function resizeTo(width, height) {
Object.assign(this, {
innerWidth: width,
innerHeight: height,
outerWidth: width,
outerHeight: height
}).dispatchEvent(new this.Event('resize'))
}
이건 나한테 효과가 있었어.
저는 위의 답변들을 모두 시도해 보았지만 아무런 성과가 없었습니다.
mocks 폴더에 matchMedia.js를 추가해서 해줬어요.
techguy2000의 콘텐츠로 작성했습니다.
// __mocks__/matchMedia.js
'use strict';
Object.defineProperty(window, 'matchMedia', {
value: () => ({
matches: false,
addListener: () => {},
removeListener: () => {}
})
});
Object.defineProperty(window, 'getComputedStyle', {
value: () => ({
getPropertyValue: () => {}
})
});
module.exports = window;
을 리리에 .setup.js
:
import matchMedia from '../__mocks__/matchMedia';
쾅! :)
'아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, window.matchMedia
하기 전의 입니다.
예:
if (typeof window.matchMedia === 'function') {
// Do something with window.matchMedia
}
그리고 테스트는 더 이상 실패하지 않을 것이다.
타이프 스크립트를 사용하고 있는 경우는, 아래의 행을 셋업시에 입력합니다.Tests.ts 파일이 방법은 효과가 있었습니다.
export default global.matchMedia =
global.matchMedia ||
function (query) {
return {
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
};
};
이들은 Jest setupFiles를 통해 상당히 슬릭한 솔루션을 제공합니다.
https://github.com/HospitalRun/components/pull/117/commits/210d1b74e4c8c14e1ffd527042e3378bba064ed8
왜냐하면 나는 그 도서관을 이용했기 때문이다.window.matchMedia
컴포넌트와 리액트(React)가 합니다.window.matchMedia
으로는 jest.isolateModules()
function getMyComponentUnderTest(): typeof ComponentUnderTest {
let Component: typeof ComponentUnderTest;
// Must use isolateModules because we need to require a new module everytime so
jest.isolateModules(() => {
// Required so the library (inside Component) won't fail as it uses the window.matchMedia
// If we import/require it regularly once a new error will happen:
// `TypeError: Cannot read property 'matches' of undefined`
require('<your-path-to-the-mock>/__mocks__/window/match-media');
Component = require('./<path-to-component>');
});
// @ts-ignore assert the Component (TS screams about using variable before initialization)
// If for some reason in the future the behavior will change and this assertion will fail
// We can do a workaround by returning a Promise and the `resolve` callback will be called with the Component in the `isolateModules` function
// Or we can also put the whole test function inside the `isolateModules` (less preferred)
expect(Component).toBeDefined();
// @ts-ignore the Component must be defined as we assert it
return Component;
}
window.matchMedia
)/__mocks__/window/match-media
// Mock to solve: `TypeError: window.matchMedia is not a function`
// From https://stackoverflow.com/a/53449595/5923666
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => {
return ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
});
}),
});
// Making it a module so TypeScript won't scream about:
// TS1208: 'match-media.ts' cannot be compiled under '--isolatedModules' because it is considered a global script file. Add an import, export, or an empty 'export {}' statement to make it a module.
export {};
에 테테음음음이 포함되어 있는 경우window.matchMedia()
use Media()를 사용합니다.또한 관련된 어떤 것도 테스트하는 것을 목적으로 하지 않고 윈도 체크를 컴포넌트에 추가하여 메서드를 호출하는 것을 회피할 수 있습니다.
다음 코드 예에서는 Jest에 의해 코드가 실행되면 useMedia 훅은 항상 false를 반환합니다.
모듈 Import를 조롱하는 것에 반대하는 주장에 대한 게시물이 있습니다.https://dev.to/jackmellis/don-t-mock-modules-4jof
import { useLayoutEffect, useState } from 'react';
export function useMedia(query): boolean {
const [state, setState] = useState(false);
useLayoutEffect(() => {
// ******* WINDOW CHECK START *******
if (!window || !window.matchMedia) {
return;
}
// ******* WINDOW CHECK END *******
let mounted = true;
const mql = window.matchMedia(query);
const onChange = () => {
if (!mounted) return;
setState(!!mql.matches);
};
mql.addEventListener('change', onChange);
setState(mql.matches);
return () => {
mounted = false;
mql.removeEventListener('change', onChange);
};
}, [query]);
return state;
}
그러나 메서드에서 반환된 개체에 액세스하려면 파일을 테스트하는 대신 구성 요소 자체에서 개체를 조롱할 수 있습니다.사용 예 참조: (소스 링크)
import {useState, useEffect, useLayoutEffect} from 'react';
import {queryObjectToString, noop} from './utilities';
import {Effect, MediaQueryObject} from './types';
// ************** MOCK START **************
export const mockMediaQueryList: MediaQueryList = {
media: '',
matches: false,
onchange: noop,
addListener: noop,
removeListener: noop,
addEventListener: noop,
removeEventListener: noop,
dispatchEvent: (_: Event) => true,
};
// ************** MOCK END **************
const createUseMedia = (effect: Effect) => (
rawQuery: string | MediaQueryObject,
defaultState = false,
) => {
const [state, setState] = useState(defaultState);
const query = queryObjectToString(rawQuery);
effect(() => {
let mounted = true;
************** WINDOW CHECK START **************
const mediaQueryList: MediaQueryList =
typeof window === 'undefined'
? mockMediaQueryList
: window.matchMedia(query);
************** WINDOW CHECK END **************
const onChange = () => {
if (!mounted) {
return;
}
setState(Boolean(mediaQueryList.matches));
};
mediaQueryList.addListener(onChange);
setState(mediaQueryList.matches);
return () => {
mounted = false;
mediaQueryList.removeListener(onChange);
};
}, [query]);
return state;
};
export const useMedia = createUseMedia(useEffect);
export const useMediaLayout = createUseMedia(useLayoutEffect);
export default useMedia;
이를 위해 특별히 설계된 라이브러리를 개발했습니다.https://www.npmjs.com/package/mock-match-media
은 완전한 하고 있다.matchMedia
를 지정합니다.
그리고 그것은 심지어jest-setup
모든 테스트에 이 모의실험을 적용하기 위해 jast 설정에 파일을 Import할 수 있습니다(https://www.npmjs.com/package/mock-match-media#jest):
require('mock-match-media/jest-setup);
언급URL : https://stackoverflow.com/questions/39830580/jest-test-fails-typeerror-window-matchmedia-is-not-a-function
'sourcecode' 카테고리의 다른 글
Spring Webflux + JPA :사후 대응 리포지토리는 JPA에서 지원되지 않습니다. (0) | 2023.03.19 |
---|---|
MockMvc는 더 이상 스프링 부트 2.2.0에서 UTF-8 문자를 처리하지 않습니다.풀어주다 (0) | 2023.03.19 |
스프링 부트 셧다운 훅 (0) | 2023.03.19 |
mongodb에서 여러 어레이 요소를 업데이트하는 방법 (0) | 2023.03.19 |
빈 배열을 입력으로 사용하는 'useCallback'과 두 번째 매개 변수를 사용하지 않는 'useCallback'의 차이점은 무엇입니까? (0) | 2023.03.19 |