日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

grunt 插件_从Grunt测试Grunt插件

發布時間:2023/12/3 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 grunt 插件_从Grunt测试Grunt插件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

grunt 插件

編寫針對grunt插件的測試結果比預期的要簡單。 我需要運行多個任務配置,并想通過在主目錄中鍵入grunt test來調用它們。

在第一個任務失敗后,咕聲通常會退出。 這使得不可能在主項目gruntfile中存儲多個失敗方案。 從那里運行它們將需要--force選項,但是grunt會忽略所有不是最佳的警告。

較干凈的解決方案是在單獨的目錄中有一堆gruntfile,然后從主項目gruntfile調用它們。 這篇文章解釋了如何做到這一點。

示范項目

演示項目是帶有一個grunt任務的小型grunt插件。 根據action options屬性的值,任務要么失敗并顯示警告,要么將成功消息打印到控制臺中。

任務:

grunt.registerMultiTask('plugin_tester', 'Demo grunt task.', function() {//merge supplied options with default optionsvar options = this.options({ action: 'pass', message: 'unknown error'});//pass or fail - depending on configured optionsif (options.action==='pass') {grunt.log.writeln('Plugin worked correctly passed.');} else {grunt.warn('Plugin failed: ' + options.message);} });

有三種不同的方式編寫grunt插件單元測試。 每個解決方案在test目錄中都有自己的nodeunit文件,并在這篇文章中進行說明:

  • plugin_exec_test.js –最實用的解決方案 ,
  • plugin_fork_test.js – 解決了先前解決方案失敗的罕見情況,
  • plugin_spawn_test.js – 可能 ,但最不實用。

所有這三個演示測試都包含三種不同的任務配置:

// Success scenario options: { action: 'pass' } // Fail with "complete failure" message options: { action: 'fail', message: 'complete failure' } //Fail with "partial failure" message options: { action: 'fail', message: 'partial failure' }

每個配置都存儲在test目錄內的單獨gruntfile中。 例如,存儲在gruntfile-pass.js文件中的成功方案如下所示:

grunt.initConfig({// prove that npm plugin works toojshint: { all: [ 'gruntfile-pass.js' ] },// Configuration to be run (and then tested).plugin_tester: { pass: { options: { action: 'pass' } } } });// Load this plugin's task(s). grunt.loadTasks('./../tasks'); // next line does not work - grunt requires locally installed plugins grunt.loadNpmTasks('grunt-contrib-jshint');grunt.registerTask('default', ['plugin_tester', 'jshint']);

這三個測試gruntfiles看起來幾乎相同,只有plugin_tester目標的options對象改變了。

從子目錄運行Gruntfile

我們的測試gruntfiles存儲在test子目錄中,而grunt不能很好地處理這種情況。 本章介紹了問題所在,并介紹了兩種解決方法。

問題

要查看問題,請轉到演示項目目錄并運行以下命令:

grunt --gruntfile test/gruntfile-problem.js

Grunt響應以下錯誤:

Local Npm module "grunt-contrib-jshint" not found. Is it installed? Warning: Task "jshint" not found. Use --force to continue.Aborted due to warnings.

說明

Grunt假定grunfile和node_modules存儲庫存儲在同一目錄中。 雖然node.js require函數會在所有父目錄中搜索所需模塊,但loadNpmTasks不會。

這個問題有兩種可能的解決方案,一種簡單而有趣:

  • 在測試目錄( 簡單 )中創建本地npm存儲庫,
  • 從父目錄中執行繁重的加載任務( fancy )。

盡管第一個“簡單”解決方案比較干凈,但演示項目使用了第二個“精美”解決方案。

解決方案1:復制Npm存儲庫

主要思想很簡單,只需在tests目錄內創建另一個本地npm存儲庫:

  • 將package.json文件復制到tests目錄。
  • 向其中添加僅測試依賴項。
  • 每次運行測試時,請運行npm install命令。

這是更清潔的解決方案。 它只有兩個缺點:

  • 測試依賴項必須單獨維護,
  • 所有插件依賴項都必須安裝在兩個位置。

解決方案2:從父目錄加載Grunt任務

另一個解決方案是強制grunt從存儲在另一個目錄中的npm存儲庫加載任務。

Grunt插件加載

Grunt有兩種方法可以加載插件:

  • loadTasks('directory-name') –將所有任務加載到目錄中,
  • loadNpmTasks('plugin-name') –加載插件定義的所有任務。

loadNpmTasks函數采用grunt插件和模塊存儲庫的固定目錄結構。 它猜測應該存儲任務的目錄名稱,然后調用loadTasks('directory-name')函數。

本地npm存儲庫為每個npm軟件包都有單獨的子目錄。 所有grunt插件都應該具有tasks子目錄,并且其中的.js文件都包含任務。 例如, loadNpmTasks('grunt-contrib-jshint')調用從node_mudules/grunt-contrib-jshint/tasks目錄加載任務,等效于:

grunt.loadTasks('node_modules/grunt-contrib-jshint/tasks')

因此,如果要從父目錄加載grunt-contrib-jshint插件的所有任務,可以執行以下操作:

grunt.loadTasks('../node_modules/grunt-contrib-jshint/tasks')

循環父目錄

更為靈活的解決方案是遍歷所有父目錄,直到找到最近的node_modules存儲庫或到達根目錄為止。 這是在grunt-hacks.js模塊內部實現的。

loadParentNpmTasks函數循環父目錄:

module.exports = new function() {this.loadParentNpmTasks = function(grunt, pluginName) {var oldDirectory='', climb='', directory, content;// search for the right directorydirectory = climb+'node_modules/'+ pluginName;while (continueClimbing(grunt, oldDirectory, directory)) {climb += '../';oldDirectory = directory;directory = climb+'node_modules/'+ pluginName;}// load tasks or return an errorif (grunt.file.exists(directory)) {grunt.loadTasks(directory+'/tasks');} else {grunt.fail.warn('Tasks plugin ' + pluginName + ' was not found.');}}function continueClimbing(grunt, oldDirectory, directory) {return !grunt.file.exists(directory) &&!grunt.file.arePathsEquivalent(oldDirectory, directory);}}();

修改后的Gruntfile

最后,我們需要通過以下步驟替換grunt.loadNpmTasks('grunt-contrib-jshint')中通常的grunt.loadNpmTasks('grunt-contrib-jshint')調用:

var loader = require("./grunt-hacks.js"); loader.loadParentNpmTasks(grunt, 'grunt-contrib-jshint');

縮短的gruntfile:

module.exports = function(grunt) {var loader = require("./grunt-hacks.js");grunt.initConfig({jshint: { /* ... */ },plugin_tester: { /* ... */ }});grunt.loadTasks('./../tasks');loader.loadParentNpmTasks(grunt, 'grunt-contrib-jshint'); };

缺點

該解決方案有兩個缺點:

  • 它不處理集合插件。
  • 如果grunt曾經改變grunt插件的預期結構,則必須修改解決方案。

如果您還需要集合插件,請查看grunts task.js以了解如何支持它們。

從Java腳本調用Gruntfile

我們需要做的第二件事是從javascript調用gruntfile。 唯一的麻煩是,咕unt聲會在任務失敗時退出整個過程。 因此,我們需要從子進程中調用它。

節點模塊子進程具有三種不同的功能,能夠在子進程內部運行命令:

  • exec –在命令行執行命令,
  • spawn –在命令行上執行命令的方式不同,
  • fork –在子進程中運行節點模塊。

第一個是exec ,最易于使用,并在第一章中進行了說明。 第二章介紹了如何使用fork以及為什么它不如exec最佳。 第三章是關于生成。

執行力

Exec在子進程中運行命令行命令。 您可以指定要在哪個目錄中運行它,設置環境變量,設置超時,然后在該超時后將命令終止。 當命令完成運行時,exec調用回調并將其傳遞給stdout流,stderr流和命令崩潰時的錯誤。

除非另有配置,否則命令將在當前目錄中運行。 我們希望它在tests子目錄中運行,所以我們必須指定options對象的cwd屬性: {cwd: 'tests/'} 。

stdout和stderr流內容都存儲在緩沖區中。 每個緩沖區的最大大小設置為204800,如果命令產生更多輸出,則exec調用將崩潰。 這筆錢足以應付我們的小任務。 如果需要更多,則必須設置maxBuffer options屬性。

致電執行

以下代碼段顯示了如何從exec運行gruntfile。 該函數是異步的,并在完成之后調用whenDoneCallback :

var cp = require("child_process");function callGruntfile(filename, whenDoneCallback) {var command, options;command = "grunt --gruntfile "+filename+" --no-color";options = {cwd: 'test/'};cp.exec(command, options, whenDoneCallback); }

注意:如果將npm安裝到測試目錄( 簡單解決方案 ),則需要使用callNpmInstallAndGruntfile函數而不是callGruntfile :

function callNpmInstallAndGruntfile(filename, whenDoneCallback) {var command, options;command = "npm install";options = {cwd: 'test/'};cp.exec(command, {}, function(error, stdout, stderr) {callGruntfile(filename, whenDoneCallback);}); }

單元測試

第一節點單元測試運行成功方案,然后檢查流程是否成功完成而沒有失敗,標準輸出是否包含預期的消息以及標準錯誤是否為空。

成功場景單元測試:

pass: function(test) {test.expect(3);callGruntfile('gruntfile-pass.js', function (error, stdout, stderr) {test.equal(error, null, "Command should not fail.");test.equal(stderr, '', "Standard error stream should be empty.");var stdoutOk = contains(stdout, 'Plugin worked correctly.');test.ok(stdoutOk, "Missing stdout message.");test.done();}); },

第二節點單元測試運行“完全失敗”方案,然后檢查進程是否按預期失敗。 請注意,標準錯誤流為空,警告被打印到標準輸出中。

失敗的場景單元測試:

fail_1: function(test) {test.expect(3);var gFile = 'gruntfile-fail-complete.js';callGruntfile(gFile, function (error, stdout, stderr) {test.equal(error, null, "Command should have failed.");test.equal(error.message, 'Command failed: ', "Wrong error message.");test.equal(stderr, '', "Non empty stderr.");var stdoutOk = containsWarning(stdout, 'complete failure');test.ok(stdoutOk, "Missing stdout message.");test.done();}); }

第三次“部分故障”節點單元測試與之前的測試幾乎相同。 整個測試文件可在github上找到 。

缺點

壞處:

  • 必須預先設置最大緩沖區大小。

叉子

Fork在子進程中運行node.js模塊,等效于在命令行上調用node <module-name> 。 Fork使用回調將標準輸出和標準錯誤發送給調用方。 兩個回調都可以被多次調用,并且調用方可以分段獲取子進程的輸出。

僅在需要處理任意大小的stdout和stderr或需要自定義grunt功能時,使用fork才有意義。 如果您不這樣做,則exec更易于使用。

本章分為四個子章節:

  • 從javascript 呼叫grunt ,
  • 讀取節點模塊中的命令行參數,
  • 在子進程中啟動節點模塊,
  • 編寫單元測試。

呼喚咕unt聲

Grunt并非以編程方式被調用。 它沒有公開“公共” API,也沒有對其進行記錄。

我們的解決方案模仿了grunt-cli的功能,因此相對安全。 Grunt-cli與grunt核心分開分發,因此更改的可能性較小。 但是,如果確實更改,則此解決方案也必須更改。

從javascript運行咕unt聲需要我們執行以下操作:

  • 將gruntfile名稱與其路徑分開,
  • 更改活動目錄,
  • 調用grunts tasks功能。

從javascript呼叫grunt:

this.runGruntfile = function(filename) {var grunt = require('grunt'), path = require('path'), directory, filename;// split filename into directory and filedirectory = path.dirname(filename);filename = path.basename(filename);//change directoryprocess.chdir(directory);//call gruntgrunt.tasks(['default'], {gruntfile:filename, color:false}, function() {console.log('done');}); };

模塊參數

該模塊將從命令行調用。 節點將命令行參數保留在內部
process.argv數組:

module.exports = new function() {var filename, directory;this.runGruntfile = function(filename) {/* ... */};//get first command line argumentfilename = process.argv[2];this.runGruntfile(filename); }();

呼叫叉

Fork具有三個參數:模塊的路徑,帶有命令行參數的數組和options對象。 使用tests/Gruntfile-1.js參數調用module.js :

child = cp.fork('./module.js', ['tests/Gruntfile-1.js'], {silent: true})

silent: true選項使返回的child進程的stdout和stderr在父級內部可用。 如果將其設置為true,則返回的對象將提供對調用者的stdout和stderr流的訪問。

在每個流上調用on('data', callback) 。 每次子進程向流發送某些內容時,都會調用傳遞的回調:

child.stdout.on('data', function (data) {console.log('stdout: ' + data); // handle piece of stdout }); child.stderr.on('data', function (data) {console.log('stderr: ' + data); // handle piece of stderr });

子進程可能崩潰或正常結束其工作:

child.on('error', function(error){// handle child crashconsole.log('error: ' + error); }); child.on('exit', function (code, signal) {// this is called after child process endedconsole.log('child process exited with code ' + code); });

演示項目使用以下函數來調用fork和綁定回調:

/*** callbacks: onProcessError(error), onProcessExit(code, signal), onStdout(data), onStderr(data)*/ function callGruntfile(filename, callbacks) {var comArg, options, child;callbacks = callbacks || {};child = cp.fork('./test/call-grunt.js', [filename], {silent: true});if (callbacks.onProcessError) {child.on("error", callbacks.onProcessError);}if (callbacks.onProcessExit) {child.on("exit", callbacks.onProcessExit);}if (callbacks.onStdout) {child.stdout.on('data', callbacks.onStdout);}if (callbacks.onStderr) {child.stderr.on('data', callbacks.onStderr);} }

編寫測試

每個單元測試都調用callGruntfile函數。 回調會在標準輸出流中搜索所需的內容,檢查退出代碼是否正確,在錯誤流中出現錯誤時失敗,或者在fork調用返回錯誤時失敗。

成功場景單元測試:

pass: function(test) {var wasPassMessage = false, callbacks;test.expect(2);callbacks = {onProcessError: function(error) {test.ok(false, "Unexpected error: " + error);test.done();},onProcessExit: function(code, signal) {test.equal(code, 0, "Exit code should have been 0");test.ok(wasPassMessage, "Pass message was never sent ");test.done();},onStdout: function(data) {if (contains(data, 'Plugin worked correctly.')) {wasPassMessage = true;}},onStderr: function(data) {test.ok(false, "Stderr should have been empty: " + data);}};callGruntfile('test/gruntfile-pass.js', callbacks); }

對應于失敗場景的測試幾乎相同,可以在github上找到。

缺點

缺點:

  • 使用的grunt函數不屬于官方API。
  • 子進程輸出流以塊而不是一個大塊的形式提供。

產生

Spawn是fork和exec之間的交叉。 與exec類似,spawn能夠運行可執行文件并向其傳遞命令行參數。 子進程輸出流的處理方式與fork中的處理方式相同。 它們通過回調分段發送給父級。 因此,與使用fork一樣,僅當需要任意大小的stdout或stderr時,使用spawn才有意義。

問題

產卵的主要問題發生在Windows上。 必須準確指定要運行的命令的名稱。 如果使用參數grunt調用spawn,則spawn期望可執行文件名不帶后綴。 grunt.cmd真正的grunt可執行文件grunt.cmd 。 否則, spawn 忽略Windows環境變量PATHEXT 。

循環后綴

如果要從spawn調用grunt ,則需要執行以下操作之一:

  • 針對Windows和Linux使用不同的代碼,或者
  • 從環境中讀取PATHEXT并循環遍歷,直到找到正確的后綴。

以下函數循環遍歷PATHEXT并將正確的文件名傳遞給回調:

function findGruntFilename(callback) {var command = "grunt", options, extensionsStr, extensions, i, child, onErrorFnc, hasRightExtension = false;onErrorFnc = function(data) {if (data.message!=="spawn ENOENT"){grunt.warn("Unexpected error on spawn " +extensions[i]+ " error: " + data);}};function tryExtension(extension) {var child = cp.spawn(command + extension, ['--version']);child.on("error", onErrorFnc);child.on("exit", function(code, signal) {hasRightExtension = true;callback(command + extension);});}extensionsStr = process.env.PATHEXT || '';extensions = [''].concat(extensionsStr.split(';'));for (i=0; !hasRightExtension && i<extensions.length;i++) {tryExtension(extensions[i]);} }

編寫測試

一旦有了grunt命令名,就可以調用spawn 。 Spawn會觸發與fork完全相同的事件,因此
callGruntfile接受完全相同的回調對象,并將其屬性綁定到子進程事件:

function callGruntfile(command, filename, callbacks) {var comArg, options, child;callbacks = callbacks || {};comArg = ["--gruntfile", filename, "--no-color"];options = {cwd: 'test/'};child = cp.spawn(command, comArg, options);if (callbacks.onProcessError) {child.on("error", callbacks.onProcessError);}/* ... callbacks binding exactly as in fork ...*/ }

測試也幾乎與上一章中的測試相同。 唯一的區別是,在執行其他所有操作之前,您必須先找到grunt可執行文件名。 成功場景測試如下所示:

pass: function(test) {var wasPassMessage = false;test.expect(2);findGruntFilename(function(gruntCommand){var callbacks = {/* ... callbacks look exactly the same way as in fork ... */};callGruntfile(gruntCommand, 'gruntfile-pass.js', callbacks);}); }

完整的成功方案測試以及兩個失敗方案測試都可以在github上獲得 。

缺點

缺點:

  • Spawn會忽略PATHEXT后綴,需要使用自定義代碼來處理它。
  • 子進程輸出流以塊而不是一個大塊的形式提供。

結論

有三種方法可以從gruntfile內部測試grunt插件。 除非您有非常強烈的理由不這樣做,否則請使用exec 。

翻譯自: https://www.javacodegeeks.com/2015/02/testing-grunt-plugin-from-grunt.html

grunt 插件

總結

以上是生活随笔為你收集整理的grunt 插件_从Grunt测试Grunt插件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 色婷婷久 | 日韩每日更新 | 深夜免费在线视频 | 啪啪免费视频网站 | 日本成人精品视频 | 国产高清免费av | 青草青草视频 | 中字幕视频在线永久在线观看免费 | 日韩av线上 | 涩涩成人 | 最新日韩精品 | 麻豆传媒网 | 黄片一区二区 | 欧美一区二区三区在线观看视频 | 97精品人妻麻豆一区二区 | 亚洲狼人综合网 | ass亚洲熟妇毛耸耸pics | 亚洲黄网在线 | 欧美日韩a | 欧美极品一区二区三区 | 色视频国产 | 国产一线二线三线在线观看 | 狠狠干在线 | 日本成人免费观看 | 精品在线观看一区二区 | 欧美爱爱网 | 欧美精品在线播放 | 国产精品无码久久久久高潮 | 免费一级特黄特色毛片久久看 | 午夜视频福利在线观看 | 蜜臀av无码精品人妻色欲 | 岳狂躁岳丰满少妇大叫 | 一区二区三区影院 | 中文字幕在线高清 | 久久一精品 | 欧洲av无码放荡人妇网站 | 亚洲国产aaa | 国产精品av久久久久久无 | 欧美又黑又粗 | 手机av电影在线 | 四虎影院在线免费播放 | 奇米二区| 日本熟妇一区二区 | 69av网站| 1769国产精品 | 91尤物国产福利在线观看 | 青青草成人在线 | 欧美日韩www | 黄色国产网站 | 国产午夜精品久久久久久久久久 | 在线精品视频一区 | 日本黄色片| 天堂中文视频 | 欧美999| 五月丁香综合激情六月久久 | 天堂av观看 | 波多一区 | 性饥渴的农村熟妇 | 欧美另类v| 国产爆操视频 | 成熟丰满熟妇高潮xxxxx视频 | 九九热色| 成人免费av网站 | 国产精品一线二线三线 | 性生交生活影碟片 | 久久久久久久久久一级 | 国产九九在线 | 欧美另类在线视频 | 婷婷激情成人 | 99久久精品日本一区二区免费 | 伊人精品一区二区三区 | 日韩av色| 无套日出白浆 | 麻豆视频精品 | 巨物撞击尤物少妇呻吟 | 成人五区| 秋霞一级全黄大片 | 亚洲色图丝袜美腿 | 日日干夜夜干 | 污污在线免费观看 | 国产真实自拍 | 厕拍极品 | 深爱激情久久 | 色婷婷综合久久久久中文一区二区 | 亚洲黄网站在线观看 | 久久婷婷热 | 日韩欧美大片在线观看 | 欧美一级一片 | 中文字幕国产精品 | 欧美成年人网站 | 精品乱码一区二区三区四区 | wwwav视频| 调教91 | 欧美日韩中文字幕在线播放 | 成人黄色片免费看 | 日韩三级小视频 | 久久精品视频在线播放 | 国产视频第二页 | 日韩毛片一区 |