mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge branch 'master' into context-store-logging
This commit is contained in:
commit
bf5d36d6bd
61
CHANGELOG.md
61
CHANGELOG.md
@ -1,3 +1,64 @@
|
|||||||
|
#### 0.19: Milestone Release
|
||||||
|
|
||||||
|
Editor
|
||||||
|
|
||||||
|
- Add Context data sidebar
|
||||||
|
- Index all node properties when searching Fixes #1446
|
||||||
|
- Handle NaN and Infinity properly in debug sidebar Fixes #1778 #1779
|
||||||
|
- Prevent horizontal scroll when palette name cannot wrap
|
||||||
|
- Ignore middle-click on node/ports to enable panning
|
||||||
|
- Better wire layout when looping back
|
||||||
|
- fix appearence of retry button of remote branch management dialog
|
||||||
|
- Handle releasing ctrl when using quick-add node dialog
|
||||||
|
- Add $env function to JSONata expressions
|
||||||
|
- Widen support for env var to use ${} or $() syntax
|
||||||
|
- Add env-var support to TypedInput
|
||||||
|
- Show unknown node properties in info tab
|
||||||
|
- Add node icon picker widget
|
||||||
|
- Only edit nodes on dbl click on primary button with no modifiers
|
||||||
|
- Allow subflows to be put in any palette category
|
||||||
|
- Add flow navigator widget
|
||||||
|
- Cache flow library result to improve response time Fixes #1753
|
||||||
|
- Add middle-button-drag to pan the workspace
|
||||||
|
- allow multi-line category name in editor
|
||||||
|
- Redesign sidebar tabs
|
||||||
|
- Do not disable the export-clipboard menu option with empty selection
|
||||||
|
|
||||||
|
Nodes
|
||||||
|
|
||||||
|
- Change: Ensure runtime errors in Change node can be caught Fixes #1769
|
||||||
|
- File: Add output to File Out node
|
||||||
|
- Function: add expandable JavaScript editor pane
|
||||||
|
- Function: allow id and name reference in function node code (#1731)
|
||||||
|
- HTTP Request: Move to request module
|
||||||
|
- HTTP: Ensure apiMaxLength applies to HTTP Nodes Fixes #1278
|
||||||
|
- Join: accumulate top level properties
|
||||||
|
- Join: allow environment variable as reduce init value
|
||||||
|
- JSON: add JSON schema validation via msg.schema
|
||||||
|
- Pi: Let nrgpio code work with python 3
|
||||||
|
- Pi: let Pi nodes be visible/editable on all platforms
|
||||||
|
- Switch: add isEmpty rule
|
||||||
|
- TCP: queue messages while connecting; closes #1414
|
||||||
|
- TLS: Add servername option to TLS config node for SNI Fixes #1805
|
||||||
|
- UDP: Don't accidentally re-use udp port when set to not do so
|
||||||
|
|
||||||
|
Persistent Context
|
||||||
|
|
||||||
|
- Add persistable context option
|
||||||
|
- Add default memory store
|
||||||
|
- Add file-based context store
|
||||||
|
- Add async mode to evaluateJSONataExpression
|
||||||
|
- Update RED.util.evaluateNodeProperty to support context stores
|
||||||
|
|
||||||
|
Runtime
|
||||||
|
|
||||||
|
- Support flow.disabled and .info in /flow API
|
||||||
|
- Node errors should be Strings not Errors Fixes #1781
|
||||||
|
- Add detection of connection timeout in git communication Fixes #1770
|
||||||
|
- Handle loading empty nodesDir
|
||||||
|
- Add 'private' property to userDir generated package.json
|
||||||
|
- Add RED.require to allow nodes to access other modules
|
||||||
|
|
||||||
#### 0.18.7: Maintenance Release
|
#### 0.18.7: Maintenance Release
|
||||||
|
|
||||||
Editor Fixes
|
Editor Fixes
|
||||||
|
@ -706,7 +706,7 @@ RED.editor = (function() {
|
|||||||
pickerBackground.on("mousedown", hide);
|
pickerBackground.on("mousedown", hide);
|
||||||
|
|
||||||
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(picker);
|
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(picker);
|
||||||
searchInput = $('<input type="text">').attr("placeholder","Search icons").appendTo(searchDiv).searchBox({
|
searchInput = $('<input type="text">').attr("placeholder",RED._("editor.searchIcons")).appendTo(searchDiv).searchBox({
|
||||||
delay: 50,
|
delay: 50,
|
||||||
change: function() {
|
change: function() {
|
||||||
var searchTerm = $(this).val().trim();
|
var searchTerm = $(this).val().trim();
|
||||||
@ -730,7 +730,7 @@ RED.editor = (function() {
|
|||||||
var iconList = $('<div class="red-ui-icon-list">').appendTo(picker);
|
var iconList = $('<div class="red-ui-icon-list">').appendTo(picker);
|
||||||
var metaRow = $('<div class="red-ui-icon-meta"></div>').appendTo(picker);
|
var metaRow = $('<div class="red-ui-icon-meta"></div>').appendTo(picker);
|
||||||
var summary = $('<span>').appendTo(metaRow);
|
var summary = $('<span>').appendTo(metaRow);
|
||||||
var resetButton = $('<button class="editor-button editor-button-small">use default</button>').appendTo(metaRow).click(function(e) {
|
var resetButton = $('<button class="editor-button editor-button-small">'+RED._("editor.useDefault")+'</button>').appendTo(metaRow).click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
hide();
|
hide();
|
||||||
done(null);
|
done(null);
|
||||||
|
@ -162,7 +162,7 @@
|
|||||||
$("#node-input-op1").typedInput({
|
$("#node-input-op1").typedInput({
|
||||||
default: 'str',
|
default: 'str',
|
||||||
typeField: $("#node-input-op1type"),
|
typeField: $("#node-input-op1type"),
|
||||||
types:['flow','global','str','num','bool','json',
|
types:['flow','global','str','num','bool','json','bin','date','env',
|
||||||
optionPayload,
|
optionPayload,
|
||||||
optionNothing
|
optionNothing
|
||||||
]
|
]
|
||||||
@ -170,7 +170,7 @@
|
|||||||
$("#node-input-op2").typedInput({
|
$("#node-input-op2").typedInput({
|
||||||
default: 'str',
|
default: 'str',
|
||||||
typeField: $("#node-input-op2type"),
|
typeField: $("#node-input-op2type"),
|
||||||
types:['flow','global','str','num','bool','json',
|
types:['flow','global','str','num','bool','json','bin','date','env',
|
||||||
optionOriginalPayload,
|
optionOriginalPayload,
|
||||||
optionLatestPayload,
|
optionLatestPayload,
|
||||||
optionNothing
|
optionNothing
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<dt class="optional">kill <span class="property-type">文字列</span></dt>
|
<dt class="optional">kill <span class="property-type">文字列</span></dt>
|
||||||
<dd>execノードのプロセスに対して送るシグナルの種別を指定します</dd>
|
<dd>execノードのプロセスに対して送るシグナルの種別を指定します</dd>
|
||||||
<dt class="optional">pid <span class="property-type">数値|文字列</span></dt>
|
<dt class="optional">pid <span class="property-type">数値|文字列</span></dt>
|
||||||
<dd>シグナル送信対象のexecノードのプロセスID</dd>
|
<dd>シグナル送信対象のexecノードのプロセスIDを指定します</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h3>出力</h3>
|
<h3>出力</h3>
|
||||||
@ -60,13 +60,12 @@
|
|||||||
</ol>
|
</ol>
|
||||||
<h3>詳細</h3>
|
<h3>詳細</h3>
|
||||||
<p>デフォルトでは、<code>exec</code>システムコールを用いてコマンドを呼び出してその完了を待ち、出力を返します。例えば、コマンドの実行が成功した場合には、<code>{ code: 0 }</code>と言う返却値を返します。</p>
|
<p>デフォルトでは、<code>exec</code>システムコールを用いてコマンドを呼び出してその完了を待ち、出力を返します。例えば、コマンドの実行が成功した場合には、<code>{ code: 0 }</code>と言う返却値を返します。</p>
|
||||||
<p><code>spawn</code>を使ってコマンドを実行し、
|
<p><code>spawn</code>を使ってコマンドを実行し、標準出力および標準エラー出力へ出力を返すようにすることもできます。この場合、通常1行毎に値を返します。コマンドの実行が完了すると、3番目の端子にオブジェクトを出力します。例えば、コマンドの実行が成功した場合には、<code>{ code: 0 }</code>という返却値を返します。</p>
|
||||||
標準出力および標準エラー出力へ出力を返すようにすることもできます。この場合、通常1行毎に値を返します。コマンドの実行が完了すると、3番目の端子にオブジェクトを出力します。例えば、コマンドの実行が成功した場合には、<code>{ code: 0 }</code>と言う返却値を返します。</p>
|
|
||||||
<p>エラー発生時には、3番目の端子の<code>msg.payload</code>に<code>message</code>、<code>signal</code>など付加情報を返します。</p>
|
<p>エラー発生時には、3番目の端子の<code>msg.payload</code>に<code>message</code>、<code>signal</code>など付加情報を返します。</p>
|
||||||
<p>実行対象のコマンドはノード設定で定義します。<code>msg.payload</code>や追加引数をコマンドに追加することもできます。</p>
|
<p>実行対象のコマンドはノード設定で定義します。<code>msg.payload</code>や追加引数をコマンドに追加することもできます。</p>
|
||||||
<p>コマンドもしくはパラメータが空白を含む場合には、引用符で囲みます。- <code>"This is a single parameter"</code></p>
|
<p>コマンドもしくはパラメータが空白を含む場合には、引用符で囲みます。- <code>"これは一つのパラメータです"</code></p>
|
||||||
<p>返却する<code>payload</code>は通常<i>文字列</i>ですが、UTF8文字以外が存在すると<i>バッファ</i>となります。</p>
|
<p>返却する<code>payload</code>は通常<i>文字列</i>ですが、UTF8文字以外が存在すると<i>バッファ</i>となります。</p>
|
||||||
<p>ノードが実行中の場合、ステータスアイコンとPIDを表示します。この状態変化は<code>status</code>ノードで検知できます。</p>
|
<p>ノードが実行中の場合、ステータスアイコンとPIDを表示します。この状態変化は<code>Status</code>ノードで検知できます。</p>
|
||||||
<h4>プロセスの停止</h4>
|
<h4>プロセスの停止</h4>
|
||||||
<p><code>msg.kill</code>を受信すると、実行中のプロセスを停止することができます。<code>msg.kill</code>には送出するシグナルの種別を指定します。例えば、<code>SIGINT</code>、<code>SIGQUIT</code>、<code>SIGHUP</code>などです。空の文字列を指定した場合には、<code>SIGTERM</code>を指定したものとみなします。</p>
|
<p><code>msg.kill</code>を受信すると、実行中のプロセスを停止することができます。<code>msg.kill</code>には送出するシグナルの種別を指定します。例えば、<code>SIGINT</code>、<code>SIGQUIT</code>、<code>SIGHUP</code>などです。空の文字列を指定した場合には、<code>SIGTERM</code>を指定したものとみなします。</p>
|
||||||
<p>ノードが1つ以上のプロセスを実行している場合、<code>msg.pid</code>に停止対象のPIDを指定しなければなりません。</p>
|
<p>ノードが1つ以上のプロセスを実行している場合、<code>msg.pid</code>に停止対象のPIDを指定しなければなりません。</p>
|
||||||
|
@ -30,7 +30,9 @@
|
|||||||
<dt class="optional">payload</dt>
|
<dt class="optional">payload</dt>
|
||||||
<dd>リクエストボディとして送るデータ</dd>
|
<dd>リクエストボディとして送るデータ</dd>
|
||||||
<dt class="optional">rejectUnauthorized</dt>
|
<dt class="optional">rejectUnauthorized</dt>
|
||||||
<dd><code>true</code>をセットすると、自己署名証明書を使用するhttpsサイトへのリクエストを許可します。</dd>
|
<dd><code>false</code>をセットすると、自己署名証明書を使用するhttpsサイトへのリクエストを許可します。</dd>
|
||||||
|
<dt class="optional">followRedirects</dt>
|
||||||
|
<dd><code>false</code>をセットすると、リダイレクトを行いません。デフォルトは<code>true</code>です。</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h3>出力</h3>
|
<h3>出力</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
|
@ -29,7 +29,11 @@
|
|||||||
<li><b>その他</b> - これより前のルールにマッチするものがなかった場合に適用</li>
|
<li><b>その他</b> - これより前のルールにマッチするものがなかった場合に適用</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
<h3>注釈</h3>
|
||||||
|
<p><code>is true/false</code>と<code>is null</code>のルールは、型に対して厳密な比較を行います。型変換した上での比較はしません。</p>
|
||||||
|
<p><code>is empty</code>のルールは、長さ0の文字列・配列・バッファ、またはプロパティを持たないオブジェクトを出力します。<code>null</code>や<code>undefined</code>は出力しません。</p>
|
||||||
|
|
||||||
<h3>メッセージ列の扱い</h3>
|
<h3>メッセージ列の扱い</h3>
|
||||||
<p>switchノードは入力メッセージの列に関する情報を保持する<code>msg.parts</code>をデフォルトでは変更しません。</p>
|
<p>switchノードは入力メッセージの列に関する情報を保持する<code>msg.parts</code>をデフォルトでは変更しません。</p>
|
||||||
<p>「<b>メッセージ列の補正</b>」オプションを指定すると、マッチした各ルールに対して新しいメッセージ列を生成します。このモードでは、switchノードは新たなメッセージ列を送信する前に、入力メッセージ列全体を内部に蓄積します。<code>nodeMessageBufferMaxLength</code>を設定すると、蓄積するメッセージ数を制限できます。</p>
|
<p>「<b>メッセージ列の補正</b>」オプションを指定すると、マッチした各ルールに対して新しいメッセージ列を生成します。このモードでは、switchノードは新たなメッセージ列を送信する前に、入力メッセージ列全体を内部に蓄積します。<b>settings.js</b>の<code>nodeMessageBufferMaxLength</code>を設定すると、蓄積するメッセージ数を制限できます。</p>
|
||||||
</script>
|
</script>
|
||||||
|
@ -30,5 +30,5 @@
|
|||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h4>メッセージの蓄積</h4>
|
<h4>メッセージの蓄積</h4>
|
||||||
<p>このノードの処理ではメッセージ列の処理のためメッセージを内部に蓄積します。<code>nodeMessageBufferMaxLength</code>を指定することで蓄積するメッセージの最大値を制限することができます。</p>
|
<p>このノードの処理ではメッセージ列の処理のためメッセージを内部に蓄積します。<b>settings.js</b>の<code>nodeMessageBufferMaxLength</code>を指定することで蓄積するメッセージの最大値を制限することができます。</p>
|
||||||
</script>
|
</script>
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt>payload<span class="property-type">オブジェクト | 文字列</span></dt>
|
<dt>payload<span class="property-type">オブジェクト | 文字列</span></dt>
|
||||||
<dd>JavaScriptオブジェクトもしくはJSON文字列</dd>
|
<dd>JavaScriptオブジェクトもしくはJSON文字列</dd>
|
||||||
|
<dt>schema<span class="property-type">オブジェクト</span></dt>
|
||||||
|
<dd>JSONの検証に利用するJSONスキーマ。設定されていない場合は検証を行いません。</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h3>出力</h3>
|
<h3>出力</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
@ -30,9 +32,12 @@
|
|||||||
<li>入力がJavaScriptオブジェクトの場合、JSON文字列に変換します。JSON文字列は整形することも可能です。</li>
|
<li>入力がJavaScriptオブジェクトの場合、JSON文字列に変換します。JSON文字列は整形することも可能です。</li>
|
||||||
</ul>
|
</ul>
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt>schemaError<span class="property-type">配列</span></dt>
|
||||||
|
<dd>JSONの検証でエラーが発生した場合、Catchノードを利用し、エラーを配列として<code>schemaError</code>プロパティから取得することができます。</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h3>詳細</h3>
|
<h3>詳細</h3>
|
||||||
<p>デフォルトの変換対象は<code>msg.payload</code>ですが、他のメッセージプロパティを変換対象とすることも可能です。</p>
|
<p>デフォルトの変換対象は<code>msg.payload</code>ですが、他のメッセージプロパティを変換対象とすることも可能です。</p>
|
||||||
<p>双方向の変換を自動選択するのではなく、特定の変換のみ行うように設定できます。この機能は、例えば、<code>HTTP In</code>ノードに対するリクエストがcontent-typeを正しく設定していない場合であっても、JSONノードによる変換結果がJavaScriptオブジェクトであることを保証するために利用します。</p>
|
<p>双方向の変換を自動選択するのではなく、特定の変換のみ行うように設定できます。この機能は、例えば、<code>HTTP In</code>ノードに対するリクエストがcontent-typeを正しく設定していない場合であっても、JSONノードによる変換結果がJavaScriptオブジェクトであることを保証するために利用します。</p>
|
||||||
<p>JSON文字列への変換が指定されている場合、受信した文字列に対してさらなるチェックは行いません。すなわち、文字列がJSONとして正しいかどうかの検査や、整形オプションを指定していたとしても整形処理を実施しません。</p>
|
<p>JSON文字列への変換が指定されている場合、受信した文字列に対してさらなるチェックは行いません。すなわち、文字列がJSONとして正しいかどうかの検査や、整形オプションを指定していたとしても整形処理を実施しません。</p>
|
||||||
|
<p>JSONスキーマの詳細については、<a href="http://json-schema.org/latest/json-schema-validation.html">こちら</a>を参照してください。</p>
|
||||||
</script>
|
</script>
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
<dt class="optional">filename <span class="property-type">文字列</span></dt>
|
<dt class="optional">filename <span class="property-type">文字列</span></dt>
|
||||||
<dd>対象ファイル名をノードに設定していない場合、このプロパティでファイルを指定できます</dd>
|
<dd>対象ファイル名をノードに設定していない場合、このプロパティでファイルを指定できます</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
<h3>出力</h3>
|
||||||
|
<p>書き込みの完了時、入力メッセージを出力端子に送出します。</p>
|
||||||
<h3>詳細</h3>
|
<h3>詳細</h3>
|
||||||
<p>入力メッセージのペイロードをファイルの最後に追記します。改行(\n)を各データの最後に追加することもできます。</p>
|
<p>入力メッセージのペイロードをファイルの最後に追記します。改行(\n)を各データの最後に追加することもできます。</p>
|
||||||
<p><code>msg.filename</code>を使う場合、書き込みを行う毎にファイルをクローズします。より良い性能を得るためにはファイル名をノードに設定してください。</p>
|
<p><code>msg.filename</code>を使う場合、書き込みを行う毎にファイルをクローズします。より良い性能を得るためにはファイル名をノードに設定してください。</p>
|
||||||
|
@ -147,7 +147,7 @@
|
|||||||
}
|
}
|
||||||
if ((rule.t === 'btwn') || (rule.t === 'index')) {
|
if ((rule.t === 'btwn') || (rule.t === 'index')) {
|
||||||
label += " "+getValueLabel(rule.vt,rule.v)+" & "+getValueLabel(rule.v2t,rule.v2);
|
label += " "+getValueLabel(rule.vt,rule.v)+" & "+getValueLabel(rule.v2t,rule.v2);
|
||||||
} else if (rule.t !== 'true' && rule.t !== 'false' && rule.t !== 'null' && rule.t !== 'nnull' && rule.t !== 'else' ) {
|
} else if (rule.t !== 'true' && rule.t !== 'false' && rule.t !== 'null' && rule.t !== 'nnull' && rule.t !== 'empty' && rule.t !== 'nempty' && rule.t !== 'else' ) {
|
||||||
label += " "+getValueLabel(rule.vt,rule.v);
|
label += " "+getValueLabel(rule.vt,rule.v);
|
||||||
}
|
}
|
||||||
return label;
|
return label;
|
||||||
@ -199,7 +199,7 @@
|
|||||||
} else if (type === "istype") {
|
} else if (type === "istype") {
|
||||||
typeField.typedInput("width",(newWidth-selectWidth-70));
|
typeField.typedInput("width",(newWidth-selectWidth-70));
|
||||||
} else {
|
} else {
|
||||||
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
|
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "empty" || type === "nempty" || type === "else") {
|
||||||
// valueField.hide();
|
// valueField.hide();
|
||||||
} else {
|
} else {
|
||||||
valueField.typedInput("width",(newWidth-selectWidth-70));
|
valueField.typedInput("width",(newWidth-selectWidth-70));
|
||||||
@ -295,7 +295,7 @@
|
|||||||
numValueField.typedInput('hide');
|
numValueField.typedInput('hide');
|
||||||
typeValueField.typedInput('hide');
|
typeValueField.typedInput('hide');
|
||||||
valueField.typedInput('hide');
|
valueField.typedInput('hide');
|
||||||
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
|
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "empty" || type === "nempty" || type === "else") {
|
||||||
valueField.typedInput('hide');
|
valueField.typedInput('hide');
|
||||||
typeValueField.typedInput('hide');
|
typeValueField.typedInput('hide');
|
||||||
}
|
}
|
||||||
@ -396,7 +396,7 @@
|
|||||||
var rule = $(this);
|
var rule = $(this);
|
||||||
var type = rule.find("select").val();
|
var type = rule.find("select").val();
|
||||||
var r = {t:type};
|
var r = {t:type};
|
||||||
if (!(type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else")) {
|
if (!(type === "true" || type === "false" || type === "null" || type === "nnull" || type === "empty" || type === "nempty" || type === "else")) {
|
||||||
if ((type === "btwn") || (type === "index")) {
|
if ((type === "btwn") || (type === "index")) {
|
||||||
r.v = rule.find(".node-input-rule-btwn-value").typedInput('value');
|
r.v = rule.find(".node-input-rule-btwn-value").typedInput('value');
|
||||||
r.vt = rule.find(".node-input-rule-btwn-value").typedInput('type');
|
r.vt = rule.find(".node-input-rule-btwn-value").typedInput('type');
|
||||||
|
@ -34,7 +34,7 @@ module.exports = function(RED) {
|
|||||||
'empty': function(a) {
|
'empty': function(a) {
|
||||||
if (typeof a === 'string' || Array.isArray(a) || Buffer.isBuffer(a)) {
|
if (typeof a === 'string' || Array.isArray(a) || Buffer.isBuffer(a)) {
|
||||||
return a.length === 0;
|
return a.length === 0;
|
||||||
} else if (typeof a === 'object') {
|
} else if (typeof a === 'object' && a !== null) {
|
||||||
return Object.keys(a).length === 0;
|
return Object.keys(a).length === 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -42,7 +42,7 @@ module.exports = function(RED) {
|
|||||||
'nempty': function(a) {
|
'nempty': function(a) {
|
||||||
if (typeof a === 'string' || Array.isArray(a) || Buffer.isBuffer(a)) {
|
if (typeof a === 'string' || Array.isArray(a) || Buffer.isBuffer(a)) {
|
||||||
return a.length !== 0;
|
return a.length !== 0;
|
||||||
} else if (typeof a === 'object') {
|
} else if (typeof a === 'object' && a !== null) {
|
||||||
return Object.keys(a).length !== 0;
|
return Object.keys(a).length !== 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -143,7 +143,7 @@ module.exports = function(RED) {
|
|||||||
if (rule.fromt === "msg") {
|
if (rule.fromt === "msg") {
|
||||||
resolve(RED.util.getMessageProperty(msg,rule.from));
|
resolve(RED.util.getMessageProperty(msg,rule.from));
|
||||||
} else if (rule.fromt === 'flow' || rule.fromt === 'global') {
|
} else if (rule.fromt === 'flow' || rule.fromt === 'global') {
|
||||||
var contextKey = RED.util.parseContextStore(rule.from);
|
var contextKey = RED.util.parseContextStore(rule.from);
|
||||||
node.context()[rule.fromt].get(contextKey.key, contextKey.store, (err,fromValue) => {
|
node.context()[rule.fromt].get(contextKey.key, contextKey.store, (err,fromValue) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
@ -166,12 +166,10 @@ module.exports = function(RED) {
|
|||||||
try {
|
try {
|
||||||
fromRE = new RegExp(fromRE, "g");
|
fromRE = new RegExp(fromRE, "g");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject(new Error(RED._("change.errors.invalid-from",{error:e.message})));
|
return Promise.reject(new Error(RED._("change.errors.invalid-from",{error:e.message})));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reject(new Error(RED._("change.errors.invalid-from",{error:"unsupported type: "+(typeof fromValue)})));
|
return Promise.reject(new Error(RED._("change.errors.invalid-from",{error:"unsupported type: "+(typeof fromValue)})));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
fromType,
|
fromType,
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
<dt class="optional">filename <span class="property-type">string</span></dt>
|
<dt class="optional">filename <span class="property-type">string</span></dt>
|
||||||
<dd>If not configured in the node, this optional property sets the name of the file to be updated.</dd>
|
<dd>If not configured in the node, this optional property sets the name of the file to be updated.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
<h3>Output</h3>
|
||||||
|
<p>On completion of write, input message is sent to output port.</p>
|
||||||
<h3>Details</h3>
|
<h3>Details</h3>
|
||||||
<p>Each message payload will be added to the end of the file, optionally appending
|
<p>Each message payload will be added to the end of the file, optionally appending
|
||||||
a newline (\n) character between each one.</p>
|
a newline (\n) character between each one.</p>
|
||||||
|
@ -265,6 +265,8 @@
|
|||||||
"settingIcon": "Icon",
|
"settingIcon": "Icon",
|
||||||
"noDefaultLabel": "none",
|
"noDefaultLabel": "none",
|
||||||
"defaultLabel": "use default label",
|
"defaultLabel": "use default label",
|
||||||
|
"searchIcons": "Search icons",
|
||||||
|
"useDefault": "use default",
|
||||||
"errors": {
|
"errors": {
|
||||||
"scopeChange": "Changing the scope will make it unavailable to nodes in other flows that use it"
|
"scopeChange": "Changing the scope will make it unavailable to nodes in other flows that use it"
|
||||||
}
|
}
|
||||||
|
@ -264,6 +264,8 @@
|
|||||||
"settingIcon": "アイコン",
|
"settingIcon": "アイコン",
|
||||||
"noDefaultLabel": "なし",
|
"noDefaultLabel": "なし",
|
||||||
"defaultLabel": "既定の名前を使用",
|
"defaultLabel": "既定の名前を使用",
|
||||||
|
"searchIcons": "アイコンを検索",
|
||||||
|
"useDefault": "デフォルトを使用",
|
||||||
"errors": {
|
"errors": {
|
||||||
"scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします"
|
"scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします"
|
||||||
}
|
}
|
||||||
@ -455,8 +457,14 @@
|
|||||||
"filtered": "__count__ 個が無効"
|
"filtered": "__count__ 個が無効"
|
||||||
},
|
},
|
||||||
"context": {
|
"context": {
|
||||||
"name": "コンテキスト",
|
"name": "コンテキストデータ",
|
||||||
"label": "コンテキスト"
|
"label": "コンテキストデータ",
|
||||||
|
"none": "選択されていません",
|
||||||
|
"refresh": "読み込みのため更新してください",
|
||||||
|
"empty": "データが存在しません",
|
||||||
|
"node": "Node",
|
||||||
|
"flow": "Flow",
|
||||||
|
"global": "Global"
|
||||||
},
|
},
|
||||||
"palette": {
|
"palette": {
|
||||||
"name": "パレットの管理",
|
"name": "パレットの管理",
|
||||||
@ -637,6 +645,9 @@
|
|||||||
"eval": "表現評価エラー:\n __message__"
|
"eval": "表現評価エラー:\n __message__"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jsEditor": {
|
||||||
|
"title": "JavaScriptエディタ"
|
||||||
|
},
|
||||||
"jsonEditor": {
|
"jsonEditor": {
|
||||||
"title": "JSONエディタ",
|
"title": "JSONエディタ",
|
||||||
"format": "JSONフォーマット"
|
"format": "JSONフォーマット"
|
||||||
|
@ -203,6 +203,8 @@ LocalFileSystem.prototype.set = function(scope, key, value, callback) {
|
|||||||
var storagePath = getStoragePath(this.storageBaseDir ,scope);
|
var storagePath = getStoragePath(this.storageBaseDir ,scope);
|
||||||
fs.outputFile(storagePath + ".json", JSON.stringify(newContext, undefined, 4), "utf8").catch(function(err) {
|
fs.outputFile(storagePath + ".json", JSON.stringify(newContext, undefined, 4), "utf8").catch(function(err) {
|
||||||
});
|
});
|
||||||
|
} else if (callback && typeof callback !== 'function') {
|
||||||
|
throw new Error("Callback must be a function");
|
||||||
} else {
|
} else {
|
||||||
this._set(scope,key,value,callback);
|
this._set(scope,key,value,callback);
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ util.inherits(injectNode, nodePage);
|
|||||||
var payloadType = {
|
var payloadType = {
|
||||||
"flow": 1,
|
"flow": 1,
|
||||||
"global": 2,
|
"global": 2,
|
||||||
"string": 3,
|
"str": 3,
|
||||||
"num": 4,
|
"num": 4,
|
||||||
"bool": 5,
|
"bool": 5,
|
||||||
"json": 6,
|
"json": 6,
|
||||||
@ -43,6 +43,13 @@ var timeType = {
|
|||||||
"atASpecificTime": 4,
|
"atASpecificTime": 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var timeType = {
|
||||||
|
"none": 1,
|
||||||
|
"interval": 2,
|
||||||
|
"intervalBetweenTimes": 3,
|
||||||
|
"atASpecificTime": 4,
|
||||||
|
};
|
||||||
|
|
||||||
injectNode.prototype.setPayload = function(type, value) {
|
injectNode.prototype.setPayload = function(type, value) {
|
||||||
// Open a payload type list.
|
// Open a payload type list.
|
||||||
browser.clickWithWait('//*[contains(@class, "red-ui-typedInput-container")]');
|
browser.clickWithWait('//*[contains(@class, "red-ui-typedInput-container")]');
|
||||||
|
@ -24,4 +24,23 @@ function debugNode(id) {
|
|||||||
|
|
||||||
util.inherits(debugNode, nodePage);
|
util.inherits(debugNode, nodePage);
|
||||||
|
|
||||||
|
var target = {
|
||||||
|
"msg": 1,
|
||||||
|
"full": 2
|
||||||
|
};
|
||||||
|
|
||||||
|
debugNode.prototype.setTarget = function(type, value) {
|
||||||
|
// Open a payload type list.
|
||||||
|
browser.clickWithWait('//*[contains(@class, "red-ui-typedInput-container")]/button');
|
||||||
|
// Select a payload type.
|
||||||
|
var xPath = '/html/body/div[11]/a[' + target[type] + ']';
|
||||||
|
browser.clickWithWait(xPath);
|
||||||
|
if (value) {
|
||||||
|
browser.clickWithWait('//*[contains(@class, "red-ui-typedInput-input")]/input');
|
||||||
|
browser.keys(['Control', 'a', 'Control']);
|
||||||
|
browser.keys(['Delete']);
|
||||||
|
browser.setValue('//*[contains(@class, "red-ui-typedInput-input")]/input', value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = debugNode;
|
module.exports = debugNode;
|
||||||
|
35
test/editor/pageobjects/nodes/core/core/80-function_page.js
Normal file
35
test/editor/pageobjects/nodes/core/core/80-function_page.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var util = require("util");
|
||||||
|
|
||||||
|
var nodePage = require("../../node_page");
|
||||||
|
|
||||||
|
function functionNode(id) {
|
||||||
|
nodePage.call(this, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(functionNode, nodePage);
|
||||||
|
|
||||||
|
functionNode.prototype.setCode = function(value) {
|
||||||
|
browser.click('#node-input-func-editor');
|
||||||
|
browser.keys(['Control', 'Home', 'Control']);
|
||||||
|
for (var i=0; i<value.length; i++) {
|
||||||
|
browser.keys([value.substr(i, 1)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = functionNode;
|
55
test/editor/pageobjects/nodes/core/core/80-template_page.js
Normal file
55
test/editor/pageobjects/nodes/core/core/80-template_page.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var util = require("util");
|
||||||
|
|
||||||
|
var nodePage = require("../../node_page");
|
||||||
|
|
||||||
|
function templateNode(id) {
|
||||||
|
nodePage.call(this, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(templateNode, nodePage);
|
||||||
|
|
||||||
|
var syntaxType = {
|
||||||
|
"mustache": 1,
|
||||||
|
"plain": 2
|
||||||
|
};
|
||||||
|
|
||||||
|
templateNode.prototype.setSyntax = function(type) {
|
||||||
|
// Open a method type list.
|
||||||
|
browser.clickWithWait('#node-input-syntax');
|
||||||
|
// Select a method type.
|
||||||
|
var syntaxTypeXPath = '//*[@id="node-input-syntax"]/option[' + syntaxType[type] + ']';
|
||||||
|
browser.clickWithWait(syntaxTypeXPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
templateNode.prototype.setFormat = function(type) {
|
||||||
|
browser.selectByValue('#node-input-format', type);
|
||||||
|
}
|
||||||
|
|
||||||
|
templateNode.prototype.setTemplate = function(value) {
|
||||||
|
browser.click('#node-input-template-editor');
|
||||||
|
browser.keys(['Control', 'a', 'Control']); // call twice to release the keys.
|
||||||
|
// Need to add a character one by one since some words such as 'Control' are treated as a special word.
|
||||||
|
for (var i=0; i<value.length; i++) {
|
||||||
|
browser.keys([value.charAt(i)]);
|
||||||
|
}
|
||||||
|
browser.keys(['Control', 'Shift', 'End', 'Shift', 'Control']);
|
||||||
|
browser.keys(['Delete']);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = templateNode;
|
51
test/editor/pageobjects/nodes/core/io/21-httpin_page.js
Normal file
51
test/editor/pageobjects/nodes/core/io/21-httpin_page.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var util = require("util");
|
||||||
|
|
||||||
|
var nodePage = require("../../node_page");
|
||||||
|
|
||||||
|
function httpinNode(id) {
|
||||||
|
nodePage.call(this, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMethod(type) {
|
||||||
|
browser.selectByValue('#node-input-method', type);
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(httpinNode, nodePage);
|
||||||
|
|
||||||
|
var methodType = {
|
||||||
|
"get": 1,
|
||||||
|
"post": 2,
|
||||||
|
"put": 3,
|
||||||
|
"delete": 4,
|
||||||
|
"patch": 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
httpinNode.prototype.setMethod = function(type) {
|
||||||
|
// Open a method type list.
|
||||||
|
browser.clickWithWait('#node-input-method');
|
||||||
|
// Select a method type.
|
||||||
|
var methodTypeXPath = '//*[@id="node-input-method"]/option[' + methodType[type] + ']';
|
||||||
|
browser.clickWithWait(methodTypeXPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
httpinNode.prototype.setUrl = function(value) {
|
||||||
|
browser.setValue('#node-input-url', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = httpinNode;
|
59
test/editor/pageobjects/nodes/core/io/21-httprequest_page.js
Normal file
59
test/editor/pageobjects/nodes/core/io/21-httprequest_page.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var util = require("util");
|
||||||
|
|
||||||
|
var nodePage = require("../../node_page");
|
||||||
|
|
||||||
|
function httpRequestNode(id) {
|
||||||
|
nodePage.call(this, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(httpRequestNode, nodePage);
|
||||||
|
|
||||||
|
var methodType = {
|
||||||
|
"get": 1,
|
||||||
|
"post": 2,
|
||||||
|
"put": 3,
|
||||||
|
"delete": 4,
|
||||||
|
"setByMsgMethod": 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
var retType = {
|
||||||
|
"txt": 1,
|
||||||
|
"bin": 2,
|
||||||
|
"obj": 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
httpRequestNode.prototype.setUrl = function(value) {
|
||||||
|
browser.setValue('#node-input-url', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
httpRequestNode.prototype.setMethod = function(type) {
|
||||||
|
// Open a method type list.
|
||||||
|
browser.clickWithWait('#node-input-method');
|
||||||
|
// Select a method type.
|
||||||
|
var methodTypeXPath = '//*[@id="node-input-method"]/option[' + methodType[type] + ']';
|
||||||
|
browser.clickWithWait(methodTypeXPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
httpRequestNode.prototype.setRet = function(type) {
|
||||||
|
browser.clickWithWait('#node-input-ret');
|
||||||
|
var retTypeXPath = '//*[@id="node-input-ret"]/option[' + retType[type] + ']';
|
||||||
|
browser.clickWithWait(retTypeXPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = httpRequestNode;
|
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var util = require("util");
|
||||||
|
|
||||||
|
var nodePage = require("../../node_page");
|
||||||
|
|
||||||
|
function httpResponseNode(id) {
|
||||||
|
nodePage.call(this, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(httpResponseNode, nodePage);
|
||||||
|
|
||||||
|
module.exports = httpResponseNode;
|
@ -24,14 +24,58 @@ function changeNode(id) {
|
|||||||
|
|
||||||
util.inherits(changeNode, nodePage);
|
util.inherits(changeNode, nodePage);
|
||||||
|
|
||||||
|
var tType = {
|
||||||
|
"set": 1,
|
||||||
|
"change": 2,
|
||||||
|
"delete": 3,
|
||||||
|
"move": 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
var totType = {
|
||||||
|
"msg": 1,
|
||||||
|
"flow": 2,
|
||||||
|
"global": 3,
|
||||||
|
"str": 4,
|
||||||
|
"num": 5,
|
||||||
|
"bool": 6,
|
||||||
|
"json": 7,
|
||||||
|
"bin": 8,
|
||||||
|
"date": 9,
|
||||||
|
"jsonata": 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
var ptType = {
|
||||||
|
"msg": 1,
|
||||||
|
"flow": 2,
|
||||||
|
"global": 3,
|
||||||
|
};
|
||||||
|
|
||||||
function setT(rule, index) {
|
function setT(rule, index) {
|
||||||
browser.selectByValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[1]/select', rule);
|
browser.selectByValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[1]/select', rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
changeNode.prototype.ruleSet = function(to, index) {
|
// It is better to create a function whose input value is the object type in the future,
|
||||||
|
changeNode.prototype.ruleSet = function(p, pt, to, tot, index) {
|
||||||
index = index ? index : 1;
|
index = index ? index : 1;
|
||||||
setT("set", index);
|
setT("set", index);
|
||||||
browser.setValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[2]/div[2]/div/input', to);
|
if (pt) {
|
||||||
|
browser.clickWithWait('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[1]/div/button[1]');
|
||||||
|
var num = 5 * index + 6;
|
||||||
|
var ptXPath = '/html/body/div[' + num + ']/a[' + ptType[pt] + ']';
|
||||||
|
browser.clickWithWait(ptXPath);
|
||||||
|
}
|
||||||
|
if (p) {
|
||||||
|
browser.setValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[1]/div/div/input', p);
|
||||||
|
}
|
||||||
|
if (tot) {
|
||||||
|
browser.clickWithWait('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[2]/div[2]/button[1]');
|
||||||
|
var num = 5 * index + 7;
|
||||||
|
var totXPath = '/html/body/div[' + num + ']/a[' + totType[tot] + ']';
|
||||||
|
browser.clickWithWait(totXPath);
|
||||||
|
}
|
||||||
|
if (to) {
|
||||||
|
browser.setValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[2]/div[2]/div/input' , to);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changeNode.prototype.ruleDelete = function(index) {
|
changeNode.prototype.ruleDelete = function(index) {
|
||||||
|
31
test/editor/pageobjects/nodes/core/parsers/70-HTML_page.js
Normal file
31
test/editor/pageobjects/nodes/core/parsers/70-HTML_page.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var util = require("util");
|
||||||
|
|
||||||
|
var nodePage = require("../../node_page");
|
||||||
|
|
||||||
|
function htmlNode(id) {
|
||||||
|
nodePage.call(this, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(htmlNode, nodePage);
|
||||||
|
|
||||||
|
htmlNode.prototype.setTag = function(value) {
|
||||||
|
browser.setValue('#node-input-tag', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = htmlNode;
|
@ -16,17 +16,30 @@
|
|||||||
|
|
||||||
var injectNode = require('./core/core/20-inject_page');
|
var injectNode = require('./core/core/20-inject_page');
|
||||||
var debugNode = require('./core/core/58-debug_page');
|
var debugNode = require('./core/core/58-debug_page');
|
||||||
|
var templateNode = require('./core/core/80-template_page');
|
||||||
|
var functionNode = require('./core/core/80-function_page');
|
||||||
|
var httpinNode = require('./core/io/21-httpin_page');
|
||||||
|
var httpResponseNode = require('./core/io/21-httpresponse_page');
|
||||||
var changeNode = require('./core/logic/15-change_page');
|
var changeNode = require('./core/logic/15-change_page');
|
||||||
var rangeNode = require('./core/logic/16-range_page');
|
var rangeNode = require('./core/logic/16-range_page');
|
||||||
|
var httpRequestNode = require('./core/io/21-httprequest_page');
|
||||||
|
var htmlNode = require('./core/parsers/70-HTML_page');
|
||||||
|
|
||||||
|
|
||||||
var nodeCatalog = {
|
var nodeCatalog = {
|
||||||
// input
|
// input
|
||||||
"inject": injectNode,
|
"inject": injectNode,
|
||||||
|
"httpin": httpinNode,
|
||||||
// output
|
// output
|
||||||
"debug": debugNode,
|
"debug": debugNode,
|
||||||
|
"httpResponse": httpResponseNode,
|
||||||
// function
|
// function
|
||||||
|
"function": functionNode,
|
||||||
|
"template": templateNode,
|
||||||
"change": changeNode,
|
"change": changeNode,
|
||||||
"range": rangeNode,
|
"range": rangeNode,
|
||||||
|
"httpRequest": httpRequestNode,
|
||||||
|
"html": htmlNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
function create(type, id) {
|
function create(type, id) {
|
||||||
|
@ -17,11 +17,17 @@
|
|||||||
var idMap = {
|
var idMap = {
|
||||||
// input
|
// input
|
||||||
"inject": "#palette_node_inject",
|
"inject": "#palette_node_inject",
|
||||||
|
"httpin": "#palette_node_http_in",
|
||||||
// output
|
// output
|
||||||
"debug": "#palette_node_debug",
|
"debug": "#palette_node_debug",
|
||||||
|
"httpResponse": "#palette_node_http_response",
|
||||||
// function
|
// function
|
||||||
|
"function": "#palette_node_function",
|
||||||
|
"template": "#palette_node_template",
|
||||||
"change": "#palette_node_change",
|
"change": "#palette_node_change",
|
||||||
"range": "#palette_node_range",
|
"range": "#palette_node_range",
|
||||||
|
"httpRequest": "#palette_node_http_request",
|
||||||
|
"html": "#palette_node_html",
|
||||||
};
|
};
|
||||||
|
|
||||||
function getId(type) {
|
function getId(type) {
|
||||||
|
@ -24,6 +24,8 @@ var workspace = require('../../pageobjects/workspace/workspace_page');
|
|||||||
var specUtil = require('../../pageobjects/util/spec_util_page');
|
var specUtil = require('../../pageobjects/util/spec_util_page');
|
||||||
|
|
||||||
var nodeWidth = 200;
|
var nodeWidth = 200;
|
||||||
|
var nodeHeight = 100;
|
||||||
|
var httpNodeRoot = "/api";
|
||||||
|
|
||||||
// https://cookbook.nodered.org/
|
// https://cookbook.nodered.org/
|
||||||
describe('cookbook', function() {
|
describe('cookbook', function() {
|
||||||
@ -46,7 +48,7 @@ describe('cookbook', function() {
|
|||||||
var debugNode = workspace.addNode("debug", nodeWidth * 2);
|
var debugNode = workspace.addNode("debug", nodeWidth * 2);
|
||||||
|
|
||||||
changeNode.edit();
|
changeNode.edit();
|
||||||
changeNode.ruleSet("Hello World!");
|
changeNode.ruleSet("payload", "msg", "Hello World!");
|
||||||
changeNode.clickOk();
|
changeNode.clickOk();
|
||||||
|
|
||||||
injectNode.connect(changeNode);
|
injectNode.connect(changeNode);
|
||||||
@ -150,7 +152,7 @@ describe('cookbook', function() {
|
|||||||
var debugNode = workspace.addNode("debug", nodeWidth * 2);
|
var debugNode = workspace.addNode("debug", nodeWidth * 2);
|
||||||
|
|
||||||
injectNode.edit();
|
injectNode.edit();
|
||||||
injectNode.setPayload("string", "Started!")
|
injectNode.setPayload("str", "Started!")
|
||||||
injectNode.setOnce(true);
|
injectNode.setOnce(true);
|
||||||
injectNode.clickOk();
|
injectNode.clickOk();
|
||||||
injectNode.connect(debugNode);
|
injectNode.connect(debugNode);
|
||||||
@ -185,4 +187,270 @@ describe('cookbook', function() {
|
|||||||
// skip this case since it needs up to one minite.
|
// skip this case since it needs up to one minite.
|
||||||
it.skip('trigger a flow at a specific time');
|
it.skip('trigger a flow at a specific time');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('HTTP requests', function() {
|
||||||
|
it('simple get request', function() {
|
||||||
|
var injectNode = workspace.addNode("inject");
|
||||||
|
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth);
|
||||||
|
var htmlNode = workspace.addNode("html", nodeWidth * 2);
|
||||||
|
var debugNode = workspace.addNode("debug", nodeWidth * 3);
|
||||||
|
|
||||||
|
httpRequetNode.edit();
|
||||||
|
httpRequetNode.setMethod("get");
|
||||||
|
httpRequetNode.setUrl(helper.url());
|
||||||
|
httpRequetNode.clickOk();
|
||||||
|
|
||||||
|
htmlNode.edit();
|
||||||
|
htmlNode.setTag("title");
|
||||||
|
htmlNode.clickOk();
|
||||||
|
|
||||||
|
injectNode.connect(httpRequetNode);
|
||||||
|
httpRequetNode.connect(htmlNode);
|
||||||
|
htmlNode.connect(debugNode);
|
||||||
|
|
||||||
|
workspace.deploy();
|
||||||
|
|
||||||
|
debugTab.open();
|
||||||
|
debugTab.clearMessage();
|
||||||
|
injectNode.clickLeftButton();
|
||||||
|
debugTab.getMessage().should.be.equal('"Node-RED"');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('set the URL of a request', function() {
|
||||||
|
var injectNode = workspace.addNode("inject");
|
||||||
|
var changeNode = workspace.addNode("change", nodeWidth * 1.5);
|
||||||
|
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth * 2.5);
|
||||||
|
var debugNode = workspace.addNode("debug", nodeWidth * 3.5);
|
||||||
|
|
||||||
|
injectNode.edit();
|
||||||
|
injectNode.setPayload("str", helper.url());
|
||||||
|
injectNode.clickOk();
|
||||||
|
|
||||||
|
changeNode.edit();
|
||||||
|
changeNode.ruleSet("url", "msg", "payload", "msg");
|
||||||
|
changeNode.clickOk();
|
||||||
|
|
||||||
|
injectNode.connect(changeNode);
|
||||||
|
changeNode.connect(httpRequetNode);
|
||||||
|
httpRequetNode.connect(debugNode);
|
||||||
|
|
||||||
|
workspace.deploy();
|
||||||
|
|
||||||
|
debugTab.open();
|
||||||
|
debugTab.clearMessage();
|
||||||
|
injectNode.clickLeftButton();
|
||||||
|
debugTab.getMessage().should.containEql('<title>Node-RED</title>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('set the URL of a request using a template', function() {
|
||||||
|
var injectNode = workspace.addNode("inject");
|
||||||
|
var changeNode = workspace.addNode("change", nodeWidth * 1.5);
|
||||||
|
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth * 2.5);
|
||||||
|
var debugNode = workspace.addNode("debug", nodeWidth * 3.5);
|
||||||
|
|
||||||
|
injectNode.edit();
|
||||||
|
injectNode.setPayload("str", 'settings');
|
||||||
|
injectNode.clickOk();
|
||||||
|
|
||||||
|
changeNode.edit();
|
||||||
|
changeNode.ruleSet("query", "msg", "payload", "msg");
|
||||||
|
changeNode.clickOk();
|
||||||
|
|
||||||
|
httpRequetNode.edit();
|
||||||
|
httpRequetNode.setUrl(helper.url() + "/{{{query}}}");
|
||||||
|
httpRequetNode.clickOk();
|
||||||
|
|
||||||
|
injectNode.connect(changeNode);
|
||||||
|
changeNode.connect(httpRequetNode);
|
||||||
|
httpRequetNode.connect(debugNode);
|
||||||
|
|
||||||
|
workspace.deploy();
|
||||||
|
|
||||||
|
debugTab.open();
|
||||||
|
debugTab.clearMessage();
|
||||||
|
injectNode.clickLeftButton();
|
||||||
|
debugTab.getMessage().should.containEql('httpNodeRoot');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('set the query string parameters', function() {
|
||||||
|
var injectNode = workspace.addNode("inject");
|
||||||
|
var changeNode = workspace.addNode("change", nodeWidth);
|
||||||
|
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth * 2);
|
||||||
|
var debugNode = workspace.addNode("debug", nodeWidth * 3);
|
||||||
|
|
||||||
|
injectNode.edit();
|
||||||
|
injectNode.setPayload("str", 'Nick');
|
||||||
|
injectNode.clickOk();
|
||||||
|
|
||||||
|
changeNode.edit();
|
||||||
|
changeNode.ruleSet("query", "msg", "payload", "msg");
|
||||||
|
changeNode.clickOk();
|
||||||
|
|
||||||
|
httpRequetNode.edit();
|
||||||
|
httpRequetNode.setUrl(helper.url() + httpNodeRoot + '/set-query?q={{{query}}}');
|
||||||
|
httpRequetNode.clickOk();
|
||||||
|
|
||||||
|
injectNode.connect(changeNode);
|
||||||
|
changeNode.connect(httpRequetNode);
|
||||||
|
httpRequetNode.connect(debugNode);
|
||||||
|
|
||||||
|
// The code for confirmation starts from here.
|
||||||
|
var httpinNode = workspace.addNode("httpin", 0, nodeHeight);
|
||||||
|
var templateNode = workspace.addNode("template", nodeWidth, nodeHeight);
|
||||||
|
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 2, nodeHeight);
|
||||||
|
|
||||||
|
httpinNode.edit();
|
||||||
|
httpinNode.setMethod("get");
|
||||||
|
httpinNode.setUrl("/set-query");
|
||||||
|
httpinNode.clickOk();
|
||||||
|
|
||||||
|
templateNode.edit();
|
||||||
|
templateNode.setSyntax("mustache");
|
||||||
|
templateNode.setFormat("handlebars");
|
||||||
|
templateNode.setTemplate("Hello {{req.query.q}}");
|
||||||
|
templateNode.clickOk();
|
||||||
|
|
||||||
|
httpinNode.connect(templateNode);
|
||||||
|
templateNode.connect(httpResponseNode);
|
||||||
|
// The code for confirmation ends here.
|
||||||
|
|
||||||
|
workspace.deploy();
|
||||||
|
debugTab.open();
|
||||||
|
debugTab.clearMessage();
|
||||||
|
injectNode.clickLeftButton();
|
||||||
|
debugTab.getMessage().should.eql('"Hello Nick"');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('get a parsed JSON response', function() {
|
||||||
|
var injectNode = workspace.addNode("inject");
|
||||||
|
var changeNode_setPost = workspace.addNode("change", nodeWidth);
|
||||||
|
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth * 2);
|
||||||
|
var debugNode = workspace.addNode("debug", nodeWidth * 3);
|
||||||
|
|
||||||
|
injectNode.edit();
|
||||||
|
injectNode.setPayload("str", "json-response");
|
||||||
|
injectNode.clickOk();
|
||||||
|
|
||||||
|
changeNode_setPost.edit();
|
||||||
|
changeNode_setPost.ruleSet("post", "msg", "payload", "msg");
|
||||||
|
changeNode_setPost.clickOk();
|
||||||
|
|
||||||
|
httpRequetNode.edit();
|
||||||
|
httpRequetNode.setMethod("get");
|
||||||
|
var url = helper.url() + httpNodeRoot + "/{{post}}";
|
||||||
|
httpRequetNode.setUrl(url);
|
||||||
|
httpRequetNode.setRet("obj");
|
||||||
|
httpRequetNode.clickOk();
|
||||||
|
|
||||||
|
debugNode.edit();
|
||||||
|
debugNode.setTarget("msg", "payload.title");
|
||||||
|
debugNode.clickOk();
|
||||||
|
|
||||||
|
injectNode.connect(changeNode_setPost);
|
||||||
|
changeNode_setPost.connect(httpRequetNode);
|
||||||
|
httpRequetNode.connect(debugNode);
|
||||||
|
|
||||||
|
// The code for confirmation starts from here.
|
||||||
|
var httpinNode = workspace.addNode("httpin", 0, nodeHeight);
|
||||||
|
var templateNode = workspace.addNode("template", nodeWidth * 1.5, nodeHeight);
|
||||||
|
var changeNode_setHeader = workspace.addNode("change", nodeWidth * 2.5, nodeHeight);
|
||||||
|
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 3.5, nodeHeight);
|
||||||
|
|
||||||
|
httpinNode.edit();
|
||||||
|
httpinNode.setMethod("get");
|
||||||
|
httpinNode.setUrl("/json-response");
|
||||||
|
httpinNode.clickOk();
|
||||||
|
|
||||||
|
templateNode.edit();
|
||||||
|
templateNode.setSyntax("mustache");
|
||||||
|
templateNode.setFormat("handlebars");
|
||||||
|
templateNode.setTemplate("{\"title\": \"Hello\"}");
|
||||||
|
templateNode.clickOk();
|
||||||
|
|
||||||
|
changeNode_setHeader.edit();
|
||||||
|
changeNode_setHeader.ruleSet("headers", "msg", "{\"content-type\":\"application/json\"}", "json");
|
||||||
|
changeNode_setHeader.clickOk();
|
||||||
|
|
||||||
|
httpinNode.connect(templateNode);
|
||||||
|
templateNode.connect(changeNode_setHeader);
|
||||||
|
changeNode_setHeader.connect(httpResponseNode);
|
||||||
|
// The code for confirmation ends here.
|
||||||
|
|
||||||
|
workspace.deploy();
|
||||||
|
debugTab.open();
|
||||||
|
debugTab.clearMessage();
|
||||||
|
injectNode.clickLeftButton();
|
||||||
|
debugTab.getMessage().should.eql('"Hello"');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('get a binary response', function() {
|
||||||
|
var injectNode = workspace.addNode("inject");
|
||||||
|
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth);
|
||||||
|
var debugNode = workspace.addNode("debug", nodeWidth * 2);
|
||||||
|
|
||||||
|
httpRequetNode.edit();
|
||||||
|
httpRequetNode.setMethod("get");
|
||||||
|
httpRequetNode.setUrl(helper.url() + "/settings");
|
||||||
|
httpRequetNode.setRet("bin");
|
||||||
|
httpRequetNode.clickOk();
|
||||||
|
|
||||||
|
injectNode.connect(httpRequetNode);
|
||||||
|
httpRequetNode.connect(debugNode);
|
||||||
|
|
||||||
|
workspace.deploy();
|
||||||
|
|
||||||
|
debugTab.open();
|
||||||
|
debugTab.clearMessage();
|
||||||
|
injectNode.clickLeftButton();
|
||||||
|
|
||||||
|
debugTab.getMessage().should.eql(['123', '34', '104', '116', '116', '112', '78', '111', '100', '101']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('set a request header', function() {
|
||||||
|
var injectNode = workspace.addNode("inject");
|
||||||
|
var functionNode = workspace.addNode("function", nodeWidth);
|
||||||
|
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth * 2);
|
||||||
|
var debugNode = workspace.addNode("debug", nodeWidth * 3);
|
||||||
|
|
||||||
|
functionNode.edit();
|
||||||
|
functionNode.setCode("msg.payload = \"data to post\";");
|
||||||
|
functionNode.clickOk();
|
||||||
|
|
||||||
|
httpRequetNode.edit();
|
||||||
|
httpRequetNode.setMethod("post");
|
||||||
|
var url = helper.url() + httpNodeRoot + "/set-header";
|
||||||
|
httpRequetNode.setUrl(url);
|
||||||
|
httpRequetNode.clickOk();
|
||||||
|
|
||||||
|
injectNode.connect(functionNode);
|
||||||
|
functionNode.connect(httpRequetNode);
|
||||||
|
httpRequetNode.connect(debugNode);
|
||||||
|
|
||||||
|
// The code for confirmation starts from here.
|
||||||
|
var httpinNode = workspace.addNode("httpin", 0, nodeHeight);
|
||||||
|
var templateNode = workspace.addNode("template", nodeWidth * 1.5, nodeHeight);
|
||||||
|
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 2.5, nodeHeight);
|
||||||
|
|
||||||
|
httpinNode.edit();
|
||||||
|
httpinNode.setMethod("post");
|
||||||
|
httpinNode.setUrl("/set-header");
|
||||||
|
httpinNode.clickOk();
|
||||||
|
|
||||||
|
templateNode.edit();
|
||||||
|
templateNode.setSyntax("mustache");
|
||||||
|
templateNode.setFormat("handlebars");
|
||||||
|
templateNode.setTemplate("{{ payload }}");
|
||||||
|
templateNode.clickOk();
|
||||||
|
|
||||||
|
httpinNode.connect(templateNode);
|
||||||
|
templateNode.connect(httpResponseNode);
|
||||||
|
// The code for confirmation ends here.
|
||||||
|
|
||||||
|
workspace.deploy();
|
||||||
|
debugTab.open();
|
||||||
|
debugTab.clearMessage();
|
||||||
|
injectNode.clickLeftButton();
|
||||||
|
debugTab.getMessage().should.eql('"data to post"');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -36,6 +36,9 @@ describe('template node', function() {
|
|||||||
function initContext(done) {
|
function initContext(done) {
|
||||||
Context.init({
|
Context.init({
|
||||||
contextStorage: {
|
contextStorage: {
|
||||||
|
memory0: { // do not use (for excluding effect fallback)
|
||||||
|
module: "memory"
|
||||||
|
},
|
||||||
memory1: {
|
memory1: {
|
||||||
module: "memory"
|
module: "memory"
|
||||||
},
|
},
|
||||||
@ -337,7 +340,7 @@ describe('template node', function() {
|
|||||||
msg.should.have.property('topic', 'bar');
|
msg.should.have.property('topic', 'bar');
|
||||||
msg.should.have.property('payload', 'foo');
|
msg.should.have.property('payload', 'foo');
|
||||||
// result is in flow context
|
// result is in flow context
|
||||||
n2.context().flow.get("payload", "memory", function (err, val) {
|
n2.context().flow.get("payload", "memory1", function (err, val) {
|
||||||
val.should.equal("payload=foo");
|
val.should.equal("payload=foo");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -375,7 +378,7 @@ describe('template node', function() {
|
|||||||
msg.should.have.property('topic', 'bar');
|
msg.should.have.property('topic', 'bar');
|
||||||
msg.should.have.property('payload', 'foo');
|
msg.should.have.property('payload', 'foo');
|
||||||
// result is in global context
|
// result is in global context
|
||||||
n2.context().global.get("payload", "memory", function (err, val) {
|
n2.context().global.get("payload", "memory1", function (err, val) {
|
||||||
val.should.equal("payload=foo");
|
val.should.equal("payload=foo");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -35,6 +35,9 @@ describe('trigger node', function() {
|
|||||||
},
|
},
|
||||||
memory1: {
|
memory1: {
|
||||||
module: "memory"
|
module: "memory"
|
||||||
|
},
|
||||||
|
memory2: {
|
||||||
|
module: "memory"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -96,6 +99,74 @@ describe('trigger node', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function basicTest(type, val, rval) {
|
||||||
|
it('should output 1st value when triggered ('+type+')', function(done) {
|
||||||
|
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:val, op1type:type, op2:"", op2type:"null", duration:"20", wires:[["n2"]] },
|
||||||
|
{id:"n2", type:"helper"} ];
|
||||||
|
process.env[val] = rval;
|
||||||
|
helper.load(triggerNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
try {
|
||||||
|
if (rval) {
|
||||||
|
msg.should.have.property("payload");
|
||||||
|
should.deepEqual(msg.payload, rval);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
msg.should.have.property("payload", val);
|
||||||
|
}
|
||||||
|
delete process.env[val];
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
catch(err) { done(err); }
|
||||||
|
});
|
||||||
|
n1.emit("input", {payload:null});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should output 2st value when triggered ('+type+')', function(done) {
|
||||||
|
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:"foo", op1type:"str", op2:val, op2type:type, duration:"20", wires:[["n2"]] },
|
||||||
|
{id:"n2", type:"helper"} ];
|
||||||
|
process.env[val] = rval;
|
||||||
|
helper.load(triggerNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
var c = 0;
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
try {
|
||||||
|
if (c === 0) {
|
||||||
|
msg.should.have.property("payload", "foo");
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (rval) {
|
||||||
|
msg.should.have.property("payload");
|
||||||
|
should.deepEqual(msg.payload, rval);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
msg.should.have.property("payload", val);
|
||||||
|
}
|
||||||
|
delete process.env[val];
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(err) { done(err); }
|
||||||
|
});
|
||||||
|
n1.emit("input", {payload:null});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
basicTest("num", 10);
|
||||||
|
basicTest("str", "10");
|
||||||
|
basicTest("bool", true);
|
||||||
|
var val_json = '{ "x":"vx", "y":"vy", "z":"vz" }';
|
||||||
|
basicTest("json", val_json, JSON.parse(val_json));
|
||||||
|
var val_buf = "[1,2,3,4,5]";
|
||||||
|
basicTest("bin", val_buf, Buffer.from(JSON.parse(val_buf)));
|
||||||
|
basicTest("env", "NR-TEST", "env-val");
|
||||||
|
|
||||||
it('should output 1 then 0 when triggered (default)', function(done) {
|
it('should output 1 then 0 when triggered (default)', function(done) {
|
||||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:"20", wires:[["n2"]] },
|
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:"20", wires:[["n2"]] },
|
||||||
{id:"n2", type:"helper"} ];
|
{id:"n2", type:"helper"} ];
|
||||||
@ -336,8 +407,8 @@ describe('trigger node', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to return things from persistable flow and global context variables', function (done) {
|
it('should be able to return things from persistable flow and global context variables', function (done) {
|
||||||
var flow = [{"id": "n1", "type": "trigger", "name": "triggerNode", "op1": "#:(memory0)::foo", "op1type": "flow",
|
var flow = [{"id": "n1", "type": "trigger", "name": "triggerNode", "op1": "#:(memory1)::foo", "op1type": "flow",
|
||||||
"op2": "#:(memory0)::bar", "op2type": "global", "duration": "20", "wires": [["n2"]], "z": "flow" },
|
"op2": "#:(memory1)::bar", "op2type": "global", "duration": "20", "wires": [["n2"]], "z": "flow" },
|
||||||
{"id": "n2", "type": "helper"}];
|
{"id": "n2", "type": "helper"}];
|
||||||
helper.load(triggerNode, flow, function () {
|
helper.load(triggerNode, flow, function () {
|
||||||
initContext(function () {
|
initContext(function () {
|
||||||
@ -360,8 +431,8 @@ describe('trigger node', function() {
|
|||||||
var context = n1.context();
|
var context = n1.context();
|
||||||
var flow = context.flow;
|
var flow = context.flow;
|
||||||
var global = context.global;
|
var global = context.global;
|
||||||
flow.set("foo", "foo", "memory0", function (err) {
|
flow.set("foo", "foo", "memory1", function (err) {
|
||||||
global.set("bar", "bar", "memory0", function (err) {
|
global.set("bar", "bar", "memory1", function (err) {
|
||||||
n1.emit("input", { payload: null });
|
n1.emit("input", { payload: null });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -372,8 +443,8 @@ describe('trigger node', function() {
|
|||||||
it('should be able to return things from multiple persistable global context variables', function (done) {
|
it('should be able to return things from multiple persistable global context variables', function (done) {
|
||||||
var flow = [{"id": "n1", "z": "flow", "type": "trigger",
|
var flow = [{"id": "n1", "z": "flow", "type": "trigger",
|
||||||
"duration": "20", "wires": [["n2"]],
|
"duration": "20", "wires": [["n2"]],
|
||||||
"op1": "#:(memory0)::val", "op1type": "global",
|
"op1": "#:(memory1)::val", "op1type": "global",
|
||||||
"op2": "#:(memory1)::val", "op2type": "global"
|
"op2": "#:(memory2)::val", "op2type": "global"
|
||||||
},
|
},
|
||||||
{"id": "n2", "type": "helper"}];
|
{"id": "n2", "type": "helper"}];
|
||||||
helper.load(triggerNode, flow, function () {
|
helper.load(triggerNode, flow, function () {
|
||||||
@ -399,8 +470,8 @@ describe('trigger node', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
var global = n1.context().global;
|
var global = n1.context().global;
|
||||||
global.set("val", "foo", "memory0", function (err) {
|
global.set("val", "foo", "memory1", function (err) {
|
||||||
global.set("val", "bar", "memory1", function (err) {
|
global.set("val", "bar", "memory2", function (err) {
|
||||||
n1.emit("input", { payload: null });
|
n1.emit("input", { payload: null });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -411,8 +482,8 @@ describe('trigger node', function() {
|
|||||||
it('should be able to return things from multiple persistable flow context variables', function (done) {
|
it('should be able to return things from multiple persistable flow context variables', function (done) {
|
||||||
var flow = [{"id": "n1", "z": "flow", "type": "trigger",
|
var flow = [{"id": "n1", "z": "flow", "type": "trigger",
|
||||||
"duration": "20", "wires": [["n2"]],
|
"duration": "20", "wires": [["n2"]],
|
||||||
"op1": "#:(memory0)::val", "op1type": "flow",
|
"op1": "#:(memory1)::val", "op1type": "flow",
|
||||||
"op2": "#:(memory1)::val", "op2type": "flow"
|
"op2": "#:(memory2)::val", "op2type": "flow"
|
||||||
},
|
},
|
||||||
{"id": "n2", "type": "helper"}];
|
{"id": "n2", "type": "helper"}];
|
||||||
helper.load(triggerNode, flow, function () {
|
helper.load(triggerNode, flow, function () {
|
||||||
@ -438,8 +509,8 @@ describe('trigger node', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
var flow = n1.context().flow;
|
var flow = n1.context().flow;
|
||||||
flow.set("val", "foo", "memory0", function (err) {
|
flow.set("val", "foo", "memory1", function (err) {
|
||||||
flow.set("val", "bar", "memory1", function (err) {
|
flow.set("val", "bar", "memory2", function (err) {
|
||||||
n1.emit("input", { payload: null });
|
n1.emit("input", { payload: null });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -450,8 +521,8 @@ describe('trigger node', function() {
|
|||||||
it('should be able to return things from multiple persistable flow & global context variables', function (done) {
|
it('should be able to return things from multiple persistable flow & global context variables', function (done) {
|
||||||
var flow = [{"id": "n1", "z": "flow", "type": "trigger",
|
var flow = [{"id": "n1", "z": "flow", "type": "trigger",
|
||||||
"duration": "20", "wires": [["n2"]],
|
"duration": "20", "wires": [["n2"]],
|
||||||
"op1": "#:(memory0)::val", "op1type": "flow",
|
"op1": "#:(memory1)::val", "op1type": "flow",
|
||||||
"op2": "#:(memory1)::val", "op2type": "global"
|
"op2": "#:(memory2)::val", "op2type": "global"
|
||||||
},
|
},
|
||||||
{"id": "n2", "type": "helper"}];
|
{"id": "n2", "type": "helper"}];
|
||||||
helper.load(triggerNode, flow, function () {
|
helper.load(triggerNode, flow, function () {
|
||||||
@ -479,8 +550,8 @@ describe('trigger node', function() {
|
|||||||
var context = n1.context();
|
var context = n1.context();
|
||||||
var flow = context.flow;
|
var flow = context.flow;
|
||||||
var global = context.flow;
|
var global = context.flow;
|
||||||
flow.set("val", "foo", "memory0", function (err) {
|
flow.set("val", "foo", "memory1", function (err) {
|
||||||
global.set("val", "bar", "memory1", function (err) {
|
global.set("val", "bar", "memory2", function (err) {
|
||||||
n1.emit("input", { payload: null });
|
n1.emit("input", { payload: null });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -379,7 +379,7 @@ describe('switch Node', function() {
|
|||||||
singularSwitchTest("empty", true, false, undefined, done);
|
singularSwitchTest("empty", true, false, undefined, done);
|
||||||
});
|
});
|
||||||
it('should check if payload is empty (0)', function(done) {
|
it('should check if payload is empty (0)', function(done) {
|
||||||
singularSwitchTest("empty", true, false, null, done);
|
singularSwitchTest("empty", true, false, 0, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should check if payload is not empty (string)', function(done) {
|
it('should check if payload is not empty (string)', function(done) {
|
||||||
@ -413,7 +413,7 @@ describe('switch Node', function() {
|
|||||||
singularSwitchTest("nempty", true, false, undefined, done);
|
singularSwitchTest("nempty", true, false, undefined, done);
|
||||||
});
|
});
|
||||||
it('should check if payload is not empty (0)', function(done) {
|
it('should check if payload is not empty (0)', function(done) {
|
||||||
singularSwitchTest("nempty", true, false, null, done);
|
singularSwitchTest("nempty", true, false, 0, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1272,6 +1272,25 @@ describe('change Node', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('reports invalid fromValue', function(done) {
|
||||||
|
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"change","p":"payload","from":"null","fromt":"msg","to":"abc","tot":"str"}],"name":"changeNode","wires":[["helperNode1"]]},
|
||||||
|
{id:"helperNode1", type:"helper", wires:[]}];
|
||||||
|
helper.load(changeNode, flow, function() {
|
||||||
|
var changeNode1 = helper.getNode("changeNode1");
|
||||||
|
setTimeout(function() {
|
||||||
|
var logEvents = helper.log().args.filter(function (evt) {
|
||||||
|
return evt[0].type == "change";
|
||||||
|
});
|
||||||
|
logEvents.should.have.length(1);
|
||||||
|
var msg = logEvents[0][0];
|
||||||
|
msg.should.have.property('level', helper.log().ERROR);
|
||||||
|
msg.should.have.property('id', 'changeNode1');
|
||||||
|
done();
|
||||||
|
},25);
|
||||||
|
changeNode1.receive({payload:"",null:null});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('env var', function() {
|
describe('env var', function() {
|
||||||
before(function() {
|
before(function() {
|
||||||
process.env.NR_TEST_A = 'foo';
|
process.env.NR_TEST_A = 'foo';
|
||||||
|
@ -53,75 +53,143 @@ describe('file Nodes', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should write to a file', function(done) {
|
it('should write to a file', function(done) {
|
||||||
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":true}];
|
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":true, wires: [["helperNode1"]]},
|
||||||
|
{id:"helperNode1", type:"helper"}];
|
||||||
helper.load(fileNode, flow, function() {
|
helper.load(fileNode, flow, function() {
|
||||||
var n1 = helper.getNode("fileNode1");
|
var n1 = helper.getNode("fileNode1");
|
||||||
n1.emit("input", {payload:"test"});
|
var n2 = helper.getNode("helperNode1");
|
||||||
setTimeout(function() {
|
n2.on("input", function(msg) {
|
||||||
var f = fs.readFileSync(fileToTest);
|
var f = fs.readFileSync(fileToTest);
|
||||||
f.should.have.length(4);
|
f.should.have.length(4);
|
||||||
fs.unlinkSync(fileToTest);
|
fs.unlinkSync(fileToTest);
|
||||||
|
msg.should.have.property("payload", "test");
|
||||||
done();
|
done();
|
||||||
},wait);
|
});
|
||||||
|
n1.receive({payload:"test"});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should append to a file and add newline', function(done) {
|
it('should append to a file and add newline', function(done) {
|
||||||
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":false}];
|
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":false, wires: [["helperNode1"]]},
|
||||||
|
{id:"helperNode1", type:"helper"}];
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(fileToTest);
|
fs.unlinkSync(fileToTest);
|
||||||
}catch(err) {}
|
} catch(err) {
|
||||||
|
}
|
||||||
helper.load(fileNode, flow, function() {
|
helper.load(fileNode, flow, function() {
|
||||||
var n1 = helper.getNode("fileNode1");
|
var n1 = helper.getNode("fileNode1");
|
||||||
n1.emit("input", {payload:"test2"}); // string
|
var n2 = helper.getNode("helperNode1");
|
||||||
|
var count = 0;
|
||||||
|
var data = ["test2", true, 999, [2]];
|
||||||
|
|
||||||
|
n2.on("input", function (msg) {
|
||||||
|
msg.should.have.property("payload", data[count]);
|
||||||
|
if (count === 3) {
|
||||||
|
var f = fs.readFileSync(fileToTest).toString();
|
||||||
|
if (os.type() !== "Windows_NT") {
|
||||||
|
f.should.have.length(19);
|
||||||
|
f.should.equal("test2\ntrue\n999\n[2]\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f.should.have.length(23);
|
||||||
|
f.should.equal("test2\r\ntrue\r\n999\r\n[2]\r\n");
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
});
|
||||||
|
|
||||||
|
n1.receive({payload:"test2"}); // string
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
n1.emit("input", {payload:true}); // boolean
|
n1.receive({payload:true}); // boolean
|
||||||
},30);
|
},30);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
n1.emit("input", {payload:999}); // number
|
n1.receive({payload:999}); // number
|
||||||
},60);
|
},60);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
n1.emit("input", {payload:[2]}); // object (array)
|
n1.receive({payload:[2]}); // object (array)
|
||||||
},90);
|
},90);
|
||||||
setTimeout(function() {
|
|
||||||
var f = fs.readFileSync(fileToTest).toString();
|
|
||||||
if (os.type() !== "Windows_NT") {
|
|
||||||
f.should.have.length(19);
|
|
||||||
f.should.equal("test2\ntrue\n999\n[2]\n");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
f.should.have.length(23);
|
|
||||||
f.should.equal("test2\r\ntrue\r\n999\r\n[2]\r\n");
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
},wait);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should append to a file after it has been deleted ', function(done) {
|
it('should append to a file after it has been deleted ', function(done) {
|
||||||
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":false}];
|
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":false, wires: [["helperNode1"]]},
|
||||||
|
{id:"helperNode1", type:"helper"}];
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(fileToTest);
|
fs.unlinkSync(fileToTest);
|
||||||
} catch(err) {}
|
} catch(err) {
|
||||||
|
}
|
||||||
helper.load(fileNode, flow, function() {
|
helper.load(fileNode, flow, function() {
|
||||||
var n1 = helper.getNode("fileNode1");
|
var n1 = helper.getNode("fileNode1");
|
||||||
// Send two messages to the file
|
var n2 = helper.getNode("helperNode1");
|
||||||
n1.emit("input", {payload:"one"});
|
var data = ["one", "two", "three", "four"];
|
||||||
n1.emit("input", {payload:"two"});
|
var count = 0;
|
||||||
setTimeout(function() {
|
|
||||||
|
n2.on("input", function (msg) {
|
||||||
|
msg.should.have.property("payload", data[count]);
|
||||||
try {
|
try {
|
||||||
// Check they got appended as expected
|
if (count === 1) {
|
||||||
var f = fs.readFileSync(fileToTest).toString();
|
// Check they got appended as expected
|
||||||
f.should.equal("onetwo");
|
var f = fs.readFileSync(fileToTest).toString();
|
||||||
|
f.should.equal("onetwo");
|
||||||
|
|
||||||
// Delete the file
|
// Delete the file
|
||||||
fs.unlinkSync(fileToTest);
|
fs.unlinkSync(fileToTest);
|
||||||
|
setTimeout(function() {
|
||||||
|
// Send two more messages to the file
|
||||||
|
n1.receive({payload:"three"});
|
||||||
|
n1.receive({payload:"four"});
|
||||||
|
}, wait);
|
||||||
|
}
|
||||||
|
if (count === 3) {
|
||||||
|
var f = fs.readFileSync(fileToTest).toString();
|
||||||
|
f.should.equal("threefour");
|
||||||
|
fs.unlinkSync(fileToTest);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
done(err);
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send two messages to the file
|
||||||
|
n1.receive({payload:"one"});
|
||||||
|
n1.receive({payload:"two"});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Send two more messages to the file
|
it('should append to a file after it has been recreated ', function(done) {
|
||||||
n1.emit("input", {payload:"three"});
|
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":false, wires: [["helperNode1"]]},
|
||||||
n1.emit("input", {payload:"four"});
|
{id:"helperNode1", type:"helper"}];
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(fileToTest);
|
||||||
|
} catch(err) {
|
||||||
|
}
|
||||||
|
helper.load(fileNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("fileNode1");
|
||||||
|
var n2 = helper.getNode("helperNode1");
|
||||||
|
var data = ["one", "two", "three", "four"];
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
n2.on("input", function (msg) {
|
||||||
|
try {
|
||||||
|
msg.should.have.property("payload", data[count]);
|
||||||
|
if (count == 1) {
|
||||||
|
// Check they got appended as expected
|
||||||
|
var f = fs.readFileSync(fileToTest).toString();
|
||||||
|
f.should.equal("onetwo");
|
||||||
|
|
||||||
setTimeout(function() {
|
if (os.type() === "Windows_NT") {
|
||||||
|
var dummyFile = path.join(resourcesDir,"50-file-test-dummy.txt");
|
||||||
|
fs.rename(fileToTest, dummyFile, function() {
|
||||||
|
recreateTest(n1, dummyFile);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
recreateTest(n1, fileToTest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count == 3) {
|
||||||
// Check the file was updated
|
// Check the file was updated
|
||||||
try {
|
try {
|
||||||
var f = fs.readFileSync(fileToTest).toString();
|
var f = fs.readFileSync(fileToTest).toString();
|
||||||
@ -131,42 +199,16 @@ describe('file Nodes', function() {
|
|||||||
} catch(err) {
|
} catch(err) {
|
||||||
done(err);
|
done(err);
|
||||||
}
|
}
|
||||||
},wait);
|
|
||||||
} catch(err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
},wait);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should append to a file after it has been recreated ', function(done) {
|
|
||||||
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":false}];
|
|
||||||
try {
|
|
||||||
fs.unlinkSync(fileToTest);
|
|
||||||
} catch(err) {}
|
|
||||||
helper.load(fileNode, flow, function() {
|
|
||||||
var n1 = helper.getNode("fileNode1");
|
|
||||||
// Send two messages to the file
|
|
||||||
n1.emit("input", {payload:"one"});
|
|
||||||
n1.emit("input", {payload:"two"});
|
|
||||||
setTimeout(function() {
|
|
||||||
try {
|
|
||||||
// Check they got appended as expected
|
|
||||||
var f = fs.readFileSync(fileToTest).toString();
|
|
||||||
f.should.equal("onetwo");
|
|
||||||
|
|
||||||
if (os.type() === "Windows_NT") {
|
|
||||||
var dummyFile = path.join(resourcesDir,"50-file-test-dummy.txt");
|
|
||||||
fs.rename(fileToTest, dummyFile, function() {
|
|
||||||
recreateTest(n1, dummyFile);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
recreateTest(n1, fileToTest);
|
|
||||||
}
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
done(err);
|
done(err);
|
||||||
}
|
}
|
||||||
},wait);
|
count++;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send two messages to the file
|
||||||
|
n1.receive({payload:"one"});
|
||||||
|
n1.receive({payload:"two"});
|
||||||
});
|
});
|
||||||
|
|
||||||
function recreateTest(n1, fileToDelete) {
|
function recreateTest(n1, fileToDelete) {
|
||||||
@ -177,30 +219,23 @@ describe('file Nodes', function() {
|
|||||||
fs.writeFileSync(fileToTest,"");
|
fs.writeFileSync(fileToTest,"");
|
||||||
|
|
||||||
// Send two more messages to the file
|
// Send two more messages to the file
|
||||||
n1.emit("input", {payload:"three"});
|
n1.receive({payload:"three"});
|
||||||
n1.emit("input", {payload:"four"});
|
n1.receive({payload:"four"});
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
// Check the file was updated
|
|
||||||
try {
|
|
||||||
var f = fs.readFileSync(fileToTest).toString();
|
|
||||||
f.should.equal("threefour");
|
|
||||||
fs.unlinkSync(fileToTest);
|
|
||||||
done();
|
|
||||||
} catch(err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
},wait);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should use msg.filename if filename not set in node', function(done) {
|
it('should use msg.filename if filename not set in node', function(done) {
|
||||||
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "appendNewline":true, "overwriteFile":true}];
|
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "appendNewline":true, "overwriteFile":true, wires: [["helperNode1"]]},
|
||||||
|
{id:"helperNode1", type:"helper"}];
|
||||||
helper.load(fileNode, flow, function() {
|
helper.load(fileNode, flow, function() {
|
||||||
var n1 = helper.getNode("fileNode1");
|
var n1 = helper.getNode("fileNode1");
|
||||||
n1.emit("input", {payload:"fine", filename:fileToTest});
|
var n2 = helper.getNode("helperNode1");
|
||||||
setTimeout(function() {
|
|
||||||
|
n2.on("input", function (msg) {
|
||||||
|
msg.should.have.property("payload", "fine");
|
||||||
|
msg.should.have.property("filename", fileToTest);
|
||||||
|
|
||||||
var f = fs.readFileSync(fileToTest).toString();
|
var f = fs.readFileSync(fileToTest).toString();
|
||||||
if (os.type() !== "Windows_NT") {
|
if (os.type() !== "Windows_NT") {
|
||||||
f.should.have.length(5);
|
f.should.have.length(5);
|
||||||
@ -211,16 +246,20 @@ describe('file Nodes', function() {
|
|||||||
f.should.equal("fine\r\n");
|
f.should.equal("fine\r\n");
|
||||||
}
|
}
|
||||||
done();
|
done();
|
||||||
},wait);
|
});
|
||||||
|
|
||||||
|
n1.receive({payload:"fine", filename:fileToTest});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to delete the file', function(done) {
|
it('should be able to delete the file', function(done) {
|
||||||
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":"delete"}];
|
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":"delete", wires: [["helperNode1"]]},
|
||||||
|
{id:"helperNode1", type:"helper"}];
|
||||||
helper.load(fileNode, flow, function() {
|
helper.load(fileNode, flow, function() {
|
||||||
var n1 = helper.getNode("fileNode1");
|
var n1 = helper.getNode("fileNode1");
|
||||||
n1.emit("input", {payload:"fine"});
|
var n2 = helper.getNode("helperNode1");
|
||||||
setTimeout(function() {
|
|
||||||
|
n2.on("input", function (msg) {
|
||||||
try {
|
try {
|
||||||
var f = fs.readFileSync(fileToTest).toString();
|
var f = fs.readFileSync(fileToTest).toString();
|
||||||
f.should.not.equal("fine");
|
f.should.not.equal("fine");
|
||||||
@ -230,7 +269,9 @@ describe('file Nodes', function() {
|
|||||||
e.code.should.equal("ENOENT");
|
e.code.should.equal("ENOENT");
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
},wait);
|
});
|
||||||
|
|
||||||
|
n1.receive({payload:"fine"});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -308,13 +308,21 @@ describe('context', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should fail when using invalid store name', function(done) {
|
it('should fail when using invalid store name', function(done) {
|
||||||
Context.init({contextStorage:{'Invalid name':"noexist"}});
|
Context.init({contextStorage:{'Invalid name':{module:testPlugin}}});
|
||||||
Context.load().then(function(){
|
Context.load().then(function(){
|
||||||
done("An error was not thrown");
|
done("An error was not thrown");
|
||||||
}).catch(function(){
|
}).catch(function(){
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('should fail when using invalid sign character', function (done) {
|
||||||
|
Context.init({ contextStorage:{'abc-123':{module:testPlugin}}});
|
||||||
|
Context.load().then(function () {
|
||||||
|
done("An error was not thrown");
|
||||||
|
}).catch(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
it('should fail when using invalid default context', function(done) {
|
it('should fail when using invalid default context', function(done) {
|
||||||
Context.init({contextStorage:{default:"noexist"}});
|
Context.init({contextStorage:{default:"noexist"}});
|
||||||
Context.load().then(function(){
|
Context.load().then(function(){
|
||||||
@ -339,6 +347,20 @@ describe('context', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('should fail to load invalid module', function (done) {
|
||||||
|
Context.init({contextStorage: {
|
||||||
|
test: {
|
||||||
|
module: function (config) {
|
||||||
|
throw new Error("invalid plugin was loaded.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
Context.load().then(function () {
|
||||||
|
done("An error was not thrown");
|
||||||
|
}).catch(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('close modules',function(){
|
describe('close modules',function(){
|
||||||
@ -419,7 +441,7 @@ describe('context', function() {
|
|||||||
Context.load().then(function(){
|
Context.load().then(function(){
|
||||||
var context = Context.get("1","flow");
|
var context = Context.get("1","flow");
|
||||||
var cb = function(){done("An error occurred")}
|
var cb = function(){done("An error occurred")}
|
||||||
context.set("foo","bar","defaultt",cb);
|
context.set("foo","bar","default",cb);
|
||||||
context.get("foo","default",cb);
|
context.get("foo","default",cb);
|
||||||
context.keys("default",cb);
|
context.keys("default",cb);
|
||||||
stubGet.called.should.be.false();
|
stubGet.called.should.be.false();
|
||||||
@ -763,6 +785,93 @@ describe('context', function() {
|
|||||||
});
|
});
|
||||||
}).catch(function(err){ done(err); });
|
}).catch(function(err){ done(err); });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw an error if callback of context.get is not a function', function (done) {
|
||||||
|
Context.init({ contextStorage: memoryStorage });
|
||||||
|
Context.load().then(function () {
|
||||||
|
var context = Context.get("1", "flow");
|
||||||
|
context.get("foo", "memory", "callback");
|
||||||
|
done("should throw an error.");
|
||||||
|
}).catch(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if callback of context.get is not specified', function (done) {
|
||||||
|
Context.init({ contextStorage: memoryStorage });
|
||||||
|
Context.load().then(function () {
|
||||||
|
var context = Context.get("1", "flow");
|
||||||
|
context.get("foo", "memory");
|
||||||
|
done("should throw an error.");
|
||||||
|
}).catch(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if callback of context.set is not a function', function (done) {
|
||||||
|
Context.init({ contextStorage: memoryStorage });
|
||||||
|
Context.load().then(function () {
|
||||||
|
var context = Context.get("1", "flow");
|
||||||
|
context.set("foo", "bar", "memory", "callback");
|
||||||
|
done("should throw an error.");
|
||||||
|
}).catch(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not throw an error if callback of context.set is not specified', function (done) {
|
||||||
|
Context.init({ contextStorage: memoryStorage });
|
||||||
|
Context.load().then(function () {
|
||||||
|
var context = Context.get("1", "flow");
|
||||||
|
context.set("foo", "bar", "memory");
|
||||||
|
done();
|
||||||
|
}).catch(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if callback of context.keys is not a function', function (done) {
|
||||||
|
Context.init({ contextStorage: memoryStorage });
|
||||||
|
Context.load().then(function () {
|
||||||
|
var context = Context.get("1", "flow");
|
||||||
|
context.keys("memory", "callback");
|
||||||
|
done("should throw an error.");
|
||||||
|
}).catch(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if callback of context.keys is not specified', function (done) {
|
||||||
|
Context.init({ contextStorage: memoryStorage });
|
||||||
|
Context.load().then(function () {
|
||||||
|
var context = Context.get("1", "flow");
|
||||||
|
context.keys("memory");
|
||||||
|
done("should throw an error.");
|
||||||
|
}).catch(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('listStores', function () {
|
||||||
|
it('should list context storages', function (done) {
|
||||||
|
Context.init({ contextStorage: contextDefaultStorage });
|
||||||
|
Context.load().then(function () {
|
||||||
|
var list = Context.listStores();
|
||||||
|
list.default.should.equal("default");
|
||||||
|
list.stores.should.eql(["default", "test"]);
|
||||||
|
done();
|
||||||
|
}).catch(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should list context storages without default storage', function (done) {
|
||||||
|
Context.init({ contextStorage: contextStorage });
|
||||||
|
Context.load().then(function () {
|
||||||
|
var list = Context.listStores();
|
||||||
|
list.default.should.equal("test");
|
||||||
|
list.stores.should.eql(["test"]);
|
||||||
|
done();
|
||||||
|
}).catch(done);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('delete context',function(){
|
describe('delete context',function(){
|
||||||
|
@ -63,6 +63,15 @@ describe('localfilesystem',function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should store local scope property', function (done) {
|
||||||
|
context.set("abc:def", "foo.bar", "test", function (err) {
|
||||||
|
context.get("abc:def", "foo", function (err, value) {
|
||||||
|
value.should.be.eql({ bar: "test" });
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should delete property',function(done) {
|
it('should delete property',function(done) {
|
||||||
context.set("nodeX","foo.abc.bar1","test1",function(err){
|
context.set("nodeX","foo.abc.bar1","test1",function(err){
|
||||||
context.set("nodeX","foo.abc.bar2","test2",function(err){
|
context.set("nodeX","foo.abc.bar2","test2",function(err){
|
||||||
@ -240,6 +249,81 @@ describe('localfilesystem',function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw an error when getting a value with invalid key', function (done) {
|
||||||
|
context.set("nodeX","foo","bar",function(err) {
|
||||||
|
context.get("nodeX"," ",function(err,value) {
|
||||||
|
should.exist(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when setting a value with invalid key',function (done) {
|
||||||
|
context.set("nodeX"," ","bar",function (err) {
|
||||||
|
should.exist(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when callback of get() is not a function',function (done) {
|
||||||
|
try {
|
||||||
|
context.get("nodeX","foo","callback");
|
||||||
|
done("should throw an error.");
|
||||||
|
} catch (err) {
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when callback of get() is not specified',function (done) {
|
||||||
|
try {
|
||||||
|
context.get("nodeX","foo");
|
||||||
|
done("should throw an error.");
|
||||||
|
} catch (err) {
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when callback of set() is not a function',function (done) {
|
||||||
|
try {
|
||||||
|
context.set("nodeX","foo","bar","callback");
|
||||||
|
done("should throw an error.");
|
||||||
|
} catch (err) {
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not throw an error when callback of set() is not specified', function (done) {
|
||||||
|
try {
|
||||||
|
context.set("nodeX"," ","bar");
|
||||||
|
done();
|
||||||
|
} catch (err) {
|
||||||
|
done("should not throw an error.");
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle empty context file', function (done) {
|
||||||
|
fs.outputFile(path.join(resourcesDir,"contexts","nodeX","flow.json"),"",function(){
|
||||||
|
context.get("nodeX", "foo", function (err, value) {
|
||||||
|
should.not.exist(value);
|
||||||
|
context.set("nodeX", "foo", "test", function (err) {
|
||||||
|
context.get("nodeX", "foo", function (err, value) {
|
||||||
|
value.should.be.equal("test");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when reading corrupt context file', function (done) {
|
||||||
|
fs.outputFile(path.join(resourcesDir, "contexts", "nodeX", "flow.json"),"{abc",function(){
|
||||||
|
context.get("nodeX", "foo", function (err, value) {
|
||||||
|
should.exist(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#keys',function() {
|
describe('#keys',function() {
|
||||||
@ -286,6 +370,24 @@ describe('localfilesystem',function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw an error when callback of keys() is not a function', function (done) {
|
||||||
|
try {
|
||||||
|
context.keys("nodeX", "callback");
|
||||||
|
done("should throw an error.");
|
||||||
|
} catch (err) {
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when callback of keys() is not specified', function (done) {
|
||||||
|
try {
|
||||||
|
context.keys("nodeX");
|
||||||
|
done("should throw an error.");
|
||||||
|
} catch (err) {
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#delete',function() {
|
describe('#delete',function() {
|
||||||
@ -497,4 +599,131 @@ describe('localfilesystem',function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Configuration', function () {
|
||||||
|
it('should change a base directory', function (done) {
|
||||||
|
var differentBaseContext = LocalFileSystem({
|
||||||
|
base: "contexts2",
|
||||||
|
dir: resourcesDir,
|
||||||
|
cache: false
|
||||||
|
});
|
||||||
|
differentBaseContext.open().then(function () {
|
||||||
|
differentBaseContext.set("node2", "foo2", "bar2", function (err) {
|
||||||
|
differentBaseContext.get("node2", "foo2", function (err, value) {
|
||||||
|
value.should.be.equal("bar2");
|
||||||
|
context.get("node2", "foo2", function(err, value) {
|
||||||
|
should.not.exist(value);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use userDir', function (done) {
|
||||||
|
var userDirContext = LocalFileSystem({
|
||||||
|
base: "contexts2",
|
||||||
|
cache: false,
|
||||||
|
settings: {
|
||||||
|
userDir: resourcesDir
|
||||||
|
}
|
||||||
|
});
|
||||||
|
userDirContext.open().then(function () {
|
||||||
|
userDirContext.set("node2", "foo2", "bar2", function (err) {
|
||||||
|
userDirContext.get("node2", "foo2", function (err, value) {
|
||||||
|
value.should.be.equal("bar2");
|
||||||
|
context.get("node2", "foo2", function (err, value) {
|
||||||
|
should.not.exist(value);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use NODE_RED_HOME', function (done) {
|
||||||
|
var oldNRH = process.env.NODE_RED_HOME;
|
||||||
|
process.env.NODE_RED_HOME = resourcesDir;
|
||||||
|
fs.mkdirSync(resourcesDir);
|
||||||
|
fs.writeFileSync(path.join(resourcesDir,".config.json"),"");
|
||||||
|
var nrHomeContext = LocalFileSystem({
|
||||||
|
base: "contexts2",
|
||||||
|
cache: false
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
nrHomeContext.open().then(function () {
|
||||||
|
nrHomeContext.set("node2", "foo2", "bar2", function (err) {
|
||||||
|
nrHomeContext.get("node2", "foo2", function (err, value) {
|
||||||
|
value.should.be.equal("bar2");
|
||||||
|
context.get("node2", "foo2", function (err, value) {
|
||||||
|
should.not.exist(value);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
process.env.NODE_RED_HOME = oldNRH;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use HOME_PATH', function (done) {
|
||||||
|
var oldNRH = process.env.NODE_RED_HOME;
|
||||||
|
var oldHOMEPATH = process.env.HOMEPATH;
|
||||||
|
process.env.NODE_RED_HOME = resourcesDir;
|
||||||
|
process.env.HOMEPATH = resourcesDir;
|
||||||
|
var homePath = path.join(resourcesDir, ".node-red");
|
||||||
|
fs.outputFile(path.join(homePath, ".config.json"),"",function(){
|
||||||
|
var homeContext = LocalFileSystem({
|
||||||
|
base: "contexts2",
|
||||||
|
cache: false
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
homeContext.open().then(function () {
|
||||||
|
homeContext.set("node2", "foo2", "bar2", function (err) {
|
||||||
|
homeContext.get("node2", "foo2", function (err, value) {
|
||||||
|
value.should.be.equal("bar2");
|
||||||
|
context.get("node2", "foo2", function (err, value) {
|
||||||
|
should.not.exist(value);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
process.env.NODE_RED_HOME = oldNRH;
|
||||||
|
process.env.HOMEPATH = oldHOMEPATH;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use HOME_PATH', function (done) {
|
||||||
|
var oldNRH = process.env.NODE_RED_HOME;
|
||||||
|
var oldHOMEPATH = process.env.HOMEPATH;
|
||||||
|
var oldHOME = process.env.HOME;
|
||||||
|
process.env.NODE_RED_HOME = resourcesDir;
|
||||||
|
process.env.HOMEPATH = resourcesDir;
|
||||||
|
process.env.HOME = resourcesDir;
|
||||||
|
var homeContext = LocalFileSystem({
|
||||||
|
base: "contexts2",
|
||||||
|
cache: false
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
homeContext.open().then(function () {
|
||||||
|
homeContext.set("node2", "foo2", "bar2", function (err) {
|
||||||
|
homeContext.get("node2", "foo2", function (err, value) {
|
||||||
|
value.should.be.equal("bar2");
|
||||||
|
context.get("node2", "foo2", function (err, value) {
|
||||||
|
should.not.exist(value);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
process.env.NODE_RED_HOME = oldNRH;
|
||||||
|
process.env.HOMEPATH = oldHOMEPATH;
|
||||||
|
process.env.HOME = oldHOME;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -144,6 +144,32 @@ describe('memory',function() {
|
|||||||
keysY.should.have.length(1);
|
keysY.should.have.length(1);
|
||||||
keysY[0].should.equal("hoge");
|
keysY[0].should.equal("hoge");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should enumerate global context keys', function () {
|
||||||
|
var keys = context.keys("global");
|
||||||
|
keys.should.be.an.Array();
|
||||||
|
keys.should.be.empty();
|
||||||
|
|
||||||
|
context.set("global", "foo", "bar");
|
||||||
|
keys = context.keys("global");
|
||||||
|
keys.should.have.length(1);
|
||||||
|
keys[0].should.equal("foo");
|
||||||
|
|
||||||
|
context.set("global", "abc.def", "bar");
|
||||||
|
keys = context.keys("global");
|
||||||
|
keys.should.have.length(2);
|
||||||
|
keys[1].should.equal("abc");
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not return specific keys as global context keys', function () {
|
||||||
|
var keys = context.keys("global");
|
||||||
|
|
||||||
|
context.set("global", "set", "bar");
|
||||||
|
context.set("global", "get", "bar");
|
||||||
|
context.set("global", "keys", "bar");
|
||||||
|
keys = context.keys("global");
|
||||||
|
keys.should.have.length(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('async',function() {
|
describe('async',function() {
|
||||||
@ -212,6 +238,14 @@ describe('memory',function() {
|
|||||||
should.not.exist(context.get("nodeY","foo"));
|
should.not.exist(context.get("nodeY","foo"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('should not clean global context', function () {
|
||||||
|
context.set("global", "foo", "abc");
|
||||||
|
context.get("global", "foo").should.equal("abc");
|
||||||
|
|
||||||
|
return context.clean(["global"]).then(function () {
|
||||||
|
should.exist(context.get("global", "foo"));
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user