JavaScript mocked function returning undefined in tests - javascript

I'm trying to test some JavaScript functions that are part of a larger React app. They make heavy use of the module pattern, which I suspect may be what I'm not understanding correctly. Here is the script I'm testing (nearly identical to the one actually used in the real app except that GetFeedData.getFeedData in the real one makes a call to an external API):
const GetFeedData = (function () {
let feed, feedId;
return {
getFeedId: function (sub) {
switch (sub) {
case '1': case '2': case '3': case '4': case '5': case '6': case 'S':
feedId = 1;
break;
case 'A': case 'C': case 'E':
feedId = 26;
break;
case 'N': case 'Q': case 'R': case 'W':
feedId = 16;
break;
case 'B': case 'D': case 'F': case 'M':
feedId = 21;
break;
case 'L':
feedId = 2;
break;
case 'G':
feedId = 31;
break;
}
},
getFeedData: function () {
if (feedId === 2) {
feed = require('./MockData');
}
},
feed: feed
};
})();
const ReverseStop = (function () {
let stopIdN, stopIdS;
const stopData = require('../utils/stops');
return {
reverseStop: function (sub, stop) {
var invalidEntries = 0;
function filterByName (item) {
if (item.stop_name == stop && typeof item.stop_id === 'string' && item.stop_id.charAt(0) == sub) {
return true;
}
invalidEntries ++;
return false;
}
var stopObjs = stopData.filter(filterByName);
for (var i = 0; i < stopObjs.length; i++) {
if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'N') {
stopIdN = stopObjs[i].stop_id;
} else if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'S') {
stopIdS = stopObjs[i].stop_id;
}
}
},
stopIdN: stopIdN,
stopIdS: stopIdS
};
})();
export const IsDelayN = (function () {
let noDelay, yesDelay, nextArrival, delay;
return {
isDelay: function (sub, stop) {
GetFeedData.getFeedId(sub);
GetFeedData.getFeedData();
ReverseStop.reverseStop(sub, stop);
var arrivals = [];
var delays = [];
function dataFilter () {
var invalidEntries = 0;
var feedObjs = GetFeedData.feed.filter(function (feedObj) {
if (feedObj.entity.trip_update.stop_time_update.stop_id == ReverseStop.stopIdN) {
return feedObj.entity.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs.length; i++) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
}
nextArrival = Math.min(...arrivals);
var delayIndex = arrivals.indexOf(nextArrival);
delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
noDelay = Math.ceil((nextArrival - GetFeedData.feed.header.timestamp.low) / 60);
} else {
yesDelay = Math.ceil(delay / 60);
}
},
noDelay: noDelay,
yesDelay: yesDelay,
nextArrival: nextArrival
};
})();
export const IsDelayS = (function () {
let noDelay, yesDelay, nextArrival, delay;
return {
isDelay: function (sub, stop) {
GetFeedData.getFeedId(sub);
GetFeedData.getFeedData();
ReverseStop.reverseStop(sub, stop);
var arrivals = [];
var delays = [];
function dataFilter () {
var invalidEntries = 0;
var feedObjs = GetFeedData.feed.filter(function (feedObj) {
if (feedObj.entity.trip_update.stop_time_update.stop_id == ReverseStop.stopIdS) {
return feedObj.entity.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs; i++) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
}
nextArrival = Math.min(...arrivals);
var delayIndex = arrivals.indexOf(nextArrival);
delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
noDelay = Math.ceil((nextArrival - GetFeedData.feed.header.timestamp.low) / 60);
} else {
yesDelay = Math.ceil(delay / 60);
}
},
noDelay: noDelay,
yesDelay: yesDelay,
nextArrival: nextArrival
};
})();
What I'm attempting to do is separate out my functions so I have several shorter ones I can call in the exported functions, rather than one or two extremely long functions. Because I need to call a couple variables - GetFeedData.feed, ReverseStop.stopIdN, and ReverseStop.stopIdS in the exported functions, I am assuming that the module pattern is a better way to go than using callbacks. I could totally be wrong.
In my tests, I try log noDelay, nextArrival, and delay to the console to see if they are defined. I'm using Jest, if that information is helpful. I'll omit the other parts of my test for now because they don't seem relevant (please correct me if that's wrong), but here is that section:
it('correctly takes input at beginning of api logic and outputs expected values at end', () => {
IsDelayN.isDelay('L', 'Lorimer St');
IsDelayS.isDelay('L', 'Lorimer St');
expect(IsDelayN.noDelay).toBeTruthy();
expect(IsDelayN.yesDelay).toBeFalsy();
expect(IsDelayS.noDelay).toBeTruthy();
expect(IsDelayS.yesDelay).toBeFalsy();
console.log('IsDelayN noDelay: ' + IsDelayN.noDelay);
console.log('IsDelayN nextArrival: ' + IsDelayN.nextArrival);
console.log('IsDelayN delay: ' + IsDelayN.delay);
console.log('IsDelayS noDelay: ' + IsDelayS.noDelay);
console.log('IsDelayS nextArrival: ' + IsDelayS.nextArrival);
console.log('IsDelayS delay: ' + IsDelayS.delay);
});
The tests prior to my console.log()s are all passing, but every console.log() is turning up undefined. Also, the script that's actually being called by my React components is coming up with the same results. I have my component set to render null if these variables aren't defined, and that's exactly what's happening.
Any help with understanding this is greatly appreciated.

You do not set the modules correctly, when setting a member value you should mutate the object, now you just set a variable value.
The following should work for you:
var module = (function(){
const ret = {
mutateSomething:function(value){
//set otherValue on the object returned (mutate ret)
ret.otherValue = value;
}
,otherValue:undefined
};//create the object first
return ret;//then return the object
}())//IIFE
console.log("before mutate:",module.otherValue);
module.mutateSomething("Hello World");
console.log("after mutate:",module.otherValue);

Related

Module not found with npm package in React app

I have a React app that takes some data from an API. The data is transit data and is serialized with protocol buffers, so I'm using the gtfs-realtime-bindings.js package to deserialize it. That also uses ProtoBuf.js and ByteBuffer.js under the hood. However, when I run my dev server, I'm getting this error in the browser:
./node_modules/protobufjs/ProtoBuf.js
Module not found: `/Users/Ben/React/subway-
checker/node_modules/ByteBuffer/ByteBuffer.js` does not match the
corresponding path on disk `bytebuffer`.
I'm not really sure how to start debugging this. It could be a Webpack issue? I'm using create-react-app if that helps diagnose.
For context, here's the rest of the code in the file that's causing the error:
import GtfsRealtimeBindings from 'gtfs-realtime-bindings';
import request from 'request';
function getFeedData (sub) {
var feedId;
switch (sub) {
case '1' || '2' || '3' || '4' || '5' || '6' || 'S':
feedId = 1;
break;
case 'A' || 'C' || 'E':
feedId = 26;
break;
case 'N' || 'Q' || 'R' || 'W':
feedId = 16;
break;
case 'B' || 'D' || 'F' || 'M':
feedId = 21;
break;
case 'L':
feedId = 2;
break;
case 'G':
feedId = 31;
break;
}
var requestSettings = {
method: 'GET',
uri: 'http://datamine.mta.info/mta_esi.php?key=YOUR_KEY_HERE&feed_id=2',
encoding: null
};
request(requestSettings, function (error, response, body) {
if (!error && response.statusCode == 200) {
var feed = GtfsRealtimeBindings.FeedMessage.decode(body);
return { feed: feed };
}
});
}
function reverseStop (sub, stop) {
var stopIdN
var stopIdS
var stopData = require('./stops');
var invalidEntries = 0;
function filterByName (item) {
if (item.stop_name == stop && item.stop_id.charAt(0) == sub) {
return true;
}
invalidEntries++;
return false;
}
var stopObjs = stopData.filter(filterByName);
for (var i = 0; i < stopObjs.length; i++) {
if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'N') {
stopIdN = stopObjs[i].stop_id;
} else if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'S') {
stopIdS = stopObjs[i].stop_id;
}
}
return {
stopIdN: stopIdN,
stopIdS: stopIdS
};
}
var isDelayN = (function (sub, stop) {
var arrivals = [];
var delays = [];
reverseStop(sub, stop);
getFeedData(sub);
(function () {
var invalidEntries = 0;
var feedObjs = getFeedData.feed.filter(function (feedObj) {
if (feedObj.entity.trip_update.stop_time_update.stop_id == reverseStop.stopIdN) {
return feedObj.entity.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs.length; i++) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
})();
var nextArrival = Math.min(...arrivals);
var delayIndex = arrivals.findIndexOf(nextArrival);
var delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
var noDelay = Math.ceil((nextArrival - getFeedData.feed.header.timestamp.low) / 60);
return { noDelay: noDelay };
} else {
var yesDelay = Math.ceil(delay / 60);
return { yesDelay: yesDelay };
}
})();
var isDelayS = (function (sub, stop) {
var arrivals = [];
var delays = [];
reverseStop(stop);
getFeedData(sub)
.then(function (feed) {
var invalidEntries = 0;
var feedObjs = feed.filter(function (feedObj) {
if (feedObj.entity.trip_update.stop_time_update.stop_id == reverseStop.stopIdS) {
return feedObj.entity.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs; i++) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
});
var nextArrival = Math.min(...arrivals);
var delayInex = arrivals.findIndexOf(nextArrival);
var delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
var noDelay = Math.ceil((nextArrival - getFeedData.feed.header.timestamp.low) / 60);
return { noDelay: noDelay };
} else {
var yesDelay = Math.ceil(delay / 60);
return { yesDelay: yesDelay };
}
})();
export { isDelayN, isDelayS };
I realize that code may need a lot of context. In lieu of posting all of my components and having an unreasonably long post, here's the full Github repo as it stands right now: https://github.com/benuchadnezzar/subway-checker
Any help is appreciated! Including if you see something else egregiously wrong with the code in this file.

Unexpected token in module export [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
I'm getting the following error with a file that's part of a React app:
./src/utils/api.js
Syntax error: Unexpected token (118:1)
116 | }
117 | }
> 118 | }
| ^
Here's the full code for the file in question:
import GtfsRealtimeBindings from 'mta-gtfs-realtime-bindings';
import rp from 'request-promise';
function getFeedData (sub) {
var feedId;
switch (sub) {
case '1': case '2': case '3': case '4': case '5': case '6': case 'S':
feedId = 1;
break;
case 'A': case 'C': case 'E':
feedId = 26;
break;
case 'N': case 'Q': case 'R': case 'W':
feedId = 16;
break;
case 'B': case 'D': case 'F': case 'M':
feedId = 21;
break;
case 'L':
feedId = 2;
break;
case 'G':
feedId = 31;
break;
}
rp({
method: 'GET',
url: 'http://datamine.mta.info/mta_esi.php?key=5db5e052519d17320f490738f2afe0d5&feed_id=' + feedId,
encoding: null
}).then((buf) => {
const feed = GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(buf);
return { feed: feed };
});
function reverseStop (sub, stop) {
var stopIdN
var stopIdS
var stopData = require('./stops');
var invalidEntries = 0;
function filterByName (item) {
if (item.stop_name == stop && item.stop_id.charAt(0) == sub) {
return true;
}
invalidEntries++;
return false;
}
var stopObjs = stopData.filter(filterByName);
for (var i = 0; i < stopObjs.length; i++) {
if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'N') {
stopIdN = stopObjs[i].stop_id;
} else if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'S') {
stopIdS = stopObjs[i].stop_id;
}
}
return {
stopIdN: stopIdN,
stopIdS: stopIdS
};
}
module.exports = {
isDelayN: function (sub, stop) {
var arrivals = [];
var delays = [];
reverseStop(sub, stop);
getFeedData(sub);
(function () {
var invalidEntries = 0;
var feedObjs = getFeedData.feed.filter(function (feedObj) {
if (feedObj.entity.trip_update.stop_time_update.stop_id == reverseStop.stopIdN) {
return feedObj.entity.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs.length; i++) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
})();
var nextArrival = Math.min(...arrivals);
var delayIndex = arrivals.findIndexOf(nextArrival);
var delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
var noDelay = Math.ceil((nextArrival - getFeedData.feed.header.timestamp.low) / 60);
return { noDelay: noDelay };
} else {
var yesDelay = Math.ceil(delay / 60);
return { yesDelay: yesDelay };
}
},
isDelayS: function (sub, stop) {
var arrivals = [];
var delays = [];
reverseStop(stop);
getFeedData(sub)
.then(function (feed) {
var invalidEntries = 0;
var feedObjs = feed.filter(function (feedObj) {
if (feedObj.entity.trip_update.stop_time_update.stop_id == reverseStop.stopIdS) {
return feedObj.entity.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs; i++) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
});
var nextArrival = Math.min(...arrivals);
var delayInex = arrivals.findIndexOf(nextArrival);
var delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
var noDelay = Math.ceil((nextArrival - getFeedData.feed.header.timestamp.low) / 60);
return { noDelay: noDelay };
} else {
var yesDelay = Math.ceil(delay / 60);
return { yesDelay: yesDelay };
}
}
}
The thing is I'm pretty sure it's not that final bracket that's actually causing the error, but I'm not sure how to diagnose what is doing it. My guess is that there's something I'm not understanding properly about exporting modules? I realize a question about syntax errors isn't the best thing to post here, so thank you for bearing with me. If anyone has tips for how I can better diagnose problems like this on my own (Google wasn't helpful), I'd greatly appreciate those as well.
I was missing a closing bracket in an earlier function. Let this be a lesson to me to use a linter.

Javascript: Updating direction of robot using string is not working

Javascript
Trying to work on a simple game of moving a robot using key L(to move left), R(to move right), F(to move forward) from a specific position on a board where it is created using 5x5 dimension and always facing North (shown as N). Clicking a Move button after entering any of above string/characters should display the current position.
Expected: For instance if I say board dimension (5x5), current position (3,3), enter 'R' and hit Move button it should show the resulting position as (3,3) E because the robot was facing north (N) first and now asked to move to RIGHT which would be east (E).
Problem: Can't seem to spot the issue in my code why the direction is not getting updated.
Here is the code that does all calculation and update.
var RobotManager = {
roomType: 'square',
roomParameters: [5, 5],
robotDirection: 'N',
robotPosition: [1, 2],
possibleDirections: ["N", "E", "S", "W"],
errorMessageNumber: -1,
errorMessage: [
"error0",
"error1",
"all other errors removed to keep code clean"
],
squares: [],
stringCommandThatExexuted: '',
init: function() {
var regexp_number = /^[1-9]$|([1][0-9])$/;
return true;
},
// This should move the robot to the right direction
turnRight: function() {
var movePosition = this.possibleDirections.indexOf(this.robotDirection);
if (movePosition == this.possibleDirections.length - 1) {
return this.possibleDirections[0];
}
return this.possibleDirections[movePosition + 1];
},
turnLeft: function() {
var movePosition = this.possibleDirections.indexOf(this.robotDirection);
if (movePosition == 0) {
return this.possibleDirections[this.possibleDirections.length - 1];
}
return this.possibleDirections[movePosition - 1];
},
moveForward: function() {
var nextPosition = this.getNextPosition();
var nextSquare = {
X: nextPosition[0],
Y: nextPosition[1]
};
if (this.isSquareAvailable(nextSquare)) {
this.robotPosition = nextPosition;
} else {
this.errorMessageNumber = 1;
return false;
}
return true;
},
//this is not getting executed to update the direction
getNextPosition: function() {
var x, y;
switch (this.robotDirection) {
case "N":
x = this.robotPosition[0];
y = this.robotPosition[1] - 1;
break;
case "E":
x = this.robotPosition[0] + 1;
y = this.robotPosition[1];
break;
case "W":
x = this.robotPosition[0] - 1;
y = this.robotPosition[1];
break;
case "S":
y = this.robotPosition[1] + 1;
x = this.robotPosition[0];
break;
}
return [x, y];
},
//First button clicks comes here and just renders default value of direction
getRobotsPositionAndDirection: function() {
if (this.errorMessageNumber <= 1) {
var message = "";
if (this.errorMessageNumber == 0) {
return this.errorMessage[0];
}
if (this.errorMessageNumber == 1) {
message = this.errorMessage[1];
}
return message + this.robotPosition[0] + " " + this.robotPosition[1] + " " + this.robotDirection;
}
return this.errorMessage[8];
},
checkCommandString: function(string) {
var english_command = /^[LRF]*$/;
if (english_command.test(string)) {
return true;
}
this.errorMessageNumber = 0;
return false;
},
getCommandStringThatExecuted: function() {
return this.stringCommandThatExexuted;
},
//This is where index is passed as 0 and doesn't execute
moveRobotToOnePosition: function(letter) {
switch (letter) {
case 'L':
this.robotDirection = this.turnLeft();
this.stringCommandThatExexuted += 'L';
break;
case 'R':
this.robotDirection = this.turnRight();
this.stringCommandThatExexuted += 'R';
break;
case 'F':
if (this.moveForward()) {
this.stringCommandThatExexuted += 'F';
return true;
} else {
return false;
}
break;
}
},
moveRobot: function(string) {
string = string.toUpperCase();
if (this.checkCommandString(string)) {
var array = string.split('');
for (var i = 0; i < array.length; i++) {
return this.moveRobotToOnePosition(i);
}
return true;
}
this.errorMessageNumber = 0;
}
}
So your problem is actually pretty simple, and my apologies for taking so long to figure this out. The issue is that you were passing the array index and not the array element.
moveRobot: function(string) {
string = string.toUpperCase();
if (this.checkCommandString(string)) {
var array = string.split('');
for (var i = 0; i < array.length; i++) {
// return this.moveRobotToOnePosition(i);
this.moveRobotToOnePosition(array[i]); // don't use return here unless you want to exit the function.
}
return true;
}
this.errorMessageNumber = 0;
}

How to stop executing Javascript function containing infinite loop after some time

Suppose I have following piece of code that contains an infinite loop:
function infiniteLoop() {
while(true) {
//do something, eg.
document.getElementById("someID").innerHTML = "Blah";
}
}
If we execute this code in an online compiler, browser will crash. I want to prevent that from happening. So I tried following code following this answer:
function willNotCrash() {
myVar = setInterval(infiniteLoop, 5000);
setTimeout(function(){
clearInterval(myVar);
}, 4000);
}
This code doesn't make the browser to crash, because I am stopping the execution before infiniteLoop() gets called by clearInterval(myVar).
My question is how do I stop executing such functions if they don't response within some period of time (eg. after 5 seconds or before the browser is crashed).
For example, if we copy paste following java code in https://www.compilejava.net/
public class HelloWorld {
public static void main(String[] args) {
while(true) {
System.out.println("Blah");
}
}
}
we get a nice output saying,
Script was taking longer than 5 seconds to execute so it was killed.
Here is my current code: http://js.do/code/106546
This is a bit tricky but perfectly doable. You need to tokenize the script and then rebuild it but insert a counter increment in every loop and function call. If the counter goes above some threshold, then bomb out. I did it here: https://littleminigames.com/
You can see the source at https://bitbucket.org/cskilbeck/littleminigames/src
The interesting bits are in wrapper.js (https://bitbucket.org/cskilbeck/littleminigames/src/ac29d0d0787abe93c75b88520050a6792c04d34d/public_html/static/js/wrapper.js?at=master&fileviewer=file-view-default)
Google escodegen, estraverse and esprima
I relied heavily on this: https://github.com/CodeCosmos/codecosmos/blob/master/www/js/sandbox.js
wrapper.js, as requested:
// Don't obfuscate this file! We depend on the toString() of functions!
// this was all nicked from https://github.com/CodeCosmos/codecosmos/blob/master/www/js/sandbox.js
(function(mainApp) {
'use strict';
var esprima = window.esprima,
estraverse = window.estraverse,
escodegen = window.escodegen,
errors = [],
eng,
Syntax = estraverse.Syntax;
// This implements the jankiest possible "source map", where we keep an array
// of [generatedLine, knownSourceLine]. Seems to essentially work.
function SourceNode(line, col, _sourceMap, generated) {
this.line = line;
this.col = col;
this.generated = generated;
}
SourceNode.prototype.toStringWithSourceMap = function toStringWithSourceMap() {
var code = [];
var mapLines = {};
var map = [];
// assumes that wrapCode adds two lines
var line = 3;
var lastMapLine = null;
function walk(node) {
if (typeof(node) === "string") {
if (node) {
code.push(node);
var matches = node.match(/\n/g);
if (matches !== null) {
line += matches.length;
}
}
} else if (node instanceof SourceNode) {
if (node.line !== null) {
if (!mapLines[line]) {
map.push([line, node.line]);
mapLines[line] = node.line;
}
}
walk(node.generated);
} else {
node.forEach(walk);
}
}
walk(this);
return {
code: code.join(''),
map: map
};
};
SourceNode.prototype.toString = function toString() {
return this.toStringWithSourceMap().code;
};
// This is used by escodegen
window.sourceMap = {
SourceNode: SourceNode
};
// TODO (chs): add in all the things that need to be masked
function runWrapper($userCode, __sys) {
var clear = __sys.clear,
setpixel = __sys.setpixel,
rectangle = __sys.rectangle,
box = __sys.box,
line = __sys.line,
getpixel = __sys.getpixel,
getpixeli = __sys.getpixeli,
keypress = __sys.keypress,
keyrelease = __sys.keyrelease,
keyheld = __sys.keyheld,
reset = __sys.reset;
__sys.userFunction = __sys.catchErrors($userCode);
}
function extractCode(fn) {
var code = fn.toString();
return code.substring(code.indexOf('{') + 1, code.lastIndexOf('}'));
}
function makeOneLine(code) {
return code.replace(/(\/\/[^\n]+|\n\s|\r\n\s*)/g, '');
}
var runTemplate = makeOneLine(extractCode(runWrapper));
function wrapCode(code, template, functionName, postCode) {
// avoid interpretation of the replacement string by using a fun.
// otherwise mo' $ mo problems.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter
return ("'use strict';" + template.replace(/\$userCode/, function() {
return 'function ' + functionName + '() {\n' + code + postCode + '\n}';
}));
}
var injectStatement = esprima.parse("if (++__sys.ctr >= __sys.maxctr) throw new Error('Script halted - infinite loop?');").body[0];
var injectElseStatement = esprima.parse("if (++__sys.ctr >= __sys.maxctr) throw new Error('Script halted - infinite loop?'); else ;").body[0];
function CallExpression(callee, args) {
this.callee = callee;
this.arguments = args;
}
CallExpression.prototype.type = Syntax.CallExpression;
function Identifier(name) {
this.name = name;
}
Identifier.prototype.type = Syntax.Identifier;
function BlockStatement(body) {
this.body = body;
}
BlockStatement.prototype.type = Syntax.BlockStatement;
function ReturnStatement(argument) {
this.argument = argument;
}
ReturnStatement.prototype.type = Syntax.ReturnStatement;
function FunctionExpression(id, params, body) {
this.id = id;
this.params = params;
this.body = body;
this.defaults = [];
this.expression = false;
this.generator = false;
this.rest = null;
}
FunctionExpression.prototype.type = Syntax.FunctionExpression;
function wrapId(node, defaultName) {
if (node.loc) {
var id = (node.id || {
name: null,
loc: null
});
var loc = id.loc || node.loc;
var name = id.name || defaultName;
return new Identifier(name + '$' + loc.start.line);
} else {
return node.id;
}
}
function instrumentAST(ast) {
var identifierStack = [];
function pushIdentifier(s) {
identifierStack[identifierStack.length - 1].push(s);
}
function popIdentifierStack() {
identifierStack.pop();
}
function pushIdentifierStack() {
identifierStack.push([]);
}
function peekLastIdentifier() {
var lastStackIdx = identifierStack.length - 1;
if (lastStackIdx >= 0) {
var stack = identifierStack[lastStackIdx];
if (stack.length) {
return stack[stack.length - 1];
}
}
return '';
}
pushIdentifierStack();
return estraverse.replace(ast, {
enter: function enterAST(node) {
switch (node.type) {
case Syntax.VariableDeclarator:
if (node.id.type === Syntax.Identifier) {
pushIdentifier(node.id.name);
}
break;
case Syntax.MemberExpression:
if (node.object.type === Syntax.Identifier) {
var id = node.object.name;
if (node.property.type === Syntax.Identifier) {
id += '__dot__' + node.property.name; // huh? why mangle these?
// console.log(id);
}
pushIdentifier(id);
} else if (node.property.type === Syntax.Identifier) {
pushIdentifier(node.property.name);
}
break;
case Syntax.FunctionDeclaration:
pushIdentifierStack();
break;
case Syntax.FunctionExpression:
pushIdentifierStack();
break;
default:
break;
}
return node;
},
leave: function leaveAST(node) {
switch (node.type) {
case Syntax.DoWhileStatement:
break;
case Syntax.ForStatement:
break;
case Syntax.FunctionDeclaration:
break;
case Syntax.FunctionExpression:
break;
case Syntax.WhileStatement:
break;
default:
return estraverse.SKIP;
}
// modify the BlockStatement in-place to inject the instruction counter
if(node.body.body === undefined) {
// they have used a non-block statement as the body of a function or loop construct
// not allowed for function declarations - should never get here
if(node.type === Syntax.FunctionDeclaration) {
errors.push({
message: "Missing {",
line: node.loc.start.line,
column: node.loc.start.column
});
}
else {
// otherwise insert the test
var newBody = angular.copy(injectElseStatement);
newBody.alternate = node.body;
node.body = newBody;
}
return estraverse.SKIP;
}
node.body.body.unshift(injectStatement);
if (node.type === Syntax.FunctionExpression) {
popIdentifierStack();
// __catchErrors(node)
node.id = wrapId(node, peekLastIdentifier());
return new CallExpression(
new Identifier("__sys.catchErrors"), [node]);
}
if (node.type === Syntax.FunctionDeclaration) {
popIdentifierStack();
// modify the BlockStatement in-place to be
// return __catchErrors(function id() { body });
var funBody = node.body;
node.body = new BlockStatement([
new ReturnStatement(
new CallExpression(
new CallExpression(
new Identifier("__sys.catchErrors"), [new FunctionExpression(
wrapId(node, peekLastIdentifier()), [],
funBody)]), []))
]);
}
return node;
}
});
}
// mainApp.sandbox('var a = 1; function update(frame) { clear(0); }').code
// give it the source code as a string
mainApp.sandbox = function(code) {
var rc = {};
this.errors = [];
try {
this.ast = instrumentAST(esprima.parse(code, { range: true, loc: true }));
this.map = escodegen.generate(this.ast, { sourceMap: true, sourceMapWithCode: true });
this.code = wrapCode(this.map.code, runTemplate, '', ';\n__sys.updateFunction = (typeof update === "function") ? update : null;');
}
catch(e) {
this.errors.push({
message: e.description,
line: e.lineNumber,
column: e.column
});
}
if(this.code) {
this.code = "eng.clientFunction = function(__sys) {" + this.code + "};";
}
};
mainApp.sandbox.prototype.searchMap = function(needle) {
// binary search
var lo = 0;
var hi = this.map.map.length;
var mid, here;
while (true) {
mid = lo + ((hi - lo) >> 1);
here = this.map.map[mid];
if (mid === lo || here[0] === needle) {
return here[1];
} else if (here[0] > needle) {
hi = mid;
} else {
lo = mid;
}
}
};
})(mainApp);
Typically all JavaScript runs in one thread, so it is impossible to run any JavaScript that could stop your loop while your loop is running. Using HTML5 web workers, you can run the infinite loop in a separate thread, and then you can terminate it:
var myWorker = new Worker( '/infinite.js ');
setTimeout( function ( ) {
myWorker.terminate( );
}, 5000 );
However your web worker won't have access to the DOM, so the contents of your infinite loop would need to be different that what you have in your question.
I found exactly what I was looking for in Bergi's comment,
Alternatively, place a if (Date.now() > dateAtStartOfExecution+5000) return; in every loop body.
So now my code looks like:
function infiniteLoop() {
dateAtStartOfExecution = Date.now();
while(true) {
//do something
document.getElementById("someID").innerHTML = "Blah";
if (Date.now() > dateAtStartOfExecution+5000) {
alert("Taking too much time. Killing.");
return;
}
}
}
If I run this code after 5 seconds I will get an alert and the execution will stop. Try this:
http://js.do/code/106565

Switch statement is returning no value

I have a test i'm writing which reads in a string and then takes that string and applies it to a switch statement. I then match the string to the case and set an integer value which I pass back to the spec page which then passes the int value to another test that I use for an if statement. I cannot get the int to pass so the if statement will not work properly.
The object for switch:
var appsNotPurchased = 0;
this.checksHomeSublevel = function(mmCode) {
browser.get('https://iplan-qa.meetingmatrix.com/Home/Index/' + mmCode);
marketingObjects.level.getText().then(function(text) {
var homeText = text;
browser.get('https://iplan-qa.meetingmatrix.com/Home/Apps/' + mmCode);
expect($('div.apps-subscription > span').getText()).toEqual('iPlan Level: ' + homeText);
switch (homeText) {
case 'Select':
console.log(homeText);
appsNotPurchased = 6;
return appsNotPurchased;
break;
case 'Content':
console.log(homeText);
appsNotPurchased = 0 || 1 || 2 || 3 || 4 || 5 || 6;
return appsNotPurchased;
break;
}
});
the testSpec describe function:
describe('should upload media: ', function() {
it('should select add media', function() {
var mmCode = "ACC0572";
var appsNotPurchased = appsObjects.checksHomeSublevel(mmCode);
appsObjects.checksSubLevelSelect(mmCode, appsNotPurchased);
});
});
The object I am passing the value to:
this.checksSubLevelSelect = function(mmCode, appsNotPurchased) {
//counts the apps
apps.count().then(function(count) {
expect(count).toEqual(7);
for (var i = 0; i < count; i++) {
if (appsPlace == appsNotPurchased) {
//does something here
} else {
//does something here
}
appsPlace++;
}
});
};
You should be returning an object instead of || statement. Also return statement should be written outside switch rather than inside it.
Simplest solution would be to use a global variable appsNotPurchased which stores the value and then you can use it in your test specs without returning. But that would be a poor coding standard.
Second solution would be to return a promise of the function as protractor executes asynchronously.
Here's an example of second solution -
this.checksHomeSublevel = function(mmCode) {
var getval = marketingObjects.level.getText().then(function(text) {
switch (homeText) {
case 'Select':
console.log(homeText);
appsNotPurchased = [6];
break;
case 'Content':
console.log(homeText);
appsNotPurchased = [0, 1, 2, 3, 4, 5, 6]; //either use array or object
break;
default:
console.log("Default");
}
return appsNotPurchased;
});
return protractor.promise.fulfilled(getval);
};
and then use it like a promise in your spec -
appsObjects.checksHomeSublevel(mmCode).then(function(appsNotPurchased){
appsObjects.checksSubLevelSelect(mmCode, appsNotPurchased);
});
Use above result in your function now -
this.checksSubLevelSelect = function(mmCode, appsNotPurchased) {
//counts the apps
apps.count().then(function(count) {
expect(count).toEqual(7);
for (var i = 0; i < count; i++) {
if (appsPlace == appsNotPurchased[i]) {
//does something here
} else {
//does something here
}
appsPlace++;
}
});
};
Hope it helps.

Categories

Resources