I have node.js installed and protractor installed. I have experience with selenium-webdriver but Protractor is driving me nuts!!! I am also not that familiar with javascript.
This is what my code looks like:
describe('My app', function() {
var result = element(by.id('result-name'));
var enterBtn = element(by.id('enter'));
var clearFieldBtn = element(by.id('clear-field');
it('should bring up components on load', function() {
browser.get(`http://localhost:${process.env.PORT}`);
browser.wait(until.titleContains('Sample App'), 500);
browser.wait(until.presenceOf(browser.element(by.id('my-test-app'))), 500);
expect(enterBtn).isPresent;
});
it('result should equal username', function () {
browser.get(`http://localhost:${process.env.PORT}`);
expect(clearFieldBtn).isPresent;
expect(result.getText()).toEqual('John Smith'); //both tests pass without this line of code
});
});
The last line "expect(result.getText()).toEqual('John Smith');" throws me an error. I get:
expect(...).toEqual is not a function
Any help would be much appreciated. I have spent a couple of hours trying to find a solution and trying different things.
I also wanted to implement the isPresent function how it's done in the api docs which is like this: expect($('.item').isPresent()).toBeTruthy();
I tried to do:
expect(clearFieldBtn).isPresent().toBeTruthy();
But I get that isPresent is not a function...
The expect above that line seems poor. It should read
expect(clearFieldBtn.isPresent()).toBeTruthy();
not sure if that is causing the weird error on the line below...just thought I would throw it out there. All your protractor APIs need be be called within the expect because isPresent is not a attribute of expect
Have you tried these lines:
clearFieldBtn.isPresent().then(function(bln) {
expect(bln).toBe(true);
});
result.getText().then(function(tmpText) {
expect(tmpText).toBe('John Smith');
});
If you still get an error on result.getText(), please check the presence of the result object.
Related
Hi working on a project at the moment and currently getting it to call the api, great! however I'm looking at refactoring my test files as there will be quite a few so initially this is how I've done it.
var chakram = require('chakram');
expect = chakram.expect;
var baseFixture = require('../../test/fixtures/');
it("Should return the matching test file", function () {
var response = chakram.get("http://testurl");
return expect(response).to.have.json(baseFixture + 'testfile.json')
});
However with the code above I'm getting this error.
Error: Cannot find module '../../../../test/fixtures'
If I put the json file into the variable at declared at the top with a call to base fixture within the function the test will pass.
Where am I going wrong?
Thanks in advance.
In my Protractor framework, I am using a POM model, so a lot of code resides in different .js files, which are then called into , at necessary junctions, to have the e2e tests.
I have a CompleteProfile.js file (dummy name), where I have a condition,
if profile_flag ===100,
then do nothing
else
complete profile (includes a lot of forms)
For the else portion, I have the code in a differentfillCustomerForms.js file, whose code is something like this
var completeprofile = function(){
this.locator = element(by.css('some_css_locator'));
this.locator.click();
browser.sleep(2000);
}
module.exports={
profileComplete1 = completeprofile
}
I'm using this from fillCustomerForms.js in my CompleteProfile.js as
var Profile = require('./fillCustomerForms.js');
var c_profile = new Profile.profileComplete1();
var compl_profile = function(){
this.someFunction= function(){
profile_flag = "90"
if profile_flag ==="100"{
then do nothing;
}else{
c_profile.completeprofile();
}
}
}
module.exports={
finalExp = compl_profile
}
Inside my spec.js, I am calling the CompleteProfile.js as
var Profile = require('./CompleteProfile.js');
var co_profile = new Profile.finalExp();
describe("Modules",()=>{
it('Modules that load other things',()=>{
//do other things neccessary
});
});
describe("Module",()=>{
it("should do something,"()=>{
co_profile.someFunction();
});
});
The first describe block is the one that loads the browser and checks for the URL and other test cases. My issue is when if I add the second describe block, then the URL that is sent in first describe block is rendered empty i.e. Chrome loads without any URL, and errors out due to timeout error. I have checked the code and it seems fine. What did I do wrong here.
I'm guessing this might have to do with some basics of JS, that I might have overlooked, but right now I'm not able to figure this one out.
You have a syntax error in your second testcase (the it function). Every callback of each testcase in Mocha requires to be resolved or rejected. e.g:
it('should ...', done => {
/* assertion */
done(/* passing a new instance of Error will reject the testcase*/);
});`.
The called function doesn't not return anything in the provided code snippet, I don't really see what you're trying to test for.
im running a rails app which im running Unit tests on the Javascript side (Using Teaspoon/Jasmine).
the funny thing is, on the function I call I KNOW Mustache.render function is working (Im able to console.log it's return value (which is the Mustache.render function) and see that it is working. However when I call that function from my unit tests im getting a:
Failure/Error: ReferenceError: Can't find variable: Mustache.
For reference I don't actually call the Mustache render function directly im simply calling the function that uses it and grabbing it's return value to check again.
I've been able to successfully grab and use various other functions and use them just fine, this one is just giving me trouble. Can the Mustache.render object not exist outside it's own file or scope or something?
Edit: Example code:
_makeSomething: function viewMakeSomething(data) {
const template = templates.something;
return Mustache.render(document.querySelector(template).innerHTML, data);
}
and my test code is simply:
it('_makeSomething object', function() {
let obj = {id: 1234, content: "_makeSomething Assertion", author: "Test User"}
let $something = _makeSomething(obj);
});
(Right now im just capturing it before I assert anything or split it up/etc...., but it's just calling it at all)
Problem is that you teaspoon doesn't have access to your dev/production assets pipelene. You should specify what JS to load for your tests. This is necessary to prevent loading all files from manifest to test some feature. Because this is unit testing.
From example:
//= require mustache
describe("My great feature", function() {
it("will change the world", function() {
expect(true).toBe(true);
expect(Mustache).toBeDefined();
});
});
I have another question (last question). At the moment i am working on a Node.js project and in this I have many console.log() functions. This has worked okay so far but I also want everything that's written to the console to also be written in a log-file. Can someone please help me?
For example:
Console.log('The value of array position [5] is '+ array[5]);
In my real code its a bit more but this should give you an idea.
Thank you hopefully.
Just run the script in your terminal like this...
node script-file.js > log-file.txt
This tells the shell to write the standard output of the command node script-file.js to your log file instead of the default, which is printing it to the console.
This is called redirection and its very powerful. Say you wanted to write all errors to a separate file...
node script-file.js >log-file.txt 2>error-file.txt
Now all console.log are written to log-file.txt and all console.error are written to error-file.txt
I would use a library instead of re-inventing the wheel. I looked for a log4j-type library on npm, and it came up with https://github.com/nomiddlename/log4js-node
if you want to log to the console and to a file:
var log4js = require('log4js');
log4js.configure({
appenders: [
{ type: 'console' },
{ type: 'file', filename: 'logs/cheese.log', category: 'cheese' }
]
});
now your code can create a new logger with
var logger = log4js.getLogger('cheese');
and use the logger in your code
logger.warn('Cheese is quite smelly.');
logger.info('Cheese is Gouda.');
logger.debug('Cheese is not a food.');
const fs = require('fs');
const myConsole = new console.Console(fs.createWriteStream('./output.txt'));
myConsole.log('hello world');
This will create an output file with all the output which can been triggered through console.log('hello world') inside the console.
This is the easiest way to convert the console.log() output into a text file.`
You could try overriding the built in console.log to do something different.
var originalLog = console.log;
console.log = function(str){
originalLog(str);
// Your extra code
}
However, this places the originalLog into the main scope, so you should try wrapping it in a function. This is called a closure, and you can read more about them here.
(function(){
var originalLog = console.log;
console.log = function(str){
originalLog(str);
// Your extra code
})();
To write files, see this stackoverflow question, and to override console.log even better than the way I showed, see this. Combining these two answers will get you the best possible solution.
Just write your own log function:
function log(message) {
console.log(message);
fs.writeFileSync(...);
}
Then replace all your existing calls to console.log() with log().
#activedecay's answer seems the way to go. However, as of april 30th 2018, I have had trouble with that specific model (node crashed due to the structure of the object passed on to .configure, which seems not to work in the latest version). In spite of that, I've managed to work around an updated solution thanks to nodejs debugging messages...
const myLoggers = require('log4js');
myLoggers.configure({
appenders: { mylogger: { type:"file", filename: "path_to_file/filename" } },
categories: { default: { appenders:["mylogger"], level:"ALL" } }
});
const logger = myLoggers.getLogger("default");
Now if you want to log to said file, you can do it just like activedecay showed you:
logger.warn('Cheese is quite smelly.');
logger.info('Cheese is Gouda.');
logger.debug('Cheese is not a food.');
This however, will not log anything to the console, and since I haven't figured out how to implement multiple appenders in one logger, you can still implement the good old console.log();
PD: I know that this is a somewhat old thread, and that OP's particular problem was already solved, but since I came here for the same purpose, I may as well leave my experience so as to help anyone visiting this thread in the future
Here is simple solution for file logging
#grdon/logger
const logger = require('#grdon/logger')({
defaultLogDirectory : __dirname + "/logs",
})
// ...
logger(someParams, 'logfile.txt')
logger(anotherParams, 'anotherLogFile.log')
So I've been trying to figure out how front end testing works (unit testing) but I am getting stuck on some point.
So I have my jasmine test set up as follows:
describe('Blabla', function () {
it('returns true', function () {
var people = require(["people"], function(ppl) {
return ppl;
});
expect(people.getTitle()).toBe('People piolmjage');
});
});
But running this gets me:
TypeError: undefined is not a funtion
So obviously, people is undefined. So perhaps my callback comes in too late. But if I remove the callback I get following error:
it('returns true', function () {
var people = require("people");
expect(people.getTitle()).toBe('People piolmjage');
});
Error: Module name "people" has not been loaded yet for context: _. Use require([])
I figure there is something wrong in my setup...Anyone have any idea how to get this FE testing to work?
I did manage to get it to work from console and using define combined with phantomjs and the durandal test files but I need this to work outside of the console and hereby I cannot use this define because the test runner won't find my tests.
That's why I need to use the CommonJS was of getting the required viewmodels.
people model
define([],
function () {
var getTitle = function() {
return "hello";
}
var peopleViewModel = {
title: 'People page',
getTitle: getTitle
};
return peopleViewModel;
});
UPDATE
I got the code working but not with resharper. Following this page from the durandal webpage.
But this gets me console output which is way to unstructured to actually read through.
I can however use the define keyword and then it works fine. So I assume it is the require keyword where I mess up something?
UPDATE 2
So I used fiddler to check what is going on. I also finally got it working (kinda...).
My testfile looks like this now:
///<reference path="../../Scripts/require.js"/>
///<reference path="../../test/lib/jasmine-2.1.3/jasmine.js"/>
///<reference path="../../App/viewmodels/people.js"/>
describe('Blabla', function () {
it('require test', function (done) {
require(['people'], function (people) {
expect(people.title).toBe('People page');
done();
});
});
});
And then I changed my people file:
define("people", ["bla"], function (bla) {
return {
title: 'People page',
bla: bla
};
});
As you can see here, I name my viewmodel to be people.
This works for the testrunner but he doesn't actually get any files through requireJS but only the reference paths. Also this does not fit my needs because the durandal models are unnamed.
Fiddler screenshot:
So basically he does not use requireJS to get the viewmodels and therefor I cannot just use the require.config initializer to get to my viewmodels folder and download every viewmodel using requireJS. Any thoughts?
I finally got it working, took me like a day and a half.
Anyway I don't use resharper anymore, or it's test runner to be more precise.
Chutzpah is the one I turned to in the end. This too took me some research but I got it to the point where it includes everything as I want it to.
Check this post for sure
Here is what I did:
My people.js looks like this:
define(['viewmodels/bla'], function (bla) {
return {
title: 'People page',
bla: bla //testing dependencies on other viewmodels
};
});
Then I also made a bla.js
define(function() {
return {
bla: "bla"
};
});
And now for the tests:
describe('Blabla', function () {
it('require test', function (done) {
require(['viewmodels/people'], function (people) {
expect(people.title).toBe('People page');
done();
});
});
it('dependency on require test', function (done) {
require(['viewmodels/people'], function (people) {
console.log(people.bla);
expect(people.bla.bla).toBe('bla');
done();
});
});
});
And then eventually, reading the answers on the link provided on top I had to create a Chutzpah config file to create a test harnass:
{
"Framework": "jasmine",
"TestHarnessReferenceMode": "AMD",
"TestHarnessLocationMode": "SettingsFileAdjacent",
"References" : [
{"Path" : "../Scripts/require.js" },
{"Path" : "requireConfig.js" }
],
"Tests" : [
{"Path": "specs"}
]
}
Now, running the tests with Visual studio test runner actually gets me everything I need and as you can see, I can now access all my viewmodels through require like so: require(['viewmodels/whateverviewmodel'], function(whateverviewmodel){....})
I hope this answer can get people on their way to testing your (Durandal)SPA using Jasmine and RequireJS.
I know my viewmodels in this answer, nor in the question itself, say much but this should get you an idea of how to go about all of this.
Small Edit
You can now also skip the callback mess with require([]... inside of the tests and build your tests like you do your viewmodels with define
define(['viewmodels/people'], function (people) {
describe('Blabla', function () {
it('require test', function () {
expect(people.title).toBe('People page');
});
it('dependency on require test', function () {
console.log(people.bla);
expect(people.bla.bla).toBe('bla');
});
});
});
This gets you less indents and is more readable in itself.
The require call provided by RequireJS is inherently asynchronous so you need to do something like this:
it('returns true', function (done) {
require(["people"], function(people) {
expect(people.getTitle()).toBe('People piolmjage');
done(); // Signal that the test is done.
});
});
The first attempt you show in your question cannot work. That's the classical "trying to return values synchronously form asynchronous code" mistake. The second attempt with require("people") does not work either because this require call is pseudo-synchronous and will work only if the module requested is already loaded. See this answer for an explanation of how this pseudo-synchronous require works.