Gruntfile.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. "use strict";
  2. var resolve = require('resolve');
  3. var path = require('path');
  4. var testFolder = path.relative(process.cwd(), path.dirname(resolve.sync('@less/test-data')));
  5. var lessFolder = path.join(testFolder, 'less');
  6. module.exports = function(grunt) {
  7. grunt.option("stack", true);
  8. // Report the elapsed execution time of tasks.
  9. require("time-grunt")(grunt);
  10. var COMPRESS_FOR_TESTS = false;
  11. var git = require("git-rev");
  12. // Sauce Labs browser
  13. var browsers = [
  14. // Desktop browsers
  15. {
  16. browserName: "chrome",
  17. version: "latest",
  18. platform: "Windows 7"
  19. },
  20. {
  21. browserName: "firefox",
  22. version: "latest",
  23. platform: "Linux"
  24. },
  25. {
  26. browserName: "safari",
  27. version: "9",
  28. platform: "OS X 10.11"
  29. },
  30. {
  31. browserName: "internet explorer",
  32. version: "8",
  33. platform: "Windows XP"
  34. },
  35. {
  36. browserName: "internet explorer",
  37. version: "11",
  38. platform: "Windows 8.1"
  39. },
  40. {
  41. browserName: "edge",
  42. version: "13",
  43. platform: "Windows 10"
  44. },
  45. // Mobile browsers
  46. {
  47. browserName: "ipad",
  48. deviceName: "iPad Air Simulator",
  49. deviceOrientation: "portrait",
  50. version: "8.4",
  51. platform: "OS X 10.9"
  52. },
  53. {
  54. browserName: "iphone",
  55. deviceName: "iPhone 5 Simulator",
  56. deviceOrientation: "portrait",
  57. version: "9.3",
  58. platform: "OS X 10.11"
  59. },
  60. {
  61. browserName: "android",
  62. deviceName: "Google Nexus 7 HD Emulator",
  63. deviceOrientation: "portrait",
  64. version: "4.4",
  65. platform: "Linux"
  66. }
  67. ];
  68. var sauceJobs = {};
  69. var browserTests = [
  70. "filemanager-plugin",
  71. "visitor-plugin",
  72. "global-vars",
  73. "modify-vars",
  74. "production",
  75. "rootpath-relative",
  76. "rootpath-rewrite-urls",
  77. "rootpath",
  78. "relative-urls",
  79. "rewrite-urls",
  80. "browser",
  81. "no-js-errors",
  82. "legacy"
  83. ];
  84. function makeJob(testName) {
  85. sauceJobs[testName] = {
  86. options: {
  87. urls:
  88. testName === "all"
  89. ? browserTests.map(function(name) {
  90. return (
  91. "http://localhost:8081/tmp/browser/test-runner-" +
  92. name +
  93. ".html"
  94. );
  95. })
  96. : [
  97. "http://localhost:8081/tmp/browser/test-runner-" +
  98. testName +
  99. ".html"
  100. ],
  101. testname:
  102. testName === "all" ? "Unit Tests for Less.js" : testName,
  103. browsers: browsers,
  104. public: "public",
  105. recordVideo: false,
  106. videoUploadOnPass: false,
  107. recordScreenshots: process.env.TRAVIS_BRANCH !== "master",
  108. build:
  109. process.env.TRAVIS_BRANCH === "master"
  110. ? process.env.TRAVIS_JOB_ID
  111. : undefined,
  112. tags: [
  113. process.env.TRAVIS_BUILD_NUMBER,
  114. process.env.TRAVIS_PULL_REQUEST,
  115. process.env.TRAVIS_BRANCH
  116. ],
  117. statusCheckAttempts: -1,
  118. sauceConfig: {
  119. "idle-timeout": 100
  120. },
  121. throttled: 5,
  122. onTestComplete: function(result, callback) {
  123. // Called after a unit test is done, per page, per browser
  124. // 'result' param is the object returned by the test framework's reporter
  125. // 'callback' is a Node.js style callback function. You must invoke it after you
  126. // finish your work.
  127. // Pass a non-null value as the callback's first parameter if you want to throw an
  128. // exception. If your function is synchronous you can also throw exceptions
  129. // directly.
  130. // Passing true or false as the callback's second parameter passes or fails the
  131. // test. Passing undefined does not alter the test result. Please note that this
  132. // only affects the grunt task's result. You have to explicitly update the Sauce
  133. // Labs job's status via its REST API, if you want so.
  134. // This should be the encrypted value in Travis
  135. var user = process.env.SAUCE_USERNAME;
  136. var pass = process.env.SAUCE_ACCESS_KEY;
  137. git.short(function(hash) {
  138. require("phin")(
  139. {
  140. method: "PUT",
  141. url: [
  142. "https://saucelabs.com/rest/v1",
  143. user,
  144. "jobs",
  145. result.job_id
  146. ].join("/"),
  147. auth: { user: user, pass: pass },
  148. data: {
  149. passed: result.passed,
  150. build: "build-" + hash
  151. }
  152. },
  153. function(error, response) {
  154. if (error) {
  155. console.log(error);
  156. callback(error);
  157. } else if (response.statusCode !== 200) {
  158. console.log(response);
  159. callback(
  160. new Error("Unexpected response status")
  161. );
  162. } else {
  163. callback(null, result.passed);
  164. }
  165. }
  166. );
  167. });
  168. }
  169. }
  170. };
  171. }
  172. // Make the SauceLabs jobs
  173. ["all"].concat(browserTests).map(makeJob);
  174. var semver = require('semver');
  175. var path = require('path');
  176. // Handle async / await in Rollup build for tests
  177. // Remove this when Node 6 is no longer supported for the build/test process
  178. const nodeVersion = semver.major(process.versions.node);
  179. const tsNodeRuntime = path.resolve(path.join('node_modules', '.bin', 'ts-node'));
  180. let scriptRuntime = 'node';
  181. if (nodeVersion < 8) {
  182. scriptRuntime = tsNodeRuntime;
  183. }
  184. // Project configuration.
  185. grunt.initConfig({
  186. shell: {
  187. options: {
  188. stdout: true,
  189. failOnError: true,
  190. execOptions: {
  191. maxBuffer: Infinity
  192. }
  193. },
  194. build: {
  195. command: [
  196. /** Browser runtime */
  197. scriptRuntime + " build/rollup.js --dist",
  198. /** Copy to repo root */
  199. "npm run copy:root",
  200. /** Node.js runtime */
  201. "npm run build"
  202. ].join(" && ")
  203. },
  204. testbuild: {
  205. command: [
  206. "npm run build",
  207. scriptRuntime + " build/rollup.js --browser --out=./tmp/browser/less.min.js"
  208. ].join(" && ")
  209. },
  210. testcjs: {
  211. command: "npm run build"
  212. },
  213. testbrowser: {
  214. command: scriptRuntime + " build/rollup.js --browser --out=./tmp/browser/less.min.js"
  215. },
  216. test: {
  217. command: [
  218. tsNodeRuntime + " test/test-es6.ts",
  219. "node test/index.js"
  220. ].join(' && ')
  221. },
  222. generatebrowser: {
  223. command: 'node test/browser/generator/generate.js'
  224. },
  225. runbrowser: {
  226. command: 'node test/browser/generator/runner.js'
  227. },
  228. benchmark: {
  229. command: "node benchmark/index.js"
  230. },
  231. opts: {
  232. // test running with all current options (using `opts` since `options` means something already)
  233. command: [
  234. // @TODO: make this more thorough
  235. // CURRENT OPTIONS
  236. `node bin/lessc --ie-compat ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  237. // --math
  238. `node bin/lessc --math=always ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  239. `node bin/lessc --math=parens-division ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  240. `node bin/lessc --math=parens ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  241. `node bin/lessc --math=strict ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  242. `node bin/lessc --math=strict-legacy ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  243. // DEPRECATED OPTIONS
  244. // --strict-math
  245. `node bin/lessc --strict-math=on ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`
  246. ].join(" && ")
  247. },
  248. plugin: {
  249. command: [
  250. `node bin/lessc --clean-css="--s1 --advanced" ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  251. "cd lib",
  252. `node ../bin/lessc --clean-css="--s1 --advanced" ../${lessFolder}/_main/lazy-eval.less ../tmp/lazy-eval.css`,
  253. "cd ..",
  254. // Test multiple plugins
  255. `node bin/lessc --plugin=clean-css="--s1 --advanced" --plugin=autoprefix="ie 11,Edge >= 13,Chrome >= 47,Firefox >= 45,iOS >= 9.2,Safari >= 9" ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`
  256. ].join(" && ")
  257. },
  258. "sourcemap-test": {
  259. // quoted value doesn't seem to get picked up by time-grunt, or isn't output, at least; maybe just "sourcemap" is fine?
  260. command: [
  261. `node bin/lessc --source-map=test/sourcemaps/maps/import-map.map ${lessFolder}/_main/import.less test/sourcemaps/import.css`,
  262. `node bin/lessc --source-map ${lessFolder}/sourcemaps/basic.less test/sourcemaps/basic.css`
  263. ].join(" && ")
  264. }
  265. },
  266. eslint: {
  267. target: [
  268. "test/**/*.js",
  269. "lib/less*/**/*.js",
  270. "!test/less/errors/plugin/plugin-error.js"
  271. ],
  272. options: {
  273. configFile: ".eslintrc.json",
  274. fix: true
  275. }
  276. },
  277. connect: {
  278. server: {
  279. options: {
  280. port: 8081
  281. }
  282. }
  283. },
  284. "saucelabs-mocha": sauceJobs,
  285. // Clean the version of less built for the tests
  286. clean: {
  287. test: ["test/browser/less.js", "tmp", "test/less-bom"],
  288. "sourcemap-test": [
  289. "test/sourcemaps/*.css",
  290. "test/sourcemaps/*.map"
  291. ],
  292. sauce_log: ["sc_*.log"]
  293. }
  294. });
  295. // Load these plugins to provide the necessary tasks
  296. grunt.loadNpmTasks("grunt-saucelabs");
  297. require("jit-grunt")(grunt);
  298. // by default, run tests
  299. grunt.registerTask("default", ["test"]);
  300. // Release
  301. grunt.registerTask("dist", [
  302. "shell:build"
  303. ]);
  304. // Create the browser version of less.js
  305. grunt.registerTask("browsertest-lessjs", [
  306. "shell:testbrowser"
  307. ]);
  308. // Run all browser tests
  309. grunt.registerTask("browsertest", [
  310. "browsertest-lessjs",
  311. "connect",
  312. "shell:runbrowser"
  313. ]);
  314. // setup a web server to run the browser tests in a browser rather than phantom
  315. grunt.registerTask("browsertest-server", [
  316. "browsertest-lessjs",
  317. "shell:generatebrowser",
  318. "connect::keepalive"
  319. ]);
  320. var previous_force_state = grunt.option("force");
  321. grunt.registerTask("force", function(set) {
  322. if (set === "on") {
  323. grunt.option("force", true);
  324. } else if (set === "off") {
  325. grunt.option("force", false);
  326. } else if (set === "restore") {
  327. grunt.option("force", previous_force_state);
  328. }
  329. });
  330. grunt.registerTask("sauce", [
  331. "browsertest-lessjs",
  332. "shell:generatebrowser",
  333. "connect",
  334. "sauce-after-setup"
  335. ]);
  336. grunt.registerTask("sauce-after-setup", [
  337. "saucelabs-mocha:all",
  338. "clean:sauce_log"
  339. ]);
  340. var testTasks = [
  341. "clean",
  342. "eslint",
  343. "shell:testbuild",
  344. "shell:test",
  345. "shell:opts",
  346. "shell:plugin",
  347. "connect",
  348. "shell:runbrowser"
  349. ];
  350. if (
  351. isNaN(Number(process.env.TRAVIS_PULL_REQUEST, 10)) &&
  352. (process.env.TRAVIS_BRANCH === "master")
  353. ) {
  354. testTasks.push("force:on");
  355. testTasks.push("sauce-after-setup");
  356. testTasks.push("force:off");
  357. }
  358. // Run all tests
  359. grunt.registerTask("test", testTasks);
  360. // Run shell option tests (includes deprecated options)
  361. grunt.registerTask("shell-options", ["shell:opts"]);
  362. // Run shell plugin test
  363. grunt.registerTask("shell-plugin", ["shell:plugin"]);
  364. // Quickly build and run Node tests
  365. grunt.registerTask("quicktest", [
  366. "shell:testcjs",
  367. "shell:test"
  368. ]);
  369. // generate a good test environment for testing sourcemaps
  370. grunt.registerTask("sourcemap-test", [
  371. "clean:sourcemap-test",
  372. "shell:build:lessc",
  373. "shell:sourcemap-test",
  374. "connect::keepalive"
  375. ]);
  376. // Run benchmark
  377. grunt.registerTask("benchmark", [
  378. "shell:testcjs",
  379. "shell:benchmark"
  380. ]);
  381. };