TL; DR Antwort weiter unten
In meinem Fall war die Antwort nicht genug, da window.matchMediasie immer zurückkehren würde false(oder truewenn 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-mockwar 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, truewenn Ihr Code window.matchMediadieselbe 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-mediaquerynpm-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-mediaquerymit 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.resizeToverspotteten Implementierung ausgelöst wurden , um den matchesWert zu aktualisieren .
Sie können jetzt window.resizeToin Ihren Tests die Breite des Fensters ändern, damit Ihre Aufrufe window.matchMediadiese 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