I'm working on a geb page object with a repeating set of UI elements a div container with a text input and button within.
I am attempting the following:
class MyModule extends Module{
static content = {
textInput {$("input.editTextField")}
removeInputButton {$("button.removeButton")}
}
}
class MyPage extends Page{
static content = {
myInputs { index ->
$("div.container", index).module(MyModule)
}
}
In IntelliJ the code is highlighted in MyPage on ("div.container, index) when I hover over this I see "'$' in 'geb.Page' cannot be applied to '(java.lang.String.?)'
My goal is to be able pick an iteration of the UI and to perform something like:
myInputs(0).textInput = 'foo'
myInputs(1).textInput = 'bar'
myInputs(5).removeInputButton.click()
I've referred to the documentation for Geb but by all accounts this should work. Any help would be appreciated.
This will work, it's just that your code is not type safe enough for IntelliJ to know which method you're calling. If you change your content definition to:
myInputs { int index ->
$("div.container", index).module(MyModule)
}
then the warning will disappear.
Related
I had a complex data structure and Vue handled it fine. Then I refactored it and suddenly nothing seems to work. I verified that the data structure was correctly assembled but nothing displays. Vue didn't report any errors and nothing is displayed.
After several hours I found that the Vue render system does not work when the data structure contains a circular reference. To verify I defined two classes A and B. Each can have a reference to the other.
classA.js
export default class classA {
constructor(name) {
this.name = name
this.refB = undefined
}
get name() {return this._name}
set name(n) { this._name= n}
get type() {return 'classA'}
get refB() {return this._refB}
set refB(n) { this._refB= n}
}
classB.js
export default class classB {
constructor(name) {
this.name = name
this.refA = undefined
}
get name() {return this._name}
set name(n) { this._name= n}
get type() {return 'classB'}
get refA() {return this._refA}
set refA(n) { this._refA= n}
}
Next define a Vue component that displays a list of class A. Construct the list in the mount lifecycle hook and be sure to NOT link the instance of classB back to classA. Verify the following renders a raw display of each element of the classAList
<template lang="pug">
div Circular References
div ClassAList length: {{classAlist.length}}
div(v-for="cA in classAlist")
div {{cA}}
</template>
<script>
import ClassA from '../classA'
import ClassB from '../classB'
export default {
data () {
return {
classAlist: []
}
},
mounted: function () {
let a = new ClassA('a1')
let b = new ClassB('b1')
a.refB = b
// Uncomment the next line to create a circular reference in the
// data structure. Immediately, once this next line establishes the
// circular reference the Vue render system fails, silently
// b.refA = a
this.classAlist.push(a)
console.log('Console listing the classA list ', this.classAlist)
}
}
</script>
Check the console to see the array is constructed as expected. Now uncomment the line of code that links the instance of B back to the instance of A. The console will continue to show the array is constructed as expected but the Vue render system doesn't like the circular references.
Is there a workaround?
Is there a way to get Vue to show some error message. (e.g. like JSON.stringfy does on objects like this)?
I'm trying to create a simple widget test in Flutter. I have a custom widget that receives some values, composes a string and shows a Text with that string. I got to create the widget and it works, but I'm having trouble reading the value of the Text component to assert that the generated text is correct.
I created a simple test that illustrates the issue. I want to get the text value, which is "text". I tried several ways, if I get the finder asString() I could interpret the string to get the value, but I don't consider that a good solution. I wanted to read the component as a Text so that I have access to all the properties.
So, how would I read the Text widget so that I can access the data property?
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('my first widget test', (WidgetTester tester) async {
await tester
.pumpWidget(MaterialApp(home: Text("text", key: Key('unit_text'))));
// This works and prints: (Text-[<'unit_text'>]("text"))
var finder = find.byKey(Key("unit_text"));
print(finder.evaluate().first);
// This also works and prints: (Text-[<'unit_text'>]("text"))
var finderByType = find.byType(Text);
print(finderByType.evaluate().first);
// This returns empty
print(finder.first.evaluate().whereType<Text>());
// This throws: type 'StatelessElement' is not a subtype of type 'Text' in type cast
print(finder.first.evaluate().cast<Text>().first);
});
}
I got it working. I had to access the widget property of the Element, and then cast it as text:
var text = finder.evaluate().single.widget as Text;
print(text.data);
Please check this simple example.
testWidgets('Test name', (WidgetTester tester) async {
// findig the widget
var textFind = find.text("text_of_field");
// checking widget present or not
expect(textFind, findsOneWidget);
//getting Text object
Text text = tester.firstWidget(textFind);
// validating properies
expect(text.style.color, Colors.black);
...
...
}
You can use find.text
https://flutter.io/docs/cookbook/testing/widget/finders#1-find-a-text-widget
testWidgets('finds a Text Widget', (WidgetTester tester) async {
// Build an App with a Text Widget that displays the letter 'H'
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Text('H'),
),
));
// Find a Widget that displays the letter 'H'
expect(find.text('H'), findsOneWidget);
});
I'm working in Kotlin with the TornadoFX library. Imagine you have a toolbar which shows the tool that are useful for the current view you have. So we have a MainController which has a subController property which is the controller of some view next to the tool bar. So if our subController changes, the view should update. Also, if any property (e.g. selectedTool, tools) of the subController changes, the toolbar should update accordingly. Momentarily, the toolbar is not updated.
class ToolBar : View("Tool bar") {
private val controller: MainController by inject()
override val root = vbox {
tilepane {
for (tool in controller.subController.tools) {
button(tool.name, group).action {
controller.subController.changeTool(tool) // changes selected tool
}
}
}
this += controller.subController.selectedTool.options
}
}
Extra info: subController.tools is an ArrayList and subController.selectedTool is a Tool.
Now my question is, what's the recommended way to do this in TornadoFX?
You have several options. A Parent supports a function called bindChildren which accepts an observable list of items and a function to turn each of these items into a Node. You can use this to create your buttons in the toolbar:
tilepane {
bindChildren(controller.subController.tools) { tool ->
Button(tool.name) ...
}
}
You can also do this manually if you need more control:
tilepane {
controller.subController.tools.onChange {
children.clear()
// create new buttons here, like in your example
}
}
However, instead of injecting controller to access subController to get to the tools, you should have a ToolsModel which is injected into the current scope. The tools model could have a list of tools and the selected tools and can be injected into all views and controllers which needs it. You say that selectedTool is a Tool, but you're not showing what a Tool is, but judging from your code it looks like Tool.options is a Node subclass (?).
You can add/remove the tool.options element using the same technique, or even wrap it in a stackpane or other layoutcontainer to be able to identify the tool to remove (or simply remove all children of the stackpane) on change using the same technique.
I am learning how Aurelia works and I am trying to get a simple custom attribute working. All it will do is change the color of a div text depending on some value changing.
I have a div which has:
high.bind="changeColor"
and in my attribute I have :
import {inject, customAttribute} from 'aurelia-framework';
#customAttribute('high')
#inject(Element)
export class High {
constructor(element) {
this.element = element;
}
valueChanged(newValue){
console.log(newValue);
if (newValue) {
this.element.classList.remove('highlight-yellow');
} else {
this.element.classList.add('highlight-blue');
}
}
In my view model I have :
import {high} from './highlightattribute'
export class Welcome{
heading = 'Welcome to the Aurelia Navigation App!';
firstName = 'John';
lastName = 'Doe';
get fullName(){
return `${this.firstName} ${this.lastName}`;
}
get changeColor(){
if (this.firstName == 'John'){
return false;
}
return true;
}
welcome(){
alert(`Welcome, ${this.fullName}!`);
}
}
When I change the firstname I do not see the valueChanged event being triggered in the high custom attribute class.
It looks like you are importing the high code in to your viewmodel rather than your view. Remove this line in your ViewModel:
import {high} from './highlightattribute'
Then and add this line to your View:
<require from="./highlightattribute"></require>
Next, in the highlightattribute.js file you are removing highlight-yellow and adding highlight-blue, so you will probably want to add and remove the same class. I did also notice that there is a missing parenthesis in your highlightattribute.js file you posted, but that was probably just missed while copying the code.
Let me know if this helps solve the problems. I have pushed a sample with your code to here: https://github.com/AshleyGrant/skeleton-navigation/tree/so-answer-20150416-01/src
I am designing an app in sencha touch2. I have a panel object in my JS file. I need to dynamically set the text/html for this component. The store for this component is defined at the application level. Following is the thing I worked out:
Ext.define('class_name',{
....
config : {
pnlObj : null,
...
}
initialize : function() {
this.config.pnlObj = Ext.create('Ext.Panel');
var store = Ext.data.Storemanager.lookup('some_store');
store.on('load',this.loadStore,this);
this.setItems([{
//some items here
{
flex : 2,
// id : 'somepnl',
config : this.config.pnlObj
}
}]);
},
loadStore : function(store, rec) {
var text = rec.get('text');
var panel = this.config.pnlObj;
// var panel = Ext.getCmp('somepanl');
panel.setHtml(text);
}
});
When I inspect the inspect the element using Firebug console, I can find the panel added there. But I am not able to set the html dynamically. no html text is set there. I tried adding it using panel.add() & panel.setItems() method which doesn't work. If I give an id to that panel(somepanel here) and try to access it using Ext.getCmp('smpanel') then in that case it works fine. I have found that using Ext.getCmp() is not a good practice and want to avoid it as it might somewhere break my code in the future.
I guess the way I am instantiating the panel object is creating some issue. Can someone suggest the best way of doing it?
The recommended way to manipulate your components in Sencha Touch 2 is using controller, through refs and control configs. For example, your panel has a config like this: xtype:'myPanel', then in your controller:
refs: {
myPanel: 'myPanel'
}
control:{
myPanel: {
on_an_event: 'set_html_for_my_panel'
}
}
Lastly, define your function:
set_html_for_my_panel: function()
{
this.getMyPanel().setHtml('my_updated_html');
}
P/S: Behind the scene, Sencha Touch 2 uses Ext.ComponentQuery for refs in controllers