');
8 | phantom.exit(1);
9 | } else {
10 | port = system.args[1];
11 | var listening = server.listen(port, function (request, response) {
12 | console.log("GOT HTTP REQUEST");
13 | console.log(JSON.stringify(request, null, 4));
14 |
15 | // we set the headers here
16 | response.statusCode = 200;
17 | response.headers = {"Cache": "no-cache", "Content-Type": "text/html"};
18 | // this is also possible:
19 | response.setHeader("foo", "bar");
20 | // now we write the body
21 | // note: the headers above will now be sent implictly
22 | response.write("YES!");
23 | // note: writeBody can be called multiple times
24 | response.write("pretty cool :)");
25 | response.close();
26 | });
27 | if (!listening) {
28 | console.log("could not create web server listening on port " + port);
29 | phantom.exit();
30 | }
31 | var url = "http://localhost:" + port + "/foo/bar.php?asdf=true";
32 | console.log("SENDING REQUEST TO:");
33 | console.log(url);
34 | page.open(url, function (status) {
35 | if (status !== 'success') {
36 | console.log('FAIL to load the address');
37 | } else {
38 | console.log("GOT REPLY FROM SERVER:");
39 | console.log(page.content);
40 | }
41 | phantom.exit();
42 | });
43 | }
44 |
--------------------------------------------------------------------------------
/examples/serverkeepalive.js:
--------------------------------------------------------------------------------
1 | var port, server, service,
2 | system = require('system');
3 |
4 | if (system.args.length !== 2) {
5 | console.log('Usage: serverkeepalive.js ');
6 | phantom.exit(1);
7 | } else {
8 | port = system.args[1];
9 | server = require('webserver').create();
10 |
11 | service = server.listen(port, { keepAlive: true }, function (request, response) {
12 | console.log('Request at ' + new Date());
13 | console.log(JSON.stringify(request, null, 4));
14 |
15 | var body = JSON.stringify(request, null, 4);
16 | console.log(body.length);
17 | response.statusCode = 200;
18 | response.headers = {
19 | 'Cache': 'no-cache',
20 | 'Content-Type': 'text/plain',
21 | 'Connection': 'Keep-Alive',
22 | 'Keep-Alive': 'timeout=5, max=100',
23 | 'Content-Length': body.length
24 | };
25 | response.write(body);
26 | response.close();
27 | });
28 |
29 | if (service) {
30 | console.log('Web server running on port ' + port);
31 | } else {
32 | console.log('Error: Could not create web server listening on port ' + port);
33 | phantom.exit();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/examples/simpleserver.js:
--------------------------------------------------------------------------------
1 | var port, server, service,
2 | system = require('system');
3 |
4 | if (system.args.length !== 2) {
5 | console.log('Usage: simpleserver.js ');
6 | phantom.exit(1);
7 | } else {
8 | port = system.args[1];
9 | server = require('webserver').create();
10 |
11 | service = server.listen(port, function (request, response) {
12 |
13 | console.log('Request at ' + new Date());
14 | console.log(JSON.stringify(request, null, 4));
15 |
16 | response.statusCode = 200;
17 | response.headers = {
18 | 'Cache': 'no-cache',
19 | 'Content-Type': 'text/html'
20 | };
21 | response.write('');
22 | response.write('');
23 | response.write('Hello, world!');
24 | response.write('');
25 | response.write('');
26 | response.write('This is from PhantomJS web server.
');
27 | response.write('Request data:
');
28 | response.write('');
29 | response.write(JSON.stringify(request, null, 4));
30 | response.write('
');
31 | response.write('');
32 | response.write('');
33 | response.close();
34 | });
35 |
36 | if (service) {
37 | console.log('Web server running on port ' + port);
38 | } else {
39 | console.log('Error: Could not create web server listening on port ' + port);
40 | phantom.exit();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/examples/staticserver.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | var server = require('webserver').create();
4 | var fs = require('fs');
5 |
6 | server.listen(8897, function(request, response) {
7 | console.log('requested url--> ' + request.url);
8 | var path = request.url;
9 | if (!path || path === '/') path = '/index.html';
10 | response.write(fs.read('www' + path));
11 | response.close();
12 | });
13 |
14 |
--------------------------------------------------------------------------------
/examples/test.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 |
4 |
5 |
6 | var page = new WebPage();
7 |
8 | var msg = "message",
9 | value = "value",
10 | result,
11 | expected = "extra-value";
12 | page.onPrompt = function(msg, value) {
13 | return "extra-"+value;
14 | };
15 | result = page.evaluate(function(m, v) {
16 | return window.prompt(m, v);
17 | }, msg, value);
18 | console.log("checkPagePrompt:result(should be : " + expected + "):" + result);
19 |
20 |
21 |
22 | var sys = require("system");
23 |
24 | console.log("sys.pid: " + sys.pid);
25 | console.log("sys.os: ", sys.os);
26 | console.log("sys.env: ", sys.env);
27 |
28 | */
29 |
30 | /*
31 | var page = new WebPage();
32 | page.open("http://www.google.com", function() {
33 | console.log("page.url", page.url);
34 | console.log("page.title", page.title);
35 | console.log("page.plainText", page.plainText);
36 | })
37 | */
38 |
39 | var fs = require("fs");
40 | var path = "examples/test.js";
41 |
42 | var pathInfo = {
43 | absolute: fs.absolute(path),
44 | list: fs.list(path),
45 | size: Math.round(fs.size(path) / 1024),
46 | exists: fs.exists(path),
47 | isDirectory: fs.isDirectory(path),
48 | isFile: fs.isFile(path)
49 | }
50 |
51 | console.log("pathInfo:", pathInfo);
52 |
53 | if (pathInfo.isFile) {
54 | console.log("Reading file " + path);
55 | console.log(fs.read(path));
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/examples/universe.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | // This is to be used by "module.js" (and "module.coffee") example(s).
4 | // There should NOT be a "universe.coffee" as only 1 of the 2 would
5 | // ever be loaded unless the file extension was specified.
6 |
7 | exports.answer = 42;
8 |
9 | exports.start = function () {
10 | console.log('Starting the universe....');
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/examples/variable.js:
--------------------------------------------------------------------------------
1 |
2 | // This is a simple example of how to set a variable
3 | // Its used internally for testing script injection
4 | // phantom.injectJs();
5 |
6 | var ___test190234 = [] instanceof Array;
7 |
--------------------------------------------------------------------------------
/examples/version.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | var phantom_version = Object.keys(phantom.version).map(function(k) {return phantom.version[k]});
4 | var trifle_version = Object.keys(trifle.version).map(function(k) {return trifle.version[k]});
5 | var ie_version = trifle.emulation;
6 |
7 | console.log('phantomjs -> ' + phantom_version.join('.'));
8 | console.log('triflejs -> ' + trifle_version.join('.'));
9 | console.log('internet explorer -> ' + ie_version);
10 | console.log('userAgent -> ' + navigator.userAgent);
11 |
12 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdesalas/trifleJS/363fc3d3f168a261be2deb1f664017e0ec43bf8e/favicon.ico
--------------------------------------------------------------------------------
/includes/trifle/Callback.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Callback.js
3 | *
4 | * By: Steven de Salas
5 | * On: Sep 2013
6 | *
7 | * Generates a Callback object used for async
8 | * communication between V8 and C# runtime.
9 | *
10 | */
11 |
12 | // Initialise Namespace
13 | this.trifle = this.trifle || {};
14 |
15 | // Wrap code to avoid global vars
16 | (function(trifle) {
17 |
18 | // Closure variable that tracks existing callbacks
19 | // (hidden from outside world)
20 | var callbacks = {};
21 |
22 | // Callback Class
23 | // Define Constructor
24 | var Callback = trifle.Callback = function(func, scope, defaultArgs) {
25 | this.func = func;
26 | this.scope = scope;
27 | this.defaultArgs = defaultArgs;
28 | this.id = Callback.newUid();
29 | console.xdebug('new Callback#' + this.id + '(func, scope, defaultArgs)');
30 | callbacks[this.id] = this;
31 | };
32 |
33 | // Unique ID Generator
34 | Callback.newUid = function() {
35 | var s4 = function() {
36 | return Math.floor((1 + Math.random()) * 0x10000)
37 | .toString(16)
38 | .substring(1);
39 | };
40 | return s4() + s4();
41 | };
42 |
43 | // Execute callback
44 | Callback.execute = function(id, args) {
45 | console.xdebug('Callback.execute("' + id + '", [args])');
46 | var callback = callbacks[id];
47 | if (callback) {
48 | if (!args || !args.length) {
49 | args = callback.defaultArgs;
50 | }
51 | callback.func.apply(callback.scope || callback, args);
52 | }
53 | }
54 |
55 | // Execute callback and delete reference
56 | Callback.executeOnce = function(id, args) {
57 | console.xdebug('Callback.executeOnce("' + id + '", [args])');
58 | if (typeof id === 'string') {
59 | Callback.execute(id, args);
60 | delete callbacks[id];
61 | }
62 | }
63 |
64 | // Generates a callback and returns the id
65 | Callback.id = function(func, scope, defaultArgs) {
66 | return (new Callback(func, scope, defaultArgs)).id;
67 | };
68 |
69 |
70 | })(this.trifle);
71 |
72 |
--------------------------------------------------------------------------------
/includes/trifle/ie/tools.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * TRIFLEJS IE TOOLS
4 | * By: Steven de Salas
5 | */
6 |
7 | // Add OnCallback functionality
8 | window.callPhantom = function() {
9 | window.external.xdebug('window.callPhantom(args)');
10 | var args = [];
11 | for (var i = 0; i < arguments.length; i++) {
12 | args.push(arguments[i]);
13 | }
14 | return window.external.fireEvent('callback', JSON.stringify(args));
15 | }
16 |
17 | // Override javascript alert
18 | window.alert = function(message) {
19 | window.external.xdebug('window.alert()');
20 | message = message + "";
21 | return window.external.fireEvent('alert', JSON.stringify([message]));
22 | }
23 |
24 | // Override javascript confirm
25 | window.confirm = function(message) {
26 | window.external.xdebug('window.confirm()');
27 | message = message + "";
28 | return window.external.fireEvent('confirm', JSON.stringify([message]));
29 | }
30 |
31 | // Override javascript prompt.
32 | window.prompt = function(message, defaultValue) {
33 | window.external.xdebug('window.prompt()');
34 | message = message + "";
35 | return window.external.fireEvent('prompt', JSON.stringify([message, defaultValue || ""]));
36 | }
37 |
38 | // Capture javascript errors
39 | window.onerror = function(msg, url, line, col, e) {
40 | var caller = arguments.callee ? arguments.callee.caller : '';
41 | var trace = [{file: url, line: line, col: col, 'function': caller.toString()}];
42 | while (!!caller.caller) {
43 | trace.push({func: caller.caller.toString()});
44 | caller = caller.caller;
45 | }
46 | return window.external.fireEvent('error', JSON.stringify([msg, trace]));
47 | }
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/includes/trifle/modules/ChildProcess.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ChildProcess.js
3 | *
4 | * By: Steven de Salas
5 | * On: Jan 2015
6 | *
7 | * Defines a ChildProcess class representing a
8 | * helper to spawn and manage new child processes
9 | *
10 | */
11 |
12 | // Initialise Namespace
13 | this.trifle = this.trifle || {};
14 | trifle.modules = trifle.modules || {};
15 |
16 | // Wrap code to avoid global vars
17 | (function(trifle) {
18 |
19 | // Private
20 | var Callback = trifle.Callback;
21 |
22 | // Define Module
23 | var ChildProcess = trifle.modules.ChildProcess = trifle.extend({
24 |
25 | // Derives functionality from ChildProcess.cs
26 | module: trifle.API.ChildProcess,
27 |
28 | // Constructor
29 | init: function() {
30 | console.xdebug("new ChildProcess()");
31 | },
32 |
33 | // Additional methods
34 | methods: {
35 | // Decorate a childprocess context with event listeners
36 | // to support 'stdout' and 'stderr' events
37 | // as well as their counterpart 'fakestream' objects
38 | decorate: function(ctx) {
39 | if (ctx) {
40 | // Add StdOut and StdErr Events
41 | Object.addEvent(ctx, "onExit");
42 | Object.addEvent(ctx, "onStdOut");
43 | Object.addEvent(ctx, "onStdErr");
44 | // Pipe output to stdout and stderr 'fakestream' objects
45 | ctx.stdout = {};
46 | ctx.stderr = {};
47 | Object.addEvent(ctx.stdout, "onData");
48 | Object.addEvent(ctx.stderr, "onData");
49 | ctx.on('stdout', function(data) {
50 | ctx.stdout.fireEvent('data', [data]);
51 | });
52 | ctx.on('stderr', function(data) {
53 | ctx.stderr.fireEvent('data', [data]);
54 | });
55 | }
56 | return ctx;
57 | },
58 | spawn: function(cmd, args, opts) {
59 | // Add event listeners, spawn and return context object
60 | var context;
61 | var exit = function(id, code) {context.fireEvent('exit', [code]);};
62 | var stdout = function(data) {context.fireEvent('stdout', [data]);};
63 | var stderr = function(data) {context.fireEvent('stderr', [data]);};
64 | context = this._spawn(cmd, args || [], opts, Callback.id(exit), Callback.id(stdout), Callback.id(stderr));
65 | return this.decorate(context);
66 | },
67 | execFile: function(cmd, args, opts, callback) {
68 | var cp = this;
69 | var complete = function(contextId) {
70 | // Execute callback
71 | var context = cp._findContext(contextId);
72 | if (context && callback && callback.call) {
73 | return callback.call(cp, null, context.output, context.errorOutput);
74 | }
75 | };
76 | // Execute and return context object
77 | return this._execFile(cmd, args || [], opts, Callback.id(complete));
78 | },
79 | execSync: function(cmd, args, opts) {
80 | if (cmd) {
81 | return this._execSync(cmd, args || [], opts);
82 | }
83 | }
84 | }
85 |
86 | });
87 |
88 |
89 | })(this.trifle);
90 |
91 |
--------------------------------------------------------------------------------
/includes/trifle/modules/FileSystem.js:
--------------------------------------------------------------------------------
1 | /*
2 | * FileSystem.js
3 | *
4 | * By: Steven de Salas
5 | * On: Sep 2013
6 | *
7 | * Defines a FileSystem class representing a
8 | * helper for file read/write operations and management.
9 | *
10 | */
11 |
12 | // Initialise Namespace
13 | this.trifle = this.trifle || {};
14 | trifle.modules = trifle.modules || {};
15 |
16 | // Wrap code to avoid global vars
17 | (function(trifle) {
18 |
19 |
20 | // Define Module
21 | var FileSystem = trifle.modules.FileSystem = trifle.extend({
22 |
23 | // Derives functionality from FileSystem.cs
24 | module: trifle.API.FileSystem,
25 |
26 | // Constructor
27 | init: function() {
28 | console.xdebug("new FileSystem()");
29 | },
30 |
31 | // Additional methods
32 | methods: {
33 |
34 | }
35 |
36 | });
37 |
38 |
39 | })(this.trifle);
40 |
41 |
--------------------------------------------------------------------------------
/includes/trifle/modules/System.js:
--------------------------------------------------------------------------------
1 | /*
2 | * System.js
3 | *
4 | * By: Steven de Salas
5 | * On: Sep 2013
6 | *
7 | * Defines a System class representing a
8 | * general program helper.
9 | *
10 | */
11 |
12 | // Initialise Namespace
13 | this.trifle = this.trifle || {};
14 | trifle.modules = trifle.modules || {};
15 |
16 | // Wrap code to avoid global vars
17 | (function(trifle) {
18 |
19 |
20 | // Define Module
21 | var System = trifle.modules.System = trifle.extend({
22 |
23 | // Derives functionality from System.cs
24 | module: trifle.API.System,
25 |
26 | // Constructor
27 | init: function() {
28 | console.xdebug("new System()");
29 | }
30 |
31 | });
32 |
33 |
34 | })(this.trifle);
35 |
36 |
--------------------------------------------------------------------------------
/includes/trifle/modules/WebPage.js:
--------------------------------------------------------------------------------
1 | /*
2 | * WebPage.js
3 | *
4 | * By: Steven de Salas
5 | * On: Sep 2013
6 | *
7 | * Defines an object representing a
8 | * browser page opened inside IE environment.
9 | *
10 | */
11 |
12 | // Initialise Namespace
13 | this.trifle = this.trifle || {};
14 | this.trifle.modules = this.trifle.modules || {};
15 |
16 | // Wrap code to avoid global vars
17 | (function (trifle) {
18 |
19 | // Private
20 | var Callback = trifle.Callback;
21 |
22 | // Define Module
23 | var WebPage = this.WebPage = window.WebPage = trifle.modules.WebPage = trifle.extend({
24 |
25 | // Derives functionality from WebPage.cs
26 | module: trifle.API.WebPage,
27 |
28 | // Constructor
29 | init: function() {
30 | console.xdebug("new WebPage()");
31 | // Properties
32 | this.objectName = "WebPage";
33 | // Store reference
34 | WebPage.all[this.uuid] = this;
35 | // Add Events
36 | Object.addEvent(this, 'onCallback');
37 | Object.addEvent(this, 'onInitialized');
38 | Object.addEvent(this, 'onAlert');
39 | Object.addEvent(this, 'onConfirm', true); // unique (uses return value)
40 | Object.addEvent(this, 'onPrompt', true); // unique (uses return value)
41 | Object.addEvent(this, 'onError');
42 | Object.addEvent(this, 'onLoadStarted');
43 | Object.addEvent(this, 'onLoadFinished');
44 | Object.addEvent(this, 'onUrlChanged');
45 | Object.addEvent(this, 'onNavigationRequested');
46 | // Add event route between 'internalpagecreated' and 'pagecreated'
47 | // this allows us to use objects from V8 context
48 | // (regardless of where trigger comes from) when firing 'pagecreated'.
49 | Object.addEvent(this, 'onInternalPageCreated');
50 | Object.addEvent(this, 'onPageCreated');
51 | this.on('internalpagecreated', function() {
52 | return this.fireEvent('pagecreated');
53 | });
54 | // Add event route between 'internalclosing' and 'closing'
55 | // using same logic as above.
56 | Object.addEvent(this, 'onInternalClosing');
57 | Object.addEvent(this, 'onClosing');
58 | this.on('internalclosing', function() {
59 | return this.fireEvent('closing', [this]);
60 | });
61 | // Clear the COM event pipeline
62 | trifle.wait(1);
63 | },
64 |
65 | // Additional methods
66 | methods: {
67 |
68 | // Opens a URL
69 | open: function() {
70 | console.xdebug("WebPage.prototype.open()");
71 | var page = this, a = arguments;
72 | // Determine the arguments to use
73 | var url = a[0], method = "GET", data, headers, callback;
74 | // Using: page.open(url, method, data, callback)
75 | if (typeof a[4] === "function") {
76 | method = a[1];
77 | data = a[2];
78 | headers = a[3];
79 | callback = a[4];
80 | }
81 | // Using: page.open(url, method, data, callback)
82 | if (typeof a[3] === "function") {
83 | method = a[1];
84 | data = a[2];
85 | callback = a[3];
86 | }
87 | // Using: page.open(url, method, callback)
88 | else if (typeof a[2] === "function") {
89 | method = a[1];
90 | callback = a[2];
91 | }
92 | // Using: page.open(url, callback)
93 | else if (typeof a[1] === "function") {
94 | callback = a[1];
95 | }
96 | // Instantiate Callback
97 | var complete = function(status) {
98 | // Execute callback
99 | if (callback && callback.call) {
100 | return !!callback ? callback.call(page, status) : null;
101 | }
102 | };
103 | // Open URL in .NET API
104 | return this._open(url, method, data, Callback.id(complete));
105 | },
106 |
107 | // Executes a JavaScript code string in the browser
108 | evaluateJavaScript: function(code) {
109 | console.xdebug("WebPage.prototype.evaluateJavaScript(code)");
110 | if (code && typeof code === "string") {
111 | // Execute JS on IE host
112 | return this._evaluateJavaScript(code);
113 | }
114 | },
115 |
116 |
117 | // Executes a javascript function inside the browser
118 | evaluate: function(func) {
119 | console.xdebug("WebPage.prototype.evaluate(func)");
120 | if (!(typeof func === 'function' || typeof func === 'string' || func instanceof String)) {
121 | throw "Wrong use of WebPage.evaluate()";
122 | }
123 | var args = [];
124 | for (var i = 1; i < arguments.length; i++) {
125 | // Fix undefined (coming up as null)
126 | if (arguments[i] === undefined) {
127 | arguments[i] = "{{undefined}}";
128 | }
129 | args.push(arguments[i]);
130 | }
131 | // Execute JS on IE host
132 | return JSON.parse(this._evaluate(func.toString(), args));
133 | },
134 |
135 | // Evaluations a function in the context of the page without
136 | // blocking execution. Can be delayed by a specific timeout.
137 | evaluateAsync: function(func, timeMs) {
138 | console.xdebug("WebPage.prototype.evaluateAsync(func)");
139 | if (!(typeof func === 'function' || typeof func === 'string' || func instanceof String)) {
140 | throw "Wrong use of WebPage.evaluateAsync()";
141 | }
142 | var page = this, args = Array.prototype.slice.call(arguments, 2);
143 | args.unshift(func);
144 | window.setTimeout(function() {
145 | page.evaluate.apply(page, args);
146 | }, timeMs || 0);
147 | },
148 |
149 | // Injects a local JavaScript file into the browser
150 | injectJs: function(filename) {
151 | console.xdebug("WebPage.prototype.injectJs(filename)");
152 | if (typeof filename === 'string') {
153 | // Execute JS on IE host
154 | return this._injectJs(filename);
155 | }
156 | },
157 |
158 | // Includes a JS file from remote URL and executes it on the browser
159 | includeJs: function(url, callback) {
160 | console.xdebug("WebPage.prototype.includeJs(url, callback)");
161 | var page = this;
162 | if (typeof url === 'string') {
163 | var complete = function() {
164 | if (callback && callback.call) {
165 | callback.call(page);
166 | }
167 | };
168 | // Execute JS on IE host
169 | return this._includeJs(url, Callback.id(complete));
170 | }
171 | },
172 |
173 | // Sends mouse/keyboard event to the browser
174 | sendEvent: function(type) {
175 | console.xdebug("WebPage.prototype.sendEvent(type)");
176 | return this._sendEvent(type, Array.prototype.slice.call(arguments, 1));
177 | },
178 |
179 | /**
180 | * Renders screen to a file
181 | * @param filename
182 | * @return {*}
183 | */
184 | render: function(filename) {
185 | console.xdebug("WebPage.prototype.render(filename)");
186 | if (filename) {
187 | return this._render(filename)
188 | };
189 | },
190 |
191 | /**
192 | * Renders screen to base64 string
193 | * @param format
194 | * @return {*}
195 | */
196 | renderBase64: function(format) {
197 | console.xdebug("WebPage.prototype.renderBase64(format)");
198 | return this._renderBase64(format || "PNG");
199 | },
200 |
201 | /**
202 | * Closes current window and disposes of resources
203 | */
204 | close: function() {
205 | this.fireEvent('internalclosing');
206 | this._close();
207 | }
208 |
209 | }
210 |
211 | });
212 |
213 | // STATIC PROPERTIES
214 |
215 | // HashMap of instantiated pages
216 | WebPage.all = {};
217 |
218 | // Add static fireEvent() method for event handling
219 | WebPage.fireEvent = function(nickname, uuid, args) {
220 | console.xdebug("WebPage.fireEvent('" + nickname + "', uuid, args)");
221 | var page = WebPage.all[uuid];
222 | if (page && page.fireEvent) {
223 | return page.fireEvent(nickname, args);
224 | }
225 | };
226 |
227 |
228 | })(this.trifle);
229 |
230 |
--------------------------------------------------------------------------------
/includes/trifle/modules/WebServer.js:
--------------------------------------------------------------------------------
1 | /*
2 | * WebServer.js
3 | *
4 | * By: Steven de Salas
5 | * On: Jan 2014
6 | *
7 | * Defines a WebServer class representing a
8 | * HTTP Daemon.
9 | *
10 | */
11 |
12 | // Initialise Namespace
13 | this.trifle = this.trifle || {};
14 | trifle.modules = trifle.modules || {};
15 |
16 | // Wrap code to avoid global vars
17 | (function (trifle) {
18 |
19 | // Private
20 | var Callback = trifle.Callback;
21 |
22 | // Define Module
23 | var WebServer = trifle.modules.WebServer = trifle.extend({
24 |
25 | // Derives functionality from WebServer.cs
26 | module: trifle.API.WebServer,
27 |
28 | // Constructor
29 | init: function() {
30 | console.xdebug("new WebServer()");
31 | // Properties
32 | this.objectName = "WebServer";
33 | },
34 |
35 | // Additional methods
36 | methods: {
37 |
38 | // Listen for incoming requests
39 | listen: function(binding, opts, callback) {
40 | console.xdebug("Webserver.prototype.listen(binding, opts, callback)");
41 | var API = this;
42 | if (typeof callback === 'undefined' && typeof opts === 'function') {
43 | callback = opts;
44 | opts = {};
45 | }
46 |
47 | // Instantiate Callback
48 | var complete = function(connectionId) {
49 | // Get Request & Response
50 | var request = API._getRequest(connectionId);
51 | var response = API._getResponse(connectionId);
52 | // Decorate request object so it can be printed using console.log() or JSON.stringify()
53 | request.headers = request._headers;
54 | request.httpVersion = request._httpVersion;
55 | request.method = request._method;
56 | if (request.method === "POST")
57 | {
58 | request.post = request._post;
59 | request.postRaw = request._postRaw;
60 | }
61 | request.url = request._url;
62 | // Execute callback
63 | if (callback && callback.call) {
64 | var result = !!callback ? callback.call(API, request, response) : null;
65 | if (!opts.keepAlive) {
66 | response.close();
67 | }
68 | return result;
69 | }
70 | };
71 | // Start listening on binding
72 | return API._listen(binding, Callback.id(complete));
73 | }
74 | }
75 | });
76 |
77 |
78 | })(this.trifle);
79 |
80 |
--------------------------------------------------------------------------------
/test/feature/console.log.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* console.log() */
4 |
5 | console.log(1);
6 | console.log('a string');
7 | console.log(null);
8 | console.log(NaN);
9 | console.log(undefined);
10 | console.log(function() { var a = 1; });
11 | console.log({an: 'object'});
12 | console.log([1, 'array']);
13 |
14 | phantom.exit();
--------------------------------------------------------------------------------
/test/feature/fs.changeWorkingDirectory.js:
--------------------------------------------------------------------------------
1 |
2 | var fs = require('fs');
3 |
4 | console.log("Current Working Dir: " + fs.workingDirectory);
5 | fs.changeWorkingDirectory("C:/");
6 | console.log("Current Working Dir: " + fs.workingDirectory);
7 |
8 | phantom.exit();
9 |
10 |
--------------------------------------------------------------------------------
/test/feature/opts.ignore-ssl.js:
--------------------------------------------------------------------------------
1 |
2 | // triflejs.exe ..\..\test\feature\opts.ignore-ssl.js --ignore-ssl-errors=true
3 |
4 | var page = require("webpage").create();
5 |
6 | page.open("https://localhost", function(status) {
7 | if (status === 'success') {
8 | page.render("ingnore-ssl.png");
9 | console.log('Page rendered');
10 | } else {
11 | console.error('Cannot load url.');
12 | }
13 | phantom.exit();
14 | });
15 |
--------------------------------------------------------------------------------
/test/feature/opts.proxy.js:
--------------------------------------------------------------------------------
1 |
2 | // triflejs.exe ..\..\test\feature\opts.proxy.js --proxy=localhost:8080 --proxy-auth=MacUser:123456
3 |
4 | var page = require("webpage").create();
5 |
6 | page.open("http://www.triflejs.org", function(status) {
7 | if (status === 'success') {
8 | page.render("triflejs.org.png");
9 | console.log('Page rendered');
10 | } else {
11 | console.error('Cannot load url.');
12 | }
13 | phantom.exit();
14 | });
15 |
16 |
--------------------------------------------------------------------------------
/test/feature/page.clipRect.js:
--------------------------------------------------------------------------------
1 | var page = require("webpage").create();
2 | /*
3 | page.clipRect = {
4 | left: 150,
5 | top: 150,
6 | width: 200,
7 | height: 200
8 | };
9 | */
10 | // page.zoomFactor = 2;
11 |
12 | page.open("http://www.triflejs.org", function(status) {
13 | if (status === 'success') {
14 | page.render("triflejs.org.png");
15 | console.log('Page rendered');
16 | } else {
17 | console.error('Cannot load url.');
18 | }
19 | phantom.exit();
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/test/feature/page.customHeaders.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | var page = require("webpage").create();
4 |
5 | page.customHeaders = {
6 | 'X-Test': 'foo',
7 | 'DNT': 1,
8 | 'scooby': 'doo'
9 | }
10 |
11 | page.open("http://www.xhaus.com/headers", function(status) {
12 | if (status === 'success') {
13 | page.render("headers.png");
14 | console.log('Page rendered');
15 | } else {
16 | console.error('Cannot load url.');
17 | }
18 | phantom.exit();
19 | });
--------------------------------------------------------------------------------
/test/feature/page.evaluate.js:
--------------------------------------------------------------------------------
1 | var page = require("webpage").create();
2 |
3 | console.log(trifle);
4 |
5 | page.open("http://www.phantomjs.org", function(status) {
6 | if (status === 'success') {
7 | var message = page.evaluate(function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) {
8 | var result = arg1 + arg2 + arg3[0] + arg3[1] + arg4.a + ' ' + arg5 + arg6;
9 | if (arg7 === null) {
10 | result += arg7;
11 | };
12 | if (arg8 === undefined) {
13 | result += arg8;
14 | }
15 | return result;
16 | }, 'message 1', 234, [5, '6'], { a: "78" }, !true, NaN, null, undefined);
17 | if (message === 'message 12345678 falseNaNnullundefined') {
18 | console.log('GOOD! ' + message);
19 | } else {
20 | console.error('ERROR! ' + message);
21 | }
22 | } else {
23 | console.error('ERROR! Cannot load url.');
24 | }
25 | phantom.exit();
26 | });
--------------------------------------------------------------------------------
/test/feature/page.evaluateJavaScript.js:
--------------------------------------------------------------------------------
1 | var page = require("webpage").create();
2 |
3 | page.open("http://www.phantomjs.org", function(status) {
4 | if (status === 'success') {
5 | page.evaluateJavaScript('var message = "hello from ie";');
6 | var message = page.evaluate(function() {
7 | return message;
8 | });
9 | if (message === 'hello from ie') {
10 | console.log('GOOD!' + message);
11 | } else {
12 | console.error('ERROR! ' + message);
13 | }
14 | } else {
15 | console.error('ERROR! Cannot load url.');
16 | }
17 | phantom.exit();
18 | });
--------------------------------------------------------------------------------
/test/feature/page.eventLifecycle.js:
--------------------------------------------------------------------------------
1 |
2 | var page = require('webpage').create();
3 | var server = require('webserver').create();
4 |
5 | // Start a listener to check events
6 | server.listen(8083, function(request, response) {
7 | var bodyText = JSON.stringify({
8 | success: true,
9 | url: request.url
10 | });
11 | response.write('eventtest9837423401' +
12 | '' +
13 | '' + bodyText + '');
14 | response.close();
15 | });
16 |
17 |
18 | page.onLoadStarted = function() {
19 | console.log("LoadStarted");
20 | }
21 |
22 | page.onLoadFinished = function(status) {
23 | console.log("LoadFinished");
24 | }
25 | page.onInitialized = function () {
26 | console.log("Initialized");
27 | }
28 | page.onCallback = function(event) {
29 | console.log('Callback: ' + event);
30 | };
31 | page.evaluate(function () {
32 | callPhantom('beforeopen');
33 | });
34 | page.open('http://localhost:8083/', function (status) {
35 | //phantom.exit();
36 | });
37 |
38 |
39 |
--------------------------------------------------------------------------------
/test/feature/page.includeJs.js:
--------------------------------------------------------------------------------
1 | var page = require("webpage").create();
2 |
3 | page.open("http://www.phantomjs.org", function(status) {
4 | page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
5 | console.log(page.evaluate(function() {
6 | return $("#intro").text();
7 | }));
8 | console.wait(5000);
9 | phantom.exit();
10 | });
11 | });
--------------------------------------------------------------------------------
/test/feature/page.injectJs.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/feature/page.js:
--------------------------------------------------------------------------------
1 | var page = require("webpage").create();
2 |
3 | page.open("http://www.phantomjs.org", function(status) {
4 | console.log("Page load finished, status: " + status);
5 | page.evaluateJavaScript('var message = "hello from ie";');
6 | console.log(page.evaluate(function(message1, message2, message3) { return message + message1 + message2 + message3; }, 'hello argument1', 'argument2', 3));
7 | page.render("phantomjs.org.png");
8 | page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
9 | console.log(page.evaluate(function() {
10 | return $("#intro").text();
11 | }));
12 | trifle.wait(5000);
13 | phantom.exit();
14 | });
15 | });
--------------------------------------------------------------------------------
/test/feature/page.onAlert.js:
--------------------------------------------------------------------------------
1 | var page = new WebPage();
2 | page.onAlert = function(data, data2) {
3 | console.log(data, data2);
4 | }
5 |
6 | page.evaluateJavaScript("alert('onAlert Test');");
7 |
8 |
--------------------------------------------------------------------------------
/test/feature/page.onCallback.js:
--------------------------------------------------------------------------------
1 | console.log("STARTING");
2 | var page = new WebPage();
3 | page.onCallback = function(data, data2) {
4 | console.log(data, data2);
5 | }
6 |
7 | page.evaluateJavaScript("callPhantom({a: 1}, 'blah');");
8 | console.log("DONE!");
9 |
10 | console.log("STARTING ROUND 2");
11 | var page = new WebPage();
12 | var msgA = "a",
13 | msgB = "b",
14 | result,
15 | expected = msgA + msgB;
16 |
17 | page.onCallback = function(a, b) {
18 | console.log("page.onCallback()", a, b);
19 | return a + b;
20 | };
21 |
22 | result = page.evaluate(function(a, b) {
23 | var x = callPhantom(a, b);
24 | alert("callPhantom() complete: " + x);
25 | return x;
26 | }, msgA, msgB);
27 |
28 | console.log("RESULT:" + result);
29 | console.log("DONE!");
30 | phantom.exit();
--------------------------------------------------------------------------------
/test/feature/page.onConfirm.js:
--------------------------------------------------------------------------------
1 | var page = new WebPage();
2 |
3 | page.onAlert = function(message) {
4 | console.log("onAlert: " + message);
5 | }
6 |
7 | page.onConfirm = function(message) {
8 | console.log("onConfirm", message);
9 | return false;
10 | }
11 |
12 | page.evaluateJavaScript("alert(confirm('onAlert Test'));");
13 |
14 |
--------------------------------------------------------------------------------
/test/feature/page.open.js:
--------------------------------------------------------------------------------
1 | var page = require("webpage").create();
2 | var server = require("webserver").create();
3 |
4 | server.listen(8080, function(request, response) {
5 | console.log({
6 | method: request.method,
7 | url: request.url,
8 | httpVersion: request.httpVersion,
9 | headers: request.headers,
10 | post: request.post,
11 | rawPost: request.rawPost
12 | });
13 | response.close();
14 | });
15 |
16 | // GET
17 | page.open("http://localhost:8080/get", function(status) {
18 | if (status !== 'success') {
19 | console.error('Cannot load url.');
20 | }
21 | });
22 |
23 |
24 | page.customHeaders = {
25 | 'X-Test': 'foo',
26 | 'DNT': 1,
27 | 'scooby': 'doo'
28 | }
29 |
30 | //POST
31 | page.open("http://localhost:8080/post?custom-headers", "POST", "blah", function(status) {
32 | if (status !== 'success') {
33 | console.error('Cannot load url.');
34 | }
35 | });
36 |
37 |
38 | // FORM POST
39 | page.open("http://localhost:8080/post?form-data", 'post', "universe=expanding&answer=42", { "Content-Type" : "application/x-www-form-urlencoded" }, function (status) {
40 | if (status !== 'success') {
41 | console.error('Cannot load url.');
42 | }
43 | phantom.exit();
44 | });
45 |
--------------------------------------------------------------------------------
/test/feature/page.open.x2.js:
--------------------------------------------------------------------------------
1 |
2 | var page = new WebPage();
3 |
4 | // Open first page
5 | page.viewportSize = {width: 1024, height: 800};
6 | page.open("http://en.wikipedia.org/", function(status) {
7 | if (status !== "success") { console.log("FAIL to load the address"); phantom.exit(); }
8 | page.render('open1.png');
9 |
10 | page.open("http://google.com/");
11 |
12 | // Open second page
13 | page.open("http://en.wikipedia.org/wiki/V8_(JavaScript_engine)", function(status) {
14 | if (status !== "success") { console.log("FAIL to load the address"); phantom.exit(); }
15 | page.render('open2.png');
16 | console.log("Success, both pages opened.");
17 | phantom.exit(); // last open so exit
18 | });
19 |
20 | });
--------------------------------------------------------------------------------
/test/feature/page.render.js:
--------------------------------------------------------------------------------
1 | var page = require("webpage").create();
2 |
3 | page.open("http://www.triflejs.org", function(status) {
4 | if (status === 'success') {
5 | page.render("triflejs.org.png");
6 | console.log('Page rendered');
7 | } else {
8 | console.error('Cannot load url.');
9 | }
10 | phantom.exit();
11 | });
12 |
13 |
--------------------------------------------------------------------------------
/test/feature/page.render.noscrollbar.js:
--------------------------------------------------------------------------------
1 | var page = require('webpage').create();
2 | var url = 'http://wikipedia.org';
3 | var width = 1366;
4 | var height = 1768;
5 | var file = 'test.noscrollbar.png';
6 |
7 | page.viewportSize = { width: width, height: height };
8 |
9 | page.open(url, function() {
10 | page.render(file);
11 | phantom.exit();
12 | });
13 |
14 |
--------------------------------------------------------------------------------
/test/feature/page.viewportSize.js:
--------------------------------------------------------------------------------
1 |
2 | var page = new WebPage();
3 | page.viewportSize = {width: 800, height: 640};
4 | page.open("http://www.triflejs.org", function() {
5 | page.render("triflejs.800x640.png");
6 | });
--------------------------------------------------------------------------------
/test/feature/page.zoomFactor.js:
--------------------------------------------------------------------------------
1 | var page = require("webpage").create();
2 |
3 | page.zoomFactor = 0.5;
4 | page.open("http://www.triflejs.org", function(status) {
5 | if (status === 'success') {
6 | page.render("triflejs.org.png");
7 | console.log('Page rendered');
8 | } else {
9 | console.error('Cannot load url.');
10 | }
11 | phantom.exit();
12 | });
13 |
14 |
--------------------------------------------------------------------------------
/test/feature/phantom.injectJs.js:
--------------------------------------------------------------------------------
1 |
2 | console.log(phantom);
3 |
4 | var success = phantom.injectJs('..\\..\\test\\lib\\jasmine.js');
5 |
6 | if (!success) {
7 | console.error('File not found');
8 | phantom.exit();
9 | }
10 |
11 | if (jasmine) {
12 | console.log('Jasmine library injected ok');
13 | } else {
14 | console.error('Could not inject Jasmine library');
15 | }
16 | phantom.exit();
17 |
--------------------------------------------------------------------------------
/test/feature/phantom.libraryPath.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | var path = phantom.libraryPath;
4 |
5 | if (path) {
6 | console.log('Library Path: ' + path);
7 | } else {
8 | console.error('Library Path not set!');
9 | }
10 |
--------------------------------------------------------------------------------
/test/feature/system.js:
--------------------------------------------------------------------------------
1 | var sys = new trifle.modules.System();
2 | var sys2 = new trifle.modules.System();
3 |
4 | console.log('created');
5 |
6 |
7 | sys.blah('I am sys');
8 | sys2.blah('I am sys2');
9 |
10 | console.log({
11 | sys: sys,
12 | pid: sys.pid,
13 | args: sys.args,
14 | prototype: trifle.modules.System.prototype
15 | });
16 |
17 |
18 |
--------------------------------------------------------------------------------
/test/feature/webserver.listen.js:
--------------------------------------------------------------------------------
1 | var server = require('webserver').create();
2 | console.log('Starting webserver on port 8080');
3 |
4 | var service = server.listen(8080, function(request, response) {
5 | console.log('starting connection, printing request info');
6 | console.log({
7 | method: request.method,
8 | url: request.url,
9 | httpVersion: request.httpVersion,
10 | headers: request.headers,
11 | post: request.post,
12 | rawPost: request.rawPost
13 | });
14 |
15 | response.statusCode = 200;
16 | console.log('adding response.headers', response.headers);
17 | response.headers = {
18 | "header1": "header1",
19 | "header2": "header2"
20 | };
21 | console.log('headers added');
22 | response.setHeader('header3', 'header3');
23 | response.write('Hello there!
');
24 | response.write('From port:' + server.port + '
');
25 | response.write('
');
26 | response.close();
27 | });
28 | console.log('Ending');
29 |
30 |
31 |
32 | /*
33 | var page = require('webpage').create();
34 | var service = server.listen(8080, function(request, response) {
35 | console.log('server started, opening page');
36 | console.log({
37 | method: request.method,
38 | url: request.url,
39 | httpVersion: request.httpVersion,
40 | headers: request.headers,
41 | post: request.post,
42 | rawPost: request.rawPost
43 | });
44 | response.write('Hello there!
');
45 | response.write('From port:' + server.port + '
');
46 | response.write('');
47 | response.close();
48 | });
49 |
50 | trifle.wait(1000);
51 |
52 |
53 | page.open('http://localhost:8080', function(status) {
54 | console.log('page opened, status: ' + status);
55 | console.log('printing contents:');
56 | console.log(page.plainText);
57 | phantom.exit();
58 | });
59 |
60 | */
--------------------------------------------------------------------------------
/test/feature/window.setInterval.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* window.setInterval() */
4 |
5 | console.log('Starting..');
6 | var tries = 0;
7 |
8 | window.setInterval(function() {
9 | tries++;
10 | console.log('Tries..' + tries);
11 | if (tries > 9) {
12 | console.log('Finished.');
13 | phantom.exit();
14 | }
15 | }, 1000);
16 |
--------------------------------------------------------------------------------
/test/feature/window.setTimeout.js:
--------------------------------------------------------------------------------
1 |
2 | /* window.setTimeout() */
3 |
4 |
5 | console.log('Starting..');
6 |
7 | window.setTimeout(function() {
8 | console.log('Finished.');
9 | }, 1000);
10 |
11 |
12 |
--------------------------------------------------------------------------------
/test/integration/casper/TODO.txt:
--------------------------------------------------------------------------------
1 | Add CasperJS integration tests
--------------------------------------------------------------------------------
/test/integration/phantom/LICENSE.BSD:
--------------------------------------------------------------------------------
1 | Redistribution and use in source and binary forms, with or without
2 | modification, are permitted provided that the following conditions are met:
3 |
4 | * Redistributions of source code must retain the above copyright
5 | notice, this list of conditions and the following disclaimer.
6 | * Redistributions in binary form must reproduce the above copyright
7 | notice, this list of conditions and the following disclaimer in the
8 | documentation and/or other materials provided with the distribution.
9 | * Neither the name of the nor the
10 | names of its contributors may be used to endorse or promote products
11 | derived from this software without specific prior written permission.
12 |
13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
--------------------------------------------------------------------------------
/test/integration/phantom/README.md:
--------------------------------------------------------------------------------
1 | # [PhantomJS](http://phantomjs.org) - Scriptable Headless WebKit
2 |
3 | PhantomJS ([www.phantomjs.org](http://phantomjs.org)) is a headless WebKit scriptable with JavaScript or CoffeeScript. It is used by hundreds of [developers](https://github.com/ariya/phantomjs/wiki/Buzz) and dozens of [organizations](https://github.com/ariya/phantomjs/wiki/Users) for web-related development workflow.
4 |
5 | The latest [stable release](http://phantomjs.org/release-1.9.html) is version 1.9 (codenamed "Sakura"). Follow the official Twitter stream [@PhantomJS](http://twitter.com/PhantomJS) to get the frequent development updates.
6 |
7 | **Note**: Please **do not** create a GitHub pull request **without** reading the [Contribution Guide](https://github.com/ariya/phantomjs/blob/master/CONTRIBUTING.md) first. Failure to do so may result in the rejection of the pull request.
8 |
9 | ## Use Cases
10 |
11 | - **Headless web testing**. Lightning-fast testing without the browser is now possible! Various [test frameworks](https://github.com/ariya/phantomjs/wiki/Headless-Testing) such as Jasmine, Capybara, QUnit, Mocha, WebDriver, YUI Test, BusterJS, FuncUnit, Robot Framework, and many others are supported.
12 | - **Page automation**. [Access and manipulate](https://github.com/ariya/phantomjs/wiki/Page-Automation) web pages with the standard DOM API, or with usual libraries like jQuery.
13 | - **Screen capture**. Programmatically [capture web contents](https://github.com/ariya/phantomjs/wiki/Screen-Capture), including CSs, SVG and Canvas. Build server-side web graphics apps, from a screenshot service to a vector chart rasterizer.
14 | - **Network monitoring**. Automate performance analysis, track [page loading](https://github.com/ariya/phantomjs/wiki/Network-Monitoring) and export as standard HAR format.
15 |
16 | ## Features
17 |
18 | - **Multiplatform**, available on major operating systems: Windows, Mac OS X, Linux, other Unices.
19 | - **Fast and native implementation** of web standards: DOM, CSS, JavaScript, Canvas, SVG. No emulation!
20 | - **Pure headless (no X11) on Linux**, ideal for continuous integration systems. Also runs on Amazon EC2, Heroku, Iron.io.
21 | - **Easy to install**: [Download](http://phantomjs.org/download.html), unpack, and start having fun in just 5 minutes.
22 |
23 | ## Ecosystem
24 |
25 | PhantomJS needs not be used only as a stand-alone tool. Check also some excellent related projects:
26 |
27 | - [CasperJS](http://casperjs.org) enables easy navigation scripting and common high-level testing.
28 | - [Poltergeist](https://github.com/jonleighton/poltergeist) allows running Capybara tests headlessly.
29 | - [Guard::Jasmine](https://github.com/netzpirat/guard-jasmine) automatically tests Jasmine specs on Rails when files are modified.
30 | - [GhostDriver](http://github.com/detro/ghostdriver/) complements Selenium tests with a PhantomJS WebDriver implementation.
31 | - [PhantomRobot](https://github.com/datakurre/phantomrobot) runs Robot Framework acceptance tests in the background via PhantomJS.
32 | - [Mocha-PhantomJS](https://github.com/metaskills/mocha-phantomjs) run Mocha tests using PhantomJS.
33 |
34 | and many others [related projects](https://github.com/ariya/phantomjs/wiki/Related-Projects).
35 |
36 | ## Questions?
37 |
38 | - Explore the complete [documentation](https://github.com/ariya/phantomjs/wiki)
39 | - Read tons of [user articles](https://github.com/ariya/phantomjs/wiki/Buzz) on using PhantomJS.
40 | - Join the [mailing-list](http://groups.google.com/group/phantomjs) and discuss with other PhantomJS fans.
41 |
42 | PhantomJS is free software/open source, and is distributed under the [BSD license](http://opensource.org/licenses/BSD-3-Clause). It contains third-party code, see the included `third-party.txt` file for the license information on third-party code.
43 |
44 | PhantomJS is created and maintained by [Ariya Hidayat](http://ariya.ofilabs.com/about) (Twitter: [@ariyahidayat](http://twitter.com/ariyahidayat)), with the help of [many contributors](https://github.com/ariya/phantomjs/contributors).
45 |
46 |
--------------------------------------------------------------------------------
/test/integration/phantom/examples/universe.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | // This is to be used by "module.js" (and "module.coffee") example(s).
4 | // There should NOT be a "universe.coffee" as only 1 of the 2 would
5 | // ever be loaded unless the file extension was specified.
6 |
7 | exports.answer = 42;
8 |
9 | exports.start = function () {
10 | console.log('Starting the universe....');
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/test/integration/phantom/examples/variable.js:
--------------------------------------------------------------------------------
1 |
2 | // This is a simple example of how to set a variable
3 | // Its used internally for testing script injection
4 | // phantom.injectJs();
5 |
6 | var ___test190234 = [] instanceof Array;
7 |
--------------------------------------------------------------------------------
/test/integration/phantom/feature/page.events.js:
--------------------------------------------------------------------------------
1 |
2 | var page = require('webpage').create();
3 | var server = require('webserver').create();
4 |
5 | // Start a listener to check events
6 | server.listen(8083, function(request, response) {
7 | var bodyText = JSON.stringify({
8 | success: true,
9 | url: request.url
10 | });
11 | response.write('eventtest9837423401' +
12 | '' +
13 | '' + bodyText + '');
14 | response.close();
15 | });
16 |
17 |
18 | page.onLoadStarted = function() {
19 | console.log("LoadStarted");
20 | }
21 |
22 | page.onLoadFinished = function(status) {
23 | console.log("LoadFinished");
24 | }
25 | page.onNavigationRequested = function(url, type, willNavigate, main) {
26 | console.log("NavigationRequested: ", arguments);
27 | }
28 | page.onInitialized = function () {
29 | console.log("Initialized");
30 | }
31 | page.onCallback = function(event) {
32 | console.log('Callback: ' + event);
33 | };
34 | page.onClosing = function (closingPage) {
35 | console.log('Closing' + closingPage.url);
36 | };
37 | page.evaluate(function () {
38 | callPhantom('beforeopen');
39 | });
40 | page.open('http://localhost:8083/', function (status) {
41 | //phantom.exit();
42 | page.open('http://localhost:8083/1', function() {
43 | page.goBack();
44 | trifle.wait(10);
45 | page.close();
46 | });
47 |
48 | });
49 |
--------------------------------------------------------------------------------
/test/integration/phantom/feature/page.rendering.js:
--------------------------------------------------------------------------------
1 | var page = require('webpage').create();
2 |
3 | page.zoomFactor=1;
4 |
5 | page.onLoadFinished = function(e) {
6 | setTimeout(function(){
7 | page.render('msn.jpg',{quality:50});
8 | phantom.exit();},30000);
9 | };
10 | page.viewportSize={width:1420,height:800};
11 | console.log(page.viewportSize);
12 | page.localT1oRemoteUrlAccessEnabled =true;
13 |
14 | setTimeout(page.open('http://www.msn.com', function() {}),30000);
--------------------------------------------------------------------------------
/test/integration/phantom/phantomjs.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdesalas/trifleJS/363fc3d3f168a261be2deb1f664017e0ec43bf8e/test/integration/phantom/phantomjs.exe
--------------------------------------------------------------------------------
/test/integration/phantom/run.bat:
--------------------------------------------------------------------------------
1 | phantomjs.exe run.js
--------------------------------------------------------------------------------
/test/integration/phantom/run.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * run.js
4 | *
5 | * Initializes environment and runs triflejs unit tests
6 | * in phantomjs executable.
7 | *
8 | */
9 |
10 | console.log('=============================');
11 | console.log('PhantomJS Benchmark Tests');
12 | console.log('=============================');
13 |
14 |
15 | (function Stubs() {
16 |
17 | trifle = {
18 | wait : function(ms) {
19 | var date = new Date()
20 | var page = phantom.page;
21 | do {
22 | // To emulate trifle.wait() we have
23 | // to clear the event queue while waiting
24 | // for timer to reach destination.
25 | // This can be accomplished using page.sendEvent()
26 | // which in turn clears the queue for us
27 | // with a call to QApplication::processEvents();
28 | // @see http://qt-project.org/wiki/ThreadsEventsQObjects#7494f2b4836907fc1c09311e3a0305e6
29 | // @see https://github.com/ariya/phantomjs/blob/1.9/src/webpage.cpp#L1394
30 | page.sendEvent('mousemove');
31 | } while (new Date() < new Date(date.getTime() + ms))
32 | }
33 | };
34 |
35 | console.API = {
36 | color: function(name, msg) {
37 | console.log(msg);
38 | }
39 | };
40 |
41 | })();
42 |
43 |
44 | // Add TrifleJS unit testing tools
45 | phantom.injectJs('../../unit/tools.js');
46 |
47 | // Add TrifleJS unit testing spec
48 | //phantom.injectJs('../../unit/spec/env.js');
49 | //phantom.injectJs('../../unit/spec/require.js');
50 | //phantom.injectJs('../../unit/spec/phantom.js');
51 | //phantom.injectJs('../../unit/spec/fs.js');
52 | //phantom.injectJs('../../unit/spec/webserver.js');
53 | phantom.injectJs('../../unit/spec/webpage.js');
54 |
55 | // Finish off & Report
56 | phantom.injectJs('../../unit/finish.js');
57 |
58 |
--------------------------------------------------------------------------------
/test/lib/MIT.LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008-2011 Pivotal Labs
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/test/lib/jasmine-console.js:
--------------------------------------------------------------------------------
1 | jasmine.ConsoleReporter = function(print, doneCallback, showColors) {
2 | //inspired by mhevery's jasmine-node reporter
3 | //https://github.com/mhevery/jasmine-node
4 |
5 | doneCallback = doneCallback || function() { };
6 |
7 | var ansi = {
8 | green: '\033[32m',
9 | red: '\033[31m',
10 | yellow: '\033[33m',
11 | none: '\033[0m'
12 | },
13 | language = {
14 | spec: "spec",
15 | failure: "failure"
16 | };
17 |
18 | function coloredStr(color, str) {
19 | return showColors ? (ansi[color] + str + ansi.none) : str;
20 | }
21 |
22 | function greenStr(str) {
23 | return coloredStr("green", str);
24 | }
25 |
26 | function redStr(str) {
27 | return coloredStr("red", str);
28 | }
29 |
30 | function yellowStr(str) {
31 | return coloredStr("yellow", str);
32 | }
33 |
34 | function newline() {
35 | print("\n");
36 | }
37 |
38 | function started() {
39 | print("Started");
40 | newline();
41 | }
42 |
43 | function greenPass() {
44 | print(greenStr("PASS"));
45 | }
46 |
47 | function redFail() {
48 | print(redStr("FAIL"));
49 | }
50 |
51 | function yellowStar() {
52 | print(yellowStr("*"));
53 | }
54 |
55 | function plural(str, count) {
56 | return count == 1 ? str : str + "s";
57 | }
58 |
59 | function repeat(thing, times) {
60 | var arr = [];
61 | for (var i = 0; i < times; i++) {
62 | arr.push(thing);
63 | }
64 | return arr;
65 | }
66 |
67 | function indent(str, spaces) {
68 | var lines = (str || '').split("\n");
69 | var newArr = [];
70 | for (var i = 0; i < lines.length; i++) {
71 | newArr.push(repeat(" ", spaces).join("") + lines[i]);
72 | }
73 | return newArr.join("\n");
74 | }
75 |
76 | function specFailureDetails(suiteDescription, specDescription, stackTraces) {
77 | newline();
78 | print(suiteDescription + " " + specDescription);
79 | for (var i = 0; i < stackTraces.length; i++) {
80 | print(indent(stackTraces[i], 2));
81 | }
82 | }
83 |
84 | function finished(elapsed) {
85 | newline();
86 | print("Finished in " + elapsed / 1000 + " seconds");
87 | }
88 |
89 | function summary(colorF, specs, failed) {
90 | newline();
91 | print(colorF(specs + " " + plural(language.spec, specs) + ", " +
92 | failed + " " + plural(language.failure, failed)));
93 | }
94 |
95 | function greenSummary(specs, failed) {
96 | summary(greenStr, specs, failed);
97 | }
98 |
99 | function redSummary(specs, failed) {
100 | summary(redStr, specs, failed);
101 | }
102 |
103 | function fullSuiteDescription(suite) {
104 | var fullDescription = suite.description;
105 | if (suite.parentSuite) fullDescription = fullSuiteDescription(suite.parentSuite) + " " + fullDescription;
106 | return fullDescription;
107 | }
108 |
109 | this.now = function() {
110 | return new Date().getTime();
111 | };
112 |
113 | this.reportRunnerStarting = function() {
114 | this.runnerStartTime = this.now();
115 | started();
116 | };
117 |
118 | this.reportSpecStarting = function() { /* do nothing */
119 | };
120 |
121 | this.reportSpecResults = function(spec) {
122 | var results = spec.results();
123 | if (results.skipped) {
124 | yellowStar();
125 | } else {
126 | if (results.passed()) {
127 | print('#' + spec.id + ' ' + spec.suite.description + ': ' + spec.description);
128 | greenPass();
129 | } else {
130 | print(redStr('#' + spec.id + ' ' + spec.suite.description + ': ' + spec.description));
131 | redFail();
132 | }
133 | }
134 | };
135 |
136 | this.suiteResults = [];
137 |
138 | this.reportSuiteResults = function(suite) {
139 | var suiteResult = {
140 | description: fullSuiteDescription(suite),
141 | failedSpecResults: []
142 | };
143 |
144 | suite.results().items_.forEach(function(spec) {
145 | if (spec.failedCount > 0 && spec.description) suiteResult.failedSpecResults.push(spec);
146 | });
147 |
148 | this.suiteResults.push(suiteResult);
149 | };
150 |
151 | function eachSpecFailure(suiteResults, callback) {
152 | for (var i = 0; i < suiteResults.length; i++) {
153 | var suiteResult = suiteResults[i];
154 | for (var j = 0; j < suiteResult.failedSpecResults.length; j++) {
155 | var failedSpecResult = suiteResult.failedSpecResults[j];
156 | var stackTraces = [];
157 | for (var k = 0; k < failedSpecResult.items_.length; k++) stackTraces.push(failedSpecResult.items_[k].trace.stack);
158 | callback(suiteResult.description, failedSpecResult.description, stackTraces);
159 | }
160 | }
161 | }
162 |
163 | this.reportRunnerResults = function(runner) {
164 | eachSpecFailure(this.suiteResults, function(suiteDescription, specDescription, stackTraces) {
165 | specFailureDetails(suiteDescription, specDescription, stackTraces);
166 | });
167 |
168 | finished(this.now() - this.runnerStartTime);
169 |
170 | var results = runner.results();
171 | var summaryFunction = results.failedCount === 0 ? greenSummary : redSummary;
172 | summaryFunction(runner.specs().length, results.failedCount);
173 | doneCallback(runner);
174 | };
175 | };
--------------------------------------------------------------------------------
/test/ssl/CertEnroll.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Security.Cryptography.X509Certificates;
4 | using CERTENROLLLib;
5 |
6 | namespace TrifleJS.Test.SSL
7 | {
8 | ///
9 | /// Internal class used to generate self-signed SSL certificates for testing.
10 | /// If it does not work, try alternatives:
11 | /// - http://blogs.msdn.com/b/dcook/archive/2008/11/25/creating-a-self-signed-certificate-in-c.aspx
12 | /// - Use 'makecert.exe' and 'netsh http add sslcert' as shown in 'prepare.ssl.bat.example'
13 | ///
14 | internal class CertEnroll
15 | {
16 | // http://stackoverflow.com/questions/24098673/http-add-sslcert-fails-when-done-programatically
17 | internal static X509Certificate2 Generate()
18 | {
19 | try
20 | {
21 | X509Certificate2 cert = CreateSelfSignedCertificate("localhost");
22 |
23 | var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
24 | store.Open(OpenFlags.ReadWrite);
25 | if (!store.Certificates.Contains(cert))
26 | {
27 | store.Add(cert);
28 | }
29 | return cert;
30 | }
31 | catch { }
32 | return null;
33 | }
34 |
35 | internal static void Register(X509Certificate2 cert, int port) {
36 | if (HttpApi.IsSslRegistered(port)) throw new Exception(String.Format("Port {0} already has SSL certificate for TrifleJS!"));
37 | string appId = Native.Methods.GetAssemblyGuid();
38 | HttpApi.BindCertificate(port, cert, StoreName.My, appId);
39 | }
40 |
41 | internal static void GenerateAndRegister(int port) {
42 | Register(Generate(), port);
43 | }
44 |
45 | // http://stackoverflow.com/questions/13806299/how-to-create-a-self-signed-certificate-using-c
46 | private static X509Certificate2 CreateSelfSignedCertificate(string subjectName)
47 | {
48 | // create DN for subject and issuer
49 | var dn = new CX500DistinguishedName();
50 | dn.Encode("CN=" + subjectName, X500NameFlags.XCN_CERT_NAME_STR_NONE);
51 |
52 | // create a new private key for the certificate
53 | CX509PrivateKey privateKey = new CX509PrivateKey();
54 | privateKey.ProviderName = "Microsoft Base Cryptographic Provider v1.0";
55 | privateKey.MachineContext = true;
56 | privateKey.Length = 2048;
57 | privateKey.KeySpec = X509KeySpec.XCN_AT_SIGNATURE; // use is not limited
58 | privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
59 | privateKey.Create();
60 |
61 | // Use the stronger SHA512 hashing algorithm
62 | var hashobj = new CObjectId();
63 | hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID,
64 | ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY,
65 | AlgorithmFlags.AlgorithmFlagsNone, "SHA512");
66 |
67 | // add extended key usage if you want - look at MSDN for a list of possible OIDs
68 | var oid = new CObjectId();
69 | oid.InitializeFromValue("1.3.6.1.5.5.7.3.1"); // SSL server
70 | var oidlist = new CObjectIds();
71 | oidlist.Add(oid);
72 | var eku = new CX509ExtensionEnhancedKeyUsage();
73 | eku.InitializeEncode(oidlist);
74 |
75 | // Create the self signing request
76 | var cert = new CX509CertificateRequestCertificate();
77 | cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, privateKey, "");
78 | cert.Subject = dn;
79 | cert.Issuer = dn; // the issuer and the subject are the same
80 | cert.NotBefore = DateTime.Now;
81 | // this cert expires immediately. Change to whatever makes sense for you
82 | cert.NotAfter = DateTime.Now;
83 | cert.X509Extensions.Add((CX509Extension)eku); // add the EKU
84 | cert.HashAlgorithm = hashobj; // Specify the hashing algorithm
85 | cert.Encode(); // encode the certificate
86 |
87 | // Do the final enrollment process
88 | var enroll = new CX509Enrollment();
89 | enroll.InitializeFromRequest(cert); // load the certificate
90 | enroll.CertificateFriendlyName = subjectName; // Optional: add a friendly name
91 | string csr = enroll.CreateRequest(EncodingType.XCN_CRYPT_STRING_BASE64); // Output the request in base64
92 | // and install it back as the response
93 | enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate,
94 | csr, EncodingType.XCN_CRYPT_STRING_BASE64, ""); // no password
95 | // output a base64 encoded PKCS#12 so we can import it back to the .Net security classes
96 | var base64encoded = enroll.CreatePFX("", // no password, this is for internal consumption
97 | PFXExportOptions.PFXExportChainWithRoot, EncodingType.XCN_CRYPT_STRING_BASE64);
98 |
99 | // instantiate the target class with the PKCS#12 data (and the empty password)
100 | return new System.Security.Cryptography.X509Certificates.X509Certificate2(
101 | System.Convert.FromBase64String(base64encoded), "",
102 | // mark the private key as exportable (this is usually what you want to do)
103 | System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable
104 | );
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/test/ssl/CertInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Cryptography;
3 | using System.Security.Permissions;
4 | using System.IO;
5 | using System.Security.Cryptography.X509Certificates;
6 |
7 | ///
8 | /// CertInfo.exe
9 | /// --------------
10 | /// Command line tool to get thumbprint from SSL certificate.
11 | /// Used to speed up/automate SSL self-signed certification
12 | /// using 'makecert.exe' and 'netsh http add sslcert'
13 | /// as the 'netsh' command uses a thumbprint as input.
14 | ///
15 | class CertInfo
16 | {
17 | //Reads a file.
18 | internal static byte[] ReadFile(string fileName)
19 | {
20 | FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read);
21 | int size = (int)f.Length;
22 | byte[] data = new byte[size];
23 | size = f.Read(data, 0, size);
24 | f.Close();
25 | return data;
26 | }
27 | //Main method begins here.
28 | static void Main(string[] args)
29 | {
30 | //Test for correct number of arguments.
31 | if (args.Length < 1)
32 | {
33 | Console.WriteLine("Usage: CertInfo ");
34 | return;
35 | }
36 | try
37 | {
38 | X509Certificate2 x509 = new X509Certificate2();
39 | //Create X509Certificate2 object from .cer file.
40 | byte[] rawData = ReadFile(args[0]);
41 |
42 | x509.Import(rawData);
43 |
44 | //Print to console information contained in the certificate.
45 | Console.WriteLine(x509.Thumbprint);
46 |
47 | //Add the certificate to a X509Store.
48 | X509Store store = new X509Store();
49 | store.Open(OpenFlags.MaxAllowed);
50 | store.Add(x509);
51 | store.Close();
52 | }
53 |
54 | catch (DirectoryNotFoundException)
55 | {
56 | Console.WriteLine("Error: The directory specified could not be found.");
57 | }
58 | catch (IOException)
59 | {
60 | Console.WriteLine("Error: A file in the directory could not be accessed.");
61 | }
62 | catch (NullReferenceException)
63 | {
64 | Console.WriteLine("File must be a .cer file. Program does not have access to that type of file.");
65 | }
66 | }
67 |
68 | }
--------------------------------------------------------------------------------
/test/ssl/CertInfo.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sdesalas/trifleJS/363fc3d3f168a261be2deb1f664017e0ec43bf8e/test/ssl/CertInfo.exe
--------------------------------------------------------------------------------
/test/ssl/prepare.ssl.bat.example:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | :: Step 1: Create a Self-Signed certificate
4 | ..\..\Build\Tools\makecert.exe -r -a sha1 -n CN=localhost -sky exchange -pe -b 01/01/2010 -e 01/01/2050 -ss my -sr localmachine ..\..\test\ssl\triflejs.test.ssl.cer
5 |
6 | :: Step 2: Get Thumbprint
7 | CertInfo triflejs.test.ssl.cer
8 |
9 | :: Step 3: Register SSL certificate
10 | netsh http add sslcert 0.0.0.0:444 certhash=00112233AABBCCDDEEFF appid={00112233-4455-6677-8899-AABBCCDDEEFF}
--------------------------------------------------------------------------------
/test/unit/finish.js:
--------------------------------------------------------------------------------
1 |
2 | console.log();
3 | console.log('-------------------------------');
4 | console.log(' TESTING COMPLETED');
5 | console.log('-------------------------------');
6 | console.log('Total Tests: ' + assert.count);
7 |
8 | // ANY ERRORS?
9 | if (assert.fail.count) {
10 | console.API.color('red', 'Total Failed: ' + assert.fail.count);
11 | console.log();
12 | // RETURN ERROR
13 | phantom.exit(assert.fail.count);
14 | }
15 | else {
16 | // ALL GOOD!
17 | console.API.color('green', 'Total Passed: ' + assert.pass.count);
18 | console.log();
19 | phantom.exit(0);
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/test/unit/phantom/run-jasmine.js:
--------------------------------------------------------------------------------
1 |
2 | // Launch tests
3 | var jasmineEnv = jasmine.getEnv();
4 |
5 | // Add a ConsoleReporter to
6 | // 1) print with colors on the console
7 | // 2) exit when finished
8 | jasmineEnv.addReporter(new jasmine.ConsoleReporter(function(msg) {
9 | // Apply color
10 | var ansi = {
11 | green: '\033[32m',
12 | red: '\033[31m',
13 | yellow: '\033[33m',
14 | none: '\033[0m',
15 | newline: '\n'
16 | };
17 | msg = msg.replace(ansi.newline, '').replace(ansi.none, '');
18 | var printInColor = function(color, message) {
19 | if (color && message && ansi[color]) {
20 | console.API.color(color, message.replace(ansi[color], ''));
21 | }
22 | }
23 | // Print messages straight to console
24 | if (msg.indexOf(ansi.red) === 0) {
25 | printInColor('red', msg);
26 | } else if (msg.indexOf(ansi.yellow) === 0) {
27 | printInColor('yellow', msg);
28 | } else if (msg.indexOf(ansi.green) === 0) {
29 | printInColor('green', msg);
30 | } else {
31 | console.log(msg);
32 | }
33 | }, function(reporter) {
34 | // On complete
35 | phantom.exit(reporter.results().failedCount);
36 | }, true));
37 |
38 | // Launch tests
39 | jasmineEnv.updateInterval = 500;
40 | jasmineEnv.execute();
41 |
42 |
--------------------------------------------------------------------------------
/test/unit/phantom/run-tests.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the PhantomJS project from Ofi Labs.
3 |
4 | Copyright (C) 2011 Ariya Hidayat
5 | Copyright (C) 2011 Ivan De Marino
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | * Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 | * Neither the name of the nor the
16 | names of its contributors may be used to endorse or promote products
17 | derived from this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 | */
30 |
31 | // Load Jasmine and the HTML reporter
32 | phantom.injectJs("./lib/jasmine.js");
33 | phantom.injectJs("./lib/jasmine-console.js");
34 | phantom.injectJs("./lib/chai.js");
35 |
36 | var should = chai.should();
37 |
38 | // Helper funcs
39 | function expectHasFunction(o, name) {
40 | it("should have '" + name + "' function", function() {
41 | expect(typeof o[name]).toEqual('function');
42 | });
43 | }
44 |
45 | function expectHasProperty(o, name) {
46 | it("should have '" + name + "' property", function() {
47 | expect(o.hasOwnProperty(name)).toBeTruthy();
48 | });
49 | }
50 |
51 | function expectHasPropertyString(o, name) {
52 | expectHasProperty(o, name);
53 |
54 | it("should have '" + name + "' as a string", function() {
55 | expect(typeof o[name]).toEqual('string');
56 | });
57 | }
58 |
59 | // Setting the "working directory" to the "/test" directory
60 | var fs = require('fs');
61 |
62 | fs.changeWorkingDirectory(phantom.libraryPath);
63 |
64 | // Remove xdebug
65 | console.xdebug = function() { };
66 |
67 | // Load specs
68 | phantom.injectJs("./spec/phantom.js");
69 |
70 | // Execute!
71 | phantom.injectJS("run-jasmine.js");
72 |
--------------------------------------------------------------------------------
/test/unit/phantom/scripts/frametest-harness.js:
--------------------------------------------------------------------------------
1 |
2 | var page = require('webpage').create();
3 | var server = require('webserver').create();
4 | var fs = require('fs');
5 |
6 | fs.changeWorkingDirectory('E:\\PROJECTS\\GITHUB\\trifleJS\\bin\\Debug\\');
7 |
8 | server.listen(8897, function(request, response) {
9 | console.log('requested url--> ' + request.url);
10 | var path = request.url;
11 | if (!path || path === '/') path = '/index.html';
12 | response.write(fs.read('test/frames' + path));
13 | response.close();
14 | });
15 |
16 |
--------------------------------------------------------------------------------
/test/unit/phantom/scripts/frametest.js:
--------------------------------------------------------------------------------
1 |
2 | var page = require('webpage').create();
3 |
4 | page.open('http://localhost:8897', function(status) {
5 |
6 | console.log(status);
7 | page.windowName = "main frame";
8 | console.log(JSON.stringify({
9 | "page.framesCount": page.framesCount,
10 | "page.framesName": page.framesName,
11 | "page.windowName": page.windowName,
12 | "page.frameName": page.frameName,
13 | "page.frameUrl": page.frameUrl,
14 | "page.focusedFrameName": page.focusedFrameName
15 | }));
16 | page.switchToFrame('frame1');
17 | console.log('------');
18 |
19 | console.log(JSON.stringify({
20 | "page.framesCount": page.framesCount,
21 | "page.framesName": page.framesName,
22 | "page.windowName": page.windowName,
23 | "page.frameName": page.frameName,
24 | "page.frameUrl": page.frameUrl,
25 | "page.focusedFrameName": page.focusedFrameName
26 | }));
27 | page.switchToMainFrame();
28 | page.switchToFrame('frame2-1');
29 | console.log('------');
30 |
31 | console.log(JSON.stringify({
32 | "page.framesCount": page.framesCount,
33 | "page.framesName": page.framesName,
34 | "page.windowName": page.windowName,
35 | "page.frameName": page.frameName,
36 | "page.frameUrl": page.frameUrl,
37 | "page.focusedFrameName": page.focusedFrameName
38 | }));
39 | phantom.exit();
40 | })
--------------------------------------------------------------------------------
/test/unit/phantom/spec/phantom.js:
--------------------------------------------------------------------------------
1 | describe("phantom global object", function() {
2 | it("should exist", function() {
3 | expect(typeof phantom).toEqual('object');
4 | });
5 |
6 | it("should have args property", function() {
7 | expect(phantom.hasOwnProperty('args')).toBeTruthy();
8 | });
9 |
10 | it("should have args as an array", function() {
11 | expect(typeof phantom.args).toEqual('object');
12 | });
13 |
14 | it("should have libraryPath property", function() {
15 | expect(phantom.hasOwnProperty('libraryPath')).toBeTruthy();
16 | });
17 |
18 | it("should have libraryPath as a string", function() {
19 | expect(typeof phantom.libraryPath).toEqual('string');
20 | });
21 |
22 | it("should not have an empty libraryPath", function() {
23 | expect(phantom.libraryPath.length).toNotEqual(0);
24 | });
25 |
26 | it("should have scriptName property", function() {
27 | expect(phantom.hasOwnProperty('scriptName')).toBeTruthy();
28 | });
29 |
30 | it("should have scriptName as a string", function() {
31 | expect(typeof phantom.scriptName).toEqual('string');
32 | });
33 |
34 | it("should not have an empty scriptName", function() {
35 | expect(phantom.scriptName.length).toNotEqual(0);
36 | });
37 |
38 | it("should have outputEncoding property", function() {
39 | expect(phantom.hasOwnProperty('outputEncoding')).toBeTruthy();
40 | });
41 |
42 | it("should have the default outputEncoding of UTF-8", function() {
43 | expect(phantom.outputEncoding.toLowerCase()).toEqual('utf-8');
44 | });
45 |
46 | it("should have version property", function() {
47 | expect(phantom.hasOwnProperty('version')).toBeTruthy();
48 | });
49 |
50 | it("should return 1 as the major version", function() {
51 | expect(phantom.version.major).toEqual(1);
52 | });
53 |
54 | it("should return 7 as the minor version", function() {
55 | expect(phantom.version.minor).toEqual(7);
56 | });
57 |
58 | it("should return 0 as the patch version", function() {
59 | expect(phantom.version.patch).toEqual(0);
60 | });
61 |
62 | it("should have 'injectJs' function", function() {
63 | expect(typeof phantom.injectJs).toEqual("function");
64 | });
65 |
66 | it("should have 'exit' function", function() {
67 | expect(typeof phantom.exit).toEqual("function");
68 | });
69 |
70 | it("should have 'cookiesEnabled' property, and should be 'true' by default", function() {
71 | expect(phantom.hasOwnProperty('cookiesEnabled')).toBeTruthy();
72 | expect(phantom.cookiesEnabled).toBeTruthy();
73 | });
74 |
75 | // it("should be able to get the error signal handler that is currently set on it", function() {
76 | // phantom.onError = undefined;
77 | // expect(phantom.onError).toBeUndefined();
78 | // var onErrorFunc1 = function() { return !"x"; };
79 | // phantom.onError = onErrorFunc1;
80 | // expect(phantom.onError).toEqual(onErrorFunc1);
81 | // var onErrorFunc2 = function() { return !!"y"; };
82 | // phantom.onError = onErrorFunc2;
83 | // expect(phantom.onError).toEqual(onErrorFunc2);
84 | // expect(phantom.onError).toNotEqual(onErrorFunc1);
85 | // phantom.onError = null;
86 | // // Will only allow setting to a function value, so setting it to `null` returns `undefined`
87 | // expect(phantom.onError).toBeUndefined();
88 | // phantom.onError = undefined;
89 | // expect(phantom.onError).toBeUndefined();
90 | // });
91 |
92 | // it("reports parse time error source and line in stack", function() {
93 | // var stack;
94 | // phantom.onError = function(message, s) { stack = s; };
95 |
96 | // var helperFile = "./fixtures/parse-error-helper.js";
97 | // phantom.injectJs(helperFile);
98 |
99 | // waits(0);
100 |
101 | // runs(function() {
102 | // expect(stack[0].file).toEqual(helperFile);
103 | // expect(stack[0].line).toEqual(2);
104 | // phantom.onError = phantom.defaultErrorHandler;
105 | // });
106 | // });
107 | });
108 |
--------------------------------------------------------------------------------
/test/unit/phantom/spec/webserver.js:
--------------------------------------------------------------------------------
1 | describe("WebServer constructor", function() {
2 | it("should not exist in window", function() {
3 | expect(window.hasOwnProperty('WebServer')).toBeFalsy();
4 | });
5 |
6 | it("should be a function", function() {
7 | var WebServer = require('webserver').create;
8 | expect(typeof WebServer).toEqual('function');
9 | });
10 | });
11 |
12 | var expectedPostData = false, expectedBinaryData = false;
13 |
14 | function checkRequest(request, response) {
15 | console.log('checking request...');
16 | expect(typeof request).toEqual('object');
17 | expect(request.hasOwnProperty('url')).toBeTruthy();
18 | expect(request.hasOwnProperty('method')).toBeTruthy();
19 | expect(request.hasOwnProperty('httpVersion')).toBeTruthy();
20 | expect(request.hasOwnProperty('headers')).toBeTruthy();
21 | expect(typeof request.headers).toEqual('object');
22 |
23 | expect(typeof response).toEqual('object');
24 | expect(response.hasOwnProperty('statusCode')).toBeTruthy();
25 | expect(response.hasOwnProperty('headers')).toBeTruthy();
26 | //expect(typeof response['setHeaders']).toEqual('function');
27 | expect(typeof response['setHeader']).toEqual('function');
28 | expect(typeof response['header']).toEqual('function');
29 | expect(typeof response['write']).toEqual('function');
30 | expect(typeof response['writeHead']).toEqual('function');
31 |
32 | if (expectedPostData !== false) {
33 | expect(request.method).toEqual("POST");
34 | expect(request.hasOwnProperty('post')).toBeTruthy();
35 | console.log("request.post => " + JSON.stringify(request.post, null, 4));
36 | console.log("expectedPostData => " + JSON.stringify(expectedPostData, null, 4));
37 | console.log("request.headers => " + JSON.stringify(request.headers, null, 4));
38 | if (request.headers["Content-Type"] && request.headers["Content-Type"] === "application/x-www-form-urlencoded") {
39 | expect(typeof request.post).toEqual('object');
40 | expect(request.post).toEqual(expectedPostData);
41 | expect(request.postRaw).toBeTruthy();
42 | expect(typeof request.postRaw).toEqual('string');
43 | } else {
44 | expect(typeof request.post).toEqual('string');
45 | expect(request.post).toNotEqual(expectedPostData);
46 | expect(request.postRaw).toBeFalsy();
47 | }
48 | expectedPostData = false;
49 | }
50 |
51 | if (expectedBinaryData !== false) {
52 | response.setEncoding('binary');
53 | response.write(expectedBinaryData);
54 | expectedBinaryData = false;
55 | } else {
56 | response.write("request handled");
57 | }
58 | response.close();
59 | }
60 |
61 | describe("WebServer object", function() {
62 | var server = require('webserver').create();
63 |
64 | it("should be creatable", function() {
65 | expect(typeof server).toEqual('object');
66 | expect(server).toNotEqual(null);
67 | });
68 |
69 | it("should have objectName as 'WebServer'", function() {
70 | expect(server.objectName).toEqual('WebServer');
71 | });
72 |
73 | expectHasProperty(server, 'port');
74 | it("should have port as string", function() {
75 | expect(typeof server.port).toEqual('string');
76 | });
77 | it("should not listen to any port by default", function() {
78 | expect(server.port).toEqual("");
79 | });
80 |
81 | expectHasFunction(server, 'listen');
82 | expectHasFunction(server, 'close');
83 |
84 | it("should fail to listen to blocked ports", function() {
85 | //NOTE: is this really blocked everywhere?
86 | expect(server.listen(80, function(){})).toEqual(false);
87 | expect(server.port).toEqual("");
88 | });
89 | it("should be able to listen to some port", function() {
90 | //NOTE: this can fail if the port is already being listend on...
91 | expect(server.listen("12345", checkRequest)).toEqual(true);
92 | expect(server.port).toEqual("12345");
93 | });
94 |
95 | it("should handle requests", function() {
96 | console.debug("should handle requests..");
97 | var page = require('webpage').create();
98 | var url = "http://localhost:12345/foo/bar.php?asdf=true";
99 | var handled = false;
100 | runs(function() {
101 | expect(handled).toEqual(false);
102 | page.open(url, function (status) {
103 | expect(status == 'success').toEqual(true);
104 | expect(page.plainText).toEqual("request handled");
105 | handled = true;
106 | });
107 | });
108 |
109 | waits(50);
110 |
111 | runs(function() {
112 | expect(handled).toEqual(true);
113 | });
114 | });
115 |
116 | it("should handle post requests ('Content-Type' = 'application/x-www-form-urlencoded')", function() {
117 | var page = require('webpage').create();
118 | var url = "http://localhost:12345/foo/bar.txt?asdf=true";
119 | //note: sorted by key (map)
120 | expectedPostData = {'answer' : "42", 'universe' : "expanding"};
121 | var handled = false;
122 | runs(function() {
123 | expect(handled).toEqual(false);
124 | page.open(url, 'post', "universe=expanding&answer=42", { "Content-Type" : "application/x-www-form-urlencoded" }, function (status) {
125 | expect(status == 'success').toEqual(true);
126 | expect(page.plainText).toEqual("request handled");
127 | handled = true;
128 | });
129 | });
130 |
131 | waits(50);
132 |
133 | runs(function() {
134 | expect(handled).toEqual(true);
135 | });
136 | });
137 |
138 | it("should handle post requests ('Content-Type' = 'ANY')", function() {
139 | var page = require('webpage').create();
140 | var url = "http://localhost:12345/foo/bar.txt?asdf=true";
141 | //note: sorted by key (map)
142 | expectedPostData = {'answer' : "42", 'universe' : "expanding"};
143 | var handled = false;
144 | runs(function() {
145 | expect(handled).toEqual(false);
146 | page.open(url, 'post', "universe=expanding&answer=42", { "Content-Type" : "application/json;charset=UTF-8" }, function (status) {
147 | expect(status == 'success').toEqual(true);
148 | expect(page.plainText).toEqual("request handled");
149 | handled = true;
150 | });
151 | });
152 |
153 | waits(50);
154 |
155 | runs(function() {
156 | expect(handled).toEqual(true);
157 | });
158 | });
159 |
160 | it("should handle binary data", function() {
161 | var page = require('webpage').create();
162 | var url = "http://localhost:12345/";
163 | var fs = require('fs');
164 | expectedBinaryData = fs.read('phantomjs.png', 'b');
165 | var handled = false;
166 | runs(function() {
167 | expect(handled).toEqual(false);
168 | page.open(url, 'get', function(status) {
169 | expect(status == 'success').toEqual(true);
170 | function checkImg() {
171 | var img = document.querySelector('img');
172 | return (img) && (img.width == 200) && (img.height == 200);
173 | }
174 | expect(page.evaluate(checkImg)).toEqual(true);
175 | handled = true;
176 | });
177 | });
178 |
179 | waits(50);
180 |
181 | runs(function() {
182 | expect(handled).toEqual(true);
183 | });
184 | });
185 |
186 | });
--------------------------------------------------------------------------------
/test/unit/phantom/tools.js:
--------------------------------------------------------------------------------
1 |
2 | // Add Helper Functions
3 | function expectHasFunction(o, name) {
4 | it("should have '" + name + "' function", function() {
5 | expect(typeof o[name]).toEqual('function');
6 | });
7 | }
8 |
9 | function expectHasProperty(o, name) {
10 | it("should have '" + name + "' property", function() {
11 | expect(o.hasOwnProperty(name)).toBeTruthy();
12 | });
13 | }
14 |
15 | function expectHasPropertyString(o, name) {
16 | expectHasProperty(o, name);
17 |
18 | it("should have '" + name + "' as a string", function() {
19 | expect(typeof o[name]).toEqual('string');
20 | });
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/test/unit/ref/sample.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello there!
4 | From port:[[PORT]]
5 |
6 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/test/unit/ref/sample_module.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | exports.ok = true;
4 | exports.module = module;
5 | exports.require = require;
6 |
7 |
--------------------------------------------------------------------------------
/test/unit/ref/script.js:
--------------------------------------------------------------------------------
1 |
2 | var ___test190234 = [] instanceof Array;
3 |
--------------------------------------------------------------------------------
/test/unit/spec/require.js:
--------------------------------------------------------------------------------
1 | /*
2 | * require.js
3 | *
4 | * Runs a set of unit tests used to verify the
5 | * commonJS module functionality.
6 | *
7 | */
8 |
9 | assert.suite('CommonJS functionality', function() {
10 |
11 | assert.section('Globals');
12 |
13 | assert(typeof require === 'function', 'require is a function');
14 |
15 | assert.section('Calling Inbuilt Modules');
16 |
17 | var fs = require('fs');
18 | assert(typeof fs === 'object', 'fs module can be instantiated');
19 | assert(typeof fs.workingDirectory === 'string', 'fs module contains a workingDirectory')
20 | var fs2 = require('fs');
21 | assert(typeof fs2 === 'object', 'fs module can be instantiated a second time');
22 | assert(fs2 === fs, 'fs module returns the same object when instantiated a second time');
23 |
24 | assert.section('Calling Modules using a path');
25 |
26 | var path = 'examples/universe';
27 | var sample_module = require(path);
28 | assert(typeof sample_module === 'object', 'module can be instantiated without an extension');
29 | assert(!!sample_module.id, 'module has an id property');
30 |
31 | assert(sample_module.answer === 42, 'module.answer is set to 42');
32 |
33 | path = 'examples/universe.js';
34 | sample_module = require(path);
35 | assert(typeof sample_module === 'object', 'module can be instantiated using a file path');
36 | assert(sample_module.answer === 42, 'module.answer is set to 42');
37 |
38 | var sample_module2 = require(path);
39 |
40 | assert(typeof sample_module2 === 'object', 'module can be instantiated a second time');
41 | assert(sample_module2.answer === 42, 'module.answer is set to 42 when instantiated a second time');
42 | assert(sample_module === sample_module2, 'module returns same object when instantiated a second time');
43 |
44 | var sample_module3 = require('examples\\universe.js');
45 |
46 | assert(typeof sample_module3 === 'object', 'module can be instantiated using a windows path');
47 | assert(sample_module3.answer === 42, 'module.answer is set to 42 when instantiated using windows path');
48 | assert(sample_module === sample_module3, 'module returns same object when instantiated using windows path');
49 |
50 | });
--------------------------------------------------------------------------------
/test/unit/spec/ssl.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ssl.js
3 | *
4 | * Runs a set of unit tests used to verify
5 | * SSL connectivity.
6 | *
7 | */
8 |
9 |
10 | assert.suite('SSL connectivity', function() {
11 |
12 | if (sslSupport !== true) {
13 | console.warn('No SSL Support, skipping tests!');
14 | return;
15 | }
16 |
17 | // Instantiate SSL server
18 | var serverCount = 0;
19 | var server = require('webserver').create();
20 | server.listen('https://localhost:8043', function(request, response) {
21 | serverCount++;
22 | response.write("Hello SSL!");
23 | response.close();
24 | });
25 |
26 | // --------------------------------------------
27 | assert.section('Basic SSL Interaction (WebServer & WebPage)', function() {
28 |
29 | var clientCount = 0;
30 | var page = require('webpage').create();
31 |
32 | // Turn errors on
33 | trifle.API.IgnoreSSLErrors = false;
34 |
35 | page.open('https://localhost:8043/1', function(status) {
36 | clientCount++;
37 | });
38 |
39 | trifle.wait(1000);
40 |
41 | assert(serverCount === 0, 'Browser does not hit the server if we turn errors on');
42 | assert(clientCount === 1, 'Browser executes callback if we turn errors on');
43 | assert(page.plainText.indexOf('security certificate') > -1, 'Browser shows a certificate error page');
44 |
45 |
46 | // Turn errors off
47 | trifle.API.IgnoreSSLErrors = true;
48 |
49 | page.open('https://localhost:8043/2', function(status) {
50 | assert.ready = true;
51 | clientCount++;
52 | });
53 |
54 | assert.waitUntilReady();
55 |
56 | assert(serverCount === 1, 'Browser hits the server when ignoring SSL errors');
57 | assert(clientCount === 2, 'Browser executes callback if we turn SSL errors off');
58 | assert(page.plainText === 'Hello SSL!', 'Correct text returned from SSL server');
59 |
60 | });
61 |
62 | assert.section('CLI Options', function() {
63 |
64 |
65 |
66 | });
67 |
68 | });
--------------------------------------------------------------------------------
/test/unit/spec/system.js:
--------------------------------------------------------------------------------
1 | /*
2 | * require.js
3 | *
4 | * Runs a set of unit tests used to verify
5 | * system functionality (platform, arguments etc)
6 | *
7 | */
8 |
9 | assert.suite('Object: system', function() {
10 |
11 | // SETUP
12 | var system = require('system');
13 |
14 | // --------------------------------------------
15 | assert.section('Properties & methods');
16 |
17 | assert.checkMembers(system, 'system', {
18 | pid: 'number',
19 | platform: 'string',
20 | os: 'object',
21 | env: 'object',
22 | args: 'object'
23 | });
24 |
25 | assert.checkMembers(system.os, 'system.os', {
26 | architecture: 'string',
27 | name: 'string',
28 | version: 'string'
29 | });
30 |
31 | var exists = {};
32 |
33 | Object.keys(system.env).forEach(function(key) {
34 | switch(key.toLowerCase()) {
35 | case 'path':
36 | assert(typeof system.env[key] === 'string', 'system.env "' + key + '" variable is of type string');
37 | exists.path = true;
38 | break;
39 | case 'programfiles':
40 | assert(typeof system.env[key] === 'string', 'system.env "' + key + '" variable is of type string');
41 | exists.programfiles = true;
42 | break;
43 | }
44 | });
45 |
46 | assert(exists.path === true, 'system.env contains the "PATH" variable');
47 | assert(exists.programfiles === true, 'system.env contains the "ProgramFiles" variable');
48 |
49 | assert(system.args instanceof Array, 'system.args is an array');
50 | assert(system.os.name === 'windows', 'system.os.name is "windows"');
51 |
52 | if (system.env.ProgramFiles.indexOf('x86') > 0) {
53 | assert(system.os.architecture === '64bit', 'system.os.architecture is "64bit"');
54 | } else {
55 | assert(system.os.architecture === '32bit', 'system.os.architecture is "32bit"');
56 | }
57 |
58 | });
59 |
--------------------------------------------------------------------------------
/test/unit/spec/webserver.js:
--------------------------------------------------------------------------------
1 | /*
2 | * webserver.js
3 | *
4 | * Runs a set of unit tests used that check
5 | * the the functionality in the webserver module
6 | *
7 | */
8 |
9 | assert.suite('Module: WebServer', function() {
10 |
11 | // SETUP
12 | var fs = require("fs");
13 | var server = require('webserver').create();
14 | var page = require('webpage').create();
15 | var workingDirectory = fs.workingDirectory;
16 | var loadCount = 0;
17 | var helloWorldListener = function(request, response) { loadCount++; response.write("Hello World"); response.close(); }
18 | var helloWorld2Listener = function(request, response) { loadCount++; response.write("Hello World2"); response.close(); }
19 | var infoListener = function(request, response) { loadCount++; response.write(JSON.stringify({success: true, httpVersion: request.httpVersion, method: request.method, url: request.url, headers: request.headers, post: request.post, postRaw: request.postRaw})); response.close(); }
20 |
21 | // --------------------------------------------
22 | assert.section('Instantiation');
23 | // --------------------------------------------
24 |
25 | assert(!!server, 'server can be instantiated using require()');
26 | assert(typeof server === 'object', 'server is an object');
27 |
28 | // --------------------------------------------
29 | assert.section('Properties & methods');
30 | // --------------------------------------------
31 |
32 | assert(typeof server.listen === 'function', 'server.listen() is a function');
33 | assert(typeof server.close === 'function', 'server.close() is a function');
34 | assert(typeof server.port === 'string', 'server.port is a string');
35 | assert(server.port === '', 'server.port is an empty string to beging with')
36 |
37 | // --------------------------------------------
38 | assert.section('Listening for connections');
39 | // --------------------------------------------
40 |
41 | var requestInfo;
42 |
43 | var isListening = server.listen(8080, helloWorldListener);
44 |
45 | assert(isListening === true, 'server.listen() returns true when listening');
46 | assert(server.port === '8080', 'server.port returns the correct port')
47 |
48 | page.open('http://localhost:8080/hello1', function(status) {
49 | assert.ready = true;
50 | });
51 |
52 | assert.waitUntilReady();
53 |
54 | assert(page.plainText === "Hello World", 'server responded with "Hello World" on 8080');
55 | assert(loadCount === 1, 'listener on 8080 fired once');
56 |
57 | // Try again on same port
58 |
59 | isListening = server.listen(8080, helloWorld2Listener);
60 |
61 | assert(isListening === true, 'server.listen() return true when listening on same port');
62 | assert(server.port === '8080', 'server.port returns the correct port')
63 |
64 | page.open('http://localhost:8080/hello2', function(status) {
65 | assert.ready = true;
66 | });
67 |
68 | assert.waitUntilReady();
69 |
70 | assert(page.plainText === "Hello World2", 'server responded with "Hello World2" on 8080 (binding is replaced)');
71 | assert(loadCount === 2, 'listener on 8080 fired once');
72 |
73 | isListening = server.listen(8081, infoListener);
74 |
75 | assert(isListening === true, 'server.listen() return true when listening on a different port');
76 | assert(server.port === '8081', 'server.port returns the correct port')
77 |
78 | page.open('http://localhost:8081/testurl?k=v', function(status) {
79 | assert.ready = true;
80 | });
81 |
82 | assert.waitUntilReady();
83 |
84 | requestInfo = JSON.parse(page.plainText);
85 |
86 | assert(loadCount === 3, 'listener on 8081 fired once');
87 | assert(requestInfo.success === true, 'request was a success');
88 | assert(requestInfo.httpVersion === '1.1', 'request httpVersion was 1.1');
89 | assert(requestInfo.method === 'GET', 'request method was correct (GET)');
90 | assert(typeof(requestInfo.headers) === 'object', 'request has some headers');
91 | assert(requestInfo.headers.Host === 'localhost:8081', 'request has correct Origin header');
92 | assert(requestInfo.url === '/testurl?k=v', 'request url was correct (/testurl?k=v)');
93 |
94 | // --------------------------------------------
95 | assert.section('POST Request');
96 | // --------------------------------------------
97 |
98 | page.open('http://localhost:8081/', 'POST', function(status) {
99 | assert.ready = true;
100 | });
101 |
102 | assert.waitUntilReady();
103 |
104 | requestInfo = JSON.parse(page.plainText);
105 |
106 | assert(loadCount === 4, 'listener on 8081 fired once');
107 | assert(requestInfo.method === 'POST', 'request method was correct (POST)');
108 | assert(typeof(requestInfo.headers) === 'object', 'request has some headers');
109 | assert(requestInfo.post === '', 'request body was empty (no data was posted)');
110 | assert(requestInfo.postRaw === '', 'request raw post was empty (no data was posted)');
111 |
112 | page.customHeaders = {
113 | 'Content-Type': 'application/x-www-form-urlencoded'
114 | };
115 |
116 | page.open('http://localhost:8081/', 'POST', 'user=username&pass=password&price=$15&location=o\'rileys bar&perc=10%', function(status) {
117 | assert.ready = true;
118 | });
119 |
120 | assert.waitUntilReady();
121 |
122 | requestInfo = JSON.parse(page.plainText);
123 |
124 | assert(loadCount === 5, 'listener on 8081 fired once');
125 | assert(requestInfo.method === 'POST', 'request method was correct (POST)');
126 | assert(typeof(requestInfo.headers) === 'object', 'request has some headers');
127 | assert(requestInfo.headers['Content-Type'] === 'application/x-www-form-urlencoded', 'Content-Type header set to application/x-www-form-urlencoded');
128 | assert(typeof(requestInfo.post) === 'object', 'request body is an object with some data');
129 | assert(requestInfo.post.user === 'username', 'request body contains username');
130 | assert(requestInfo.post.pass === 'password', 'request body contains password');
131 | assert(requestInfo.post.price === '$15', 'request body contains price ($15)');
132 | assert(requestInfo.post.location === 'o\'rileys bar', 'request body contains location (including special chars)');
133 | assert(requestInfo.post.perc === '10%', 'request body contains perc (including percentage sign)');
134 | assert(requestInfo.postRaw === 'user=username&pass=password&price=$15&location=o\'rileys bar&perc=10%', 'request raw post contains the data sent');
135 |
136 |
137 | // TEARDOWN
138 | server.close()
139 |
140 | });
141 |
142 |
143 |
--------------------------------------------------------------------------------
/test/unit/tools.js:
--------------------------------------------------------------------------------
1 |
2 | var assert = function(condition, message) {
3 | assert.n++;
4 | assert.count++;
5 | if (condition !== true) {
6 | assert.fail(message);
7 | } else {
8 | assert.pass(message);
9 | }
10 | }
11 |
12 | assert.count = 0;
13 |
14 | assert.pass = function(message) {
15 | console.API.color('green', assert.n + '. PASS: ' + (message || '(no message)') + '.');
16 | assert.pass.count++;
17 | }
18 |
19 | assert.pass.count = 0;
20 |
21 | assert.fail = function(message) {
22 | console.API.color('red', assert.n + '. FAIL: ' + (message || '(no message)') + '.');
23 | assert.fail.count++;
24 | }
25 |
26 | assert.fail.count = 0;
27 |
28 |
29 | assert.isError = function(callback, message) {
30 | assert.n++;
31 | assert.count++;
32 | try {
33 | callback.call(this);
34 | } catch(e) {
35 | assert.pass(message);
36 | return;
37 | }
38 | assert.fail(message);
39 | }
40 |
41 | assert.checkMembers = function(obj, objName, config) {
42 | if (obj && objName && config) {
43 | if (config instanceof Array) {
44 | config.forEach(function(prop) {
45 | assert(typeof obj[prop] !== 'undefined', objName + '.' + prop + ' exists');
46 | });
47 | return;
48 | } else if (config instanceof Object) {
49 | Object.keys(config).forEach(function(prop) {
50 | assert(typeof obj[prop] === config[prop], objName + '.' + prop + ' exists and is of type "' + config[prop] + '"');
51 | });
52 | return;
53 | }
54 | }
55 | throw new Error('assert.checkMembers() received an incorrect config object');
56 | }
57 |
58 | assert.reset = function() {
59 | assert.n = 0;
60 | }
61 |
62 | assert.suite = function(name, callback) {
63 | this.reset();
64 | console.log('');
65 | console.log('-------------------------------');
66 | console.log(' ' + name)
67 | console.log('-------------------------------');
68 | this.suitename = name;
69 | try {
70 | callback();
71 | } catch (e) {
72 | assert.n++
73 | assert.fail(e);
74 | }
75 | }
76 |
77 | assert.section = function(name, callback) {
78 | console.log('');
79 | console.log(' ' + this.suitename + ' - ' + name);
80 | console.log('');
81 | this.sectionname = name;
82 | if (typeof callback === 'function') {
83 | callback();
84 | }
85 | }
86 |
87 | assert.waitFor = function(callback, defaultTimeout) {
88 | if (defaultTimeout) {
89 | var start = (new Date()).getTime();
90 | do {
91 | trifle.wait(10);
92 | console.log((new Date()).getTime());
93 | } while (!callback() && (new Date()).getTime() < (start + defaultTimeout));
94 | } else {
95 | do {
96 | trifle.wait(10);
97 | } while (!callback());
98 | }
99 | }
100 |
101 | assert.waitUntilReady = function() {
102 | while(assert.ready !== true) {
103 | trifle.wait(10);
104 | }
105 | assert.ready = false;
106 | }
107 |
108 |
--------------------------------------------------------------------------------