I have a slide-box described in one of my protractor tests; I can find the box and can get properties (i.e. 'how many') but how do I cycle through the boxes so I can test verify the display, e.g.
profilepage.slides.next()
expect(profilepage.slide.slideTitle = 'Credentials'
profilepage.slides.next()
expect(profilepage.slide.slideTitle = "Info"
etc.
Controller:
.controller('ProfileCtrl', function ($scope, ProfileService) {
$scope.data = {
numViewableSlides: 0,
slideIndex: 0,
initialInstruction: true,
secondInstruction: false, slides: [
{
'template': 'templates/slidebox/credentials.html',
'viewable': true
},
{
'template': 'templates/slidebox/contactinfo.html',
'viewable': true
},
{
'template': 'templates/slidebox/employeeinfo.html',
'viewable': true
},
{
'template': 'templates/slidebox/assignmentinfo.html',
'viewable': true
}
]
}
. . .
Template:
<ion-slide-box on-slide-changed="slideChanged(index)" show-pager="true">
<ion-slide ng-repeat="slide in data.slides | filter:{viewable : true}">
<div ng-include src="slide.template"></div>
</ion-slide>
</ion-slide-box>
Page Object:
profilepage.prototype = Object.create({}, {
backButton: {
get: function () {
return element(by.css('ion-ios7-arrow-back'));
}
},
slides: {
get: function () {
return element.all(by.repeater('slide in data.slides'));
}
},
slideTitle: {
get: function (id) {
element.all(by.repeater('slide in data.slides')).then(function (slidelist) {
var titleElement = slidelist[id].element(by.css('#slideName'));
return titleElement.getText();
});
}
},
. . .
Spec:
describe('Profile', function () {
var ppage = new profilepage();
beforeEach(function () {
browser.ignoreSynchronization = false;
});
it('should have correct lastname and have four slides on profile page', function () {
expect(browser.getCurrentUrl()).toEqual('http://localhost:8100/#/profile');
expect(ppage.lastname).toBe('Smith,');
expect(ppage.slides.count()).toEqual(4);
browser.sleep(1000);
});
it('should slide all the pages', function(){
expect(browser.getCurrentUrl()).toEqual('http://localhost:8100/#/profile');
// SLIDE EACH PAGE ABOUT HERE <------------
browser.sleep(1000);
})
The idea is to use ionic's $ionicSlideBoxDelegate from within the spec file. For that we'll need to make it accessible globally:
var addProtractorSlideBox, nextSlide;
addProtractorSlideBox = function() {
return browser.addMockModule("services", function() {
return angular.module("services").run(function($ionicSlideBoxDelegate) {
return window._$ionicSlideBoxDelegate = $ionicSlideBoxDelegate;
});
});
};
nextSlide = function() {
return browser.executeScript('_$ionicSlideBoxDelegate.next()');
};
...
beforeEach(function() {
...
addProtractorSlideBox();
...
});
it('...', function() {
...
nextSlide();
...
})
This pattern is very useful for other ionic/angular services.
Related
I've gotten this menu to work without filtering it, but now I'm doing an ajax request to filter out menu items the user isn't supposed to see, and I'm having some trouble to figure out how to set the resulting menu data, the line that is not working is commented below:
<script>
import { ref } from 'vue';
import axios from 'axios';
var currentSelected = 'device_access';
var menuData = [
{
text: 'Device Access',
id: 'device_access',
children: [
{
text: 'Interactive',
link: '/connection_center'
},{
text: 'Reservation',
link: '/reserve_probe'
}, {
text: 'Reservation Vue',
link: '/reservation.html'
}
]
}, {
text: 'Automation',
id: 'automation',
show: ['is_mxadmin', 'can_schedule_scripts'],
children: [
{
text: 'Builder',
link: '/builder',
},{
text: 'Execution Results',
link: '/test_suite_execution_results'
},
]
}
];
function hasMatch(props, list) {
var match = false;
for (var i=0; i < list.length && !match; i++) {
match = props[list[i]];
}
return match;
}
export default {
name: 'Header',
setup() {
const cursorPosition = ref('0px');
const cursorWidth = ref('0px');
const cursorVisible = ref('visible');
//the menu is zero length until I get the data:
const menu = ref([]);
return {
menu,
cursorPosition,
cursorWidth,
cursorVisible
}
},
created() {
let that = this;
axios.get('navigation_props')
.then(function(res) {
var data = res.data;
var result = [];
menuData.forEach(function(item) {
if (!item.show || hasMatch(data, item.show)) {
var children = [];
item.children.forEach(function (child) {
if (!child.show || hasMatch(data, child.show)) {
children.push({ text: child.text, link: child.link });
}
});
if (children.length > 0) {
result.push({ text: item.text,
children: children, lengthClass: "length_" + children.length });
}
}
});
//continues after comment
this is probably the only thing wrong, I've run this in the debugger and I'm getting the
correct data:
that.$refs.menu = result;
since the menu is not being rebuilt, then this fails:
//this.restoreCursor();
})
.catch(error => {
console.log(error)
// Manage errors if found any
});
},
this.$refs is for template refs, which are not the same as the refs from setup().
And the data fetching in created() should probably be moved to onMounted() in setup(), where the axios.get() callback sets menu.value with the results:
import { onMounted, ref } from 'vue'
export default {
setup() {
const menu = ref([])
onMounted(() => {
axios.get(/*...*/).then(res => {
const results = /* massage res.data */
menu.value = results
})
})
return {
menu
}
}
}
I finally figured out the problem.
This code above will probably work with:
that.menu = result;
You don't need: that.$refs.menu
You can't do it in setup because for some reason "that" is not yet defined.
In my working code I added a new method:
methods: {
setMenuData: function() {
this.menu = filterMenu();
},
}
And "this" is properly defined inside them.
i am using Protractor with Cucumber to test angular application, for reporting i am using "cucumber-html-reporter", i am not able to capture the screenshot in report and its not getting saved in the given folder as well
reporter.js
const reporter = require("cucumber-html-reporter");
cucumberReporteroptions = {
theme: "bootstrap",
//jsonFile: targetJson,
jsonDir: targetjsonDir,
output: htmlReports + "/cucumber_reporter"+datetime+".html",
reportSuiteAsScenarios: true,
storeScreenshots:true,
screenshotsDirectory:htmlReports +'/screenshots',
reportSuiteAsScenarios:true,
launchReport:true,
ignoreBadJsonFile:true
};
class Reporter {
static createHTMLReport() {
try {
reporter.generate(cucumberReporteroptions); //invoke cucumber-html-reporter
} catch (err) {
if (err) {
console.log("Failed to save cucumber test results to json file.");
console.log(err);
}
}
}
hooks.js
After(function(scenario) {
const attach = this.attach;
return browser.takeScreenshot().then(function(png) {
const decodedImage = new Buffer(png, "base64");
return attach(decodedImage, "image/png");
});
});
Quick checks that you can do from your side, to make sure reporter is invoked properly:
onPrepare: () => {
browser.ignoreSynchronization = true;
browser.manage().window().maximize();
Reporter.createDirectory(jsonReports);
},
cucumberOpts: {
compiler: "ts:ts-node/register",
format: "json:./reports/json/cucumber_report.json",
require: ["../../typeScript/stepdefinitions/*.js", "../../typeScript/support/*.js"],
strict: true,
},
onComplete: () => {
Reporter.createHTMLReport();
},
Can you try this,
defineSupportCode(({After}) => {
After(function(scenario) {
if (scenario.isFailed()) {
var attach = this.attach;
return browser.takeScreenshot().then(function(png) {
var decodedImage = new Buffer(png, "base64");
return attach(decodedImage, "image/png");
});
}
});
});
Lemme know how it goes!
I'm new to qunit + sinon.js, I want to write a unit test for function onMultiSelectPress, so I need to mock:
this.myController._oList
this.myController.getResourceBundle()
this.myController.getModel("masterView")
Right?
I'm stuck at get a stub for getModel("masterView"), any suggestion?
onInit : function () {
var oList = this.byId("list"),
oViewModel = this._createViewModel();
this._oList = oList;
this.setModel(oViewModel, "masterView");
},
_createViewModel : function() {
return new JSONModel({
isFilterBarVisible: false,
filterBarLabel: "",
delay: 0,
title: this.getResourceBundle().getText("masterTitleCount", [0]),
noDataText: this.getResourceBundle().getText("masterListNoDataText"),
sortBy: "Name",
groupBy: "None",
listMode: "SingleSelectMaster",
showDeleteButton: false
});
},
getModel : function (sName) {
return this.getView().getModel(sName);
},
onMultiSelectPress : function () {
var oMasterViewModel = this.getModel("masterView");
switch(this._oList.getMode()) {
case "MultiSelect":
oMasterViewModel.setProperty("/listMode", "SingleSelectMaster");
oMasterViewModel.setProperty("/showDeleteButton", false);
break;
case "SingleSelectMaster":
oMasterViewModel.setProperty("/listMode", "MultiSelect");
oMasterViewModel.setProperty("/showDeleteButton", true);
break;
}
},
Add a oViewStub in beforeEach, and set an empty JSON model using for testing.
QUnit.module("MasterController", {
beforeEach: function() {
this.oMasterController = new MasterController();
this.models = {};
var oViewStub = {
setModel: function(model, name) {
this.models[name] = model;
}.bind(this),
getModel: function(name) {
return this.models[name];
}.bind(this)
};
sinon.stub(Controller.prototype, "getView").returns(oViewStub);
},
afterEach: function() {
this.oMasterController.destroy();
jQuery.each(this.models, function(i, model) {
model.destroy();
});
Controller.prototype.getView.restore();
}
});
QUnit.test("test onMultiSelectPress() ", function(assert) {
var oMasterController = this.oMasterController;
var oModel = new JSONModel();
oMasterController.setModel(oModel, "masterView");
var oMasterViewModel = oMasterController.getModel("masterView");
oMasterController._oList = new sap.m.List();
sinon.stub(oMasterController._oList, "getMode").returns("MultiSelect");
oMasterController.onMultiSelectPress();
assert.strictEqual(oMasterViewModel.getProperty("/listMode"), "SingleSelectMaster", "Did change list mode to SingleSelectMaster");
assert.strictEqual(oMasterViewModel.getProperty("/showDeleteButton"), false, "Did hide the delete button");
oMasterController._oList.getMode.restore();
sinon.stub(oMasterController._oList, "getMode").returns("SingleSelectMaster");
oMasterController.onMultiSelectPress();
assert.strictEqual(oMasterViewModel.getProperty("/listMode"), "MultiSelect", "Did change list mode to MultiSelect");
assert.strictEqual(oMasterViewModel.getProperty("/showDeleteButton"), true, "Did show the delete button");
oMasterController._oList.destroy();
});
Can we show adMob ads for particular DIV in Android application?
If possible, Can you tell me how to implement?
install this plugin cordova plugin add https://github.com/floatinghotpot/cordova-plugin-admob.git
and past bellow code inside your controller
$(function () {
// alert('1');
if ((/(ipad|iphone|ipod|android|windows phone)/i.test(navigator.userAgent))) {
document.addEventListener('deviceready', initApp, false);
} else {
initApp()
// alert('2');
}
})
function initApp() {
// alert('3');
initAd()
// display the banner at startup
window.plugins.AdMob.createBannerView();
}
function initAd() {
// alert('4');
if (window.plugins && window.plugins.AdMob) {
var ad_units = {
ios: {
banner: 'ca-app-pub-6869992474017983/4806197152',
interstitial: 'ca-app-pub-6869992474017983/7563979554'
},
android: {
banner: 'ca-app-pub-6869992474017983/9375997553',
interstitial: 'ca-app-pub-6869992474017983/1657046752'
},
wp8: {
banner: 'ca-app-pub-6869992474017983/8878394753',
interstitial: 'ca-app-pub-6869992474017983/1355127956'
}
};
var admobid = "";
if (/(android)/i.test(navigator.userAgent)) {
admobid = ad_units.android;
} else if (/(iphone|ipad)/i.test(navigator.userAgent)) {
admobid = ad_units.ios;
} else {
admobid = ad_units.wp8;
}
window.plugins.AdMob.setOptions({
publisherId: admobid.banner,
interstitialAdId: admobid.interstitial,
bannerAtTop: false, // set to true, to put banner at top
overlap: false, // set to true, to allow banner overlap webview
offsetTopBar: false, // set to true to avoid ios7 status bar overlap
isTesting: true, // receiving test ad
autoShow: true // auto show interstitial ad when loaded
});
// alert('5');
registerAdEvents()
} else {
// alert( 'admob plugin not ready' );
}
}
// optional, in case respond to events
function registerAdEvents() {
document.addEventListener('onReceiveAd', function() {});
document.addEventListener('onFailedToReceiveAd', function(data) {});
document.addEventListener('onPresentAd', function() {});
document.addEventListener('onDismissAd', function() {});
document.addEventListener('onLeaveToAd', function() {});
document.addEventListener('onReceiveInterstitialAd', function() {});
document.addEventListener('onPresentInterstitialAd', function() {});
document.addEventListener('onDismissInterstitialAd', function() {});
// alert('6');
}
function onResize() {
// alert('7');
var msg = 'web view: ' + window.innerWidth + ' x ' + window.innerHeight;
document.getElementById('sizeinfo').innerHTML = msg;
}
// ADMob
})
I would like to use tinyMCE with a custom Slick Editor outside of the table, or inside a dialog. It's just to enable rich text editing.
Can I use this external plugin for a custom Slick Editor? I have not seen any example of usages like this.
Is there any potential problems using this two plugins at the same time (injecting conflicting HTML for example or preventing some firing events)?
Use a jquery alias "jQuery_new" with a compatible version
Register the new editor "TinyMCEEditor" & Add it into slick.editors.js
Use it like this {id: "column2", name: "Year", field: "year", editor: Slick.Editors.TinyMCE}
jQuery_new.extend(true, window, {
"Slick": {
"Editors": {
(..)
"TinyMCE": TinyMCEEditor
}
}});
function TinyMCEEditor(args) {
var $input, $wrapper;
var defaultValue;
var scope = this;
this.guid = function () {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4();
},
this.init = function () {
var $container = jQuery_new(".container");
var textAreaIdString = 'rich-editor-'+guid();
$wrapper = jQuery_new("<DIV ID='rds-wrapper'/>").appendTo($container);
$input = jQuery_new("<TEXTAREA id=" + textAreaIdString + "/>");
$input.appendTo($wrapper);
jQuery_new("#" +textAreaIdString).val( args.item[args.column.field] );
var _this = this;
tinymce.init({
selector: "#"+textAreaIdString,
forced_root_block : "",
plugins : "save image imagetools",
toolbar: 'undo redo | styleselect | bold italic | link image | save',
save_onsavecallback: function() {
jQuery_new("#" +textAreaIdString).val( this.getContent() );
_this.save();
}
});
$input.bind("keydown", this.handleKeyDown);
scope.position(args.position);
$input.focus().select();
};
this.handleKeyDown = function (e) {
if (e.which == jQuery_new.ui.keyCode.ENTER && e.ctrlKey) {
scope.save();
} else if (e.which == jQuery_new.ui.keyCode.ESCAPE) {
e.preventDefault();
scope.cancel();
} else if (e.which == jQuery_new.ui.keyCode.TAB && e.shiftKey) {
e.preventDefault();
args.grid.navigatePrev();
} else if (e.which == jQuery_new.ui.keyCode.TAB) {
e.preventDefault();
args.grid.navigateNext();
}
};
this.save = function () {
args.commitChanges();
};
this.cancel = function () {
$input.val(defaultValue);
args.cancelChanges();
};
this.hide = function () {
$wrapper.hide();
};
this.show = function () {
$wrapper.show();
};
this.position = function (position) {
};
this.destroy = function () {
$wrapper.remove();
};
this.focus = function () {
$input.focus();
};
this.loadValue = function (item) {
$input.val(defaultValue = item[args.column.field]);
$input.select();
};
this.serializeValue = function () {
return $input.val();
};
this.applyValue = function (item, state) {
item[args.column.field] = state;
};
this.isValueChanged = function () {
return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
};
this.validate = function () {
return {
valid: true,
msg: null
};
};
this.init();
}