I have a Page class as
class SignUpPage extends Page {
static url = "signup"
static at = { waitFor { title.startsWith("Join") } }
static content = {
firstNameField { $("input", name:"firstName") }
lastNameField { $("input", name:"lastName") }
emailField { $("input", name:"email") }
passwordField { $("input", name:"password") }
}
}
I want to add a populateFields method to this class. This will allow me to call this method to populate the text fields from my test cases. This method has one argument passed in - a Map that allows me to override certain field values as necessary from my test cases.
The problem is that I don't know how I can iterate over the 'content' of the page. To make this clearer look at the code below:
class SignUpPage extends Page {
static url = "signup"
// .. as defined above ..
def populateFields(customValues = [:]) {
// I want to iterate of the textFields here
// Something like...
textFields = this.metaclass.methods.findAll {
it.name.endsWith("Field")
}
textFields.each {
// populate with data
}
}
}
This doesn't work.
How do I get the content of the closure 'content'?
I think that there is a much easier way of implementing it and you don't need to iterate over contents of your page object. Given the keys in your map are name attributes of the inputs you want to modify, you can do the following:
def populateFields(customValues = [:]) {
def form = $('form') //can be any element that is enclosing all of your inputs
customValues.each { key, value ->
form[key] = value
}
}
Have a look at the section on form control shortcuts in the manual to understand how it works.
If content becomes too complicated to use the available tools you could always create a list of the page contents in your content.
static content = {
username { module $(... }
contactTitle { $(... }
contactGivenName { $(... }
contactFamilyName { moduleList $(... }
pageFields {
[
username,
contactTitle,
contactGivenName,
contactFamilyName,
]
}
}
def populateFields(valueList) {
pageFields.each {
it.value(somevaluefromList)
}
}
Related
some times code says it best. In below example code in Chain.add I have the function name and vars fed in to it. But I am trying to reference the object that the function is associated with. How can I do this
class Chainable {
constructor(...values) {
this._chainableConstruct={
name: this.constructor.name,
values
};
}
}
class Chain {
constructor() {
this.data=[];
}
add(func,vars) {
console.log(func.name); //returns fun
console.log(...vars); //returns test 45
console.log(func.parent); //return undefined want object t from line 28
}
}
class Test extends Chainable {
fun() {
console.log("fun");
}
}
let t=new Test();
let c=new Chain();
c.add(t.fun,["test",45]);
Out of the box, you can't. Furthermore, you can set property values of multiple objects with the same value, so the same function object might have multiple "parents".
I've been playing around with lit-element, and I want to grab my custom element to run a getElementById. The only examples I can find use the shadow root (since that's the recommended way to use lit-element). How do you get access to your custom element to run a query on just your element?
import { LitElement, html }
from 'https://unpkg.com/lit-element/lit-element.js?module';
class RenderRootTest extends LitElement {
constructor() {
super();
}
render () {
const renderRoot = this.shadowRoot; //Won't work, because I'm overriding the shadowroot
return html`
<div>Rendered</div>
${renderRoot ?
html`<div>Render root found</div>` :
html``
}
`;
}
createRenderRoot() {
return this;
}
}
customElements.define('render-root-test', RenderRootTest);
I found the answer myself after enough tinkering. You can either use this.renderRoot or just this. However, note that certain methods such as .getElementById don't seem to exist. If anyone has any additional details on this topic, I would appreciate it.
ex.
import { LitElement, html }
from 'https://unpkg.com/lit-element/lit-element.js?module';
class RenderRootTest extends LitElement {
constructor() {
super();
}
render () {
const renderRoot = this.renderRoot;
return html`
<div>Rendered</div>
${renderRoot ?
html`<div>Render root found</div>` :
html``
}
`;
}
createRenderRoot() {
return this;
}
}
customElements.define('render-root-test', RenderRootTest);
Just reference this which is the instance of the custom element. The shadowRoot is created and returned by LitElement's createRenderRoot() so if you don't create one and instead of this.shadowRoot return this--which is the node itself--that is what the content is rendered into, there is no shadowRoot.
I have this (working) code, which is extended from the gradle documentation
https://docs.gradle.org/4.10.3/userguide/custom_plugins.html#sec:implementing_a_dsl
class User {
String name
}
class Group {
User user
}
class GreetingPluginExtension {
String message
final Group group
#javax.inject.Inject
GreetingPluginExtension(ObjectFactory objectFactory) {
group = objectFactory.newInstance(Group)
group.user = objectFactory.newInstance(User)
}
void group(Action<? super Group> action) {
action.execute(group)
}
void user(Action<? super User> action) {
action.execute(group.user)
}
}
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
// Create the extension, passing in an ObjectFactory for it to use
def extension = project.extensions.create('greeting', GreetingPluginExtension, project.objects)
project.task('hello') {
doLast {
println "${extension.message} from ${extension.group.user.name}"
}
}
}
}
The configuration closure looks like this:
greeting {
message = 'Hello'
group {
user {
name = 'tom'
}
}
}
But I would like to have a List of users an I tried:
class User {
String name
}
class Group {
ArrayList<User> users
}
class GreetingPluginExtension {
String message
final Group group
#javax.inject.Inject
GreetingPluginExtension(ObjectFactory objectFactory) {
// Create a Person instance
group = objectFactory.newInstance(Group)
group.users = []
}
void group(Action<? super Group> action) {
action.execute(group)
}
void users(Action<? super ArrayList<User>> action) {
action.execute(group.users)
}
}
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
// Create the extension, passing in an ObjectFactory for it to use
def extension = project.extensions.create('greeting', GreetingPluginExtension, project.objects)
project.task('hello') {
doLast {
extension.group.users.each {
println "${extension.message} from ${it.name}"
}
}
}
}
}
with this closure:
greeting {
message = 'Hello'
group {
users = [
{name = 'tom'} ,
{name = 'tim'}
]
}
}
my output is the following:
Hello from myProjectName
Hello from myProjectName
which is not the expected output but the rootProject.name
The output has the right number of elements, but is not referenced to the user.
How can I fix this? I would also appreciate informations about other approaches to map nested objects (and lists) into the extension-setting.
Greetings Tom
The following slightly modified version I believe does what you intended:
apply plugin: GreetingPlugin
greeting {
message = 'Hello'
group {
user(name: 'tom')
user(name: 'tim')
}
}
class User {
String name
}
class Group {
ArrayList<User> users = []
def user(props) {
users << new User(props)
}
}
class GreetingPluginExtension {
String message
final Group group
#javax.inject.Inject
GreetingPluginExtension(ObjectFactory objectFactory) {
// Create a Person instance
group = objectFactory.newInstance(Group)
}
void group(Action<? super Group> action) {
action.execute(group)
}
}
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
// Create the extension, passing in an ObjectFactory for it to use
def extension = project.extensions.create('greeting', GreetingPluginExtension, project.objects)
project.task('hello') {
doLast {
extension.group.users.each {
println "${extension.message} from ${it.name}"
}
}
}
}
}
When run, it prints:
~> gradle hello
> Task :hello
Hello from tom
Hello from tim
BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed
Note that I have removed the method:
void users(Action<? super ArrayList<User>> action)
as it is not needed for the above to work. I also changed the dsl somewhat. I actually think the changed dsl looks more readable and idiomatic but this is of course a matter of taste.
Note also that if you want to send in more properties to the user (say email), you can do this without modifying the scaffolding code, i.e.:
greeting {
message = 'Hello'
group {
user(name: 'tom', email: 'tom#wonderland.org')
user(name: 'tim', email: 'tim#wonderland.org')
}
}
class User {
String name
String email
}
If you were specifically looking for how you make a doubly nested configuration closure for a collection work, this does not solve your problem, but it does give you a reasonably clean way of accomplishing what the build script intended.
I have an app.js with this code:
var addnote = (title,body) => { /* enter code here */ }
module.exports = {addnote};
Can I add another addnotes function with different parameters to that file?
Function overloading in JavaScript does not exist like in other programming languages such as C# and Java.
What you should be looking to do is pass an object as a parameter that has properties attached and filter them out there..
You could call different functions from your little 'mapping function' just implement the logic there if it isn't big (to keep the code clear).
function foo(parameters){
var title = parameters.title;
var body = parameters.body;
if(parameters.extraProperty){
// oh we have extraProperty passed in too, run a different function?
bar(title, body, parameters.extraProperty); // ??
}
}
foo({title: 'Title', body: 'Body', extraProperty: 'This is extra...'});
If this is your own custom module, you can use the concept of function overriding, where each child class can have its own way to handle something and also have a default way to do things.
class Parent {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello ${this.name}`);
}
}
class Child1 extends Parent {
constructor(name) {
super(name);
}
greet() {
console.log(`Hey there ${this.name}. This is Child 1`);
}
}
class Child2 extends Parent {
constructor(name) {
super(name);
}
greet() {
console.log(`Hi there ${this.name}. This is Child 2`);
}
}
const o1 = new Child1('Foo')
const o2 = new Child2('Foo')
o1.greet();
o2.greet();
But if you are trying to override a function in an external module(You do not have access to that code, like a library), my suggestion is to create a wrapper and add functionality there.
What would be the best approach to map particular type to a Func of TResult? For example:
ViewModelBase GetScreen(Type type)
{
// mapping code here
}
ScreenA GetScreenA()
{
// returns new instance of ScreenA
}
// usage
var screen = GetScreen(typeof(ScreenA));
What I need to do here is to map ScreenA type to GetScreenA() method (strongly typed). Each screen inherits from ViewModelBase. What would be the best way to achieve this? I am not considering bunch of ifs as solution.
if (type = typeof(ScreenA))
return GetScreenA();
else if ....
You could use a a dictionary to map to the different actions instead of using if statements.
private Dictionary<Type , Func<ViewModelBase>> Method2ObjectMap
= new Dictionary<Type , Func<ViewModelBase>>
{
{ ScreenA, GetScreenA },
{ ScreenB, GetScreenB },
{ ScreenC, GetScreenC }
};
And then call it with something like:
if(Method2ObjectMap.ContainsKey(ScreenB))
{
return Method2ObjectMap[ScreenB];
}
Something like this will help you
class TypeA
{
}
class TypeB:TypeA
{
}
class TypeC : TypeA
{
}
private static Dictionary<Type, Func<TypeA>> ScreenMap =
new Dictionary<Type, Func<TypeA>>
{
{typeof(TypeA),()=> new TypeA() },
{typeof(TypeB) ,()=> new TypeB() },
{typeof(TypeC),()=> new TypeC() }
};
And to use it
TypeA a= ScreenMap[typeof(TypeA)]();