Gruntfile.js 14 KB

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