Skip to content

Commit

Permalink
chore(promises) move interactive_test_util off q, rework to ES6 syntax (
Browse files Browse the repository at this point in the history
angular#5037)

- move interactive_test_util off q
- rework to ES6 syntax
  • Loading branch information
CrispusDH authored and cnishina committed Mar 23, 2019
1 parent c9db3f3 commit 45e163b
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 153 deletions.
32 changes: 16 additions & 16 deletions scripts/interactive_tests/interactive_test.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
var env = require('../../spec/environment.js');
var InteractiveTest = require('./interactive_test_util').InteractiveTest;
var port = env.interactiveTestPort;
var test = new InteractiveTest('node built/cli.js --elementExplorer true', port);
const env = require('../../spec/environment.js');
const InteractiveTest = require('./interactive_test_util');
const port = env.interactiveTestPort;
const test = new InteractiveTest('node built/cli.js --elementExplorer true', port);

// Check state persists.
test.addCommandExpectation('var x = 3');
test.addCommandExpectation('x', '3');
test.addCommandExpectation('x', '3');

// Check can return functions.
test.addCommandExpectation('var y = function(param) {return param;}');
test.addCommandExpectation('y', 'function (param) {return param;}');
test.addCommandExpectation('y', 'function (param) {return param;}');

// Check promises complete.
test.addCommandExpectation('browser.driver.getCurrentUrl()', 'data:,');
test.addCommandExpectation('browser.get("http://localhost:' + env.webServerDefaultPort + '/ng1")');
test.addCommandExpectation('browser.getCurrentUrl()',
'http://localhost:' + env.webServerDefaultPort + '/ng1/#/form');
test.addCommandExpectation('browser.getCurrentUrl()',
'http://localhost:' + env.webServerDefaultPort + '/ng1/#/form');

// Check promises are resolved before being returned.
test.addCommandExpectation('var greetings = element(by.binding("greeting"))');
Expand All @@ -26,24 +26,24 @@ test.addCommandExpectation('var q = require("q")');

// Check errors are handled gracefully
test.addCommandExpectation('element(by.binding("nonexistent"))');
test.addCommandExpectation('element(by.binding("nonexistent")).getText()',
'ERROR: NoSuchElementError: No element found using locator: ' +
test.addCommandExpectation('element(by.binding("nonexistent")).getText()',
'ERROR: NoSuchElementError: No element found using locator: ' +
'by.binding("nonexistent")');

// Check global `list` works.
test.addCommandExpectation('list(by.binding("greeting"))', '[ \'Hiya\' ]');
test.addCommandExpectation('list(by.binding("nonexistent"))', '[]');

// Check complete calls
test.addCommandExpectation('\t',
'[["element(by.id(\'\'))","element(by.css(\'\'))",' +
'"element(by.name(\'\'))","element(by.binding(\'\'))",' +
'"element(by.xpath(\'\'))","element(by.tagName(\'\'))",' +
test.addCommandExpectation('\t',
'[["element(by.id(\'\'))","element(by.css(\'\'))",' +
'"element(by.name(\'\'))","element(by.binding(\'\'))",' +
'"element(by.xpath(\'\'))","element(by.tagName(\'\'))",' +
'"element(by.className(\'\'))"],""]');
test.addCommandExpectation('ele\t', '[["element"],"ele"]');
test.addCommandExpectation('br\t', '[["break","","browser"],"br"]');
// Make sure the global 'list' we added shows up.
test.addCommandExpectation('li\t', '[["list"],"li"]');
test.addCommandExpectation('li\t', '[["list"],"li"]');

test.run();
test.run().then();

271 changes: 145 additions & 126 deletions scripts/interactive_tests/interactive_test_util.js
Original file line number Diff line number Diff line change
@@ -1,150 +1,169 @@
var child_process = require('child_process'),
q = require('q'),
net = require('net');
const child_process = require('child_process');
const net = require('net');

var TIMEOUT = 10000;
const TIMEOUT = 10000;

// An instance of a protractor debugger server.
var Server = function(serverStartCmd, port) {
class Server {
constructor(command, port) {
this.command = command;
this.port = port;
}
// Start protractor and its debugger server as a child process.
this.start = function() {
var deferred = q.defer();
var received = '';

serverStartCmd += ' --debuggerServerPort ' + port;
serverStartCmd = serverStartCmd.split(/\s/);
var test_process = child_process.spawn(serverStartCmd[0],
serverStartCmd.slice(1));

var timeoutObj = setTimeout(function() {
var errMsg = 'Did not start interactive server in ' + TIMEOUT/1000 + 's.';
if (received) {
errMsg += ' Server startup output: ' + received;
}
deferred.reject(errMsg);
}, TIMEOUT);
test_process.stdout.on('data', function(data) {
received += data;
if (received.indexOf('Server listening on 127.0.0.1:' + port) >= 0) {
clearTimeout(timeoutObj);
// Add a small time for browser to get ready
setTimeout(deferred.resolve, 2000);
}
});
start() {
return new Promise((resolve, reject) => {
let received = '';

const commands = `${this.command} --debuggerServerPort ${this.port}`.split(/\s/);
const command = commands[0];
const args = commands.slice(1);
const test_process = child_process.spawn(command, args);

const timeout = setTimeout(() => {
let errorMessage = `Did not start interactive server in ${TIMEOUT/1000}s.`;
if (received) {
errorMessage += ` Server startup output: ${received}`;
}
reject(errorMessage);
}, TIMEOUT);

test_process.stdout.on('data', (data) => {
received += data;
if (received.indexOf(`Server listening on 127.0.0.1:${this.port}`) !== -1) {
clearTimeout(timeout);
// Add a small time for browser to get ready
setTimeout(resolve(), 2000);
}
});

test_process.stderr.on('data', function(data) {
received += data;
test_process.stderr.on('data', (data) => {
received += data;
});
});

return deferred.promise;
};
};

// A client to attach to Protractor's debugger server and exchange data.
var Client = function(port) {
var socket;

// Connect to the server.
this.connect = function() {
var deferred = q.defer();
socket = net.connect({port: port}, function() {
deferred.resolve();
}
}

// A client to attach to Protractor's debugger server and exchange data.
class Client {
constructor(port) {
this.port = port;
this.socket = undefined;
}

// Connect to the server.
connect() {
return new Promise(resolve => {
this.socket = net.connect({port: this.port}, () => {
resolve();
});
});
return deferred.promise;
};
}

// Disconnect from the server.
this.disconnect = function() {
socket.end();
};

// Send a command to the server and wait for a response. Return response as a
// promise.
this.sendCommand = function(cmd) {
var deferred = q.defer();
var received = '';
var timeoutObj = setTimeout(function() {
var errMsg = 'Command <' + JSON.stringify(cmd) +
'> did not receive a response in ' + TIMEOUT/1000 + 's.';
if (received) {
errMsg += ' Received messages so far: ' + received;
}
deferred.reject(errMsg);
}, TIMEOUT);

var ondata = function(data) {
received += data.toString();
var i = received.indexOf('\r\n');
if (i >= 0) {
clearTimeout(timeoutObj);
var response = received.substring(0, i).trim();
deferred.resolve(response);
}
};
socket.on('data', ondata);

var onerror = function(data) {
deferred.reject('Received error: ' + data);
};
socket.on('error', onerror);

socket.write(cmd + '\r\n');
return deferred.promise.fin(function() {
clearTimeout(timeoutObj);
socket.removeListener('data', ondata);
socket.removeListener('error', onerror);
disconnect() {
this.socket.end();
}

// Send a command to the server and wait for a response. Return response as a
// promise.
sendCommand(command) {
let timeout;
let ondata;
let onerror;

return new Promise((resolve, reject) => {
let received = '';
timeout = setTimeout(() => {
let errorMessage = `Command ${JSON.stringify(command)} did not receive a response in ${TIMEOUT/1000}s.`;
if (received) {
errorMessage += ` Received messages so far: ${received}`;
}
reject(errorMessage);
}, TIMEOUT);

ondata = (data) => {
received += data.toString();
let i = received.indexOf('\r\n');
if (i !== -1) {
clearTimeout(timeout);
const response = received.substring(0, i).trim();
resolve(response);
}
};
this.socket.on('data', ondata);

onerror = (data) => {
reject(`Received error: ${data}`);
};
this.socket.on('error', onerror);

this.socket.write(`${command}\r\n`);
}).finally(() => {
clearTimeout(timeout);
this.socket.removeListener('data', ondata);
this.socket.removeListener('error', onerror);
});
};
};
}
}

/**
* Util for running an interactive Protractor test.
*/
exports.InteractiveTest = function(interactiveServerStartCmd, port) {
var expectations = [];

// Adds a command to send as well as the response to verify against.
module.exports = class InteractiveTest {
constructor(command, port) {
this.command = command;
this.port = port;
this.expectations = [];
}

// Adds a command to send as well as the response to verify against.
// If opt_expectedResult is undefined, the test will still wait for the server
// to respond after sending the command, but will not verify against it.
// Note, this does not actually interact with the server, but simply adds the
// Note, this does not actually interact with the server, but simply adds the
// command to a queue.
this.addCommandExpectation = function(command, opt_expectedResult) {
expectations.push({
addCommandExpectation(command, opt_expectedResult) {
this.expectations.push({
command: command,
expectedResult: opt_expectedResult
});
};
}

// Execute the interactive test. This will first start Protractor and its
// debugger server. Then it will connect to the server. Finally, it will
// debugger server. Then it will connect to the server. Finally, it will
// send the queue of commands against the server sequentially and verify the
// response from the server if needed.
this.run = function() {
var server = new Server(interactiveServerStartCmd, port);
return server.start().then(function() {
var client = new Client(port);
return client.connect().then(function() {
var verifyAll = function(i) {
if (i < expectations.length) {
var expectedResult = expectations[i].expectedResult;
var command = expectations[i].command;
return client.sendCommand(command).then(function(response) {
if (expectedResult !== undefined && expectedResult !== response) {
throw ('Command <' + JSON.stringify(command) + '> received: ' +
response + ', but expects: ' + expectedResult);
} else {
return verifyAll(i + 1);
}
});
}
};
return verifyAll(0);
}).fin(function() {
// '^]' This is the term signal.
client.sendCommand(String.fromCharCode(0x1D));
client.disconnect();
});
}).done();
};
// response from the server if needed.
async run() {
let failed = false;
let successfulCommands = [];
let failedCommands = [];

const server = new Server(this.command, this.port);
await server.start();
const client = new Client(this.port);
await client.connect();
for (let expectation of this.expectations) {
const expectedResult = expectation.expectedResult;
const command = expectation.command;
const response = await client.sendCommand(command);
if (expectedResult !== undefined && expectedResult !== response) {
failed = true;
successfulCommands.push(
`Command ${JSON.stringify(command)} received: ${response}, but expects: ${expectedResult}\n`
);
} else {
failedCommands.push('Command response as expected\n');
}
}
console.log('Successful commands: ');
for (let command of successfulCommands) {
console.log(command);
}
console.log('Failed commands: ');
for (let command of failedCommands) {
console.log(command);
}
console.log('Summary: ' + (failed ? 'fail' : 'pass'));
await client.sendCommand(String.fromCharCode(0x1D));
await client.disconnect();
}
};
16 changes: 8 additions & 8 deletions scripts/interactive_tests/with_base_url.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
var env = require('../../spec/environment.js');
var InteractiveTest = require('./interactive_test_util').InteractiveTest;
var port = env.interactiveTestPort;
var test = new InteractiveTest(
'node built/cli.js --baseUrl http://localhost:' + env.webServerDefaultPort +
const env = require('../../spec/environment.js');
const InteractiveTest = require('./interactive_test_util');
const port = env.interactiveTestPort;
const test = new InteractiveTest(
'node built/cli.js --baseUrl http://localhost:' + env.webServerDefaultPort +
'/ng1 --elementExplorer true', port);

// Check we automatically go to to baseUrl.
test.addCommandExpectation(
'browser.driver.getCurrentUrl()',
'http://localhost:' + env.webServerDefaultPort + '/ng1/#/form');
test.run();
'browser.driver.getCurrentUrl()',
'http://localhost:' + env.webServerDefaultPort + 'asdasd/asdng1/#/form');
test.run().then();
6 changes: 3 additions & 3 deletions scripts/test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/usr/bin/env node
var path = require('path');
const path = require('path');

var Executor = require('./test/test_util').Executor;
const Executor = require('./test/test_util').Executor;

var passingTests = [
const passingTests = [
'node built/cli.js spec/basicConf.js',
// 'node built/cli.js spec/basicConf.js --useBlockingProxy',
'node built/cli.js spec/multiConf.js',
Expand Down
2 changes: 2 additions & 0 deletions spec/.jshintrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"strict": false,
"esversion": 6,
"predef": [
"protractor",
"browser",
Expand Down

0 comments on commit 45e163b

Please sign in to comment.