UNPKG

23.4 kBJavaScriptView Raw
1"use strict";
2
3require("jest-styled-components");
4
5var _react = _interopRequireDefault(require("react"));
6
7var _reactTestRenderer = _interopRequireWildcard(require("react-test-renderer"));
8
9var _styledComponents = require("styled-components");
10
11var _Media = require("../Media");
12
13var _MediaQueries = require("../MediaQueries");
14
15var _server = _interopRequireDefault(require("react-dom/server"));
16
17var _reactDom = _interopRequireDefault(require("react-dom"));
18
19function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
20
21function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
22
23function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
24
25function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
26
27function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
28
29function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
30
31function _templateObject() {
32 var data = _taggedTemplateLiteral(["\n ", "\n "]);
33
34 _templateObject = function _templateObject() {
35 return data;
36 };
37
38 return data;
39}
40
41function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
42
43var config = {
44 breakpoints: {
45 "extra-small": 0,
46 small: 768,
47 medium: 1024,
48 large: 1120
49 },
50 interactions: {
51 hover: "not all and (hover:hover)"
52 }
53};
54
55var _createMedia = (0, _Media.createMedia)(config),
56 Media = _createMedia.Media,
57 MediaContextProvider = _createMedia.MediaContextProvider,
58 createMediaStyle = _createMedia.createMediaStyle,
59 SortedBreakpoints = _createMedia.SortedBreakpoints,
60 findBreakpointAtWidth = _createMedia.findBreakpointAtWidth,
61 findBreakpointsForWidths = _createMedia.findBreakpointsForWidths,
62 valuesWithBreakpointProps = _createMedia.valuesWithBreakpointProps;
63
64var mediaQueries = new _MediaQueries.MediaQueries(config.breakpoints, config.interactions);
65describe("utilities", function () {
66 it("returns a list of breakpoints sorted from small to large", function () {
67 expect(SortedBreakpoints).toEqual(["extra-small", "small", "medium", "large"]);
68 });
69 it("returns the breakpoint that supports the given width", function () {
70 expect(findBreakpointAtWidth(-42)).toEqual(undefined);
71 expect(findBreakpointAtWidth(42)).toEqual("extra-small");
72 expect(findBreakpointAtWidth(767)).toEqual("extra-small");
73 expect(findBreakpointAtWidth(768)).toEqual("small");
74 expect(findBreakpointAtWidth(1042)).toEqual("medium");
75 expect(findBreakpointAtWidth(9999)).toEqual("large");
76 });
77 it("returns the breakpoints from the first through the last given widths", function () {
78 expect(findBreakpointsForWidths(-42, -21)).toEqual(undefined);
79 expect(findBreakpointsForWidths(42, 767)).toEqual(["extra-small"]);
80 expect(findBreakpointsForWidths(42, 768)).toEqual(["extra-small", "small"]);
81 expect(findBreakpointsForWidths(42, 1042)).toEqual(["extra-small", "small", "medium"]);
82 expect(findBreakpointsForWidths(768, 9999)).toEqual(["small", "medium", "large"]);
83 });
84 it("maps a list of responsive values to breakpoint props", function () {
85 expect(valuesWithBreakpointProps([1])).toEqual([[1, {
86 greaterThanOrEqual: "extra-small"
87 }]]);
88 expect(valuesWithBreakpointProps([1, 2])).toEqual([[1, {
89 at: "extra-small"
90 }], [2, {
91 greaterThanOrEqual: "small"
92 }]]);
93 expect(valuesWithBreakpointProps([1, 2, 2, 3])).toEqual([[1, {
94 at: "extra-small"
95 }], [2, {
96 between: ["small", "large"]
97 }], [3, {
98 greaterThanOrEqual: "large"
99 }]]);
100 expect(valuesWithBreakpointProps([2, 2, 2, 3])).toEqual([[2, {
101 between: ["extra-small", "large"]
102 }], [3, {
103 greaterThanOrEqual: "large"
104 }]]);
105 });
106});
107describe("Media", function () {
108 beforeEach(function () {
109 (0, _styledComponents.injectGlobal)(_templateObject(), createMediaStyle());
110 });
111 afterEach(function () {
112 window.matchMedia = undefined;
113 });
114 describe("concerning errors and warnings", function () {
115 var errorLogger = global.console.error;
116 var warnLogger = global.console.warn;
117 afterEach(function () {
118 global.console.error = errorLogger;
119 global.console.warn = warnLogger;
120 });
121 it("throws when trying to use mutually exclusive props", function () {
122 global.console.error = jest.fn();
123 expect(function () {
124 _reactTestRenderer.default.create(_react.default.createElement(Media, {
125 lessThan: "small",
126 at: "extra-small"
127 }, "ohai"));
128 }).toThrow();
129 });
130 it("warns when using `at` in conjunction with the largest breakpoint", function () {
131 global.console.warn = jest.fn();
132
133 _reactTestRenderer.default.create(_react.default.createElement(Media, {
134 at: "large"
135 }, "ohai")).toJSON();
136
137 expect(global.console.warn).toHaveBeenCalled();
138 });
139 });
140 describe("concerning styling", function () {
141 it("doesn’t add any size to the layout", function () {
142 var query = _reactTestRenderer.default.create(_react.default.createElement(Media, {
143 lessThan: "small"
144 }, "ohai")).toJSON();
145
146 expect(query.type).toEqual("div");
147 expect(query).toHaveStyleRule("margin", "0");
148 expect(query).toHaveStyleRule("padding", "0");
149 });
150 it("applies additional classNames passed as props", function () {
151 var query = _reactTestRenderer.default.create(_react.default.createElement(Media, {
152 lessThan: "small",
153 className: "foo"
154 }, "ohai")).toJSON();
155
156 expect(query.props.className).toContain("foo");
157 });
158 });
159 describe("concerning breakpoints", function () {
160 it("creates a container that will only display when the page size is less than the specified breakpoint", function () {
161 var query = _reactTestRenderer.default.create(_react.default.createElement(Media, {
162 lessThan: "small"
163 }, "ohai")).toJSON();
164
165 expect(query.type).toEqual("div");
166 expect(query).toHaveStyleRule("display", "none!important", {
167 media: "not all and (max-width:767px)"
168 });
169 });
170 it("creates a container that will only display when the page size is greater than or equal to the next breakpoint of the specified breakpoint", function () {
171 var query = _reactTestRenderer.default.create(_react.default.createElement(Media, {
172 greaterThan: "medium"
173 }, "ohai")).toJSON();
174
175 expect(query.type).toEqual("div");
176 expect(query).toHaveStyleRule("display", "none!important", {
177 media: "not all and (min-width:1120px)"
178 });
179 });
180 it("creates a container that will only display when the page size is greater than or equal to the specified breakpoint", function () {
181 var query = _reactTestRenderer.default.create(_react.default.createElement(Media, {
182 greaterThanOrEqual: "medium"
183 }, "ohai")).toJSON();
184
185 expect(query.type).toEqual("div");
186 expect(query).toHaveStyleRule("display", "none!important", {
187 media: "not all and (min-width:1024px)"
188 });
189 });
190 it("creates a container that will only display when the page size is between the specified breakpoints", function () {
191 var query = _reactTestRenderer.default.create(_react.default.createElement(Media, {
192 between: ["small", "large"]
193 }, "ohai")).toJSON();
194
195 expect(query.type).toEqual("div");
196 expect(query).toHaveStyleRule("display", "none!important", {
197 media: "not all and (min-width:768px) and (max-width:1119px)"
198 });
199 });
200 describe("concerning shortcuts", function () {
201 // FIXME: styled-components reconciliation issues. Output is right yet the
202 // generated classNames don't match
203 xit("creates a container that will only display when the page size is between the specified breakpoint and the next one", function () {
204 expect(_reactTestRenderer.default.create(_react.default.createElement(Media, {
205 at: "extra-small"
206 }, "ohai")).toJSON()).toEqual(_reactTestRenderer.default.create(_react.default.createElement(Media, {
207 between: ["extra-small", "small"]
208 }, "ohai")).toJSON());
209 expect(_reactTestRenderer.default.create(_react.default.createElement(Media, {
210 at: "small"
211 }, "ohai")).toJSON()).toEqual(_reactTestRenderer.default.create(_react.default.createElement(Media, {
212 between: ["small", "medium"]
213 }, "ohai")).toJSON());
214 expect(_reactTestRenderer.default.create(_react.default.createElement(Media, {
215 at: "medium"
216 }, "ohai")).toJSON()).toEqual(_reactTestRenderer.default.create(_react.default.createElement(Media, {
217 between: ["medium", "large"]
218 }, "ohai")).toJSON());
219 expect(_reactTestRenderer.default.create(_react.default.createElement(Media, {
220 at: "large"
221 }, "ohai")).toJSON()).toEqual(_reactTestRenderer.default.create(_react.default.createElement(Media, {
222 greaterThanOrEqual: "large"
223 }, "ohai")).toJSON());
224 });
225 });
226 });
227 describe("concerning interactions", function () {
228 it("creates a container that will only display when the interaction media query matches", function () {
229 var query = _reactTestRenderer.default.create(_react.default.createElement(Media, {
230 interaction: "hover"
231 }, "ohai")).toJSON();
232
233 expect(query.type).toEqual("div");
234 expect(query).toHaveStyleRule("display", "none!important", {
235 media: "not all and (hover:hover)"
236 });
237 });
238 });
239 describe("with a render prop", function () {
240 it("yields the class name so it can be applied to another element", function () {
241 var query = _reactTestRenderer.default.create(_react.default.createElement(Media, {
242 lessThan: "small"
243 }, function (className) {
244 return _react.default.createElement("span", {
245 className: className
246 }, "ohai");
247 })).toJSON();
248
249 expect(query.type).toEqual("span");
250 expect(query).toHaveStyleRule("display", "none!important", {
251 media: "not all and (max-width:767px)"
252 });
253 });
254 it("yields wether or not the element’s children should be rendered", function () {
255 var query = _reactTestRenderer.default.create(_react.default.createElement(MediaContextProvider, {
256 onlyMatch: ["extra-small", "small"]
257 }, _react.default.createElement(Media, {
258 at: "extra-small"
259 }, function (_, renderChildren) {
260 return _react.default.createElement("span", null, renderChildren && "extra-small");
261 }), _react.default.createElement(Media, {
262 at: "small"
263 }, function (_, renderChildren) {
264 return _react.default.createElement("span", null, renderChildren && "small");
265 }), _react.default.createElement(Media, {
266 at: "medium"
267 }, function (_, renderChildren) {
268 return _react.default.createElement("span", null, renderChildren && "medium");
269 })));
270
271 expect(query.root.findAllByType("span").map(function (div) {
272 return div.props.children;
273 }).filter(Boolean)).toEqual(["extra-small", "small"]);
274 });
275 });
276 describe("with a context", function () {
277 it("renders only matching `at` breakpoints", function () {
278 var query = _reactTestRenderer.default.create(_react.default.createElement(MediaContextProvider, {
279 onlyMatch: ["extra-small", "small"]
280 }, _react.default.createElement(Media, {
281 at: "extra-small"
282 }, "extra-small"), _react.default.createElement(Media, {
283 at: "small"
284 }, "small"), _react.default.createElement(Media, {
285 at: "medium"
286 }, "medium")));
287
288 expect(query.root.findAllByType("div").map(function (div) {
289 return div.props.children;
290 }).filter(Boolean)).toEqual(["extra-small", "small"]);
291 });
292 it("renders only matching `lessThan` breakpoints", function () {
293 var query = _reactTestRenderer.default.create(_react.default.createElement(MediaContextProvider, {
294 onlyMatch: ["small", "medium"]
295 }, _react.default.createElement(Media, {
296 lessThan: "small"
297 }, "extra-small"), _react.default.createElement(Media, {
298 lessThan: "medium"
299 }, "small"), _react.default.createElement(Media, {
300 lessThan: "large"
301 }, "medium")));
302
303 expect(query.root.findAllByType("div").map(function (div) {
304 return div.props.children;
305 }).filter(Boolean)).toEqual(["small", "medium"]);
306 });
307 it("renders only matching `greaterThan` breakpoints", function () {
308 var query = _reactTestRenderer.default.create(_react.default.createElement(MediaContextProvider, {
309 onlyMatch: ["small", "medium"]
310 }, _react.default.createElement(Media, {
311 greaterThan: "extra-small"
312 }, "small"), _react.default.createElement(Media, {
313 greaterThan: "small"
314 }, "medium"), _react.default.createElement(Media, {
315 greaterThan: "medium"
316 }, "large")));
317
318 expect(query.root.findAllByType("div").map(function (div) {
319 return div.props.children;
320 }).filter(Boolean)).toEqual(["small", "medium"]);
321 });
322 it("renders only matching `greaterThanOrEqual` breakpoints", function () {
323 var query = _reactTestRenderer.default.create(_react.default.createElement(MediaContextProvider, {
324 onlyMatch: ["small", "medium"]
325 }, _react.default.createElement(Media, {
326 greaterThanOrEqual: "small"
327 }, "small"), _react.default.createElement(Media, {
328 greaterThanOrEqual: "medium"
329 }, "medium"), _react.default.createElement(Media, {
330 greaterThanOrEqual: "large"
331 }, "large")));
332
333 expect(query.root.findAllByType("div").map(function (div) {
334 return div.props.children;
335 }).filter(Boolean)).toEqual(["small", "medium"]);
336 });
337 it("renders only matching `between` breakpoints", function () {
338 var query = _reactTestRenderer.default.create(_react.default.createElement(MediaContextProvider, {
339 onlyMatch: ["medium", "large"]
340 }, _react.default.createElement(Media, {
341 between: ["extra-small", "medium"]
342 }, "extra-small - medium"), _react.default.createElement(Media, {
343 between: ["small", "large"]
344 }, "small - large")));
345
346 expect(query.root.findAllByType("div").map(function (div) {
347 return div.props.children;
348 }).filter(Boolean)).toEqual(["small - large"]);
349 });
350 it("renders only matching interactions", function () {
351 var query = _reactTestRenderer.default.create(_react.default.createElement(MediaContextProvider, {
352 onlyMatch: ["hover"]
353 }, _react.default.createElement(Media, {
354 interaction: "hover"
355 }, "hover"), _react.default.createElement(Media, {
356 between: ["small", "large"]
357 }, "small - large")));
358
359 expect(query.root.findAllByType("div").map(function (div) {
360 return div.props.children;
361 }).filter(Boolean)).toEqual(["hover"]);
362 });
363 describe("client-side with dynamic media query API available", function () {
364 Object.entries({
365 breakpoint: "medium",
366 interaction: "hover"
367 }).forEach(function (_ref) {
368 var _ref2 = _slicedToArray(_ref, 2),
369 type = _ref2[0],
370 mediaQuery = _ref2[1];
371
372 it("only renders the current ".concat(type, " media query"), function () {
373 mockCurrentDynamicBreakpoint(mediaQuery);
374
375 var query = _reactTestRenderer.default.create(_react.default.createElement(MediaContextProvider, {
376 onlyMatch: ["small", mediaQuery]
377 }, _react.default.createElement(Media, {
378 at: "extra-small"
379 }, _react.default.createElement("span", {
380 className: "extra-small"
381 })), _react.default.createElement(Media, {
382 at: "medium"
383 }, _react.default.createElement("span", {
384 className: "medium"
385 })), _react.default.createElement(Media, {
386 at: "large"
387 }, _react.default.createElement("span", {
388 className: "large"
389 })), _react.default.createElement(Media, {
390 interaction: "hover"
391 }, _react.default.createElement("span", {
392 className: "hover"
393 }))));
394
395 expect(query.root.findAllByType("span").length).toEqual(1);
396 expect(query.root.findByProps({
397 className: mediaQuery
398 })).not.toBeNull();
399 });
400 });
401 it("disables usage of dynamic API to further narrow down", function () {
402 mockCurrentDynamicBreakpoint("medium");
403
404 var query = _reactTestRenderer.default.create(_react.default.createElement(MediaContextProvider, {
405 onlyMatch: ["extra-small", "medium", "large"],
406 disableDynamicMediaQueries: true
407 }, _react.default.createElement(Media, {
408 at: "extra-small"
409 }, _react.default.createElement("span", {
410 className: "extra-small"
411 })), _react.default.createElement(Media, {
412 at: "medium"
413 }, _react.default.createElement("span", {
414 className: "medium"
415 })), _react.default.createElement(Media, {
416 at: "large"
417 }, _react.default.createElement("span", {
418 className: "large"
419 }))));
420
421 expect(query.root.findAllByType("span").length).toEqual(3);
422 });
423 it("does not render anything if the current breakpoint isn’t in the already narrowed down set", function () {
424 mockCurrentDynamicBreakpoint("large");
425
426 var query = _reactTestRenderer.default.create(_react.default.createElement(MediaContextProvider, {
427 onlyMatch: ["small", "medium"]
428 }, _react.default.createElement(Media, {
429 at: "extra-small"
430 }, _react.default.createElement("span", {
431 className: "extra-small"
432 })), _react.default.createElement(Media, {
433 at: "medium"
434 }, _react.default.createElement("span", {
435 className: "medium"
436 })), _react.default.createElement(Media, {
437 at: "large"
438 }, _react.default.createElement("span", {
439 className: "large"
440 }))));
441
442 expect(query.root.findAllByType("span").length).toEqual(0);
443 });
444 });
445 });
446 describe("during hydration", function () {
447 // FIXME: Unable to reproduce this here, so we'll do a more synthetic test.
448 xit("does not warn about Media components that do not match and are empty", function (done) {
449 var spy = jest.spyOn(console, "error");
450
451 var App = function App() {
452 return _react.default.createElement(MediaContextProvider, null, _react.default.createElement(Media, {
453 at: "extra-small"
454 }, _react.default.createElement("div", {
455 className: "extra-small"
456 })), _react.default.createElement(Media, {
457 at: "medium"
458 }, _react.default.createElement("div", {
459 className: "medium"
460 })), _react.default.createElement(Media, {
461 greaterThanOrEqual: "large"
462 }, _react.default.createElement("div", {
463 className: "large"
464 })));
465 };
466
467 var container = document.createElement("div");
468 document.body.appendChild(container);
469 mockCurrentDynamicBreakpoint("medium");
470 container.innerHTML = _server.default.renderToString(_react.default.createElement(App, null));
471
472 _reactDom.default.hydrate(_react.default.createElement(App, null), container, function () {
473 expect(spy).not.toHaveBeenCalled();
474 done();
475 });
476 }); // This is the best we can do until we figure out a way to reproduce a
477 // warning, as per above.
478
479 it("does not warn about Media components that do not match and are empty", function () {
480 mockCurrentDynamicBreakpoint("medium");
481
482 var query = _reactTestRenderer.default.create(_react.default.createElement(MediaContextProvider, null, _react.default.createElement(Media, {
483 at: "extra-small"
484 }, _react.default.createElement("span", {
485 className: "extra-small"
486 })), _react.default.createElement(Media, {
487 at: "medium"
488 }, _react.default.createElement("span", {
489 className: "medium"
490 })), _react.default.createElement(Media, {
491 at: "large"
492 }, _react.default.createElement("span", {
493 className: "large"
494 })))).toJSON();
495
496 expect(query.find(function (e) {
497 return e.props.className.includes("extra-small");
498 }).props.suppressHydrationWarning).toEqual(true);
499 expect(query.find(function (e) {
500 return e.props.className.includes("medium");
501 }).props.suppressHydrationWarning).toEqual(false);
502 expect(query.find(function (e) {
503 return e.props.className.includes("large");
504 }).props.suppressHydrationWarning).toEqual(true);
505 });
506 }); // TODO: This actually doesn’t make sense, I think, because if the user
507 // decides to not use a provider they are opting for rendering all
508 // variants. We just need to make sure to document this well.
509
510 xdescribe("without a context provider", function () {
511 it("only renders the current breakpoint", function () {
512 mockCurrentDynamicBreakpoint("medium");
513
514 var query = _reactTestRenderer.default.create(_react.default.createElement(_react.default.Fragment, null, _react.default.createElement(Media, {
515 at: "extra-small"
516 }, _react.default.createElement("span", {
517 className: "extra-small"
518 })), _react.default.createElement(Media, {
519 at: "medium"
520 }, _react.default.createElement("span", {
521 className: "medium"
522 })), _react.default.createElement(Media, {
523 at: "large"
524 }, _react.default.createElement("span", {
525 className: "large"
526 }))));
527
528 expect(query.root.findAllByType("span").length).toEqual(1);
529 expect(query.root.findByProps({
530 className: "medium"
531 })).not.toBeNull();
532 });
533 });
534});
535
536function mockCurrentDynamicBreakpoint(at) {
537 window.matchMedia = jest.fn(function (mediaQuery) {
538 var key = Object.entries(mediaQueries.dynamicResponsiveMediaQueries).find(function (_ref3) {
539 var _ref4 = _slicedToArray(_ref3, 2),
540 _ = _ref4[0],
541 query = _ref4[1];
542
543 return mediaQuery === query;
544 })[0]; // Return mock object that only matches the mocked breakpoint
545
546 return {
547 matches: key === at,
548 addListener: jest.fn(),
549 removeListener: jest.fn()
550 };
551 });
552}
553//# sourceMappingURL=Media.test.js.map
\No newline at end of file