Jasmine : Fixture could not be loaded - javascript

So i wanted to get into Test Driven Development and decided to use Jasmine on my project.
The thing is, i can't load fixtures.
The 2 solutions commonly proposed are :
Run chrome with --allow-file-access-from-files
Serve the file from you local server
So i used the first solution, but no result.
Then i set up the routes of my webserver so that localhost/fixture/my_fixture would return the content of my_fixture.html.
So when i manually access localhost/fixture/my_fixture, the content of the fixture is displayed on screen. But in my jasmine spec file, when i use :
jasmine.getFixtures().fixturesPath = 'http://localhost/fixture'
loadFixtures('quizz_fixture')
I get the following errors :
Error: Fixture could not be loaded: http://localhost/fixture/quizz_fixture
(status: error, message: Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'http://localhost/fixture/quizz_fixture?_=1455854875950'.)
When i use the URL given in the error, my browser displays the content of the fixture without errors.
Therefore, i don't understand the reason for this error. Does anyone have an insight?
Edit:
Web server : Apache
Browser : Chrome
OS : Windows 7
Edit 2
The issue comes from jasmine-jquery, on line 139 below, where the fail function is called. I can't figure out what's happening as the URL that supposedly can't be loaded actually loads just fine in my browser :
jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function (relativeUrl) {
var self = this
, url = this.makeFixtureUrl_(relativeUrl)
, htmlText = ''
, request = $.ajax({
async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
cache: false,
url: url,
dataType: 'html',
success: function (data, status, $xhr) {
htmlText = $xhr.responseText
}
}).fail(function ($xhr, status, err) {
throw new Error('Fixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + err.message + ')')
})
The result is :
Failed to load 'http://localhost/fixture/quizz_fixture.html?_=1456886216017'
Which works when called in the browser. I just don't get it.
Thanks.

It's really hard to answer without knowing at least a little about the nature of your server, or what the fixture looks like. Is the server just a simple file server like node-http-server, or is this pointing to your app? Is it serving the fixture correctly? Does your fixture have a mistake in it? I can't tell any of that from here.
What I would say though is that if you are just beginning TDD you should probably avoid fixtures entirely. One of the biggest challenges to somebody new to TDD is writing small enough tests, and Jasmine fixtures make it easy to write really big tests.
Instead I would recommend manually adding the bare minimum of DOM you need to the page and removing that in an after hook. jasmine-fixture is a tool that essentially does this. This'll force you to consider how much of the DOM you actually need to write a test, and will make the DOM changes you are making visible in the tests itself.

So i found a very unsatisfying solution, but a solution nonetheless.
To summarize
Using chrome, i tried to load jasmine fixture from a local file, which wouldn't work with chrome (this is something known, disabled for security reasons).
I tried using the chrome flag --allow-file-access-from-files but it didn't work. So i gave up on using a fixture from a local file.
I understood that the fixture file had to be served from my web server, which i did. But it didn't work either, because of some Ajax error related to the caching of fixtures. I tried updating my version of jquery (which was a bit old) but it didn't work. In the end, I wasn't able to understand what the issue was.
I downloaded firefox and tried executing the jasmine specRunner with the configuration of point 3 above (fixture served by web server) but again, it didn't work.
Using firefox, I reverted to the method in point 1, which is using a local fixture file, and it did work. I hate that solution, but i need to go forward, so that will do.
Conclusion
If stuck with that kind of issue, save yourself some time and use firefox which will allow the use of a local fixture file.

In the command line you can write:
start chrome --allow-file-access-from-files "path_to_test/SpecRunner.html"
That solved to me... hope can help some more people.

Related

How to write file in Google Chrome App without prompting?

I am fumbling around with the free Chrome Dev Editor on my Chromebook. I am trying to use the fileSystem to read and write .txt files. It is all very wrapped up, not at all like in C. I can no more tell if I am even allowed to do something, let alone where the proper place is to find out how.
I think the files I can see using the Files thingy are in the sandbox that I am allowed to play in (meaning, folders that are accessible by the app?) The root is called Downloads. Sure enough, if I use all the dot calls and callback arguments for the read, as in the examples at developer.chrome.com/apps/filesystem, it works. But I have to have a prompt
every time for both reads and writes.
A little more Googling came up with this trick: (I think it was here in stackoverflow, in fact) a chrome.runtime call, getPackagedDirectoryEntry, that seems to give me a handle to the folder of my app. Great! That's all I need to not have to go through the prompting. For the readfile, anyway.
But then trying to apply the same trick to the writefile did not work. In fact, it did nothing discernible. No errors, no complaints. Nothing. Even though the write file with prompting works fine (so presumably I have the permissions and Blob construction right.) What to do?
Here is my code:
function test(){
// Samsung 303C Chromebook - Chrome Dev Editor - /Downloads/Daily/main.js
// prompted write
chrome.fileSystem.chooseEntry({type:'saveFile'},function(a){
a.createWriter(function(b){
b.write(new Blob(["Programming fun"],{type:'text/plain'}));
},function(e){trace.innerText = 'error is ' + e;});
});
// unprompted read
chrome.runtime.getPackageDirectoryEntry(function(a){
a.getFile('text.txt',{},function(b){
b.file(function(c){
var d = new FileReader();
d.onloadend = function(){trace.innerText = this.result;};
d.readAsText(c);
});
});
});
// unprompted write - why not?
chrome.runtime.getPackageDirectoryEntry(function(a){
a.getFile('new.txt',{create:true},function(b){
b.createWriter(function(c){
c.write(new Blob(["Miss Manners fan"],{type:'text/plain'}));
},function(e){trace.innerText = 'error is ' + e;});
});
});
}
To be fair, Filesystem API is a big mess of callbacks and it's not unreasonable to get drowned in it.
It's not currently documented, but chrome.runtime.getPackageDirectoryEntry returns a read-only DirectoryEntry, and there is no way to make it writable (it's specifically blacklisted).
You probably don't see an error, because it fails at the getFile stage, for which you don't have an error handler.
Unfortunately, for a Chrome App the only option to write out to a real filesystem is to prompt the user. However, you can retain the entry and ask only once.
If you don't need to write out to the real filesystem but need only internal storage, HTML Filesystem API can help you (yes, it's marked as abandoned, but Chrome maintains it since chrome.fileSystem is built on it).
Extensions additionally have access to chrome.downloads API that enables writing to (but not reading) the Downloads folder.
P.S. What you see in Files app is your "real" local filesystem in ChromeOS + mounted cloud filesystems (e.g. Google Drive)
You can use the basic web Filesystem API. First, add the "unlimitedStorage" permission. Then, copy the packaged files to the sandboxed filesystem, like this:
chrome.runtime.getPackageDirectoryEntry(function(package) {
package.getMetadata(function(metadata) {
webkitRequestFileSystem(PERSISTENT, metadata.size, function(filesystem) {
package.copyTo(filesystem.root)
})
})
})

