We are moving from GEB/Spock to Cypress for front end automation. With GEB/Spock, the page objects had static content. This was used to create the selectors for the page objects.
class LoginPage extends Page {
//private static Logger log = LoggerFactory.getLogger(LoginPage.class);
static url = 'login/'
static at = { title == "Login to TalentBank"}
static content = {
backgroundImage { $("div [style*=\"background-image\"]") }
logo { $(".center-img img") }
emailHeader { $("#emailGroup:not([style*=\"none\"]) label") }
emailTextBox { $('#emailGroup:not([style*="none"]) #email') }
nextButton { $('#loginWithEmail') }
pwdHeader { $("#passwordGroup:not([style*=\"none\"]) label") }
pwdTextBox { $("#passwordGroup:not([style*=\"none\"]) #password") }
loginButton { $("#loginWithPassword") }
loginError(wait: true) { $("#loginError") }
In cypress, I'm unsure where to create and call these objects. Are the selectors supposed to be created as fixtures or as support files? I've read through the cypress documentation, but can't find what I am looking for.
Edit: 2/4
Under support, I tried creating a LoginPage.js file to contain the objects
// Login Page Objects
const emailTextBox = $('#emailGroup:not([style*="none"]) #email');
My test is under integration directory. I use the new constant in my test. There are no errors in my IDE, as the test appears to find the constant as it displays in the Ctrl+Space code completions.
describe('Successfull log in to the System', function() {
it('Standard User - Successful log in ', function() {
cy.get(emailTextBox).type('RodneyRuxin#mailinator.com')
When I run my test however, I get an error that says
ReferenceError: emailTextBox is not defined
.
Okay so these are different selectors to interact with:
I would recommend a completely different class and then do an import of them?
So for example a file called locators.js
which contains:
export const backgroundImage = () => cy.get("div [style*=\"background-image\"]");
then in your other file, you can import it like so:
import * as locators from "../locators/locators.js";
and call it like this (example):
locators.backgroundImage()
.should('be.visible')
.click();
Hope this helps!
Related
The following code renders a warning message conditionally, when user switch site (by clicking the button, or accessing directly using URL), the website will show a warning message, and disappear on refresh.
Things work fine within the docusaurus local development server, but behaves differently once built into a production static site.
import Cookies from 'js-cookie';
import React from 'react';
import { DocProvider } from '#docusaurus/theme-common/internal';
import { HtmlClassNameProvider } from '#docusaurus/theme-common';
import { translate } from '#docusaurus/Translate';
import CommunityLinkGroup from "#site/src/components/LinkGroup";
import DocItemLayout from '#theme/DocItem/Layout';
import DocItemMetadata from '#theme/DocItem/Metadata';
import styles from "./index.module.css";
export default function DocItem(props) {
const docHtmlClassName = `docs-doc-id-${props.content.metadata.unversionedId}`;
const MDXComponent = props.content;
const url = props.location.pathname;
const prevEdition = Cookies.get('doc_edition');
var displayAlert = false;
if (url.includes('/community/')) {
Cookies.set('doc_edition', 'community');
if (prevEdition == 'cloud') {
displayAlert = true;
}
} else if (url.includes('/cloud/')) {
Cookies.set('doc_edition', 'cloud');
if (prevEdition == 'community') {
displayAlert = true;
}
}
var alertMsg = "bad msg";
var alertClass = "badcls";
var alertRole = "badrole";
if (displayAlert == true) {
alertMsg = translate({
id: 'theme.DocItem.switchDocAlertMsg',
message: 'you just switched site, please notice.',
});
alertClass = "alert alert--warning";
alertRole = "alert";
}
console.log(alertMsg, alertClass, alertRole);
return (
<DocProvider content={props.content}>
<HtmlClassNameProvider className={docHtmlClassName}>
<div className={alertClass} role={alertRole}>{alertMsg}</div>
<DocItemMetadata />
<DocItemLayout>
<MDXComponent />
</DocItemLayout>
<div className={styles.communityLinkContainer}>
<CommunityLinkGroup />
</div>
</HtmlClassNameProvider>
</DocProvider>
);
}
Works fine inside the local dev server:
But once built into a production static site, it yields impossible rendering result:
Meanwhile, production site console output shows you just switched site, please notice. alert alert--warning alert, which clearly indicates alertMsg=='you just switched site, please notice.', alertClass=="alert alert--warning", alertRole=="alert", meaning that displayAlert must be true.
But as shown in above screenshot, it looks like as if displayAlert is both false and true at the same time, a totally impossible DOM state.
Also, this only happens when accessed directly using URL path, if I click on the button provided by the website to change site, the website warning message will display normally through dynamic rendering.
I should be using state variables, like https://stackblitz.com/edit/react-pcagrw?file=src/App.js, consider this a React 101.
I feel like this should be a very trivial thing to accomplish, yet I've been struggling for too long now. I'm trying to load a static minified script in my vue project.
This is my project structure:
project
-- public
index.html
-- src
App.vue
main.js
-- static
p5.min.js
vanta.waves.min.js
I'm trying to follow the setup as instructed here:
<script src="three.r92.min.js"></script>
<script src="vanta.waves.min.js"></script>
<script>
VANTA.WAVES('#my-background')
</script>
Since I'm only using the script in one component, I would like to load it there instead of globally including it in the index.html file.
export default {
...
methods: {
animate() {
const p5Script = document.createElement('script')
p5Script.async = true;
p5Script.defer = true;
p5Script.id = 'p5'
p5Script.src = '#/static/p5.min.js';
document.head.appendChild(p5Script);
const vantaScript = document.createElement('script')
vantaScript.async = true;
vantaScript.defer = true;
vantaScript.id = 'vanta'
vantaScript.src = '#/static/vanta.topology.min.js'
document.head.appendChild(vantaScript);
vantaScript.onload = () => {
// window???
window.VANTA.TOPOLOGY({
el: '#vanta',
color: 0xced4b1,
backgroundColor: 0xe0ebeb
})
}
}
},
mounted() {
this.animate();
},
});
I'm trying to access the VANTA object on window after it loads, but there is none. It feels like my approach is just wrong to begin with, but I'm not able to find any documentation on how to include static scripts?
Check this repo for a vue vanta component with slots to use in specific components https://github.com/iwatakeshi/vue-vanta
My Problem:
I am trying to click options in a dropdown with Nightwatch, using sections in page objects. I'm not sure if it's a problem with the section declaration or i'm missing something scope-related. Problem is that it finds the element as visible, but when it tries to click it will throw error that it cannot locate it using recursion.
What could i try to do to fix this issue using sections?
In the test:
var myPage = browser.page.searchPageObject();
var mySection = searchPage.section.setResults;
// [finding and clicking the dropdown so it opens and displays the options]
browser.pause (3000);
browser.expect.section('#setResults').to.be.visible.before(1000);
myPage.myFunction(mySection, '18');
In the page object:
var searchKeywordCommands = {
myFunction: function (section, x) {
section.expect.element('#set18').to.be.visible.before(2000);
if (x == '18') section.click('#set18');
//[...]
};
module.exports = {
//[.. other elements and commands..]
sections: {
setResults: {
selector: '.select-theme-result', //have also tried with '.select-content' and '.select-options' but with the same result
elements: {
set18: '.select-option[data-value="18"]',
set36: '.select-option[data-value="36"]' //etc
}}}}
Here is my source code:
When i run this piece of core, it seems to find the section, finds the element visible (i also can clearly see that it opens the dropdown and shows the options) but when trying to click any option, i get the error: ERROR: Unable to locate element: Section[name=setResults], Element[name=#set18]" using: recursion
Here is the full error:
My attempts:
I have tried to declare that set18 selector as an individual element instead of inside of the section and everything works fine this way, but won't work inside of the section. I have also tried all the selectors available to define the section's selector, but it won't work with any of them.
This is what i am doing with(LOL)
I assume steps would be (find dropbox - click dropbox - select value).
var getValueElement = {
getValueSelector: function (x) {
return 'li[data-value="'+ x + '"]';
}
};
module.exports = {
//[.. other elements and commands..]
sections: {
setResults: {
commands:[getValueElement],
selector: 'div[class*="select-theme-result"', //* mean contains,sometime class is too long and unique,also because i am lazy.
elements: {
setHighlight:'li[class*="select-option-highlight"]',
setSelected:'li[class*="select-option-selected"]',
//set18: 'li[data-value="18"]',
//set36: 'li[data-value="36"]'
// i think getValueFunction is better,what if you have 100+ of set.
}}}}
In your test
var myPage = browser.page.searchPageObject();
var mySection = searchPage.section.setResults;
// [finding and clicking the dropdown so it opens and displays the options]
mySection
.click('#dropboxSelector')
.waitForElementVisible('#setHighlight',5000,false,
function(){
var set18 = mySection.getValueElement(18);
mySection.click(set18);
});
Ps:in my case(i think your case also), dropbox or any small third-party js framework which is used many times in your web app, so better create a different PageObject for it,make pageObject/section is simple as possible.
Say I have a simple view model (widget.js):
import {Behavior} from 'aurelia-framework';
export class Widget
{
static metadata() { return Behavior.customElement('widget') }
constructor()
{
this.title= "AwesomeWidget";
}
}
With the following view: (widget.html):
<template>
<div>${title}</div>
</template>
Now say I inject some markup like this into the DOM:
var markup = `<div><widget></widget></div>`;
var $markup = $(markup);
var $placeholder = $("#placeholder");
$placeholder.append($markup);
How can I now tell Aurelia to compile this newly added part of the DOM against a new instance of Widget? I know it involves ViewCompiler but need an example to help me along. I'd greatly appreciate any help. Thanks!
A few months ago the TemplatingEngine class got a newly accessible enhance API method. This shortcuts the need to manually use the viewCompiler and compile method which was originally the only easy approach. This blog post details how you can use the enhance API to Aureliaify dynamically added HTML in your pages.
This has the added benefit of not needing to clean up the compiled HTML or detach anything either.
Here's an example: https://gist.run/?id=762c00133d5d5be624f9
It uses Aurelia's view compiler to compile the html and create a view instance, bound to the supplied view-model.
view-factory.js
import {
inject,
ViewCompiler,
ViewResources,
Container,
ViewSlot,
createOverrideContext
} from 'aurelia-framework';
#inject(ViewCompiler, ViewResources)
export class ViewFactory {
constructor(viewCompiler, resources, container) {
this.viewCompiler = viewCompiler;
this.resources = resources;
this.container = container;
}
insert(containerElement, html, viewModel) {
let viewFactory = this.viewCompiler.compile(html);
let view = viewFactory.create(this.container);
let anchorIsContainer = true;
let viewSlot = new ViewSlot(containerElement, anchorIsContainer);
viewSlot.add(view);
view.bind(viewModel, createOverrideContext(viewModel));
return () => {
viewSlot.remove(view);
view.unbind();
};
}
}
Usage:
let view = this.viewFactory.insert(containerElement, viewHtml, viewModel);
I wanted to hide some issue link outward & inwards strings of Link type from the Link Issues Popup Window using java script.
I have tried using java script but I am not getting the popup screen from the java script.
Please see the screenshot below :
Can anyone tell me how can I get this popup screen in the java script?
Is there any other method to hide this?
Thanks & Regards,
Renuka.
To hide the clone issue link every page:
edit the file system-webresources-plugin.xml (should be at /atlassian-jira/WEB-INF/classes/), and add to <web-resource key="jira-fields"> this code:
<resource type="download" name="myScript.js" location="/includes/jira/field/script.js">
<param name="source" value="webContextStatic"/>
</resource>
than, on /includes/jira/field/myScript.js write this:
AJS.$(document).ready(function() {
if (AJS.$("#link-type option[value*='clon']").size() > 0) {
// will work even when right clicking on More
// Actions->Link & open it into a new window
AJS.$("#link-type option[value*='clon']").remove()
} else if (AJS.$("#link-issue").size() > 0) {
// will work in case the link menu showing via popup
AJS.$("#link-issue").click(function(){
// wait for the popup to show, and remove the clone options
setTimeout(function (){
AJS.$("#link-type option[value*='clon']").remove();
}, 300);
});
}
});
restart Jira and it that it!
The script attaches a function to the link-menu opening, than gives the menu 0.3 seconds to load, and removes the unwanted items. If it doesn't work well for you, try to raise the timeout from 300 to 500-1000.
On jira 4, run instead:
AJS.$("#issue-link-link-type option[value*='clon']").remove();
The previous solution has an issue:
It will only work when clicking the "Link Issue"-Menu-Item.
When I use the Point (.)-Shortcut-Menu, it won't remove the issue types.
I have established the following solution:
JS-Binding-Part:
AJS.$(document).ready(function() {
JIRA.bind(JIRA.Events.NEW_CONTENT_ADDED, function(e, context, reason) {
hideIssueLinkTypes();
});
});
JS-Backing-Function:
function hideIssueLinkTypes() {
var apiURL = "/rest/scriptrunner/latest/custom/getHiddenLinkTypes"
$.getJSON( apiURL, {
}).done(function( objectData ) {
$.each( objectData, function( i, item ) {
var issueLinkType = item.issueLinkType[0];
AJS.$("#link-type option[value='"+issueLinkType.inwardDescription+"']").remove();
AJS.$("#link-type option[value='"+issueLinkType.outwardDescription+"']").remove();
});
});
}
Scriptrunner-REST-Endpoint:
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonBuilder
import groovy.transform.BaseScript
import com.atlassian.jira.issue.link.DefaultIssueLinkTypeManager
import com.atlassian.jira.issue.link.IssueLinkTypeManager
import com.atlassian.jira.issue.link.IssueLinkType
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.properties.ApplicationProperties
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
#BaseScript CustomEndpointDelegate delegate
String HIDDEN_IDENT="[hidden]"
getHiddenLinkTypes(httpMethod: "GET") { MultivaluedMap queryParams, String body ->
def appProperties = ((ApplicationProperties) ComponentAccessor.getComponentOfType(ApplicationProperties.class));
def appClonersLinkTypeName = appProperties.getDefaultBackedText("jira.clone.linktype.name");
def jsBuilder=new JsonBuilder();
def issueLinkTypes = ((IssueLinkTypeManager) ComponentAccessor.getComponentOfType(IssueLinkTypeManager.class)).getIssueLinkTypes();
jsBuilder issueLinkTypes.findAll({it.getName().contains(HIDDEN_IDENT) || it.getName()==appClonersLinkTypeName }),
{ IssueLinkType linkType ->
issueLinkType linkType.getId(),
name: linkType.getName(),
inwardDescription: linkType.getInward(),
outwardDescription: linkType.getOutward()
}
return Response.ok(jsBuilder.toString()).build();
}
What you can do then ist just annotate and Link-Type with putting [hidden] in the link name and it will disappear for all users (It can still be programmatically added though or created by cloning).
If you don't have Scriptrunner or don't need the dynamic nature of the implementation, you can still hard-code the values as Kuf described in the answer above in hideIssueTypes() like this:
AJS.$("#issue-link-link-type option[value*='clon']").remove();