From 2337dab8feb4641c2675522927ed5777f5d14e36 Mon Sep 17 00:00:00 2001 From: rtrufin Date: Wed, 1 Jun 2016 11:41:01 +0300 Subject: [PATCH 01/15] Support for mixin nested selectors & multiple values for same property Test for Mixins that Nest Selectors #13. Fixed issue with properties that have fallback. E.g.: padding: 16px; padding: 1rem; --- src/mixinResult.js | 17 ++++++++++++++++ src/parsers.js | 49 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/mixinResult.js b/src/mixinResult.js index 97ce09a..a3bf820 100644 --- a/src/mixinResult.js +++ b/src/mixinResult.js @@ -123,6 +123,23 @@ MixinResult.prototype = { assert.equal(declarationValue, value.toString(), message); }, + declaresProperties: function(property, value) { + var declarations = parsers.findDeclarations(this.ast, property); + var declarationValues = []; + declarations.forEach(function(declaration){ + declarationValues.push(declaration.value); + }); + var message = 'Value: ' + declarationValues + ' does not equal value: ' + value + '.'; + assert.equal(declarationValues.toString(), value.toString(), message); + }, + + declaresInSelector: function(selector, property, value) { + var declaration = parsers.findDeclarationInSelector(this.ast, selector, property); + var declarationValue = declaration ? utilities.scrubQuotes(declaration.value) : ''; + var message = 'In Selector:'+ selector + ' the value: ' + declarationValue + ' does not equal value: ' + value + '.'; + assert.equal(declarationValue, value.toString(), message); + }, + doesNotDeclare: function(property, value) { var declaration = parsers.findDeclaration(this.ast, property); var declarationValue = declaration ? utilities.scrubQuotes(declaration.value) : ''; diff --git a/src/parsers.js b/src/parsers.js index c88971e..1981a0c 100644 --- a/src/parsers.js +++ b/src/parsers.js @@ -23,7 +23,6 @@ function hasSelectorValue(rule, selectorValue) { function findDeclarationProperty(rule, declarationProperty) { var foundDeclaration; - if (rule.declarations) { rule.declarations.forEach(function(declaration) { if (declaration.property === declarationProperty) { @@ -31,10 +30,21 @@ function findDeclarationProperty(rule, declarationProperty) { } }); } - return foundDeclaration; } +function findDeclarationsProperties(rule, declarationProperty) { + var foundDeclarations = []; + if (rule.declarations) { + rule.declarations.forEach(function(declaration) { + if (declaration.property === declarationProperty) { + foundDeclarations.push(declaration); + } + }); + } + return foundDeclarations; +} + function isFontFace(rule) { if (rule.type === 'font-face') { return true; @@ -57,10 +67,8 @@ var Parsers = { }); return count; }, - findDeclaration: function(ast, property) { var found; - ast.stylesheet.rules.forEach(function(rule) { if (rule.type === 'media') { rule.rules.forEach(function(rule) { @@ -74,6 +82,39 @@ var Parsers = { return found; }, + findDeclarations: function(ast, property) { + var found; + ast.stylesheet.rules.forEach(function(rule) { + if (rule.type === 'media') { + rule.rules.forEach(function(rule) { + found = found || findDeclarationsProperties(rule, property); + }); + } else { + found = found || findDeclarationsProperties(rule, property); + } + }); + + return found; + }, + + findDeclarationInSelector: function(ast, selector, property) { + var found; + if (selector.indexOf("&") > -1) { + selector = selector.replace("&", ".test"); + } + if (selector.indexOf("@at-root") > -1) { + selector = selector.replace("@at-root ", ""); + } + ast.stylesheet.rules.forEach(function(rule) { + for(var i = 0; i < rule.selectors.length; i++) { + if(rule.selectors[i].indexOf(selector) >= 0 ) { + found = found || findDeclarationProperty(rule, property); + } + } + }); + return found; + }, + findMedia: function(ast) { var found = []; From 688cae9196d091f322e423ff71f43c00484714a1 Mon Sep 17 00:00:00 2001 From: rtrufin Date: Wed, 1 Jun 2016 11:49:36 +0300 Subject: [PATCH 02/15] Update README.md --- README.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2600f43..d170a69 100644 --- a/README.md +++ b/README.md @@ -283,6 +283,28 @@ Assert that the mixin makes a declaration of the given rule-property pair. sassaby.includedMixin('appearance').calledWithArgs('button').declares('-webkit-appearance', 'button'); ``` +#### declaresInSelector +Assert that the mixin makes a declaration of the given rule-property pair inside the provided selector. +E.g. for the mixin: +``` +@mixin clearfix() { + &:before, + &:after { + content: " "; // 1 + display: table; // 2 + } + &:after { + clear: both; + } +} +``` +```js +sassaby.includedMixin('appearance').calledWithArgs('button').declaresInSelector(':before', 'display', 'table'); +sassaby.includedMixin('appearance').calledWithArgs('button').declaresInSelector(':before', 'display', 'table');; +sassaby.includedMixin('appearance').calledWithArgs('button').declaresInSelector(':before', 'display', 'table');; +sassaby.includedMixin('appearance').calledWithArgs('button').declaresInSelector(':before', 'display', 'table');; +``` + #### doesNotDeclare Assert that the mixin does not make a declaration of the given rule-property pair. ```js @@ -341,4 +363,4 @@ to cover it. Continuous Integration is handled by [Travis](https://travis-ci.org MIT © Ryan Bahniuk [ci]: https://travis-ci.org/ryanbahniuk/sassaby -[npm]: https://www.npmjs.com/package/sassaby \ No newline at end of file +[npm]: https://www.npmjs.com/package/sassaby From 779945fad8009d8360e54f36cd2c747ed7bca47f Mon Sep 17 00:00:00 2001 From: rtrufin Date: Wed, 1 Jun 2016 13:13:18 +0300 Subject: [PATCH 03/15] updated readme with the new functionality --- README.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d170a69..5f2a489 100644 --- a/README.md +++ b/README.md @@ -283,6 +283,19 @@ Assert that the mixin makes a declaration of the given rule-property pair. sassaby.includedMixin('appearance').calledWithArgs('button').declares('-webkit-appearance', 'button'); ``` +#### declaresProperties +Assert that the mixin makes a declaration of the given property with fallback values. +E.g. for the mixin: +``` +@mixin font-size($font-size: 1.6) { + font-size: $font-size * 16 + px; + font-size: $font-size + rem; +} +``` +```js +sassaby.includedMixin('font-size').calledWithArgs('2').declaresProperties('max-height', ['32px', '2rem']); +``` + #### declaresInSelector Assert that the mixin makes a declaration of the given rule-property pair inside the provided selector. E.g. for the mixin: @@ -299,10 +312,11 @@ E.g. for the mixin: } ``` ```js -sassaby.includedMixin('appearance').calledWithArgs('button').declaresInSelector(':before', 'display', 'table'); -sassaby.includedMixin('appearance').calledWithArgs('button').declaresInSelector(':before', 'display', 'table');; -sassaby.includedMixin('appearance').calledWithArgs('button').declaresInSelector(':before', 'display', 'table');; -sassaby.includedMixin('appearance').calledWithArgs('button').declaresInSelector(':before', 'display', 'table');; +sassaby.includedMixin('clearfix').called().declaresInSelector(':before', 'content', " "); +sassaby.includedMixin('clearfix').called().declaresInSelector(':before', 'display', 'table'); +sassaby.includedMixin('clearfix').called().declaresInSelector(':after', 'content', " "); +sassaby.includedMixin('clearfix').called().declaresInSelector(':after', 'display', 'table'); +sassaby.includedMixin('clearfix').called().declaresInSelector(':after', 'clear', 'both'); ``` #### doesNotDeclare From 30cd089620f2627c7652b44dd3f9048818f68e74 Mon Sep 17 00:00:00 2001 From: razvan Date: Thu, 19 Oct 2017 17:02:30 +0300 Subject: [PATCH 04/15] Resolved tests that were failing --- package.json | 15 +++++++-- src/sassaby.js | 83 +++++++++++++++++++++++++------------------------- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index f7f859b..affa5b5 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,15 @@ "name": "sassaby", "version": "2.1.1", "description": "A unit testing library for SASS", - "keywords": ["sass", "scss", "testing", "unit testing", "bdd", "tdd", "test"], + "keywords": [ + "sass", + "scss", + "testing", + "unit testing", + "bdd", + "tdd", + "test" + ], "author": "Ryan Bahniuk ", "license": "MIT", "repository": { @@ -14,13 +22,14 @@ "css": "^2.2.0", "cssmin": "^0.4.3", "mocha": "^2.2.5", - "node-sass": "^3.1.2" + "node-sass": "^3.1.2", + "normalize-path": "^2.1.1" }, "devDependencies": { "proxyquire": "^1.5.0", "sinon": "^1.14.1" }, "scripts": { - "test": "NODE_ENV=test mocha" + "test": "SET NODE_ENV=test & mocha" } } diff --git a/src/sassaby.js b/src/sassaby.js index 2f60025..221d696 100644 --- a/src/sassaby.js +++ b/src/sassaby.js @@ -5,66 +5,67 @@ var assert = require('assert'); var Mixin = require('./types/mixin'); var Func = require('./types/func'); var parsers = require('./parsers'); +var normalize = require('normalize-path'); function setVariables(varz) { - var sassVariables = ''; - for (var variableName in varz) { - sassVariables = sassVariables + '$' + variableName + ':' + varz[variableName] + ';'; - } - return sassVariables; + var sassVariables = ''; + for (var variableName in varz) { + sassVariables = sassVariables + '$' + variableName + ':' + varz[variableName] + ';'; + } + return sassVariables; } function setDependencies(dependencies) { - var sassImports = ''; - dependencies.forEach(function(fileName) { - sassImports = sassImports + "@import '" + fileName + "';"; - }); - return sassImports; + var sassImports = ''; + dependencies.forEach(function(fileName) { + sassImports = sassImports + "@import '" + normalize(fileName) + "';"; + }); + return sassImports; } function Sassaby(path, options) { - options = options || {}; - this.path = path; - this.file = fs.readFileSync(path).toString(); - this.variables = ''; - this.dependencies = ''; + options = options || {}; + this.path = path; + this.file = fs.readFileSync(normalize(path), 'utf-8').toString(); + this.variables = ''; + this.dependencies = ''; - if (options.variables) { - this.variables = setVariables(options.variables); - } + if (options.variables) { + this.variables = setVariables(options.variables); + } - if (options.dependencies) { - this.dependencies = setDependencies(options.dependencies); - } + if (options.dependencies) { + this.dependencies = setDependencies(options.dependencies); + } } Sassaby.prototype = { - imports: function(name) { - var message = 'Could not find an import statement with ' + name + ' in file.'; - assert(parsers.hasImport(this.file, name), message); - }, + imports: function(name) { + var message = 'Could not find an import statement with ' + name + ' in file.'; + assert(parsers.hasImport(this.file, name), message); + }, - doesNotImport: function(name) { - var message = 'Found an import statement with ' + name + ' in file.'; - assert(!parsers.hasImport(this.file, name), message); - }, + doesNotImport: function(name) { + var message = 'Found an import statement with ' + name + ' in file.'; + assert(!parsers.hasImport(this.file, name), message); + }, - includedMixin: function(call) { - return new Mixin('included', this.variables, this.dependencies, this.file, call); - }, + includedMixin: function(call) { + return new Mixin('included', this.variables, this.dependencies, this.file, call); + }, - standaloneMixin: function(call) { - return new Mixin('standalone', this.variables, this.dependencies, this.file, call); - }, + standaloneMixin: function(call) { + return new Mixin('standalone', this.variables, this.dependencies, this.file, call); + }, - func: function(call) { - return new Func(this.variables, this.dependencies, this.file, call); - } + func: function(call) { + return new Func(this.variables, this.dependencies, this.file, call); + } }; if (process.env.NODE_ENV === 'test') { - Sassaby.setVariables = setVariables; - Sassaby.setDependencies = setDependencies; + Sassaby.setVariables = setVariables; + Sassaby.setDependencies = setDependencies; } -module.exports = Sassaby; +module.exports = Sassaby; \ No newline at end of file From 1fecc49e00f613ee7436187d6e698118309bb2cf Mon Sep 17 00:00:00 2001 From: razvan Date: Fri, 20 Oct 2017 10:05:51 +0300 Subject: [PATCH 05/15] Locked node sass version to 3.1.2 --- package.json | 68 ++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index affa5b5..9ec239a 100644 --- a/package.json +++ b/package.json @@ -1,35 +1,35 @@ { - "name": "sassaby", - "version": "2.1.1", - "description": "A unit testing library for SASS", - "keywords": [ - "sass", - "scss", - "testing", - "unit testing", - "bdd", - "tdd", - "test" - ], - "author": "Ryan Bahniuk ", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/ryanbahniuk/sassaby" - }, - "main": "src/sassaby", - "dependencies": { - "css": "^2.2.0", - "cssmin": "^0.4.3", - "mocha": "^2.2.5", - "node-sass": "^3.1.2", - "normalize-path": "^2.1.1" - }, - "devDependencies": { - "proxyquire": "^1.5.0", - "sinon": "^1.14.1" - }, - "scripts": { - "test": "SET NODE_ENV=test & mocha" - } -} + "name": "sassaby", + "version": "2.1.1", + "description": "A unit testing library for SASS", + "keywords": [ + "sass", + "scss", + "testing", + "unit testing", + "bdd", + "tdd", + "test" + ], + "author": "Ryan Bahniuk ", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/ryanbahniuk/sassaby" + }, + "main": "src/sassaby", + "dependencies": { + "css": "^2.2.0", + "cssmin": "^0.4.3", + "mocha": "^2.2.5", + "node-sass": "3.1.2", + "normalize-path": "^2.1.1" + }, + "devDependencies": { + "proxyquire": "^1.5.0", + "sinon": "^1.14.1" + }, + "scripts": { + "test": "SET NODE_ENV=test & mocha" + } +} \ No newline at end of file From 5a685b070542902dd57dc3aab6ba22f2693060e0 Mon Sep 17 00:00:00 2001 From: razvan Date: Fri, 20 Oct 2017 10:08:27 +0300 Subject: [PATCH 06/15] Locked node sass version to 2.81.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9ec239a..ee79a53 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "css": "^2.2.0", "cssmin": "^0.4.3", "mocha": "^2.2.5", - "node-sass": "3.1.2", + "node-sass": "2.81.0", "normalize-path": "^2.1.1" }, "devDependencies": { From c4c7ef61769d325c9a3437cf58b2c07c4fe80028 Mon Sep 17 00:00:00 2001 From: razvan Date: Fri, 20 Oct 2017 10:13:43 +0300 Subject: [PATCH 07/15] Locked node sass version to 2.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ee79a53..c013ad8 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "css": "^2.2.0", "cssmin": "^0.4.3", "mocha": "^2.2.5", - "node-sass": "2.81.0", + "node-sass": "2.0.1", "normalize-path": "^2.1.1" }, "devDependencies": { From 9d4e6ff884235987805e8f1f37804a50267856be Mon Sep 17 00:00:00 2001 From: razvan Date: Fri, 20 Oct 2017 10:54:03 +0300 Subject: [PATCH 08/15] Added request 2.81.0 module as a possible fix for node-sass issue --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index c013ad8..1bc8aa6 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "cssmin": "^0.4.3", "mocha": "^2.2.5", "node-sass": "2.0.1", + "request": "2.81.0", "normalize-path": "^2.1.1" }, "devDependencies": { From 6449a88ef15e46b9635e2dbfa0496f444e368745 Mon Sep 17 00:00:00 2001 From: razvan Date: Fri, 20 Oct 2017 11:07:31 +0300 Subject: [PATCH 09/15] Added cross env to handle the set of the node_env environment variable --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1bc8aa6..a0d0ffa 100644 --- a/package.json +++ b/package.json @@ -27,10 +27,11 @@ "normalize-path": "^2.1.1" }, "devDependencies": { + "cross-env": "^5.1.0", "proxyquire": "^1.5.0", "sinon": "^1.14.1" }, "scripts": { - "test": "SET NODE_ENV=test & mocha" + "test": "cross-env NODE_ENV=test & mocha" } } \ No newline at end of file From fd20a6863b2aab9ef24511752f7affdd5372ab70 Mon Sep 17 00:00:00 2001 From: razvan Date: Fri, 20 Oct 2017 11:11:23 +0300 Subject: [PATCH 10/15] Added node_env value in travis config file --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 04f6d65..2df9852 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,6 @@ sudo: false language: node_js node_js: - "0.12" - - "0.10" \ No newline at end of file + - "0.10" +env: + - NODE_ENV=test \ No newline at end of file From 26029fc93ee0ec4d7f76f29939bc353734254c15 Mon Sep 17 00:00:00 2001 From: razvan Date: Fri, 20 Oct 2017 11:15:03 +0300 Subject: [PATCH 11/15] Added more node js versions to test --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2df9852..d395657 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,9 @@ sudo: false language: node_js node_js: + - "6.11.4" + - "5.12.0" + - "4.8.4" - "0.12" - "0.10" env: From a3ce2269753803e748c57b334cffb0d4a2063419 Mon Sep 17 00:00:00 2001 From: rtrufin <7871937+rtrufin@users.noreply.github.com> Date: Wed, 25 Oct 2017 09:49:41 +0300 Subject: [PATCH 12/15] Fixed indentation --- src/sassaby.js | 82 +++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/sassaby.js b/src/sassaby.js index 221d696..52d9638 100644 --- a/src/sassaby.js +++ b/src/sassaby.js @@ -8,64 +8,64 @@ var parsers = require('./parsers'); var normalize = require('normalize-path'); function setVariables(varz) { - var sassVariables = ''; - for (var variableName in varz) { - sassVariables = sassVariables + '$' + variableName + ':' + varz[variableName] + ';'; - } - return sassVariables; + var sassVariables = ''; + for (var variableName in varz) { + sassVariables = sassVariables + '$' + variableName + ':' + varz[variableName] + ';'; + } + return sassVariables; } function setDependencies(dependencies) { - var sassImports = ''; - dependencies.forEach(function(fileName) { - sassImports = sassImports + "@import '" + normalize(fileName) + "';"; - }); - return sassImports; + var sassImports = ''; + dependencies.forEach(function(fileName) { + sassImports = sassImports + "@import '" + normalize(fileName) + "';"; + }); + return sassImports; } function Sassaby(path, options) { - options = options || {}; - this.path = path; - this.file = fs.readFileSync(normalize(path), 'utf-8').toString(); - this.variables = ''; - this.dependencies = ''; + options = options || {}; + this.path = path; + this.file = fs.readFileSync(normalize(path), 'utf-8').toString(); + this.variables = ''; + this.dependencies = ''; - if (options.variables) { - this.variables = setVariables(options.variables); - } + if (options.variables) { + this.variables = setVariables(options.variables); + } - if (options.dependencies) { - this.dependencies = setDependencies(options.dependencies); - } + if (options.dependencies) { + this.dependencies = setDependencies(options.dependencies); + } } Sassaby.prototype = { - imports: function(name) { - var message = 'Could not find an import statement with ' + name + ' in file.'; - assert(parsers.hasImport(this.file, name), message); - }, + imports: function(name) { + var message = 'Could not find an import statement with ' + name + ' in file.'; + assert(parsers.hasImport(this.file, name), message); + }, - doesNotImport: function(name) { - var message = 'Found an import statement with ' + name + ' in file.'; - assert(!parsers.hasImport(this.file, name), message); - }, + doesNotImport: function(name) { + var message = 'Found an import statement with ' + name + ' in file.'; + assert(!parsers.hasImport(this.file, name), message); + }, - includedMixin: function(call) { - return new Mixin('included', this.variables, this.dependencies, this.file, call); - }, + includedMixin: function(call) { + return new Mixin('included', this.variables, this.dependencies, this.file, call); + }, - standaloneMixin: function(call) { - return new Mixin('standalone', this.variables, this.dependencies, this.file, call); - }, + standaloneMixin: function(call) { + return new Mixin('standalone', this.variables, this.dependencies, this.file, call); + }, - func: function(call) { - return new Func(this.variables, this.dependencies, this.file, call); - } + func: function(call) { + return new Func(this.variables, this.dependencies, this.file, call); + } }; if (process.env.NODE_ENV === 'test') { - Sassaby.setVariables = setVariables; - Sassaby.setDependencies = setDependencies; + Sassaby.setVariables = setVariables; + Sassaby.setDependencies = setDependencies; } -module.exports = Sassaby; \ No newline at end of file +module.exports = Sassaby; From b14a0274710208b0a8b628f246a2c585bd724480 Mon Sep 17 00:00:00 2001 From: razvan Date: Wed, 25 Oct 2017 21:06:27 +0300 Subject: [PATCH 13/15] Fixed functionality & added unit tests to cover all the implementation --- .gitignore | 1 + README.md | 2 +- src/mixinResult.js | 25 ++-- src/parsers.js | 20 ++- test/fixtures/ast.json | 65 ++++++++- test/fixtures/astMediaQuery.json | 34 ++++- test/fixtures/sample.scss | 10 ++ test/integrationTests.js | 19 +++ test/integrationTestsWithBlocks.js | 2 +- test/parsersTests.js | 224 ++++++++++++++++++++++------- 10 files changed, 324 insertions(+), 78 deletions(-) diff --git a/.gitignore b/.gitignore index 3c3629e..55371e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +.vscode \ No newline at end of file diff --git a/README.md b/README.md index f62e7da..2839b76 100644 --- a/README.md +++ b/README.md @@ -343,7 +343,7 @@ E.g. for the mixin: } ``` ```js -sassaby.includedMixin('font-size').calledWithArgs('2').declaresProperties('max-height', ['32px', '2rem']); +sassaby.includedMixin('font-size').calledWithArgs('2').declares('max-height', ['32px', '2rem']); ``` #### declaresInSelector diff --git a/src/mixinResult.js b/src/mixinResult.js index a3bf820..ab2ae4f 100644 --- a/src/mixinResult.js +++ b/src/mixinResult.js @@ -117,20 +117,19 @@ MixinResult.prototype = { }, declares: function(property, value) { - var declaration = parsers.findDeclaration(this.ast, property); - var declarationValue = declaration ? utilities.scrubQuotes(declaration.value) : ''; + var declaration, declarationValue; + if (Array.isArray(value) && value.length > 1) { + declaration = parsers.findDeclarations(this.ast, property); + declarationValue = []; + declaration.forEach(function(declaration){ + declarationValue.push(declaration.value); + }); + } else { + declaration = parsers.findDeclaration(this.ast, property); + declarationValue = declaration ? utilities.scrubQuotes(declaration.value) : ''; + } var message = 'Value: ' + declarationValue + ' does not equal value: ' + value + '.'; - assert.equal(declarationValue, value.toString(), message); - }, - - declaresProperties: function(property, value) { - var declarations = parsers.findDeclarations(this.ast, property); - var declarationValues = []; - declarations.forEach(function(declaration){ - declarationValues.push(declaration.value); - }); - var message = 'Value: ' + declarationValues + ' does not equal value: ' + value + '.'; - assert.equal(declarationValues.toString(), value.toString(), message); + assert.equal(declarationValue.toString(), value.toString(), message); }, declaresInSelector: function(selector, property, value) { diff --git a/src/parsers.js b/src/parsers.js index 1981a0c..5b53f66 100644 --- a/src/parsers.js +++ b/src/parsers.js @@ -83,18 +83,23 @@ var Parsers = { }, findDeclarations: function(ast, property) { - var found; + var found = []; ast.stylesheet.rules.forEach(function(rule) { if (rule.type === 'media') { rule.rules.forEach(function(rule) { - found = found || findDeclarationsProperties(rule, property); + found.push(findDeclarationsProperties(rule, property)); }); } else { - found = found || findDeclarationsProperties(rule, property); + found.push(findDeclarationsProperties(rule, property)); } }); - - return found; + var declarationsArray; + found.forEach(function(value) { + if(value.length !== 0) { + declarationsArray = value; + } + }) + return declarationsArray; }, findDeclarationInSelector: function(ast, selector, property) { @@ -107,11 +112,12 @@ var Parsers = { } ast.stylesheet.rules.forEach(function(rule) { for(var i = 0; i < rule.selectors.length; i++) { - if(rule.selectors[i].indexOf(selector) >= 0 ) { - found = found || findDeclarationProperty(rule, property); + if(rule.selectors[i].indexOf(selector) >= 0 ) { + found = found || findDeclarationProperty(rule, property); } } }); + console.log(found); return found; }, diff --git a/test/fixtures/ast.json b/test/fixtures/ast.json index 11fd863..f76ad35 100644 --- a/test/fixtures/ast.json +++ b/test/fixtures/ast.json @@ -86,6 +86,69 @@ "column": 18 } } + }, + { + "type": "declaration", + "property": "max-height", + "value": "16px", + "position": { + "start": { + "line": 9, + "column": 3 + }, + "end": { + "line": 9, + "column": 18 + } + } + }, + { + "type": "declaration", + "property": "max-height", + "value": "1rem", + "position": { + "start": { + "line": 10, + "column": 3 + }, + "end": { + "line": 10, + "column": 18 + } + } + } + ], + "position": { + "start": { + "line": 11, + "column": 1 + }, + "end": { + "line": 13, + "column": 2 + } + } + }, + { + "type": "rule", + "selectors": [ + ".test.testInSelector" + ], + "declarations": [ + { + "type": "declaration", + "property": "color", + "value": "red", + "position": { + "start": { + "line": 11, + "column": 3 + }, + "end": { + "line": 11, + "column": 13 + } + } } ], "position": { @@ -94,7 +157,7 @@ "column": 1 }, "end": { - "line": 9, + "line": 14, "column": 2 } } diff --git a/test/fixtures/astMediaQuery.json b/test/fixtures/astMediaQuery.json index 22453c4..89106b5 100644 --- a/test/fixtures/astMediaQuery.json +++ b/test/fixtures/astMediaQuery.json @@ -41,6 +41,36 @@ "column": 20 } } + }, + { + "type": "declaration", + "property": "max-height", + "value": "16px", + "position": { + "start": { + "line": 5, + "column": 3 + }, + "end": { + "line": 5, + "column": 18 + } + } + }, + { + "type": "declaration", + "property": "max-height", + "value": "1rem", + "position": { + "start": { + "line": 6, + "column": 3 + }, + "end": { + "line": 6, + "column": 18 + } + } } ], "position": { @@ -49,7 +79,7 @@ "column": 3 }, "end": { - "line": 5, + "line": 7, "column": 4 } } @@ -61,7 +91,7 @@ "column": 1 }, "end": { - "line": 6, + "line": 8, "column": 2 } } diff --git a/test/fixtures/sample.scss b/test/fixtures/sample.scss index 0d8ecbd..24d1da8 100644 --- a/test/fixtures/sample.scss +++ b/test/fixtures/sample.scss @@ -94,3 +94,13 @@ } } +@mixin fallback-font-size { + font-size: 16px; + font-size: 1rem; +} + +@mixin hover-link { + &:hover { + text-transform: none; + } +} diff --git a/test/integrationTests.js b/test/integrationTests.js index ad820c5..d47576c 100644 --- a/test/integrationTests.js +++ b/test/integrationTests.js @@ -218,4 +218,23 @@ describe('sample.scss', function() { mixin.called().calls('create-header'); }); }); + describe('fallback-font-size', function() { + beforeEach(function() { + mixin = sassaby.includedMixin('fallback-font-size'); + }); + + it('should have the correct color declaration', function() { + mixin.called().declares('font-size', ['16px', '1rem']); + }); + }); + + describe('hover-link', function() { + beforeEach(function() { + mixin = sassaby.includedMixin('hover-link'); + }); + + it('should have the correct color declaration', function() { + mixin.called().declaresInSelector('&:hover', 'text-transform', 'none'); + }); + }) }); diff --git a/test/integrationTestsWithBlocks.js b/test/integrationTestsWithBlocks.js index 3fc8ee8..63fc45c 100644 --- a/test/integrationTestsWithBlocks.js +++ b/test/integrationTestsWithBlocks.js @@ -126,4 +126,4 @@ describe('sample-with-blocks.scss', function() { mixin.calledWithBlockAndArgs(block, color).declares('width', '100%'); }); }); -}); +}); \ No newline at end of file diff --git a/test/parsersTests.js b/test/parsersTests.js index 130b318..7598ce1 100644 --- a/test/parsersTests.js +++ b/test/parsersTests.js @@ -8,9 +8,9 @@ var astNoSelectors = require('./fixtures/astNoSelectors.json'); var astMediaQuery = require('./fixtures/astMediaQuery.json'); var astMediaQueryFontFace = require('./fixtures/astMediaQueryFontFace.json'); -describe('Parsers', function() { - describe('escapeCharacters', function() { - it('should escape all special characters that can be used in a filename', function() { +describe('Parsers', function () { + describe('escapeCharacters', function () { + it('should escape all special characters that can be used in a filename', function () { assert.equal(parsers.escapeCharacters('test/this'), 'test\/this'); assert.equal(parsers.escapeCharacters('test.this'), 'test\.this'); assert.equal(parsers.escapeCharacters('test*this'), 'test\*this'); @@ -22,28 +22,28 @@ describe('Parsers', function() { }); }); - describe('hasSelectorValue', function() { + describe('hasSelectorValue', function () { var ruleWithoutSelectors = {}; var rule = { type: 'rule', selectors: ['.test', '.second'] }; - it('should return true if the selector is in the rule', function() { + it('should return true if the selector is in the rule', function () { assert(parsers.hasSelectorValue(rule, '.test')); assert(parsers.hasSelectorValue(rule, '.second')); }); - it('should return false if the selector is not in the rule', function() { + it('should return false if the selector is not in the rule', function () { assert(!parsers.hasSelectorValue(rule, '.blah')); }); - it('should return false if the rule has no selectors', function() { + it('should return false if the rule has no selectors', function () { assert(!parsers.hasSelectorValue(ruleWithoutSelectors, '.test')); }); }); - describe('findDeclarationProperty', function() { + describe('findDeclarationProperty', function () { var declaration = { 'type': 'declaration', 'property': 'color' @@ -63,20 +63,20 @@ describe('Parsers', function() { declarations: [declaration] }; - it('should return the declaration if it is in the rule', function() { + it('should return the declaration if it is in the rule', function () { assert.equal(parsers.findDeclarationProperty(rule, 'color'), declaration); }); - it('should return undefined if the declaration is not in the rule', function() { + it('should return undefined if the declaration is not in the rule', function () { assert.equal(parsers.findDeclarationProperty(ruleWithoutDeclaration, 'color'), undefined); }); - it('should return undefined if the rule has no declarations', function() { + it('should return undefined if the rule has no declarations', function () { assert.equal(parsers.findDeclarationProperty(ruleWithoutDeclarations, 'color'), undefined); }); }); - describe('isFontFace', function() { + describe('isFontFace', function () { var font = { type: 'font-face' }; @@ -85,27 +85,35 @@ describe('Parsers', function() { type: 'media' }; - it('should return true if the rule is a font-face type', function() { + it('should return true if the rule is a font-face type', function () { assert(parsers.isFontFace(font)); }); - it('should return false if the rule is not a font-face type', function() { + it('should return false if the rule is not a font-face type', function () { assert(!parsers.isFontFace(media)); }); }); - describe('countDeclarations', function() { - it('should return the number of declarations in output', function() { - assert.equal(parsers.countDeclarations(ast), 4); + describe('countDeclarations', function () { + it('should return the number of declarations in output', function () { + assert.equal(parsers.countDeclarations(ast), 7); }); - it('should return 0 if there are no declarations', function() { - assert.equal(parsers.countDeclarations({stylesheet: {rules: [{declarations: []}]}}), 0); + it('should return 0 if there are no declarations', function () { + assert.equal(parsers.countDeclarations({ + stylesheet: { + rules: [ + { + declarations: [] + } + ] + } + }), 0); }); }); - describe('findDeclaration', function() { - it('should return the declaration object if the property is found', function() { + describe('findDeclaration', function () { + it('should return the declaration object if the property is found', function () { var declaration = { 'type': 'declaration', 'property': 'background-color', @@ -124,7 +132,7 @@ describe('Parsers', function() { assert.deepEqual(parsers.findDeclaration(ast, 'background-color'), declaration); }); - it('should return the first declaration object if two of the property are found', function() { + it('should return the first declaration object if two of the property are found', function () { var declaration = { 'type': 'declaration', 'property': 'color', @@ -143,134 +151,244 @@ describe('Parsers', function() { assert.deepEqual(parsers.findDeclaration(ast, 'color'), declaration); }); - it('should return undefined if the declaration is not found', function() { + it('should return undefined if the declaration is not found', function () { assert.equal(parsers.findDeclaration(ast, 'display'), undefined); }); }); + describe('findDeclarations', function () { + it('should return the declaration object array if the property is found', function () { + var declaration = [ + { + "type": "declaration", + "property": "max-height", + "value": "16px", + "position": { + "start": { + "line": 9, + "column": 3 + }, + "end": { + "line": 9, + "column": 18 + } + } + }, { + "type": "declaration", + "property": "max-height", + "value": "1rem", + "position": { + "start": { + "line": 10, + "column": 3 + }, + "end": { + "line": 10, + "column": 18 + } + } + } + ]; + assert.deepEqual(parsers.findDeclarations(ast, 'max-height'), declaration); + }); + it('should return the declaration object array if the property is found inside a media query', function() { + var declaration = [ + { + "type": "declaration", + "property": "max-height", + "value": "16px", + "position": { + "start": { + "line": 5, + "column": 3 + }, + "end": { + "line": 5, + "column": 18 + } + } + }, { + "type": "declaration", + "property": "max-height", + "value": "1rem", + "position": { + "start": { + "line": 6, + "column": 3 + }, + "end": { + "line": 6, + "column": 18 + } + } + } + ]; + assert.deepEqual(parsers.findDeclarations(astMediaQuery, 'max-height'), declaration); + }) + }); + + describe('findDeclarationInSelector', function() { + it('should return the declaration Object found in the specified selector when @at-root is being used', function () { + var declaration = { + 'type': 'declaration', + 'property': 'color', + 'value': 'red', + 'position': { + 'start': { + 'line': 11, + 'column': 3 + }, + 'end': { + 'line': 11, + 'column': 13 + } + } + }; + assert.deepEqual(parsers.findDeclarationInSelector(ast, '@at-root .testInSelector', 'color'), declaration); + }) + + it('should return the declaration Object found in the specified selector when & selector is used', function () { + var declaration = { + 'type': 'declaration', + 'property': 'color', + 'value': 'red', + 'position': { + 'start': { + 'line': 11, + 'column': 3 + }, + 'end': { + 'line': 11, + 'column': 13 + } + } + }; + assert.deepEqual(parsers.findDeclarationInSelector(ast, '&.testInSelector', 'color'), declaration); + }) + }); - describe('findMedia', function() { - it('should return the first rule of the type media', function() { + describe('findMedia', function () { + it('should return the first rule of the type media', function () { var media = parsers.findMedia(astMediaQuery); assert.equal(media.type, 'media'); assert.equal(media.media, 'screen and (min-width: 600px)'); }); - it('should return undefined if there are no rules of the type media', function() { + it('should return undefined if there are no rules of the type media', function () { var media = parsers.findMedia(ast); assert.deepEqual(media, undefined); }); }); - describe('hasSelector', function() { - it('should return true if the selector is defined by itself', function() { + describe('hasSelector', function () { + it('should return true if the selector is defined by itself', function () { assert(parsers.hasSelector(ast, '.test')); }); - it('should return true if the selector is defined in a list', function() { + it('should return true if the selector is defined in a list', function () { assert(parsers.hasSelector(ast, '.hello')); assert(parsers.hasSelector(ast, '.blah')); }); - it('should return true if the selector is defined in a media query', function() { + it('should return true if the selector is defined in a media query', function () { assert(parsers.hasSelector(astMediaQuery, 'body')); }); - it('should return false if the selector not defined', function() { + it('should return false if the selector not defined', function () { assert(!parsers.hasSelector(ast, '.not-defined')); }); - it('should return false if no stylesheet is defined', function() { + it('should return false if no stylesheet is defined', function () { assert(!parsers.hasSelector(astNoSelectors, '.test')); }); - it('should return false if no rules are defined', function() { + it('should return false if no rules are defined', function () { assert(!parsers.hasSelector(astNoSelectors, '.test')); }); }); - describe('hasFontFace', function() { - it('should return true if font-face is defined', function() { + describe('hasFontFace', function () { + it('should return true if font-face is defined', function () { assert(parsers.hasFontFace(astNoSelectors)); }); - it('should return true if font-face is defined inside a media query', function() { + it('should return true if font-face is defined inside a media query', function () { assert(parsers.hasFontFace(astMediaQueryFontFace)); }); - it('should return false if font-face not defined', function() { + it('should return false if font-face not defined', function () { assert(!parsers.hasFontFace(ast)); }); }); - describe('hasImport', function() { + describe('hasImport', function () { var name = 'test'; - context('should return true if the import exists', function() { - it('if it uses single quotes', function() { + context('should return true if the import exists', function () { + it('if it uses single quotes', function () { var sass = "@import '" + name + "';"; assert(parsers.hasImport(sass, name)); }); - it('if it is nested in a directory', function() { + it('if it is nested in a directory', function () { var sass = "@import 'testing/" + name + "';"; assert(parsers.hasImport(sass, 'testing/' + name)); }); - it('if it uses double quotes', function() { + it('if it uses double quotes', function () { var sass = '@import "' + name + '";'; assert(parsers.hasImport(sass, name)); }); - it('if it has no space', function() { + it('if it has no space', function () { var sass = '@import"' + name + '";'; assert(parsers.hasImport(sass, name)); }); - it('if it has multiple on the same line', function() { + it('if it has multiple on the same line', function () { var sass = '@import "hello"; @import"' + name + '";'; assert(parsers.hasImport(sass, name)); }); - it('if it has multiple on different lines', function() { + it('if it has multiple on different lines', function () { var sass = '@import "hello";\n@import"' + name + '";'; assert(parsers.hasImport(sass, name)); }); - it('if it has multiple in a comma separated list', function() { + it('if it has multiple in a comma separated list', function () { var sass = '@import "hello", "' + name + '";'; assert(parsers.hasImport(sass, name)); }); }); - context('should return false if the import does not exist', function() { + context('should return false if the import does not exist', function () { var alternate = 'nope'; - it('if it uses single quotes', function() { + it('if it uses single quotes', function () { var sass = "@import '" + alternate + "';"; assert(!parsers.hasImport(sass, name)); }); - it('if it uses double quotes', function() { + it('if it uses double quotes', function () { var sass = '@import "' + alternate + '";'; assert(!parsers.hasImport(sass, name)); }); - it('if it has no space', function() { + it('if it has no space', function () { var sass = '@import"' + alternate + '";'; assert(!parsers.hasImport(sass, name)); }); - it('if it has multiple on the same line', function() { + it('if it has multiple on the same line', function () { var sass = '@import "hello"; @import"' + alternate + '";'; assert(!parsers.hasImport(sass, name)); }); - it('if it has multiple on different lines', function() { + it('if it has multiple on different lines', function () { var sass = '@import "hello";\n@import"' + alternate + '";'; assert(!parsers.hasImport(sass, name)); }); - it('if it has multiple in a comma separated list', function() { + it('if it has multiple in a comma separated list', function () { var sass = '@import "hello", "' + alternate + '";'; assert(!parsers.hasImport(sass, name)); }); From 45df6d638e15aa9b501ecc4cad58bbd77ce931ed Mon Sep 17 00:00:00 2001 From: razvan Date: Wed, 25 Oct 2017 21:07:12 +0300 Subject: [PATCH 14/15] Removed newer versions of node --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d395657..2df9852 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,6 @@ sudo: false language: node_js node_js: - - "6.11.4" - - "5.12.0" - - "4.8.4" - "0.12" - "0.10" env: From 895650abe14b3893668b4b88ed81ca898b863079 Mon Sep 17 00:00:00 2001 From: rtrufin <7871937+rtrufin@users.noreply.github.com> Date: Mon, 30 Oct 2017 11:17:14 +0200 Subject: [PATCH 15/15] Update Readme to remove declaresProperties. declaresProperties has been merged into the declares method --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2839b76..a828523 100644 --- a/README.md +++ b/README.md @@ -328,13 +328,13 @@ sassaby.includedMixin('appearance').calledWithArgs('button').hasNumDeclarations( ``` #### declares -Assert that the mixin makes a declaration of the given rule-property pair. +Can be either called with a string as property value or with an Array object. + +Called with a String it asserts that the mixin makes a declaration of the given rule-property pair. ```js sassaby.includedMixin('appearance').calledWithArgs('button').declares('-webkit-appearance', 'button'); ``` - -#### declaresProperties -Assert that the mixin makes a declaration of the given property with fallback values. +Called with an Object it asserts that the mixin makes a declaration of the given property with the provided fallback values. E.g. for the mixin: ``` @mixin font-size($font-size: 1.6) {