When I create plane java Swing components like dialog boxes etc, it is very easy to make a unit test to display the Dialog. Basically, I can just create an instance of the dialog and call setIsVisible(true). I'm having a really tough time figuring out how to do this with a griffon View. I've been trying to do this with integration tests but I can't seem to get it.
I've tried a few things to show the view and nothing seems to work. The only way I seem to be able to get an instance of the view is:
AirplaneView view = helper.newInstance(app, griffonpractice.AirplaneView.class, "Airplane")
After this I thought I may be able to do a view.setIsVisible(true) or view.frame.setIsVisible(true) but no luck. I'm guessing I am thinking about this the wrong way, there has to be a fairly simple way to do this. Any help is appreciated. My view looks like the following, note that there are no bindings so I shouldn't need to mock anything.
package griffonpractice
import javax.swing.JFrame
JFrame frame = application(title: 'GriffonPractice',
size: [320,480],
pack: true,
location: [50,50],
locationByPlatform:true){
borderLayout()
{
hbox(constraints: BL.NORTH)
{
label(text: "shane")
label(text: "Jack");
}
}
}
Have you tried using FEST? http://easytesting.org
The book Griffon in Action has a detailed example on testing a Griffon application using FEST, the source code is available at http://code.google.com/p/griffoninaction/source/browse/trunk/chap09/dictionary
Here's a short example of 3 tests for a simple application
package dictionary
import org.fest.swing.fixture.*
import griffon.fest.FestSwingTestCase
class DictionaryTests extends FestSwingTestCase {
void testInitialState() {
window.button('search').requireDisabled()
}
void testWordIsFound() {
window.with {
textBox('word').enterText('griffon')
button('search').click()
textBox('result')
.requireText('griffon: Grails inspired desktop application development platform.')
}
}
void testWordIsNotFound() {
window.with {
textBox('word').enterText('spock')
button('search').click()
textBox('result')
.requireText("spock: Word doesn't exist in dictionary")
}
}
protected void onTearDown() {
app.models.dictionary.with {
word = ""
result = ""
}
}
}
Related
I am using Kotlin's html library kotlinx.html for dynamic html building.
I want to create a button which triggers a function when clicked. This is my current code:
class TempStackOverflow(): Template<FlowContent> {
var counter: Int = 1
override fun FlowContent.apply() {
div {
button(type = ButtonType.button) {
onClick = "${clicked()}"
}
}
}
fun clicked() {
counter++
}
}
This results in the following source code:
<button type="button" onclick="kotlin.Unit">testkotlin.Unit</button>
Which gives this error when clicked (from Chrome developer console):
Uncaught ReferenceError: kotlin is not defined at HTMLButtonElement.onclick
I have tried several approves, and search for a solution - but could not find the proper documentation.
I am not a Kotlin expert, but it's perfectly possible to write event handlers using kotlinx. Rather than:
onClick = "${clicked()}"
have you tried using this?
onClickFunction = { clicked() }
If you really need a bit on Javascript here, you can type this:
unsafe {
+"<button onClick = console.log('!')>Test</button>"
}
Good for debugging and tests, but not very nice for production code.
Unfortunately, you're completely missing the point of the kotlinx.html library. It can only render HTML for you, it's not supposed to be dynamic kotlin->js bridge, like Vaadin or GWT. So, you just set result of clicked function converted to String to onClick button's property, which is effective kotlin.Unit, because kotlin.Unit is default return value of a function if you not specify another type directly.
fun clicked() {
counter++
}
is the same as
fun clicked():Unit {
counter++
}
and same as
fun clicked():Kotlin.Unit {
counter++
}
So, when you set "${clicked()}" to some property it actually exec function (your counter is incremented here) and return Koltin.Unit value, which is becomes "Kotlin.Unit" string when it rendered inside "${}" template
I was looking at the sample code for the tutorial at https://forge.autodesk.com/blog/custom-window-selection-forge-viewer-part-iii which is located at https://github.com/Autodesk-Forge/forge-rcdb.nodejs/blob/master/src/client/viewer.components/Viewer.Extensions.Dynamic/Viewing.Extension.SelectionWindow/Viewing.Extension.SelectionWindow.Tool.js as well as the documentation at https://developer.autodesk.com/en/docs/viewer/v2/reference/javascript/toolinterface/ --- Most of these functions are getting called properly in my tool such as handleSingleClick, handleMouseMove, handleKeyDown, and so on, but two of them are not getting hit -- handleButtonDown and handleButtonUp. I was using viewer version 3.3.x but I have updated to use 4.0.x thinking that that might help to resolve the problem, but the same issue occurs in both versions. Thanks for any help.
The following code block from theAutodesk.Viewing.ToolController#__invokeStack(), _toolStack stands for activated tools in the ToolController, the method stands for callback functions started with handle, i.e. handleSingleClick, handleMouseMove, handleKeyDown, handleButtonDown, handleButtonUp, etc.
for( var n = _toolStack.length; --n >= 0; )
{
var tool = _toolStack[n];
if( tool[method] && tool[method](arg1, arg2) )
{
return true;
}
}
Based on my experience, if there is a handle function such as handleButtonDown or handleButtonUp executed before your custom tools' and returned true, then your handles will never be called.
Fortunately, Forge Viewer (v3.2) starts invoking a priority mechanism for custom tools registered in ToolController. ToolController will use the priority number to sort the tools in it, and the priority number of each tool is 0 by default. You can override the priority to make your tools be hit before other tools like this way, to add a function getPriority() to return a number greater than 0:
this.getPriority = function() {
return 100;
};
I found out that when using ES6 and the class syntax, extending your tool from Autodesk.Viewing.ToolInterface will prevent the overrides to work properly, probably because it is not implemented using prototype in the viewer source code.
You can simply create a class and implement the methods that are of interest for your tool:
// KO: not working!
class MyTool extends Autodesk.Viewing.ToolInterface {
getName () {
return 'MyTool'
}
getNames () {
return ['MyTool']
}
handleButtonDown (event, button) {
return false
}
}
// OK
class MyTool {
getName () {
return 'MyTool'
}
getNames () {
return ['MyTool']
}
handleButtonDown (event, button) {
return false
}
}
I have the following code in Cocos2d-x v3.1:
void Board::createNewRandomBottomRow()
{
//eventHappening is a variable modified in other parts of the code
//I don't want that while eventHappening is true, this method does anything
if ( eventHappening ) {
this -> scheduleOnce( SEL_SCHEDULE( &Board::createNewRandomBottomRow ), 0.3f );
}
else
{
//actual logic
}
}
However, I check with the debugger that the method is not being rescheduled. Isn't it possible to reschedule a method from inside the same method?
Well, I did the same again in another simpler scenario, and the rescheduling works fine, so I guess I messed up in the logic in another part of the code.
So just to sum up: rescheduling a method from inside the method itself works fine.
I am starting to implement MVVM in my application and got an issue of knowing when the user navigated to the view.
To navigate between views, I can just use the navigationService.Navigate(...);
How do I check when I navigated to the view?
May I use the event navigationService.Navigated?
Is there no other method I can use like OnNavigatedTo that the page itself provide?
XAML:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP71"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
DataContext="{Binding titleSearchViewModel, Source={StaticResource Locator}}">
<i:Interaction.Triggers>
<i:EventTrigger>
<cmd:EventToCommand Command="{Binding PageLoaded, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
VM:
private RelayCommand _PageLoaded;
public RelayCommand PageLoaded
{
get
{
if (_PageLoaded == null)
{
_PageLoaded = new RelayCommand(
() => Loaded()
);
}
return _PageLoaded;
}
}
In case this question is still actual, i prefer this solution: http://www.geoffhudik.com/tech/2010/10/10/another-wp7-navigation-approach-with-mvvm.html
If to use it, it is possible to send recipient ViewModel's parameters from the sender ViewModel:
SendNavigationMessage(Settings.NAVIGATION_PRODUCTS_SUBCATEGORIES,
new Dictionary<string, object> { { "SelectedIndex", Int32.Parse(item.id) } });
And receiver should define in xaml:
NavigatedToCommand="{Binding RefreshCommand}"
And then in receiver ViewModel:
public ICommand RefreshCommand // Should be set as NavigatedToCommand="{Binding RefreshCommand}" in xaml
{
get { return new RelayCommand(Refresh); }
}
public void Refresh()
{
_dataService.GetList(SelectedIndex, DownloadedCallback); // So, this would be called automatically after navigating is complete. SelectedIndex is updated at this moment.
}
Thanks for the answers provided. Both were helpful over a period of time until I decided to create a custom implementation of the navigation service that has been created by a few people.
I then made a contribution to the Cimbalino toolkit to suggest this and it has been introduced a while back.
I my personal opinion, that solves my issue the best. Have a look at the navigation service in there. The Navigated event pretty much solves my issue I had.
https://github.com/Cimbalino/Cimbalino-Toolkit
It basically comes down to this (in your viewmodel):
_navigationService.Navigated += OnNavigated;
I'm still pretty new to Grails and I'm developing an online survey. I decided to use web flow and I have been running into many issues. I'm trying to pass the survey id from the gsp page to the flow controller. This works perfectly fine on any other controller action but whenever I do it to the action for the start state of the flow I always get the same error. I've followed a tutorial in a text book that does this the EXACT same way and I'm running out of ideas.
here is the link from the gsp page:
<g:link controller="surveyPage" action="beginTest" id="${survey.id}">
${survey.surveyName}
</g:link>
and here is the flow with the start state
def beginTestFlow = {
showSurvey{
def survey = Survey.get(params.id)
on("cancel").to "cancelSurvey"
on("continueSurvey").to "nextQuestion"
}
cancelSurvey { redirect(controller:"surveyPage") }
}
it always throws the exception:
argument type mismatch on the line with
def survey = Survey.get(params.id)
I've also tried:
flow.survey = Survey.get(params.id)
or even:
flow.survey = Survey.get(session.survey.id)
always the same error. Also, I made sure class Survey implements Serializable. I've copied and pasted the same code into a different action with the same controller and it works flawlessly. Any ideas to what is different with the web flow?
You can't put code like that directly inside a state definition, you need to use an action state or an onEntry block
def beginTestFlow = {
showSurvey{
onEntry {
flow.survey = Survey.get(params.id)
}
on("cancel").to "cancelSurvey"
on("continueSurvey").to "nextQuestion"
}
cancelSurvey { redirect(controller:"surveyPage") }
}
The onEntry block will fire every time the showSurvey state is entered. If instead you want some logic to be run just once at the start of the whole flow (for example if some later transition might re-enter the initial state), you can use a flow-level onStart block instead:
def beginTestFlow = {
onStart {
flow.survey = Survey.get(params.id)
}
showSurvey{
on("cancel").to "cancelSurvey"
// ...
Ivo Houbrechts wrote an excelent tutorial about grails 2.0 webflow. You can read it here:
http://livesnippets.cloudfoundry.com/docs/guide/