├── .gitignore ├── .travis.yml ├── .npmignore ├── HISTORY.md ├── package.json ├── LICENSE ├── README.md ├── index.js └── test └── unit-tests.js /.gitignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .gitignore 3 | .travis.yml 4 | coverage/ 5 | node_modules/ 6 | test/ 7 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | CSS Media Query Change History 2 | ============================== 3 | 4 | NEXT 5 | ---- 6 | 7 | * Made `parse()` sticter; it will now thorw a `SyntaxError` if a media query is 8 | invalid. This makes it behave more like `JSON.parse()`. 9 | 10 | 11 | 0.1.2 (2014-01-21) 12 | ------------------ 13 | 14 | * Fixed issue with parsing media queries that do not have expressions. ([#5][]) 15 | 16 | 17 | [#5]: https://github.com/ericf/css-mediaquery/issues/5 18 | 19 | 20 | 0.1.1 (2014-01-08) 21 | ------------------ 22 | 23 | * Added docs to README for `parse()`. 24 | 25 | 26 | 0.1.0 (2014-01-08) 27 | ------------------ 28 | 29 | * Initial public release. 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "css-mediaquery", 3 | "version": "0.1.2", 4 | "description": "Parses and determines if a given CSS Media Query matches a set of values.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "istanbul cover -- ./node_modules/mocha/bin/_mocha test/ --reporter spec" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git://github.com/ericf/css-mediaquery.git" 12 | }, 13 | "keywords": [ 14 | "css", 15 | "media", 16 | "query", 17 | "mediaquery", 18 | "media-query", 19 | "mobile", 20 | "parse", 21 | "match" 22 | ], 23 | "author": "Eric Ferraiuolo ", 24 | "contributors": [ 25 | "Tilo Mitra " 26 | ], 27 | "license": "BSD-3-Clause", 28 | "bugs": { 29 | "url": "https://github.com/ericf/css-mediaquery/issues" 30 | }, 31 | "homepage": "https://github.com/ericf/css-mediaquery", 32 | "devDependencies": { 33 | "mocha": "~1.16.2", 34 | "chai": "~1.8.1", 35 | "istanbul": "~0.2.3" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014 Yahoo! Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the Yahoo! Inc. nor the 15 | names of its contributors may be used to endorse or promote products 16 | derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL YAHOO! INC. BE LIABLE FOR ANY 22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CSS Media Query 2 | =============== 3 | 4 | [![Build Status](https://travis-ci.org/ericf/css-mediaquery.png?branch=master)](https://travis-ci.org/ericf/css-mediaquery) 5 | [![Dependency Status](https://gemnasium.com/ericf/css-mediaquery.png)](https://gemnasium.com/ericf/css-mediaquery) 6 | [![npm Version](https://badge.fury.io/js/css-mediaquery.png)](https://npmjs.org/package/css-mediaquery) 7 | 8 | Parses and determines if a given CSS Media Query matches a set of values via 9 | JavaScript. 10 | 11 | Installation 12 | ------------ 13 | 14 | Install via npm: 15 | 16 | ```shell 17 | $ npm install css-mediaquery 18 | ``` 19 | 20 | Usage 21 | ----- 22 | 23 | This package has two exports: `parse()`, and `match()` which can parse CSS Media 24 | Queries and determine if a media query matches a given set of values. 25 | 26 | ### Matching 27 | 28 | The `match()` method lets you compare a media query expression with a JavaScript 29 | object and determine if a media query matches a given set of values. 30 | 31 | ```javascript 32 | var mediaQuery = require('css-mediaquery'); 33 | 34 | var isMatch = mediaQuery.match('screen and (min-width: 40em)', { 35 | type : 'screen', 36 | width: '1024px' 37 | }); 38 | 39 | console.log(isMatch); // => true 40 | ``` 41 | 42 | The values specified to check a media query string against should be thought of 43 | as if they are the current state of a device/browser. A `type` value _must_ be 44 | specified, and it can _not_ be `"all"`. 45 | 46 | ### Parsing 47 | 48 | Existing CSS Parsers don't do a great job at parsing the details of media 49 | queries. That's where `css-mediaquery` shines. You can parse a media query 50 | expression and get an AST back by using the `parse()` method. 51 | 52 | ```javascript 53 | var mediaQuery = require('css-mediaquery'), 54 | ast = mediaQuery.parse('screen and (min-width: 48em)'); 55 | ``` 56 | 57 | The `ast` variable will have the following payload: 58 | 59 | ```javascript 60 | [ 61 | { 62 | inverse: false, 63 | type : 'screen', 64 | 65 | expressions: [ 66 | { 67 | modifier: 'min', 68 | feature : 'width', 69 | value : '48em' 70 | } 71 | ] 72 | } 73 | ] 74 | ``` 75 | 76 | This package was written with care to following the W3C Recommendations for 77 | [CSS3 Media Queries][w3c-mq] and [CSS3 Values and Units][w3c-vu]. It supports 78 | all of the [Media Features][w3c-mq-features] and will properly convert values to 79 | a common unit before comparing them. 80 | 81 | 82 | [w3c-mq]: http://www.w3.org/TR/css3-mediaqueries/ 83 | [w3c-mq-features]: http://www.w3.org/TR/css3-mediaqueries/#media1 84 | [w3c-vu]: http://www.w3.org/TR/css3-values/ 85 | 86 | 87 | License 88 | ------- 89 | 90 | This software is free to use under the Yahoo! Inc. BSD license. 91 | See the [LICENSE file][] for license text and copyright information. 92 | 93 | 94 | [LICENSE file]: https://github.com/ericf/css-mediaquery/blob/master/LICENSE 95 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014, Yahoo! Inc. All rights reserved. 3 | Copyrights licensed under the New BSD License. 4 | See the accompanying LICENSE file for terms. 5 | */ 6 | 7 | 'use strict'; 8 | 9 | exports.match = matchQuery; 10 | exports.parse = parseQuery; 11 | 12 | // ----------------------------------------------------------------------------- 13 | 14 | var RE_MEDIA_QUERY = /^(?:(only|not)?\s*([_a-z][_a-z0-9-]*)|(\([^\)]+\)))(?:\s*and\s*(.*))?$/i, 15 | RE_MQ_EXPRESSION = /^\(\s*([_a-z-][_a-z0-9-]*)\s*(?:\:\s*([^\)]+))?\s*\)$/, 16 | RE_MQ_FEATURE = /^(?:(min|max)-)?(.+)/, 17 | RE_LENGTH_UNIT = /(em|rem|px|cm|mm|in|pt|pc)?\s*$/, 18 | RE_RESOLUTION_UNIT = /(dpi|dpcm|dppx)?\s*$/; 19 | 20 | function matchQuery(mediaQuery, values) { 21 | return parseQuery(mediaQuery).some(function (query) { 22 | var inverse = query.inverse; 23 | 24 | // Either the parsed or specified `type` is "all", or the types must be 25 | // equal for a match. 26 | var typeMatch = query.type === 'all' || values.type === query.type; 27 | 28 | // Quit early when `type` doesn't match, but take "not" into account. 29 | if ((typeMatch && inverse) || !(typeMatch || inverse)) { 30 | return false; 31 | } 32 | 33 | var expressionsMatch = query.expressions.every(function (expression) { 34 | var feature = expression.feature, 35 | modifier = expression.modifier, 36 | expValue = expression.value, 37 | value = values[feature]; 38 | 39 | // Missing or falsy values don't match. 40 | if (!value) { return false; } 41 | 42 | switch (feature) { 43 | case 'orientation': 44 | case 'scan': 45 | return value.toLowerCase() === expValue.toLowerCase(); 46 | 47 | case 'width': 48 | case 'height': 49 | case 'device-width': 50 | case 'device-height': 51 | expValue = toPx(expValue); 52 | value = toPx(value); 53 | break; 54 | 55 | case 'resolution': 56 | expValue = toDpi(expValue); 57 | value = toDpi(value); 58 | break; 59 | 60 | case 'aspect-ratio': 61 | case 'device-aspect-ratio': 62 | case /* Deprecated */ 'device-pixel-ratio': 63 | expValue = toDecimal(expValue); 64 | value = toDecimal(value); 65 | break; 66 | 67 | case 'grid': 68 | case 'color': 69 | case 'color-index': 70 | case 'monochrome': 71 | expValue = parseInt(expValue, 10) || 1; 72 | value = parseInt(value, 10) || 0; 73 | break; 74 | } 75 | 76 | switch (modifier) { 77 | case 'min': return value >= expValue; 78 | case 'max': return value <= expValue; 79 | default : return value === expValue; 80 | } 81 | }); 82 | 83 | return (expressionsMatch && !inverse) || (!expressionsMatch && inverse); 84 | }); 85 | } 86 | 87 | function parseQuery(mediaQuery) { 88 | return mediaQuery.split(',').map(function (query) { 89 | query = query.trim(); 90 | 91 | var captures = query.match(RE_MEDIA_QUERY); 92 | 93 | // Media Query must be valid. 94 | if (!captures) { 95 | throw new SyntaxError('Invalid CSS media query: "' + query + '"'); 96 | } 97 | 98 | var modifier = captures[1], 99 | type = captures[2], 100 | expressions = ((captures[3] || '') + (captures[4] || '')).trim(), 101 | parsed = {}; 102 | 103 | parsed.inverse = !!modifier && modifier.toLowerCase() === 'not'; 104 | parsed.type = type ? type.toLowerCase() : 'all'; 105 | 106 | // Check for media query expressions. 107 | if (!expressions) { 108 | parsed.expressions = []; 109 | return parsed; 110 | } 111 | 112 | // Split expressions into a list. 113 | expressions = expressions.match(/\([^\)]+\)/g); 114 | 115 | // Media Query must be valid. 116 | if (!expressions) { 117 | throw new SyntaxError('Invalid CSS media query: "' + query + '"'); 118 | } 119 | 120 | parsed.expressions = expressions.map(function (expression) { 121 | var captures = expression.match(RE_MQ_EXPRESSION); 122 | 123 | // Media Query must be valid. 124 | if (!captures) { 125 | throw new SyntaxError('Invalid CSS media query: "' + query + '"'); 126 | } 127 | 128 | var feature = captures[1].toLowerCase().match(RE_MQ_FEATURE); 129 | 130 | return { 131 | modifier: feature[1], 132 | feature : feature[2], 133 | value : captures[2] 134 | }; 135 | }); 136 | 137 | return parsed; 138 | }); 139 | } 140 | 141 | // -- Utilities ---------------------------------------------------------------- 142 | 143 | function toDecimal(ratio) { 144 | var decimal = Number(ratio), 145 | numbers; 146 | 147 | if (!decimal) { 148 | numbers = ratio.match(/^(\d+)\s*\/\s*(\d+)$/); 149 | decimal = numbers[1] / numbers[2]; 150 | } 151 | 152 | return decimal; 153 | } 154 | 155 | function toDpi(resolution) { 156 | var value = parseFloat(resolution), 157 | units = String(resolution).match(RE_RESOLUTION_UNIT)[1]; 158 | 159 | switch (units) { 160 | case 'dpcm': return value / 2.54; 161 | case 'dppx': return value * 96; 162 | default : return value; 163 | } 164 | } 165 | 166 | function toPx(length) { 167 | var value = parseFloat(length), 168 | units = String(length).match(RE_LENGTH_UNIT)[1]; 169 | 170 | switch (units) { 171 | case 'em' : return value * 16; 172 | case 'rem': return value * 16; 173 | case 'cm' : return value * 96 / 2.54; 174 | case 'mm' : return value * 96 / 2.54 / 10; 175 | case 'in' : return value * 96; 176 | case 'pt' : return value * 72; 177 | case 'pc' : return value * 72 / 12; 178 | default : return value; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /test/unit-tests.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | 'use strict'; 4 | 5 | var expect = require('chai').expect, 6 | mediaQuery = require('../'); 7 | 8 | describe('mediaQuery.parse()', function () { 9 | it('should parse media queries without expressions', function () { 10 | expect(mediaQuery.parse('screen')).to.eql([ 11 | { 12 | inverse : false, 13 | type : 'screen', 14 | expressions: [] 15 | } 16 | ]); 17 | 18 | expect(mediaQuery.parse('not screen')).to.eql([ 19 | { 20 | inverse : true, 21 | type : 'screen', 22 | expressions: [] 23 | } 24 | ]); 25 | }); 26 | 27 | it('should parse common retina media query list', function () { 28 | var parsed = mediaQuery.parse( 29 | 'only screen and (-webkit-min-device-pixel-ratio: 2),\n' + 30 | 'only screen and ( min--moz-device-pixel-ratio: 2),\n' + 31 | 'only screen and ( -o-min-device-pixel-ratio: 2/1),\n' + 32 | 'only screen and ( min-device-pixel-ratio: 2),\n' + 33 | 'only screen and ( min-resolution: 192dpi),\n' + 34 | 'only screen and ( min-resolution: 2dppx)' 35 | ); 36 | 37 | expect(parsed).to.be.an.array; 38 | expect(parsed).to.have.length(6); 39 | expect(parsed[0].expressions[0].feature).to.equal('-webkit-min-device-pixel-ratio'); 40 | expect(parsed[1].expressions[0].modifier).to.equal('min'); 41 | }); 42 | 43 | it('should throw a SyntaxError when a media query is invalid', function () { 44 | function parse(query) { 45 | return function () { mediaQuery.parse(query); }; 46 | } 47 | 48 | expect(parse('some crap')).to.throw(SyntaxError); 49 | expect(parse('48em')).to.throw(SyntaxError); 50 | expect(parse('screen and crap')).to.throw(SyntaxError); 51 | expect(parse('screen and (48em)')).to.throw(SyntaxError); 52 | expect(parse('screen and (foo:)')).to.throw(SyntaxError); 53 | expect(parse('()')).to.throw(SyntaxError); 54 | expect(parse('(foo) (bar)')).to.throw(SyntaxError); 55 | expect(parse('(foo:) and (bar)')).to.throw(SyntaxError); 56 | }); 57 | }); 58 | 59 | describe('mediaQuery.match()', function () { 60 | describe('Equality Check', function () { 61 | it('Orientation: should return true for a correct match (===)', function () { 62 | expect(mediaQuery.match( 63 | '(orientation: portrait)', {orientation: 'portrait'} 64 | )).to.be.true; 65 | }); 66 | 67 | it('Orientation: should return false for an incorrect match (===)', function () { 68 | expect(mediaQuery.match( 69 | '(orientation: landscape)', {orientation: 'portrait'} 70 | )).to.be.false; 71 | }); 72 | 73 | it('Scan: should return true for a correct match (===)', function () { 74 | expect(mediaQuery.match( 75 | '(scan: progressive)', {scan: 'progressive'} 76 | )).to.be.true; 77 | }); 78 | 79 | it('Scan: should return false for an incorrect match (===)', function () { 80 | expect(mediaQuery.match( 81 | '(scan: progressive)', {scan: 'interlace'} 82 | )).to.be.false; 83 | }); 84 | 85 | it('Width: should return true for a correct match', function () { 86 | expect(mediaQuery.match( 87 | '(width: 800px)', {width: 800} 88 | )).to.be.true; 89 | }); 90 | 91 | it('Width: should return false for an incorrect match', function () { 92 | expect(mediaQuery.match( 93 | '(width: 800px)', {width: 900} 94 | )).to.be.false; 95 | }); 96 | }); 97 | 98 | describe('Length Check', function () { 99 | describe('Width', function () { 100 | it('should return true for a width higher than a min-width', function () { 101 | expect(mediaQuery.match( 102 | '(min-width: 48em)', {width: '80em'} 103 | )).to.be.true; 104 | }); 105 | 106 | it('should return false for a width lower than a min-width', function () { 107 | expect(mediaQuery.match( 108 | '(min-width: 48em)', {width: '20em'} 109 | )).to.be.false; 110 | }); 111 | 112 | it('should return false when no width value is specified', function () { 113 | expect(mediaQuery.match( 114 | '(min-width: 48em)', {resolution: 72} 115 | )).to.be.false; 116 | }); 117 | }); 118 | 119 | describe('Different Units', function () { 120 | it('should work with ems', function () { 121 | expect(mediaQuery.match( 122 | '(min-width: 500px)', {width: '48em'} 123 | )).to.be.true; 124 | }); 125 | 126 | it('should work with rems', function () { 127 | expect(mediaQuery.match( 128 | '(min-width: 500px)', {width: '48rem'} 129 | )).to.be.true; 130 | }); 131 | 132 | it('should work with cm', function () { 133 | expect(mediaQuery.match( 134 | '(max-height: 1000px)', {height: '20cm'} 135 | )).to.be.true; 136 | }); 137 | 138 | it('should work with mm', function () { 139 | expect(mediaQuery.match( 140 | '(max-height: 1000px)', {height: '200mm'} 141 | )).to.be.true; 142 | }); 143 | 144 | it('should work with inch', function () { 145 | expect(mediaQuery.match( 146 | '(max-height: 1000px)', {height: '20in'} 147 | )).to.be.false; 148 | }); 149 | 150 | it('should work with pt', function () { 151 | expect(mediaQuery.match( 152 | '(max-height: 1000px)', {height: '850pt'} 153 | )).to.be.false; 154 | }); 155 | 156 | it('should work with pc', function () { 157 | expect(mediaQuery.match( 158 | '(max-height: 1000px)', {height: '60pc'} 159 | )).to.be.true; 160 | }); 161 | }); 162 | 163 | }); 164 | 165 | describe('Resolution Check', function () { 166 | it('should return true for a resolution match', function () { 167 | expect(mediaQuery.match( 168 | '(resolution: 50dpi)', {resolution: 50} 169 | )).to.be.true; 170 | }); 171 | 172 | it('should return true for a resolution higher than a min-resolution', function () { 173 | expect(mediaQuery.match( 174 | '(min-resolution: 50dpi)', {resolution: 72} 175 | )).to.be.true; 176 | }); 177 | 178 | it('should return false for a resolution higher than a max-resolution', function () { 179 | expect(mediaQuery.match( 180 | '(max-resolution: 72dpi)', {resolution: 300} 181 | )).to.be.false; 182 | }); 183 | 184 | it('should return false if resolution isnt passed in', function () { 185 | expect(mediaQuery.match( 186 | '(min-resolution: 72dpi)', {width: 300} 187 | )).to.be.false; 188 | }); 189 | 190 | it('should convert units properly', function () { 191 | expect(mediaQuery.match( 192 | '(min-resolution: 72dpi)', {resolution: '75dpcm'} 193 | )).to.be.false; 194 | 195 | expect(mediaQuery.match( 196 | '(resolution: 192dpi)', {resolution: '2dppx'} 197 | )).to.be.true; 198 | }); 199 | }); 200 | 201 | describe('Aspect Ratio Check', function () { 202 | it('should return true for an aspect-ratio higher than a min-aspect-ratio', function () { 203 | expect(mediaQuery.match( 204 | '(min-aspect-ratio: 4/3)', {'aspect-ratio': '16 / 9'} 205 | )).to.be.true; 206 | }); 207 | 208 | it('should return false for an aspect-ratio higher than a max-aspect-ratio', function () { 209 | expect(mediaQuery.match( 210 | '(max-aspect-ratio: 4/3)', {'aspect-ratio': '16/9'} 211 | )).to.be.false; 212 | }); 213 | 214 | it('should return false if aspect-ratio isnt passed in', function () { 215 | expect(mediaQuery.match( 216 | '(max-aspect-ratio: 72dpi)', {width: 300} 217 | )).to.be.false; 218 | }); 219 | 220 | it('should work numbers', function () { 221 | expect(mediaQuery.match( 222 | '(min-aspect-ratio: 2560/1440)', {'aspect-ratio': 4 / 3} 223 | )).to.be.false; 224 | }); 225 | }); 226 | 227 | describe('Grid/Color/Color-Index/Monochrome', function () { 228 | it('should return true for a correct match', function () { 229 | expect(mediaQuery.match( 230 | '(grid)', {grid: 1} 231 | )).to.be.true; 232 | 233 | expect(mediaQuery.match( 234 | '(color)', {color: 1} 235 | )).to.be.true; 236 | 237 | expect(mediaQuery.match( 238 | '(color-index: 3)', {'color-index': 3} 239 | )).to.be.true; 240 | 241 | expect(mediaQuery.match( 242 | '(monochrome)', {monochrome: 1} 243 | )).to.be.true; 244 | }); 245 | 246 | it('should return false for an incorrect match', function () { 247 | expect(mediaQuery.match( 248 | '(grid)', {grid: 0} 249 | )).to.be.false; 250 | 251 | expect(mediaQuery.match( 252 | '(color)', {color: 0} 253 | )).to.be.false; 254 | 255 | expect(mediaQuery.match( 256 | '(color-index: 3)', {'color-index': 2} 257 | )).to.be.false; 258 | 259 | expect(mediaQuery.match( 260 | '(monochrome)', {monochrome: 0} 261 | )).to.be.false; 262 | 263 | expect(mediaQuery.match( 264 | '(monochrome)', {monochrome: 'foo'} 265 | )).to.be.false; 266 | }); 267 | }); 268 | 269 | describe('Type', function () { 270 | it('should return true for a correct match', function () { 271 | expect(mediaQuery.match( 272 | 'screen', {type: 'screen'} 273 | )).to.be.true; 274 | }); 275 | 276 | it('should return false for an incorrect match', function () { 277 | expect(mediaQuery.match( 278 | 'screen and (color:1)', { 279 | type : 'tv', 280 | color: 1 281 | } 282 | )).to.be.false; 283 | }); 284 | 285 | it('should return false for a media query without a type when type is specified in the value object', function () { 286 | expect(mediaQuery.match( 287 | '(min-width: 500px)', {type: 'screen'} 288 | )).to.be.false; 289 | }); 290 | 291 | it('should return true for a media query without a type when type is not specified in the value object', function () { 292 | expect(mediaQuery.match( 293 | '(min-width: 500px)', {width: 700} 294 | )).to.be.true; 295 | }); 296 | }); 297 | 298 | describe('Not', function () { 299 | it('should return false when theres a match on a `not` query', function () { 300 | expect(mediaQuery.match( 301 | 'not screen and (color)', { 302 | type : 'screen', 303 | color: 1 304 | } 305 | )).to.be.false; 306 | }); 307 | 308 | it('should not disrupt an OR query', function () { 309 | expect(mediaQuery.match( 310 | 'not screen and (color), screen and (min-height: 48em)', { 311 | type : 'screen', 312 | height: 1000 313 | } 314 | )).to.be.true; 315 | }); 316 | 317 | it('should return false for when type === all', function () { 318 | expect(mediaQuery.match( 319 | 'not all and (min-width: 48em)', { 320 | type : 'all', 321 | width: 1000 322 | } 323 | )).to.be.false; 324 | }); 325 | 326 | it('should return true for inverted value', function () { 327 | expect(mediaQuery.match( 328 | 'not screen and (min-width: 48em)', {width: '24em'} 329 | )).to.be.true; 330 | }); 331 | }); 332 | 333 | describe('mediaQuery.match() Integration Tests', function () { 334 | describe('Real World Use Cases (mostly AND)', function () { 335 | it('should return true because of width and type match', function () { 336 | expect(mediaQuery.match( 337 | 'screen and (min-width: 767px)', { 338 | type : 'screen', 339 | width: 980 340 | } 341 | )).to.be.true; 342 | }); 343 | 344 | it('should return true because of width is within bounds', function () { 345 | expect(mediaQuery.match( 346 | 'screen and (min-width: 767px) and (max-width: 979px)', { 347 | type : 'screen', 348 | width: 800 349 | } 350 | )).to.be.true; 351 | }); 352 | 353 | it('should return false because width is out of bounds', function () { 354 | expect(mediaQuery.match( 355 | 'screen and (min-width: 767px) and (max-width: 979px)', { 356 | type : 'screen', 357 | width: 980 358 | } 359 | )).to.be.false; 360 | }); 361 | 362 | it('should return false since monochrome is not specified', function () { 363 | expect(mediaQuery.match( 364 | 'screen and (monochrome)', {width: 980} 365 | )).to.be.false; 366 | }); 367 | 368 | it('should return true since color > 0', function () { 369 | expect(mediaQuery.match( 370 | 'screen and (color)', { 371 | type : 'screen', 372 | color: 1 373 | } 374 | )).to.be.true; 375 | }); 376 | 377 | it('should return false since color = 0', function () { 378 | expect(mediaQuery.match( 379 | 'screen and (color)', { 380 | type : 'screen', 381 | color: 0 382 | } 383 | )).to.be.false; 384 | }); 385 | }); 386 | 387 | describe('Grouped Media Queries (OR)', function () { 388 | it('should return true because of color', function () { 389 | expect(mediaQuery.match( 390 | 'screen and (min-width: 767px), screen and (color)', { 391 | type : 'screen', 392 | color: 1 393 | } 394 | )).to.be.true; 395 | }); 396 | 397 | it('should return true because of width and type', function () { 398 | expect(mediaQuery.match( 399 | 'screen and (max-width: 1200px), handheld and (monochrome)', { 400 | type : 'screen', 401 | width: 1100 402 | } 403 | )).to.be.true; 404 | }); 405 | 406 | it('should return false because of monochrome mis-match', function () { 407 | expect(mediaQuery.match( 408 | 'screen and (max-width: 1200px), handheld and (monochrome)', { 409 | type : 'screen', 410 | monochrome: 0 411 | } 412 | )).to.be.false; 413 | }); 414 | }); 415 | }); 416 | }); 417 | 418 | --------------------------------------------------------------------------------