Skip to content
This repository was archived by the owner on May 12, 2021. It is now read-only.

Commit 5e9fb06

Browse files
committed
Fixed issue #1, version updated
0 parents  commit 5e9fb06

7 files changed

Lines changed: 560 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.idea
2+
node_modules
3+
benchmark

Gruntfile.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module.exports = function (grunt) {
2+
grunt.initConfig({
3+
nodeunit: {
4+
all: ['./test/*.test.js']
5+
}
6+
});
7+
8+
grunt.loadNpmTasks('grunt-contrib-nodeunit');
9+
};

README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
TestCafe RPC
2+
======
3+
RPC library for the [TestCafé](http://testcafe.devexpress.com/). It allows you to create a single TestCafé instance and then interact with it programmatically from any machine in your network.
4+
5+
6+
Install
7+
-------
8+
```
9+
$ npm install testcafe-rpc
10+
```
11+
12+
Running a server
13+
-------------
14+
```js
15+
var TestCafeRemote = require('testcafe-rpc');
16+
17+
//Options for TestCafé instance
18+
var opt = {
19+
controlPanelPort: 1337,
20+
servicePort: 1338,
21+
testsDir: 'YOUR_TESTS_DIR',
22+
browsers: {
23+
'Mozilla Firefox': {
24+
path: "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe",
25+
icon: "ff",
26+
cmd: "-new-window"
27+
}
28+
}
29+
},
30+
rpcPort = 1339;
31+
32+
//Create TestCafé server instance with given options which can be accessed via RPC on port 1339.
33+
var testCafeServer = new TestCafeRemote.Server(opt, rpcPort);
34+
35+
//Returned object exposes standard TestCafé API, so you can use it as a regular TestCafé instance.
36+
testCafeServer.runTests({ browsers: testCafeServer.listAvailableBrowsers() }, function (errors, taskUid, workers) {
37+
//do smthg...
38+
});
39+
```
40+
41+
Running a client
42+
-------------
43+
```js
44+
var TestCafeRemote = require('testcafe-rpc');
45+
46+
var rpcHostname = 'myhostname',
47+
rpcPort = 1339;
48+
49+
//Connect to the existent TestCafé server (if you running both client and server on the same machine
50+
//hostname-parameter can be ommited).
51+
var testCafeClient = new TestCafeRemote.Client(rpcPort, rpcHostname);
52+
53+
//Client can be used as a regular TestCafé instance with exception that listAvailableBrowsers() and listConnectedWorkers()
54+
//are asynchronous methods.
55+
testCafeClient.listAvailableBrowsers(function(browsers) {
56+
testCafeClient.runTests({ browsers: browsers }, function (errors, taskUid, workers) {
57+
//do smthg...
58+
});
59+
});
60+
```
61+
Need more help to get started?
62+
--------------
63+
Visit TestCafé [Continuous integration guide](http://testcafe.devexpress.com/Documentation/Tutorial/Continuous_Integration) and [Continuous integration API reference](http://testcafe.devexpress.com/Documentation/ApiReference/Continuous_Integration_API_Reference). If you have any additional questions or suggestions don't hesitate to ask using [DevExpress Support Center](http://www.devexpress.com/Support/Center/Question/ChangeFilterSet/1?FavoritesOnly=False&MyItemsOnly=False&MyTeamItemsOnly=False&TechnologyName=Testing+Tools&PlatformName=AllPlatforms&ProductName=AllProducts&TicketType=All).
64+
65+
66+

index.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
var net = require('net'),
2+
dnode = require('dnode'),
3+
TestCafe = require('testcafe').TestCafe;
4+
5+
exports.Server = function (cfg, port) {
6+
var testCafe = new TestCafe(cfg);
7+
8+
var server = net.createServer(function (conn) {
9+
var d = dnode({
10+
on: function (evtName, callback) {
11+
testCafe.on(evtName, callback);
12+
},
13+
14+
listAvailableBrowsers: function (callback) {
15+
callback(testCafe.listAvailableBrowsers());
16+
},
17+
18+
listConnectedWorkers: function (callback) {
19+
callback(testCafe.listConnectedWorkers());
20+
},
21+
22+
listDirectory: testCafe.listDirectory.bind(testCafe),
23+
runTests: testCafe.runTests.bind(testCafe)
24+
});
25+
26+
conn.pipe(d).pipe(conn);
27+
28+
//NOTE: this fixes https://github.com/DevExpress/TestCafe-RPC/issues/1
29+
conn.on('error', function () {
30+
conn.destroy();
31+
});
32+
});
33+
34+
server.listen(port);
35+
36+
return testCafe;
37+
};
38+
39+
var Client = exports.Client = function (serverPort, serverHostname) {
40+
this.serverPort = serverPort;
41+
this.serverHostname = serverHostname;
42+
43+
};
44+
45+
Client.prototype._rpc = function (methodName, args, callback, isEvent) {
46+
var d = dnode.connect(this.serverPort, this.serverHostname).on('remote', function (remote) {
47+
args.push(function () {
48+
callback.apply(null, arguments);
49+
50+
if (!isEvent)
51+
d.end();
52+
});
53+
54+
remote[methodName].apply(remote, args);
55+
});
56+
};
57+
58+
Client.prototype.listAvailableBrowsers = function (callback) {
59+
this._rpc('listAvailableBrowsers', [], callback, false);
60+
};
61+
62+
Client.prototype.listConnectedWorkers = function (callback) {
63+
this._rpc('listConnectedWorkers', [], callback, false);
64+
};
65+
66+
Client.prototype.listDirectory = function (path, callback) {
67+
this._rpc('listDirectory', [path], callback, false);
68+
};
69+
70+
Client.prototype.runTests = function (options, callback) {
71+
this._rpc('runTests', [options], callback, false);
72+
};
73+
74+
Client.prototype.on = function (evtName, handler) {
75+
this._rpc('on', [evtName], handler, true);
76+
};
77+

package.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "testcafe-rpc",
3+
"author": "DevExpress (www.devexpress.com)",
4+
"version": "0.6.0",
5+
"keywords": [
6+
"TestCafe",
7+
"RPC",
8+
"remoting",
9+
"remote",
10+
"testing",
11+
"functional"
12+
],
13+
"main": "./index.js",
14+
15+
"dependencies": {
16+
"dnode": "~1.0.5",
17+
"testcafe": "~13.1.1"
18+
},
19+
"devDependencies": {
20+
"grunt": "~0.4.1",
21+
"grunt-contrib-nodeunit": "~0.2.0",
22+
"node-phantom": "~0.2.3",
23+
"phantomjs": "~1.9.2-0"
24+
}
25+
}
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
'@fixture TestCafe Example Page';
2+
3+
'@page http://testcafe.devexpress.com/Example';
4+
5+
'@test'['act.type examples'] = {
6+
'Type name': function () {
7+
act.type($('#Developer_Name'), 'Peter');
8+
},
9+
'Replace with last name': function () {
10+
act.type($('#Developer_Name'), 'Paker', {
11+
replace: true
12+
});
13+
},
14+
'Update last name': function () {
15+
act.type($('#Developer_Name'), 'r', {
16+
caretPos: 2
17+
});
18+
},
19+
'Check result': function () {
20+
eq($('#Developer_Name').val(), 'Parker');
21+
}
22+
};
23+
24+
'@test'['act.click, array parameter, ok() assertion'] = {
25+
'Click two checkbox labels': function () {
26+
var labels = [$(':containsExcludeChildren(Support for testing on remote devices)'),
27+
$(':containsExcludeChildren(Reusing existing JavaScript code for testing)')];
28+
act.click(labels);
29+
},
30+
'Confirm checked state': function () {
31+
ok($('#testing-on-remote-devices').is(':checked'));
32+
ok($('#re-using-existing-javascript').is(':checked'));
33+
}
34+
};
35+
36+
'@test'['act.click on an input, eq() assertion'] = {
37+
'Type name': function () {
38+
act.type(getInput(), 'Peter Parker');
39+
},
40+
'Move caret position': function () {
41+
act.click(getInput(), {
42+
caretPos: 5
43+
});
44+
},
45+
'Erase a character': function () {
46+
act.press('backspace');
47+
},
48+
'Check result': function () {
49+
eq(getInput().val(), 'Pete Parker');
50+
}
51+
};
52+
53+
'@test'['act.press example'] = {
54+
'Type name': function () {
55+
act.type(getInput(), 'Peter Parker');
56+
},
57+
'Erase Peter': function () {
58+
act.press('home right . delete delete delete delete');
59+
},
60+
'Check result': function () {
61+
eq(getInput().val(), 'P. Parker');
62+
}
63+
};
64+
65+
'@test'['ok() vs notOk() assertions'] = {
66+
'Check comments area is disabled': function () {
67+
ok($('#Developer_Comments').is(':disabled'));
68+
},
69+
'Click label "I have tried TestCafe"': function () {
70+
var label = $(':containsExcludeChildren(I have tried TestCafe)');
71+
act.click(label);
72+
},
73+
'Check comments area is enabled': function () {
74+
notOk($('#Developer_Comments').is(':disabled'));
75+
}
76+
};
77+
78+
'@test'['eq() assertion example'] = {
79+
'Type name': function () {
80+
act.type(getInput(), 'Peter Parker');
81+
},
82+
'Submit form': function () {
83+
var submitButton = $('.button.blue.fix-width-180');
84+
act.click(submitButton);
85+
},
86+
'Check message': function () {
87+
var header = $('.article-header');
88+
eq(header.html(), 'Thank You, Peter Parker!');
89+
}
90+
};
91+
92+
'@test'['act.drag example'] = {
93+
'Click label "I have tried TestCafe"': function () {
94+
var label = $(':containsExcludeChildren(I have tried TestCafe)');
95+
act.click(label);
96+
},
97+
'Check initial slider value': function () {
98+
eq($('#Developer_Rating').val(), 0);
99+
},
100+
'Drag slider handle': function () {
101+
var sliderHandle = $('.ui-slider-handle');
102+
act.drag(sliderHandle, 357, 0, {
103+
offsetX: 10,
104+
offsetY: 10
105+
});
106+
},
107+
'Check resulting slider value': function () {
108+
eq($('#Developer_Rating').val(), 7);
109+
}
110+
};
111+
112+
'@test'['act.hover example'] = {
113+
'Hover over the combo box': function () {
114+
var div = $('.text-field');
115+
act.hover(div);
116+
},
117+
'Select "Both"': function () {
118+
var div = $(':containsExcludeChildren(Both)').eq(0);
119+
act.click(div);
120+
},
121+
'Check result': function () {
122+
var value = $('.text-field').html();
123+
eq(value, 'Both');
124+
}
125+
};
126+
127+
'@test'['act.wait example'] = {
128+
'Initiate animation and wait': function () {
129+
$('.article-header').animate({
130+
opacity: 0
131+
}, 1e3);
132+
act.wait(1e4, isTransparent);
133+
},
134+
'Type': function () {
135+
var input = $('#Developer_Name');
136+
act.type(input, 'The wait is over!');
137+
}
138+
};
139+
140+
'@test'['handleConfirm() example'] = {
141+
'1.Click "Populate"': function () {
142+
var populateFormButton = $(':containsExcludeChildren(Populate)');
143+
handleConfirm('OK');
144+
act.click(populateFormButton);
145+
},
146+
'2.Click "Submit"': function () {
147+
this.autoGeneratedName = $('#Developer_Name').val();
148+
var submitButton = $('.button.blue.fix-width-180');
149+
act.click(submitButton);
150+
},
151+
'Check result': function () {
152+
var header = $('.article-header');
153+
var expectedResult = 'Thank You, ' + this.autoGeneratedName + '!';
154+
eq(header.html(), expectedResult);
155+
}
156+
};
157+
158+
'@test'['video example'] = {
159+
'1.Click "MacOS"': function () {
160+
var label = $(':containsExcludeChildren(MacOS)');
161+
act.click(label);
162+
},
163+
'2.Type a name': function () {
164+
var input = $('#Developer_Name');
165+
act.type(input, 'Peter Parker', {
166+
offsetX: 59,
167+
offsetY: 22,
168+
caretPos: 0
169+
});
170+
},
171+
'3.Hover over "Visual recorder"': function () {
172+
var div = $('.text-field');
173+
act.hover(div);
174+
},
175+
'4.Click "Both"': function () {
176+
var div = $(':containsExcludeChildren(Both)').eq(0);
177+
act.click(div, {
178+
offsetX: 71,
179+
offsetY: 12
180+
});
181+
},
182+
'5.Click "Submit"': function () {
183+
var submitButton = $('#submit-button');
184+
act.click(submitButton, {
185+
offsetX: 126,
186+
offsetY: 38
187+
});
188+
},
189+
'6. Check Result': function () {
190+
var header = $('.article-header');
191+
eq(header.html(), 'Thank You, Peter Parker!');
192+
}
193+
194+
};
195+
196+
//helpers
197+
var isTransparent = function () {
198+
return $('.article-header').css('opacity') == 0;
199+
};
200+
201+
var getInput = function () {
202+
return $('#Developer_Name');
203+
};

0 commit comments

Comments
 (0)