UNPKG

6.6 kBJavaScriptView Raw
1var assert = require('assert'),
2 fs = require('fs'),
3 exists = fs.existsSync,
4 join = require('path').join,
5 read = fs.readFileSync,
6 sass = process.env.NODESASS_COV
7 ? require('../lib-cov')
8 : require('../lib'),
9 readYaml = require('read-yaml'),
10 mergeWith = require('lodash/mergeWith'),
11 assign = require('lodash/assign'),
12 glob = require('glob'),
13 specPath = require('sass-spec').dirname.replace(/\\/g, '/'),
14 impl = 'libsass',
15 version = 3.5;
16
17var normalize = function(str) {
18 // This should be /\r\n/g, '\n', but there seems to be some empty line issues
19 return str.replace(/\s+/g, '');
20};
21
22var inputs = glob.sync(specPath + '/**/input.*');
23
24var initialize = function(inputCss, options) {
25 var testCase = {};
26 var folders = inputCss.split('/');
27 var folder = join(inputCss, '..');
28 testCase.folder = folder;
29 testCase.name = folders[folders.length - 2];
30 testCase.inputPath = inputCss;
31 testCase.expectedPath = join(folder, 'expected_output.css');
32 testCase.errorPath = join(folder, 'error');
33 testCase.statusPath = join(folder, 'status');
34 testCase.optionsPath = join(folder, 'options.yml');
35 if (exists(testCase.optionsPath)) {
36 options = mergeWith(assign({}, options), readYaml.sync(testCase.optionsPath), customizer);
37 }
38 testCase.includePaths = [
39 folder,
40 join(folder, 'sub')
41 ];
42 testCase.precision = parseFloat(options[':precision']) || 5;
43 testCase.outputStyle = options[':output_style'] ? options[':output_style'].replace(':', '') : 'nested';
44 testCase.todo = options[':todo'] !== undefined && options[':todo'] !== null && options[':todo'].indexOf(impl) !== -1;
45 testCase.only = options[':only_on'] !== undefined && options[':only_on'] !== null && options[':only_on'];
46 testCase.warningTodo = options[':warning_todo'] !== undefined && options[':warning_todo'] !== null && options[':warning_todo'].indexOf(impl) !== -1;
47 testCase.startVersion = parseFloat(options[':start_version']) || 0;
48 testCase.endVersion = parseFloat(options[':end_version']) || 99;
49 testCase.options = options;
50 testCase.result = false;
51
52 // Probe filesystem once and cache the results
53 testCase.shouldFail = exists(testCase.statusPath) && !fs.statSync(testCase.statusPath).isDirectory();
54 testCase.verifyStderr = exists(testCase.errorPath) && !fs.statSync(testCase.errorPath).isDirectory();
55 return testCase;
56};
57
58var runTest = function(inputCssPath, options) {
59 var test = initialize(inputCssPath, options);
60
61 it(test.name, function(done) {
62 if (test.todo || test.warningTodo) {
63 this.skip('Test marked with TODO');
64 } else if (test.only && test.only.indexOf(impl) === -1) {
65 this.skip('Tests marked for only: ' + test.only.join(', '));
66 } else if (version < test.startVersion) {
67 this.skip('Tests marked for newer Sass versions only');
68 } else if (version > test.endVersion) {
69 this.skip('Tests marked for older Sass versions only');
70 } else {
71 var expected = normalize(read(test.expectedPath, 'utf8'));
72 sass.render({
73 file: test.inputPath,
74 includePaths: test.includePaths,
75 precision: test.precision,
76 outputStyle: test.outputStyle
77 }, function(error, result) {
78 if (test.shouldFail) {
79 // Replace 1, with parseInt(read(test.statusPath, 'utf8')) pending
80 // https://github.com/sass/libsass/issues/2162
81 assert.equal(error.status, 1);
82 } else if (test.verifyStderr) {
83 var expectedError = read(test.errorPath, 'utf8');
84 if (error === null) {
85 // Probably a warning
86 assert.ok(expectedError, 'Expected some sort of warning, but found none');
87 } else {
88 // The error messages seem to have some differences in areas
89 // like line numbering, so we'll check the first line for the
90 // general errror message only
91 assert.equal(
92 error.formatted.toString().split('\n')[0],
93 expectedError.toString().split('\n')[0],
94 'Should Error.\nOptions' + JSON.stringify(test.options));
95 }
96 } else if (expected) {
97 assert.equal(
98 normalize(result.css.toString()),
99 expected,
100 'Should equal with options ' + JSON.stringify(test.options)
101 );
102 }
103 done();
104 });
105 }
106 });
107};
108
109var specSuite = {
110 name: specPath.split('/').slice(-1)[0],
111 folder: specPath,
112 tests: [],
113 suites: [],
114 options: {}
115};
116
117function customizer(objValue, srcValue) {
118 if (Array.isArray(objValue)) {
119 return objValue.concat(srcValue);
120 }
121}
122
123var executeSuite = function(suite, tests) {
124 var suiteFolderLength = suite.folder.split('/').length;
125 var optionsFile = join(suite.folder, 'options.yml');
126 if (exists(optionsFile)) {
127 suite.options = mergeWith(assign({}, suite.options), readYaml.sync(optionsFile), customizer);
128 }
129
130 // Push tests in the current suite
131 tests = tests.filter(function(test) {
132 var testSuiteFolder = test.split('/');
133 var inputSass = testSuiteFolder[suiteFolderLength + 1];
134 // Add the test if the specPath matches the testname
135 if (inputSass === 'input.scss' || inputSass === 'input.sass') {
136 suite.tests.push(test);
137 } else {
138 return test;
139 }
140 });
141
142 if (tests.length !== 0) {
143 var prevSuite = tests[0].split('/')[suiteFolderLength];
144 var suiteName = '';
145 var prevSuiteStart = 0;
146 for (var i = 0; i < tests.length; i++) {
147 var test = tests[i];
148 suiteName = test.split('/')[suiteFolderLength];
149 if (suiteName !== prevSuite) {
150 suite.suites.push(
151 executeSuite(
152 {
153 name: prevSuite,
154 folder: suite.folder + '/' + prevSuite,
155 tests: [],
156 suites: [],
157 options: assign({}, suite.options),
158 },
159 tests.slice(prevSuiteStart, i)
160 )
161 );
162 prevSuite = suiteName;
163 prevSuiteStart = i;
164 }
165 }
166 suite.suites.push(
167 executeSuite(
168 {
169 name: suiteName,
170 folder: suite.folder + '/' + suiteName,
171 tests: [],
172 suites: [],
173 options: assign({}, suite.options),
174 },
175 tests.slice(prevSuiteStart, tests.length)
176 )
177 );
178 }
179 return suite;
180};
181var allSuites = executeSuite(specSuite, inputs);
182var runSuites = function(suite) {
183 describe(suite.name, function(){
184 suite.tests.forEach(function(test){
185 runTest(test, suite.options);
186 });
187 suite.suites.forEach(function(subsuite) {
188 runSuites(subsuite);
189 });
190 });
191};
192runSuites(allSuites);