TL; DR Antwort weiter unten
In meinem Fall war die Antwort nicht genug, da window.matchMedia
sie immer zurückkehren würde false
(oder true
wenn Sie sie ändern). Ich hatte einige React-Hooks und -Komponenten, die mehrere verschiedene Abfragen mit möglicherweise unterschiedlichen abhören mussten matches
.
Was ich versucht habe
Wenn Sie jeweils nur eine Abfrage testen müssen und Ihre Tests nicht auf mehreren Übereinstimmungen beruhen, jest-matchmedia-mock
war dies hilfreich. Nach dem Versuch, es 3 Stunden lang zu verwenden, habe ich jedoch verstanden useMediaQuery
, dass die vorherigen Abfragen, die Sie gestellt haben , beim Anrufen nicht mehr funktionieren. Tatsächlich stimmt die Abfrage, an die Sie übergeben useMediaQuery
, nur dann überein, true
wenn Ihr Code window.matchMedia
dieselbe Abfrage aufruft , unabhängig von der tatsächlichen "Fensterbreite".
Antworten
Nachdem mir klar wurde, dass ich meine Abfragen nicht testen konnte jest-matchmedia-mock
, änderte ich die ursprüngliche Antwort ein wenig, um das Verhalten dynamischer Abfragen verspotten zu können matches
. Diese Lösung erfordert das css-mediaquery
npm-Paket.
import mediaQuery from "css-mediaquery";
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(),
removeListener: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
};
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;
}),
});
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"));
},
});
Es wird css-mediaquery
mit dem verwendet window.innerWidth
, um zu bestimmen, ob die Abfrage tatsächlich mit einem fest codierten Booleschen Wert übereinstimmt. Außerdem wird die Größe von Ereignissen abgehört, die von der window.resizeTo
verspotteten Implementierung ausgelöst wurden , um den matches
Wert zu aktualisieren .
Sie können jetzt window.resizeTo
in Ihren Tests die Breite des Fensters ändern, damit Ihre Aufrufe window.matchMedia
diese Breite widerspiegeln. Hier ist ein Beispiel, das nur für diese Frage erstellt wurde. Ignorieren Sie also die Leistungsprobleme!
const bp = { xs: 200, sm: 620, md: 980, lg: 1280, xl: 1920 };
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 }} />;
};
it("should use the md width value", () => {
window.resizeTo(bp.md, 1000);
const wrapper = mount(<Component />);
const div = wrapper.find("div").first();
expect(div.prop("style")).toHaveProperty("width", "600px");
});
Hinweis: Ich habe das Verhalten beim Ändern der Fenstergröße NACH der Montage der Komponente nicht getestet