Opa5: cannot read property "iLookAtTheScreen" of undefined - sapui5

So I'm writing my first test in Opa5 and I get this error, when I call the iLookAtTheScreen function to a page. I have a Worklist test to a page and a WorklistJourney which calls the test functions.
WorklistJourney:
QUnit.module("TabBar");
opaTest("Should see all the toolbar buttons", function (Given, When, Then) {
// Arrangements
Given.iStartMyApp();
//Actions
When.onTheWorklistPage.iLookAtTheScreen();
// Assertions
Then.onTheWorklistPage.theTabBarShouldHaveAllTheButtons().
and.iTeardownMyAppFrame();
});
}
Here when I call the iLookAtTheScreen() function it says that onTheWorklistPage is undefined. I do have an onTheWorklistPage segment in the Worklist.js file. I have no idea what's the problem.

Related

How to get the textarea element in the linter onUpdateLinting callback

TLDR: How can I get a reference to the textarea HTML element within the linting onUpdateLinting function.
Long version: CodeMirror has a lint option which allows the setting of a function to be called when linting is complete. I want to use this to update an HTML element to show the number of errors in the code in the codeMirror instance. Because my page might have multiple codeMirror instances - think of tabs with codeMirrors on them - my approach is to discover the textarea then from that get the appropriate display element to show the error count on the tab.
However, I cannot find how to get that textarea reference from within the onUpdateLinting function.
My onUpdateLinting function is:
lint: {
onUpdateLinting: function onUpdateLinting(annotationsNotSorted, annotations, cm) {
let errCnt = annotationsNotSorted.length;
console.log(errCnt + " errors");
let textArea = cm.getTextArea(); // << fails with cm.getTextArea is not a function
}
Which throws error 'cm.getTextArea is not a function'.
I note that if I use getTextArea when I am creating the codeMirror instance then that does not throw the error.
My conclusion is that the cm being passed into the onUpdateLinting callback is not the 'proper' codeMirror instance.
However, the codeMirror docs (screengrab below) days that the
I found that on the first callback of the onUpdateLinting the cm parameter is undefined. I guess what is happening is that the codeMirror instance is not yet defined to the linter when the linter fires up. The answer was then to check the cm reference before using it.
lint: {
onUpdateLinting: function onUpdateLinting(annotationsNotSorted, annotations, cm) {
let errCnt = annotationsNotSorted.length;
console.log(errCnt + " errors");
if (cm.getTextArea){
let textArea = cm.getTextArea();
// code to find and set the display element.
}
}
However, this left me with the situation that the error count was not updated when the codeMirror was first set up. The answer was to move the config of the lint option out of the config object and into a call to setOption, so the code became:
let myCodeMirror = CodeMirror.fromTextArea(myTextArea, {..setup options NOT including lint..})
myCodeMirror.setOption("lint", {
onUpdateLinting: function onUpdateLinting(annotationsNotSorted, annotations, cm) {
let errCnt = annotationsNotSorted.length;
console.log(errCnt + " errors");
if (cm.getTextArea){
let textArea = cm.getTextArea();
// code to find and set the display element.
}
},
esversion: 6,// use this instead of plain 'true' to allow ES6 code such as 'const' and 'let' to pass without erroneous complaints from linter.
undef: true, // linter config option
unused: true // linter config option
});
Summary - the codeMirror instance is instantiated without the lint option, then when the setOption() call is made for the lint, the linter runs causing the callback function to fire and I get the first-time-thru affect that I need to show any errors when the code is loaded.

Best practice for testing for data-testid in a nested component with React Testing Library?

I'm trying to write a test to check if my app is rendering correctly. On the initial page Ive added a data-testid of "start". So my top level test checks that the initial component has been rendered.
import React from "react";
import { render } from "react-testing-library";
import App from "../App";
test("App - Check the choose form is rendered", () => {
const wrapper = render(<App />);
const start = wrapper.getByTestId("start");
// console.log(start)
// start.debug();
});
If I console.log(start) the I can see all the properties of the node. However if I try and debug() then it errors saying it's not a function.
My test above does seem to work. If I change the getByTestId from start to anything else then it does error. But I'm not using the expect function so am I violating best practices?
There are two parts to this question -
Why console.log(start) works and why not start.debug()?
getByTestId returns an HTMLElement. When you use console.log(start), the HTMLElement details are logged. But an HTMLElement does not have debug function. Instead, react-testing-library provides you with a debug function when you use render to render a component. So instead of using start.debug(), you should use wrapper.debug().
Because you don't have an expect function, is it a good practice to write such tests ?
I am not sure about what could be a great answer to this, but I will tell the way I use it. There are two variants for getting an element using data-testid - getByTestId and queryByTestId. The difference is that getByTestId throws error if an element with the test id is not found whereas queryByTestId returns null in such case. This means that getByTestId in itself is an assertion for presence of element. So having another expect which checks if the element was found or not will be redundant in case you are using getByTestId. I would rather use queryByTestId if I am to assert the presence/absence of an element. Example below -
test("App - Check the "Submit" button is rendered", () => {
const { queryByTestId } = render(<App />)
expect(queryByTestId('submit')).toBeTruthy()
});
I would use getByTestId in such tests where I know that the element is present and we have expects for the element's properties (not on the element's presence/absence). Example below -
test("App - Check the "Submit" button is disabled by default", () => {
const { getByTestId } = render(<App />)
expect(getByTestId('submit')).toHaveClass('disabled')
});
In the above test, if getByTestId is not able to find the submit button, it fails by throwing an error, and does not execute the toHaveClass. Here we don't need to test for presence/absence of the element, as this test is concerned only with the "disabled" state of the button.

Protractor page object definition not working as expected

I apologize for the slightly vague title, I'm not sure how exactly to word this.
I have my Page Object which, with one exception, works perfectly. Here's the excerpt:
module.exports = function(){
this.facilityList = element(by.name('facility')).all(by.tagName('option'));
this.randomFacility = element(by.name('facility')).all(by.tagName('option')).count().then(function(numberOfItems) {
var rnum = parseInt(Math.random() * numberOfItems);
return rnum;
}).then(function(randomNumber) {
element(by.name('facility')).all(by.tagName('option')).get(randomNumber)
});
}
I can access and use facilityList just fine. But then I realized that I'm almost always doing the same thing to facilityList so why don't I just create another line to make it choose a random one. So I create randomFacility using the code from the main conf.js.
It didn't work. The error I see displayed is:
Failed: Error while waiting for Protractor to sync with the page: "both angularJS testability and angular testability are undefined. This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping. See http://git.io/v4gXM for details"
I'm confused. Is this saying I can't do all that processing in the page object to get the random one or do I simply have to manipulate facilityList in the conf.js and be done with it?
You nee to know the mechanism about how protractor to find element. Protractor only to start find element from page when protractor's action API be called, like getText(), click(), count() etc.
So when you define variable to represent certain element on page, when Nodejs execute this line, protractor won't to start find element from page:
// page object login.page.js
module.exports = function LoginPage(){
this.sumbitButton = element(by.css('#submit'));
this.countName = element.all(by.css('.username')).count();
}
// use page object in conf.js
var LoginPage = require('./login.page.js');
var loginPage = new Loginpage();
When Nodejs execute line var loginPage = new Loginpage();, all lines in function LoginPage will be executed.
When execute the first line, protractor not to find element from current open page,
When execute the second line, protractor will find element from current open page, But at this time point, protractor is possible to launching browser with a blank page, the target page have not been opened or navigated to.
To fix your problem, you need to define randomFacility as class's Method, rather than Property:
module.exports = function() {
this.facilityList = element(by.name('facility')).all(by.tagName('option'));
this.randomFacility = function() {
return element(by.name('facility'))
.all(by.tagName('option')).count()
.then(function(numberOfItems) {
console.log('count: '+numberOfItems);
var rnum = parseInt(Math.random() * numberOfItems);
console.log('random index: '+rnum);
return rnum;
})
.then(function(randomNumber) {
console.log('argument randomNumber: '+randomNumber);
return element(by.name('facility'))
.all(by.tagName('option')).get(randomNumber)
});
}
};
// how to use
pageObject.randomFacility().then(function(ele){
return ele.click();
});

Click on Leaflet map closes modal, click on marker opens modal

My Leaflet map has markers that open modals.
When a user clicks on the map, however, I would like for the modal to close. But the bit of code that makes that happen (below) interacts with the marker, and forces it to close as soon as it opens:
map.on('click', function(e) {
$('.modal').modal('hide'); });
I did get this to work—see the JSFiddle here: https://jsfiddle.net/askebos/Lh1y12uq/
But as you can see, the only reason it seems to be working is because it creates the following error:
Uncaught TypeError: e.preventDefault is not a function.
I imagine it's because the map.on('click'...) function is prevented from executing.
Any thoughts on how I can get to the same behaviour without the error?
The solution is to add an init() function that keeps track when a marker is clicked. Inspiration came from this question.
First, add the init() function to your code:
function init() {
init.called = true;
}
Then call the function when the marker is clicked:
function markerOnClick(e) {
init();
...
}
Make a function that fires when the map is clicked, but include an if/else statement that checks whether init.called has been set to true. If this is the case, reset init.called. If it has not been set to true, then the map was clicked elsewhere and any modals may close.
function mapClick () {
if(init.called) {
init.called = false;
}
else{
$('.modal').modal('hide');
}
}
Finally, bind the mapClick function to map clicks.
map.on('click', mapClick);
The function will no longer override marker clicks, and the error has been resolved as well. That still doesn't tell me why e.preventDefault caused an error, so any explanations would be welcome!
A working JSFiddle can be found here: https://jsfiddle.net/askebos/oesh59jr/

How to identify the ID or value of when the submit button is clicked

I am having trouble identifying the particular value or ID of a submit button after it has been clicked and submitted using AJAX.
If I place the following code as a global function, it properly alerts the value of the button clicked:
$(":submit").live('click', function() {
alert($(this).val());
})
However, when I attempt to define the variable, I am unable to use that variable from within the success callback function:
$(":submit").live('click', function() {
var whichButton = $(this).val();
})
...
$("#applicant-form").validate({
function(form) {
$(form).ajaxSubmit({
...
success: alert(whichButton);
I have also tried placing the code in the submitHandler, but that doesn't work either.
In a somewhat related post, a user had suggested I place the following code:
$("#accordion .edit").click(function(){
window.lastButtonClicked = this;
});
...
submitHandler: function(){
var index_origin = $(window.lastButtonClicked).attr("name");
}
But I was not able to get that to get the value of the button clicked (it said that the value was undefined).
Any suggestions?
UPDATE: It might help if I provide more information about why I need to know which button is pressed. I have two kinds of submit buttons for each form in a multi-part form. I would like to do different things based on which button was clicked.
$(":submit").live('click', function() {
var whichButton = $(this).val();
})
The scope of whichbutton is inside of this anonymous function; you can't access it from elsewhere. A quick fix might be to declare whichbutton as a global variable but there's probably very few cases where you should do that. More context as to what it is you're trying to do would help, right now it just looks like you're trying to alert the button text on success after an ajax form submit.