Currently, I am trying to use page objects for an e2e tests to reduce the maintenance effort, and I was able to write something like this:
Test1- declare login page fields
var xxxx_Page_Mdemo = function () {
var companycode = element(by.id('company-code'));
var username = element(by.id('username'));
var password = element(by.id('password'));
var signclick = element(by.css('section>form>button'));
this.get = function () {
browser.get('https://xxxx.com');
};
this.setCompanycode = function (ccode) {
companycode.sendKeys(ccode);
};
this.setUsername = function (uname) {
username.sendKeys(uname);
};
this.setPassword = function (pasword) {
password.sendKeys(pasword);
};
this.setsignclick = function (signin) {
signclick.click(signin);
};
};
module.exports = new xxxx_Page_Mdemo();
Test2
var xxxxlogin_Page_Mdemo = require('./PageAdminuserlogsuper.js');
describe('xxlogin page', function () {
beforeEach(function () {
browser.waitForAngularEnabled(false);
});
afterEach(function () {
browser.executeScript('window.sessionStorage.clear();');
browser.executeScript('window.localStorage.clear();');
browser.restart();
});
it('should login to thexxx dashboard', function () {
login_Page_Mdemo.get();
var EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf($('#company-code')))
.then(function () {
login_Page_Mdemo.setCompanycode('cc90');
login_Page_Mdemo.setUsername('xxxx.com');
xxxx_Page_Mdemo.setPassword('pass');
xxxx_Page_Mdemo.setsignclick();
browser.wait(EC.urlContains('https://.xxx.com/#/xxx/index'), 100000).then(function () {
console.log('xxxx');
browser.sleep(4000);
});
});
});
});
From that I was able to login to a particular page,
and my question is I have to navigate to some other field inside the app after the login and perform some clicks on separate page. I have already created the same page objects for that and I can not link the login functions to that I got this error. Any comments?
at Module._compile (module.js:635:30)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
[09:25:28] E/launcher - Process exited with error code 100
Process finished with exit code 4
Empty test suite.
My conf file is something like this:
'./tests/MainObjects/PageAdminuserlogsuper.js',
'./tests/MainObjects/AdminuserlogPageobjectadopt.js',
'./tests/MainObjects/PageEmployeetemplatesuper.js',
'./tests/MainObjects/QE35CustomizeEmptemplate.js'
Here, I wrote a simple utilities class in Javascript that parses and stringify Json data.
//public/js/utilities.js
function UtilitiesClass(){
var parserJson = function(obj){
if (typeof(obj) !== "undefined") {
return JSON.parse(obj);
};
}
var stringifyJson = function(obj){
if (typeof(obj) !== "undefined") {
return JSON.stringify(obj);
};
}
}
module.exports = UtilitiesClass
Then in my test.js
require('../public/js/utilities.js');
describe('JS Utilities Classs Tests', function () {
var jsonObjToStr, strtojsonObj;
beforeEach(function () {
this.jsonObjToStr = [1, 2, 3, 4];
this.strtojsonObj = "[1, 2, 3, 4]";
});
it('should parse a string into JSON ', function () {
expect(parserJson(this.strtojsonObj)).to.not.be.undefined;
});
it('should stringify JSON into a string', function () {
expect(stringifyJson(this.jsonObjToStr)).to.not.be.undefined;
});
});
Then when I tried running mocha, I got the following error output.
andy#LINUXAWCM:~/Projects/Javascript/e-shop-gadgets$ mocha
JS Utilities Classs Tests
1) should parse a string into JSON
2) should stringify JSON into a string
0 passing (12ms)
2 failing
1) JS Utilities Classs Tests should parse a string into JSON :
ReferenceError: parserJson is not defined
at Context.<anonymous> (test/test.js:12:18)
2) JS Utilities Classs Tests should stringify JSON into a string:
ReferenceError: stringifyJson is not defined
at Context.<anonymous> (test/test.js:16:16)
Why wouldn't this simply work? The require statement on public/js/utilities.js comes out fine. But it's saying the parserJson and stringifyJson are not defined or found when really it's already loaded.
Isn't it?
Simply declaring a variable inside a function is not enough, you need to return these since they aren't available outside the function's scope.
You're also exporting a function and not calling it.
Also requiring a file doesn't magically make your variables available to your scope.
//public/js/utilities.js
function UtilitiesClass(){
var parserJson = function(obj){
if (typeof(obj) !== "undefined") {
return JSON.parse(obj);
};
}
var stringifyJson = function(obj){
if (typeof(obj) !== "undefined") {
return JSON.stringify(obj);
};
}
return {
parserJson: parserJson,
stringifyJson: stringifyJson
};
}
module.exports = UtilitiesClass;
var util = require('../public/js/utilities.js')();
util.parserJson(...) //etc
Though you probably don't need to export a function, just each method.
//public/js/utilities.js
var parserJson = function(obj){
if (typeof(obj) !== "undefined") {
return JSON.parse(obj);
};
}
var stringifyJson = function(obj){
if (typeof(obj) !== "undefined") {
return JSON.stringify(obj);
};
}
module.exports = {
parserJson: parserJson,
stringifyJson: stringifyJson
};
Then you'd use
var utils = require('../public/js/utilities.js');
I would like to use https://github.com/isaacs/readable-stream instead of core node.js stream module. However I would like other third-party modules to use it as well - is it possible to override core module at runtime?
For example I would like this code:
var stream = require('stream');
to return readable-stream library instead of core stream module.
You can use the following module (mock-require.js):
'use strict';
var Module = require('module');
var assert = require('assert');
var require = function require(path) {
assert(typeof(path) == 'string', 'path must be a string');
assert(path, 'missing path');
var _this = this;
var next = function() { return Module.prototype.require.next.apply(_this, arguments); };
console.log('mock-require: requiring <' + path + '> from <' + this.id + '>');
switch (path) {
case 'stream':
// replace module with other
if (/\/readable-stream\//.exec(this.filename)) {
// imports from within readable-stream resolve into original module
return next('stream');
} else {
return next('readable-stream');
}
case 'events':
// mock module completely
return {
EventEmitter: next('eventemitter2').EventEmitter2,
usingDomains: false
}
case 'hello/world :)':
// name can be anything as well
return { hello: 'world!' };
default:
// forward unrecognized modules to previous handler
console.log(path);
return next(path);
}
};
require.next = Module.prototype.require;
Module.prototype.require = require;
module.exports = {};
You need to require it once somewhere in your project, so require() is properly intercepted. You are also free to provide some flexible API to registering/unregistering mock modules (something like require.filter(/^foo\/\d+/, function(path) { return { boo: 'hoo' }; }); — I hadn't bothered with it yet.
Usage example then is as follows:
'use strict';
require('./mock-require');
require('util');
console.log(require('hello/world :)'));
console.log(require('events'));
console.log(require('stream'));
How would I require() a file if I had the file's contents as a string in memory, without writing it out to disk? Here's an example:
// Load the file as a string
var strFileContents = fs.readFileSync( "./myUnalteredModule.js", 'utf8' );
// Do some stuff to the files contents
strFileContents[532] = '6';
// Load it as a node module (how would I do this?)
var loadedModule = require( doMagic(strFileContents) );
function requireFromString(src, filename) {
var Module = module.constructor;
var m = new Module();
m._compile(src, filename);
return m.exports;
}
console.log(requireFromString('module.exports = { test: 1}', ''));
look at _compile, _extensions and _load in module.js
The question is already answered by Andrey, but I ran into a shortcoming that I had to solve and which might be of interest for others.
I wanted the module in the memorized string to be able to load other modules via require, but the module path was broken with the above solution (so e.g. needle wasn't found).
I tried to find an elegant solution to maintain the paths, by using some existing function but I ended up with hard wiring the paths:
function requireFromString(src, filename) {
var m = new module.constructor();
m.paths = module.paths;
m._compile(src, filename);
return m.exports;
}
var codeString = 'var needle = require(\'needle\');\n'
+ '[...]\n'
+ 'exports.myFunc = myFunc;';
var virtMod = requireFromString(codeString);
console.log('Available public functions: '+Object.keys(virtMod));
After that I was able to load all existing modules from the stringified module.
Any comments or better solutions highly appreciated!
The require-from-string package does the job.
Usage:
var requireFromString = require('require-from-string');
requireFromString('module.exports = 1');
//=> 1
After analyzing the source code of such solutions as pirates and require-from-string, I came to the conclusion that a simple mock of fs and Module methods would be no worse in terms of support. And in terms of functionality it will be better, because it supports #babel/register, pirates and other modules that changes the module loading process.
You can try this npm module require-from-memory
import fs from 'fs'
import BuiltinModule from 'module'
const Module = module.constructor.length > 1 ? module.constructor : BuiltinModule
function requireFromString(code, filename) {
if (!filename) {
filename = ''
}
if (typeof filename !== 'string') {
throw new Error(`filename must be a string: ${filename}`)
}
let buffer
function getBuffer() {
if (!buffer) {
buffer = Buffer.from(code, 'utf8')
}
return buffer
}
const now = new Date()
const nowMs = now.getTime()
const size = Buffer.byteLength(code, 'utf8')
const fileStat = {
size,
blksize : 4096,
blocks : Math.ceil(size / 4096),
atimeMs : nowMs,
mtimeMs : nowMs,
ctimeMs : nowMs,
birthtimeMs: nowMs,
atime : now,
mtime : now,
ctime : now,
birthtime : now
}
const resolveFilename = Module._resolveFilename
const readFileSync = fs.readFileSync
const statSync = fs.statSync
try {
Module._resolveFilename = () => {
Module._resolveFilename = resolveFilename
return filename
}
fs.readFileSync = (fname, options, ...other) => {
if (fname === filename) {
console.log(code)
return typeof options === 'string'
? code
: getBuffer()
}
console.log(code)
return readFileSync.apply(fs, [fname, options, ...other])
}
fs.statSync = (fname, ...other) => {
if (fname === filename) {
return fileStat
}
return statSync.apply(fs, [fname, ...other])
}
return require(filename)
} finally {
Module._resolveFilename = resolveFilename
fs.readFileSync = readFileSync
fs.statSync = statSync
}
}
Based on Andrey Sidorov & Dominic solutions, I was saddened by the fact of not being able to require a stringified module then I suggest this version *.
Code:
void function() {
'use strict';
const EXTENSIONS = ['.js', '.json', '.node'];
var Module,
path,
cache,
resolveFilename,
demethodize,
hasOwnProperty,
dirname,
parse,
resolve,
stringify,
virtual;
Module = require('module');
path = require('path');
cache = Module._cache;
resolveFilename = Module._resolveFilename;
dirname = path.dirname;
parse = path.parse;
resolve = path.resolve;
demethodize = Function.bind.bind(Function.call);
hasOwnProperty = demethodize(Object.prototype.hasOwnProperty);
Module._resolveFilename = function(request, parent) {
var filename;
// Pre-resolution
filename = resolve(parse(parent.filename).dir, request);
// Adding extension, if needed
if (EXTENSIONS.indexOf(parse(filename).ext) === -1) {
filename += '.js';
}
// If the module exists or is virtual, return the filename
if (virtual || hasOwnProperty(cache, filename)) {
return filename;
}
// Preserving the native behavior
return resolveFilename.apply(Module, arguments);
};
Module._register = function(request, parent, src) {
var filename,
module;
// Enabling virtual resolution
virtual = true;
filename = Module._resolveFilename(request, parent);
// Disabling virtual resolution
virtual = false;
// Conflicts management
if (hasOwnProperty(cache, filename)) {
error = new Error('Existing module "' + request + '"');
error.code = 'MODULE_EXISTS';
throw error;
}
// Module loading
cache[filename] = module = new Module(filename, parent);
module.filename = filename;
module.paths = Module._nodeModulePaths(dirname(filename));
module._compile(stringify(src), filename);
module.loaded = true;
return module;
};
stringify = function(src) {
// If src is a function, turning to IIFE src
return typeof src === 'function'
? 'void ' + src.toString() + '();'
: src;
};
}();
void function() {
var Module,
parentModule,
child;
Module = require('module');
// Creating a parent module from string
parentModule = Module._register('parent', process.mainModule, `
module.exports = {
name: module.filename,
getChild: function() {
return require('child');
}
};
`);
// Creating a child module from function
Module._register('child', parentModule, function() {
module.exports = {
name: module.filename,
getParent: function() {
return module.parent.exports;
}
};
});
child = require('child');
console.log(child === child.getParent().getChild());
}();
Usage:
void function() {
var Module,
parentModule,
child;
Module = require('module');
// Creating a parent module from string
parentModule = Module._register('parent', process.mainModule, `
module.exports = {
name: module.filename,
getChild: function() {
return require('child');
}
};
`);
// Creating a child module from function
Module._register('child', parentModule, function() {
module.exports = {
name: module.filename,
getParent: function() {
return module.parent.exports;
}
};
});
child = require('child');
console.log(child === child.getParent().getChild());
}();
* as you can see, it contains a function formater which provides a way to create some modules from functions.
I think the better way to approach this would be to have a parameter that you could set afterwards...
such as inside the file: myUnalteredModule.js
exports.setChanges = function( args )...
Then you could do:
var loadedModule = require( 'myUnalteredModule' );
loadedModule
I have a module "sitescollection" like this:
var site = require('./site'); // <- this should be stubbed
var sitesCollection = function(spec) {
var that = {};
that.sites = {};
that.findOrCreateById = function(id) {
if (typeof(that.sites[id]) == "undefined") {
that.sites[id] = site({id: id}); // <- its used here
}
return that.sites[id];
};
return that;
};
module.exports = sitesCollection;
so within sitescollection, site is a module that is not exported. But inside the code, i use it. Now i'm writing jasmine specs for #findOrCreateById().
I want to spec my the findOrCreateBy() function. But i want to stub the site() function, because the spec should be independent from the implementation. Where do i have to create the spyed method on?
var sitescollection = require('../../lib/sitescollection');
describe("#findOrCreateById", function() {
it("should return the site", function() {
var sites = sitescollection();
mysite = { id: "bla" };
// Here i want to stub the site() method inside the sitescollection module.
// spyOn(???,"site").andRetur(mysite);
expect(sites.findOrCreateById(mysite.id)).toEqual(mysite);
});
});
You can achieve this using https: //github.com/thlorenz/proxyquire
var proxyquire = require('proxyquire');
describe("#findOrCreateById", function() {
it("should return the site", function() {
// the path '../../lib/sitescollection' is relative to this test file
var sitesCollection = proxyquire('../../lib/sitescollection', {
// the path './site' is relative to sitescollection, it basically
// should be an exact match for the path passed to require in the
// file you want to test
'./site': function() {
console.log('fake version of "./site" is called');
}
});
// now call your sitesCollection, which is using your fake './site'
var sites = sitesCollection();
var mysite = {
id: "bla"
};
expect(sites.findOrCreateById(mysite.id)).toEqual(mysite);
});
});