Gruntfile.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  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. benchmarkbrowser: {
  232. command: "node test/browser/generator/runner.js benchmark"
  233. },
  234. opts: {
  235. // test running with all current options (using `opts` since `options` means something already)
  236. command: [
  237. // @TODO: make this more thorough
  238. // CURRENT OPTIONS
  239. // --math
  240. `node bin/lessc --math=always ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  241. `node bin/lessc --math=parens-division ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  242. `node bin/lessc --math=parens ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  243. `node bin/lessc --math=strict ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  244. `node bin/lessc --math=strict-legacy ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  245. // DEPRECATED OPTIONS
  246. // --strict-math
  247. `node bin/lessc --strict-math=on ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`
  248. ].join(" && ")
  249. },
  250. plugin: {
  251. command: [
  252. `node bin/lessc --clean-css="--s1 --advanced" ${lessFolder}/_main/lazy-eval.less tmp/lazy-eval.css`,
  253. "cd lib",
  254. `node ../bin/lessc --clean-css="--s1 --advanced" ../${lessFolder}/_main/lazy-eval.less ../tmp/lazy-eval.css`,
  255. "cd ..",
  256. // Test multiple plugins
  257. `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`
  258. ].join(" && ")
  259. },
  260. "sourcemap-test": {
  261. // quoted value doesn't seem to get picked up by time-grunt, or isn't output, at least; maybe just "sourcemap" is fine?
  262. command: [
  263. `node bin/lessc --source-map=test/sourcemaps/maps/import-map.map ${lessFolder}/_main/import.less test/sourcemaps/import.css`,
  264. `node bin/lessc --source-map ${lessFolder}/sourcemaps/basic.less test/sourcemaps/basic.css`
  265. ].join(" && ")
  266. }
  267. },
  268. eslint: {
  269. target: [
  270. "test/**/*.js",
  271. "lib/less*/**/*.js",
  272. "!test/less/errors/plugin/plugin-error.js"
  273. ],
  274. options: {
  275. configFile: ".eslintrc.json",
  276. fix: true
  277. }
  278. },
  279. connect: {
  280. server: {
  281. options: {
  282. port: 8081
  283. }
  284. }
  285. },
  286. "saucelabs-mocha": sauceJobs,
  287. // Clean the version of less built for the tests
  288. clean: {
  289. test: ["test/browser/less.js", "tmp", "test/less-bom"],
  290. "sourcemap-test": [
  291. "test/sourcemaps/*.css",
  292. "test/sourcemaps/*.map"
  293. ],
  294. sauce_log: ["sc_*.log"]
  295. }
  296. });
  297. // Load these plugins to provide the necessary tasks
  298. grunt.loadNpmTasks("grunt-saucelabs");
  299. require("jit-grunt")(grunt);
  300. // by default, run tests
  301. grunt.registerTask("default", ["test"]);
  302. // Release
  303. grunt.registerTask("dist", [
  304. "shell:build"
  305. ]);
  306. // Create the browser version of less.js
  307. grunt.registerTask("browsertest-lessjs", [
  308. "shell:testbrowser"
  309. ]);
  310. // Run all browser tests
  311. grunt.registerTask("browsertest", [
  312. "browsertest-lessjs",
  313. "connect",
  314. "shell:runbrowser"
  315. ]);
  316. // setup a web server to run the browser tests in a browser rather than phantom
  317. grunt.registerTask("browsertest-server", [
  318. "browsertest-lessjs",
  319. "shell:generatebrowser",
  320. "connect::keepalive"
  321. ]);
  322. var previous_force_state = grunt.option("force");
  323. grunt.registerTask("force", function(set) {
  324. if (set === "on") {
  325. grunt.option("force", true);
  326. } else if (set === "off") {
  327. grunt.option("force", false);
  328. } else if (set === "restore") {
  329. grunt.option("force", previous_force_state);
  330. }
  331. });
  332. grunt.registerTask("sauce", [
  333. "browsertest-lessjs",
  334. "shell:generatebrowser",
  335. "connect",
  336. "sauce-after-setup"
  337. ]);
  338. grunt.registerTask("sauce-after-setup", [
  339. "saucelabs-mocha:all",
  340. "clean:sauce_log"
  341. ]);
  342. var testTasks = [
  343. "clean",
  344. "eslint",
  345. "shell:testbuild",
  346. "shell:test",
  347. "shell:opts",
  348. "shell:plugin",
  349. "connect",
  350. "shell:runbrowser"
  351. ];
  352. if (
  353. isNaN(Number(process.env.TRAVIS_PULL_REQUEST, 10)) &&
  354. (process.env.TRAVIS_BRANCH === "master")
  355. ) {
  356. testTasks.push("force:on");
  357. testTasks.push("sauce-after-setup");
  358. testTasks.push("force:off");
  359. }
  360. // Run all tests
  361. grunt.registerTask("test", testTasks);
  362. // Run shell option tests (includes deprecated options)
  363. grunt.registerTask("shell-options", ["shell:opts"]);
  364. // Run shell plugin test
  365. grunt.registerTask("shell-plugin", ["shell:plugin"]);
  366. // Quickly build and run Node tests
  367. grunt.registerTask("quicktest", [
  368. "shell:testcjs",
  369. "shell:test"
  370. ]);
  371. // generate a good test environment for testing sourcemaps
  372. grunt.registerTask("sourcemap-test", [
  373. "clean:sourcemap-test",
  374. "shell:build:lessc",
  375. "shell:sourcemap-test",
  376. "connect::keepalive"
  377. ]);
  378. // Run benchmark
  379. grunt.registerTask("benchmark-node", [
  380. "shell:testcjs",
  381. "shell:benchmark"
  382. ]);
  383. // Run all browser tests
  384. grunt.registerTask("benchmark", [
  385. "browsertest-lessjs",
  386. "connect",
  387. "shell:benchmarkbrowser"
  388. ]);
  389. };