I'm running some e2e tests on an Angular2 app. One test involves clicking a button to open a Bootstrap modal. Even though I simulate the click of the button in my e2e test, it seems I cannot access the modal.
I'm currently just trying to run a simple test to click the button, open the modal, and check the text in an h4 element within the modal.
app.po.ts:
import { browser, element, by } from 'protractor';
export class SolarUi4Page {
navigateTo() {
return browser.get('http://localhost:4200/');
}
getAddButton() {
return element(by.css('.icon-plus'));
}
//2nd and 3rd lines attempt to do the same thing. Neither work
getH4() {
//return element(by.css('main-page')).element(by.id('data')).getText();
//return element(by.css('add-validation')).element(by.tagName('h4')).getText();
return element(by.css('h4')).getText();
}
}
app.e2e-spec.ts:
import { SolarUi4Page } from './app.po';
describe('solar-ui4 main page', function() {
let page: SolarUi4Page;
beforeEach(() => {
page = new SolarUi4Page();
});
it('should add new value to array/table and display it', () => {
page.navigateTo();
let addButton = page.getAddButton();
addButton.click();
expect(page.getH4()).toEqual('Add Data Point');
});
});
app.component.html (contains three custom components):
<main-page></main-page>
<add-validation></add-validation>
<delete-validation></delete-validation>
I am able to access any element inside the main-page component via syntax like the first commented out line in getH4() method. It seems I cannot access anything from the add-validation element, which is my Bootstrap modal. I'm assuming it is because that HTML is not present on the page on load, but shouldn't addButton.click(); trigger the modal to open so it IS present?
You might need to wait for the popup to be visible via browser.wait():
var EC = protractor.ExpectedConditions;
var elm = element(by.css('h4'));
browser.wait(EC.visibilityOf(elm), 5000);
expect(elm.getText()).toEqual('Add Data Point');
Related
I have a multiple charts in my page and I'm trying to make a delete call but some reason my chart UI is not updating immediately when I click the delete button. I always need to refresh the browser in order to see the changes.
I uploaded the full code for this two component her https://stackblitz.com/edit/angular-ivy-nnun96 so I would be really appreciated if I can get any suggestion on how to make the UI remove the Chart immediately when the user press Delete button.
Mc Chart List TS
deleteChart(){
this.chartService.deleteChart(this.chart.guid).subscribe((deleted) => {
console.log(deleted);
});
}
Mc Chart List HTML
<button mat-menu-item (click) = "deleteChart()" *ngIf = "chart.hasAccess && chart.canEdit && !chart.isPublished">Delete Chart</button>
Parent HTML
<mc-chart-list [chart]="chart" [editMode]="true" [wsType]="workspace.type"></mc-chart-list>
Parent TS
ngOnInit(): void {
this.charts = this.workspace.charts;
}
It look like this right now
You can use ChangeDetectorRef to detect changes on the view.
import {ChangeDetectorRef} from '#angular/core';
constructor(private ref: ChangeDetectorRef)
deleteChart(){
this.chartService.deleteChart(this.chart.guid).subscribe((deleted) => {
console.log(deleted);
this.ref.detectChanges();
});
}
Note: Remove changeDetection: ChangeDetectionStrategy.OnPush (if you are using it)
I tried global event listeners pane in Chrome DevTools, I tried to put a debugger; inside document/window.addEventListener("unload", ...) and it is not working.
I tried to step over the statements in the file main.ts and nothing is breaking the code in there when I click on a link that should open another page than the one it is opening. I checked its HTML attributes and the correct URL is set in its href attribute. The link has a single class which is not used to open another page in the page's code as far as I know.
I also searched for all the places in my code where the (window.)location is changed.
I also updated npm packages using npm update.
I use KnockOut.js and I have this static HTML for the links that go to wrong pages:
<ul class="main-nav" data-bind="foreach: mainMenuItems">
<li>
<a data-bind="attr: { href: url, title: text }, text: text, css: { active: $data == $root.activeMenuItem() }"></a>
<div class="bg"></div>
</li>
</ul>
And this is a part of the TypeScript code (sorry for the ugly code, it is WIP):
let vm = new PageViewModel(null, "home", () => {
sammyApp = $.sammy(function () {
// big article URLs w/ date and slug
this.get(/\/(.+)\/(.+)\/(.+)\/(.+)\/(.*)[\/]?/, function() {
vm.language("ro");
vm.isShowingPage(false);
vm.isShowingHomePage(false);
let slug : string = this.params['splat'][3];
vm.slug(slug);
console.log('logging', { language: vm.language(), slug: vm.slug() });
vm.fetch();
vm.isShowingContactPage(false);
vm.activeMenuItem(vm.getMenuItemBySlug(slug));
});
// any other page
this.get(/\/ro\/(.+)\//, function () {
console.log('pseudo-navigating to /ro/etc.');
vm.language("ro");
vm.isShowingPage(true);
vm.isShowingHomePage(false);
let slug : string = this.params["splat"][0];
//slug = slug.substr(0, slug.length - 1);
if (slug !== 'contact') { // this page is in the default HTML, just hidden
vm.slug(slug);
vm.fetch();
vm.isShowingContactPage(false);
} else {
vm.isShowingContactPage(true);
window.scrollTo(0, 0);
}
vm.activeMenuItem(vm.getMenuItemBySlug(slug));
});
this.get(/\/en\/(.+)\//, function () {
console.log('pseudo-navigating to /en/etc.');
vm.language("en");
vm.isShowingPage(true);
vm.isShowingHomePage(false);
let slug : string = this.params["splat"][0];
//slug = slug.substr(0, slug.length - 1);
if (slug !== 'contact') { // this page is in the default HTML, just hidden
vm.slug(slug);
vm.fetch();
vm.isShowingContactPage(false);
} else {
vm.isShowingContactPage(true);
, () => {
uuuuucons
}9 function
window.scrollTo(0, 0);
}
vm.activeMenuItem(vm.getMenuItemBySlug(slug));
});
// the home page
this.get("/", function () {
console.log(`pseudo-navigating to /${vm.language()}/home`);
sammyApp.setLocation(`/${vm.language()}/home`);
});
});
sammyApp.run();
});
I have this code that catches the click event:
$("a").on("click", () => {
debugger;
});
But after this finding I do not know what I can do to find the source of the problem.
When the click is catched by the 3 LOCs above, I get this:
What could be the issue?
Thank you.
Update 1
After seeing these questions and their answers (the only thing I did not try was using an iframe):
How can I find the place in my code or page where the location is set?
Breakpoint right before page refresh?
Break javascript before an inline javascript redirect in Chrome
If I have a page for which I check the beforeunload and unload event checkboxes in the Event Listener Breakpoints pane in Chrome DevTools' tab Sources, and I click on a link which should not reload the page but it does, and the two breakpoints (beforeunload and unload) are not triggered in this process, what should I do next?
Is this a known bug? If so, can someone give me an URL?
Thank you.
The manual solutions for Auto Reloading the HTML page of a specific component:
Either by navigating to the HTML page on click.
Or calling the ngOnInit() of that component on click.
I am doing it manually using a click event from the HTML code as follows:
HTML Code: app.component.html
<button (click) = reloadPage()>
TS Code: app.component.ts
reloadPage() {
// Solution 1:
this.router.navigate('localhost:4200/new');
// Solution 2:
this.ngOnInit();
}
But I need to achieve this automatically. I hope I am clear. The page should auto-reload after some specific interval and call the ngOnInit() on each interval.
Add correct call to setInterval anywhere in your call:
setInterval(() => reloadPage(), 150000); and inside the method reloadPage put the same logic you have for the button.
An example:
Just put the reloadPage function call inside the constructor:
export class SomeComponent {
constructor() {
setInterval(() => this.reloadPage(), 150000);
}
reloadPage() {
// anything your button doeas
}
}
also note, that correct call of setInterval would be:
setInterval(() => this.reloadPage(), 150000);
Note: My answer just fixes the code you presented. But it seems there is some bigger logical misunderstanding of "reloading page" in angular and using ngOnInit
I used .open() to create a tab displaying the HTML in data/search.html and attached data/search.js as a content script file.
var tabs = require("sdk/tabs");
var data = require("sdk/self").data;
function executeSearch () {
/* set up search tab */
tabs.open({
url: data.url("search.html"),
onReady: function (tab) {
var worker = tab.attach({
contentScriptFile: data.url("search.js")
});
worker.port.on("searchtext", function (wordsJson) {
worker.port.emit("matchingPages", JSON.stringify(hlutils.matchingPages(wordsJson)));
});
}
});
}
The HTML displays correctly and the content script runs properly, but in the HTML file (which is in valid HTML5) the autofocus property of an input element is not honored. Basically there is no cursor in the page as displayed, and no input can be made without clicking into the input element. I tried doing it the old-fashioned way by using
document.getElementById("search").focus();
in the content script file, and also in a script element in the HTML file (below the referenced element), all to no avail.
Finally figured it out. Had to add the following to the content script file:
window.addEventListener("load", function (event) {
document.getElementById("search").focus();
});
I have a typical primefaces dialog and it works great but I can't find any options to have it close when someone clicks outside the dialog. I have seen a few jquery examples and I'm guessing I can adapt those for the primefaces dialog but first wanted to make sure there wasn't a solution already?
Thanks.
Just sharing my solution that works globally for any modal dialog. Code adapted from http://blog.hatemalimam.com/get-widgetvar-by-id/ .
When you show a dialog, a mask (that has the .ui-dialog-mask class) is created, and it has the id of the opened dialog, appended with a "_modal" keyword.
This scripts gets that id when that mask is clicked, removes that appended text, and finds the corresponding widget to be closed.
To use it, just save the code on a .js file, import on your page and it will work.
Tested on Primefaces 6.0.
/**
* Listener to trigger modal close, when clicked on dialog mask.
*/
$(document).ready(function(){
$("body").on("click",'.ui-dialog-mask',function () {
idModal = this.id;
idModal = idModal.replace("_modal","");
getWidgetVarById(idModal).hide();
})
});
/**
* Returns the PrimefacesWidget from ID
* #param id
* #returns {*}
*/
function getWidgetVarById(id) {
for (var propertyName in PrimeFaces.widgets) {
var widget = PrimeFaces.widgets[propertyName];
if (widget && widget.id === id) {
return widget;
}
}
}
You can write a javascript function for onClick event and close the dialog.
<h:body onclick="closeDialog();">
function closeDialog(){
widgetWarDialog.hide();
}
I have an other solution for a "modal" primefaces dialog.
I just want to add the click event, when my button is clicked to open the Dialog. And not allways when i click anything on the body element.
Add a styleClass to your button. For example styleClass="mybutton-class".
Then add a widgetVar to your <p:dialog widgetVar="widgetVarName" ...>
jQuery(".mybutton-class").on("click", function() {
jQuery('.ui-widget-overlay').click(function(){
PF('widgetVarName').hide();
})
});
Additional for Ajax Update Events:
I build 3 JS functions.
//for the first time the page is loaded
jQuery(document).ready(function() {
onLoadFunction();
});
//to load the script after you reload your page with ajax
jQuery(document).on("pfAjaxComplete", function(){
onLoadFunction();
});
//your code you handle with
function onLoadFunction(){
jQuery(".mybutton-class").on("click", function() {
jQuery('.ui-widget-overlay').click(function(){
PF('widgetVarName').hide();
})
});
}
It is an 8 years old question, but recently I meet the same problem and here is my solution for a modal primefaces dialog.
I wrote a js function which adds a listener to overlay panel around the dialogue
function addListenerOnDialogueOverlay() {
document.getElementById('test-dialog_modal')
.addEventListener('click', function (event) {
PF('test-dialog-widget').hide();
});
}
and call the finction in "onShow" tag of the dialogue
<p:dialog id="test-dialog"
widgetVar="test-dialog-widget"
modal="true"
onShow="addListenerOnDialogueOverlay()">