forked from yotsumoto/casperjs-goto
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinfiniteloop.js
206 lines (176 loc) · 8.08 KB
/
infiniteloop.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/*!
* This script is demonstrating the new CasperJS Navigation Step Flow Control
* by adding new functions label() and goto().
*
* As a sample, this 'infiniteloop.js' is the minimum infinite loop.
*/
//================================================================================
var casper = require('casper').create({
// verbose: true, // true or false
// logLevel: 'debug', // 'debug' 'info' 'warning' 'error'
});
//================================================================================
//================================================================================
// Extending Casper functions for realizing label() and goto()
//
// Functions:
// checkStep() Revised original checkStep()
// then() Revised original then()
// label() New function for making empty new navigation step and affixing the new label on it.
// goto() New function for jumping to the labeled navigation step that is affixed by label()
// dumpSteps() New function for Dump Navigation Steps. This is very helpful as a flow control debugging tool.
//
var utils = require('utils');
var f = utils.format;
/**
* Revised checkStep() function for realizing label() and goto()
* Every revised points are commented.
*
* @param Casper self A self reference
* @param function onComplete An options callback to apply on completion
*/
casper.checkStep = function checkStep(self, onComplete) {
if (self.pendingWait || self.loadInProgress) {
return;
}
self.current = self.step; // Added: New Property. self.current is current execution step pointer
var step = self.steps[self.step++];
if (utils.isFunction(step)) {
self.runStep(step);
step.executed = true; // Added: This navigation step is executed already or not.
} else {
self.result.time = new Date().getTime() - self.startTime;
self.log(f("Done %s steps in %dms", self.steps.length, self.result.time), "info");
clearInterval(self.checker);
self.emit('run.complete');
if (utils.isFunction(onComplete)) {
try {
onComplete.call(self, self);
} catch (err) {
self.log("Could not complete final step: " + err, "error");
}
} else {
// default behavior is to exit
self.exit();
}
}
};
/**
* Revised then() function for realizing label() and goto()
* Every revised points are commented.
*
* @param function step A function to be called as a step
* @return Casper
*/
casper.then = function then(step) {
if (!this.started) {
throw new CasperError("Casper not started; please use Casper#start");
}
if (!utils.isFunction(step)) {
throw new CasperError("You can only define a step as a function");
}
// check if casper is running
if (this.checker === null) {
// append step to the end of the queue
step.level = 0;
this.steps.push(step);
step.executed = false; // Added: New Property. This navigation step is executed already or not.
this.emit('step.added', step); // Moved: from bottom
} else {
if( !this.steps[this.current].executed ) { // Added: Add step to this.steps only in the case of not being executed yet.
// insert substep a level deeper
try {
// step.level = this.steps[this.step - 1].level + 1; <=== Original
step.level = this.steps[this.current].level + 1; // Changed: (this.step-1) is not always current navigation step
} catch (e) {
step.level = 0;
}
var insertIndex = this.step;
while (this.steps[insertIndex] && step.level === this.steps[insertIndex].level) {
insertIndex++;
}
this.steps.splice(insertIndex, 0, step);
step.executed = false; // Added: New Property. This navigation step is executed already or not.
this.emit('step.added', step); // Moved: from bottom
} // Added: End of if() that is added.
}
// this.emit('step.added', step); // Move above. Because then() is not always adding step. only first execution time.
return this;
};
/**
* Adds a new navigation step by 'then()' with naming label
*
* @param String labelname Label name for naming execution step
*/
casper.label = function label( labelname ) {
var step = new Function('"empty function for label: ' + labelname + ' "'); // make empty step
step.label = labelname; // Adds new property 'label' to the step for label naming
this.then(step); // Adds new step by then()
};
/**
* Goto labeled navigation step
*
* @param String labelname Label name for jumping navigation step
*/
casper.goto = function goto( labelname ) {
for( var i=0; i<this.steps.length; i++ ){ // Search for label in steps array
if( this.steps[i].label == labelname ) { // found?
this.step = i; // new step pointer is set
}
}
};
// End of Extending Casper functions for realizing label() and goto()
//================================================================================
//================================================================================
//================================================================================
//================================================================================
// Extending Casper functions for dumpSteps()
/**
* Dump Navigation Steps for debugging
* When you call this function, you cat get current all information about CasperJS Navigation Steps
* This is compatible with label() and goto() functions already.
*
* @param Boolen showSource showing the source code in the navigation step?
*
* All step No. display is (steps array index + 1), in order to accord with logging [info] messages.
*
*/
casper.dumpSteps = function dumpSteps( showSource ) {
this.echo( "=========================== Dump Navigation Steps ==============================", "RED_BAR");
if( this.current ){ this.echo( "Current step No. = " + (this.current+1) , "INFO"); }
this.echo( "Next step No. = " + (this.step+1) , "INFO");
this.echo( "steps.length = " + this.steps.length , "INFO");
this.echo( "================================================================================", "WARNING" );
for( var i=0; i<this.steps.length; i++){
var step = this.steps[i];
var msg = "Step: " + (i+1) + "/" + this.steps.length + " level: " + step.level
if( step.executed ){ msg = msg + " executed: " + step.executed }
var color = "PARAMETER";
if( step.label ){ color="INFO"; msg = msg + " label: " + step.label }
if( i == this.current ) {
this.echo( msg + " <====== Current Navigation Step.", "COMMENT");
} else {
this.echo( msg, color );
}
if( showSource ) {
this.echo( "--------------------------------------------------------------------------------" );
this.echo( this.steps[i] );
this.echo( "================================================================================", "WARNING" );
}
}
};
// End of Extending Casper functions for dumpSteps()
//================================================================================
//================================================================================
//================================================================================
// The minimum infinite loop sample
casper.start();
casper.label( "LOOP_START" ); // LOOP_START label here: *** DO NOT put then() around label() for labeling ***
casper.then(function() {
this.echo( "Showing This Message Forever !" );
});
casper.then(function() { // *** NEED to put then() around goto() ***
this.goto( "LOOP_START" ); // unconditional jump for making infinite loop
});
casper.run();
//================================================================================