Rails page JS works in real browser / manual testing but not in PhantomJS & Selenium specs

In one of my Rails projects, I'm working on an interface to do CRUD operations on a resource (Commands) fully via AJAX (ie. no page reload needed). So there's a link to add a Command to the list, the user can click on any Command to edit its data then click Save to update via AJAX, and so forth. This last operation (clicking the Update button) is causing me trouble: it works perfectly in any browser I've tried, but when I follow the exact same steps in my Capybara specs (using either PhantomJS or Poltergeist driver) the specs fail right around that step.
I'm posting to ask for guidance re: how to move forward with this. I can get away with incomplete test coverage in this case, but it worries me to think that PhantomJS isn't executing all page javascript properly. (This app relies heavily on PhantomJS for unrelated reasons, so it's important for me to know how faithful its JS execution is.)
Does anyone know of any cases where PhantomJS executes Jquery AJAXy JS less-than-faithfully, and if so, what can be done about it?
Thanks in advance. Specifics and code snippets are below. Any ideas are appreciated.
Specifics
The offending JS
This is vanilla Jquery. Nothing too complicated.
// User clicks "Save" in a URL edit form to update that URL
$('.command .update_url').click(function(){
var command = $(this).parents('.command');
var command_path = command.attr('command_path');
var new_url = command.find('.url_field').val();
$.ajax({
type: 'PATCH',
url: command_path,
data: { command: { url: new_url }}, // <-- (Defines required param)
success: function(data){
if (data.success) {
// ... Close edit window & display cues that save is complete
} else {
alert("Unable to save changes. Please refresh the page.");
}
}
})
});
The spec
The following is a plain Rspec integration test that uses Capybara, FactoryGirl, and not much else.
#user = create :user
#site = create :site, user: #user
#command = create :command, site: #site, url: "http://example.com/123"
stub_login(#user) # a helper I wrote that stubs Devise #current_user etc.
visit site_path(#site)
first('.command .edit_link').click
within '.editing' do
fill_in 'url', with: "http://example.com/456"
click_button "Save" # <-- (This triggers the above listener)
# <-- (PhantomJS: Controller hits an error here)
end
# <-- (The spec fails before this point)
page.should have_css '.command .edit_link', text: "http://example.com/456"
page.should_not have_css '.url_field'
#command.reload.url.should eq "http://example.com/456"
The expected behavior
Again, this works perfectly in a real live browser. Which it should, because the above sort of ajax is extremely common and not particularly complicated.
When the button is clicked, the above JS listener is triggered. The listener gathers a couple variables, then sends a request to the Rails app to update that Command record with the URL provided.
When I open up my browser and follow the exact same steps as defined in the above Capybara spec, the controller sees the following parameters as expected:
Parameters: {
"command" => {"url"=>"http://example.com/456"},
"action" => "update",
"controller" => "commands",
"id" => "578"}
But the "command" param is absent when I execute the Capybara spec, which triggers the exact same JS code. That's the crux of the problem; see below.
The actual behavior
When I run the above example using the Poltergeist (PhantomJS) driver, the CommandsController raises an error because a required parameter (:command) wasn't present. But that parameter should be included in the PATCH request; see "Defines required param" in the JS above. Instead, the Rails controller receives the following params:
Parameters: {
"action" => "update",
"controller" => "commands",
"id" => "934"}
...which understandably triggers a ParameterMissing error:
1) Command pages user updates command URL
Failure/Error: Unable to find matching line from backtrace
ActionController::ParameterMissing:
param not found: command
# /Users/topher/.rvm/gems/ruby-2.0.0-p598/gems/actionpack-4.0.3/lib/action_controller/metal/strong_parameters.rb:173:in `require'
# ./app/controllers/commands_controller.rb:46:in `command_params'
# ./app/controllers/commands_controller.rb:14:in `update'
Note that, when I run the exact same steps manually in a browser, the controller receives additional parameters (see above) and therefore no error occurs.
Out of curiosity I installed selenium-webdriver and tried running the spec using that driver. When I ran the spec under Selenium, it hit an error even sooner, seemingly unrelated but equally confusing. I haven't dug into this one because I don't have much interest in Selenium, and the error makes my head hurt. Will post more if requested.
What's going on?
Any ideas as to what's happening here would be greatly appreciated. As I said above, I can skip test coverage on this AJAX update feature; I'm very confident in my Jquery (or at least I was...) and it won't be a dealbreaker if I can't figure this out. But I do care to get a feel for whether or not PhantomJS can be trusted with Javascript like this; if it can't, that would really reduce my confidence in the project.
Thanks in advance!
Update: as #Artjom B suggested, I upgraded to PhantomJS 2.0.0. It appears that this partially fixed the problem: running the specs now properly sends the AJAX request to the server, but it appears that the success function still doesn't execute (ie. the page HTML doesn't change). So at least this gets me to the point where I can do 80% tests of these features... good enough to set aside for now.

Can I/how can I translate a Selenium webdriver test script from node.js over to phantomjs - ghostdriver?

I recently began working with Selenium and to make life easier to start I was using node to run my scripts so that I could visually monitor the tests. My challenge now is to convert it so that it can be run as a headless test. Unfortunately, most of the resources that I have come across only address using phantomjs and ghostdriver with Java or Python. My boss wants me to run the test through phantomjs without Java or Python. Eventually these tests will be run remotely through a Linux VM on a server without a GUI. Currently I am testing using Mac OS X 10.8 and still have many bridges to cross in order to get to my goal.
My most important question firstly, is it possible to run a script from phantomjs through a port without the use of Java or Python? I have spent hours poring through as many resources as I could come across and I've come up with no solution.
If so, how can I properly initialize the test to run headless? Here is how I scripted the start of my functioning test. I want to properly switch the capabilities from firefox to phantomjs and be able to run it headless using the appropriate port. The rest of the test navigates to a specific site, logs in through a widget, then does further navigation to the area which I will build further tests on which to manipulate after I get this working.
var webdriver = require('selenium-webdriver'),
SeleniumServer = require('selenium-webdriver/remote').SeleniumServer;
var server = new SeleniumServer("Path/selenium-server-standalone-2.39.0.jar", {
port: 8910
});
server.start();
var driver = new webdriver.Builder().
usingServer(server.address()).
withCapabilities(webdriver.Capabilities.firefox()).
build();
The test works perfectly, but I am new to this so there might be something foolish that I am overlooking. Please let me know what adjustments to make so that it will run headless through phantom. When I attempt to use node to run the script after switching capabilities to phantomjs it produces
"/Selenium/node_modules/selenium-webdriver/phantomjs.js:22
LogLevel = webdriver.logging.LevelName,
^
TypeError: Cannot read property 'LevelName' of undefined
at Object.<anonymous> (/Selenium/node_modules/selenium-webdriver/phantomjs.js:22:33)
That's a read only file that I can't adjust, any attempts that I made to define "LogLevel" or "LevelName" to the appropriate corresponding value (DEBUG, etc.) were fruitless.
And if I run it through phantomjs itself I get -
"Error: Cannot find module 'path'
phantomjs://bootstrap.js:289
phantomjs://bootstrap.js:254 in require"
(It also lists module 'http') -- (and various undefined function errors)
I feel that with that instance I didn't properly organize where the files for Selenium, phantomjs, and ghostdriver should go in order to play nice. I also removed the server setup portion and instead ran this first, then the script separately.
phantomjs --webdriver=8910
But it yielded the same result. All of my research to fix these issues turned up instructions for Java and Python but not Javascript by itself. Rather than chase through many rabbit holes I figured it wise to consult better minds.
If you know better than I do and that it is fruitless to attempt this without Java or Python, please let me know. If you know where the issue lies within my script and could propose a fix please let me know. I hope that I have properly described the nature of my issue and if you need more information I will do my best to provide it to you.
This is my second week working with Javascript so if you believe I am making a noob error you very well may be correct. Please, keep in mind that the script works through node with selenium webdriver.
Many thanks for your time!!!
~Isaac
This was a bit tricky but here is the solution I've pieced together:
var webdriver = require('selenium-webdriver'),
SeleniumServer = require('selenium-webdriver/remote').SeleniumServer,
server = new SeleniumServer('/path/to/selenium/selenium-server-standalone-2.41.0.jar', {
port: 4444
}),
capabilities = webdriver.Capabilities.phantomjs();
capabilities.set('phantomjs.binary.path', 'path/to/phantom/bin/phantomjs');
var promise = server.start().then(function() {
var client = new webdriver.Builder().
usingServer(server.address()).withCapabilities(
capabilities
).build();
return {
'client': client,
'server': server
};
}, function(err) {
console.log('error starting server', err);
});
You can then use the promise with selenium's mocha-compatible test framework to hold the test till the server has started.
I found the documentation really helpful once i figured out the navigation is on the far right of the page. Here's the URL: http://selenium.googlecode.com/git/docs/api/javascript/module_selenium-webdriver.html
Then you'll be stuck where I am. Getting selenium-webdriver to quiet down.

Log JavaScript console into a log file with Firefox

We have a web application which runs in a kiosk mode Firefox, using the RKiosk extension to achieve this. We suspect that we have a very rare error in the system which yields in a JavaScript error. However because we can't access the JavaScript console we can't examine the log.
I'm searching for an option to make Firefox log all JavaScript console messages into a file regardless of the tab and page opened. I can't seem to find any extension for this. I'm already using log4javascript which sends errors back to the server, but it seems that our application crashes in a way that it skips the logging altogether.
Writing to a file sounds like a tedious task to me. It requires privileges that browser code doesn't normally have and you'd have to negotiate with an add-on you'd have to write in order to access file I/O.
From what I understand your issue is
I'd like to make Firefox log all errors
There are several approaches we can do to tackle this
First approach - log everything to localStorage too:
Now, rather than writing to an actual file, you can write to localStorage or IndexedDB instead.
localStorage["myApplog"] = localStorage["myApplog"] || "";
var oldLog = console.log;
console.log = function(){
oldLog.apply(console,arguments); // use the old console log
var message = "\n "+(new Date).toISOString() + " :: "+
Array.prototype.join.call(arguments," , "); // the arguments
localStorage["myApplog"] += message;
}
This is rather dirty and rather slow, but it should get the job done and you can access the log later in local storage. LocalStorage has a ~5MB limit if I recall correctly which I think is enough if you don't go crazy with logging. You can also run it selectively.
Second approach - log only errors
This is similar to what Pumbaa80 suggested. You can simply override window.onerror and only log errors.
// put an empty string in loggedWinErrors first
var oldError = window.onerror || function(){};
window.onerror = function(err,url,lineNumber){
oldError.call(this,err,url,lineNumber);
var err ="\n Error: (file: " + url+", error: "+err+", lineNumber: "+lineNumber+")");
localStorage["loggedWinErrors"] += err;
}
Third and drastic approach - use a VM.
This is the most powerful version, but it provides the most problematic user experience. You run the kiosk in a virtual machine, you detect an uncaught exception - when you do you freeze the machine and save its state, and run a backup VM instead. I've only had to do this when tackling the most fearsome errors and it's not pretty. Unless you really want the whole captured state - don't do this.
Really, do the extension before this - this is tedious but it gets very solid results.
In conclusion, I think the first approach or even just the second one are more than enough for what you need. localStorage is an abstracted storage that web pages get for saving state without security issues. If that's not big enough we can talk about an IndexedDB solution.
It all really depends on the use case you have.
You can use XULRunner...a Mozilla runtime environment for XUL applications. It uses Gecko like Firefox and:
You can access the file system or using the SQLite database to store logs.
You can render your kiosk in fullscreen mode without using extensions.
Have you tried jserrorcollector? We are using it and it works fine (only in Firefox). It's only for Java.
// Initialize
FirefoxProfile ffProfile = null;
ffProfile = new FirefoxProfile();
JavaScriptError.addExtension(ffProfile);
// Get the errors
List<JavaScriptError> jsErrors = JavaScriptError.readErrors(webDriver);
More information: https://github.com/mguillem/JSErrorCollector
Have you considered remote logging?
I commonly assign window.onerror to do send a request to a webserver storing the details of the error remotely. You could do the same with console.log if you preferred.
Try the following console export. It is a plugin for Firebug of Firefox. It's quite handy.
http://www.softwareishard.com/blog/consoleexport/
If you are able/willing to switch from Firefox to Chrome or Opera you would be able to use the Sandboxed Filesystem API to write a local file. See:
http://www.html5rocks.com/en/tutorials/file/filesystem/
http://caniuse.com/filesystem
Start in kiosk mode using chrome.exe --kiosk <url>
You would then want to disable Alt-F4 and Ctrl-Alt-Del which on Windows can be done with several third-party tools like Auto Hotkey (Disable Ctrl-Alt-Del Script).
You could use a remote logging script like Qbaka. It catches every JS error and sends it to the Qbaka server. There you can login and see all JS errors. Qbaka stores the exact error message, the script, line number, stack trace and the used browser for each error message.

Hosting phono (jquery softphone plugin) dependencies locally?

This may be too obscure a question, but perhaps someone can spot what I'm doing wrong.
Phono (jquery plugin for javascript/flash-based softphone built on top of Tropo/Voxeo) loads a couple of dependencies from the phono.com servers. Namely,
flensed.js
checkplayer.js
swfobject.js
phono.audio.swf
I would very much like to avoid loading these dependencies from an external server (for obvious reasons) and going by this thread on their forums (which I can't register for because it appears every possible username has been "taken") , it should be possible to host them locally.
Here's a prettified source for the main jquery plugin. Maybe I'm just bad at looking, but I could not find a commented, un-minified version either in their full SDK or on github.
So after changing
base_path: "http://s.phono.com/deps/flensed/1.0/"
and
swf: "http://s.phono.com/releases/" + Phono.version + "/plugins/audio/phono.audio.swf"
... all dependencies seem to load just fine, phono successfully grabs a session ID and chats by SIP appear to be working. When I try to dial out or call the session id/SIP, however, I get a javascript error:
Uncaught TypeError: Cannot call method 'start' of null
referring to line 770 : h.start().
this.$flash.play(g, j); appears to return null or undefined. I suck at javascript and can't figure out why.
EDIT - if anyone would be so adventurous as to try this out, you can just grab their "kitchen sink" demo and slap it up on a server without much hassle.
Okay -- this is ridiculous and I'm an idiot for not catching it sooner.
Flash was trying to load the ringtones off my server at the URL that requires authentication. Unfortunately, flash is not a user with a valid session. Hence, flash was grabbing big handful of nothing. Sorry.
You can download the PhonoSDK and all of the samples (including the kitchen sink demo) and run it on your localhost. Here's the link: http://s.phono.com/releases/PhonoSDK-0.2.zip. It's open source, do you can also fork/contribute to the project as well - https://github.com/phono
I just tried it using Apache on my localhost it worked without editing anything.

Categories

Resources